I'm trying to implement and simulate a network where I can try some routing methods.
My problem is that one of my routing methods is require me to calculate MaxFlow/MinCut.
I have a custom implementation for the edges, where I added some new fields like Capacity. Here is my implementation:
import org.jgrapht.graph.DefaultWeightedEdge;
import java.io.Serializable;
public class MyDefaultWeightedEdge extends DefaultWeightedEdge implements Serializable {
protected int freecapacity;
protected boolean isFeasable;
public MyDefaultWeightedEdge(){
this.isFeasable = true;
}
protected int getFreeCapacity(){return this.freecapacity;}
protected void setFreeCapacity(int i)
{
this.freecapacity = i;
}
protected boolean getFeasable(){return this.isFeasable;}
protected void setFeasable(boolean b){this.isFeasable = b;}
@Override
protected Object getSource() {
return super.getSource();
}
@Override
protected Object getTarget() {
return super.getTarget();
}
@Override
protected double getWeight(){
System.out.println("getWeight");
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
String methodName = e.getMethodName();
if(methodName.equals(""))
{
return this.freecapacity;
}
else {
return super.getWeight();
}
}
public String toString() {
return "(" + this.getSource() + " : " + this.getTarget() + ") " + "Weight " + this.getWeight() + " Capacity " + this.getFreeCapacity();
}
}
When I try to use EdmondsKarpMFImpl my problem is that the algorithm uses the edgeweight as the capacity.
Question: How can I use my implementation of the edge?
Question: How can I get all of the edges which are in MinCut/MaxFlow ?
Thanks!
There's a lot of different solutions.
DefaultWeightedEdge
and use the graph's setEdgeWeight
and getEdgeWeight
methods to define the edge's weight. You are free to interpret this weight in whatever way that fits your application.public static void exampleNF(){
//Standard approach
Graph<Integer, DefaultWeightedEdge> graph = new DefaultUndirectedWeightedGraph<>(DefaultWeightedEdge.class);
Graphs.addAllVertices(graph, Arrays.asList(1,2,3,4));
Graphs.addEdge(graph, 1,2,10);
Graphs.addEdge(graph, 2,3,4);
Graphs.addEdge(graph, 2,4,3);
Graphs.addEdge(graph, 1,4,8);
Graphs.addEdge(graph, 4,3,15);
MaximumFlowAlgorithm<Integer, DefaultWeightedEdge> mf = new EdmondsKarpMFImpl<>(graph);
System.out.println(mf.getMaximumFlow(1,3));
}
AsWeightedGraph
. This is convenient if your graph doesn't have weights, or, if your edges have more than 1 weight (e.g. both a cost and a capacity) and you want to switch between them.public static void exampleNF2(){
//Make an unweighted graph weighted using an AsWeightedGraph wrapper
Graph<Integer, DefaultEdge> graph = new DefaultUndirectedGraph<>(DefaultEdge.class);
Graphs.addAllVertices(graph, Arrays.asList(1,2,3,4));
DefaultEdge e1 = graph.addEdge(1,2);
DefaultEdge e2 = graph.addEdge(2,3);
DefaultEdge e3 = graph.addEdge(2,4);
DefaultEdge e4 = graph.addEdge(1,4);
DefaultEdge e5 = graph.addEdge(4,3);
Map<DefaultEdge, Double> capacities = Map.of(e1, 10.0, e2, 4.0, e3, 3.0, e4, 8.0, e5, 15.0);
MaximumFlowAlgorithm<Integer, DefaultEdge> mf = new EdmondsKarpMFImpl<>(new AsWeightedGraph<>(graph, capacities));
System.out.println(mf.getMaximumFlow(1,3));
}
AsWeightedGraph
, but this time using a function as a 'pass-through' to get a specific weight stored on the arcs themselvespublic static void exampleNF3(){
//Using the AsWeightedGraph as a function
Graph<Integer, MyEdge> graph = new DefaultUndirectedGraph<>(MyEdge.class);
Graphs.addAllVertices(graph, Arrays.asList(1,2,3,4));
graph.addEdge(1,2, new MyEdge(10));
graph.addEdge(2,3, new MyEdge(4));
graph.addEdge(2,4, new MyEdge(3));
graph.addEdge(1,4, new MyEdge(8));
graph.addEdge(4,3, new MyEdge(15));
MaximumFlowAlgorithm<Integer, MyEdge> mf = new EdmondsKarpMFImpl<>(new AsWeightedGraph<>(graph, e -> e.capacity, false, false));
System.out.println(mf.getMaximumFlow(1,3));
}
private static class MyEdge {
private final double capacity;
public MyEdge(double capacity){
this.capacity=capacity;
}
}
getEdgeWeight
and setEdgeWeight
methods. In this example, we use the MyEdge
class from the previous example.public static void exampleNF4(){
//Using a custom graph
MyGraph graph = new MyGraph(MyEdge.class);
Graphs.addAllVertices(graph, Arrays.asList(1,2,3,4));
graph.addEdge(1,2, new MyEdge(10));
graph.addEdge(2,3, new MyEdge(4));
graph.addEdge(2,4, new MyEdge(3));
graph.addEdge(1,4, new MyEdge(8));
graph.addEdge(4,3, new MyEdge(15));
MaximumFlowAlgorithm<Integer, MyEdge> mf = new EdmondsKarpMFImpl<>(graph);
System.out.println(mf.getMaximumFlow(1,3));
}
private static class MyGraph extends SimpleWeightedGraph<Integer, MyEdge>{
public MyGraph(Class<? extends MyEdge> edgeClass) {
super(edgeClass);
}
@Override
public double getEdgeWeight(MyEdge e){
return e.capacity;
}
}
There's probably more, but this covers quite a range of different approaches already. Personally I would not implement my own graph class unless I need it for something very specific.