CouenneFPphaseNLP.cpp
Go to the documentation of this file.
1 /* $Id$
2  *
3  * Name: CouenneFPphaseNLP.cpp
4  * Authors: Pietro Belotti
5  * Purpose: NLP part of the loop
6  * Created: February 1, 2014
7  *
8  * This file is licensed under the Eclipse Public License (EPL)
9  */
10 
11 #include "CbcModel.hpp"
12 #include "CoinTime.hpp"
13 #include "CoinHelperFunctions.hpp"
14 
15 #include "CouenneExprAux.hpp"
16 #include "CouenneFeasPump.hpp"
17 #include "CouenneProblem.hpp"
18 #include "CouenneProblemElem.hpp"
19 #include "CouenneCutGenerator.hpp"
20 #include "CouenneTNLP.hpp"
21 #include "CouenneFPpool.hpp"
22 #include "CouenneRecordBestSol.hpp"
23 
24 #ifdef COIN_HAS_SCIP
25 /* general SCIP includes */
26 #include "scip/scip.h"
27 #include "scip/cons_linear.h"
28 #include "scip/scipdefplugins.h"
29 #endif
30 
31 using namespace Ipopt;
32 using namespace Couenne;
33 
34 void printDist (CouenneProblem *p, const double *iSol, double *nSol);
35 void printCmpSol (CouenneProblem *p, const double *iSol, double *nSol, int direction);
36 
37 // Solve
38 int CouenneFeasPump::solution (double &objVal, double *newSolution) {
39 
40  const int depth = (model_ && (model_ -> currentNode ())) ? model_ -> currentNode () -> depth () : 0;
41 
42  double time0 = CoinCpuTime();
43 
44  if ((nCalls_ == 0) || // check upper limit on number of runs
45  //(problem_ -> nIntVars () <= 0) || // feas pump on NLP? Why not?
46  (CoinCpuTime () >= problem_ -> getMaxCpuTime ()) || // don't start if time is out
47  ((numberSolvePerLevel_ >= 0) && // stop FP after a certain level
48  (CoinDrand48 () > 1. / CoinMax // decided randomly and inversely proportional
49  (1., (double) ((CoinMax (0, depth - numberSolvePerLevel_ + 1)) * // to BB tree depth
50  (depth - numberSolvePerLevel_ + 1))))))
51  return 0;
52 
53  if (nCalls_ > 0) // only decrease it if positive. If -1, no limit on # calls
54  --nCalls_;
55 
56  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "==================================================== FP: BEGIN\n");
57  problem_ -> Jnlst () -> Printf (J_ERROR, J_NLPHEURISTIC, "[FeasPump] Initializing\n");
58 
59  // Solve NLP once at the beginning ////////////////////////
60  //
61  // First, it possibly provides an NLP feasible point (the LP
62  // provides a neither NLP nor integer point)
63  //
64  // Second, we need it to compile the Lagrangian Hessian used as a
65  // distance
66 
67  if (!nlp_) // first call (in this run of FP). Create NLP
68  nlp_ = new CouenneTNLP (problem_);
69 
70  problem_ -> domain () -> push (*(problem_ -> domain () -> current ()));
71 
72  // Initial Bound Tightening: since Cbc prefers (reasonably) to call
73  // a heuristic before any cut separator and because BT is instead
74  // quite fast, let's see if we can reduce bounds to get a tighter
75  // MILP relaxation.
76 
77  t_chg_bounds *chg_bds = new t_chg_bounds [problem_ -> nVars ()];
78 
79  for (int i=problem_ -> nVars (); i--;) {
80  chg_bds [i]. setLower (t_chg_bounds::CHANGED);
81  chg_bds [i]. setUpper (t_chg_bounds::CHANGED);
82  }
83 
84  bool is_still_feas = problem_ -> btCore (chg_bds);
85 
86  delete [] chg_bds;
87 
88  // Now that bounds are possibly reduced, put current point within
89  // bounds
90 
91  double
92  *lb = problem_ -> domain () -> lb (),
93  *ub = problem_ -> domain () -> ub (),
94  *sol = problem_ -> domain () -> x ();
95 
96  for (int i=problem_ -> nVars (); i--;)
97 
98  if (sol [i] < lb [i]) sol [i] = lb [i];
99  else if (sol [i] > ub [i]) sol [i] = ub [i];
100 
101  // fix integer coordinates of current (MINLP feasible!) solution
102  // and set it as initial (obviously NLP feasible) solution
103 
104  nlp_ -> setInitSol (sol);
105 
107 
108  if ((multHessNLP_ != 0.) ||
109  (multHessMILP_ != 0.))
110  nlp_ -> getSaveOptHessian () = true;
111 
112  if (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC)) {
113  printf ("initial: solving NLP:---------\n");
114  problem_ -> print ();
115  printf ("---------------------\n");
116  }
117 
118  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: Initial NLP... "); fflush (stdout);
119 
120  // Solve with original objective function
121  ApplicationReturnStatus status = app_ -> OptimizeTNLP (nlp_);
122 
123  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "done\n"); fflush (stdout);
124 
125  if (nlp_ -> getSolution () && (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC))) { // check if non-NULL
126  printf ("######################## NLP solution (init):\n");
127  for (int i=0; i< problem_ -> nVars ();) {
128  printf ("%+e ", nlp_ -> getSolution () [i]);
129  if (!(++i % 15)) printf ("\n");
130  }
131  if ((problem_ -> nVars () - 1) % 5) printf ("\n");
132  }
133 
135 
136  problem_ -> domain () -> pop ();
137 
138  if ((status != Solve_Succeeded) && (status != Solved_To_Acceptable_Level))
139  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "Feasibility Pump: error in initial NLP problem\n");
140 
141  if ((multHessNLP_ != 0.) ||
142  (multHessMILP_ != 0.))
143  nlp_ -> getSaveOptHessian () = false;
144 
145  // This FP works as follows:
146  //
147  // obtain current NLP solution xN or, if none available, current LP solution
148  //
149  // repeat {
150  //
151  // 1) compute MILP solution(s) {xI} H_1-closest to xN
152  // 2) insert them in pool
153  // 3) consider the most promising one xI in the whole pool
154  //
155  // if xI is MINLP-feasible (hack incumbent callback)
156  // update cutoff with min obj among MINLP-feasible
157  // run BT
158  // [else // a little out of the FP scheme
159  // apply linearization cuts to MILP]
160  //
161  // select subset of variables (cont or integer), fix them
162  //
163  // compute NLP solution xN that is H_2-closest to xI
164  //
165  // if MINLP feasible
166  // update cutoff with min obj among MINLP-feasible
167  // run BT
168  //
169  // } until exit condition satisfied
170  //
171  // fix integer variables
172  // resolve NLP
173 
174  CouNumber
175  *nSol = NULL, // solution of the nonlinear problem
176  *iSol = NULL, // solution of the IP problem
177  *best = NULL; // best solution found so far
178 
179  int
180  niter = 0, // iteration counter
181  nsuciter = 0, // counter for consecutive successful applications of one MILP solving method
182  retval = 0, // 1 if found a better solution
183  nSep = 0, // If separation short circuit, max # of consecutive separations
184  objInd = problem_ -> Obj (0) -> Body () -> Index ();
185 
187  // _ _
188  // (_) | |
189  // _ __ ___ __ _ _ _ __ | | ___ ___ _ __
190  // | '_ ` _ \ / _` | | | | '_ \ | | / _ \ / _ \ | '_ `.
191  // | | | | | | | (_| | | | | | | | | | | (_) | | (_) | | |_) |
192  // |_| |_| |_| \__,_| |_| |_| |_| |_| \___/ \___/ | .__/
193  // | |
195 
196  // copy bounding box and current solution to the problem (better
197  // linearization cuts). Note that this push is pop()'d at the end
198  // of the main routine
199 
200  problem_ -> domain () -> push (model_ -> solver ());
201 
202  expression *originalObjective = problem_ -> Obj (0) -> Body ();
203 
204  double
205  save_mDN = multDistNLP_,
206  save_mHN = multHessNLP_,
207  save_mON = multObjFNLP_,
208  save_mDM = multDistMILP_,
209  save_mHM = multHessMILP_,
210  save_mOM = multObjFMILP_;
211 
212  do {
213 
214  if (niter) {
215  multDistNLP_ *= fabs (save_mDN); // update within loop
216  multHessNLP_ *= fabs (save_mHN);
217  multObjFNLP_ *= fabs (save_mON);
218  multDistMILP_ *= fabs (save_mDM);
219  multHessMILP_ *= fabs (save_mHM);
220  multObjFMILP_ *= fabs (save_mOM);
221  }
222 
223  if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
224  break;
225 
226  problem_ -> Jnlst () -> Printf (J_ERROR, J_NLPHEURISTIC, "[FeasPump] Iteration %d [%gs]\n", niter, CoinCpuTime() - time0);
227 
228  // INTEGER PART /////////////////////////////////////////////////////////
229 
230  // Solve IP using nSol as the initial point to minimize weighted
231  // l-1 distance from. If nSol==NULL, the MILP is created using the
232  // original milp's LP solution.
233 
234  double z = solveMILP (nSol, iSol, niter, &nsuciter);
235 
236  // if no MILP solution was found, bail out
237 
238  bool try_again = false;
239 
240  if (!iSol || z >= COIN_DBL_MAX/2) {
241 
242  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: could not find IP solution\n");
243 
244  // find non-tabu solution in the solution pool
245  while (!pool_ -> Set (). empty ()) {
246 
247  // EXTRACT the closest (to nSol) IP solution from the pool
248  pool_ -> findClosestAndReplace (iSol, iSol, problem_ -> nVars ());
249 
250  CouenneFPsolution newSol (problem_, iSol);
251 
252  // we found a solution that is not in the tabu list
253  if (tabuPool_ . find (newSol) == tabuPool_ . end ()) {
254 
255  try_again = true;
256  break;
257  }
258  }
259 
260  if (!try_again) { // try moving around current solution
261 
262  // SCIP could not find a MILP solution and we're somewhat
263  // locked. Round current solution and feed it to the NLP. This
264  // is better than just bailing out.
265 
266  int n = problem_ -> nVars ();
267 
268  if (!iSol)
269  iSol = new double [n];
270 
271  for (int i=0; i<n; i++)
272  iSol [i] = (problem_ -> Var (i) -> isInteger ()) ?
273  COUENNE_round (nSol [i]) :
274  nSol [i];
275  }
276 
277  // if (!try_again) { // nothing to do, bail out
278  // problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: could not find from pool either, bailing out\n");
279  // break;
280  // }
281  }
282 
283  bool isChecked = false;
284 
285  // If a solution was found, but is in the tabu list, two choices:
286  //
287  // 1) the pool is empty: do a round of cuts and repeat;
288  //
289  // 2) the pool is nonempty: extract the best solution from the
290  // pool and use it instead
291 
292  CouenneFPsolution checkedSol (problem_, iSol, false); // false is for not allocating space for this
293 
294  if (tabuPool_. find (checkedSol) == tabuPool_ . end ())
295 
296  tabuPool_. insert (CouenneFPsolution (problem_, iSol)); // only insertion to tabu pool: we check its feasibility now
297 
298  else {
299 
300  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: found solution is tabu\n");
301 
302  // Current solution was visited before. Replace it with another
303  // MILP solution from the pool, if any.
304 
305  if (tabuMgt_ == FP_TABU_NONE) break;
306 
307  else if ((tabuMgt_ == FP_TABU_POOL) && !(pool_ -> Set (). empty ())) {
308 
309  // try to find non-tabu solution in the solution pool
310  do {
311 
312  // retrieve the top solution from the pool
313  pool_ -> findClosestAndReplace (iSol, nSol, problem_ -> nVars ());
314 
315  CouenneFPsolution newSol (problem_, iSol);
316 
317  // we found a solution that is not in the tabu list
318  if (tabuPool_. find (newSol) == tabuPool_ . end ())
319  break;
320 
321  // the pool is empty -> bail out
322  if (pool_ -> Set ().empty ())
323  {
324  delete[] iSol;
325  iSol = NULL;
326  }
327 
328  } while( !pool_ -> Set ().empty() );
329 
330  } else if (((tabuMgt_ == FP_TABU_CUT) ||
331  ((pool_ -> Set (). empty ()) && iSol))) {
332 
333  OsiCuts cs;
334 
335  problem_ -> domain () -> push (problem_ -> nVars (), iSol, milp_ -> getColLower (), milp_ -> getColUpper (), false); // don't copy vectors
336  couenneCG_ -> genRowCuts (*milp_, cs, 0, NULL); // remaining three arguments NULL by default
337  problem_ -> domain () -> pop ();
338 
339  if (cs.sizeRowCuts ()) {
340 
341  milp_ -> applyCuts (cs);
342 
343  if (nSep++ < nSepRounds_)
344  continue;
345 
346  } else break; // nothing left to do, just bail out
347 
348  } else if ((tabuMgt_ == FP_TABU_PERTURB) && iSol) {
349 
350  // perturb solution
351 
352  const CouNumber
353  *lb = milp_ -> getColLower (),
354  *ub = milp_ -> getColUpper ();
355 
356  double
357  downMoves = 0.,
358  upMoves = 0.;
359 
360  int startIndex = (int) floor (CoinDrand48 () * problem_ -> nOrigVars ());
361 
362  for (int ii = problem_ -> nOrigVars (); ii--; lb++, ub++) {
363 
364  if (problem_ -> Var (ii) -> Multiplicity () <= 0)
365  continue;
366 
367  // make perturbation start from pseudo-random points
368 
369  int i = (startIndex + ii) % problem_ -> nOrigVars ();
370 
371  if (problem_ -> Var (i) -> isInteger ()) {
372 
373  double
374  rnd = CoinDrand48 (),
375  down = 0.,
376  up = 1.;
377 
378  // if there is room on the left (resp. right) of the
379  // solution, consider moving down (resp. up). Make moves
380  // less likely as we don't want to perturb too many
381  // variables
382 
383 #define RND_DECR_EXPONENT .5
384 
385  if (iSol [i] >= lb [i] + 1.) down = 1. / pow (1. + (downMoves += 1.), RND_DECR_EXPONENT);
386  if (iSol [i] <= ub [i] - 1.) up = 1. - 1. / pow (1. + (upMoves += 1.), RND_DECR_EXPONENT);
387 
388  if (rnd < down) iSol [i] -= 1.;
389  else if (rnd > up) iSol [i] += 1.;
390  }
391  }
392  }
393  }
394 
395  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: checking IP solution for feasibility\n");
396 
397  isChecked = problem_ -> checkNLP0 (iSol, z, true,
398  false, // don't care about obj
399  true, // stop at first violation
400  true); // checkAll
401 
402  // Possible improvement: if IP-infeasible or if z does not improve
403  // the best solution found so far, then try the following:
404  //
405  // 1) Fix integer variables to IP solution's corresponding components
406  // 2) Solve restriction with original obj
407  // 3) While not found (MI)NLP solution or
408  // solution MINLP infeasible or
409  // z not better
410  // 4) Get solution x* from pool
411  // 5) Solve with original objective
412  // 6) Done
413  // 7) If found solution, set it, otherwise keep previously found (IP-feasible) one
414 
415  if ((!isChecked || // not MINLP feasible
416  z > problem_ -> getCutOff ())) { // not improving
417 
418  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: infeasible/non-improving (feas==%d, z=%g, cutoff=%g), looping on pool\n", isChecked, z, problem_->getCutOff ());
419 
420  bool try_again;
421 
422  do {
423 
424  try_again = false;
425 
426  if (CoinCpuTime () > problem_ -> getMaxCpuTime ())
427  break;
428 
429  // Check if fixing integers to those in iSol yields an
430  // infeasible problem. If so, don't optimize
431  if (fixIntVariables (iSol)) {
432 
433  nlp_ -> setInitSol (iSol);
434 
435  if (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC)) {
436  printf ("----------------------- Solving NLP:\n");
437  problem_ -> print ();
438  printf ("-----------------------\n");
439  }
440 
441  status = app_ -> OptimizeTNLP (nlp_);
442 
443  if (nlp_ -> getSolution ()) { // check if non-NULL
444  if (nSol) CoinCopyN (nlp_ -> getSolution (), problem_ -> nVars (), nSol);
445  else nSol = CoinCopyOfArray (nlp_ -> getSolution (), problem_ -> nVars ());
446  }
447 
448  if (nlp_ -> getSolution () && (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC))) { // check if non-NULL
449  printf ("######################## NLP solution (loop through pool):\n");
450  for (int i=0; i< problem_ -> nVars ();) {
451  printf ("%+e ", nlp_ -> getSolution () [i]);
452  if (!(++i % 15)) printf ("\n");
453  }
454  }
455 
456  z = nlp_ -> getSolValue ();
457 
458  if (z < problem_ -> getCutOff ()) // don't waste time if not improving
459 
460  isChecked = problem_ -> checkNLP0 (nSol, z, true,
461  false, // don't care about obj
462  true, // stop at first violation
463  true); // checkAll
464 
465  if (isChecked && (z < problem_ -> getCutOff ()))
466  break;
467  }
468 
469  // find non-tabu solution in the solution pool
470  while (!pool_ -> Set (). empty ()) {
471 
472  // EXTRACT the closest (to nSol) IP solution from the pool
473  pool_ -> findClosestAndReplace (iSol, nSol, problem_ -> nVars ());
474 
475  CouenneFPsolution newSol (problem_, iSol);
476 
477  // we found a solution that is not in the tabu list
478  if (tabuPool_ . find (newSol) == tabuPool_ . end ()) {
479  try_again = true;
480  break;
481  }
482  }
483 
484  } while (try_again);
485  }
486 
487  // Whatever the previous block yielded, we are now going to check
488  // if we have a new solution, and if so we save it.
489 
490  if (isChecked) {
491 
492  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: IP solution is MINLP feasible\n");
493 
494  // solution is MINLP feasible! Save it.
495 
496  retval = 1;
497  objVal = z;
498 
499  // Found a MINLP-feasible solution, but to keep diversity do NOT
500  // use the best available. Just use this.
501  //
502  // #ifdef FM_CHECKNLP2
503  // # ifdef FM_TRACE_OPTSOL
504  // problem_->getRecordBestSol()->update();
505  // best = problem_->getRecordBestSol()->getSol();
506  // objVal = problem_->getRecordBestSol()->getVal();
507  // # else /* not FM_TRACE_OPTSOL */
508  // best = problem_->getRecordBestSol()->getModSol(problem_->nVars());
509  // objVal = z;
510  // # endif /* not FM_TRACE_OPTSOL */
511  // #else /* not FM_CHECKNLP2 */
512  // # ifdef FM_TRACE_OPTSOL
513  // problem_->getRecordBestSol()->update(iSol, problem_->nVars(),
514  // z, problem_->getFeasTol());
515  // best = problem_->getRecordBestSol()->getSol();
516  // objVal = problem_->getRecordBestSol()->getVal();
517  // # else /* not FM_TRACE_OPTSOL */
518 
519  best = iSol;
520 
521  // objVal = z;
522  // # ifdef FM_TRACE_OPTSOL
523  // problem_->getRecordBestSol()->update();
524  // best = problem_->getRecordBestSol()->getSol();
525  // objVal = problem_->getRecordBestSol()->getVal();
526  // # endif /* not FM_TRACE_OPTSOL */
527  // #endif /* not FM_CHECKNLP2 */
528 
529  if (z < problem_ -> getCutOff ()) {
530 
531  problem_ -> setCutOff (objVal);
532 
533  t_chg_bounds *chg_bds = NULL;
534 
535  if (objInd >= 0) {
536  chg_bds = new t_chg_bounds [problem_ -> nVars ()];
537  chg_bds [objInd].setUpper (t_chg_bounds::CHANGED);
538  }
539 
540  // If, with new cutoff, bound tightening clears the whole
541  // feasible set, stop
542  bool is_still_feas = problem_ -> btCore (chg_bds);
543 
544  if (chg_bds)
545  delete [] chg_bds;
546 
547  // don't tighten MILP if BT says it's infeasible
548 
549  if (!is_still_feas)
550  break;
551 
552  // Update lb/ub on milp and nlp here
553  const CouNumber
554  *plb = problem_ -> Lb (),
555  *pub = problem_ -> Ub (),
556  *mlb = milp_ -> getColLower (),
557  *mub = milp_ -> getColUpper ();
558 
559  for (int i=problem_ -> nVars (), j=0; i--; ++j, ++plb, ++pub) {
560 
561  bool neglect = problem_ -> Var (j) -> Multiplicity () <= 0;
562 
563  if (*plb > *mlb++) milp_ -> setColLower (j, neglect ? 0. : *plb);
564  if (*pub < *mub++) milp_ -> setColUpper (j, neglect ? 0. : *pub);
565  }
566  }
567 
568  break;
569 
570  } else {
571 
572  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: IP solution NOT MINLP feasible\n");
573 
574  if (milpCuttingPlane_ == FP_CUT_EXTERNAL ||
575  milpCuttingPlane_ == FP_CUT_POST) {
576 
577  // Solution is IP- but not MINLP feasible: it might get cut by
578  // linearization cuts. If so, add a round of cuts and repeat.
579 
580  OsiCuts cs;
581 
582  problem_ -> domain () -> push (milp_);
583  couenneCG_ -> genRowCuts (*milp_, cs, 0, NULL); // remaining three arguments NULL by default
584  problem_ -> domain () -> pop ();
585 
586  if (cs.sizeRowCuts ()) {
587 
588  // the (integer, NLP infeasible) solution could be separated
589 
590  milp_ -> applyCuts (cs);
591 
592  // found linearization cut, now re-solve MILP (not quite a FP)
593  if (milpCuttingPlane_ == FP_CUT_EXTERNAL &&
594  nSep++ < nSepRounds_)
595  continue;
596  }
597  }
598  }
599 
600  //
601  // reset number of separation during non-separating iteration
602  //
603 
604  nSep = 0;
605 
606  // NONLINEAR PART ///////////////////////////////////////////////////////
607 
608  // fix some variables and solve the NLP to find a NLP (possibly
609  // non-MIP) feasible solution
610 
611  z = solveNLP (iSol, nSol);
612 
613  if ((nSol && iSol) &&
614  (problem_ -> Jnlst () -> ProduceOutput (J_WARNING, J_NLPHEURISTIC))) {
615 
616  double dist = 0.;
617  int nNonint = 0;
618 
619  for (int i = 0; i < problem_ -> nVars (); ++i) {
620 
621  exprVar *e = problem_ -> Var (i);
622 
623  if (e -> Multiplicity () <= 0)
624  continue;
625 
626  if (e -> isInteger () &&
627  (fabs (iSol [i] - ceil (iSol [i] - .5)) > COUENNE_EPS))
628  ++nNonint;
629 
630  dist +=
631  (iSol [i] - nSol [i]) *
632  (iSol [i] - nSol [i]);
633  }
634 
635  printf ("FP: after NLP, distance %g, %d nonintegers\n", sqrt (dist), nNonint);
636  }
637 
638  if (problem_ -> Jnlst () -> ProduceOutput (J_WARNING, J_NLPHEURISTIC)) {
639 
640  printDist (problem_, iSol, nSol);
641  printCmpSol (problem_, iSol, nSol, 0);
642  }
643 
644  if (z > COIN_DBL_MAX/2) // something went wrong in the NLP, bail out
645  break;
646 
647  // check if newly found NLP solution is also integer
648 
649  isChecked = false;
650 
651  if (nSol) {
652 
653  isChecked = problem_->checkNLP0 (nSol, z, true,
654  false, // do not care about obj
655  true, // stopAtFirstViol
656  true); // checkALL
657  }
658 
659  if (nSol && isChecked) {
660 
661  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: NLP solution is MINLP feasible\n");
662 
663  retval = 1;
664  objVal = z;
665 
666 #ifdef FM_TRACE_OPTSOL // - if ----------------------------
667 #ifdef FM_CHECKNLP2
668  problem_->getRecordBestSol()->update();
669 #else
670  problem_->getRecordBestSol()->update(nSol, problem_->nVars(), z, problem_->getFeasTol());
671 #endif
672  best = problem_->getRecordBestSol()->getSol();
673  objVal = problem_->getRecordBestSol()->getVal();
674 #else // - else --------------------------
675 #ifdef FM_CHECKNLP2
676  best = problem_->getRecordBestSol()->getModSol(problem_ -> nVars ());
677 #else
678  best = nSol;
679 #endif
680  objVal = z;
681 #endif // - endif -------------------------
682 
683  if (z < problem_ -> getCutOff ()) {
684 
685  problem_ -> setCutOff (objVal);
686 
687  t_chg_bounds *chg_bds = NULL;
688 
689  if (objInd >= 0) {
690 
691  chg_bds = new t_chg_bounds [problem_ -> nVars ()];
692  chg_bds [objInd].setUpper (t_chg_bounds::CHANGED);
693  }
694 
695  // if bound tightening clears the whole feasible set, stop
696  bool is_still_feas = problem_ -> btCore (chg_bds);
697 
698  if (chg_bds)
699  delete [] chg_bds;
700 
701  if (!is_still_feas)
702  break;
703  }
704  }
705 
706  // update weights for hessian, distance, and objective, for both
707  // MILP and NLP parts
708 
709  //multHessNLP_ *= save_multHessNLP_; // exponential reduction
710 
711  } while ((niter++ < maxIter_) &&
712  (retval == 0));
713 
714  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: out of the FP loop (feas=%d\n)", retval);
715 
716  // OUT OF THE LOOP ////////////////////////////////////////////////////////
717 
718  // If MINLP solution found,
719  //
720  // 1) restore original objective
721  // 2) fix integer variables
722  // 3) resolve NLP
723 
724  if (nlp_)
725  nlp_ -> setObjective (originalObjective);
726 
727  if (retval > 0) {
728 
729  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: fix integer variables and rerun NLP\n");
730 
731  if (!nlp_) // first call (in this run of FP). Create NLP
732  nlp_ = new CouenneTNLP (problem_);
733 
734  problem_ -> domain () -> push (*(problem_ -> domain () -> current ()));
735 
736  // fix integer coordinates of current (MINLP feasible!) solution
737  // and, if feasible, set it as initial (obviously NLP feasible)
738  // solution
739 
740  if (fixIntVariables (best)) {
741 
742  nlp_ -> setInitSol (best);
743 
745 
746  //app_ -> Options () -> SetStringValue ("fixed_variable_treatment", "make_parameter");
747 
748  // Solve with original objective function
749  status = app_ -> OptimizeTNLP (nlp_);
750 
752 
753  if ((status != Solve_Succeeded) &&
754  (status != Solved_To_Acceptable_Level))
755 
756  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC,
757  "Feasibility Pump: error in final NLP problem (due to fixing integer variables?)\n");
758 
759  if (nlp_ -> getSolution () && (problem_ -> Jnlst () -> ProduceOutput (J_ALL, J_NLPHEURISTIC))) { // check if non-NULL
760  printf ("######################## NLP solution (post):\n");
761  for (int i=0; i< problem_ -> nVars ();) {
762  printf ("%+e ", nlp_ -> getSolution () [i]);
763  if (!(++i % 15)) printf ("\n");
764  }
765  }
766 
767  // if found a solution with the last NLP, check & save it
768 
769  double z = nlp_ -> getSolValue ();
770 
771  // check if newly found NLP solution is also integer (unlikely...)
772  bool isChecked = false;
773 
774  if (nSol) {
775 
776  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: found nlp solution, check it\n");
777 
778  isChecked = problem_ -> checkNLP0 (nSol, z, true,
779  false,
780  true,
781  true);
782  }
783 
784  if (nSol &&
785  isChecked &&
786  (z < problem_ -> getCutOff ())) {
787 
788  problem_ -> Jnlst () -> Printf (J_WARNING, J_NLPHEURISTIC, "FP: feasible solution is improving\n");
789 
790 #ifdef FM_TRACE_OPTSOL
791 
792 #ifdef FM_CHECKNLP2
793  problem_->getRecordBestSol()->update();
794 #else
795  problem_->getRecordBestSol()->update(nSol, problem_->nVars(), z, problem_->getFeasTol());
796 #endif
797  best = problem_->getRecordBestSol()->getSol();
798  objVal = problem_->getRecordBestSol()->getVal();
799 #else
800 
801 #ifdef FM_CHECKNLP2
802  best = problem_->getRecordBestSol()->getModSol(problem_ -> nVars ());
803 #else
804  best = nSol;
805 #endif
806  objVal = z;
807 #endif
808 
809  problem_ -> setCutOff (objVal);
810  }
811  }
812 
813  problem_ -> domain () -> pop ();
814 
815  if (problem_ -> Jnlst () -> ProduceOutput (J_WARNING, J_NLPHEURISTIC)) {
816  printf ("FP: returning MINLP feasible solution:\n");
817  printDist (problem_, best, nSol);
818  }
819 
820  CoinCopyN (best, problem_ -> nVars (), newSolution);
821  }
822 
823  // post-call fading update of coefficients
824 
825  multDistNLP_ = save_mDN * fadeMult_;
826  multHessNLP_ = save_mHN * fadeMult_;
827  multObjFNLP_ = save_mON * fadeMult_;
828  multDistMILP_ = save_mDM * fadeMult_;
829  multHessMILP_ = save_mHM * fadeMult_;
830  multObjFMILP_ = save_mOM * fadeMult_;
831 
832  if (iSol) delete [] iSol;
833  if (nSol) delete [] nSol;
834 
835  // release bounding box
836  problem_ -> domain () -> pop ();
837 
838  // deleted at every call from Cbc, since it changes not only in
839  // terms of variable bounds but also in terms of linearization cuts
840  // added
841 
842  delete milp_;
843  delete postlp_;
844  milp_ = postlp_ = NULL;
845 
846  problem_ -> Jnlst () -> Printf
847  (J_WARNING, J_NLPHEURISTIC, "FP: done ===================\n");
848 
849  if (!retval)
850  problem_ -> Jnlst () -> Printf
851  (J_ERROR, J_NLPHEURISTIC, "FP: No solution found\n");
852 
853  if (retval && (-2 == nCalls_)) {
854  problem_ -> bonBase () -> options () -> SetNumericValue ("time_limit", 0.001, "couenne.");
855  problem_ -> bonBase () -> setDoubleParameter (Bonmin::BabSetupBase::MaxTime, 0.001);
856  }
857 
858  return retval;
859 }
860 
861 // gather data on single solution for later printout
863  int n,
864  const double *v,
865  double &norm,
866  int &nInfI,
867  int &nInfN,
868  double &infI,
869  double &infN) {
870 
871  p -> domain () -> push (n, v, NULL, NULL); // don't care about bounds as not used
872 
873  norm = infI = infN = 0.;
874  nInfI = nInfN = 0;
875 
876  while (n--) {
877  norm += (*v * *v);
878  ++v;
879  }
880  v -= n;
881 
882  norm = sqrt (norm);
883 
884  for (std::vector <exprVar *>::iterator i = p -> Variables (). begin ();
885  i != p -> Variables (). end ();
886  ++i) {
887 
888  if ((*i) -> Multiplicity () <= 0)
889  continue;
890 
891  CouNumber
892  vval = (**i) ();
893 
894  if ((*i) -> isInteger ()) {
895 
896  double inf = CoinMax (vval - floor (vval + COUENNE_EPS),
897  ceil (vval - COUENNE_EPS) - vval);
898 
899  if (inf > COUENNE_EPS) {
900  ++nInfI;
901  infI += inf;
902  }
903  }
904 
905  if ((*i) -> Type () == AUX) {
906 
907  double
908  diff = 0.,
909  fval = (*((*i) -> Image ())) ();
910 
911  if ((*i) -> sign () != expression::AUX_GEQ) diff = CoinMax (diff, vval - fval);
912  else if ((*i) -> sign () != expression::AUX_LEQ) diff = CoinMax (diff, fval - vval);
913 
914  if (diff > COUENNE_EPS) {
915  ++nInfN;
916  infN += diff;
917  }
918  }
919  }
920 
921  p -> domain () -> pop ();
922 }
923 
924 
925 // print solutions and distances
926 void printDist (CouenneProblem *p, const double *iSol, double *nSol) {
927 
928  int nInfII = -1, nInfNI = -1, nInfIN = -1, nInfNN = -1;
929 
930  double
931  dist = -1.,
932  normI = -1., normN = -1.,
933  infII = -1., infNI = -1.,
934  infIN = -1., infNN = -1.;
935 
936  if (iSol) compDistSingle (p, p -> nVars (), iSol, normI, nInfII, nInfNI, infII, infNI);
937  if (nSol) compDistSingle (p, p -> nVars (), nSol, normN, nInfIN, nInfNN, infIN, infNN);
938 
939  if (iSol && nSol) {
940 
941  dist = 0.;
942 
943  for (int i = p -> nVars (); i--;) {
944 
945  if (p -> Var (i) -> Multiplicity () <= 0)
946  continue;
947 
948  dist +=
949  (iSol [i] - nSol [i]) *
950  (iSol [i] - nSol [i]);
951  }
952 
953  dist = sqrt (dist);
954  }
955 
956  printf ("FP: ");
957  printf ("IP norm i:%e n:%e dist %e #inf i:%4d n:%4d max inf i:%e n:%e ", normI, normN, dist, nInfII, nInfNI, infII, infNI);
958  printf ("NL #inf i:%4d n:%4d max inf i:%e n:%e\n", nInfIN, nInfNN, infIN, infNN);
959 }
960 
961 
962 #define WRAP 3
963 
964 void printCmpSol (CouenneProblem *p, const double *iSol, double *nSol, int direction) {
965 
966  int n = p -> nVars ();
967 
968  printf ("i:%p n:%p\nFP # ",
969  (void *) iSol, (void *) nSol);
970 
971  double
972  distance = 0.,
973  diff;
974 
975  char c =
976  direction < 0 ? '<' :
977  direction > 0 ? '>' : '-';
978 
979  for (int i=0; i<n; i++) {
980 
981  if (p -> Var (i) -> Multiplicity () <= 0)
982  continue;
983 
984  if (i && !(i % WRAP))
985  printf ("\nFP # ");
986 
987  double
988  iS = iSol ? iSol [i] : 12345., // flag values, to be seen if something is wrong
989  nS = nSol ? nSol [i] : 54321.;
990 
991  printf ("[%4d %+e -%c- %+e (%e)] ",
992  i, iS, c, nS,
993  (iSol && nSol) ? fabs (iS - nS) : 0.);
994 
995  if (iSol && nSol) {
996  diff = iS - nS;
997  distance += (diff*diff);
998  }
999  }
1000 
1001  if (iSol && nSol) {
1002 
1003  distance = sqrt (distance);
1004  printf ("\n### distance: %e\n", distance);
1005  }
1006 }
#define COUENNE_round(x)
static Bigint * diff(Bigint *a, Bigint *b)
Definition: OSdtoa.cpp:1120
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
static char * j
Definition: OSdtoa.cpp:3622
#define RND_DECR_EXPONENT
int up
Definition: OSdtoa.cpp:1817
Class containing a solution with infeasibility evaluation.
void fint fint fint real fint real real real real real real real real real * e
void setUpper(ChangeStatus upper)
fint end
Class for MINLP problems with symbolic information.
#define COUENNE_EPS
static int
Definition: OSdtoa.cpp:2173
void compDistSingle(CouenneProblem *p, int n, const double *v, double &norm, int &nInfI, int &nInfN, double &infI, double &infN)
void printCmpSol(CouenneProblem *p, const double *iSol, double *nSol, int direction)
double CouNumber
main number type in Couenne
const Ipopt::EJournalCategory J_NLPHEURISTIC(Ipopt::J_USER5)
#define WRAP
variable-type operator
Expression base class.
Class for handling NLPs using CouenneProblem.
Definition: CouenneTNLP.hpp:27
double distance(const double *p1, const double *p2, int size, double k=2.)
compute Euclidean distance between two points (most likely LP solutions) l_2 norm by default...
The in-memory representation of the variables element.
Definition: OSInstance.h:83
void fint * n
real c
void printDist(CouenneProblem *p, const double *iSol, double *nSol)
void fint fint fint real fint real * x
bool isInteger(CouNumber x)
is this number integer?