splitAux.cpp
Go to the documentation of this file.
1 /* $Id: splitAux.cpp 882 2012-08-02 09:32:53Z pbelotti $
2  *
3  * Name: splitAux.cpp
4  * Author: Pietro Belotti
5  * Purpose: extract auxiliary variable from implicit equality constraint
6  *
7  * (C) Carnegie-Mellon University, 2007-10.
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CouenneExprQuad.hpp"
12 
13 #include "CouenneProblem.hpp"
14 
15 #include "CoinHelperFunctions.hpp"
16 
17 #include "CouenneExprAux.hpp"
18 #include "CouenneExprClone.hpp"
19 #include "CouenneExprSum.hpp"
20 #include "CouenneExprMul.hpp"
21 #include "CouenneExprOpp.hpp"
22 #include "CouenneExprGroup.hpp"
23 #include "CouenneLQelems.hpp"
24 
25 using namespace Couenne;
26 
30 void elementBreak (expression *, int &, CouNumber &);
31 
32 
35 
37  bool *wentAux, enum expression::auxSign &sign) {
38 
39  int auxInd = -1, // index of the auxiliary to be extracted
40  code = body -> code (); // type of expression
41 
42  expression **alist = body -> ArgList ();
43 
44  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE))
45  {printf (" Splitting expression: "); body -> print (); printf ("\n");}
46 
47  switch (code) { // constraint h(x) = 0 may be in different forms:
48  // subtraction, sum, linear group
49 
51 
52  case COU_EXPRSUB: {
53 
54  // simplest case, we have w-f(x)=rhs or f(x)-w=rhs or f(x)-g(x)=rhs
55 
56  int pos = 0;
57  CouNumber coeff = 1;
58 
59  auxInd = (*alist) -> Index ();
60 
61  if (auxInd < 0) // first argument is not a variable
62  elementBreak (*alist, auxInd, coeff); // check first element
63 
64  if ((auxInd < 0) || // first argument is not a variable
65  wentAux [auxInd] || // it was, and it already became an auxiliary
66  (alist [1] -> dependsOn (auxInd, TAG_AND_RECURSIVE) >= 1)) {
67  // it is not an auxiliary, but the remaining
68  // expression depends on it
69 
70  auxInd = (alist [1]) -> Index ();
71 
72  if (auxInd < 0)
73  elementBreak (alist [1], auxInd, coeff); // check second element
74  else coeff = 1;
75 
76  if ((auxInd < 0) || // no index found
77  wentAux [auxInd] || // or, found but invalid
78  (alist [0] -> dependsOn (auxInd, TAG_AND_RECURSIVE) >= 1))
79  // or, variable depends upon itself
80  return -1;
81 
82  pos = 1;
83  }
84 
86 
87  // what remains is the "independent" expression
88  expression *clone = alist [1 - pos] -> clone (&domain_);
89 
90  expression *auxdef;
91 
92  if (coeff == 1.) auxdef = clone; // if coefficient is 1, do nothing
93  else if (coeff == -1.) auxdef = new exprOpp (clone); // if coefficient is -1, return -f(x)
94  else auxdef = new exprMul (new exprConst (coeff), clone); // else multiply it by coefficient
95 
96  rest = (rhs == 0.) ? // no extra constant?
97  (auxdef) : // just put other argument
98  (new exprSum (auxdef, new exprConst ((pos==1) ? -rhs : rhs))); // otherwise sum it with \pm rhs
99 
100  if (pos==1) {
101  if (sign == expression::AUX_GEQ) sign = expression::AUX_LEQ;
102  else if (sign == expression::AUX_LEQ) sign = expression::AUX_GEQ;
103  }
104 
105  } break;
106 
108 
109  case COU_EXPRQUAD:
110  case COU_EXPRGROUP:
111  case COU_EXPRSUM: {
112 
113  // an expr{Sum,Group,Quad}. Decompose the expression and
114  // re-assemble (to look for right variable)
115 
116  // data structure to be used below if there is a linear term.
117  // which specifies position within arrays (negative for linear
118  // part of exprGroup, positive for all elements of exprSum)
119 
120  int maxindex = -1, nlin = 0, which = 1;
121  CouNumber c0 = 0., auxcoe = 1;
122  bool which_was_set = false;
123 
124  // check indices of linear/quadratic part /////////////////////////////////
125 
126  if (code != COU_EXPRSUM) {
127 
128  exprGroup *egBody = dynamic_cast <exprGroup *> (body -> isaCopy () ?
129  body -> Copy () :
130  body);
131  exprGroup::lincoeff &lcoe = egBody -> lcoeff ();
132 
133  // import exprGroup linear structure
134 
135  c0 = egBody -> getc0 ();
136 
137  for (int i=0, n = lcoe.size (); n--; i++, nlin++) {
138 
139  int j = lcoe [i]. first -> Index ();
140 
141  //lincoe [i] = lcoe [i]. second;
142 
143  // prefer non-integer. If integer, only take it if none chosen yet
144  if ((j > maxindex) &&
145  !(wentAux [j]) &&
146  (fabs (lcoe [i]. second) > COUENNE_EPS) &&
147  (!(lcoe [i].first -> isInteger ()) || (which==1))) {
148 
149  // fake cut in linind and check dependence. Only mark if
150  // dependsOn() gives 0
151 
152  exprVar *saveVar = lcoe [i].first;
153  //lcoe [i].first = new exprVar (nVars ()); // better use index -1
154  lcoe [i].first = new exprVar (-1);
155 
156  if (body -> dependsOn (j, TAG_AND_RECURSIVE) == 0) {
157 
158  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
159  printf ("body does not depend on x%d: ", j);
160  body -> print ();
161  printf ("\n");
162  }
163  // mark which with negative number
164  which = - nlin - 1;
165  auxcoe = lcoe [i]. second;
166  maxindex = j;
167  }
168 
169  delete lcoe [i].first;
170  lcoe [i].first = saveVar;
171  }
172  }
173  }
174 
175  if (which != 1)
176  which_was_set = true;
177  else which = -1;
178 
179  // check indices of elements of (nonlinear) sum /////////////////////////////////
180 
181  for (int i = body -> nArgs (); i--;) {
182 
183  CouNumber coeff = 1;
184  int index = alist [i] -> Index ();
185 
186  // if index < 0, this is an expression and not a single variable
187  if (index < 0)
188  elementBreak (alist [i], index, coeff);
189 
190  if ((index > maxindex) &&
191  !(wentAux [index]) &&
192  (fabs (coeff) > COUENNE_EPS)) {
193 
194  // fake a cut in the arglist and check
195 
196  expression *cut = alist [i];
197  alist [i] = new exprConst (0.);
198 
199  // not enough... check now linear (and quadratic!) terms
200 
201  if (body -> dependsOn (index, TAG_AND_RECURSIVE) == 0) {
202 
203  maxindex = index;
204  which = i;
205  auxcoe = coeff;
206  }
207 
208  delete alist [i];
209  alist [i] = cut;
210  }
211  }
212 
213  if (!which_was_set && (which == -1)) // which has not been set
214  return -1;
215 
217 
218  if (maxindex < 0) break; // no substitute found ==> no hidden auxiliary
219 
220  // create a new exprGroup, exprQuad, or exprSum with all elements but the
221  // extracted auxiliary
222 
223  // start with exprSum
224  int nargs = body -> nArgs ();
225  expression **newarglist;
226 
227  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
228  printf (" [[ind %d, coe %.1g, wh %d, nargs %d, nlin %d]] ",
229  maxindex, auxcoe, which, nargs, nlin);
230  }
231 
232  if (nargs > 0) { // there is an element in the nonlinear sum to be drawn
233 
234  int j, mid = (which < 0) ? nargs : which;
235 
236  newarglist = new expression * [nargs + 1];
237 
238  for (j=0; j<mid; j++) newarglist [j] = alist [j];// -> clone (&domain_);
239  for (j++; j<nargs; j++) newarglist [j-1] = alist [j];// -> clone (&domain_);
240 
241  // nl arglist is done, later decide whether to incorporate it as
242  // it is or with a coefficient
243 
244  } else { // no nonlinear arguments, or the only one is the new aux
245 
246  nargs++; // !!!!!!!!!!!!!!!!!!!!!!!!!
247  newarglist = new expression *;
248  *newarglist = new exprConst (0.);
249  }
250 
251  // form rhs linear part ////////////////////////////////////////////////////
252 
253  int *linind2 = NULL;
254  CouNumber *lincoe2 = NULL;
255 
256  // in case this was (and will be) an exprQuad
257  int *qindI = NULL,
258  *qindJ = NULL;
259  CouNumber *qcoe = NULL;
260 
261  if (nlin > 0) { // there is an element in the linear sum to be drawn
262 
263  exprGroup *egBody = dynamic_cast <exprGroup *> (body -> isaCopy () ?
264  body -> Copy () :
265  body);
266 
267  exprGroup::lincoeff &lcoe = egBody -> lcoeff ();
268 
269  int mid = (which >= 0) ? nlin : - which - 1;
270 
271  linind2 = new int [nlin + 1];
272  lincoe2 = new CouNumber [nlin + 1];
273 
274  register int j;
275 
276  //if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
277  //for (j=0; j<mid; j++) printf ("{%g x%d} ", lincoe [j], linind [j]);
278  //for (j++; j<nlin; j++) printf ("{%g x%d} ", lincoe [j], linind [j]);
279  //}
280 
281  CouNumber divider = -1. / auxcoe;
282 
283  for (j=0; j<mid; j++){linind2[j] =lcoe[j].first->Index();lincoe2[j] =divider*lcoe[j].second;}
284  for (j++; j<nlin; j++){linind2[j-1]=lcoe[j].first->Index();lincoe2[j-1]=divider*lcoe[j].second;}
285 
286  linind2 [j-1] = -1; // terminate list of indices
287 
288  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
289  for (j=0; j<mid; j++) printf ("<%g x%d> ", lincoe2 [j], linind2 [j]);
290  for (j++; j<nlin; j++) printf ("<%g x%d> ", lincoe2 [j-1], linind2 [j-1]);
291  }
292 
293  if (code == COU_EXPRQUAD) { // copy quadratic elements
294 
295  exprQuad *eq = dynamic_cast <exprQuad *> (body -> isaCopy () ?
296  body -> Copy () :
297  body);
298 
299  int nqt = eq -> getnQTerms (), j=0;
300 
301  qindI = new int [nqt];
302  qindJ = new int [nqt];
303  qcoe = new CouNumber [nqt];
304 
305  exprQuad::sparseQ &M = eq -> getQ ();
306 
307  for (exprQuad::sparseQ::iterator row = M.begin ();
308  row != M.end (); ++row) {
309 
310  int xind = row -> first -> Index ();
311 
312  for (exprQuad::sparseQcol::iterator col = row -> second.begin ();
313  col != row -> second.end (); ++col, ++j) {
314 
315  qindI [j] = xind;
316  qindJ [j] = col -> first -> Index ();
317  qcoe [j] = divider * col -> second;
318  }
319  }
320  }
321 
322  // nl arglist is done, later decide whether to incorporate it as
323  // it is or with a coefficient
324  }
325 
326  // the extracted index is one term of...
327  if (which >= 0) --nargs; // ...the nonlinear sum
328  else --nlin; // ...the linear part
329 
330  jnlst_ -> Printf (Ipopt::J_ALL, J_REFORMULATE, "\n::: auxcoe %g, rhs %g, lin %d, nl %d\n", auxcoe, rhs, nlin, nargs);
331 
332  // all is ready to take the independent stuff to the other side of
333  // the inequality.
334 
335  if ((code == COU_EXPRQUAD) ||
336  ((code == COU_EXPRGROUP) && (nlin > 0))) {
337 
338  // an exprGroup with at least one linear term left
339  //
340  // build new vectors for index and coeff. Two cases:
341  //
342  // 1) f(x) + c0 - w = rhs =====> w = f(x) + c0 - rhs
343  // 2) f(x) + c0 + aw = rhs =====> w = -1/a (f(x) + c0 - rhs), a != -1
344 
345  if (fabs (auxcoe + 1) < COUENNE_EPS) {
346 
347  //std::vector <std::pair <exprVar *, CouNumber> >
348  exprGroup::lincoeff lcoeff;
349  indcoe2vector (linind2, lincoe2, lcoeff);
350 
351  if (code == COU_EXPRGROUP)
352  rest = new exprGroup (c0-rhs, lcoeff, newarglist, nargs);
353 
354  else {
355  std::vector <quadElem> qcoeff;
356  indcoe2vector (qindI, qindJ, qcoe, qcoeff);
357  rest = new exprQuad (c0-rhs, lcoeff, qcoeff, newarglist, nargs);
358  }
359  }
360  else {
361 
362  expression **mullist = new expression * [1];
363 
364  // only nl term is constant
365  if ((nargs <= 1) && ((*newarglist) -> Linearity () <= CONSTANT)) {
366  *mullist = new exprConst ((*newarglist) -> Value ());
367  //delete *newarglist;
368  delete [] newarglist;
369  }
370  else if ((nargs <= 1) &&
371  ((*newarglist) -> code () == COU_EXPROPP) &&
372  (fabs (auxcoe - 1) < COUENNE_EPS))
373  //*mullist = new exprSum (newarglist, nargs);
374  *mullist = (*newarglist) -> Argument ();//, nargs);
375  else { // multiple nonlinear terms, multiply them by -1/auxcoe
376 
377  if (nargs <= 1)
378  *mullist = new exprMul (new exprConst (-1. / auxcoe),
379  *newarglist); // !!! one more leak?
380  else
381  *mullist = new exprMul (new exprConst (-1. / auxcoe),
382  new exprSum (newarglist, nargs));
383  }
384 
385  std::vector <std::pair <exprVar *, CouNumber> > lcoeff;
386  indcoe2vector (linind2, lincoe2, lcoeff);
387 
388  // final outcome: -1/a (f(x) + c0 - rhs)
389  if (code == COU_EXPRGROUP)
390  rest = new exprGroup ((rhs - c0) / auxcoe, lcoeff, mullist,1);
391 
392  else {
393  std::vector <quadElem> qcoeff;
394  indcoe2vector (qindI, qindJ, qcoe, qcoeff);
395  rest = new exprQuad ((rhs - c0) / auxcoe, lcoeff, qcoeff, mullist,1);
396  }
397  }
398  }
399  else { // simple exprSum
400 
401  if (fabs (rhs) > COUENNE_EPS) { // have to add constant to exprSum
402 
403  if ((nargs == 1) && ((*newarglist) -> Type () == CONST)) {
404 
405  CouNumber val = (*newarglist) -> Value () - rhs;
406  //delete *newarglist;
407  *newarglist = new exprConst (val);
408  }
409  else newarglist [nargs++] = new exprConst (-rhs);
410  }
411 
412  // now exprSum is complete with -rhs. Send it to right hand side
413 
414  expression *auxDef;
415 
416  if (nargs==1) {
417  auxDef = *newarglist;
418  delete [] newarglist;
419  } else auxDef = new exprSum (newarglist, nargs);
420 
421  if (auxcoe == -1.)
422  rest = auxDef;
423  else if ((auxcoe == 1.) &&
424  (auxDef -> code () == COU_EXPROPP))
425  rest = auxDef -> Argument ();
426  else
427  if (auxDef -> Type () == CONST)
428 
429  rest = new exprConst (- auxDef -> Value () / auxcoe);
430  else {
431 
432  // TODO: check if auxdef is an exprMul (k*f(x)) and
433  // -1/auxcoe simplifies
434 
435  if (auxDef -> code () == COU_EXPROPP) {
436 
437  auxDef = auxDef -> Argument ();
438  auxcoe = -auxcoe;
439  }
440 
441  // TODO: if it's a c*(ax+b) return new exprGroup with (c*a, c*b)
442 
443  rest = new exprMul (new exprConst (-1./auxcoe),
444  ((auxDef -> Type () == AUX) ||
445  (auxDef -> Type () == VAR)) ? new exprClone (auxDef) : auxDef);
446  }
447  }
448 
449  if (linind2) {
450  delete [] linind2;
451  delete [] lincoe2;
452  }
453 
454  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
455  printf (" Generated "); rest -> print (); printf ("\n");
456  }
457 
458  auxInd = maxindex;
459 
460  if (auxcoe < 0) {
461  if (sign == expression::AUX_GEQ) sign = expression::AUX_LEQ;
462  else if (sign == expression::AUX_LEQ) sign = expression::AUX_GEQ;
463  }
464 
465  } break;
466 
467  default: break;
468  }
469 
470  if ((auxInd < 0) || (wentAux [auxInd]))
471  return -1;
472 
473  // we have a variable, meaning the constraint body is of the form
474  // w +/- f(x) or f(x) +/- w
475 
476  // standardize remaining of the expression
477 
478  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
479  printf (" Standardize rest (2nd level). Rest: "); fflush (stdout); rest -> print ();
480  printf ("\n Body: "); fflush (stdout); body -> print ();
481  }
482 
483  // second argument is set to false so as to instruct standardize not
484  // to create a new auxiliary variable (we are creating it ourselves,
485  // it's aux)
486 
487  exprAux *aux = rest -> standardize (this, false);
488 
489  if (aux && jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE)) {
490  printf (" Aux: "); aux -> print ();
491  printf (" := "); aux -> Image () -> print ();
492  }
493 
494  if (aux) {
495  //delete rest;
496  //rest = aux -> Image () -> clone (&domain_);
497  rest = aux -> Image (); // -> clone (&domain_);
498  aux -> Image (NULL);
499  //delete aux; // segfaults on simplified expressions? (see test/simple.nl)
500  }
501 
502  if (jnlst_ -> ProduceOutput (Ipopt::J_ALL, J_REFORMULATE))
503  {printf (" ==> (%d)", auxInd); rest -> print (); printf ("\n");}
504 
505  return auxInd;
506 }
class Group, with constant, linear and nonlinear terms:
std::vector< std::pair< exprVar *, sparseQcol > > sparseQ
pos
position where the operator should be printed when printing the expression
class opposite,
void print(std::ostream &=std::cout)
Display current representation of problem: objective, linear and nonlinear constraints, and auxiliary variables.
Definition: problemIO.cpp:24
int splitAux(CouNumber, expression *, expression *&, bool *, enum expression::auxSign &)
split a constraint w - f(x) = c into w&#39;s index (it is returned) and rest = f(x) + c ...
Definition: splitAux.cpp:36
constant-type operator
void elementBreak(expression *arg, int &index, CouNumber &coeff)
given an element of a sum, check if it is a variable (possibly with a coefficient) and return its ind...
static char * j
Definition: OSdtoa.cpp:3622
CouenneProblem * clone() const
Clone method (for use within CouenneCutGenerator::clone)
auxSign
&quot;sign&quot; of the constraint defining an auxiliary.
expression clone (points to another expression)
const Ipopt::EJournalCategory J_REFORMULATE(Ipopt::J_USER7)
#define COUENNE_EPS
Domain domain_
current point and bounds;
bool standardize()
Break problem&#39;s nonlinear constraints in simple expressions to be convexified later.
Definition: standardize.cpp:34
std::vector< std::pair< exprVar *, CouNumber > > lincoeff
double CouNumber
main number type in Couenne
class exprQuad, with constant, linear and quadratic terms
Auxiliary variable.
variable-type operator
JnlstPtr jnlst_
SmartPointer to the Journalist.
void indcoe2vector(int *indexL, CouNumber *coeff, std::vector< std::pair< exprVar *, CouNumber > > &lcoeff)
translates pair (indices, coefficients) into vector with pointers to variables
Expression base class.
void fint * n
bool isInteger(CouNumber x)
is this number integer?