Test program for max weighted matchings
authordeba
Sat, 29 Dec 2007 15:11:41 +0000
changeset 254988b81ec599ed
parent 2548 a3ba22ebccc6
child 2550 f26368148b9c
Test program for max weighted matchings
lemon/max_matching.h
test/Makefile.am
test/max_weighted_matching_test.cc
     1.1 --- a/lemon/max_matching.h	Fri Dec 28 11:00:51 2007 +0000
     1.2 +++ b/lemon/max_matching.h	Sat Dec 29 15:11:41 2007 +0000
     1.3 @@ -30,7 +30,7 @@
     1.4  
     1.5  ///\ingroup matching
     1.6  ///\file
     1.7 -///\brief Maximum matching algorithm in undirected graph.
     1.8 +///\brief Maximum matching algorithms in undirected graph.
     1.9  
    1.10  namespace lemon {
    1.11  
    1.12 @@ -1467,7 +1467,7 @@
    1.13        int b = _blossom_set->find(_ugraph.source(pred));
    1.14        int d = _blossom_set->find(_ugraph.source(next));
    1.15        
    1.16 -      int ib, id;
    1.17 +      int ib = -1, id = -1;
    1.18        for (int i = 0; i < int(subblossoms.size()); ++i) {
    1.19  	if (subblossoms[i] == b) ib = i;
    1.20  	if (subblossoms[i] == d) id = i;
    1.21 @@ -2654,7 +2654,7 @@
    1.22        int b = _blossom_set->find(_ugraph.source(pred));
    1.23        int d = _blossom_set->find(_ugraph.source(next));
    1.24        
    1.25 -      int ib, id;
    1.26 +      int ib = -1, id = -1;
    1.27        for (int i = 0; i < int(subblossoms.size()); ++i) {
    1.28  	if (subblossoms[i] == b) ib = i;
    1.29  	if (subblossoms[i] == d) id = i;
     2.1 --- a/test/Makefile.am	Fri Dec 28 11:00:51 2007 +0000
     2.2 +++ b/test/Makefile.am	Sat Dec 29 15:11:41 2007 +0000
     2.3 @@ -30,6 +30,7 @@
     2.4  	test/maps_test \
     2.5  	test/matrix_maps_test \
     2.6  	test/max_matching_test \
     2.7 +	test/max_weighted_matching_test \
     2.8  	test/min_cost_flow_test \
     2.9  	test/path_test \
    2.10  	test/polynomial_test \
    2.11 @@ -79,6 +80,7 @@
    2.12  test_maps_test_SOURCES = test/maps_test.cc
    2.13  test_matrix_maps_test_SOURCES = test/matrix_maps_test.cc
    2.14  test_max_matching_test_SOURCES = test/max_matching_test.cc
    2.15 +test_max_weighted_matching_test_SOURCES = test/max_weighted_matching_test.cc
    2.16  test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
    2.17  test_path_test_SOURCES = test/path_test.cc
    2.18  test_polynomial_test_SOURCES = test/polynomial_test.cc
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/max_weighted_matching_test.cc	Sat Dec 29 15:11:41 2007 +0000
     3.3 @@ -0,0 +1,253 @@
     3.4 +/* -*- C++ -*-
     3.5 + *
     3.6 + * This file is a part of LEMON, a generic C++ optimization library
     3.7 + *
     3.8 + * Copyright (C) 2003-2007
     3.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    3.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    3.11 + *
    3.12 + * Permission to use, modify and distribute this software is granted
    3.13 + * provided that this copyright notice appears in all copies. For
    3.14 + * precise terms see the accompanying LICENSE file.
    3.15 + *
    3.16 + * This software is provided "AS IS" with no warranty of any kind,
    3.17 + * express or implied, and with no claim as to its suitability for any
    3.18 + * purpose.
    3.19 + *
    3.20 + */
    3.21 +
    3.22 +#include <iostream>
    3.23 +#include <sstream>
    3.24 +#include <vector>
    3.25 +#include <queue>
    3.26 +#include <cmath>
    3.27 +#include <cstdlib>
    3.28 +
    3.29 +#include "test_tools.h"
    3.30 +#include <lemon/smart_graph.h>
    3.31 +#include <lemon/max_matching.h>
    3.32 +#include <lemon/graph_reader.h>
    3.33 +
    3.34 +UGRAPH_TYPEDEFS(SmartUGraph);
    3.35 +
    3.36 +using namespace std;
    3.37 +using namespace lemon;
    3.38 +
    3.39 +const int lgfn = 3;
    3.40 +const std::string lgf[lgfn] = {   
    3.41 +  "@nodeset\n"
    3.42 +  "label\n"
    3.43 +  "0\n"
    3.44 +  "1\n"
    3.45 +  "2\n"
    3.46 +  "3\n"
    3.47 +  "4\n"
    3.48 +  "5\n"
    3.49 +  "6\n"
    3.50 +  "7\n"
    3.51 +  "@uedgeset\n"
    3.52 +  "label        weight\n"
    3.53 +  "7    4       0       984\n"
    3.54 +  "0    7       1       73\n"
    3.55 +  "7    1       2       204\n"
    3.56 +  "2    3       3       583\n"
    3.57 +  "2    7       4       565\n"
    3.58 +  "2    1       5       582\n"
    3.59 +  "0    4       6       551\n"
    3.60 +  "2    5       7       385\n"
    3.61 +  "1    5       8       561\n"
    3.62 +  "5    3       9       484\n"
    3.63 +  "7    5       10      904\n"
    3.64 +  "3    6       11      47\n"
    3.65 +  "7    6       12      888\n"
    3.66 +  "3    0       13      747\n"
    3.67 +  "6    1       14      310\n"
    3.68 +  "@end\n",
    3.69 +
    3.70 +  "@nodeset\n"
    3.71 +  "label\n"
    3.72 +  "0\n"
    3.73 +  "1\n"
    3.74 +  "2\n"
    3.75 +  "3\n"
    3.76 +  "4\n"
    3.77 +  "5\n"
    3.78 +  "6\n"
    3.79 +  "7\n"
    3.80 +  "@uedgeset\n"
    3.81 +  "label        weight\n"
    3.82 +  "2    5       0       710\n"
    3.83 +  "0    5       1       241\n"
    3.84 +  "2    4       2       856\n"
    3.85 +  "2    6       3       762\n"
    3.86 +  "4    1       4       747\n"
    3.87 +  "6    1       5       962\n"
    3.88 +  "4    7       6       723\n"
    3.89 +  "1    7       7       661\n"
    3.90 +  "2    3       8       376\n"
    3.91 +  "1    0       9       416\n"
    3.92 +  "6    7       10      391\n"
    3.93 +  "@end\n",
    3.94 +
    3.95 +  "@nodeset\n"
    3.96 +  "label\n"
    3.97 +  "0\n"
    3.98 +  "1\n"
    3.99 +  "2\n"
   3.100 +  "3\n"
   3.101 +  "4\n"
   3.102 +  "5\n"
   3.103 +  "6\n"
   3.104 +  "7\n"
   3.105 +  "@uedgeset\n"
   3.106 +  "label        weight\n"
   3.107 +  "6    2       0       553\n"
   3.108 +  "0    7       1       653\n"
   3.109 +  "6    3       2       22\n"
   3.110 +  "4    7       3       846\n"
   3.111 +  "7    2       4       981\n"
   3.112 +  "7    6       5       250\n"
   3.113 +  "5    2       6       539\n"
   3.114 +  "@end\n"
   3.115 +};
   3.116 +
   3.117 +void checkMatching(const SmartUGraph& ugraph,
   3.118 +		   const SmartUGraph::UEdgeMap<int>& weight,
   3.119 +		   const MaxWeightedMatching<SmartUGraph>& mwm) {
   3.120 +  for (SmartUGraph::UEdgeIt e(ugraph); e != INVALID; ++e) {
   3.121 +    if (ugraph.source(e) == ugraph.target(e)) continue;
   3.122 +    int rw = 
   3.123 +      mwm.nodeValue(ugraph.source(e)) + mwm.nodeValue(ugraph.target(e));
   3.124 +
   3.125 +    for (int i = 0; i < mwm.blossomNum(); ++i) {
   3.126 +      bool s = false, t = false;
   3.127 +      for (MaxWeightedMatching<SmartUGraph>::BlossomIt n(mwm, i); 
   3.128 +	   n != INVALID; ++n) {
   3.129 +	if (ugraph.source(e) == n) s = true;
   3.130 +	if (ugraph.target(e) == n) t = true;
   3.131 +      }
   3.132 +      if (s == true && t == true) {
   3.133 +	rw += mwm.blossomValue(i);
   3.134 +      }
   3.135 +    }
   3.136 +    rw -= weight[e] * mwm.dualScale;
   3.137 +
   3.138 +    check(rw >= 0, "Negative reduced weight");
   3.139 +    check(rw == 0 || !mwm.matching(e), 
   3.140 +	  "Non-zero reduced weight on matching edge");
   3.141 +  }
   3.142 +
   3.143 +  int pv = 0;
   3.144 +  for (SmartUGraph::NodeIt n(ugraph); n != INVALID; ++n) {
   3.145 +    if (mwm.matching(n) != INVALID) {
   3.146 +      check(mwm.nodeValue(n) >= 0, "Invalid node value");
   3.147 +      pv += weight[mwm.matching(n)];
   3.148 +      SmartUGraph::Node o = ugraph.target(mwm.matching(n));
   3.149 +      check(mwm.mate(n) == o, "Invalid matching");
   3.150 +      check(mwm.matching(n) == ugraph.oppositeEdge(mwm.matching(o)), 
   3.151 +	    "Invalid matching");
   3.152 +    } else {
   3.153 +      check(mwm.mate(n) == INVALID, "Invalid matching");
   3.154 +      check(mwm.nodeValue(n) == 0, "Invalid matching");
   3.155 +    }
   3.156 +  }
   3.157 +
   3.158 +  int dv = 0;
   3.159 +  for (SmartUGraph::NodeIt n(ugraph); n != INVALID; ++n) {
   3.160 +    dv += mwm.nodeValue(n);
   3.161 +  }
   3.162 +
   3.163 +  for (int i = 0; i < mwm.blossomNum(); ++i) {
   3.164 +    check(mwm.blossomValue(i) >= 0, "Invalid blossom value");
   3.165 +    check(mwm.blossomSize(i) % 2 == 1, "Even blossom size");
   3.166 +    dv += mwm.blossomValue(i) * ((mwm.blossomSize(i) - 1) / 2);
   3.167 +  }
   3.168 +
   3.169 +  check(pv * mwm.dualScale == dv * 2, "Wrong duality");
   3.170 +
   3.171 +  return;
   3.172 +}
   3.173 +
   3.174 +void checkPerfectMatching(const SmartUGraph& ugraph,
   3.175 +			  const SmartUGraph::UEdgeMap<int>& weight,
   3.176 +			  const MaxWeightedPerfectMatching<SmartUGraph>& mwpm) {
   3.177 +  for (SmartUGraph::UEdgeIt e(ugraph); e != INVALID; ++e) {
   3.178 +    if (ugraph.source(e) == ugraph.target(e)) continue;
   3.179 +    int rw = 
   3.180 +      mwpm.nodeValue(ugraph.source(e)) + mwpm.nodeValue(ugraph.target(e));
   3.181 +
   3.182 +    for (int i = 0; i < mwpm.blossomNum(); ++i) {
   3.183 +      bool s = false, t = false;
   3.184 +      for (MaxWeightedPerfectMatching<SmartUGraph>::BlossomIt n(mwpm, i); 
   3.185 +	   n != INVALID; ++n) {
   3.186 +	if (ugraph.source(e) == n) s = true;
   3.187 +	if (ugraph.target(e) == n) t = true;
   3.188 +      }
   3.189 +      if (s == true && t == true) {
   3.190 +	rw += mwpm.blossomValue(i);
   3.191 +      }
   3.192 +    }
   3.193 +    rw -= weight[e] * mwpm.dualScale;
   3.194 +
   3.195 +    check(rw >= 0, "Negative reduced weight");
   3.196 +    check(rw == 0 || !mwpm.matching(e), 
   3.197 +	  "Non-zero reduced weight on matching edge");
   3.198 +  }
   3.199 +
   3.200 +  int pv = 0;
   3.201 +  for (SmartUGraph::NodeIt n(ugraph); n != INVALID; ++n) {
   3.202 +    check(mwpm.matching(n) != INVALID, "Non perfect");
   3.203 +    pv += weight[mwpm.matching(n)];
   3.204 +    SmartUGraph::Node o = ugraph.target(mwpm.matching(n));
   3.205 +    check(mwpm.mate(n) == o, "Invalid matching");
   3.206 +    check(mwpm.matching(n) == ugraph.oppositeEdge(mwpm.matching(o)), 
   3.207 +	  "Invalid matching");
   3.208 +  }
   3.209 +
   3.210 +  int dv = 0;
   3.211 +  for (SmartUGraph::NodeIt n(ugraph); n != INVALID; ++n) {
   3.212 +    dv += mwpm.nodeValue(n);
   3.213 +  }
   3.214 +
   3.215 +  for (int i = 0; i < mwpm.blossomNum(); ++i) {
   3.216 +    check(mwpm.blossomValue(i) >= 0, "Invalid blossom value");
   3.217 +    check(mwpm.blossomSize(i) % 2 == 1, "Even blossom size");
   3.218 +    dv += mwpm.blossomValue(i) * ((mwpm.blossomSize(i) - 1) / 2);
   3.219 +  }
   3.220 +
   3.221 +  check(pv * mwpm.dualScale == dv * 2, "Wrong duality");
   3.222 +
   3.223 +  return;
   3.224 +}
   3.225 +
   3.226 +
   3.227 +int main() {
   3.228 +
   3.229 +  for (int i = 0; i < lgfn; ++i) {
   3.230 +    SmartUGraph ugraph;
   3.231 +    SmartUGraph::UEdgeMap<int> weight(ugraph);
   3.232 +    
   3.233 +    istringstream lgfs(lgf[i]);
   3.234 +    UGraphReader<SmartUGraph>(lgfs, ugraph).
   3.235 +      readUEdgeMap("weight", weight).run();
   3.236 +
   3.237 +    MaxWeightedMatching<SmartUGraph> mwm(ugraph, weight);
   3.238 +    mwm.run();
   3.239 +    checkMatching(ugraph, weight, mwm);
   3.240 +
   3.241 +    MaxMatching<SmartUGraph> mm(ugraph);
   3.242 +    mm.run();
   3.243 +
   3.244 +    MaxWeightedPerfectMatching<SmartUGraph> mwpm(ugraph, weight);
   3.245 +    bool perfect = mwpm.run();
   3.246 +
   3.247 +    check(perfect == (mm.size() * 2 == countNodes(ugraph)), 
   3.248 +	  "Perfect matching found");
   3.249 +
   3.250 +    if (perfect) {
   3.251 +      checkPerfectMatching(ugraph, weight, mwpm);
   3.252 +    }
   3.253 +  }
   3.254 +  
   3.255 +  return 0;
   3.256 +}