playground.johannes.socialnets.NetworkGenerator2.java Source code

Java tutorial

Introduction

Here is the source code for playground.johannes.socialnets.NetworkGenerator2.java

Source

/* *********************************************************************** *
 * project: org.matsim.*
 * NetworkGenerator2.java
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 * copyright       : (C) 2008 by the members listed in the COPYING,        *
 *                   LICENSE and WARRANTY file.                            *
 * email           : info at matsim dot org                                *
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *   See also COPYING, LICENSE and WARRANTY file                           *
 *                                                                         *
 * *********************************************************************** */

/**
 * 
 */
package playground.johannes.socialnets;

import gnu.trove.TDoubleDoubleHashMap;
import gnu.trove.TIntIntHashMap;
import gnu.trove.TObjectIntHashMap;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Set;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
import org.apache.log4j.Logger;
import org.matsim.config.Config;
import org.matsim.controler.ScenarioData;
import org.matsim.gbl.Gbl;
import org.matsim.population.Person;
import org.matsim.population.Population;
import org.matsim.utils.geometry.Coord;

import playground.johannes.graph.Edge;
import playground.johannes.graph.GraphStatistics;
import playground.johannes.graph.Vertex;
import playground.johannes.graph.io.PajekVisWriter;
import playground.johannes.socialnet.Ego;
import playground.johannes.socialnet.SocialNetwork;
import playground.johannes.statistics.WeightedStatistics;

/**
 * @author illenberger
 *
 */
public class NetworkGenerator2 {

    private static final Logger logger = Logger.getLogger(NetworkGenerator2.class);

    private Random random;

    private final double alpha = 1;

    private final double gamma = 1;

    //   private final int meanDegree = 10;

    private final double scale = 10;

    private final double scale2 = 100;

    private final double scale3 = 100000000;

    private static int rndLinkCount = 0;

    private List<Ego> egoList = new LinkedList<Ego>();

    /**
     * @param args
     * @throws IOException 
     * @throws FileNotFoundException 
     */
    public static void main(String[] args) throws FileNotFoundException, IOException {
        Config config = Gbl.createConfig(args);
        logger.info("Loading network and plans...");
        ScenarioData data = new ScenarioData(config);
        //      final NetworkLayer network = data.getNetwork();
        final Population population = data.getPopulation();

        NetworkGenerator2 g = new NetworkGenerator2();
        SocialNetwork net = g.generate(population);
        dumpStats(net, null, 1);
    }

    private static void dumpStats(SocialNetwork socialNet, String histfile, int it)
            throws FileNotFoundException, IOException {
        int numEdges = socialNet.getEdges().size();
        int numVertices = socialNet.getVertices().size();
        logger.info(String.format("%1$s vertices, %2$s edges.", numVertices, numEdges));

        int isolates = 0;
        for (Vertex v : socialNet.getVertices())
            if (v.getEdges().size() == 0)
                isolates++;
        logger.info(String.format("%1$s isolates.", isolates));

        DescriptiveStatistics stats = GraphStatistics.getDegreeStatistics(socialNet);
        double meanDegree = stats.getMean();
        logger.info(String.format("Mean degree is %1$s.", meanDegree));
        WeightedStatistics wstats = new WeightedStatistics();
        wstats.addAll(stats.getValues());
        WeightedStatistics.writeHistogram(wstats.absoluteDistribution(),
                "/Users/fearonni/vsp-work/socialnets/data-analysis/socialnetgenerator/" + it + ".degreehist.txt");

        double clustering = GraphStatistics.getClusteringStatistics(socialNet).getMean();
        logger.info(String.format("Mean clustering coefficient is %1$s.", clustering));

        double mutuality = GraphStatistics.getMutuality(socialNet);
        logger.info(String.format("Mutuality is %1$s.", mutuality));

        double dcorrelation = GraphStatistics.getDegreeCorrelation(socialNet);
        logger.info(String.format("Degree correlation is %1$s.", dcorrelation));

        //      logger.info(String.format("Closeness is %1$s.", GraphStatistics.getCentrality(socialNet).getGraphCloseness()));
        logger.info("Calculating distance distribution...");
        WeightedStatistics stats3 = new WeightedStatistics();
        //      HashMap<Ego, TDoubleDoubleHashMap> egoHist = new HashMap<Ego, TDoubleDoubleHashMap>();
        double binsize = 1000;
        for (Ego ego : socialNet.getVertices()) {
            TDoubleDoubleHashMap hist = new TDoubleDoubleHashMap();
            Coord c1 = ego.getPerson().getSelectedPlan().getFirstActivity().getCoord();
            for (Ego p2 : socialNet.getVertices()) {

                Coord c2 = p2.getPerson().getSelectedPlan().getFirstActivity().getCoord();
                double d = c1.calcDistance(c2);
                double bin = Math.floor(d / binsize);
                double val = hist.get(bin);
                val++;
                hist.put(bin, val);
            }
            //         egoHist.put(ego, hist);

            for (Vertex n : ego.getNeighbours()) {
                Coord c2 = ((Ego) n).getPerson().getSelectedPlan().getFirstActivity().getCoord();
                double dist = c1.calcDistance(c2);
                stats3.add(dist, 1 / hist.get(Math.floor(dist / binsize)));
            }
        }
        //      WeightedStatistics stats3 = new WeightedStatistics();
        //      for(Object o : socialNet.getEdges()) {
        //         Edge e = (Edge)o;
        //         Ego e1 = (Ego) e.getVertices().getFirst();
        //         Ego e2 = (Ego) e.getVertices().getSecond();
        //         Coord c1 = e1.getPerson().getSelectedPlan().getFirstActivity().getCoord();
        //         Coord c2 = e2.getPerson().getSelectedPlan().getFirstActivity().getCoord();
        //         double dist = c1.calcDistance(c2);
        //         stats3.add(dist);
        //      }
        WeightedStatistics.writeHistogram(stats3.absoluteDistribution(1000),
                "/Users/fearonni/vsp-work/socialnets/data-analysis/socialnetgenerator/" + it + ".edgelength.txt");

        PajekVisWriter pWriter = new PajekVisWriter();
        pWriter.write(socialNet,
                "/Users/fearonni/vsp-work/socialnets/data-analysis/socialnetgenerator/" + it + ".socialnet.net");

        WeightedStatistics stats4 = new WeightedStatistics();
        for (Object o : socialNet.getEdges()) {
            Edge e = (Edge) o;
            Ego e1 = (Ego) e.getVertices().getFirst();
            Ego e2 = (Ego) e.getVertices().getSecond();
            int age1 = e1.getPerson().getAge();
            int age2 = e2.getPerson().getAge();
            double dAge = 0;
            if (age1 > age2)
                dAge = age1 / (double) age2;
            else
                dAge = age2 / (double) age1;
            stats4.add(dAge);
        }
        WeightedStatistics.writeHistogram(stats4.absoluteDistribution(0.05),
                "/Users/fearonni/vsp-work/socialnets/data-analysis/socialnetgenerator/" + it + ".agedist.txt");

        logger.info("Random link selection = " + rndLinkCount);

        logger.info("Number of components = " + GraphStatistics.getComponents(socialNet).size());
    }

    public SocialNetwork generate(Population population) {
        random = new Random();
        logger.info("Initializing social network...");
        SocialNetwork net = new SocialNetwork();

        for (Person p : population) {
            egoList.add(net.addEgo(p));
        }

        logger.info("Initializing degree distribution...");
        TObjectIntHashMap<Ego> stubsMap = initDegreeDistribution(net.getVertices());
        //      try {
        //         dumpStats(net, null, 0);
        //      } catch (FileNotFoundException e) {
        //         // TODO Auto-generated catch block
        //         e.printStackTrace();
        //      } catch (IOException e) {
        //         // TODO Auto-generated catch block
        //         e.printStackTrace();
        //      }

        LinkedList<Ego> pendingNodes = new LinkedList<Ego>(net.getVertices());
        Collections.shuffle(pendingNodes);
        while (!pendingNodes.isEmpty()) {
            logger.info("Starting new component...");
            Ego v1 = pendingNodes.getFirst();
            Collection<Ego> nextWave = new HashSet<Ego>();
            int stubs = stubsMap.get(v1);
            for (int i = 0; i < stubs; i++) {
                Ego n1 = findNeighbour(v1, egoList, stubsMap, false);
                if (n1 == null) {
                    pendingNodes.remove(v1);
                    break;
                }
                if (!formConnection(v1, n1, net, stubsMap)) {
                    /*
                     * Should never happen (?)
                     */
                    int v2stubs = stubsMap.get(v1);
                    int v3stubs = stubsMap.get(n1);
                    System.err.println("The selected neighbour is not valid!" + " v2stubs=" + v2stubs + ", v3stubs="
                            + v3stubs);
                    System.exit(-1);
                } else {
                    nextWave.add(n1);
                    if (stubsMap.get(n1) == 0)
                        pendingNodes.remove(n1);
                }

            }
            if (stubsMap.get(v1) == 0)
                pendingNodes.remove(v1);

            while (!nextWave.isEmpty()) {
                nextWave = closeTriads(nextWave, stubsMap, pendingNodes, net);
            }
        }

        int sum = 0;
        for (int val : stubsMap.getValues()) {
            sum += val;
        }
        System.err.println(sum + " stubs left!");
        return net;
    }

    private Collection<Ego> closeTriads(Collection<Ego> currentWave, TObjectIntHashMap<Ego> stubsMap,
            Collection<Ego> pendingNodes, SocialNetwork net) {
        Collection<Ego> nextWave = new HashSet<Ego>();

        for (Ego v1 : currentWave) {
            Set<Ego> potentialTriads = new HashSet<Ego>();
            if (stubsMap.get(v1) > 0)
                potentialTriads.add(v1);

            for (Vertex n1 : v1.getNeighbours()) {
                for (Vertex n2 : n1.getNeighbours()) {
                    if (n2 != v1) {
                        if (stubsMap.get((Ego) n2) > 0)
                            potentialTriads.add((Ego) n2);
                    }
                }
            }

            for (Ego v2 : potentialTriads) {
                int stubs = stubsMap.get(v2);
                //            System.err.println("Num stubs before = " + stubs);
                //            boolean formedConnection = false;
                for (int i = 0; i < stubs; i++) {
                    List<Ego> potentialTriads2 = new LinkedList<Ego>(potentialTriads);
                    Collections.shuffle(potentialTriads2);

                    for (Ego v3 : potentialTriads2) {
                        if (v2 != v3) {
                            /*
                             * For now, constant clustering
                             */
                            double p = getDyadProba(v2, v3, scale3);
                            if (random.nextDouble() <= p) {

                                if (formConnection(v2, v3, net, stubsMap)) {
                                    //                           formedConnection = true;

                                    if (stubsMap.get(v2) == 0)
                                        pendingNodes.remove(v2);
                                    if (stubsMap.get(v3) == 0)
                                        pendingNodes.remove(v3);

                                    break;
                                }
                            }
                        }
                    }
                }

                if (stubsMap.get(v2) > 0) {
                    Ego v3 = findNeighbour(v2, egoList, stubsMap, true);
                    if (v3 == null) {
                        /*
                         * TODO: This is tricky! Obviously there are no nodes
                         * with open stubs left!
                         */
                        System.err.println("Aborted triad closure. No stubs are left!");
                        return nextWave;
                    }
                    if (formConnection(v2, v3, net, stubsMap)) {
                        if (!currentWave.contains(v3))
                            nextWave.add(v3);

                        if (stubsMap.get(v2) == 0)
                            pendingNodes.remove(v2);
                        if (stubsMap.get(v3) == 0)
                            pendingNodes.remove(v3);
                    } else {
                        int v2stubs = stubsMap.get(v2);
                        int v3stubs = stubsMap.get(v3);
                        System.err.println("The selected neighbour is not valid!" + " v2stubs=" + v2stubs
                                + ", v3stubs=" + v3stubs);
                        System.exit(-1);
                    }
                }

                //            if (stubs - (i + 1) != stubsMap.get(v2)) {
                //               System.err.println("Stub not connected!");
                //            }
                //
                //            // System.err.println("Num stubs after = " + stubsMap.get(v1));
                //            if (stubsMap.get(v2) != 0) {
                //               System.err.println("Vertex has stubs left!");
                //            }
            }
        }

        //      if(nextWave.isEmpty()) {
        //         int triadstubs = 0;
        //         for(Ego v : potentialTriads)
        //            triadstubs += stubsMap.get(v);
        //         System.err.println("Triad stubs = " + triadstubs);
        //         
        //         int totalstubs = 0;
        //         for(Ego v : egoList)
        //            totalstubs += stubsMap.get(v);
        //         System.err.println("Total stubs = " + totalstubs);
        //      }
        return nextWave;
    }

    private TObjectIntHashMap<Ego> initDegreeDistribution(Collection<? extends Ego> egos) {
        TObjectIntHashMap<Ego> stubsMap = new TObjectIntHashMap<Ego>();
        /*
         * For now, uniform degree distribution
         */
        Queue<Ego> egos2 = new LinkedList<Ego>(egos);
        while (!egos2.isEmpty()) {
            Ego e1 = egos2.poll();
            for (Ego e2 : egos) {
                if (random.nextDouble() <= 1 / alpha * getDyadProba(e1, e2, scale)) {
                    stubsMap.adjustOrPutValue(e1, 1, 1);
                    stubsMap.adjustOrPutValue(e2, 1, 1);
                }
            }
        }

        return stubsMap;
    }

    private double getDyadProba(Ego e1, Ego e2, double scale) {
        Coord c1 = e1.getPerson().getSelectedPlan().getFirstActivity().getCoord();
        Coord c2 = e2.getPerson().getSelectedPlan().getFirstActivity().getCoord();
        double d = c1.calcDistance(c2);

        return alpha / Math.pow(1 + d / scale, gamma);
    }

    private Ego findNeighbour(Ego e, List<? extends Ego> egos, TObjectIntHashMap<Ego> stubsMap, boolean bias) {
        Collections.shuffle(egos);
        Ego neighbour = null;
        /*
         * TODO: Probably do Collections.shuffle() here?
         */
        //      TIntIntHashMap pDist = new TIntIntHashMap();
        //      double k = stubsMap.get(e) + e.getNeighbours().size();
        //      Coord c1 = e.getPerson().getSelectedPlan().getFirstActivity().getCoord();
        //      if(bias) {         
        //         for(Vertex n : e.getNeighbours()) {
        //            Coord c2 = ((Ego) n).getPerson().getSelectedPlan().getFirstActivity().getCoord();
        //            double d = c1.calcDistance(c2);
        //            pDist.adjustOrPutValue((int)Math.floor(d/5000.0), 1, 1);
        //         }
        //      }

        for (Ego n : egos) {
            if (n != e) {
                //            Coord c2 = n.getPerson().getSelectedPlan().getFirstActivity().getCoord();
                //            double d = c1.calcDistance(c2);
                //            double p = getDyadProba(e, n) - (pDist.get((int)Math.floor(d/5000.0)) / k);
                double p = getDyadProba(e, n, scale2);
                if (random.nextDouble() <= p) {
                    if (!n.getNeighbours().contains(e) && stubsMap.get(n) > 0) {
                        neighbour = n;
                        break;
                    }
                }
            }
        }
        /*
         * If no neighbor has been found, choose one by random.
         */
        if (neighbour == null) {
            rndLinkCount++;
            for (Ego n : egos) {
                if (n != e) {
                    if (!n.getNeighbours().contains(e) && stubsMap.get(n) > 0) {
                        neighbour = n;
                        break;
                    }
                }
            }
        }

        return neighbour;
    }

    private boolean formConnection(Ego e1, Ego e2, SocialNetwork net, TObjectIntHashMap<Ego> stubsMap) {
        if (e1 == e2)
            return false;

        if (stubsMap.get(e1) > 0 && stubsMap.get(e2) > 0) {
            if (!e1.getNeighbours().contains(e2)) {
                net.addEdge(e1, e2);
                if (!stubsMap.adjustValue(e1, -1))
                    System.exit(-1);
                if (!stubsMap.adjustValue(e2, -1))
                    System.exit(-1);
                return true;
            } else {
                return false;
            }
        } else {
            //         System.err.println("Connection cannot be formed because no stubs are left!");
            return false;
        }
    }
}