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