constrStandardize.cpp
Go to the documentation of this file.
1 /* $Id: constrStandardize.cpp 1220 2016-09-16 10:09:46Z stefan $
2  *
3  * Name: constrStandardize.cpp
4  * Author: Pietro Belotti
5  * Purpose: standardization of constraints
6  *
7  * (C) Carnegie-Mellon University, 2007-11.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CoinHelperFunctions.hpp"
12 
13 #include "BonBabSetupBase.hpp"
14 
15 #include "CouenneProblemElem.hpp"
16 #include "CouenneProblem.hpp"
17 
18 #include "CouenneExpression.hpp"
19 #include "CouenneExprAux.hpp"
20 #include "CouenneExprClone.hpp"
21 #include "CouenneExprIVar.hpp"
22 #include "CouenneDepGraph.hpp"
23 
24 using namespace Couenne;
25 
26 // replace a variable
27 void replace (CouenneProblem *p, int wind, int xind);
28 
29 
32 
33  // spot an auxiliary variable in constraint's body w - f(x) and move
34  // the explicit w into the vector of auxiliary variables
35  //
36  // do it only if this is an equality constraint and there is at
37  // least one variable that did not show up so far (need a problem
38  // structure)
39 
40  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
41  printf ("Reformulating constraint: "); print ();
42  printf (" ["); fflush (stdout); lb_ -> print ();
43  printf (","); fflush (stdout); ub_ -> print (); fflush (stdout);
44  /* printf ("] {with auxset = ");
45  for (std::set <exprAux *, compExpr>::iterator i = p -> AuxSet () -> begin (); i != p -> AuxSet () -> end (); i++) {
46  printf ("<"); (*i) -> print (); printf (","); (*i) -> Image () -> print (); printf ("> ");}*/
47  printf ("]\n");
48  }
49 
50  // Auxiliaries used to be definable with a constraint f(x) + bw = c,
51  // which implies w := (c - f(x)) / b. Semi-auxiliaries no longer
52  // need the equality sign, but their sign will be determined by lb_
53  // and ub_. Their values allow us to decide whether we should create
54  // a (semi)auxiliary or not.
55 
56  CouNumber
57  rLb = (*lb_) (),
58  rUb = (*ub_) ();
59 
60  std::string
61  use_auxcons,
62  use_semiaux;
63 
64  p -> bonBase () -> options () -> GetStringValue ("use_auxcons", use_auxcons, "couenne.");
65  p -> bonBase () -> options () -> GetStringValue ("use_semiaux", use_semiaux, "couenne.");
66 
67  if (( use_auxcons == "yes") && // if aux generated by constraints are disabled, just bail out
68  (((use_semiaux == "yes") && // otherwise, either we allow semi-auxs
69  ((rLb < -COUENNE_INFINITY/2) || // (and either bound is infinite)
70  (rUb > COUENNE_INFINITY/2))) || //
71  (fabs (rLb-rUb) <= COUENNE_EPS))) { // or there is an equality constraint
72 
74 
75  if (rLb < -COUENNE_INFINITY/2) aSign = expression::AUX_LEQ;
76  else if (rUb > COUENNE_INFINITY/2) aSign = expression::AUX_GEQ;
77 
78  CouNumber rhs = rLb >= -COUENNE_INFINITY/2 ? rLb : rUb;
79 
80  // this could be the definition of a (semi)-auxiliary
81 
82  expression *rest;
83 
84  // split w from f(x)
85  int wind = p -> splitAux (rhs, body_, rest, p -> Commuted (), aSign);
86 
87  //printf ("REST [%d] [%g,%g]: ", wind, p -> Lb (wind), p -> Ub (wind)); rest -> print (); printf ("\n");
88 
89  if (wind >= 0) { // this IS the definition of an auxiliary variable, w [ <= | >= | = ] f(x)
90 
91  // simplify expression (you never know)
92 
93  expression *restSimple = Simplified (rest);
94 
95  // -> simplify ();
96 
97  // if (restSimple) {
98  // delete rest;
99  // rest = restSimple;
100  // }
101 
102  // if this is a constraint of the form x=k, tighten x's bounds and
103  // do nothing else
104 
105  if (rest -> code () == COU_EXPRCONST) {
106 
107  CouNumber constRHS = rest -> Value ();
108 
109  if (aSign != expression::AUX_LEQ && constRHS > p -> Var (wind) -> lb ()) p -> Var (wind) -> lb () = constRHS;
110  if (aSign != expression::AUX_GEQ && constRHS < p -> Var (wind) -> ub ()) p -> Var (wind) -> ub () = constRHS;
111 
112  //delete rest;
113  return NULL;
114  }
115 
116  // Assign a new auxiliary variable (with the same index, "wind",
117  // as the old original variable) to the expression contained in
118  // "rest"
119 
120  p -> Commuted () [wind] = true;
121 
122  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
123  printf ("---> %d & ", wind); fflush (stdout);
124  rest -> print (); printf ("[sign: %d]\n", aSign);
125  }
126 
127  assert (p -> Var (wind) -> Type () == VAR);
128 
129  int xind = rest -> Index ();
130 
131  // check if constraint now reduces to w_k = x_h, and if so
132  // replace all occurrences of x_k with x_h
133 
134  if ((xind >= 0) && (aSign == expression::AUX_EQ)) {
135 
136  // create new variable, it has to be integer if original variable was integer
137  exprAux *w = new exprAux (new exprClone (p -> Var (xind)), wind, 1 + p -> Var (xind) -> rank (),
138  p -> Var (wind) -> isInteger () ?
140  p -> domain (), aSign);
141  p -> auxiliarize (w);
142  w -> zeroMult ();
143 
144  replace (p, wind, xind);
145 
146  p -> auxiliarize (p -> Var (wind), p -> Var (xind));
147  //p -> Var (wind) -> zeroMult (); // redundant variable is neutralized
148 
149  } else {
150 
151  // create new variable, it has to be integer if original variable was integer
152  exprAux *w = new exprAux (rest, wind, 1 + rest -> rank (),
153  ((p -> Var (wind) -> isInteger ()) ||
154  (false && (rest -> isInteger ()) && (aSign == expression::AUX_EQ))) ? // FIXME!!!
156  p -> domain (), aSign);
157 
158  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
159  printf ("AuxSet:\n");
160  for (std::set <exprAux *, compExpr>::iterator i = p -> AuxSet () -> begin ();
161  i != p -> AuxSet () -> end (); ++i)
162  if ((*i) -> Image () == NULL) {
163  (*i) -> print (); printf (" does not have an image!!!\n");
164  } else {
165  printf ("-- "); (*i) -> print (); printf (" := ");
166  (*i) -> Image () -> print (); printf ("\n");
167  }
168  }
169 
170  std::set <exprAux *, compExpr>::iterator i = p -> AuxSet () -> end ();
171 
172  if (aSign == expression::AUX_EQ)
173  i = p -> AuxSet () -> find (w);
174 
175  // no such expression found in the set:
176  if ((i == p -> AuxSet () -> end ()) || (aSign != expression::AUX_EQ)) {
177 
178  p -> AuxSet () -> insert (w); // 1) beware of useless copies
179  p -> getDepGraph () -> insert (w); // 2) introduce it in acyclic structure
180 
181  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
182  printf ("now replacing x [%d] with ", wind); fflush (stdout);
183  w -> print (); printf (" := ");
184  w -> Image () -> print (); printf ("\n");
185  }
186 
187  // replace ALL occurrences of original variable (with index
188  // wind) with newly created auxiliary
189  p -> auxiliarize (w);
190  }
191 
192  else {
193 
194  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
195  printf ("found aux occurrence of "); fflush (stdout);
196  w -> print (); printf (" := ");
197  w -> Image () -> print (); printf (" ... ");
198  (*i) -> print (); printf (" := ");
199  (*i) -> Image () -> print (); printf ("\n");
200  }
201 
202  // if this is an original variable and is competing with an
203  // auxiliary variable, or at least this has a lower index,
204  // we better replace it throughout and eliminate that
205  // aux. See globallib/st_glmp_fp3 for an example where this
206  // otherwise would be a bug (x_1 unlinked from x2-x3 and
207  // leading to unbounded)
208 
209  int xind = (*i) -> Index (), iMax, iMin;
210 
211  if (xind < wind) {
212  iMax = wind;
213  iMin = xind;
214  } else {
215  iMax = xind;
216  iMin = wind;
217  }
218 
219  replace (p, iMax, iMin);
220 
221  p -> auxiliarize (p -> Var (iMax), p -> Var (iMin));
222  p -> Var (iMax) -> zeroMult (); // redundant variable is neutralized
223  p -> auxiliarize (w);
224  }
225  }
226 
227  return NULL;
228  }
229  }
230 
231  if (p -> Jnlst () -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE))
232  printf ("\nnormal\n-----------------\n");
233 
234  //body_ -> standardize (p, false); // TODO: check!
235 
236  //return NULL;
237 
238  return body_ -> standardize (p);
239 }
240 
241 
242 // Replace a variable ////////////////////////////////
243 void replace (CouenneProblem *p, int wind, int xind) {
244 
245  exprVar
246  *varLeaves = p -> Variables () [wind],
247  *varStays = p -> Variables () [xind];
248 
249  // intersect features of the two variables (integrality, bounds)
250 
251  varStays -> lb () = varLeaves -> lb () = CoinMax (varStays -> lb (), varLeaves -> lb ());
252  varStays -> ub () = varLeaves -> ub () = CoinMin (varStays -> ub (), varLeaves -> ub ());
253 
254  if (varStays -> isInteger () ||
255  varLeaves -> isInteger ()) {
256 
257  varStays -> lb () = ceil (varStays -> lb ());
258  varStays -> ub () = floor (varStays -> ub ());
259 
260  if (varStays -> Type () == AUX)
261  varStays -> setInteger (true);
262  else {
263  //expression *old = varStays; // !!! leak
264  p -> Variables () [xind] = varStays = new exprIVar (xind, p -> domain ());
265  p -> auxiliarize (varStays); // replace it everywhere in the problem
266  //delete old;
267  }
268  }
269 }
void replace(CouenneProblem *p, int wind, int xind)
virtual void print(std::ostream &=std::cout)
print constraint
Definition: constraint.cpp:19
virtual exprAux * standardize(CouenneProblem *)
decompose body of constraint through auxiliary variables
auxSign
&quot;sign&quot; of the constraint defining an auxiliary.
expression * ub_
Upper bound (expression)
fint end
Class for MINLP problems with symbolic information.
expression clone (points to another expression)
const Ipopt::EJournalCategory J_REFORMULATE(Ipopt::J_USER7)
#define COUENNE_EPS
expression * lb_
Lower bound (expression)
double CouNumber
main number type in Couenne
expression * Simplified(expression *complicated)
Macro to return already simplified expression without having to do the if part every time simplify ()...
variable-type operator.
#define COUENNE_INFINITY
Auxiliary variable.
variable-type operator
Expression base class.
expression * body_
Body of constraint.
The in-memory representation of the variables element.
Definition: OSInstance.h:83
void fint fint fint real fint real real real real real real real real * w
bool isInteger(CouNumber x)
is this number integer?