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

tour.cc

00001 #ifndef SCIL_TOUR_CC
00002 #define SCIL_TOUR_CC
00003 
00004 #include<scil/scil.h>
00005 #include<LEDA/graph.h>
00006 #include<LEDA/graph_alg.h>
00007 #include<LEDA/set.h>
00008 #include<scil/constraints/tour.h>
00009 
00010 using namespace SCIL;
00011 using namespace LEDA;
00012 
00013 #define VALONE 1000000
00014 
00015 class TOUR::degree_equality : public cons_obj
00016 {
00017   private:
00018   const graph& G;
00019   node v;
00020   double deg;
00021   scil_map<edge>& VM;
00022 
00023   public:
00024 
00025   // The constructor saves the references to the graph and to the scil_map<edge>
00026   // Furthermore we save the right hand side and the given node of the constraint.
00027   // We initialize the sense and the right hand side with equal and the given
00028   // right hand side.
00029   degree_equality(const graph& G_, node v_, scil_map<edge>& VM_,
00030                   double d)
00031   : cons_obj(Equal, d), G(G_), VM(VM_) { 
00032     v=v_; deg=d; 
00033   };
00034   
00035   virtual
00036   ~degree_equality()
00037   {};
00038   
00039   node gnode() { return v; };
00040 
00041   // To generate the row, we can simply iterate over all edges adjacent to
00042   // the node of the degree constraint and add the appropriate variables.
00043   virtual void non_zero_entries(row& r) {
00044     edge e;
00045     forall_inout_edges(e, v) {
00046       r+=VM(e);
00047     }
00048   };
00049 }; // END_OF_CLASS_DEGREE_EQUALITY
00050 
00051 class TOUR::cutset_inequality : public cons_obj {
00052   private:
00053   graph& G;
00054   scil_map<edge>& VM;
00055   node_array<bool> cut;
00056   double rhs;
00057   
00058   public:
00059   
00060   cutset_inequality(graph& Gt, scil_map<edge>& VM_, list<node>& L) 
00061   : cons_obj(Greater, 2), G(Gt), VM(VM_) {
00062     node v;
00063     cut.init(G, false);
00064     forall(v,L) cut[v]=true;
00065   }
00066 
00067   void non_zero_entries(row& r) { 
00068     edge e;
00069     forall_edges(e,G) {
00070       if(coeff(e)==1) r+=VM(e);
00071     }
00072   }
00073 
00074   virtual
00075   ~cutset_inequality() {};
00076 
00077   double coeff(edge e) { 
00078     if(e==nil) return 0;
00079     if(cut[G.source(e)] != cut[G.target(e)]) return 1;
00080     return(0);
00081   };
00082 };
00083 
00084 TOUR::TOUR(graph& G_, scil_map<edge>& VM_)
00085   /*{\Mcreate Ensures that the edges in VM form a Hamiltonian cycle.\\
00086     For a demo, see: gtsp.}*/
00087   : G(G_), VM(VM_) { 
00088 };
00089 
00090 void TOUR::init(subproblem& S) {
00091   node v;
00092   forall_nodes(v, G) {
00093     S.add_basic_constraint(new degree_equality(G,v,VM,2));
00094   }
00095 };
00096   
00097 TOUR::status TOUR::separate(subproblem& S) {
00098   // Preperation : Read the current LP-values of all edges
00099   //               We multiply the value with VALONE and round to the next integer
00100   int i=0;
00101   edge_array<int> val(G);
00102   edge e;
00103   forall_edges(e, G) val[e]=(int) (VALONE*S.value(VM(e)));
00104 
00105   // Heuristic : We create a copy H of G, where all edges with LP-value less than
00106   //             1 are deleted from the graph. We compute the connected components
00107   //             of this graph and check the subtour elemination constraints
00108   //             corresponding to the components for violation
00109   graph H;
00110   node u;
00111   node_array<node> HtoG(H, G.number_of_nodes(), u);
00112   node_array<node> GtoH(G);
00113   
00114   // Copy all nodes of G
00115   forall_nodes(u, G) { GtoH[u]=H.new_node(); HtoG[GtoH[u]]=u; }
00116   
00117   // Copy the edges with value close to 1
00118   forall_edges(e, G) if(val[e]>=VALONE-5)
00119     H.new_edge(GtoH[source(e)], GtoH[target(e)]);
00120   
00121   // Compute the connected components
00122   node_array<int> CC(H);
00123   int k=COMPONENTS(H,CC);
00124   list<node> CCL[k];
00125   forall_nodes(u,H) CCL[CC[u]].append(HtoG[u]);
00126 
00127   // Create the corresponding subtour elemination constraints and check for
00128   // violation
00129   if(k>1) {
00130     for(int j=0;j<k;j++) {
00131       cons_obj* c=new cutset_inequality(G,VM,CCL[j]);
00132       if (c->violated(S)) { 
00133         i++;
00134         S.add_basic_constraint(c, Dynamic); 
00135       } else delete c;
00136     }
00137   }
00138 
00139   // If the heuristic found a violated constraint, we stop the separation
00140   if(i>0) { 
00141     cout<<i<<" Heuristic\n"; return constraint_found; 
00142   }
00143 
00144   // If only the fast heuristic should be applied, we stop the separation  
00145   //if(S.configuration("TOUR_heuristic_only")=="true") 
00146   //  return no_constraint_found;
00147 
00148   // exact separation : We compute the minimal cut in G and check the
00149   //                    corresponding subtour elimination constraint for
00150   //                    violation
00151   list<node> mc=MIN_CUT(G, val);
00152   cons_obj* c=new cutset_inequality(G,VM,mc);
00153   if (c->violated(S)) {
00154     i++; S.add_basic_constraint(c, Dynamic);
00155   } else delete c;
00156 
00157   // return the correct value
00158   if(i>0) {
00159     return constraint_found;
00160   }
00161 
00162   return no_constraint_found;
00163 
00164   H.del_all_edges();
00165 
00166   // Copy the edges with fractional value
00167   forall_edges(e, G) if((val[e]>=5) && (val[e]<=VALONE-5))
00168     H.new_edge(GtoH[source(e)], GtoH[target(e)]);
00169   
00170   // Compute the connected components
00171   {
00172     node_array<int> CC(H);
00173     int k=COMPONENTS(H,CC);
00174     list<node> CCL[k];
00175     forall_nodes(u,H) CCL[CC[u]].append(HtoG[u]);
00176 
00177     // Create the corresponding comb constraints and check for
00178     // violation
00179     node v;
00180     node_array<bool> R(G, false);
00181     if(k>1) {
00182       for(int j=0;j<k;j++) {
00183         row r;
00184         forall(v, CCL[j]) R[v]=true;
00185         double d=0;
00186         int t=0;
00187         forall_edges(e,G) {
00188           if((R[source(e)]) && (R[target(e)])) { 
00189             d+=S.value(VM(e));
00190             r+=VM(e);
00191           }
00192           if((R[source(e)]!=R[target(e)]) && (val[e]>VALONE-10)) {
00193             d+=S.value(VM(e));
00194             r+=VM(e);
00195             t++;
00196           };
00197         };
00198         if((t % 2==1) && (d>CCL[j].size()+(t-1)/2+0.01)) {
00199           i++;
00200           S.add_basic_constraint(r<=CCL[j].size()+(t-1)/2);
00201           cout<<"comb\n";
00202         };
00203         forall(v, CCL[j]) R[v]=false;
00204       }
00205     }
00206   }
00207   if(i>0) {
00208     return constraint_found;
00209   }
00210 
00211   return no_constraint_found;
00212 }; // END_OF_SEPARATE
00213 
00214 
00215 TOUR::status TOUR::feasible(solution& S) {
00216   // We construct a copy H of G, where we delete all edges with value different
00217   // from one. We check all degree equalities. If all degree equalities are
00218   // satisfied, we know that H is a Hamiltonian cycle if H is connected
00219 
00220   // Create H
00221   node_array<node> GtoH(G);
00222   graph H;
00223   node u;
00224   forall_nodes(u, G)
00225     GtoH[u]=H.new_node();
00226   edge e;
00227   forall_edges(e,G) {
00228     if(S.value(VM(e))>0.5) H.new_edge(GtoH[source(e)], GtoH[target(e)]);
00229   }
00230 
00231   // check degree equalities
00232   forall_nodes(u,H) if (H.degree(u)!=2) return infeasible_solution;
00233 
00234   // check connectedness
00235   if (Is_Connected(H)) return feasible_solution;
00236   return infeasible_solution;
00237 }; // END_OF_FEASIBLE
00238 
00239 void TOUR::info() {
00240   cout<<"Method: Cutting Planes\n\n";
00241 
00242   cout<<"Configurations:\n";
00243   cout<<"TOUR_heuristic_only [true|false]\n";
00244 };
00245 
00246 #undef VALONE
00247 
00284 #endif

Generated on Tue Nov 16 15:18:22 2004 for SCIL by doxygen1.2.16