com.salesforce.jgrapht.alg.flow.GusfieldEquivalentFlowTree Maven / Gradle / Ivy
Show all versions of AptSpringProcessor Show documentation
/*
* (C) Copyright 2016-2017, by Joris Kinable 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.flow;
import java.util.*;
import com.salesforce.jgrapht.*;
import com.salesforce.jgrapht.alg.interfaces.*;
import com.salesforce.jgrapht.graph.*;
/**
* 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 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#calculateMaximumFlow(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
* @since January 2016
*/
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)
{
if (!(network instanceof UndirectedGraph))
throw new IllegalArgumentException("Graph must be undirected");
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 calculateMaximumFlow(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)];
}
/**
* Returns maximum flow value, that was calculated during last
* calculateMaximumFlow call.
*
* @return maximum flow value
*/
@Override
public double getMaximumFlowValue()
{
return calculateMaximumFlow(lastInvokedSource, lastInvokedTarget);
}
/**
* 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.");
}
}