All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.generate.KleinbergSmallWorldGraphGenerator Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2017-2023, by Dimitrios Michail and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.generate;

import org.jgrapht.*;
import org.jgrapht.alg.util.*;

import java.util.*;

/**
 * Kleinberg's small-world graph generator.
 * 
 * 

* The generator is described in the paper: J. Kleinberg, The Small-World Phenomenon: An Algorithmic * Perspective, in Proc. 32nd ACM Symp. Theory of Comp., 163-170, 2000. * *

* The basic structure is a a two-dimensional grid and allows for edges to be directed. It begins * with a set of nodes (representing individuals in the social network) that are identified with the * set of lattice points in an $n \times n$ square. For a universal constant $p \geq 1$, the node * $u$ has a directed edge to every other node within lattice distance $p$ (these are its local * contacts). For universal constants $q \geq 0$ and $r \geq 0$, we also construct directed edges * from $u$ to $q$ other nodes (the long-range contacts) using independent random trials; the i-th * directed edge from $u$ has endpoint $v$ with probability proportional to \frac{1}{d(u,v)^r}$ * where $d(u,v)$ is the lattice distance from $u$ to $v$. * * @author Dimitrios Michail * * @param the graph vertex type * @param the graph edge type */ public class KleinbergSmallWorldGraphGenerator implements GraphGenerator { private final Random rng; private final int n; private final int p; private final int q; private final int r; /** * Constructor * * @param n generate set of lattice points in a $n$ by $n$ square * @param p lattice distance for which each node is connected to every other node in the lattice * (local connections) * @param q how many long-range contacts to add for each node * @param r probability distribution parameter which is a basic structural parameter measuring * how widely "networked" the underlying society of nodes is * @throws IllegalArgumentException in case of invalid parameters */ public KleinbergSmallWorldGraphGenerator(int n, int p, int q, int r) { this(n, p, q, r, new Random()); } /** * Constructor * * @param n generate set of lattice points in a $n$ by $n$ square * @param p lattice distance for which each node is connected to every other node in the lattice * (local connections) * @param q how many long-range contacts to add for each node * @param r probability distribution parameter which is a basic structural parameter measuring * how widely "networked" the underlying society of nodes is * @param seed seed for the random number generator * @throws IllegalArgumentException in case of invalid parameters */ public KleinbergSmallWorldGraphGenerator(int n, int p, int q, int r, long seed) { this(n, p, q, r, new Random(seed)); } /** * Constructor * * @param n generate set of lattice points in a $n \times n$ square * @param p lattice distance for which each node is connected to every other node in the lattice * (local connections) * @param q how many long-range contacts to add for each node * @param r probability distribution parameter which is a basic structural parameter measuring * how widely "networked" the underlying society of nodes is * @param rng the random number generator to use * @throws IllegalArgumentException in case of invalid parameters */ public KleinbergSmallWorldGraphGenerator(int n, int p, int q, int r, Random rng) { if (n < 1) { throw new IllegalArgumentException("parameter n must be positive"); } this.n = n; if (p < 1) { throw new IllegalArgumentException("parameter p must be positive"); } if (p > 2 * n - 2) { throw new IllegalArgumentException("lattice distance too large"); } this.p = p; if (q < 0) { throw new IllegalArgumentException("parameter q must be non-negative"); } this.q = q; if (r < 0) { throw new IllegalArgumentException("parameter r must be non-negative"); } this.r = r; this.rng = Objects.requireNonNull(rng, "Random number generator cannot be null"); } /** * Generates a small-world graph. * * @param target the target graph * @param resultMap not used by this generator, can be null */ @Override public void generateGraph(Graph target, Map resultMap) { /* * Special cases */ if (n == 0) { return; } else if (n == 1) { target.addVertex(); return; } /* * Ensure directed or undirected */ GraphTests.requireDirectedOrUndirected(target); boolean isDirected = target.getType().isDirected(); /* * Create vertices */ List nodes = new ArrayList<>(n * n); for (int i = 0; i < n * n; i++) { nodes.add(target.addVertex()); } /* * Add local-contacts */ for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { int vi = i * n + j; V v = nodes.get(vi); // lookup neighborhood for (int di = -p; di <= p; di++) { for (int dj = -p; dj <= p; dj++) { int t = (i + di) * n + (j + dj); if (t < 0 || t == vi || t >= n * n) { continue; } if (Math.abs(di) + Math.abs(dj) <= p && (isDirected || t > i * n + j)) { target.addEdge(v, nodes.get(t)); } } } } } /* * Add long-range contacts */ double[] p = new double[n * n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { V v = nodes.get(i * n + j); /* * Create inverse r power distribution */ double sum = 0d; for (int oi = 0; oi < n; oi++) { for (int oj = 0; oj < n; oj++) { if (oi != i || oj != j) { double weight = Math.pow(Math.abs(i - oi) + Math.abs(j - oj), -r); p[oi * n + oj] = weight; sum += weight; } } } p[i * n + j] = 0d; for (int k = 0; k < n * n; k++) { p[k] /= sum; } /* * Sample from distribution and add long-range edges */ AliasMethodSampler sampler = new AliasMethodSampler(p, rng); for (int k = 0; k < q; k++) { V u = nodes.get(sampler.next()); if (!u.equals(v) && !target.containsEdge(v, u)) { target.addEdge(v, u); } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy