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

org.jgrapht.alg.flow.GusfieldEquivalentFlowTree Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2016-2023, by Joris Kinable 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.flow;

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

import java.util.*;

/**
 * This class computes an Equivalent Flow Tree (EFT) using the algorithm proposed by Dan Gusfield.
 * EFTs can be used to efficiently calculate the maximum flow for all pairs of vertices. The
 * algorithm is described in: Gusfield, D, Very simple methods for all pairs network flow
 * analysis. SIAM Journal on Computing, 19(1), p142-155, 1990
* In an undirected graph, there exist $frac{n(n-1)}{2}$ different vertex pairs. This class computes * the maximum flow between each of these pairs efficiently by performing exactly $(n-1)$ minimum * $s-t$ cut computations. If your application requires fewer than $(n-1)$ flow calculations, * consider computing the maximum flows manually through {@link MaximumFlowAlgorithm}. * * *

* The runtime complexity of this class is $O((V-1)Q)$, where $Q$ is the runtime complexity of the * algorithm used to compute $s-t$ cuts in the graph. By default, this class uses the * {@link PushRelabelMFImpl} implementation to calculate minimum $s-t$ cuts. This class has a * runtime complexity of $O(V^3)$, resulting in a $O(V^4)$ runtime complexity for the overal * algorithm. * * *

* Note: this class performs calculations in a lazy manner. The EFT is not calculated until the * first invocation of {@link GusfieldEquivalentFlowTree#getMaximumFlowValue(Object, Object)} or * {@link GusfieldEquivalentFlowTree#getEquivalentFlowTree()}. Moreover, this class only * calculates the value of the maximum flow between a source-destination pair; it does not calculate * the corresponding flow per edge. If you need to know the exact flow through an edge, use one of * the alternative {@link MaximumFlowAlgorithm} implementations. * *

* Warning: EFTs do not allow you to calculate minimum cuts for all pairs of vertex! For that, * Gomory-Hu cut trees are required! Use the {@link GusfieldGomoryHuCutTree} implementation instead. * *

* This class does not support changes to the underlying graph. The behavior of this class is * undefined when the graph is modified after instantiating this class. * * @param the graph vertex type * @param the graph edge type * * @author Joris Kinable */ public class GusfieldEquivalentFlowTree implements MaximumFlowAlgorithm { /* Number of vertices in the graph */ private final int n; /* Algorithm used to computed the Maximum s-t flows */ private final MinimumSTCutAlgorithm minimumSTCutAlgorithm; /* Data structures for computations */ private List vertexList = new ArrayList<>(); private Map indexMap = new HashMap<>(); private int[] p; // See vector p in the paper description private int[] neighbors; /* Matrix containing the flow values for every s-t pair */ private double[][] flowMatrix = null; private V lastInvokedSource = null; private V lastInvokedTarget = null; /** * Constructs a new GusfieldEquivalentFlowTree instance. * * @param network input graph */ public GusfieldEquivalentFlowTree(Graph network) { this(network, MaximumFlowAlgorithmBase.DEFAULT_EPSILON); } /** * Constructs a new GusfieldEquivalentFlowTree instance. * * @param network input graph * @param epsilon precision */ public GusfieldEquivalentFlowTree(Graph network, double epsilon) { this(network, new PushRelabelMFImpl<>(network, epsilon)); } /** * Constructs a new GusfieldEquivalentFlowTree instance. * * @param network input graph * @param minimumSTCutAlgorithm algorithm used to compute the minimum $s-t$ cuts */ public GusfieldEquivalentFlowTree( Graph network, MinimumSTCutAlgorithm minimumSTCutAlgorithm) { GraphTests.requireUndirected(network); this.n = network.vertexSet().size(); if (n < 2) throw new IllegalArgumentException("Graph must have at least 2 vertices"); this.minimumSTCutAlgorithm = minimumSTCutAlgorithm; vertexList.addAll(network.vertexSet()); for (int i = 0; i < vertexList.size(); i++) indexMap.put(vertexList.get(i), i); } /** * Runs the algorithm */ private void calculateEquivalentFlowTree() { flowMatrix = new double[n][n]; p = new int[n]; neighbors = new int[n]; for (int s = 1; s < n; s++) { int t = p[s]; neighbors[s] = t; double flowValue = minimumSTCutAlgorithm.calculateMinCut(vertexList.get(s), vertexList.get(t)); Set sourcePartition = minimumSTCutAlgorithm.getSourcePartition(); // Set X in the // paper for (int i = s; i < n; i++) if (sourcePartition.contains(vertexList.get(i)) && p[i] == t) p[i] = s; // populate the flow matrix flowMatrix[s][t] = flowMatrix[t][s] = flowValue; for (int i = 0; i < s; i++) if (i != t) flowMatrix[s][i] = flowMatrix[i][s] = Math.min(flowMatrix[s][t], flowMatrix[t][i]); } } /** * Returns the Equivalent Flow Tree as an actual tree (graph). Note that this tree is not * necessarily unique. The edge weights represent the flow values/cut weights. This method runs * in $O(n)$ time * * @return Equivalent Flow Tree */ public SimpleWeightedGraph getEquivalentFlowTree() { if (p == null) // Lazy invocation of the algorithm this.calculateEquivalentFlowTree(); SimpleWeightedGraph equivalentFlowTree = new SimpleWeightedGraph<>(DefaultWeightedEdge.class); Graphs.addAllVertices(equivalentFlowTree, vertexList); for (int i = 1; i < n; i++) { DefaultWeightedEdge e = equivalentFlowTree.addEdge(vertexList.get(i), vertexList.get(neighbors[i])); equivalentFlowTree.setEdgeWeight(e, flowMatrix[i][neighbors[i]]); } return equivalentFlowTree; } /** * Unsupported operation * * @param source source of the flow inside the network * @param sink sink of the flow inside the network * * @return nothing */ @Override public MaximumFlow getMaximumFlow(V source, V sink) { throw new UnsupportedOperationException( "Flows calculated via Equivalent Flow trees only provide a maximum flow value, not the exact flow per edge/arc."); } /** * Returns the Maximum flow between source and sink. The algorithm is only executed once; * successive invocations of this method will return in $O(1)$ time. * * @param source source vertex * @param sink sink vertex * @return the Maximum flow between source and sink. */ @Override public double getMaximumFlowValue(V source, V sink) { assert indexMap.containsKey(source) && indexMap.containsKey(sink); lastInvokedSource = source; lastInvokedTarget = sink; if (p == null) // Lazy invocation of the algorithm this.calculateEquivalentFlowTree(); return flowMatrix[indexMap.get(source)][indexMap.get(sink)]; } /** * Unsupported operation * * @return nothing */ @Override public Map getFlowMap() { throw new UnsupportedOperationException( "Flows calculated via Equivalent Flow trees only provide a maximum flow value, not the exact flow per edge/arc."); } /** * Unsupported operation * * @param e edge * @return nothing */ @Override public V getFlowDirection(E e) { throw new UnsupportedOperationException( "Flows calculated via Equivalent Flow trees only provide a maximum flow value, not the exact flow per edge/arc."); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy