deba@2040: #include <cstdlib>
deba@2040: #include <iostream>
deba@2040: #include <sstream>
deba@2040: 
deba@2116: #include <lemon/list_graph.h>
deba@2040: 
deba@2040: #include <lemon/bpugraph_adaptor.h>
deba@2040: #include <lemon/bipartite_matching.h>
deba@2040: 
deba@2040: #include <lemon/graph_utils.h>
deba@2040: 
deba@2051: #include <lemon/maps.h>
deba@2051: 
deba@2040: #include "test_tools.h"
deba@2040: 
deba@2040: using namespace std;
deba@2040: using namespace lemon;
deba@2040: 
deba@2040: typedef ListBpUGraph Graph;
deba@2040: BPUGRAPH_TYPEDEFS(Graph);
deba@2040: 
deba@2040: int main(int argc, const char *argv[]) {
deba@2040:   Graph graph;
deba@2040:   vector<Node> aNodes;
deba@2040:   vector<Node> bNodes;
deba@2058:   int n = argc > 1 ? atoi(argv[1]) : 10;
deba@2058:   int m = argc > 2 ? atoi(argv[2]) : 10;
deba@2040:   int e = argc > 3 ? atoi(argv[3]) : (int)((n+m) * log(n+m));
deba@2051:   int c = argc > 4 ? atoi(argv[4]) : 100;
deba@2051: 
deba@2051:   Graph::UEdgeMap<int> weight(graph);
deba@2051: 
deba@2051:   int max_cardinality;
deba@2051:   int max_weight;
deba@2051:   int max_cardinality_max_weight;
deba@2058:   int min_cost_matching;
deba@2040: 
deba@2040:   for (int i = 0; i < n; ++i) {
deba@2040:     Node node = graph.addANode();
deba@2040:     aNodes.push_back(node);
deba@2040:   }
deba@2040:   for (int i = 0; i < m; ++i) {
deba@2040:     Node node = graph.addBNode();
deba@2040:     bNodes.push_back(node);
deba@2040:   }
deba@2040:   for (int i = 0; i < e; ++i) {
deba@2040:     Node aNode = aNodes[urandom(n)];
deba@2040:     Node bNode = bNodes[urandom(m)];
deba@2051:     UEdge uedge = graph.addEdge(aNode, bNode);
deba@2051:     weight[uedge] = urandom(c);
deba@2040:   }
deba@2040: 
deba@2040:   {
deba@2040:     MaxBipartiteMatching<Graph> bpmatch(graph);
deba@2040: 
deba@2040:     bpmatch.run();
deba@2040: 
deba@2040:     Graph::UEdgeMap<bool> mm(graph);
deba@2040:     Graph::NodeMap<bool> cs(graph);
deba@2040:     
deba@2040:     check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
deba@2040:     
deba@2040:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2040:       check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
deba@2040:     }
deba@2040:     
deba@2040:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2040:       int num = 0;
deba@2040:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2040:         if (mm[jt]) ++num;
deba@2051:       }
deba@2040:       check(num <= 1, "INVALID PRIMAL");
deba@2040:     }
deba@2051:     max_cardinality = bpmatch.matchingSize();
deba@2040:   }
deba@2040: 
deba@2040:   {
deba@2058:     Graph::UEdgeMap<bool> mm(graph);
deba@2058: 
deba@2058:     check(max_cardinality == maxBipartiteMatching(graph, mm),
deba@2058:           "WRONG MATCHING");
deba@2058:     
deba@2058:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2058:       int num = 0;
deba@2058:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2058:         if (mm[jt]) ++num;
deba@2058:       }
deba@2058:       check(num <= 1, "INVALID PRIMAL");
deba@2058:     }
deba@2058:   }
deba@2058: 
deba@2058:   {
deba@2040:     MaxBipartiteMatching<Graph> bpmatch(graph);
deba@2040: 
deba@2040:     bpmatch.greedyInit();
deba@2040:     bpmatch.start();
deba@2040: 
deba@2040:     Graph::UEdgeMap<bool> mm(graph);
deba@2040:     Graph::NodeMap<bool> cs(graph);
deba@2040: 
deba@2040:     check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
deba@2040:     
deba@2040:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2040:       check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
deba@2040:     }
deba@2040:     
deba@2040:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2040:       int num = 0;
deba@2040:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2040:         if (mm[jt]) ++num;
deba@2040:     }
deba@2040:       check(num <= 1, "INVALID PRIMAL");
deba@2040:     }
deba@2040:   }
deba@2040: 
deba@2040:   {
deba@2040:     MaxBipartiteMatching<Graph> bpmatch(graph);
deba@2040: 
deba@2040:     bpmatch.greedyInit();
deba@2040:     while (bpmatch.simpleAugment());
deba@2040:     
deba@2040:     Graph::UEdgeMap<bool> mm(graph);
deba@2040:     Graph::NodeMap<bool> cs(graph);
deba@2040:     
deba@2040:     check(bpmatch.coverSet(cs) == bpmatch.matching(mm), "INVALID PRIMAL-DUAL");
deba@2040:     
deba@2040:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2040:       check(cs[graph.aNode(it)] || cs[graph.bNode(it)], "INVALID DUAL");
deba@2040:     }
deba@2040:     
deba@2040:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2040:       int num = 0;
deba@2040:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2040:         if (mm[jt]) ++num;
deba@2040:     }
deba@2040:       check(num <= 1, "INVALID PRIMAL");
deba@2040:     }
deba@2040:   }
deba@2040: 
deba@2040:   {
deba@2051:     MaxWeightedBipartiteMatching<Graph> bpmatch(graph, weight);
deba@2051: 
deba@2051:     bpmatch.init();
deba@2051: 
deba@2051:     max_weight = 0;
deba@2051:     while (bpmatch.augment(true)) {
deba@2051:     
deba@2051:       Graph::UEdgeMap<bool> mm(graph);
deba@2051:       Graph::NodeMap<int> pm(graph);
deba@2051:       
deba@2051:       bpmatch.matching(mm);
deba@2051:       bpmatch.potential(pm);
deba@2051:       
deba@2051:       for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2051:         if (mm[it]) {
deba@2058:           check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] == 0,
deba@2051:                 "INVALID DUAL");
deba@2051:         } else {
deba@2058:           check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] >= 0,
deba@2051:                 "INVALID DUAL");
deba@2051:         }
deba@2051:       }
deba@2051: 
deba@2051:       for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2051:         int num = 0;
deba@2051:         for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2051:           if (mm[jt]) ++num;
deba@2051:         }
deba@2051:         check(num <= 1, "INVALID PRIMAL");
deba@2051:       }
deba@2051:       if (bpmatch.matchingValue() > max_weight) {
deba@2051:         max_weight = bpmatch.matchingValue();
deba@2051:       }
deba@2051:     }
deba@2051:   }
deba@2051: 
deba@2051:   {
deba@2058:     Graph::UEdgeMap<bool> mm(graph);
deba@2058: 
deba@2058:     check(max_weight == maxWeightedBipartiteMatching(graph, weight, mm),
deba@2058:           "WRONG MATCHING");
deba@2058:     
deba@2058:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2058:       int num = 0;
deba@2058:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2058:         if (mm[jt]) ++num;
deba@2058:       }
deba@2058:       check(num <= 1, "INVALID PRIMAL");
deba@2058:     }
deba@2058:   }
deba@2058: 
deba@2058:   {
deba@2051:     MaxWeightedBipartiteMatching<Graph> bpmatch(graph, weight);
deba@2040: 
deba@2040:     bpmatch.run();
deba@2051:     
deba@2051:     Graph::UEdgeMap<bool> mm(graph);
deba@2051:     Graph::NodeMap<int> pm(graph);
deba@2040: 
deba@2051:     bpmatch.matching(mm);
deba@2051:     bpmatch.potential(pm);
deba@2040:     
deba@2040:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2051:       if (mm[it]) {
deba@2058:         check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] == 0,
deba@2051:               "INVALID DUAL");
deba@2051:       } else {
deba@2058:         check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] >= 0,
deba@2051:               "INVALID DUAL");
deba@2051:       }
deba@2040:     }
deba@2051: 
deba@2040:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2040:       int num = 0;
deba@2040:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2040:         if (mm[jt]) ++num;
deba@2040:     }
deba@2040:       check(num <= 1, "INVALID PRIMAL");
deba@2040:     }
deba@2051:     check(max_weight == bpmatch.matchingValue(), "WRONG WEIGHT");
deba@2051:   }
deba@2051: 
deba@2051:   {
deba@2051:     MaxWeightedBipartiteMatching<Graph> bpmatch(graph, weight);
deba@2051: 
deba@2051:     bpmatch.run(true);
deba@2051:     
deba@2051:     Graph::UEdgeMap<bool> mm(graph);
deba@2051:     Graph::NodeMap<int> pm(graph);
deba@2051: 
deba@2051:     bpmatch.matching(mm);
deba@2051:     bpmatch.potential(pm);
deba@2051:     
deba@2051:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2051:       if (mm[it]) {
deba@2058:         check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] == 0,
deba@2051:               "INVALID DUAL");
deba@2051:       } else {
deba@2058:         check(pm[graph.aNode(it)] + pm[graph.bNode(it)] - weight[it] >= 0,
deba@2051:               "INVALID DUAL");
deba@2051:       }
deba@2051:     }
deba@2051: 
deba@2051:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2051:       int num = 0;
deba@2051:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2051:         if (mm[jt]) ++num;
deba@2051:     }
deba@2051:       check(num <= 1, "INVALID PRIMAL");
deba@2051:     }
deba@2051:     check(max_cardinality == bpmatch.matchingSize(), "WRONG SIZE");
deba@2051:     max_cardinality_max_weight = bpmatch.matchingValue();
deba@2051: 
deba@2051:   }
deba@2051: 
deba@2051:   {
deba@2058:     Graph::UEdgeMap<bool> mm(graph);
deba@2051: 
deba@2058:     check(max_cardinality_max_weight == 
deba@2058:           maxWeightedMaxBipartiteMatching(graph, weight, mm),
deba@2058:           "WRONG MATCHING");
deba@2058:     
deba@2058:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2058:       int num = 0;
deba@2058:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2058:         if (mm[jt]) ++num;
deba@2058:       }
deba@2058:       check(num <= 1, "INVALID PRIMAL");
deba@2058:     }
deba@2058:   }
deba@2058: 
deba@2058:   Graph::UEdgeMap<int> cost(graph);
deba@2058:   cost = subMap(constMap<UEdge>(c), weight);
deba@2058: 
deba@2058:   {
deba@2051: 
deba@2051:     MinCostMaxBipartiteMatching<Graph> bpmatch(graph, cost);
deba@2051: 
deba@2051:     bpmatch.run();
deba@2051:     
deba@2051:     Graph::UEdgeMap<bool> mm(graph);
deba@2051:     Graph::NodeMap<int> pm(graph);
deba@2051: 
deba@2051:     bpmatch.matching(mm);
deba@2051:     bpmatch.potential(pm);
deba@2051:     
deba@2051:     for (UEdgeIt it(graph); it != INVALID; ++it) {
deba@2051:       if (mm[it]) {
deba@2051:         check(pm[graph.aNode(it)] + cost[it] - pm[graph.bNode(it)] == 0,
deba@2051:               "INVALID DUAL");
deba@2051:       } else {
deba@2051:         check(pm[graph.aNode(it)] + cost[it] - pm[graph.bNode(it)] >= 0,
deba@2051:               "INVALID DUAL");
deba@2051:       }
deba@2051:     }
deba@2051: 
deba@2051:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2051:       int num = 0;
deba@2051:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2051:         if (mm[jt]) ++num;
deba@2051:     }
deba@2051:       check(num <= 1, "INVALID PRIMAL");
deba@2051:     }
deba@2051: 
deba@2058:     min_cost_matching = bpmatch.matchingCost();
deba@2051:     check(max_cardinality == bpmatch.matchingSize(), "WRONG SIZE");
deba@2051:     check(max_cardinality * c - max_cardinality_max_weight 
deba@2051:           == bpmatch.matchingCost(), "WRONG SIZE");
deba@2051: 
deba@2040:   }
deba@2040: 
deba@2058:   {
deba@2058:     Graph::UEdgeMap<bool> mm(graph);
deba@2058: 
deba@2058:     check(min_cost_matching == 
deba@2058:           minCostMaxBipartiteMatching(graph, cost, mm),
deba@2058:           "WRONG MATCHING");
deba@2058:     
deba@2058:     for (ANodeIt it(graph); it != INVALID; ++it) {
deba@2058:       int num = 0;
deba@2058:       for (IncEdgeIt jt(graph, it); jt != INVALID; ++jt) {
deba@2058:         if (mm[jt]) ++num;
deba@2058:       }
deba@2058:       check(num <= 1, "INVALID PRIMAL");
deba@2058:     }
deba@2058:   }
deba@2058: 
deba@2040:   return 0;
deba@2040: }