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

org.jgrapht.generate.WattsStrogatzGraphGenerator 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.util.*;

import java.util.*;

/**
 * Watts-Strogatz small-world graph generator.
 * 
 * 

* The generator is described in the paper: D. J. Watts and S. H. Strogatz. Collective dynamics of * small-world networks. Nature 393(6684):440--442, 1998. * *

* The following paragraph from the paper describes the construction. * *

* "The generator starts with a ring of $n$ vertices, each connected to its $k$ nearest neighbors * ($k$ must be even). Then it chooses a vertex and the edge that connects it to its nearest * neighbor in a clockwise sense. With probability $p$, it reconnects this edge to a vertex chosen * uniformly at random over the entire ring with duplicate edges forbidden; otherwise it leaves the * edge in place. The process is repeated by moving clock-wise around the ring, considering each * vertex in turn until one lap is completed. Next, it considers the edges that connect vertices to * their second-nearest neighbors clockwise. As before, it randomly rewires each of these edges with * probability $p$, and continues this process, circulating around the ring and proceeding outward * to more distant neighbors after each lap, until each edge in the original lattice has been * considered once. As there are $\frac{nk}{2}$ edges in the entire graph, the rewiring process * stops after $\frac{k}{2}$ laps. For $p = 0$, the original ring is unchanged; as $p$ increases, * the graph becomes increasingly disordered until for $p = 1$, all edges are rewired randomly. For * intermediate values of $p$, the graph is a small-world network: highly clustered like a regular * graph, yet with small characteristic path length, like a random graph." * *

* The authors require $n \gg k \gg \ln(n) \gg 1$ and specifically $k \gg \ln(n)$ guarantees that a * random graph will be connected. * *

* Through the constructor parameter the model can be slightly changed into adding shortcut edges * instead of re-wiring. This variation was proposed in the paper: M. E. J. Newman and D. J. Watts, * Renormalization group analysis of the small-world network model, Physics Letters A, 263, 341, * 1999. * * @author Dimitrios Michail * * @param the graph vertex type * @param the graph edge type */ public class WattsStrogatzGraphGenerator implements GraphGenerator { private static final boolean DEFAULT_ADD_INSTEAD_OF_REWIRE = false; private final Random rng; private final int n; private final int k; private final double p; private final boolean addInsteadOfRewire; /** * Constructor * * @param n the number of nodes * @param k connect each node to its k nearest neighbors in a ring * @param p the probability of re-wiring each edge * @throws IllegalArgumentException in case of invalid parameters */ public WattsStrogatzGraphGenerator(int n, int k, double p) { this(n, k, p, DEFAULT_ADD_INSTEAD_OF_REWIRE, new Random()); } /** * Constructor * * @param n the number of nodes * @param k connect each node to its k nearest neighbors in a ring * @param p the probability of re-wiring each edge * @param seed seed for the random number generator * @throws IllegalArgumentException in case of invalid parameters */ public WattsStrogatzGraphGenerator(int n, int k, double p, long seed) { this(n, k, p, DEFAULT_ADD_INSTEAD_OF_REWIRE, new Random(seed)); } /** * Constructor * * @param n the number of nodes * @param k connect each node to its k nearest neighbors in a ring * @param p the probability of re-wiring each edge * @param addInsteadOfRewire whether to add shortcut edges instead of re-wiring * @param rng the random number generator to use * @throws IllegalArgumentException in case of invalid parameters */ public WattsStrogatzGraphGenerator( int n, int k, double p, boolean addInsteadOfRewire, Random rng) { if (n < 3) { throw new IllegalArgumentException("number of vertices must be at least 3"); } this.n = n; if (k < 1) { throw new IllegalArgumentException("number of k-nearest neighbors must be positive"); } if (k % 2 == 1) { throw new IllegalArgumentException("number of k-nearest neighbors must be even"); } if (k > n - 2 + (n % 2)) { throw new IllegalArgumentException("invalid k-nearest neighbors"); } this.k = k; if (p < 0.0 || p > 1.0) { throw new IllegalArgumentException("invalid probability"); } this.p = p; this.rng = Objects.requireNonNull(rng, "Random number generator cannot be null"); this.addInsteadOfRewire = addInsteadOfRewire; } /** * Generates a small-world graph based on the Watts-Strogatz model. * * @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; } // create ring lattice List ring = new ArrayList<>(n); Map> adj = CollectionUtil.newLinkedHashMapWithExpectedSize(n); for (int i = 0; i < n; i++) { V v = target.addVertex(); ring.add(v); adj.put(v, new ArrayList<>(k)); } for (int i = 0; i < n; i++) { V vi = ring.get(i); List viAdj = adj.get(vi); for (int j = 1; j <= k / 2; j++) { viAdj.add(target.addEdge(vi, ring.get((i + j) % n))); } } // re-wire edges for (int r = 0; r < k / 2; r++) { for (int i = 0; i < n; i++) { if (rng.nextDouble() < p) { V v = ring.get(i); E e = adj.get(v).get(r); V other = ring.get(rng.nextInt(n)); if (!other.equals(v) && !target.containsEdge(v, other)) { if (!addInsteadOfRewire) { target.removeEdge(e); } target.addEdge(v, other); } } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy