initial commit of stub of integer weight scaling algorithm
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
public enum AlgorithmType {
|
public enum AlgorithmType {
|
||||||
HUNGARIAN, //Hungarian algorithm
|
HUNGARIAN, //Hungarian algorithm
|
||||||
AUCTION, //Forward auction algorithm
|
AUCTION, //Forward auction algorithm
|
||||||
|
INTEGER_WEIGHT_SCALING, //integer weight scaling algorithm of Duan and Su
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,8 @@ public class BiGpairSEQ {
|
|||||||
|
|
||||||
public static void setHungarianAlgorithm() { matchingAlgoritmType = AlgorithmType.HUNGARIAN; }
|
public static void setHungarianAlgorithm() { matchingAlgoritmType = AlgorithmType.HUNGARIAN; }
|
||||||
|
|
||||||
|
public static void setIntegerWeightScalingAlgorithm() { matchingAlgoritmType = AlgorithmType.INTEGER_WEIGHT_SCALING; }
|
||||||
|
|
||||||
public static void setAuctionAlgorithm() { matchingAlgoritmType = AlgorithmType.AUCTION; }
|
public static void setAuctionAlgorithm() { matchingAlgoritmType = AlgorithmType.AUCTION; }
|
||||||
|
|
||||||
public static void setPairingHeap() {
|
public static void setPairingHeap() {
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ public class InteractiveInterface {
|
|||||||
boolean backToOptions = false;
|
boolean backToOptions = false;
|
||||||
while(!backToOptions) {
|
while(!backToOptions) {
|
||||||
System.out.println("\n---------ALGORITHM OPTIONS----------");
|
System.out.println("\n---------ALGORITHM OPTIONS----------");
|
||||||
System.out.println("1) Use scaling algorithm by Duan and Su.");
|
System.out.println("1) Use integer weight scaling algorithm by Duan and Su.");
|
||||||
System.out.println("2) Use Hungarian algorithm with Fibonacci heap priority queue");
|
System.out.println("2) Use Hungarian algorithm with Fibonacci heap priority queue");
|
||||||
System.out.println("3) Use Hungarian algorithm with pairing heap priority queue");
|
System.out.println("3) Use Hungarian algorithm with pairing heap priority queue");
|
||||||
System.out.println("4) Use auction algorithm");
|
System.out.println("4) Use auction algorithm");
|
||||||
@@ -590,13 +590,19 @@ public class InteractiveInterface {
|
|||||||
try {
|
try {
|
||||||
input = sc.nextInt();
|
input = sc.nextInt();
|
||||||
switch (input) {
|
switch (input) {
|
||||||
case 1 -> System.out.println("This option is not yet implemented. Choose another.");
|
case 1 -> {
|
||||||
|
BiGpairSEQ.setIntegerWeightScalingAlgorithm();
|
||||||
|
System.out.println("MWM algorithm set to integer weight scaling algorithm of Duan and Su");
|
||||||
|
backToOptions = true;
|
||||||
|
}
|
||||||
case 2 -> {
|
case 2 -> {
|
||||||
|
BiGpairSEQ.setHungarianAlgorithm();
|
||||||
BiGpairSEQ.setFibonacciHeap();
|
BiGpairSEQ.setFibonacciHeap();
|
||||||
System.out.println("MWM algorithm set to Hungarian with Fibonacci heap");
|
System.out.println("MWM algorithm set to Hungarian with Fibonacci heap");
|
||||||
backToOptions = true;
|
backToOptions = true;
|
||||||
}
|
}
|
||||||
case 3 -> {
|
case 3 -> {
|
||||||
|
BiGpairSEQ.setHungarianAlgorithm();
|
||||||
BiGpairSEQ.setPairingHeap();
|
BiGpairSEQ.setPairingHeap();
|
||||||
System.out.println("MWM algorithm set to Hungarian with pairing heap");
|
System.out.println("MWM algorithm set to Hungarian with pairing heap");
|
||||||
backToOptions = true;
|
backToOptions = true;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
private final BigDecimal epsilon;
|
private final BigDecimal epsilon;
|
||||||
private final Set<E> matching;
|
private final Set<E> matching;
|
||||||
private BigDecimal matchingWeight;
|
private BigDecimal matchingWeight;
|
||||||
|
|
||||||
private boolean swappedPartitions = false;
|
private boolean swappedPartitions = false;
|
||||||
|
|
||||||
public MaximumIntegerWeightBipartiteAuctionMatching(Graph<V, E> graph, Set<V> partition1, Set<V> partition2) {
|
public MaximumIntegerWeightBipartiteAuctionMatching(Graph<V, E> graph, Set<V> partition1, Set<V> partition2) {
|
||||||
|
|||||||
126
src/main/java/MaximumIntegerWeightBipartiteMatching.java
Normal file
126
src/main/java/MaximumIntegerWeightBipartiteMatching.java
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.GraphTests;
|
||||||
|
import org.jgrapht.alg.interfaces.MatchingAlgorithm;
|
||||||
|
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum weight matching in bipartite graphs with strictly integer edge weights, using a scaling algorithm
|
||||||
|
* via Duan and Su with O(m * sqrt(n) * log(N)) running time, where m is the number of edges, n is the number
|
||||||
|
* of vertices in the larger partition of the graph, and N is the maximum integer edge weight.
|
||||||
|
*
|
||||||
|
* See:
|
||||||
|
* "A Scaling Algorithm for Maximum Weight Matching in Bipartite Graphs"
|
||||||
|
* Ran Duan and Hsin-Hao Su, Proceedings of the Twenty-Third Annual ACM-SIAM Symposium on Discrete Algorithms, p. 1413-1424. (2012)
|
||||||
|
* https://web.eecs.umich.edu/~pettie/matching/Duan-Su-scaling-bipartite-matching.pdf
|
||||||
|
*
|
||||||
|
* @param <V> the graph vertex type
|
||||||
|
* @param <E> the graph edge type
|
||||||
|
*
|
||||||
|
* @author Eugene Fischer
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MaximumIntegerWeightBipartiteMatching<V, E> implements MatchingAlgorithm<V, E> {
|
||||||
|
|
||||||
|
private final Graph<V, E> graph;
|
||||||
|
private final Set<V> partition1;
|
||||||
|
private final Set<V> partition2;
|
||||||
|
private final Set<E> matching;
|
||||||
|
private final BigInteger maxPartitionSize;
|
||||||
|
private final BigInteger maxEdgeWeight;
|
||||||
|
private BigInteger matchingWeight;
|
||||||
|
private BigInteger delta;
|
||||||
|
private final Integer numberOfScales;
|
||||||
|
public final double LOG_2 = Math.log(2.0); //constant for logBigInteger function
|
||||||
|
private final int MAX_DIGITS_2 = 977; //constant for logBigInteger function
|
||||||
|
|
||||||
|
public MaximumIntegerWeightBipartiteMatching(Graph<V, E> graph, Set<V> partition1, Set<V> partition2) {
|
||||||
|
this.graph = GraphTests.requireUndirected(graph);
|
||||||
|
this.partition1 = Objects.requireNonNull(partition1, "Partition 1 cannot be null");
|
||||||
|
this.partition2 = Objects.requireNonNull(partition2, "Partition 2 cannot be null");
|
||||||
|
Integer n = Math.max(partition1.size(), partition2.size());
|
||||||
|
this.maxPartitionSize = new BigInteger(String.valueOf(Math.max(partition1.size(), partition2.size())));
|
||||||
|
Integer maxEdgeWeight = 0;
|
||||||
|
for (E edge: graph.edgeSet()) {
|
||||||
|
Integer weight = Integer.valueOf(String.valueOf(graph.getEdgeWeight(edge)));
|
||||||
|
maxEdgeWeight = Math.max(maxEdgeWeight, weight);
|
||||||
|
}
|
||||||
|
this.maxEdgeWeight = new BigInteger(maxEdgeWeight.toString());
|
||||||
|
this.matching = new LinkedHashSet<>();
|
||||||
|
this.matchingWeight = BigInteger.ZERO;
|
||||||
|
//This takes the integer square root of the maxPartitionSize instead of the square root, not sure if this will introduce an error
|
||||||
|
Double exponent = maxEdgeWeight / Math.sqrt(Double.parseDouble(n.toString()));
|
||||||
|
exponent = Math.log10(exponent);
|
||||||
|
exponent = Math.floor(exponent);
|
||||||
|
this.delta = BigInteger.TWO.pow(Integer.parseInt(exponent.toString()));
|
||||||
|
Double numberOfScales = Math.ceil(Math.log10(Double.parseDouble(maxEdgeWeight.toString())));
|
||||||
|
this.numberOfScales = Integer.parseInt(numberOfScales.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MaximumIntegerWeightBipartiteMatching(Graph<V, E> graph, Set<V> partition1, Set<V> partition2, Integer maxEdgeWeight) {
|
||||||
|
this.graph = GraphTests.requireUndirected(graph);
|
||||||
|
this.partition1 = Objects.requireNonNull(partition1, "Partition 1 cannot be null");
|
||||||
|
this.partition2 = Objects.requireNonNull(partition2, "Partition 2 cannot be null");
|
||||||
|
Integer n = Math.max(partition1.size(), partition2.size());
|
||||||
|
this.maxPartitionSize = new BigInteger(String.valueOf(Math.max(partition1.size(), partition2.size())));
|
||||||
|
this.maxEdgeWeight = new BigInteger(maxEdgeWeight.toString());
|
||||||
|
this.matching = new LinkedHashSet<>();
|
||||||
|
this.matchingWeight = BigInteger.ZERO;
|
||||||
|
Double exponent = maxEdgeWeight / Math.sqrt(Double.parseDouble(n.toString()));
|
||||||
|
exponent = Math.log10(exponent);
|
||||||
|
exponent = Math.floor(exponent);
|
||||||
|
this.delta = BigInteger.TWO.pow(Integer.parseInt(exponent.toString()));
|
||||||
|
Double numberOfScales = Math.ceil(Math.log10(Double.parseDouble(maxEdgeWeight.toString())));
|
||||||
|
this.numberOfScales = Integer.parseInt(numberOfScales.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MaximumIntegerWeightBipartiteMatching(Graph<V, E> graph, Set<V> partition1, Set<V> partition2, BigInteger maxEdgeWeight) {
|
||||||
|
this.graph = GraphTests.requireUndirected(graph);
|
||||||
|
this.partition1 = Objects.requireNonNull(partition1, "Partition 1 cannot be null");
|
||||||
|
this.partition2 = Objects.requireNonNull(partition2, "Partition 2 cannot be null");
|
||||||
|
Integer n = Math.max(partition1.size(), partition2.size());
|
||||||
|
this.maxPartitionSize = new BigInteger(String.valueOf(Math.max(partition1.size(), partition2.size())));
|
||||||
|
this.maxEdgeWeight = maxEdgeWeight;
|
||||||
|
this.matching = new LinkedHashSet<>();
|
||||||
|
this.matchingWeight = BigInteger.ZERO;
|
||||||
|
Double exponent = maxEdgeWeight.doubleValue() / Math.sqrt(Double.parseDouble(n.toString()));
|
||||||
|
exponent = Math.log10(exponent);
|
||||||
|
exponent = Math.floor(exponent);
|
||||||
|
this.delta = BigInteger.TWO.pow(Integer.parseInt(exponent.toString()));
|
||||||
|
Double numberOfScales = Math.ceil(Math.log10(Double.parseDouble(maxEdgeWeight.toString())));
|
||||||
|
this.numberOfScales = Integer.parseInt(numberOfScales.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Matching<V, E> getMatching() {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test input instance
|
||||||
|
*/
|
||||||
|
if (!GraphTests.isSimple(graph)) {
|
||||||
|
throw new IllegalArgumentException("Only simple graphs supported");
|
||||||
|
}
|
||||||
|
if (!GraphTests.isBipartitePartition(graph, partition1, partition2)) {
|
||||||
|
throw new IllegalArgumentException("Graph partition is not bipartite");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//function to return the natural logarithm of an arbitrary BigInteger
|
||||||
|
//by leonbloy via https://stackoverflow.com/questions/6827516/logarithm-for-biginteger
|
||||||
|
private double logBigInteger(BigInteger val) {
|
||||||
|
if (val.signum() < 1)
|
||||||
|
return val.signum() < 0 ? Double.NaN : Double.NEGATIVE_INFINITY;
|
||||||
|
int blex = val.bitLength() - MAX_DIGITS_2; // any value in 60..1023 works here
|
||||||
|
if (blex > 0)
|
||||||
|
val = val.shiftRight(blex);
|
||||||
|
double res = Math.log(val.doubleValue());
|
||||||
|
return blex > 0 ? res + blex * LOG_2 : res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user