CouenneSOS.cpp
Go to the documentation of this file.
1 /* $Id: CouenneSOS.cpp 549 2011-03-26 17:44:33Z pbelotti $
2  *
3  * Name: CouenneSOS.cpp
4  * Author: Pietro Belotti
5  * Purpose: find SOS constraints in problem and add them to list of
6  * branching objects
7  *
8  * (C) Carnegie-Mellon University, 2008-10.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include <vector>
13 
14 #include "CouenneExprGroup.hpp"
15 #include "CouenneExprAux.hpp"
16 
17 #include "CbcModel.hpp"
18 #include "CbcBranchActual.hpp"
19 #include "CbcCutGenerator.hpp"
20 #include "CbcCompareActual.hpp"
21 
22 #include "CouenneProblem.hpp"
23 
24 //using namespace Osi;
25 using namespace Couenne;
26 
28 int CouenneProblem::findSOS (CbcModel *CbcModelPtr,
29  OsiSolverInterface *solver,
30  OsiObject **objects) {
31 
32  // check auxiliaries defined as
33  // x_i binary. Disable it and add relative SOS to array "objects"
34 
35  int nSOS = 0;
36 
37  for (std::vector <exprVar *>::const_iterator v = variables_.begin ();
38  v != variables_.end (); ++v)
39 
40  if (((*v) -> Type () == AUX) &&
41  ((*v) -> Multiplicity () > 0) &&
42  ((*v) -> sign () == expression::AUX_EQ) &&
43  ((*v) -> Image () -> code () == COU_EXPRGROUP)) {
44 
45  expression *img = (*v) -> Image ();
46 
47  exprGroup *group = dynamic_cast <exprGroup *> (img -> isaCopy () ?
48  img -> Copy () :
49  img);
50  if (!group)
51  continue;
52 
53  int wind = (*v) -> Index ();
54  CouNumber cterm = group -> getc0 ();
55  bool
56  defVar = true,
57  invertSOS = false;
58 
59  // now check if this is
60  //
61  // defvar==true:
62  // 1) an auxiliary fixed to one ==> it's a SOS if its image is x1+x2+...+xk
63  // 1a) an auxiliary fixed to -1 ==> it's a SOS if its image is -x1-x2-...-xk (see minlplib/csched2)
64  //
65  // defvar==false:
66  // 2) an auxiliary fixed to zero ==> it's a SOS if its image is -x1-x2-...-xk+1
67  // 2a) or if its image is x1+x2+...+xk-1
68 
69  if (fabs (cterm - 1.) < COUENNE_EPS) {defVar = false;}
70  else if (fabs (cterm + 1.) < COUENNE_EPS) {defVar = false; invertSOS = true;}
71  else if (fabs (cterm) > COUENNE_EPS) continue; // and defVar is true
72 
73  if (defVar) { // implies cterm == 0
74  if ((fabs (Lb (wind) + 1.) < COUENNE_EPS) && (fabs (Ub (wind) + 1.) < COUENNE_EPS)) invertSOS = true;
75  else if (!((fabs (Lb (wind) - 1.) < COUENNE_EPS) && (fabs (Ub (wind) - 1.) < COUENNE_EPS))) continue;
76  } else
77 
78  if ((fabs (Lb (wind)) > COUENNE_EPS) ||
79  (fabs (Ub (wind)) > COUENNE_EPS))
80  continue;
81 
82  size_t lsz = group -> lcoeff (). size ();
83 
84  if (((lsz <= 2) && defVar) ||
85  ((lsz <= 1) && !defVar))
86  continue;
87 
88  // there are two possibilities:
89  //
90  // 1) w is defined as w = 1 - \sum_{i=0}^n x_i -- defvar = false
91  // 2) w is defined as \sum_{i=0}^n x_i and w \in [1,1] -- defvar = true
92 
93  bool
94  intSOS = (*v) -> isInteger (),
95  isSOS = true,
96  onlyOrigVars = true; // if SOS constraint only contains
97  // original variables, it has been
98  // spotted by Cbc already
99 
100  exprGroup::lincoeff &lcoe = group -> lcoeff ();
101  exprGroup::lincoeff::iterator l = lcoe. begin ();
102 
103  for (;l != lcoe. end (); ++l) {
104 
105  if ((fabs (l -> second - (invertSOS ? -1. : 1.)) > COUENNE_EPS) || // wrong coefficient?
106  (fabs (Lb (l -> first -> Index ())) > COUENNE_EPS)) { // positive lower bound?
107 
108  isSOS = false;
109  break;
110 
111  } else
112  if (!(l -> first -> isInteger ()))
113  intSOS = false;
114 
115  if (l -> first -> Index () >= nOrigVars_) //
116  onlyOrigVars = false;
117  }
118 
119  if (!isSOS || !intSOS)// || onlyOrigVars)
120  continue;
121 
122  // printf ("----- found SOS: ");
123  // (*v) -> print (); printf (" := ");
124  // (*v) -> Image () -> print (); printf ("\n");
125 
126  // it is a SOS -- if intSOS==true, it's also integer
127 
128  int
129  indStart = defVar ? 0 : 1,
130  nelem = indStart + lcoe. size (),
131  *indices = new int [nelem];
132 
133  if (!defVar)
134  indices [0] = (*v) -> Index ();
135 
136  for (int i=indStart, j=0; i<nelem; i++)
137  indices [i] = lcoe [j++]. first -> Index ();
138 
139  // TODO: if use Cbc, add CbcSOSBranchingObject
140 
141  //CouenneSOSObject *newsos = new CouenneSOSObject (solver, nelem, indices, NULL, 1, jnlst_, true, true);
142  //OsiSOS *newsos = new OsiSOS (solver, nelem, indices, NULL, 1);
143  CbcSOS *newsos = new CbcSOS (CbcModelPtr, nelem, indices, NULL, nSOS, 1);
144 
145  objects [nSOS] = newsos;
146  // as in BonBabSetupBase.cpp:675
147  newsos -> setPriority (10);
148  newsos -> setIntegerValued (intSOS);
149 
150  nSOS++;
151  }
152 
153  if (nSOS)
154  jnlst_ -> Printf (Ipopt::J_ERROR, J_COUENNE, "%d SOS constraint%s found\n", nSOS, nSOS == 1 ? "" : "s");
155 
156  return nSOS;
157 }
class Group, with constant, linear and nonlinear terms:
int findSOS(CbcModel *CbcModelPtr, OsiSolverInterface *solver, OsiObject **objects)
find SOS constraints in problem
Definition: CouenneSOS.cpp:28
static char * j
Definition: OSdtoa.cpp:3622
fint end
#define COUENNE_EPS
std::vector< exprVar * > variables_
Variables (original, auxiliary, and defined)
CouNumber * Ub() const
Return vector of upper bounds.
std::vector< std::pair< exprVar *, CouNumber > > lincoeff
double CouNumber
main number type in Couenne
int nOrigVars_
Number of original variables.
JnlstPtr jnlst_
SmartPointer to the Journalist.
Expression base class.
const Ipopt::EJournalCategory J_COUENNE(Ipopt::J_USER8)
CouNumber * Lb() const
Return vector of lower bounds.
bool isInteger(CouNumber x)
is this number integer?