CouenneExprHess.cpp
Go to the documentation of this file.
1 /* $Id: CouenneExprHess.cpp 883 2012-08-03 13:39:53Z pbelotti $
2  *
3  * Name: CouenneExprHess.cpp
4  * Authors: Pietro Belotti, Lehigh University
5  * Purpose: Hessian of the Lagrangian, implementation
6  *
7  * This file is licensed under the Eclipse Public License (EPL)
8  */
9 
10 #include "CoinHelperFunctions.hpp"
11 
12 #include "CouenneExprHess.hpp"
13 #include "CouenneProblem.hpp"
14 #include "CouenneProblemElem.hpp"
15 #include "CouenneExprAux.hpp"
16 
17 using namespace Couenne;
18 
19 //#define DEBUG
20 
23 
24  nnz_ (0),
25  iRow_ (NULL),
26  jCol_ (NULL),
27  numL_ (NULL),
28  lamI_ (NULL),
29  expr_ (NULL) {}
30 
31 
34 {operator= (rhs);}
35 
36 
39 
40  nnz_ = rhs. nnz_;
41 
42  iRow_ = nnz_ && rhs.iRow_ ? (int *) malloc (nnz_ * sizeof (int)) : NULL;
43  jCol_ = nnz_ && rhs.jCol_ ? (int *) malloc (nnz_ * sizeof (int)) : NULL;
44  numL_ = nnz_ && rhs.numL_ ? (int *) malloc (nnz_ * sizeof (int)) : NULL;
45 
46  CoinCopyN (rhs.iRow_, nnz_, iRow_);
47  CoinCopyN (rhs.jCol_, nnz_, jCol_);
48  CoinCopyN (rhs.numL_, nnz_, numL_);
49 
50  if (nnz_) {
51 
52  lamI_ = (int **) malloc (nnz_ * sizeof (int *));
53  expr_ = (expression ***) malloc (nnz_ * sizeof (expression **));
54 
55  for (int i=0; i<nnz_; i++) {
56 
57  lamI_ [i] = CoinCopyOfArray (rhs. lamI_ [i], numL_ [i]);
58 
59  for (int j=0; j<numL_ [i]; j++)
60  expr_ [i] [j] = rhs. expr_ [i][j] -> clone ();
61  }
62  }
63 
64  return *this;
65 }
66 
67 
70 {return new ExprHess (*this);}
71 
72 
75 
76  if (nnz_) {
77 
78  free (iRow_);
79  free (jCol_);
80 
81  for (int i=0; i<nnz_; i++) {
82 
83  for (int j=0; j<numL_ [i]; j++)
84  delete expr_ [i] [j];
85 
86  free (expr_ [i]);
87  free (lamI_ [i]);
88  }
89 
90  free (numL_);
91  free (lamI_);
92  free (expr_);
93  }
94 }
95 
96 
98 void HessElemFill (int i, int level,
99  std::set <int> &list,
100  expression *expr,
101  int *row, int **lam, expression ***eee,
102  CouenneProblem *,
103  std::set <int> &globList);
104 
105 
107 static void reAlloc (int nCur, int &nMax, int *&r, int *&c, int *&n, int **&l, expression ***&e);
108 
109 
112 
113  nnz_ (0),
114  iRow_ (NULL),
115  jCol_ (NULL),
116  numL_ (NULL),
117  lamI_ (NULL),
118  expr_ (NULL) {
119 
120 #ifdef DEBUG
121  printf ("creating Hessian\n");
122  // p -> print ();
123 #endif
124 
127 
128  std::set <int> *deplist = new std::set <int> [1 + p -> nVars () + p -> nCons ()];
129 
130  int nLevels = 0; // depth of this 3D structure (<= #con + #var + 1)
131 
132  // fill in dependence list ///////////////////////////////////////////
133 
134  // 1) for the objective (nLevels = 0). Note: STOP_AT_AUX is
135  // sufficient to get to the leaves of this sum of squares
136 
137  p -> Obj (0) -> Body () -> DepList (deplist [nLevels++], STOP_AT_AUX);
138 
139  // 2) for the constraints
140 
141  for (int i = 0; i < p -> nCons (); i++) {
142 
143  expression *c = p -> Con (i) -> Body ();
144 
145  enum nodeType ntype = c -> Type ();
146 
147  if (ntype == AUX ||
148  ntype == VAR ||
149  ntype == CONST)
150  continue;
151 
152  c -> DepList (deplist [nLevels++], STOP_AT_AUX);
153  }
154 
155  // 3) and the auxiliaries
156 
157  for (int i = 0; i < p -> nVars (); i++) {
158 
159  exprVar *e = p -> Var (i);
160 
161  if ((e -> Type () != AUX) ||
162  (e -> Multiplicity () <= 0))
163  continue;
164 
165  e -> Image () -> DepList (deplist [nLevels++], STOP_AT_AUX);
166  }
167 
168 #ifdef DEBUG
169  for (int i=0; i<nLevels; i++) {
170  printf ("level %d: ", i);
171  for (std::set <int>::iterator j = deplist [i]. begin () ; j != deplist [i].end (); ++j)
172  printf ("%d ", *j);
173  printf ("\n");
174  }
175 #endif
176 
184 
185  int
186  nVars = p -> nVars (),
187  curSize = 0; // used to expand array through realloc
188 
190  for (int i=0; i < nVars; i++) {
191 
192  if (p -> Var (i) -> Multiplicity () <= 0)
193  continue;
194 
195  // create dense row. These will become numL later
196  int *rnz = (int *) malloc (nVars * sizeof (int)); // row's number of nonzero
197  int **lam = (int **) malloc (nVars * sizeof (int *)); // row's vectors of indices of nonzeros
198  expression ***eee = (expression ***) malloc (nVars * sizeof (expression **));
199 
200  std::set <int> globDepList;
201 
202  CoinFillN (rnz, nVars, 0);
203 
204  // No CoinFillN for int** and expression***
205  for (int j=nVars; j--;) {
206  *lam++ = NULL;
207  *eee++ = NULL;
208  }
209 
210  lam -= nVars;
211  eee -= nVars;
212 
213  // scan all levels
214  int level = 0;
215 
217  HessElemFill (i, 0, deplist [0], p -> Obj (0) -> Body (), rnz, lam, eee, p, globDepList);
218 
219  ++level;
220 
221  for (int j = 0; j < p -> nCons (); j++) {
222 
223  CouenneConstraint *c = p -> Con (j);
224  enum nodeType ctype = c -> Body () -> Type ();
225 
226  if (ctype == AUX ||
227  ctype == VAR)
228  continue;
229 
230  HessElemFill (i, level, deplist [level], c -> Body (), rnz, lam, eee, p, globDepList);
231 
232  ++level;
233  }
234 
235  // and auxiliaries
236 
237  for (int j = 0; j < p -> nVars (); j++) {
238 
239  exprVar *e = p -> Var (j);
240 
241  if ((e -> Type () != AUX) ||
242  (e -> Multiplicity () <= 0))
243  continue;
244 
245  HessElemFill (i, level, deplist [level], e -> Image (), rnz, lam, eee, p, globDepList);
246 
247  ++level;
248  }
249 
250  // sparsify rnz, eee, lam
251 
252  for (std::set <int>::iterator j = globDepList.begin (); j != globDepList. end (); ++j) {
253 
254  assert (*j <= i);
255  assert (rnz [*j]);
256 
257  reAlloc (nnz_ + 1, curSize, iRow_, jCol_, numL_, lamI_, expr_);
258 
259  iRow_ [nnz_] = i;
260  jCol_ [nnz_] = *j;
261  numL_ [nnz_] = rnz [*j];
262  lamI_ [nnz_] = (int *) realloc (lam [*j], rnz [*j] * sizeof (int));
263  expr_ [nnz_] = (expression **) realloc (eee [*j], rnz [*j] * sizeof (expression *));
264 
265  ++nnz_;
266  }
267 
268  free (rnz);
269  free (lam);
270  free (eee);
271  }
272 
273  delete [] deplist;
274 
275 #ifdef DEBUG
276  printf ("hessian: %d nonzeros\n", nnz_);
277 
278  for (int i=0; i<nnz_; i++) {
279 
280  printf ("[%d,%d]: %d lambdas: ",
281  iRow_ [i], jCol_ [i], numL_ [i]);
282 
283  fflush (stdout);
284 
285  for (int j=0; j<numL_ [i]; j++) {
286  printf ("(%d,", lamI_ [i][j]);
287  fflush (stdout);
288  expr_ [i][j] -> print ();
289  fflush (stdout);
290  printf (") ");
291  }
292  printf ("\n");
293  }
294 #endif
295 }
296 
297 
298 #define reallocStep 100
299 
300 // fills a row (?) of the Hessian using expression
301 
302 void HessElemFill (int i,
303  int level,
304  std::set <int> &list,
305  expression *expr,
306  int *nnz,
307  int **lam,
308  expression ***eee,
309  CouenneProblem *p,
310  std::set <int> &globList) {
311 
312  if (list. find (i) == list.end () || // expression does not depend on x_i
313  (expr -> Linearity () <= LINEAR)) // no second derivative here
314  return;
315 
316  // only fills lower triangular part (for symmetry)
317 
318  expression
319  *d1 = expr -> differentiate (i), // derivative w.r.t. i
320  *sd1 = d1 -> simplify (), // simplified
321  *rd1 = (sd1 ? sd1 : d1); // actually used
322 
323  rd1 -> realign (p); // fixes variables' domain with the problem.
324 
325  for (std::set <int>::iterator k = list.begin (); k != list. end (); ++k) {
326 
327  if (*k > i)
328  continue;
329 
330  // objective depends on k and i. Is its second derivative, w.r.t. k and i, nonzero?
331 
332  expression
333  *d2 = rd1 -> differentiate (*k), // rd1's derivative w.r.t. *k
334  *sd2 = d2 -> simplify (), // simplified
335  *rd2 = (sd2 ? sd2 : d2); // actually used
336 
337 #ifdef DEBUG
338  printf (" rd2 [x_%d, x_%d]: d/d x_%d = ", *k, i, *k); fflush (stdout);
339  rd1 -> print (); printf (" -> d/(d x_%d,d x_%d) = ", *k, i);
340  rd2 -> print (); printf ("\n");
341 #endif
342 
343  if (sd2) delete d2;
344 
345  if ((rd2 -> Type () != CONST) ||
346  (rd2 -> Value () != 0.)) {
347 
348  // we have a nonzero element of the hessian for constraint i
349 
350  int &curNNZ = nnz [*k];
351 
352  if (!curNNZ &&
353  globList.find (*k) == globList. end ())
354  globList.insert (*k);
355 
356  if (!(curNNZ % reallocStep)) {
357 
358  lam [*k] = (int *) realloc (lam [*k], (curNNZ + reallocStep) * sizeof (int));
359  eee [*k] = (expression **) realloc (eee [*k], (curNNZ + reallocStep) * sizeof (expression *));
360  }
361 
362  rd2 -> realign (p); // fixes variables' domain with the problem.
363 
364  lam [*k] [curNNZ] = level;
365  eee [*k] [curNNZ++] = rd2;
366 
367  } else delete rd2;
368  }
369 
370  if (sd1) delete sd1;
371  delete d1;
372 }
373 
374 static void reAlloc (int nCur, int &nMax, int *&r, int *&c, int *&n, int **&l, expression ***&e) {
375 
376  if (nCur >= nMax) {
377 
378  nMax += reallocStep;
379 
380  r = (int *) realloc (r, nMax * sizeof (int));
381  c = (int *) realloc (c, nMax * sizeof (int));
382  n = (int *) realloc (n, nMax * sizeof (int));
383  l = (int **) realloc (l, nMax * sizeof (int *));
384  e = (expression ***) realloc (e, nMax * sizeof (expression **));
385  }
386 }
expression matrices.
int * numL_
There are m+1 (m constraints + 1 obj) components:
#define d1
#define reallocStep
static void reAlloc(int nCur, int &nMax, int *&r, int *&c, int *&n, int **&l, expression ***&e)
code for refilling arrays through realloc
ExprHess()
empty constructor
expression *** expr_
list of lists of pointers to expression
static char * j
Definition: OSdtoa.cpp:3622
void fint fint fint real fint real real real real real real real real real * e
Class to represent nonlinear constraints.
int * jCol_
col indices
fint end
Class for MINLP problems with symbolic information.
void fint fint * k
void fint fint fint real fint real real real real real real real * r
static int
Definition: OSdtoa.cpp:2173
ExprHess * clone()
Cloning operator.
int nnz_
number of (symbolic) nonzeroes
int ** lamI_
vector of indices in the lambda vector whose constraint has nonzero entry in this position of the hes...
nodeType
type of a node in an expression tree
~ExprHess()
Destructor.
void fint fint fint fint fint fint fint fint fint fint real real real real real real real real real fint real fint real * lam
variable-type operator
void HessElemFill(int i, int level, std::set< int > &list, expression *expr, int *row, int **lam, expression ***eee, CouenneProblem *, std::set< int > &globList)
code for refilling jacobian
Expression base class.
int nnz
ATTENTION: Filter expect the jacobian to be ordered by row.
int * iRow_
row indices (read this way by eval_h)
ExprHess & operator=(const ExprHess &)
code for refilling jacobian
void fint * n
real c