initial commit of stub of integer weight scaling algorithm
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
public enum AlgorithmType {
|
||||
HUNGARIAN, //Hungarian 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 setIntegerWeightScalingAlgorithm() { matchingAlgoritmType = AlgorithmType.INTEGER_WEIGHT_SCALING; }
|
||||
|
||||
public static void setAuctionAlgorithm() { matchingAlgoritmType = AlgorithmType.AUCTION; }
|
||||
|
||||
public static void setPairingHeap() {
|
||||
|
||||
@@ -582,7 +582,7 @@ public class InteractiveInterface {
|
||||
boolean backToOptions = false;
|
||||
while(!backToOptions) {
|
||||
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("3) Use Hungarian algorithm with pairing heap priority queue");
|
||||
System.out.println("4) Use auction algorithm");
|
||||
@@ -590,13 +590,19 @@ public class InteractiveInterface {
|
||||
try {
|
||||
input = sc.nextInt();
|
||||
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 -> {
|
||||
BiGpairSEQ.setHungarianAlgorithm();
|
||||
BiGpairSEQ.setFibonacciHeap();
|
||||
System.out.println("MWM algorithm set to Hungarian with Fibonacci heap");
|
||||
backToOptions = true;
|
||||
}
|
||||
case 3 -> {
|
||||
BiGpairSEQ.setHungarianAlgorithm();
|
||||
BiGpairSEQ.setPairingHeap();
|
||||
System.out.println("MWM algorithm set to Hungarian with pairing heap");
|
||||
backToOptions = true;
|
||||
|
||||
@@ -36,6 +36,7 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
||||
private final BigDecimal epsilon;
|
||||
private final Set<E> matching;
|
||||
private BigDecimal matchingWeight;
|
||||
|
||||
private boolean swappedPartitions = false;
|
||||
|
||||
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