getIntegerCandidate.cpp
Go to the documentation of this file.
1 /* $Id: getIntegerCandidate.cpp 1257 2018-08-28 10:23:00Z pbelotti $
2  *
3  * Name: getIntegerCandidate.cpp
4  * Author: Pietro Belotti
5  * Purpose: generate integer NLP point Y starting from fractional
6  * solution using bound tightening
7  *
8  * (C) Carnegie-Mellon University, 2007-08.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include "CoinTime.hpp"
13 #include "CoinHelperFunctions.hpp"
14 
15 #include "CouenneProblem.hpp"
16 #include "CouenneProblemElem.hpp"
17 #include "CouenneExprVar.hpp"
18 
19 #include "CouenneRecordBestSol.hpp"
20 
21 using namespace Couenne;
22 
23 // lose patience after this many iterations of non-improving valid
24 // tightening (step 1)
25 #define VALID_ONLY_THRESHOLD 5
26 
33 
34 int CouenneProblem::getIntegerCandidate (const double *xFrac, double *xInt,
35  double *lb, double *ub) const {
36  fillIntegerRank ();
37 
38  if (numberInRank_.size () == 0) // there is no original integer to fix
39  return 0;
40 
41  CouNumber *store_optimum = optimum_; // temporary place for debug
42  // optimal solution --- we
43  // don't want to debug while
44  // faking bounds, or we'd cut
45  // the optimum all the time
46  optimum_ = NULL;
47 
48  int
49  ncols = nVars (),
50  retval = 0;
51 
52  double
53  *olb = new double [ncols], *oub = new double [ncols], // outer bounds
54  *dualL = new double [nOrigVars_], *dualR = new double [nOrigVars_]; // lb[objind] per fix index/direction
55 
56  // copy in current bounds
57  CoinCopyN (Lb (), ncols, olb);
58  CoinCopyN (Ub (), ncols, oub);
59 
60  // for now save fractional point into integer point
61  CoinCopyN (xFrac, nOrigVars_ - ndefined_, xInt);
62 
63  domain_.push (nVars (), xInt, lb, ub);
64 
65  enum fixType *fixed = new enum fixType [nOrigVars_ - ndefined_]; // integer variables that were fixed
66 
67  for (int i=0; i<nOrigVars_ - ndefined_; i++)
68  fixed [i] = (Var (i) -> isDefinedInteger () && // work on integer variables only
69  Var (i) -> Multiplicity () > 0) ? // don't care if unused variable
71 
72  // A more sophisticated rounding procedure
73  //
74  // Call aggressive tightening for all integer variables, setting
75  // each first at floor(x_i) and then at ceil(x_i).
76  //
77  //
78  // for each value r of the rank: 1 .. maxrank {
79  //
80  // restrict search of unfixed original variables with rank r to
81  // [floor,ceil] box around LP value
82  //
83  // do {
84  //
85  // threshold = nVarWithThisRank / k
86  // niter = 0;
87  // for each such (unfixed) variable {
88  //
89  // try left
90  // try right
91  //
92  // if both infeasible, abort
93  // else if one infeasible, fix
94  // else if both feasible
95  // if niter < threshold skip
96  // else fix based on lb(left<>right)
97  // }
98  //
99  // if no variables fixed, fix first unfixed
100  // ++niter
101  //
102  // } while there are unfixed variables at this rank
103  // }
104  //
105  // check value of objective -> set cutoff and run bound tightening
106  //
107 
108  const int infeasible = 1;
109 
110  try {
111 
112  // for all values of the integer rank
113 
114  jnlst_ -> Printf (Ipopt::J_ERROR, J_NLPHEURISTIC,
115  "Heuristic: looking for an initial point\n");
116 
117  if (jnlst_ -> ProduceOutput (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC)) {
118  printf ("= ===========================================\n");
119  printf ("= BEGIN ===========================================\n");
120  printf ("= ===========================================\n");
121  for (int i=0; i<nOrigVars_; i++)
122  if (variables_ [i] -> Multiplicity () > 0)
123  printf ("#### %4d: %d %c %2d frac %20g [%20g,%20g]\n",
124  i, fixed [i],
125  variables_ [i] -> isInteger () ? 'I' : ' ',
126  integerRank_ ? integerRank_ [i] : -1,
127  xFrac [i], Lb (i), Ub (i));
128  printf ("---\n");
129  for (int i=nOrigVars_; i<nVars (); i++)
130  if (variables_ [i] -> Multiplicity () > 0)
131  printf ("#### %4d: %c frac %20g [%20g,%20g]\n",
132  i, variables_ [i] -> isInteger () ? 'I' : ' ',
133  //(integerRank_ && integerRank_ [i]) ? 'F' : ' ',
134  X (i), Lb (i), Ub (i));
135  printf ("===================================================\n");
136  printf ("===================================================\n");
137  printf ("===================================================\n");
138  }
139 
140  const int
141  N_VARS_HUGE = 10000,
142  N_VARS_LARGE = 1000,
143  N_VARS_MEDIUM = 100,
144  N_VARS_SMALL = 10,
145  N_VARS_TINY = 5;
146 
147  int
148  ntrials = 0,
149  nvars = nVars (),
150  maxtrials =
151  (nvars >= N_VARS_HUGE) ? 0 :
152  (nvars >= N_VARS_LARGE) ? 1 :
153  (nvars >= N_VARS_MEDIUM) ? 2 :
154  (nvars >= N_VARS_SMALL) ? 4 :
155  (nvars >= N_VARS_TINY) ? 8 : 16;
156 
157  int rank = 1;
158 
159  for (std::vector <int>::iterator rNum = numberInRank_.begin();
160  ++rNum != numberInRank_.end(); rank++)
161 
162  if (*rNum > 0) {
163 
164  jnlst_ -> Printf (Ipopt::J_STRONGWARNING, J_NLPHEURISTIC,
165  "Analyzing %d variables with rank %d\n", *rNum, rank);
166 
167  if (CoinCpuTime () > maxCpuTime_)
168  break;
169 
170  // *rNum is the number of variable with integer rank equal to rank
171 
172  // start restricting around current integer box
173  for (int i=0; i<nOrigVars_ - ndefined_; i++)
174  if ((Var (i) -> Multiplicity () > 0) && // alive variable
175  (Var (i) -> isDefinedInteger ()) && // integer, may fix if independent of other integers
176  (integerRank_ [i] == rank)) {
177 
178  Lb (i) = CoinMax (Lb (i), floor (xFrac [i] - COUENNE_EPS));
179  Ub (i) = CoinMin (Ub (i), ceil (xFrac [i] + COUENNE_EPS));
180  }
181 
182  // translate current NLP point+bounds into higher-dimensional space
183  initAuxs ();
184 
185  if (jnlst_ -> ProduceOutput (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC)) {
186  printf ("= RANK LEVEL = %d [%d] ==================================\n", rank, *rNum);
187  for (int i=0; i<nOrigVars_; i++)
188  if (Var (i) -> Multiplicity () > 0) // alive variable
189  printf ("#### %4d: %d %c %2d frac %20g -> int %20g [%20g,%20g]\n",
190  i, fixed [i],
191  variables_ [i] -> isInteger () ? 'I' : ' ',
192  integerRank_ ? integerRank_ [i] : -1,
193  xFrac [i], xInt [i], Lb (i), Ub (i));
194  printf ("--------------------\n");
195  for (int i=nOrigVars_; i<nVars (); i++)
196  if (Var (i) -> Multiplicity () > 0) // alive variable
197  printf ("#### %4d: %c frac %20g [%20g,%20g]\n",
198  i, variables_ [i] -> isInteger () ? 'I' : ' ',
199  //(integerRank_ && integerRank_ [i]) ? 'F' : ' ',
200  X (i), Lb (i), Ub (i));
201  printf ("=================================================\n");
202  }
203 
204  //CoinCopyN (xFrac, nOrigVars_, xInt);// TODO: re-copy first nOrigVars_ variables into xInt?
205 
206  int remaining = *rNum;
207 
208  do {
209 
210  bool one_fixed = false;
211 
212  for (int i=0; i<nOrigVars_ - ndefined_; i++)
213 
214  if ((Var (i) -> Multiplicity () > 0) && // alive
215  (integerRank_ [i] == rank) && // at this rank
216  (fixed [i] == UNFIXED) && // still to be fixed
217  Var (i) -> isDefinedInteger ()) { // and integer
218 
219  if (CoinCpuTime () > maxCpuTime_)
220  break;
221 
222  // check if initAuxs() closed any bound; if so, fix variable
223  //if (Lb (i) == Ub (i)) { // doesn't work
224  if (ceil (Lb (i) - COUENNE_EPS) + COUENNE_EPS >= floor (Ub (i) + COUENNE_EPS)) {
225 
226  X (i) = Lb (i) = Ub (i) = xInt [i] = ceil (Lb (i) - COUENNE_EPS);
227  fixed [i] = FIXED;
228  one_fixed = true;
229  --remaining;
230  continue;
231  }
232 
233  // if variable already integer valued, fix it (TODO: do
234  // this only if impatient, e.g. if #variables huge)
235  if (ceil (xInt [i] - COUENNE_EPS) - COUENNE_EPS <= xInt [i]) {
236 
237  X (i) = Lb (i) = Ub (i) = xInt [i] = ceil (xInt [i] - COUENNE_EPS);
238  fixed [i] = FIXED;
239  one_fixed = true;
240  --remaining;
241  continue;
242  }
243 
244  // otherwise, test rounding up and down
245  int result = testIntFix (i, xFrac [i], fixed, xInt,
246  dualL, dualR, olb, oub, ntrials < maxtrials);
247 
248  jnlst_ -> Printf (Ipopt::J_STRONGWARNING, J_NLPHEURISTIC,
249  "testing %d [%g -> %g], res = %d\n", i, xFrac [i], xInt [i], result);
250 
251  if (result > 0) {
252  one_fixed = true;
253  --remaining;
254  } else if (result < 0)
255  throw infeasible;
256  }
257 
258  // if none fixed, fix first unfixed variable with this rank
259 
260  if (!one_fixed) {
261 
262  int index = 0;
263 
264  // find first unfixed integer at this rank
265  while ((index < nOrigVars_ - ndefined_) &&
266  (!(Var (index) -> isInteger ()) ||
267  (integerRank_ [index] != rank) ||
268  (fixed [index] != UNFIXED)))
269  ++index;
270 
271  assert (index < nOrigVars_ - ndefined_);
272 
273  jnlst_ -> Printf (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC,
274  "none fixed, fix %d from %g [%g,%g] [L=%g, R=%g]",
275  index, xFrac [index], Lb (index), Ub (index),
276  dualL [index], dualR [index]);
277 
278  Lb (index) = Ub (index) = X (index) = xInt [index] =
279  ((dualL [index] < dualR [index] - COUENNE_EPS) ? floor (xFrac [index]) :
280  (dualL [index] > dualR [index] + COUENNE_EPS) ? ceil (xFrac [index]) :
281  ((CoinDrand48 () > xFrac [index] - floor (xFrac [index])) ?
282  floor (xFrac [index]) : ceil (xFrac [index])));
283 
284  jnlst_ -> Printf (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC, " to %g\n", xInt [index]);
285 
286  fixed [index] = FIXED;
287 
288  --remaining;
289  }
290 
291  ntrials++;
292 
293  if (jnlst_ -> ProduceOutput (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC)) {
294  printf ("--- remaining = %d --------------------------- \n", remaining);
295  for (int i=0; i<nOrigVars_; i++)
296  if (variables_ [i] -> Multiplicity () > 0)
297  printf ("#### %4d: %d %c %2d frac %20g -> int %20g [%20g,%20g]\n",
298  i, fixed [i],
299  variables_ [i] -> isInteger () ? 'I' : ' ',
300  integerRank_ ? integerRank_ [i] : -1,
301  xFrac [i], xInt [i], Lb (i), Ub (i));
302  printf ("---------------------------\n");
303 
304  }
305 
306  if (CoinCpuTime () > maxCpuTime_)
307  break;
308 
309  } while (remaining > 0);
310  } // for
311 
312  // save tightened bounds in NLP space. Sanity check
313  for (int i = nOrigVars_ - ndefined_; i--;)
314  if (Var (i) -> Multiplicity () > 0) {
315 
316  if (fixed [i] == FIXED) // integer point, fixed
317  lb [i] = ub [i] = X (i) = xInt [i];
318 
319  else if (Lb (i) > Ub (i)) { // non-sense bounds, fix them
320  xInt [i] = X (i) = lb [i] = ub [i] =
321  (fixed [i] == CONTINUOUS) ?
322  (0.5 * (Lb (i) + Ub (i))) :
323  COUENNE_round (0.5 * (Lb (i) + Ub (i)));
324 
325  if (fixed [i] != CONTINUOUS)
326  fixed [i] = FIXED;
327 
328  } else { // normal case
329  lb [i] = Lb (i);
330  ub [i] = Ub (i);
331  if (xInt [i] < lb [i]) X (i) = xInt [i] = lb [i];
332  else if (xInt [i] > ub [i]) X (i) = xInt [i] = ub [i];
333  }
334  }
335 
336  restoreUnusedOriginals (xInt);
337 
338  // if initial point is feasible, compute corresponding objective
339  // and update if upper bound improves
340  initAuxs ();
341  int objind = Obj (0) -> Body () -> Index ();
342 
343  CouNumber xp = objind >= 0 ? X (objind) : Obj (0) -> Body () -> Value ();
344 
345  const CouNumber *x = X ();
346 
347  if (checkNLP0 (x, xp, true, false, true, true)) {
348 // #ifdef FM_CHECKNLP2
349 // (checkNLP2(x, 0, false, true, true, feas_tolerance_))
350 // // false for not caring about objective value,
351 // // true for stopping at first violation and true for checkAll
352 // #else
353 // (checkNLP (x, xp, true)) // true for recomputing xp
354 // #endif
355 
356 #ifdef FM_TRACE_OPTSOL
357 #ifdef FM_CHECKNLP2
358  recBSol->update();
359  xp = recBSol->getVal();
360 #else
361  recBSol -> update (x, nVars(), xp, feas_tolerance_);
362 #endif
363 #endif
364  if (xp < getCutOff ()) {
365 
366  setCutOff (xp, x);
367  jnlst_ -> Printf (Ipopt::J_DETAILED, J_NLPHEURISTIC,
368  "new cutoff from getIntCand: %g\n", xp);
369  }
370  }
371  } // try
372 
373  catch (int i) {
374 
375  if (i == infeasible)
376  retval = -1;
377 
378  //
379  // While Couenne does not use this solution (retval==-1), the FP can still use a rounded solution
380  //
381 
382  for (int j=nVars(); j--;)
383  xInt [j] = ceil (xInt [j] - 0.5);
384  }
385 
387 
388  if (jnlst_->ProduceOutput(Ipopt::J_MOREVECTOR, J_NLPHEURISTIC)) {
389  if (retval >= 0) {
390  printf ("- Done: retval %d ----------------------------------------------------------------\n",
391  retval);
392  for (int i=0; i<nOrigVars_; i++)
393  if (variables_ [i] -> Multiplicity () > 0)
394  printf ("#### %4d: %d %c frac %20g -> int %20g [%20g,%20g]\n",
395  i, fixed [i], variables_ [i] -> isInteger () ? 'I' : ' ',
396  xFrac [i], xInt [i], lb [i], ub [i]);
397  } else printf ("no good point was found\n");
398  }
399 
400  jnlst_ -> Printf (Ipopt::J_ERROR, J_NLPHEURISTIC, "Heuristic done\n");
401 
402 
403  delete [] fixed;
404 
405  delete [] olb; delete [] oub;
406  delete [] dualL; delete [] dualR;
407 
408  domain_.pop ();
409 
410  jnlst_ -> Printf (Ipopt::J_MOREVECTOR, J_NLPHEURISTIC, "Done with GetIntegerCandidate\n");
411 
412  optimum_ = store_optimum; // restore
413 
414  return retval;
415 }
#define COUENNE_round(x)
int nVars() const
Total number of variables.
double maxCpuTime_
maximum cpu time
void update(const double *givenSol, const int givenCard, const double givenVal, const double givenMaxViol)
void fillIntegerRank() const
fill freeIntegers_ array
int * integerRank_
each element is true if variable is integer and, if auxiliary, depends on no integer ...
void setCutOff(CouNumber cutoff, const CouNumber *sol=NULL) const
Set cutoff.
Definition: problem.cpp:326
bool checkNLP0(const double *solution, double &obj, bool recompute_obj=false, const bool careAboutObj=false, const bool stopAtFirstViol=true, const bool checkAll=false, const double precision=-1) const
And finally a method to get both.
Definition: checkNLP.cpp:959
static char * j
Definition: OSdtoa.cpp:3622
CouNumber getCutOff() const
Get cutoff.
void restoreUnusedOriginals(CouNumber *=NULL) const
Some originals may be unused due to their zero multiplicity (that happens when they are duplicates)...
int ndefined_
Number of &quot;defined variables&quot; (aka &quot;common expressions&quot;)
std::vector< int > numberInRank_
numberInRank_ [i] is the number of integer variables in rank i
int testIntFix(int index, CouNumber xFrac, enum fixType *fixed, CouNumber *xInt, CouNumber *dualL, CouNumber *dualR, CouNumber *olb, CouNumber *oub, bool patient) const
Test fixing of an integer variable (used in getIntegerCandidate())
Definition: testIntFix.cpp:19
void pop()
restore previous point
Definition: domain.cpp:255
#define COUENNE_EPS
exprVar * Var(int i) const
Return pointer to i-th variable.
std::vector< exprVar * > variables_
Variables (original, auxiliary, and defined)
int getIntegerCandidate(const double *xFrac, double *xInt, double *lb, double *ub) const
generate integer NLP point Y starting from fractional solution using bound tightening ...
CouenneRecordBestSol * recBSol
Domain domain_
current point and bounds;
CouNumber * Ub() const
Return vector of upper bounds.
CouNumber * optimum_
Best solution known to be loaded from file – for testing purposes.
static const int infeasible
Definition: Couenne.cpp:68
void initAuxs() const
Initialize auxiliary variables and their bounds from original variables.
Definition: problem.cpp:51
double CouNumber
main number type in Couenne
fixType
structure to record fixed, non-fixed, and continuous variables
int nOrigVars_
Number of original variables.
CouNumber feas_tolerance_
feasibility tolerance (to be used in checkNLP)
const Ipopt::EJournalCategory J_NLPHEURISTIC(Ipopt::J_USER5)
CouNumber * X() const
Return vector of variables.
void push(int dim, CouNumber *x, CouNumber *lb, CouNumber *ub, bool copy=true)
save current point and start using another
Definition: domain.cpp:166
JnlstPtr jnlst_
SmartPointer to the Journalist.
CouenneObjective * Obj(int i) const
i-th objective
void fint fint fint real fint real * x
CouNumber * Lb() const
Return vector of lower bounds.
bool isInteger(CouNumber x)
is this number integer?