/**
   * Compute the unique decomposition of the input graph G (atoms of G). Implementation of algorithm
   * Atoms as described in Berry et al. (2010), DOI:10.3390/a3020197, <a
   * href="http://www.mdpi.com/1999-4893/3/2/197">http://www.mdpi.com/1999-4893/3/2/197</a>
   */
  private void computeAtoms() {
    if (chordalGraph == null) {
      computeMinimalTriangulation();
    }

    separators = new HashSet<>();

    // initialize g' as subgraph of graph (same vertices and edges)
    UndirectedGraph<V, E> gprime = copyAsSimpleGraph(graph);

    // initialize h' as subgraph of chordalGraph (same vertices and edges)
    UndirectedGraph<V, E> hprime = copyAsSimpleGraph(chordalGraph);

    atoms = new HashSet<>();

    Iterator<V> iterator = meo.descendingIterator();
    while (iterator.hasNext()) {
      V v = iterator.next();
      if (generators.contains(v)) {
        Set<V> separator = new HashSet<>(Graphs.neighborListOf(hprime, v));

        if (isClique(graph, separator)) {
          if (separator.size() > 0) {
            if (separators.contains(separator)) {
              fullComponentCount.put(separator, fullComponentCount.get(separator) + 1);
            } else {
              fullComponentCount.put(separator, 2);
              separators.add(separator);
            }
          }
          UndirectedGraph<V, E> tmpGraph = copyAsSimpleGraph(gprime);

          tmpGraph.removeAllVertices(separator);
          ConnectivityInspector<V, E> con = new ConnectivityInspector<>(tmpGraph);
          if (con.isGraphConnected()) {
            throw new RuntimeException("separator did not separate the graph");
          }
          for (Set<V> component : con.connectedSets()) {
            if (component.contains(v)) {
              gprime.removeAllVertices(component);
              component.addAll(separator);
              atoms.add(new HashSet<>(component));
              assert (component.size() > 0);
              break;
            }
          }
        }
      }

      hprime.removeVertex(v);
    }

    if (gprime.vertexSet().size() > 0) {
      atoms.add(new HashSet<>(gprime.vertexSet()));
    }
  }
  public void testUndirectedGraphGnp3() {
    GraphGenerator<Integer, DefaultEdge, Integer> gen =
        new GnpRandomBipartiteGraphGenerator<>(4, 4, 0.0, SEED);
    UndirectedGraph<Integer, DefaultEdge> g = new SimpleGraph<>(DefaultEdge.class);
    gen.generateGraph(g, new IntegerVertexFactory(), null);

    assertEquals(4 + 4, g.vertexSet().size());
    assertEquals(0, g.edgeSet().size());
  }
예제 #3
0
  /**
   * This method will return a list of vertices which represents the Eulerian circuit of the graph.
   *
   * @param g The graph to find an Eulerian circuit
   * @return null if no Eulerian circuit exists, or a list of vertices representing the Eulerian
   *     circuit if one does exist
   */
  public static <V, E> List<V> getEulerianCircuitVertices(UndirectedGraph<V, E> g) {
    // If the graph is not Eulerian then just return a null since no
    // Eulerian circuit exists
    if (!isEulerian(g)) {
      return null;
    }

    // The circuit will be represented by a linked list
    List<V> path = new LinkedList<V>();
    UndirectedGraph<V, E> sg = new UndirectedSubgraph<V, E>(g, null, null);
    path.add(sg.vertexSet().iterator().next());

    // Algorithm for finding an Eulerian circuit Basically this will find an
    // arbitrary circuit, then it will find another arbitrary circuit until
    // every edge has been traversed
    while (sg.edgeSet().size() > 0) {
      V v = null;

      // Find a vertex which has an edge that hasn't been traversed yet,
      // and keep its index position in the circuit list
      int index = 0;
      for (Iterator<V> iter = path.iterator(); iter.hasNext(); index++) {
        v = iter.next();
        if (sg.degreeOf(v) > 0) {
          break;
        }
      }

      // Finds an arbitrary circuit of the current vertex and
      // appends this into the circuit list
      while (sg.degreeOf(v) > 0) {
        for (Iterator<V> iter = sg.vertexSet().iterator(); iter.hasNext(); ) {
          V temp = iter.next();
          if (sg.containsEdge(v, temp)) {
            path.add(index, temp);
            sg.removeEdge(v, temp);
            v = temp;
            break;
          }
        }
      }
    }
    return path;
  }
  public void testUndirectedGraphGnp1() {
    GraphGenerator<Integer, DefaultEdge, Integer> gen =
        new GnpRandomBipartiteGraphGenerator<>(4, 4, 0.5, SEED);
    UndirectedGraph<Integer, DefaultEdge> g = new SimpleGraph<>(DefaultEdge.class);
    gen.generateGraph(g, new IntegerVertexFactory(), null);

    int[][] edges = {{1, 6}, {1, 7}, {1, 8}, {2, 5}, {2, 7}, {3, 5}, {3, 8}, {4, 6}, {4, 7}};

    assertEquals(4 + 4, g.vertexSet().size());
    for (int[] e : edges) {
      assertTrue(g.containsEdge(e[0], e[1]));
    }
    assertEquals(edges.length, g.edgeSet().size());
  }
예제 #5
0
  /**
   * This method will check whether the graph passed in is Eulerian or not.
   *
   * @param g The graph to be checked
   * @return true for Eulerian and false for non-Eulerian
   */
  public static <V, E> boolean isEulerian(UndirectedGraph<V, E> g) {
    // If the graph is not connected, then no Eulerian circuit exists
    if (!(new ConnectivityInspector<V, E>(g)).isGraphConnected()) {
      return false;
    }

    // A graph is Eulerian if and only if all vertices have even degree
    // So, this code will check for that
    Iterator<V> iter = g.vertexSet().iterator();
    while (iter.hasNext()) {
      V v = iter.next();
      if ((g.degreeOf(v) % 2) == 1) {
        return false;
      }
    }
    return true;
  }
  /**
   * Create a copy of a graph for internal use.
   *
   * @param graph the graph to copy.
   * @return A copy of the graph projected to a SimpleGraph.
   */
  private static <V, E> UndirectedGraph<V, E> copyAsSimpleGraph(UndirectedGraph<V, E> graph) {
    UndirectedGraph<V, E> copy = new SimpleGraph<>(graph.getEdgeFactory());

    if (graph instanceof SimpleGraph) {
      Graphs.addGraph(copy, graph);
    } else {
      // project graph to SimpleGraph
      Graphs.addAllVertices(copy, graph.vertexSet());
      for (E e : graph.edgeSet()) {
        V v1 = graph.getEdgeSource(e);
        V v2 = graph.getEdgeTarget(e);
        if ((v1 != v2) && !copy.containsEdge(e)) {
          copy.addEdge(v1, v2);
        }
      }
    }
    return copy;
  }
  /**
   * Compute the minimal triangulation of the graph. Implementation of Algorithm MCS-M+ as described
   * in Berry et al. (2010), DOI:10.3390/a3020197 <a href="http://www.mdpi.com/1999-4893/3/2/197">
   * http://www.mdpi.com/1999-4893/3/2/197</a>
   */
  private void computeMinimalTriangulation() {
    // initialize chordGraph with same vertices as graph
    chordalGraph = new SimpleGraph<>(graph.getEdgeFactory());
    for (V v : graph.vertexSet()) {
      chordalGraph.addVertex(v);
    }

    // initialize g' as subgraph of graph (same vertices and edges)
    final UndirectedGraph<V, E> gprime = copyAsSimpleGraph(graph);
    int s = -1;
    generators = new ArrayList<>();
    meo = new LinkedList<>();

    final Map<V, Integer> vertexLabels = new HashMap<>();
    for (V v : gprime.vertexSet()) {
      vertexLabels.put(v, 0);
    }
    for (int i = 1, n = graph.vertexSet().size(); i <= n; i++) {
      V v = getMaxLabelVertex(vertexLabels);
      LinkedList<V> Y = new LinkedList<>(Graphs.neighborListOf(gprime, v));

      if (vertexLabels.get(v) <= s) {
        generators.add(v);
      }

      s = vertexLabels.get(v);

      // Mark x reached and all other vertices of gprime unreached
      HashSet<V> reached = new HashSet<>();
      reached.add(v);

      // mark neighborhood of x reached and add to reach(label(y))
      HashMap<Integer, HashSet<V>> reach = new HashMap<>();

      // mark y reached and add y to reach
      for (V y : Y) {
        reached.add(y);
        addToReach(vertexLabels.get(y), y, reach);
      }

      for (int j = 0; j < graph.vertexSet().size(); j++) {
        if (!reach.containsKey(j)) {
          continue;
        }
        while (reach.get(j).size() > 0) {
          // remove a vertex y from reach(j)
          V y = reach.get(j).iterator().next();
          reach.get(j).remove(y);

          for (V z : Graphs.neighborListOf(gprime, y)) {
            if (!reached.contains(z)) {
              reached.add(z);
              if (vertexLabels.get(z) > j) {
                Y.add(z);
                E fillEdge = graph.getEdgeFactory().createEdge(v, z);
                fillEdges.add(fillEdge);
                addToReach(vertexLabels.get(z), z, reach);
              } else {
                addToReach(j, z, reach);
              }
            }
          }
        }
      }

      for (V y : Y) {
        chordalGraph.addEdge(v, y);
        vertexLabels.put(y, vertexLabels.get(y) + 1);
      }

      meo.addLast(v);
      gprime.removeVertex(v);
      vertexLabels.remove(v);
    }
  }