private static WorkVertex getBfsPred(WorkVertex v) { return (WorkVertex) v.getData(); }
/** * @param maxSize Must be != 0. * @return True if must stop, false otherwise. */ private static boolean computeShortestCycles_onScc( ArrayList<InterfaceVertex> scc, int maxSize, InterfaceVertexCollProcessor processor) { if (maxSize == 0) { throw new AssertionError(); } /* * Dealing with SCCs of size 1 (and with cycles of size 1 along with that), * early, before creating a work graph, because it's the common case for * graphs with no or few cycles. */ for (InterfaceVertex v : scc) { // Might have vertices outside the SCC as successors, // so need to use contains(...). if (v.successors().contains(v)) { // Has itself as successor. if (processOneBackingVertexCycle(v, processor)) { return true; } } } if ((scc.size() == 1) || (maxSize == 1)) { // No need to go further here. return false; } /* * Using a work graph, not so much to have predecessors (which could * easily be computed by iterating on successors of each vertex), than * not to have edges dangling outside the SCC, and to be able to remove * cycles of size 1, to make things simpler. */ final ArrayList<WorkVertex> workScc = WorkGraphUtilz.newWorkGraphAsArrayList(scc); // Removing elementary circuits (already processed if any). for (WorkVertex v : workScc) { WorkGraphUtilz.removeEdge(v, v); } /* * */ final ArrayList<WorkVertex> bfsPredCleanupList = new ArrayList<WorkVertex>(); // Sets initially never empty, since we are in an SCC of size > 1, // and mapping is removed when set gets empty, to help memory. final Map<WorkVertex, Set<WorkVertex>> predToVisitSetByVertex = new HashMap<WorkVertex, Set<WorkVertex>>(); for (WorkVertex v : workScc) { predToVisitSetByVertex.put(v, new HashSet<WorkVertex>(v.predecessors())); } if (MUST_SORT_VERTICES) { SortUtils.sort(workScc, WORK_VERTEX_COMPARATOR); } /* * name_in_paper/name_in_code: * * parent: predecessor (parent/child more suited to tree-like graphs) * x: x (vertex) * A: predToVisitSet (set of vertices) * Q: queue (FIFO of vertices) * p: v (vertex) * y: succ (Vertex) * c: cycle * B: v.successors() (set of vertices) */ for (WorkVertex x : workScc) { final Set<WorkVertex> predToVisitSet = predToVisitSetByVertex.get(x); if (predToVisitSet == null) { // Corresponding cycles already taken care of. continue; } resetAndClear(bfsPredCleanupList); setBfsPredWithCleanup(x, TOMBSTONE, bfsPredCleanupList); final LinkedList<WorkVertex> queue = new LinkedList<WorkVertex>(); push(queue, x); while (predToVisitSet.size() != 0) { // Queue must not be empty, as long as we work on a SCC. final WorkVertex v = pop(queue); for (WorkVertex succ : v.successors()) { /* * Modif/paper: simpler conditional code. */ if (getBfsPred(succ) == null) { // Not yet "visited" nor enqueued. setBfsPredWithCleanup(succ, v, bfsPredCleanupList); push(queue, succ); } if (removeAndCleanupIfEmpty( predToVisitSet, succ, // predToVisitSetByVertex, x)) { /* * Found a new cycle. */ final ArrayList<WorkVertex> cycle = newReversedCycle(workScc.size(), succ); final boolean smallEnoughForProcess = (maxSize < 0) || (cycle.size() <= maxSize); if (smallEnoughForProcess) { dereverse(cycle); if (processCycle(cycle, processor)) { return true; } /* * Modif/paper: removal of already covered edges. */ removeCycleEdges(predToVisitSetByVertex, cycle); } } } } } return false; }
private static void setBfsPred(WorkVertex v, WorkVertex bfsPred) { v.setData(bfsPred); }
// @Override public int compare(WorkVertex v1, WorkVertex v2) { final int n1 = v1.successors().size(); final int n2 = v2.successors().size(); // No overflow since both >= 0. return n1 - n2; }