00001
00002
00003
00004
00005
00006
00007
00008
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
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 void CouenneProblem::sym_setup (){
00082
00083
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
00113 if (e -> getc0 () != 0 ){
00114 num_affine ++;
00115 }
00116
00117
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
00129
00130 int nc = num_affine + nVars ();
00131
00132
00133
00134 nauty_info = new Nauty(nc);
00135
00136
00137 int coef_count= nVars ();
00138 for (std::vector <exprVar *>:: iterator i = Variables (). begin ();
00139 i != Variables (). end (); ++i) {
00140
00141
00142
00143 if ((*i) -> Type () == AUX) {
00144
00145
00146
00147 Node vertex;
00148 vertex.node( (*i) -> Index () , 0.0 , (*i) -> lb () , (*i) -> ub () , (*i) -> Image () -> code(), (*i)-> sign() );
00149
00150 node_info.push_back( vertex);
00151
00152
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
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
00184
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
00202 exprGroup *e = dynamic_cast <exprGroup *> ((*i) -> Image ());
00203
00204
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
00211
00212 nauty_info->addElement((*i) -> Index (), coef_count);
00213 nauty_info->addElement( coef_count, (*i) -> Index ());
00214
00215
00216 coef_count ++;
00217 }
00218
00219
00220
00221 for (exprGroup::lincoeff::iterator el = e ->lcoeff().begin (); el != e -> lcoeff ().end (); ++el) {
00222
00223 if ( el -> second ==1){
00224
00225 nauty_info->addElement((*i) -> Index (), el -> first -> Index());
00226 nauty_info->addElement( el -> first -> Index (), (*i) -> Index ());
00227 }
00228 else{
00229
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
00235 nauty_info->addElement((*i) -> Index (), coef_count);
00236 nauty_info->addElement( coef_count, (*i) -> Index ());
00237
00238
00239 nauty_info->addElement(coef_count, el -> first -> Index());
00240 nauty_info->addElement( el -> first -> Index (), coef_count);
00241 coef_count ++;
00242 }
00243
00244
00245
00246 }
00247
00248 }
00249
00250 }
00251 else if ((*i) -> Image () -> Type () == UNARY) {
00252
00253 expression *arg = (*i) -> Image () -> Argument () ;
00254 nauty_info->addElement( arg-> Index(), (*i) -> Index() );
00255
00256 }
00257 else if ((*i) -> Image () -> Type () == AUX) {
00258
00259 nauty_info->addElement((*i) -> Index (), (*i) -> Image() -> Index());
00260 nauty_info->addElement( (*i) -> Image() -> Index(), (*i) -> Index() );
00261
00262 }
00263 else if ((*i) -> Image () -> Type () == VAR) {
00264
00265 nauty_info->addElement((*i) -> Index (), (*i) -> Image() -> Index());
00266 nauty_info->addElement( (*i) -> Image() -> Index(), (*i) -> Index() );
00267
00268
00269 }
00270 }
00271 else {
00272
00273 Node var_vertex;
00274
00275
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
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
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
00290 }
00291 else{
00292 var_vertex.node( (*i) -> Index () , 0 , (*i) -> lb () , (*i) -> ub () , -1, -1 );
00293
00294
00295 node_info.push_back(var_vertex);
00296
00297 }
00298 }
00299 }
00300
00301 }
00302
00303
00304 void CouenneProblem::Compute_Symmetry() const{
00305
00306 ChangeBounds (Lb (), Ub (), nVars ());
00307
00308
00309
00310
00311
00312
00313
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
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
00331 }
00332
00333
00334 color++;
00335 }
00336 }
00337
00338
00339
00340 nauty_info -> computeAuto();
00341 }
00342
00343
00344 void CouenneProblem::Print_Orbits () const {
00345
00346
00347
00348 std::vector<std::vector<int> > *new_orbits = nauty_info->getOrbits();
00349
00350
00351
00352
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
00362
00363
00364
00365
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
00397 if( (*new_orbits)[i][j] == index)
00398 which_orbit = i;
00399 }
00400 }
00401
00402
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 ());
00414 std::sort(node_info. begin (), node_info. end (), index_sort);
00415
00416 for (int i = 0; i < num_cols; i++) {
00417
00418
00419 assert (node_info[i].get_index () == i);
00420 node_info[i ].bounds ( new_lb[i] , new_ub[i] );
00421
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 }