/**
   * Finds the set of clusters which have the strongest "community structure". The more edges
   * removed the smaller and more cohesive the clusters.
   *
   * @param graph the graph
   */
  public Set<Set<V>> transform(Graph<V, E> graph) {

    if (mNumEdgesToRemove < 0 || mNumEdgesToRemove > graph.getEdgeCount()) {
      throw new IllegalArgumentException("Invalid number of edges passed in.");
    }

    edges_removed.clear();

    for (int k = 0; k < mNumEdgesToRemove; k++) {
      BetweennessCentrality<V, E> bc = new BetweennessCentrality<V, E>(graph);
      E to_remove = null;
      double score = 0;
      for (E e : graph.getEdges()) {
        Integer weight = mWeight.get(e);
        if (bc.getEdgeScore(e) / weight > score) {
          to_remove = e;
          score = bc.getEdgeScore(e) / weight;
        }
      }
      edges_removed.put(to_remove, graph.getEndpoints(to_remove));
      graph.removeEdge(to_remove);
    }

    WeakComponentClusterer<V, E> wcSearch = new WeakComponentClusterer<V, E>();
    Set<Set<V>> clusterSet = wcSearch.transform(graph);

    for (Map.Entry<E, Pair<V>> entry : edges_removed.entrySet()) {
      Pair<V> endpoints = entry.getValue();
      graph.addEdge(entry.getKey(), endpoints.getFirst(), endpoints.getSecond());
    }
    return clusterSet;
  }
Пример #2
0
  protected void initialize(Graph<V, E> graph) {
    this.graph = graph;
    this.vertex_scores = new HashMap<V, Double>();
    this.edge_scores = new HashMap<E, Double>();
    this.vertex_data = new HashMap<V, BetweennessData>();

    for (V v : graph.getVertices()) this.vertex_scores.put(v, 0.0);

    for (E e : graph.getEdges()) this.edge_scores.put(e, 0.0);
  }
Пример #3
0
  /**
   * Calculates betweenness scores based on the all-pairs weighted shortest paths in the graph.
   *
   * <p>NOTE: This version of the algorithm may not work correctly on all graphs; we're still
   * working out the bugs. Use at your own risk.
   *
   * @param graph the graph for which the scores are to be calculated
   * @param edge_weights the edge weights to be used in the path length calculations
   */
  public BetweennessCentrality(Graph<V, E> graph, Transformer<E, ? extends Number> edge_weights) {
    // reject negative-weight edges up front
    for (E e : graph.getEdges()) {
      double e_weight = edge_weights.transform(e).doubleValue();
      if (e_weight < 0)
        throw new IllegalArgumentException("Weight for edge '" + e + "' is < 0: " + e_weight);
    }

    initialize(graph);
    computeBetweenness(new MapBinaryHeap<V>(new BetweennessComparator()), edge_weights);
  }
Пример #4
0
  /**
   * Searches the graph and searches for the shortest path from a given start node to the
   * destination. Returns {@code null} if there are no vertices, edges, or path to the goal,
   * otherwise a list with the order of vertices on the shortest path.
   *
   * @param graph The graph to search
   * @param source The vertex to start the search from
   * @param destination The goal vertex
   * @return A list with the order of vertices on the shortest path, null if no path exists in the
   *     graph.
   */
  public List<V> search(Graph<V, E> graph, V source, V destination) {

    // Check if it is even possible to find a path, return null
    // if the graph has no vertices or edges
    if (graph.getVertexCount() == 0) {
      System.out.println("No nodes in the graph, " + "no shortest path can be found");
      return null;
    } else if (graph.getEdgeCount() == 0) {
      System.out.println("No edges in graph, no path " + "can be found");
      return null;
    }

    // Keep record of distance to each vertex, map each vertex
    // in the graph to it's distance
    HashMap<V, Number> distanceTable = new HashMap<>();

    // Unvisited node queue, uses a pair <Vertex, Double> and ordered
    // by the distance to the vertex
    PriorityQueue<Pair<V, Number>> queue = new PriorityQueue<>(new QueueComparator());

    // Map of nodes on the path, parents is value, key is child
    HashMap<V, V> parent = new HashMap<>();

    Number maxValue;
    E edgeTest = graph.getEdges().iterator().next();

    // This is so ugly, I hate Java Numbers
    int numberType = 0;
    if (edgeTest.getWeight() instanceof Integer) {
      numberType = 1;
    } else if (edgeTest.getWeight() instanceof Double) {
      numberType = 2;
    }
    // Place each vertex in the map, initialize distances and put
    // the pairings into the queue.
    for (V vertex : graph.getVertices()) {
      if (numberType == 1) {
        maxValue = Integer.MAX_VALUE;
        if (vertex.equals(source)) {
          distanceTable.put(source, 0);
          queue.add(new Pair<>(vertex, 0));
        } else {
          distanceTable.put(vertex, Integer.MAX_VALUE);
          queue.add(new Pair<>(vertex, maxValue));
        }
      } else if (numberType == 2) {
        maxValue = Double.MAX_VALUE;
        if (vertex.equals(source)) {
          distanceTable.put(source, 0.0);
          queue.add(new Pair<>(vertex, 0.0));
        } else {
          distanceTable.put(vertex, Double.MAX_VALUE);
          queue.add(new Pair<>(vertex, maxValue));
        }
      }
    }

    parent.put(source, null);

    while (!queue.isEmpty()) {

      Pair<V, Number> topPair = queue.remove();
      V vertex = topPair.getLeft();

      // Goal test, return the list of nodes on the path
      // if we reach the destination
      if (vertex.equals(destination)) {
        return tracePath(parent, destination);
      }

      Collection<V> neighbours = graph.getNeighbors(vertex);

      for (V neighbour : neighbours) {

        E edge = graph.findEdge(vertex, neighbour);
        assert (edge != null);

        // Test for type of number used for weight, work accordingly
        // Did I mention I hate the Java Number class.
        if (numberType == 1) {

          Integer alternateDistance = (Integer) edge.getWeight();

          if (alternateDistance < (Integer) distanceTable.get(neighbour)) {
            distanceTable.put(neighbour, alternateDistance);
            parent.put(neighbour, vertex);
            queue.add(new Pair<>(neighbour, alternateDistance));
          }
        } else if (numberType == 2) {
          Double alternateDistance = (Double) edge.getWeight();

          if (alternateDistance < (Double) distanceTable.get(neighbour)) {
            distanceTable.put(neighbour, alternateDistance);
            parent.put(neighbour, vertex);
            queue.add(new Pair<>(neighbour, alternateDistance));
          }
        }
      }
    }
    // Exhausted all possible paths from source, could not find a path
    // to the goal.
    return null;
  }
Пример #5
0
  public void testMixedSaveLoadSave() throws IOException {
    Graph<Number, Number> graph1 = new SparseMultigraph<Number, Number>();
    for (int i = 0; i < 5; i++) {
      graph1.addVertex(i);
    }
    int j = 0;

    List<Number> id = new ArrayList<Number>(graph1.getVertices());
    GreekLabels<Number> gl = new GreekLabels<Number>(id);
    Number[] edges = {0, 1, 2, 3, 4, 5};

    graph1.addEdge(j++, 0, 1, EdgeType.DIRECTED);
    graph1.addEdge(j++, 0, 2, EdgeType.DIRECTED);
    graph1.addEdge(j++, 1, 2, EdgeType.DIRECTED);
    graph1.addEdge(j++, 1, 3);
    graph1.addEdge(j++, 1, 4);
    graph1.addEdge(j++, 4, 3);

    Map<Number, Number> nr = new HashMap<Number, Number>();
    for (int i = 0; i < edges.length; i++) {
      nr.put(edges[i], new Float(Math.random()));
    }

    assertEquals(graph1.getEdgeCount(), 6);

    //        System.err.println(" mixed graph1 = "+graph1);
    //        for(Number edge : graph1.getEdges()) {
    //        	System.err.println("edge "+edge+" is directed? "+graph1.getEdgeType(edge));
    //        }
    //        for(Number v : graph1.getVertices()) {
    //        	System.err.println(v+" outedges are "+graph1.getOutEdges(v));
    //        	System.err.println(v+" inedges are "+graph1.getInEdges(v));
    //        	System.err.println(v+" incidentedges are "+graph1.getIncidentEdges(v));
    //        }

    String testFilename = "mtest.net";
    String testFilename2 = testFilename + "2";

    // assign arbitrary locations to each vertex
    Map<Number, Point2D> locations = new HashMap<Number, Point2D>();
    for (Number v : graph1.getVertices()) {
      locations.put(v, new Point2D.Double(v.intValue() * v.intValue(), 1 << v.intValue()));
    }
    Function<Number, Point2D> vld = Functions.forMap(locations);

    PajekNetWriter<Number, Number> pnw = new PajekNetWriter<Number, Number>();
    pnw.save(graph1, testFilename, gl, Functions.forMap(nr), vld);

    Graph<Number, Number> graph2 = pnr.load(testFilename, graphFactory);
    Function<Number, String> pl = pnr.getVertexLabeller();
    List<Number> id2 = new ArrayList<Number>(graph2.getVertices());
    Function<Number, Point2D> vld2 = pnr.getVertexLocationTransformer();

    assertEquals(graph1.getVertexCount(), graph2.getVertexCount());
    assertEquals(graph1.getEdgeCount(), graph2.getEdgeCount());

    // test vertex labels and locations
    for (int i = 0; i < graph1.getVertexCount(); i++) {
      Number v1 = id.get(i);
      Number v2 = id2.get(i);
      assertEquals(gl.apply(v1), pl.apply(v2));
      assertEquals(vld.apply(v1), vld2.apply(v2));
    }

    // test edge weights
    Function<Number, Number> nr2 = pnr.getEdgeWeightTransformer();
    for (Number e2 : graph2.getEdges()) {
      Pair<Number> endpoints = graph2.getEndpoints(e2);
      Number v1_2 = endpoints.getFirst();
      Number v2_2 = endpoints.getSecond();
      Number v1_1 = id.get(id2.indexOf(v1_2));
      Number v2_1 = id.get(id2.indexOf(v2_2));
      Number e1 = graph1.findEdge(v1_1, v2_1);
      assertNotNull(e1);
      assertEquals(nr.get(e1).floatValue(), nr2.apply(e2).floatValue(), 0.0001);
    }

    pnw.save(graph2, testFilename2, pl, nr2, vld2);

    compareIndexedGraphs(graph1, graph2);

    pnr.setVertexLabeller(null);
    Graph<Number, Number> graph3 = pnr.load(testFilename2, graphFactory);

    compareIndexedGraphs(graph2, graph3);

    File file1 = new File(testFilename);
    File file2 = new File(testFilename2);

    Assert.assertTrue(file1.length() == file2.length());
    file1.delete();
    file2.delete();
  }
Пример #6
0
  protected void computeBetweenness(Queue<V> queue, Transformer<E, ? extends Number> edge_weights) {
    for (V v : graph.getVertices()) {
      // initialize the betweenness data for this new vertex
      for (V s : graph.getVertices()) this.vertex_data.put(s, new BetweennessData());

      // if (v.equals(new Integer(0)))
      // System.out.println("pause");

      vertex_data.get(v).numSPs = 1;
      vertex_data.get(v).distance = 0;

      Stack<V> stack = new Stack<V>();
      // Buffer<V> queue = new UnboundedFifoBuffer<V>();
      // queue.add(v);
      queue.offer(v);

      while (!queue.isEmpty()) {
        // V w = queue.remove();
        V w = queue.poll();
        stack.push(w);
        BetweennessData w_data = vertex_data.get(w);

        for (E e : graph.getOutEdges(w)) {
          // TODO (jrtom): change this to getOtherVertices(w, e)
          V x = graph.getOpposite(w, e);
          if (x.equals(w)) continue;
          double wx_weight = edge_weights.transform(e).doubleValue();

          // for(V x : graph.getSuccessors(w))
          // {
          // if (x.equals(w))
          // continue;

          // FIXME: the other problem is that I need to
          // keep putting the neighbors of things we've just
          // discovered in the queue, if they're undiscovered or
          // at greater distance.

          // FIXME: this is the problem, right here, I think:
          // need to update position in queue if distance changes
          // (which can only happen with weighted edges).
          // for each outgoing edge e from w, get other end x
          // if x not already visited (dist x < 0)
          // set x's distance to w's dist + edge weight
          // add x to queue; pri in queue is x's dist
          // if w's dist + edge weight < x's dist
          // update x's dist
          // update x in queue (MapBinaryHeap)
          // clear x's incoming edge list
          // if w's dist + edge weight = x's dist
          // add e to x's incoming edge list

          BetweennessData x_data = vertex_data.get(x);
          double x_potential_dist = w_data.distance + wx_weight;

          if (x_data.distance < 0) {
            // queue.add(x);
            // vertex_data.get(x).distance =
            // vertex_data.get(w).distance + 1;
            x_data.distance = x_potential_dist;
            queue.offer(x);
          }

          // note:
          // (1) this can only happen with weighted edges
          // (2) x's SP count and incoming edges are updated below
          if (x_data.distance > x_potential_dist) {
            x_data.distance = x_potential_dist;
            // invalidate previously identified incoming edges
            // (we have a new shortest path distance to x)
            x_data.incomingEdges.clear();
            // update x's position in queue
            ((MapBinaryHeap<V>) queue).update(x);
          }
          // if (vertex_data.get(x).distance ==
          // vertex_data.get(w).distance + 1)
          //
          // if (x_data.distance == x_potential_dist)
          // {
          // x_data.numSPs += w_data.numSPs;
          //// vertex_data.get(x).predecessors.add(w);
          // x_data.incomingEdges.add(e);
          // }
        }
        for (E e : graph.getOutEdges(w)) {
          V x = graph.getOpposite(w, e);
          if (x.equals(w)) continue;
          double e_weight = edge_weights.transform(e).doubleValue();
          BetweennessData x_data = vertex_data.get(x);
          double x_potential_dist = w_data.distance + e_weight;
          if (x_data.distance == x_potential_dist) {
            x_data.numSPs += w_data.numSPs;
            // vertex_data.get(x).predecessors.add(w);
            x_data.incomingEdges.add(e);
          }
        }
      }
      while (!stack.isEmpty()) {
        V x = stack.pop();

        // for (V w : vertex_data.get(x).predecessors)
        for (E e : vertex_data.get(x).incomingEdges) {
          V w = graph.getOpposite(x, e);
          double partialDependency =
              vertex_data.get(w).numSPs
                  / vertex_data.get(x).numSPs
                  * (1.0 + vertex_data.get(x).dependency);
          vertex_data.get(w).dependency += partialDependency;
          // E w_x = graph.findEdge(w, x);
          // double w_x_score = edge_scores.get(w_x).doubleValue();
          // w_x_score += partialDependency;
          // edge_scores.put(w_x, w_x_score);
          double e_score = edge_scores.get(e).doubleValue();
          edge_scores.put(e, e_score + partialDependency);
        }
        if (!x.equals(v)) {
          double x_score = vertex_scores.get(x).doubleValue();
          x_score += vertex_data.get(x).dependency;
          vertex_scores.put(x, x_score);
        }
      }
    }

    if (graph instanceof UndirectedGraph) {
      for (V v : graph.getVertices()) {
        double v_score = vertex_scores.get(v).doubleValue();
        v_score /= 2.0;
        vertex_scores.put(v, v_score);
      }
      for (E e : graph.getEdges()) {
        double e_score = edge_scores.get(e).doubleValue();
        e_score /= 2.0;
        edge_scores.put(e, e_score);
      }
    }

    vertex_data.clear();
  }