/** * */ package org.bhave.network.model.impl; import java.util.ArrayList; import java.util.Collections; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.math3.random.RandomGenerator; import org.bhave.network.api.Link; import org.bhave.network.api.Network; import org.bhave.network.api.Node; import org.bhave.network.model.KRegularModel; import org.bhave.network.model.WSModel; import org.bhave.network.model.utils.NetworkModelUtils; import com.google.inject.Inject; import com.google.inject.Provider; /** * @author Davide Nunes * */ public class DefaultWSModel extends AbstractNetworkModel implements WSModel { private static final String PARAM_NUM_NODES = P_NUM_NODES; private static final String PARAM_DEGREE = P_D; private static final String PARAM_REATTACHP = P_P; private final KRegularModel regularModel; @Inject public DefaultWSModel(Configuration config, RandomGenerator random, Provider<Network> networkProvider, KRegularModel regularModel) { super(config, random, networkProvider); this.regularModel = regularModel; } @Override void generateNetwork() { int n = config.getInt(PARAM_NUM_NODES); double p = config.getDouble(PARAM_REATTACHP); // regular model was already configured and is ready to be used network = regularModel.generate(); ArrayList<Link> links = new ArrayList<>(network.getLinks()); if (p > 0) { for (int l = 0; l < links.size(); l++) { double r = random.nextDouble(); // re-wire the current link if (r < p) { Pair<Node, Node> nodes = links.get(l).nodes(); // get a random node excluding its current neighbours ArrayList<Integer> toExclude = new ArrayList<>(); // the first node is to be excluded toExclude.add(nodes.getLeft().getID()); for (Node neighbour : network .getNeighbours(nodes.getLeft())) { toExclude.add(neighbour.getID()); } Collections.sort(toExclude); int[] exclude = new int[toExclude.size()]; for (int i = 0; i < toExclude.size(); i++) { exclude[i] = toExclude.get(i); } int newPartner = NetworkModelUtils.getRandomNode(random, n, exclude); network.removeLink(links.get(l)); network.addLink(nodes.getLeft(), network.getNode(newPartner)); } } } } @Override public void configure(Configuration configuration) throws ConfigurationException { int numNodes = configuration.getInt(PARAM_NUM_NODES); int d = configuration.getInt(PARAM_DEGREE); double p = configuration.getDouble(PARAM_REATTACHP); long seed = config.getLong(PARAM_SEED); if (numNodes < 0) { throw new ConfigurationException(PARAM_NUM_NODES + "must be positive"); } if (d < 1 || d > ((numNodes - 1) / 2)) { throw new ConfigurationException(PARAM_DEGREE + "must be within: 1 <= d <= ((n-1)/ 2)"); } if (p < 0 || p >= 1) { throw new ConfigurationException(PARAM_REATTACHP + "must be within: 0 <= p < 1"); } // also configures the kRegular network model regularModel.configure(numNodes, d, seed); } @Override Configuration defaultConfiguration(Configuration config) { config.setProperty(PARAM_NUM_NODES, 10); config.setProperty(PARAM_DEGREE, 2); config.setProperty(PARAM_REATTACHP, 0.2); config.setProperty(PARAM_SEED, System.currentTimeMillis()); return config; } @Override public void configure(int numNodes, int k, double p, long seed) throws ConfigurationException { this.config.setProperty(PARAM_NUM_NODES, numNodes); this.config.setProperty(PARAM_DEGREE, k); this.config.setProperty(PARAM_REATTACHP, p); this.config.setProperty(PARAM_SEED, seed); configure(this.config); } }