Update comments
This commit is contained in:
@@ -5,12 +5,27 @@ import org.jgrapht.alg.interfaces.MatchingAlgorithm;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Maximum weight matching in bipartite graphs using a forward auction algorithm. This implementation uses the Gauss-Seidel
|
* Maximum weight matching in bipartite graphs with strictly integer edge weights, using a forward auction algorithm.
|
||||||
version of the forward auction algorithm, in which bids are submitted one at a time. For any weighted bipartite graph
|
* This implementation uses the Gauss-Seidel version of the forward auction algorithm, in which bids are submitted
|
||||||
with n vertices in the smaller partition, this algorithm will produce a matching that is within n*epsilon of being
|
* one at a time. For any weighted bipartite graph with n vertices in the smaller partition, this algorithm will produce
|
||||||
optimal. For a weighted bipartite graph with strictly integer weights, this matching will always be optimal, and thus
|
* a matching that is within n*epsilon of being optimal. Using an epsilon = 1/(n+1) ensures that this matching differs
|
||||||
is a maximum weight matching.
|
* from an optimal matching by <1. Thus, for a bipartite graph with strictly integer weights, this algorithm returns
|
||||||
|
* a maximum weight matching.
|
||||||
|
*
|
||||||
|
* See:
|
||||||
|
* "Towards auction algorithms for large dense assignment problems"
|
||||||
|
* Libor Buš and Pavel Tvrdík, Comput Optim Appl (2009) 43:411-436
|
||||||
|
* https://link.springer.com/article/10.1007/s10589-007-9146-5
|
||||||
|
*
|
||||||
|
* See also:
|
||||||
|
* Many books and papers by Dimitri Bertsekas, including chapter 4 of Linear Network Optimization:
|
||||||
|
* https://web.mit.edu/dimitrib/www/LNets_Full_Book.pdf
|
||||||
|
*
|
||||||
|
* @param <V> the graph vertex type
|
||||||
|
* @param <E> the graph edge type
|
||||||
|
*
|
||||||
|
* @author Eugene Fischer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements MatchingAlgorithm<V, E> {
|
public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements MatchingAlgorithm<V, E> {
|
||||||
@@ -28,7 +43,7 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
this.partition1 = Objects.requireNonNull(partition1, "Partition 1 cannot be null");
|
this.partition1 = Objects.requireNonNull(partition1, "Partition 1 cannot be null");
|
||||||
this.partition2 = Objects.requireNonNull(partition2, "Partition 2 cannot be null");
|
this.partition2 = Objects.requireNonNull(partition2, "Partition 2 cannot be null");
|
||||||
int n = Math.max(partition1.size(), partition2.size());
|
int n = Math.max(partition1.size(), partition2.size());
|
||||||
this.epsilon = BigDecimal.valueOf(1 / ((double) n + 1));
|
this.epsilon = BigDecimal.valueOf(1 / ((double) n + 1)); //The minimum price increase of a bid
|
||||||
this.matching = new LinkedHashSet<>();
|
this.matching = new LinkedHashSet<>();
|
||||||
this.matchingWeight = BigDecimal.ZERO;
|
this.matchingWeight = BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
@@ -76,12 +91,13 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
prices.put(item, BigDecimal.ZERO);
|
prices.put(item, BigDecimal.ZERO);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Initialize queue of all bidders that don't currently own an item
|
//Create a queue of bidders that don't currently own an item, which is initially all of them
|
||||||
Queue<V> unmatchedBidders = new ArrayDeque<>();
|
Queue<V> unmatchedBidders = new ArrayDeque<>();
|
||||||
for(V bidder: bidders) {
|
for(V bidder: bidders) {
|
||||||
unmatchedBidders.offer(bidder);
|
unmatchedBidders.offer(bidder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Run the auction while there are remaining unmatched bidders
|
||||||
while (unmatchedBidders.size() > 0) {
|
while (unmatchedBidders.size() > 0) {
|
||||||
V bidder = unmatchedBidders.poll();
|
V bidder = unmatchedBidders.poll();
|
||||||
V item = null;
|
V item = null;
|
||||||
@@ -89,15 +105,15 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
BigDecimal runnerUpValue = BigDecimal.valueOf(-1.0);
|
BigDecimal runnerUpValue = BigDecimal.valueOf(-1.0);
|
||||||
/*
|
/*
|
||||||
Find the items that offer the best and second-best value for the bidder,
|
Find the items that offer the best and second-best value for the bidder,
|
||||||
then submit a bid equal to the price of the best item plus the marginal value over
|
then submit a bid equal to the price of the best-valued item plus the marginal value over
|
||||||
the second-best item plus delta.
|
the second-best-valued item plus epsilon.
|
||||||
*/
|
*/
|
||||||
for (E edge: graph.edgesOf(bidder)) {
|
for (E edge: graph.edgesOf(bidder)) {
|
||||||
double weight = graph.getEdgeWeight(edge);
|
double weight = graph.getEdgeWeight(edge);
|
||||||
if(weight == 0.0) {
|
if(weight == 0.0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
V tmp = getItem(bidder, edge);
|
V tmp = getItem(edge);
|
||||||
BigDecimal value = BigDecimal.valueOf(weight).subtract(prices.get(tmp));
|
BigDecimal value = BigDecimal.valueOf(weight).subtract(prices.get(tmp));
|
||||||
if (value.compareTo(bestValue) >= 0) {
|
if (value.compareTo(bestValue) >= 0) {
|
||||||
runnerUpValue = bestValue;
|
runnerUpValue = bestValue;
|
||||||
@@ -119,21 +135,21 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
prices.put(item, bid);
|
prices.put(item, bid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Add all edges between items and their owners to the matching
|
||||||
for (V item: owners.keySet()) {
|
for (V item: owners.keySet()) {
|
||||||
if (owners.get(item) != null) {
|
if (owners.get(item) != null) {
|
||||||
matching.add(graph.getEdge(item, owners.get(item)));
|
matching.add(graph.getEdge(item, owners.get(item)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Sum the edges of the matching to obtain the matching weight
|
||||||
for(E edge: matching) {
|
for(E edge: matching) {
|
||||||
this.matchingWeight = this.matchingWeight.add(BigDecimal.valueOf(graph.getEdgeWeight(edge)));
|
this.matchingWeight = this.matchingWeight.add(BigDecimal.valueOf(graph.getEdgeWeight(edge)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new MatchingImpl<>(graph, matching, matchingWeight.doubleValue());
|
return new MatchingImpl<>(graph, matching, matchingWeight.doubleValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
private V getItem(V bidder, E edge) {
|
private V getItem(E edge) {
|
||||||
if (swappedPartitions) {
|
if (swappedPartitions) {
|
||||||
return graph.getEdgeSource(edge);
|
return graph.getEdgeSource(edge);
|
||||||
}
|
}
|
||||||
@@ -142,14 +158,15 @@ public class MaximumIntegerWeightBipartiteAuctionMatching<V, E> implements Match
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private V getBidder(V item, E edge) {
|
// //method for implementing a forward-reverse auction algorithm, not used here
|
||||||
if (swappedPartitions) {
|
// private V getBidder(E edge) {
|
||||||
return graph.getEdgeTarget(edge);
|
// if (swappedPartitions) {
|
||||||
}
|
// return graph.getEdgeTarget(edge);
|
||||||
else {
|
// }
|
||||||
return graph.getEdgeSource(edge);
|
// else {
|
||||||
}
|
// return graph.getEdgeSource(edge);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
public BigDecimal getMatchingWeight() {
|
public BigDecimal getMatchingWeight() {
|
||||||
return matchingWeight;
|
return matchingWeight;
|
||||||
|
|||||||
Reference in New Issue
Block a user