Main Page   Class Hierarchy   Compound List   File List   Contact   Download   Symbolic Constraints   Examples  

matching.cc

00001 #ifndef SCIL_MATCHING_CC
00002 #define SCIL_MATCHING_CC
00003 
00004 #define LEPS 1e-8 //must be larger than 1e-10, because of the cut tree alg.
00005 
00006 /*namespace {
00007 extern "C" {
00008    void compute_tree (int n, int m, int* os, int* ot, double* oc, int* cts, int* ctt, double* ctc);
00009    }
00010 }*/
00011 
00012 using namespace boost;
00013 using namespace SCIL;
00014 using namespace std;
00015 
00016 template <typename Graph>
00017 MATCHING<Graph>::MATCHING(Graph& G_, map<vertex_descriptor, int>& NC_,
00018                           var_map<edge_descriptor>& VM_, bool perfect_)
00019    : G(G_), NC(NC_), VM(VM_), perfect(perfect_) {
00020    feps = 1.0e-4;
00021    BGL_FORALL_EDGES_T(e, G, Graph)
00022       if(VM[e].type() != Vartype_Binary) {
00023          cerr << "matching.cc: All variables in VM need to be";
00024          cerr << "Vartype_Binary" << endl;
00025          exit(1);
00026       }
00027    os = new int[num_edges(G) + num_vertices(G)];
00028    ot = new int[num_edges(G) + num_vertices(G)];
00029    oc =  new double [num_edges(G) + num_vertices(G)];
00030    cts = new int[num_vertices(G)];
00031    ctt = new int[num_vertices(G)];
00032    ctc = new double[num_vertices(G)];
00033    edg = new edge_descriptor[num_edges(G)];
00034 }
00035 
00036 template <typename Graph>
00037 MATCHING<Graph>::~MATCHING() {
00038    delete[]os;
00039    delete[]ot;
00040    delete[]oc;
00041    delete[]cts;
00042    delete[]ctt;
00043    delete[]ctc;
00044    delete[]edg;
00045 }
00046 
00047 template <typename Graph>
00048 void MATCHING<Graph>::init(subproblem& S) {
00049    if(S.configuration("MATCHING_Debug_Out")=="true")
00050       cerr << "MATCHING::init\n";
00051 
00052    typedef map<vertex_descriptor, int> cn_t;
00053    cn_t cn;
00054    associative_property_map<cn_t> pm_cn(cn);
00055    int comps = connected_components(G, pm_cn);
00056    if( comps != 1 ) {
00057       if(S.configuration("MATCHING_Debug_Out")=="true")
00058          cerr << "G is not connected! " << comps << endl;
00059       //so what?
00060       //exit(1);
00061    }
00062 
00063    //Check whether Graph is undirected
00064    typedef typename GraphTraits::directed_category directed_category;
00065    if (!(is_same<directed_category,undirected_tag>::value
00066          || is_base_and_derived<undirected_tag, directed_category>::value)) {
00067       cerr << "kconnected.cc: The graph has to be undirected." << endl;
00068       exit(1);
00069    };
00070 
00071    //Graph has to provides edges() and vertices()
00072    BOOST_CONCEPT_ASSERT((VertexAndEdgeListGraphConcept<Graph>));
00073    //Graph has to provide out_edges()
00074    BOOST_CONCEPT_ASSERT((IncidenceGraphConcept<Graph>));
00075    //Graph has to provide remove_edge()
00076    BOOST_CONCEPT_ASSERT((MutableGraphConcept<Graph>));
00077 
00078    int cap = 0;
00079    int i = 1;
00080    BGL_FORALL_VERTICES_T(v, G, Graph) {
00081       nid[v] = i++;
00082       cap += NC[v];
00083 
00084       if( NC[v] < 0 ) {
00085          if(S.configuration("MATCHING_Debug_Out")=="true")
00086             cerr << "MATCHING::init   Node capacities must be positive!" << endl;
00087          exit(1);
00088       }
00089 
00090       //add the capacity equalities
00091       row r;
00092       typename GraphTraits::out_edge_iterator oe_it, oe_it_end;
00093       for(tie(oe_it, oe_it_end) = out_edges(v, G); oe_it != oe_it_end; oe_it++)
00094          r += VM[*oe_it];
00095       if( perfect )
00096          S.add_basic_constraint(r==NC[v], Static);
00097       else
00098          S.add_basic_constraint(r<=NC[v], Static);
00099    }
00100 
00101    if( perfect && cap % 2 != 0 ) {
00102       if(S.configuration("MATCHING_Debug_Out")=="true")
00103          cerr << "MATCHING::init   Sum of node capacities must be even for perfect matchings!" << endl;
00104       exit(1);
00105    }
00106 
00107    i = 0;
00108    BGL_FORALL_EDGES_T(e, G, Graph) {
00109       os[i] = nid[source(e, G)];
00110       ot[i] = nid[target(e, G)];
00111       edg[i] = e;
00112       i++;
00113    }
00114 
00115    return;
00116 }
00117 
00118 template <typename Graph>
00119 int MATCHING<Graph>::exactBlossomSeparation(subproblem& S) {
00120    if(S.configuration("MATCHING_Debug_Out")=="true")
00121       cerr << "MATCHING::exactBlossomSeparation\n";
00122 
00123    int numfound = 0;
00124    Graph H;
00125    map<edge_descriptor, double> ctc;
00126    map<vertex_descriptor, vertex_descriptor> p;
00127    map<vertex_descriptor, double> fl;
00128    double x;
00129    BGL_FORALL_EDGES_T(b, G, Graph) {
00130       x = S.value(VM[b]);
00131       ctc[b] = (x < .5) ? x: 1. - x;
00132    }
00133    computeCutTree(G, ctc, p, fl);
00134 
00135    //for each cut induced by an edge in the cut tree determine the cut edges in G 
00136    BGL_FORALL_VERTICES_T(v, G, Graph) {
00137       if( p[v] == v )
00138          continue;
00139       row s;
00140       int rt = 0;
00141 
00142       //temporarily delete one edge of the cut tree
00143       vertex_descriptor ov = p[v];
00144       p[v] = v;
00145 
00146       //determine the cut nodes
00147       typedef map<vertex_descriptor, set<vertex_descriptor>* > vertex_partition;
00148       vertex_partition vpartition;
00149       //Initialize the vertex_partition
00150       BGL_FORALL_VERTICES_T(w, G, Graph) {
00151          vpartition[w] = new set<vertex_descriptor>();
00152          vpartition[w]->insert(w);
00153       }
00154 
00155       //Union sets of vertices w with sets of vertices p[w]
00156       BGL_FORALL_VERTICES_T(w, G, Graph) {
00157          set<vertex_descriptor> *tmp = vpartition[p[w]];
00158          vpartition[w]->insert(tmp->begin(), tmp->end());
00159          typename set<vertex_descriptor>::iterator it;
00160          //Update the pointers of the vertices in vpartition[p[w]]
00161          for(it = tmp->begin(); it != tmp->end(); it++)
00162             vpartition[*it] = vpartition[w];
00163       }
00164 
00165       vertex_descriptor t = *(vertices(G).first);
00166 
00167       int bW = 0;
00168       BGL_FORALL_VERTICES_T(w, G, Graph) {
00169                if( *(vpartition[w]) == *(vpartition[t]) )
00170                   bW += NC[v]%2; 
00171                //bW += NC[w]; 
00172       }
00173 
00174       list<edge_descriptor> F; //the cut edges with 1 - x^* < x^*
00175       list<edge_descriptor> delta; //the cut edges that are not in F
00176       BGL_FORALL_EDGES_T(f, G, Graph) {
00177          if( !(*(vpartition[source(f, G)]) == *(vpartition[target(f, G)])) ) {
00178             if( S.value(VM[f]) > .5 )
00179                F.push_back(f);
00180             else
00181                delta.push_back(f);
00182          }
00183       }
00184 
00185       // if b(W) + |F| is odd, we take F and construct the blossom 
00186       // inequality, if lhs < 1.
00187       // Otherwise we construct F' (symmetric difference) and proceed. 
00188 
00189       edge_descriptor f;
00190       if( ((bW + F.size()) % 2) == 0 ) {
00191          edge_descriptor ff;
00192          double m;
00193          double minm = 2.;
00194          bool fffound = false;
00195          BOOST_FOREACH(f, delta) {
00196             m = fabs((2. * S.value(VM[f])) - 1.);
00197             if( m <= minm ) {
00198                minm = m;
00199                ff = f;
00200             }
00201          }
00202          BOOST_FOREACH(f, F) {
00203             m = fabs((2. * S.value(VM[f])) - 1.);
00204             if( m <= minm ) {
00205                minm = m;
00206                ff = f;
00207                fffound = true;
00208             }
00209          }
00210          // the symmetric diff. of F and {ff} is 
00211          // F \ ff, if ff \in F, F \cup ff else 
00212          if( fffound ) {
00213             F.remove(ff);
00214             delta.push_back(ff);
00215          }
00216          else {
00217             F.push_back(ff);
00218             delta.remove(ff);
00219          }
00220       }
00221 
00222       //construct the violated blossom inequality
00223       double rhs = 1. - double(F.size()); 
00224       row r;
00225       BOOST_FOREACH(f, delta) {
00226          r += VM[f];
00227       }
00228       BOOST_FOREACH(f, F) {
00229          r -= VM[f];
00230       }
00231      
00232       if( r.size() > 0 ) {
00233          if(S.configuration("MATCHING_Debug_Out")=="true")
00234             cerr << "constraint found" << endl;
00235          if( !perfect ) {
00236             rhs += double(rt);
00237             r += s;
00238          }
00239 
00240          //r.normalize(true);
00241          cons_obj* c = (r>=rhs);
00242          if( c->violation(S) > feps ) {
00243             if(S.configuration("MATCHING_Debug_Out")=="true")
00244                cerr << r << " >= " << rhs << endl;
00245             S.add_basic_constraint(r>=rhs); 
00246             numfound++;
00247          }
00248          delete c;
00249       }
00250       p[v] = ov;
00251    }
00252    if(S.configuration("MATCHING_Debug_Out")=="true")
00253       cerr << "MAT: " << numfound << endl;
00254    return numfound;
00255 }
00256 
00257 template <typename Graph>
00258 typename MATCHING<Graph>::status MATCHING<Graph>::feasible(solution& S) {
00259    if(S.originating_subproblem()->configuration("MATCHING_Debug_Out")=="true")
00260       cerr << "MATCHING::feasible\n";
00261 /*   double b;
00262 
00263    BGL_FORALL_VERTICES_T(v, G, Graph) {
00264       b = 0.;
00265       typename GraphTraits::out_edge_iterator oe_it, oe_it_end;
00266       for(tie(oe_it, oe_it_end) = out_edges(v, G); oe_it != oe_it_end; oe_it++) 
00267          b += S.value(VM[*oe_it]);
00268       if( perfect ) {
00269          if( fabs(b - double(NC[v])) > LEPS )
00270             return infeasible_solution;
00271       } else {
00272          if ( b + LEPS > double(NC[v]) )
00273             return infeasible_solution;
00274       }
00275    }*/
00276    return feasible_solution;
00277 }
00278 
00279 //compare Cunha and Lucena 'A Hybrid Relax and Cut
00280 //Branch-And-Cut Algorithm for the DCMST-Problem
00281 template <typename Graph>
00282 int MATCHING<Graph>::heuristicBlossomSeparation(subproblem& S) {
00283    if(S.configuration("MATCHING_Debug_Out")=="true")
00284       cerr << "MATCHING::heuristicBlossomSeparation\n";
00285 
00286    int numfound = 0;
00287 
00288    list<edge_descriptor> edgesH;
00289    list<edge_descriptor> edgesNotH;
00290    map<vertex_descriptor, vertex_descriptor> verticesHtoG;
00291    map<vertex_descriptor, vertex_descriptor> verticesGtoH;
00292    map<edge_descriptor, edge_descriptor> edgesHtoG;
00293    Graph H;
00294    BGL_FORALL_VERTICES_T(v, G, Graph) {
00295       vertex_descriptor newNodeInH = add_vertex(H);
00296       verticesHtoG[newNodeInH] = v;
00297       verticesGtoH[v] = newNodeInH;
00298    }
00299    BGL_FORALL_EDGES_T(e, G, Graph) {
00300       edge_descriptor newEdgeInH = (add_edge(verticesGtoH[source(e, G)], 
00301                                              verticesGtoH[target(e, G)],
00302                                              H)).first;
00303       edgesHtoG[newEdgeInH] = e;
00304    }
00305 
00306    list<edge_descriptor> toBeDeleted;
00307    BGL_FORALL_EDGES_T(e, H, Graph) {
00308       if( (S.value(VM[edgesHtoG[e]]) < LEPS)
00309           || (S.value(VM[edgesHtoG[e]]) > 1. - LEPS) ) {
00310          edgesNotH.push_back(edgesHtoG[e]);
00311          toBeDeleted.push_back(e);
00312       } else
00313          edgesH.push_back(edgesHtoG[e]);
00314    }
00315    edge_descriptor e;
00316    BOOST_FOREACH(e, toBeDeleted)
00317       remove_edge(e, H);
00318 
00319    typedef map<vertex_descriptor, int> compnumH_t;
00320    compnumH_t compnumH;
00321    associative_property_map<compnumH_t> pm_compnumH(compnumH);
00322    int comps = connected_components(H, pm_compnumH);
00323 
00324    if( comps < 2 )
00325       return 0;
00326 
00327    compnumH_t compnum;
00328    BGL_FORALL_VERTICES_T(v, H, Graph)
00329       compnum[verticesHtoG[v]] = compnumH[v];
00330    
00331    for( int i = 0; i < comps; i++ ) {
00332       row r;
00333       double rhs = 1.;
00334       edge_descriptor e;
00335       BOOST_FOREACH(e, edgesNotH) {
00336                vertex_descriptor s = source(e, G);
00337                vertex_descriptor t = target(e, G);
00338                if( ((compnum[s] == i) || (compnum[t] == i)) && compnum[s] != compnum[t] ) {
00339                   if( S.value(VM[e]) > 1. - LEPS ) {
00340                      r -= VM[e];
00341                      rhs -= 1.;
00342                   }
00343                   else 
00344                      r += VM[e];
00345                }
00346       }
00347 
00348       int b = 0;
00349       int c = 0;
00350       double sl = 0.;
00351       BGL_FORALL_VERTICES_T(v, G, Graph) {
00352          if( compnum[v] == i ) {
00353             rhs -= NC[v];
00354             b += NC[v];
00355             typename GraphTraits::out_edge_iterator it, it_end;
00356             for(tie(it, it_end) = out_edges(v, G); it != it_end; it++) {
00357                r -= VM[*it];
00358                sl += S.value(VM[*it]);
00359                if( S.value(VM[*it]) > 1. - LEPS )
00360                       c++;
00361                   }
00362                }
00363       }
00364 
00365 
00366       if( ((b - c) % 2) && (double(b) - sl < 1. - LEPS) ) {
00367          //FIXME
00368          r.normalize();
00369          if( r.size() > 0 ) {
00370             S.add_basic_constraint(r>=rhs);
00371             numfound++;
00372          }
00373       }
00374    }
00375    if(S.configuration("MATCHING_Debug_Out")=="true")
00376       cerr << "h: numfound:" << numfound << endl;
00377    return numfound;
00378 }
00379 
00380 template <typename Graph>
00381 typename MATCHING<Graph>::status MATCHING<Graph>::standard_separation(subproblem& S) {
00382    if(S.configuration("MATCHING_Debug_Out")=="true")
00383       cerr << "MATCHING::standard_separation\n";
00384 
00385    if( heuristicBlossomSeparation(S) )
00386       return constraint_found; 
00387    if( perfect && exactBlossomSeparation(S) )
00388       return constraint_found;
00389    else
00390       return no_constraint_found;
00391 }
00392 
00393 template <typename Graph>
00394 typename MATCHING<Graph>::status MATCHING<Graph>::fast_separation(subproblem& S) {
00395    if(S.configuration("MATCHING_Debug_Out")=="true")
00396       cerr << "MATCHING::fast_separation\n";
00397 
00398    if( heuristicBlossomSeparation(S) )
00399       return constraint_found;
00400    else
00401       return no_constraint_found;
00402 }
00403 
00404 
00405 template <typename Graph>
00406 void MATCHING<Graph>::info() {
00407    cout<<"Configurations:\n";
00408    cout<<"MATCHING_Debug_Out [true|false]\n";
00409 };
00410 #endif
Generated on Mon Mar 28 22:03:48 2011 for SCIL by  doxygen 1.6.3