Beispiel #1
0
    /** {@inheritDoc} */
    protected void encounterVertexAgain(V vertex, E edge) {
      super.encounterVertexAgain(vertex, edge);

      int i;

      if (root != null) {
        // For rooted detection, the path must either
        // double back to the root, or to a node of a cycle
        // which has already been detected.
        if (vertex.equals(root)) {
          i = 0;
        } else if ((cycleSet != null) && cycleSet.contains(vertex)) {
          i = 0;
        } else {
          return;
        }
      } else {
        i = path.indexOf(vertex);
      }

      if (i > -1) {
        if (cycleSet == null) {
          // we're doing yes/no cycle detection
          throw new CycleDetectedException();
        } else {
          for (; i < path.size(); ++i) {
            cycleSet.add(path.get(i));
          }
        }
      }
    }
  /**
   * 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()));
    }
  }
 private V lowestCommonAncestor(V a, V b) {
   Set<V> seen = new HashSet<>();
   for (; ; ) {
     a = contracted.get(a);
     seen.add(a);
     if (!match.containsKey(a)) {
       break;
     }
     a = path.get(match.get(a));
   }
   for (; ; ) {
     b = contracted.get(b);
     if (seen.contains(b)) {
       return b;
     }
     b = path.get(match.get(b));
   }
 }
    /** @see Graph#edgesOf(Object) */
    public Set<E> edgesOf(V vertex) {
      ArrayUnenforcedSet<E> inAndOut = new ArrayUnenforcedSet<E>(getEdgeContainer(vertex).incoming);
      inAndOut.addAll(getEdgeContainer(vertex).outgoing);

      // we have two copies for each self-loop - remove one of them.
      if (allowingLoops) {
        Set<E> loops = getAllEdges(vertex, vertex);

        for (int i = 0; i < inAndOut.size(); ) {
          Object e = inAndOut.get(i);

          if (loops.contains(e)) {
            inAndOut.remove(i);
            loops.remove(e); // so we remove it only once
          } else {
            i++;
          }
        }
      }

      return Collections.unmodifiableSet(inAndOut);
    }
  /**
   * Runs the algorithm on the input graph and returns the match edge set.
   *
   * @return set of Edges
   */
  private Set<E> findMatch() {
    Set<E> result = new ArrayUnenforcedSet<>();
    match = new HashMap<>();
    path = new HashMap<>();
    contracted = new HashMap<>();

    for (V i : graph.vertexSet()) {
      // Any augmenting path should start with _exposed_ vertex
      // (vertex may not escape match-set being added once)
      if (!match.containsKey(i)) {
        // Match is maximal iff graph G contains no more augmenting paths
        V v = findPath(i);
        while (v != null) {
          V pv = path.get(v);
          V ppv = match.get(pv);
          match.put(v, pv);
          match.put(pv, v);
          v = ppv;
        }
      }
    }

    Set<V> seen = new HashSet<>();
    graph
        .vertexSet()
        .stream()
        .filter(v -> !seen.contains(v) && match.containsKey(v))
        .forEach(
            v -> {
              seen.add(v);
              seen.add(match.get(v));
              result.add(graph.getEdge(v, match.get(v)));
            });

    return result;
  }
  private V findPath(V root) {
    Set<V> used = new HashSet<>();
    Queue<V> q = new ArrayDeque<>();

    // Expand graph back from its contracted state
    path.clear();
    contracted.clear();

    graph.vertexSet().forEach(vertex -> contracted.put(vertex, vertex));

    used.add(root);
    q.add(root);

    while (!q.isEmpty()) {
      V v = q.remove();

      for (E e : graph.edgesOf(v)) {
        V to = graph.getEdgeSource(e);

        if (to.equals(v)) {
          to = graph.getEdgeTarget(e);
        }

        if ((contracted.get(v).equals(contracted.get(to))) || to.equals(match.get(v))) {
          continue;
        }

        // Check whether we've hit a 'blossom'
        if ((to.equals(root)) || ((match.containsKey(to)) && (path.containsKey(match.get(to))))) {
          V stem = lowestCommonAncestor(v, to);

          Set<V> blossom = new HashSet<>();

          markPath(v, to, stem, blossom);
          markPath(to, v, stem, blossom);

          graph
              .vertexSet()
              .stream()
              .filter(i -> contracted.containsKey(i) && blossom.contains(contracted.get(i)))
              .forEach(
                  i -> {
                    contracted.put(i, stem);
                    if (!used.contains(i)) {
                      used.add(i);
                      q.add(i);
                    }
                  });

          // Check whether we've had hit a loop (of even length (!) presumably)
        } else if (!path.containsKey(to)) {
          path.put(to, v);

          if (!match.containsKey(to)) {
            return to;
          }

          to = match.get(to);

          used.add(to);
          q.add(to);
        }
      }
    }
    return null;
  }