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

org.jgrapht.alg.cycle.PatonCycleBase Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2013-2023, by Nikolay Ognyanov 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 org.jgrapht.alg.cycle;

import org.jgrapht.*;
import org.jgrapht.alg.interfaces.*;

import java.util.*;

/**
 * Find a cycle basis of an undirected graph using a variant of Paton's algorithm.
 * 
 * 

* See:
* K. Paton, An algorithm for finding a fundamental set of cycles for an undirected linear graph, * Comm. ACM 12 (1969), pp. 514-518. * *

* Note that Paton's algorithm produces a fundamental cycle basis while this implementation produces * a weakly * fundamental cycle basis. A cycle basis is called weakly fundamental if there exists a linear * ordering of the cycles in a cycle basis such that each cycle includes at least one edge that is * not part of any previous cycle. Every fundamental cycle basis is weakly fundamental (for all * linear orderings) but not necessarily vice versa. * * @param the graph vertex type * @param the graph edge type * * @author Nikolay Ognyanov */ public class PatonCycleBase implements CycleBasisAlgorithm { private Graph graph; /** * Create a cycle base finder for the specified graph. * * @param graph the input graph * @throws IllegalArgumentException if the graph argument is null or the graph is * not undirected */ public PatonCycleBase(Graph graph) { this.graph = GraphTests.requireUndirected(graph); } /** * Return an undirected cycle basis of a graph. Works only for undirected graphs which do not * have multiple (parallel) edges. * * @return an undirected cycle basis * @throws IllegalArgumentException if the graph is not undirected * @throws IllegalArgumentException if the graph contains multiple edges between two vertices */ @Override public CycleBasis getCycleBasis() { GraphTests.requireUndirected(graph); if (GraphTests.hasMultipleEdges(graph)) { throw new IllegalArgumentException("Graphs with multiple edges not supported"); } Map> used = new HashMap<>(); Map parent = new HashMap<>(); ArrayDeque stack = new ArrayDeque<>(); Set> cycles = new LinkedHashSet<>(); int totalLength = 0; double totalWeight = 0d; for (V root : graph.vertexSet()) { // Loop over the connected // components of the graph. if (parent.containsKey(root)) { continue; } // Free some memory in case of // multiple connected components. used.clear(); // Prepare to walk the spanning tree. parent.put(root, null); used.put(root, new HashMap<>()); stack.push(root); // Do the walk. It is a BFS with // a LIFO instead of the usual // FIFO. Thus it is easier to // find the cycles in the tree. while (!stack.isEmpty()) { V current = stack.pop(); Map currentUsed = used.get(current); for (E e : graph.edgesOf(current)) { V neighbor = Graphs.getOppositeVertex(graph, e, current); if (!used.containsKey(neighbor)) { // found a new node parent.put(neighbor, e); Map neighbourUsed = new HashMap<>(); neighbourUsed.put(current, e); used.put(neighbor, neighbourUsed); stack.push(neighbor); } else if (neighbor.equals(current)) { // found a self loop List cycle = new ArrayList<>(); cycle.add(e); totalWeight += graph.getEdgeWeight(e); totalLength += 1; cycles.add(cycle); } else if (!currentUsed.containsKey(neighbor)) { // found a cycle Map neighbourUsed = used.get(neighbor); double weight = 0d; List cycle = new ArrayList<>(); cycle.add(e); weight += graph.getEdgeWeight(e); V v = current; while (!neighbourUsed.containsKey(v)) { E p = parent.get(v); cycle.add(p); weight += graph.getEdgeWeight(p); v = Graphs.getOppositeVertex(graph, p, v); } E a = neighbourUsed.get(v); cycle.add(a); weight += graph.getEdgeWeight(a); neighbourUsed.put(current, e); cycles.add(cycle); totalLength += cycle.size(); totalWeight += weight; } } } } return new CycleBasisImpl(graph, cycles, totalLength, totalWeight); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy