All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.salesforce.jgrapht.alg.cycle.HawickJamesSimpleCycles Maven / Gradle / Ivy

Go to download

This project contains the apt processor that implements all the checks enumerated in @Verify. It is a self contained, and shaded jar.

There is a newer version: 2.0.7
Show newest version
/*
 * (C) Copyright 2014-2017, by Luiz Kill and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package com.salesforce.jgrapht.alg.cycle;

import java.util.*;

import com.salesforce.jgrapht.*;

/**
 * Find all simple cycles of a directed graph using the algorithm described by Hawick and James.
 *
 * 

* See:
* K. A. Hawick, H. A. James. Enumerating Circuits and Loops in Graphs with Self-Arcs and * Multiple-Arcs. Computational Science Technical Note CSTN-013, 2008 * * @param the vertex type. * @param the edge type. * * @author Luiz Kill */ public class HawickJamesSimpleCycles implements DirectedSimpleCycles { private enum Operation { ENUMERATE, PRINT_ONLY, COUNT_ONLY } // The graph private DirectedGraph graph = null; // Number of vertices private int nVertices = 0; // Number of simple cycles private long nCycles = 0; // Simple cycles found private List> cycles = null; // The main state of the algorithm private Integer start = 0; private List[] Ak = null; private List[] B = null; private boolean[] blocked = null; private ArrayDeque stack = null; // Giving an index to every V private V[] iToV = null; private Map vToI = null; /** * Create a simple cycle finder with an unspecified graph. */ public HawickJamesSimpleCycles() { } /** * Create a simple cycle finder for the specified graph. * * @param graph the DirectedGraph in which to find cycles. * * @throws IllegalArgumentException if the graph argument is * null. */ public HawickJamesSimpleCycles(DirectedGraph graph) throws IllegalArgumentException { if (graph == null) { throw new IllegalArgumentException("Null graph argument."); } this.graph = graph; } @SuppressWarnings("unchecked") private void initState(Operation o) { nCycles = 0; nVertices = graph.vertexSet().size(); if (o == Operation.ENUMERATE) { cycles = new ArrayList<>(); } blocked = new boolean[nVertices]; stack = new ArrayDeque<>(nVertices); B = new ArrayList[nVertices]; for (int i = 0; i < nVertices; i++) { // B[i] = new ArrayList(nVertices); B[i] = new ArrayList<>(); } iToV = (V[]) graph.vertexSet().toArray(); vToI = new HashMap<>(); for (int i = 0; i < iToV.length; i++) { vToI.put(iToV[i], i); } Ak = buildAdjacencyList(); stack.clear(); } @SuppressWarnings("unchecked") private List[] buildAdjacencyList() { @SuppressWarnings("rawtypes") List[] Ak = new ArrayList[nVertices]; for (int j = 0; j < nVertices; j++) { V v = iToV[j]; List s = Graphs.successorListOf(graph, v); Ak[j] = new ArrayList(s.size()); for (V value : s) { Ak[j].add(vToI.get(value)); } } return Ak; } private void clearState() { Ak = null; nVertices = 0; blocked = null; stack = null; iToV = null; vToI = null; Ak = null; B = null; } private boolean circuit(Integer v, Operation o) { boolean f = false; stack.push(v); blocked[v] = true; for (Integer w : Ak[v]) { if (w < start) { continue; } if (w == start) { if (o == Operation.ENUMERATE) { List cycle = new ArrayList<>(stack.size()); Iterator iteratorStack = stack.iterator(); while (iteratorStack.hasNext()) { cycle.add(iToV[iteratorStack.next()]); } cycles.add(cycle); } if (o == Operation.PRINT_ONLY) { for (Integer i : stack) { System.out.print(iToV[i].toString() + " "); } System.out.println(""); } nCycles++; f = true; } else if (!blocked[w]) { if (circuit(w, o)) { f = true; } } } if (f) { unblock(v); } else { for (Integer w : Ak[v]) { if (w < start) { continue; } if (!B[w].contains(v)) { B[w].add(v); } } } stack.pop(); return f; } private void unblock(Integer u) { blocked[u] = false; for (int wPos = 0; wPos < B[u].size(); wPos++) { Integer w = B[u].get(wPos); wPos -= removeFromList(B[u], w); if (blocked[w]) { unblock(w); } } } /** * Remove all occurrences of a value from the list. * * @param u the Integer to be removed. * @param list the list from which all the occurrences of u must be removed. */ private int removeFromList(List list, Integer u) { int nOccurrences = 0; Iterator iterator = list.iterator(); while (iterator.hasNext()) { Integer w = iterator.next(); if (w == u) { nOccurrences++; iterator.remove(); } } return nOccurrences; } /** * {@inheritDoc} */ @Override public DirectedGraph getGraph() { return graph; } /** * {@inheritDoc} */ @Override public void setGraph(DirectedGraph graph) throws IllegalArgumentException { if (graph == null) { throw new IllegalArgumentException("Null graph argument."); } this.graph = graph; } /** * {@inheritDoc} */ @Override public List> findSimpleCycles() throws IllegalArgumentException { if (graph == null) { throw new IllegalArgumentException("Null graph."); } initState(Operation.ENUMERATE); for (int i = 0; i < nVertices; i++) { for (int j = 0; j < nVertices; j++) { blocked[j] = false; B[j].clear(); } start = vToI.get(iToV[i]); circuit(start, Operation.ENUMERATE); } List> result = cycles; clearState(); return result; } /** * Print to the standard output all simple cycles without building a list to keep them, thus * avoiding high memory consumption when investigating large and much connected graphs. */ public void printSimpleCycles() { if (graph == null) { throw new IllegalArgumentException("Null graph."); } initState(Operation.PRINT_ONLY); for (int i = 0; i < nVertices; i++) { for (int j = 0; j < nVertices; j++) { blocked[j] = false; B[j].clear(); } start = vToI.get(iToV[i]); circuit(start, Operation.PRINT_ONLY); } clearState(); } /** * Count the number of simple cycles. It can count up to Long.MAX cycles in a graph. * * @return the number of simple cycles */ public long countSimpleCycles() { if (graph == null) { throw new IllegalArgumentException("Null graph."); } initState(Operation.COUNT_ONLY); for (int i = 0; i < nVertices; i++) { for (int j = 0; j < nVertices; j++) { blocked[j] = false; B[j].clear(); } start = vToI.get(iToV[i]); circuit(start, Operation.COUNT_ONLY); } clearState(); return nCycles; } } // End HawickAndJamesSimpleCycles.java





© 2015 - 2025 Weber Informatics LLC | Privacy Policy