/home/coin/SVN-release/OS-2.4.2/Couenne/src/problem/CouenneSymmetry.cpp

Go to the documentation of this file.
00001 /* $Id: CouenneSymmetry.cpp 725 2011-06-30 12:20:29Z pbelotti $
00002  *
00003  * Name:    CouenneSymmetry.cpp
00004  * Author:  Jim Ostrowski
00005  * Purpose: methods for exploiting symmetry
00006  * Date:    October 13, 2010
00007  *
00008  * This file is licensed under the Eclipse Public License (EPL)
00009  */
00010 
00011 #include <cassert>
00012 #include <vector>
00013 #include <algorithm>
00014 #include <ostream>
00015 #include <iterator>
00016 #include <stdio.h>
00017 
00018 #include "CouenneExprVar.hpp"
00019 #include "CouenneExprGroup.hpp"
00020 
00021 #include "CouenneProblem.hpp"
00022 
00023 using namespace Couenne;
00024 
00025 #ifdef COIN_HAS_NTY
00026 
00027 #include "Nauty.h"
00028 
00029 void Node::node(int i, double c , double l, double u, int cod, int s){
00030   index = i;
00031   coeff = c;
00032   lb = l;
00033   ub = u;
00034   color = -1;
00035   code = cod;
00036   sign = s;
00037 }
00038 
00039 inline bool CouenneProblem::compare (register Node &a, register Node &b) const {
00040   if(a.get_code() == b.get_code() )
00041     if(a.get_coeff() == b.get_coeff() )
00042       if(a.get_sign() == b.get_sign() )
00043         if( fabs ( a.get_lb() - b.get_lb() ) <= COUENNE_EPS )
00044           if( fabs ( a.get_ub() - b.get_ub() ) <= COUENNE_EPS )
00045             return 1; 
00046   return 0;
00047 }
00048 
00049 /*
00050 bool CouenneProblem::node_sort (Node a, Node  b){
00051   bool is_less = 0;
00052 
00053   if(a.get_code() < b.get_code() )
00054     is_less = 1;
00055   else {
00056     if(a.get_code() == b.get_code() )
00057       if(a.get_coeff() < b.get_coeff() )
00058         is_less = 1;
00059       else{
00060         if(a.get_coeff() ==  b.get_coeff() )
00061           if(a.get_lb() < b.get_lb())
00062             is_less = 1;
00063           else{
00064             if(a.get_lb() == b.get_lb())
00065               if(a.get_ub() < b.get_ub())
00066                 is_less = 1;
00067               else{
00068                 if(a.get_index() < b.get_index())
00069                   is_less = 1;
00070               }
00071           }
00072       }
00073   }
00074   return is_less;
00075 }
00076 bool CouenneProblem::index_sort (Node a, Node b){
00077   return (a.get_index() < b.get_index() );
00078 }
00079 */
00080 
00081 void CouenneProblem::sym_setup (){
00082 
00083   //  // Find Coefficients
00084 
00086 
00087   int num_affine = 0;
00088 
00089   for (std::vector <exprVar *>:: iterator i = Variables (). begin ();
00090        i != Variables (). end (); ++i) {
00091 
00092     if ((*i) -> Type () == AUX) {
00093       if ((*i) -> Image () -> code () == COU_EXPRDIV) {
00094               num_affine ++;
00095       }
00096       if ((*i) -> Image () -> code () != COU_EXPRGROUP) {
00097         if ((*i) -> Image () -> Type () == N_ARY) {
00098           for (int a=0; a < (*i) -> Image () -> nArgs(); a++) {
00099             expression *arg = (*i) -> Image () -> ArgList () [a];
00100 
00101             if (arg -> Type () == CONST) {
00102               num_affine ++;
00103 
00104             }
00105           }
00106         }
00107       }
00108       if ((*i) -> Image () -> code () == COU_EXPRGROUP) {
00109 
00110         exprGroup *e = dynamic_cast <exprGroup *> ((*i) -> Image ());
00111 
00112         // add a node for e -> getC0 ();
00113         if (e -> getc0 () != 0 ){
00114           num_affine ++;
00115         }
00116 
00117         // for each term add nodes for their non-one coefficients and their variable
00118 
00119         for (exprGroup::lincoeff::iterator el = e ->lcoeff().begin (); el != e -> lcoeff ().end (); ++el) {
00120           if ( el -> second !=1){
00121             num_affine ++;
00122           }
00123         }
00124       }
00125     }
00126   }
00127 
00128   // Create global Nauty object
00129 
00130   int nc = num_affine + nVars ();
00131   // printf (" There are   %d  coefficient vertices in the graph \n", num_affine);
00132   //printf (" Graph has    %d  vertices \n", nc);
00133 
00134   nauty_info = new Nauty(nc);
00135   // create graph
00136 
00137   int coef_count= nVars ();
00138   for (std::vector <exprVar *>:: iterator i =  Variables (). begin ();
00139        i != Variables (). end (); ++i) {
00140 
00141     //    printf ("I have code %d \n",  (*i) ->  Image() -> code() );
00142 
00143     if ((*i) -> Type () == AUX) {
00144       //printf ("aux is %d with code %d \n", (*i) -> Index (), (*i) -> Image () -> code() );
00145       // this is an auxiliary variable
00146 
00147       Node vertex;
00148       vertex.node( (*i) -> Index () , 0.0 , (*i) -> lb () , (*i) -> ub () ,  (*i) -> Image () -> code(), (*i)-> sign() );
00149       //printf(" sign of aux %d \n", (*i) -> sign () );
00150       node_info.push_back( vertex);
00151 
00152       // add node in nauty graph for its index, (*i) -> Index ()
00153 
00154       if ((*i) -> Image () -> Type () == N_ARY) {
00155 
00156         if ((*i) -> Image () -> code () == COU_EXPRDIV) {
00157           expression *arg = (*i) -> Image () -> ArgList () [0];
00158           nauty_info->addElement((*i) -> Index (),  arg -> Index ());
00159           expression *arg2 = (*i) -> Image () -> ArgList () [1];
00160           nauty_info->addElement((*i) -> Index (),  coef_count);
00161           nauty_info->addElement( coef_count,  arg2 -> Index ());
00162           Node coef_vertex;
00163           coef_vertex.node( coef_count, -1, -1 ,-1, -2 , 0);
00164           node_info.push_back(coef_vertex);
00165           coef_count ++;
00166         }
00167         
00168         if ((*i) -> Image () -> code () != COU_EXPRGROUP) {
00169 
00170           for (int a=0; a < (*i) -> Image () -> nArgs(); a++) {
00171             expression *arg = (*i) -> Image () -> ArgList () [a];
00172 
00173             if (arg -> Type () != CONST) {
00174               //printf (" add edge  %d , %d\n", (*i) -> Index (),  arg -> Index ());
00175               nauty_info->addElement((*i) -> Index (),  arg -> Index ());
00176               nauty_info->addElement( arg -> Index (), (*i) -> Index ());
00177             }
00178 
00179             else{
00180 
00181               assert (arg -> Type () == CONST);
00182 
00183               // printf (" add new vertex to graph, coef # %d, value %g \n", coef_count, arg -> Value() );
00184               // printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (),  coef_count);
00185               nauty_info->addElement((*i) -> Index (),  coef_count);
00186               nauty_info->addElement( coef_count, (*i) -> Index ());
00187 
00188 
00189               Node coef_vertex;
00190               coef_vertex.node( coef_count, arg -> Value(), arg -> Value() , arg -> Value(), -2 , 0);
00191               node_info.push_back(coef_vertex);
00192               coef_count ++;
00193             }
00194 
00195           }
00196         }
00197 
00198 
00199         if ((*i) -> Image () -> code () == COU_EXPRGROUP) {
00200 
00201           // dynamic_cast it to an exprGroup
00202           exprGroup *e = dynamic_cast <exprGroup *> ((*i) -> Image ());
00203 
00204           // add a node for e -> getC0 ();
00205           if (e -> getc0 () != 0 ){
00206             Node coef_vertex;
00207             coef_vertex.node( coef_count, e -> getc0(), e -> getc0() , e -> getc0(), -2, 0 );
00208             node_info.push_back(coef_vertex);
00209 
00210             //printf ("Add coef vertex to graph (coef value   %f) \n", e -> getc0 () );
00211             //printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (), coef_count);
00212             nauty_info->addElement((*i) -> Index (),  coef_count);
00213             nauty_info->addElement( coef_count, (*i) -> Index ());
00214 
00215 
00216             coef_count ++;
00217           }
00218 
00219           // for each term add nodes for their non-one coefficients and their variable
00220 
00221           for (exprGroup::lincoeff::iterator el = e ->lcoeff().begin (); el != e -> lcoeff ().end (); ++el) {
00222 
00223             if ( el -> second ==1){
00224               //printf (" add edge index %d ,  index %d\n", (*i) -> Index (), el -> first -> Index()    );
00225               nauty_info->addElement((*i) -> Index (),  el -> first -> Index());
00226               nauty_info->addElement( el -> first -> Index (), (*i) -> Index ());
00227             }
00228             else{
00229               //printf (" add new vertex to graph, coef # %d with coef %f \n", coef_count, el -> second);
00230               Node coef_vertex;
00231               coef_vertex.node( coef_count, el -> second, el -> second, el -> second, -2, 0 );
00232               node_info.push_back(coef_vertex);
00233 
00234               //printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (), coef_count);
00235               nauty_info->addElement((*i) -> Index (),  coef_count);
00236               nauty_info->addElement( coef_count, (*i) -> Index ());
00237 
00238               // printf (" add edge coef index %d ,  2nd index %d\n", coef_count,  el -> first -> Index()  );
00239               nauty_info->addElement(coef_count,  el -> first -> Index());
00240               nauty_info->addElement( el -> first -> Index (), coef_count);
00241               coef_count ++;
00242             }
00243             // coefficient = el -> second
00244 
00245             // variable index is el -> first -> Index ()
00246           }
00247 
00248         }
00249         
00250       }
00251       else if ((*i) -> Image () -> Type () == UNARY) {
00252         //      printf ("variable is unary  %d\n", (*i) -> Index ());
00253         expression *arg = (*i) -> Image () -> Argument () ;
00254         nauty_info->addElement( arg-> Index(), (*i) -> Index() );
00255         //printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (), arg-> Index()); 
00256       }
00257       else if ((*i) -> Image () -> Type () == AUX) {
00258         //printf ("variable is AUX  %d\n", (*i) -> Index ());
00259         nauty_info->addElement((*i) -> Index (), (*i) -> Image() -> Index());
00260         nauty_info->addElement( (*i) -> Image() -> Index(), (*i) -> Index() );
00261         //printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (), (*i) -> Image() -> Index()); 
00262       }
00263       else if ((*i) -> Image () -> Type () == VAR) {
00264         //printf ("variable is VAR  %d, image %d \n", (*i) -> Index (), (*i) -> Image() -> Index());
00265         nauty_info->addElement((*i) -> Index (), (*i) -> Image() -> Index());
00266         nauty_info->addElement( (*i) -> Image() -> Index(), (*i) -> Index() );
00267 
00268         //printf (" add edge aux index %d ,  coef index %d\n", (*i) -> Index (), (*i) -> Image() -> Index()); 
00269       }
00270     }
00271     else {
00272       // printf ("variable is %d\n", (*i) -> Index ());
00273       Node var_vertex;
00274 
00275       // Bounds of +- infinity make the compare function likely to return a false negative. Rather than add inf as a boud, I use lb-1 (or ub +1 
00276       if( (*i) -> ub() >= COUENNE_INFINITY && (*i) -> lb() <= - COUENNE_INFINITY){
00277         var_vertex.node( (*i) -> Index () , 0 , 1 , 0 ,  -1, -1 );
00278         node_info.push_back(var_vertex);
00279         //printf( "var info index %d, lb %f, ub %f \n",(*i) -> Index () , 1 , 0 ) ; 
00280       }
00281       else  if( (*i) -> ub() >= COUENNE_INFINITY ){
00282         var_vertex.node( (*i) -> Index () , 0 , (*i) -> lb () , (*i) -> lb() -1 ,  -1, -1 );
00283         node_info.push_back(var_vertex);
00284         //printf( "var info index %d, lb %f, ub %f \n",(*i) -> Index () , (*i) -> lb () , (*i) -> lb () -1 ) ; 
00285       }
00286       else  if( (*i) -> lb() <= - COUENNE_INFINITY){
00287         var_vertex.node( (*i) -> Index () , 0 , (*i) -> ub () +1 , (*i) -> ub () ,  -1, -1 );
00288         node_info.push_back(var_vertex);
00289         //printf( "var info index %d, lb %f, ub %f \n",(*i) -> Index () , (*i) -> ub () +1 , (*i) -> ub () ) ; 
00290       }
00291       else{
00292         var_vertex.node( (*i) -> Index () , 0 , (*i) -> lb () , (*i) -> ub () ,  -1, -1 );
00293         //printf( "var info index %d, lb %f, ub %f \n",(*i) -> Index () , (*i) -> lb () , (*i) -> ub () ) ; 
00294         // var_vertex.get_index() , var_vertex.get_coeff() , var_vertex.get_lb() , var_vertex.get_ub() ,  var_vertex.get_code() );
00295         node_info.push_back(var_vertex);
00296         // this is an original variable
00297       }
00298     }
00299   }
00300   
00301 }
00302 
00303 
00304 void CouenneProblem::Compute_Symmetry() const{
00305 
00306   ChangeBounds (Lb (), Ub (), nVars ());
00307 
00308   // jnlst_ -> Printf(Ipopt::J_VECTOR, J_BRANCHING,"== Computing Symmetry\n");
00309   // for (int i = 0; i < nVars (); i++)
00310   //   if (Var (i) -> Multiplicity () > 0)
00311   //     jnlst_->Printf(Ipopt::J_VECTOR, J_BRANCHING,"%4d %+20.8g [%+20.8g,%+20.8g]\n", i,
00312   //                 X  (i), Lb (i), Ub (i));
00313   // jnlst_->Printf(Ipopt::J_VECTOR, J_BRANCHING,"=============================\n");
00314 
00315   std::sort(node_info. begin (), node_info. end (), node_sort);
00316 
00317   for (std::vector <Node>:: iterator i = node_info. begin ();  i != node_info. end (); ++i) 
00318     (*i).color_vertex(-1);
00319   
00320   int color = 1;
00321   for (std::vector <Node>:: iterator i = node_info. begin (); i != node_info. end (); ++i) {
00322     if( (*i).get_color() == -1){
00323       (*i).color_vertex(color);
00324       //printf ("Graph vertex %d is given color %d\n", (*i).get_index(), color);
00325       nauty_info -> color_node((*i).get_index(), color);
00326       for (std::vector <Node>:: iterator j = i+1; j != node_info. end (); ++j)
00327         if( compare( (*i) , (*j) ) ==1){
00328           (*j).color_vertex(color);
00329           nauty_info -> color_node((*j).get_index(),color);
00330           //printf ("Graph vertex %d is given color %d, the same as vertex %d\n", (*j).get_index(), color, (*i).get_index());
00331         }
00332       //       else
00333       // j = node_info. end();
00334       color++;
00335     }
00336   }
00337 
00338   //Print_Orbits ();
00339 
00340   nauty_info -> computeAuto();
00341 }
00342 
00343   
00344 void CouenneProblem::Print_Orbits () const {
00345 
00346   //printf ("num gens = %d, num orbits = %d \n", nauty_info -> getNumGenerators(), nauty_info -> getNumOrbits() );
00347 
00348   std::vector<std::vector<int> > *new_orbits = nauty_info->getOrbits();
00349 
00350   //printf("There were %d orbits and %d generators\n",
00351   //nauty_info->getNumOrbits(),
00352   //nauty_info->getNumGenerators());
00353 
00354   int nNonTrivialOrbits = 0;
00355 
00356   for (unsigned int i = 0; i < new_orbits -> size(); i++) {
00357     if ((*new_orbits)[i].size() > 1) 
00358       nNonTrivialOrbits++;
00359     else continue;
00360 
00361     // int orbsize = (*new_orbits)[i].size();
00362     // printf( "Orbit %d [size: %d] [", i, orbsize);
00363     // copy ((*new_orbits)[i].begin(), (*new_orbits)[i].end(),
00364     //    std::ostream_iterator<int>(std::cout, " "));
00365     // printf("] \n");
00366   }
00367 
00368   printf ("%d non-trivial orbits\n", nNonTrivialOrbits);
00369 
00370 #if 0
00371   if (nNonTrivialOrbits)
00372     for (int i=0; i< nVars (); i++) {
00373 
00374       std::vector< int > *branch_orbit = Find_Orbit (i);
00375 
00376       if (branch_orbit -> size () > 1) {
00377         printf ("x%04d: ", i);
00378 
00379         for (std::vector<int>::iterator it = branch_orbit -> begin (); it != branch_orbit -> end (); ++it) 
00380           printf ("%d ", *it);
00381         printf ("\n");
00382       }
00383     }
00384 #endif
00385   delete new_orbits;
00386 }
00387 
00388 std::vector<int> *CouenneProblem::Find_Orbit(int index) const{
00389 
00390   std::vector<int> *orbit = new std::vector <int>;
00391   int which_orbit = -1;
00392   std::vector<std::vector<int> > *new_orbits = nauty_info->getOrbits();
00393 
00394   for (unsigned int i = 0; i < new_orbits -> size(); i++) {
00395     for (unsigned int j = 0; j < (*new_orbits)[i].size(); j++) {
00396       //   for (std::vector <int>:: iterator j = new_orbits[i].begin(); new_orbits[i].end(); ++j){
00397       if( (*new_orbits)[i][j] ==  index)
00398         which_orbit = i;
00399     }
00400   }
00401   
00402   //  for (std::vector <int>:: iterator j = new_orbits[which_orbit].begin(); new_orbits[which_orbit].end(), ++j)
00403   for (unsigned int j = 0; j < (*new_orbits)[which_orbit].size(); j++) 
00404     orbit -> push_back ((*new_orbits)[which_orbit][j]);
00405 
00406   delete new_orbits;
00407 
00408   return orbit;
00409 }
00410 
00411 
00412 void CouenneProblem::ChangeBounds (const double * new_lb, const double * new_ub, int num_cols) const {
00413   assert (num_cols == nVars ()); // replaced Variables () . size () as Variables () is not a const method
00414   std::sort(node_info. begin (), node_info. end (), index_sort);
00415 
00416   for (int  i = 0; i < num_cols; i++) {
00417     //   printf("Var %d  lower bound: %f   upper bound %f \n", i, new_lb[i], new_ub[i]);
00418     
00419     assert (node_info[i].get_index () == i);
00420     node_info[i ].bounds ( new_lb[i] , new_ub[i] );
00421     // printf("Var %d  INPUT lower bound: %f   upper bound %f \n", i, node_info[i].get_lb(), node_info[i].get_ub());
00422   }
00423 }
00424 #endif
00425 
00426 void CouenneProblem::setupSymmetry () {
00427 
00428 #ifdef COIN_HAS_NTY
00429   sym_setup ();
00430   Compute_Symmetry ();
00431   Print_Orbits ();
00432 #else
00433   if (orbitalBranching_) {
00434     printf ("\
00435 Couenne: Warning, you have set orbital_branching but Nauty is not available.\n\
00436 Reconfigure with appropriate options --with-nauty-lib=/path/to/libnauty.* and --with-nauty-incdir=/path/to/nauty/include/files/\n");
00437   }
00438 #endif
00439 }

Generated on Wed Nov 30 03:04:07 2011 by  doxygen 1.4.7