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.

The newest version!
/*
 * (C) Copyright 2014-2018, by Luiz Kill and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package com.salesforce.jgrapht.alg.cycle;

import com.salesforce.jgrapht.*;

import java.util.*;

/**
 * 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 Graph graph; // 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(Graph graph) throws IllegalArgumentException { this.graph = GraphTests.requireDirected(graph, "Graph must be directed"); } @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 (Objects.equals(w, start)) { if (o == Operation.ENUMERATE) { List cycle = new ArrayList<>(stack.size()); for (Integer aStack : stack) { cycle.add(iToV[aStack]); } 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 (Objects.equals(w, u)) { nOccurrences++; iterator.remove(); } } return nOccurrences; } /** * Get the graph * * @return graph */ public Graph getGraph() { return graph; } /** * Set the graph * * @param graph graph */ public void setGraph(Graph graph) { this.graph = GraphTests.requireDirected(graph, "Graph must be directed"); } /** * {@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; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy