Lookback AA implementation, doesn't currently work
This commit is contained in:
212
src/main/java/MaximumWeightBipartiteLookBackAuctionMatching.java
Normal file
212
src/main/java/MaximumWeightBipartiteLookBackAuctionMatching.java
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
import org.jgrapht.Graph;
|
||||||
|
import org.jgrapht.GraphTests;
|
||||||
|
import org.jgrapht.alg.interfaces.MatchingAlgorithm;
|
||||||
|
import org.jgrapht.alg.util.Pair;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Maximum weight matching in bipartite graphs with strictly integer edge weights, found using the
|
||||||
|
unscaled look-back auction algorithm
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MaximumWeightBipartiteLookBackAuctionMatching<V, E> implements MatchingAlgorithm<V, E> {
|
||||||
|
|
||||||
|
private final Graph<V, E> graph;
|
||||||
|
private final Set<V> partition1;
|
||||||
|
private final Set<V> partition2;
|
||||||
|
private final BigDecimal delta;
|
||||||
|
private final Set<E> matching;
|
||||||
|
private BigDecimal matchingWeight;
|
||||||
|
private boolean swappedPartitions = false;
|
||||||
|
|
||||||
|
public MaximumWeightBipartiteLookBackAuctionMatching(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");
|
||||||
|
int n = Math.max(partition1.size(), partition2.size());
|
||||||
|
this.delta = BigDecimal.valueOf(1 / ((double) n + 1));
|
||||||
|
this.matching = new LinkedHashSet<>();
|
||||||
|
this.matchingWeight = BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Method coded using MaximumWeightBipartiteMatching.class from JgraphT as a model
|
||||||
|
*/
|
||||||
|
@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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If the two partitions are different sizes, the bidders must be the smaller of the two partitions.
|
||||||
|
*/
|
||||||
|
Set<V> items;
|
||||||
|
Set<V> bidders;
|
||||||
|
if (partition2.size() >= partition1.size()) {
|
||||||
|
bidders = partition1;
|
||||||
|
items = partition2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bidders = partition2;
|
||||||
|
items = partition1;
|
||||||
|
swappedPartitions = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a map to track the owner of each item, which is initially null,
|
||||||
|
and a map to track the price of each item, which is initially 0.
|
||||||
|
*/
|
||||||
|
Map<V, V> owners = new HashMap<>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a map to track the prices of the objects
|
||||||
|
*/
|
||||||
|
Map<V, BigDecimal> prices = new HashMap<>();
|
||||||
|
for(V item: items) {
|
||||||
|
owners.put(item, null);
|
||||||
|
prices.put(item, BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a map to track the most valuable object for a bidder
|
||||||
|
*/
|
||||||
|
Map<V, V> mostValuableItems = new HashMap<>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a map to track the second most valuable object for a bidder
|
||||||
|
*/
|
||||||
|
Map<V, V> runnerUpItems = new HashMap<>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a map to track the bidder value thresholds
|
||||||
|
*/
|
||||||
|
Map<V, BigDecimal> valueThresholds = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
//Initialize queue of all bidders that don't currently own an item
|
||||||
|
Queue<V> unmatchedBidders = new ArrayDeque<>();
|
||||||
|
for(V bidder: bidders) {
|
||||||
|
unmatchedBidders.offer(bidder);
|
||||||
|
valueThresholds.put(bidder, BigDecimal.ZERO);
|
||||||
|
mostValuableItems.put(bidder, null);
|
||||||
|
runnerUpItems.put(bidder, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (unmatchedBidders.size() > 0) {
|
||||||
|
V bidder = unmatchedBidders.poll();
|
||||||
|
// BigDecimal valueThreshold = valueThresholds.get(bidder);
|
||||||
|
BigDecimal bestValue = BigDecimal.ZERO;
|
||||||
|
BigDecimal runnerUpValue = BigDecimal.ZERO;
|
||||||
|
boolean reinitialize = true;
|
||||||
|
// if (mostValuableItems.get(bidder) != null && runnerUpItems.get(bidder) != null) {
|
||||||
|
// reinitialize = false;
|
||||||
|
// //get the weight of the edge between the bidder and the best valued item
|
||||||
|
// V bestItem = mostValuableItems.get(bidder);
|
||||||
|
// BigDecimal bestItemWeight = BigDecimal.valueOf(graph.getEdgeWeight(graph.getEdge(bidder, bestItem)));
|
||||||
|
// bestValue = bestItemWeight.subtract(prices.get(bestItem));
|
||||||
|
// V runnerUpItem = runnerUpItems.get(bidder);
|
||||||
|
// BigDecimal runnerUpWeight = BigDecimal.valueOf(graph.getEdgeWeight(graph.getEdge(bidder, runnerUpItem)));
|
||||||
|
// runnerUpValue = runnerUpWeight.subtract(prices.get(runnerUpItem));
|
||||||
|
// //if both values are still above the threshold
|
||||||
|
// if (bestValue.compareTo(valueThreshold) >= 0 && runnerUpValue.compareTo(valueThreshold) >= 0) {
|
||||||
|
// if (bestValue.compareTo(runnerUpValue) < 0) { //if best value is lower than runner up
|
||||||
|
// BigDecimal tmp = bestValue;
|
||||||
|
// bestValue = runnerUpValue;
|
||||||
|
// runnerUpValue = tmp;
|
||||||
|
// mostValuableItems.put(bidder, runnerUpItem);
|
||||||
|
// runnerUpItems.put(bidder, bestItem);
|
||||||
|
// }
|
||||||
|
// BigDecimal newValueThreshold = bestValue.min(runnerUpValue);
|
||||||
|
// valueThresholds.put(bidder, newValueThreshold);
|
||||||
|
// System.out.println("lookback successful");
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// reinitialize = true; //lookback failed
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (reinitialize){
|
||||||
|
bestValue = BigDecimal.ZERO;
|
||||||
|
runnerUpValue = BigDecimal.ZERO;
|
||||||
|
for (E edge: graph.edgesOf(bidder)) {
|
||||||
|
double weight = graph.getEdgeWeight(edge);
|
||||||
|
if (weight == 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
V tmpItem = getItem(bidder, edge);
|
||||||
|
BigDecimal tmpValue = BigDecimal.valueOf(weight).subtract(prices.get(tmpItem));
|
||||||
|
if (tmpValue.compareTo(bestValue) >= 0) {
|
||||||
|
runnerUpValue = bestValue;
|
||||||
|
bestValue = tmpValue;
|
||||||
|
runnerUpItems.put(bidder, mostValuableItems.get(bidder));
|
||||||
|
mostValuableItems.put(bidder, tmpItem);
|
||||||
|
}
|
||||||
|
else if (tmpValue.compareTo(runnerUpValue) >= 0) {
|
||||||
|
runnerUpValue = tmpValue;
|
||||||
|
runnerUpItems.put(bidder, tmpItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueThresholds.put(bidder, runnerUpValue);
|
||||||
|
}
|
||||||
|
//Should now have initialized the maps to make look back possible
|
||||||
|
//skip this bidder if the best value is still zero
|
||||||
|
if (BigDecimal.ZERO.equals(bestValue)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
V mostValuableItem = mostValuableItems.get(bidder);
|
||||||
|
BigDecimal price = prices.get(mostValuableItem);
|
||||||
|
BigDecimal bid = price.add(bestValue).subtract(runnerUpValue).add(this.delta);
|
||||||
|
V formerOwner = owners.get(mostValuableItem);
|
||||||
|
if (formerOwner != null) {
|
||||||
|
unmatchedBidders.offer(formerOwner);
|
||||||
|
}
|
||||||
|
owners.put(mostValuableItem, bidder);
|
||||||
|
prices.put(mostValuableItem, bid);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (V item: owners.keySet()) {
|
||||||
|
if (owners.get(item) != null) {
|
||||||
|
matching.add(graph.getEdge(item, owners.get(item)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(E edge: matching) {
|
||||||
|
this.matchingWeight = this.matchingWeight.add(BigDecimal.valueOf(graph.getEdgeWeight(edge)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new MatchingImpl<>(graph, matching, matchingWeight.doubleValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private V getItem(V bidder, E edge) {
|
||||||
|
if (swappedPartitions) {
|
||||||
|
return graph.getEdgeSource(edge);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return graph.getEdgeTarget(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private V getBidder(V item, E edge) {
|
||||||
|
if (swappedPartitions) {
|
||||||
|
return graph.getEdgeTarget(edge);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return graph.getEdgeSource(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigDecimal getMatchingWeight() {
|
||||||
|
return matchingWeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user