Scippy

SCIP

Solving Constraint Integer Programs

primal.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file primal.c
17  * @brief methods for collecting primal CIP solutions and primal informations
18  * @author Tobias Achterberg
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 
25 #include "scip/def.h"
26 #include "scip/set.h"
27 #include "scip/stat.h"
28 #include "scip/vbc.h"
29 #include "scip/event.h"
30 #include "scip/lp.h"
31 #include "scip/var.h"
32 #include "scip/prob.h"
33 #include "scip/sol.h"
34 #include "scip/primal.h"
35 #include "scip/tree.h"
36 #include "scip/disp.h"
37 #include "scip/pub_message.h"
38 
39 
40 
41 /*
42  * memory growing methods for dynamically allocated arrays
43  */
44 
45 /** ensures, that sols array can store at least num entries */
46 static
48  SCIP_PRIMAL* primal, /**< primal data */
49  SCIP_SET* set, /**< global SCIP settings */
50  int num /**< minimum number of entries to store */
51  )
52 {
53  assert(primal->nsols <= primal->solssize);
54 
55  if( num > primal->solssize )
56  {
57  int newsize;
58 
59  newsize = SCIPsetCalcMemGrowSize(set, num);
60  SCIP_ALLOC( BMSreallocMemoryArray(&primal->sols, newsize) );
61  primal->solssize = newsize;
62  }
63  assert(num <= primal->solssize);
64 
65  return SCIP_OKAY;
66 }
67 
68 /** ensures, that existingsols array can store at least num entries */
69 static
71  SCIP_PRIMAL* primal, /**< primal data */
72  SCIP_SET* set, /**< global SCIP settings */
73  int num /**< minimum number of entries to store */
74  )
75 {
76  assert(primal->nexistingsols <= primal->existingsolssize);
77 
78  if( num > primal->existingsolssize )
79  {
80  int newsize;
81 
82  newsize = SCIPsetCalcMemGrowSize(set, num);
83  SCIP_ALLOC( BMSreallocMemoryArray(&primal->existingsols, newsize) );
84  primal->existingsolssize = newsize;
85  }
86  assert(num <= primal->existingsolssize);
87 
88  return SCIP_OKAY;
89 }
90 
91 /** creates primal data */
93  SCIP_PRIMAL** primal /**< pointer to primal data */
94  )
95 {
96  assert(primal != NULL);
97 
98  SCIP_ALLOC( BMSallocMemory(primal) );
99  (*primal)->sols = NULL;
100  (*primal)->existingsols = NULL;
101  (*primal)->currentsol = NULL;
102  (*primal)->primalray = NULL;
103  (*primal)->solssize = 0;
104  (*primal)->nsols = 0;
105  (*primal)->existingsolssize = 0;
106  (*primal)->nexistingsols = 0;
107  (*primal)->nsolsfound = 0;
108  (*primal)->nlimsolsfound = 0;
109  (*primal)->nbestsolsfound = 0;
110  (*primal)->nlimbestsolsfound = 0;
111  (*primal)->upperbound = SCIP_INVALID;
112  (*primal)->cutoffbound = SCIP_INVALID;
113 
114  return SCIP_OKAY;
115 }
116 
117 /** frees primal data */
119  SCIP_PRIMAL** primal, /**< pointer to primal data */
120  BMS_BLKMEM* blkmem /**< block memory */
121  )
122 {
123  int s;
124 
125  assert(primal != NULL);
126  assert(*primal != NULL);
127 
128  /* free temporary solution for storing current solution */
129  if( (*primal)->currentsol != NULL )
130  {
131  SCIP_CALL( SCIPsolFree(&(*primal)->currentsol, blkmem, *primal) );
132  }
133 
134  /* free solution for storing primal ray */
135  if( (*primal)->primalray != NULL )
136  {
137  SCIP_CALL( SCIPsolFree(&(*primal)->primalray, blkmem, *primal) );
138  }
139 
140  /* free feasible primal CIP solutions */
141  for( s = 0; s < (*primal)->nsols; ++s )
142  {
143  SCIP_CALL( SCIPsolFree(&(*primal)->sols[s], blkmem, *primal) );
144  }
145  assert((*primal)->nexistingsols == 0);
146 
147  BMSfreeMemoryArrayNull(&(*primal)->sols);
148  BMSfreeMemoryArrayNull(&(*primal)->existingsols);
149  BMSfreeMemory(primal);
150 
151  return SCIP_OKAY;
152 }
153 
154 /** sets the cutoff bound in primal data and in LP solver */
155 static
157  SCIP_PRIMAL* primal, /**< primal data */
158  BMS_BLKMEM* blkmem, /**< block memory */
159  SCIP_SET* set, /**< global SCIP settings */
160  SCIP_STAT* stat, /**< problem statistics data */
161  SCIP_PROB* prob, /**< problem data */
162  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
163  SCIP_TREE* tree, /**< branch and bound tree */
164  SCIP_LP* lp, /**< current LP data */
165  SCIP_Real cutoffbound /**< new cutoff bound */
166  )
167 {
168  assert(primal != NULL);
169  assert(cutoffbound <= SCIPsetInfinity(set));
170  assert(SCIPsetIsLE(set, cutoffbound, primal->upperbound));
171  assert(!SCIPtreeInRepropagation(tree));
172 
173  SCIPdebugMessage("changing cutoff bound from %g to %g\n", primal->cutoffbound, cutoffbound);
174 
175  primal->cutoffbound = MIN(cutoffbound, primal->upperbound); /* get rid of numerical issues */
176 
177  /* set cut off value in LP solver */
178  SCIP_CALL( SCIPlpSetCutoffbound(lp, set, prob, primal->cutoffbound) );
179 
180  /* cut off leaves of the tree */
181  SCIP_CALL( SCIPtreeCutoff(tree, blkmem, set, stat, eventqueue, lp, primal->cutoffbound) );
182 
183  return SCIP_OKAY;
184 }
185 
186 /** sets the cutoff bound in primal data and in LP solver */
188  SCIP_PRIMAL* primal, /**< primal data */
189  BMS_BLKMEM* blkmem, /**< block memory */
190  SCIP_SET* set, /**< global SCIP settings */
191  SCIP_STAT* stat, /**< problem statistics data */
192  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
193  SCIP_PROB* transprob, /**< tranformed problem data */
194  SCIP_PROB* origprob, /**< original problem data */
195  SCIP_TREE* tree, /**< branch and bound tree */
196  SCIP_LP* lp, /**< current LP data */
197  SCIP_Real cutoffbound, /**< new cutoff bound */
198  SCIP_Bool useforobjlimit /**< should the cutoff bound be used to update the objective limit, if
199  * better? */
200  )
201 {
202  assert(primal != NULL);
203  assert(cutoffbound <= SCIPsetInfinity(set));
204  assert(cutoffbound <= primal->upperbound);
205  assert(transprob != NULL);
206  assert(origprob != NULL);
207 
208  if( cutoffbound < primal->cutoffbound )
209  {
210  if( useforobjlimit )
211  {
212  SCIP_Real objval;
213 
214  objval = SCIPprobExternObjval(transprob, origprob, set, cutoffbound);
215 
216  if( objval < SCIPprobGetObjlim(origprob, set) )
217  {
218  SCIPdebugMessage("changing cutoff bound from %g to %g changes objective limit from %g to %g\n", primal->cutoffbound, cutoffbound, SCIPprobGetObjlim(origprob, set), objval);
219  SCIPprobSetObjlim(origprob, objval);
220  }
221  }
222 
223  /* update cutoff bound */
224  SCIP_CALL( primalSetCutoffbound(primal, blkmem, set, stat, transprob, eventqueue, tree, lp, cutoffbound) );
225  }
226  else if( cutoffbound > primal->cutoffbound )
227  {
228  SCIPerrorMessage("invalid increase in cutoff bound\n");
229  return SCIP_INVALIDDATA;
230  }
231 
232  return SCIP_OKAY;
233 }
234 
235 /** sets upper bound in primal data and in LP solver */
236 static
238  SCIP_PRIMAL* primal, /**< primal data */
239  BMS_BLKMEM* blkmem, /**< block memory */
240  SCIP_SET* set, /**< global SCIP settings */
241  SCIP_STAT* stat, /**< problem statistics data */
242  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
243  SCIP_PROB* prob, /**< transformed problem after presolve */
244  SCIP_TREE* tree, /**< branch and bound tree */
245  SCIP_LP* lp, /**< current LP data */
246  SCIP_Real upperbound /**< new upper bound */
247  )
248 {
249  SCIP_Real cutoffbound;
250 
251  assert(primal != NULL);
252  assert(stat != NULL);
253  assert(upperbound <= SCIPsetInfinity(set));
254  assert(upperbound <= primal->upperbound || stat->nnodes == 0);
255 
256  SCIPdebugMessage("changing upper bound from %g to %g\n", primal->upperbound, upperbound);
257 
258  primal->upperbound = upperbound;
259 
260  /* if objective value is always integral, the cutoff bound can be reduced to nearly the previous integer number */
261  if( SCIPprobIsObjIntegral(prob) && !SCIPsetIsInfinity(set, upperbound) )
262  {
263  SCIP_Real delta;
264 
265  delta = SCIPsetCutoffbounddelta(set);
266 
267  cutoffbound = SCIPsetFeasCeil(set, upperbound) - (1.0 - delta);
268  cutoffbound = MIN(cutoffbound, upperbound); /* SCIPsetFeasCeil() can increase bound by almost 1.0 due to numerics
269  * and very large upperbound value */
270  }
271  else
272  cutoffbound = upperbound;
273 
274  /* update cutoff bound */
275  if( cutoffbound < primal->cutoffbound )
276  {
277  SCIP_CALL( primalSetCutoffbound(primal, blkmem, set, stat, prob, eventqueue, tree, lp, cutoffbound) );
278  }
279 
280  /* update upper bound in VBC output */
281  if( SCIPtreeGetCurrentDepth(tree) >= 0 )
282  {
283  SCIPvbcUpperbound(stat->vbc, stat, primal->upperbound);
284  }
285 
286  return SCIP_OKAY;
287 }
288 
289 /** sets upper bound in primal data and in LP solver */
291  SCIP_PRIMAL* primal, /**< primal data */
292  BMS_BLKMEM* blkmem, /**< block memory */
293  SCIP_SET* set, /**< global SCIP settings */
294  SCIP_STAT* stat, /**< problem statistics data */
295  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
296  SCIP_PROB* prob, /**< transformed problem after presolve */
297  SCIP_TREE* tree, /**< branch and bound tree */
298  SCIP_LP* lp, /**< current LP data */
299  SCIP_Real upperbound /**< new upper bound */
300  )
301 {
302  assert(primal != NULL);
303  assert(upperbound <= SCIPsetInfinity(set));
304 
305  if( upperbound < primal->upperbound )
306  {
307  /* update primal bound */
308  SCIP_CALL( primalSetUpperbound(primal, blkmem, set, stat, eventqueue, prob, tree, lp, upperbound) );
309  }
310  else if( upperbound > primal->upperbound )
311  {
312  SCIPerrorMessage("invalid increase in upper bound\n");
313  return SCIP_INVALIDDATA;
314  }
315 
316  return SCIP_OKAY;
317 }
318 
319 /** updates upper bound and cutoff bound in primal data after a tightening of the problem's objective limit */
321  SCIP_PRIMAL* primal, /**< primal data */
322  BMS_BLKMEM* blkmem, /**< block memory */
323  SCIP_SET* set, /**< global SCIP settings */
324  SCIP_STAT* stat, /**< problem statistics data */
325  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
326  SCIP_PROB* transprob, /**< tranformed problem data */
327  SCIP_PROB* origprob, /**< original problem data */
328  SCIP_TREE* tree, /**< branch and bound tree */
329  SCIP_LP* lp /**< current LP data */
330  )
331 {
332  SCIP_Real objlimit;
333  SCIP_Real inf;
334 
335  assert(primal != NULL);
336 
337  /* get internal objective limit */
338  objlimit = SCIPprobInternObjval(transprob, origprob, set, SCIPprobGetObjlim(origprob, set));
339  inf = SCIPsetInfinity(set);
340  objlimit = MIN(objlimit, inf);
341 
342  /* update the cutoff bound */
343  if( objlimit < primal->cutoffbound )
344  {
345  SCIP_CALL( primalSetCutoffbound(primal, blkmem, set, stat, transprob, eventqueue, tree, lp, objlimit) );
346  }
347 
348  /* set new upper bound (and decrease cutoff bound, if objective value is always integral) */
349  if( objlimit < primal->upperbound )
350  {
351  SCIP_CALL( primalSetUpperbound(primal, blkmem, set, stat, eventqueue, transprob, tree, lp, objlimit) );
352  }
353 
354  return SCIP_OKAY;
355 }
356 
357 /** recalculates upper bound and cutoff bound in primal data after a change of the problem's objective offset */
359  SCIP_PRIMAL* primal, /**< primal data */
360  BMS_BLKMEM* blkmem, /**< block memory */
361  SCIP_SET* set, /**< global SCIP settings */
362  SCIP_STAT* stat, /**< problem statistics data */
363  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
364  SCIP_PROB* transprob, /**< tranformed problem data */
365  SCIP_PROB* origprob, /**< original problem data */
366  SCIP_TREE* tree, /**< branch and bound tree */
367  SCIP_LP* lp /**< current LP data */
368  )
369 {
370  SCIP_SOL* sol;
371  SCIP_Real upperbound;
372  SCIP_Real objval;
373  SCIP_Real inf;
374  int i;
375  int j;
376 
377  assert(primal != NULL);
379 
380  /* recalculate internal objective limit */
381  upperbound = SCIPprobInternObjval(transprob, origprob, set, SCIPprobGetObjlim(origprob, set));
382  inf = SCIPsetInfinity(set);
383  upperbound = MIN(upperbound, inf);
384 
385  /* resort current primal solutions */
386  for( i = 1; i < primal->nsols; ++i )
387  {
388  sol = primal->sols[i];
389  objval = SCIPsolGetObj(sol, set, transprob, origprob);
390  for( j = i; j > 0 && objval < SCIPsolGetObj(primal->sols[j-1], set, transprob, origprob); --j )
391  primal->sols[j] = primal->sols[j-1];
392  primal->sols[j] = sol;
393  }
394 
395  /* compare objective limit to currently best solution */
396  if( primal->nsols > 0 )
397  {
398  SCIP_Real obj;
399 
400  assert(SCIPsolIsOriginal(primal->sols[0]));
401  obj = SCIPsolGetObj(primal->sols[0], set, transprob, origprob);
402 
403  upperbound = MIN(upperbound, obj);
404  }
405 
406  /* invalidate old upper bound */
407  SCIP_CALL( primalSetUpperbound(primal, blkmem, set, stat, eventqueue, transprob, tree, lp, SCIPsetInfinity(set)) );
408 
409  /* reset the cutoff bound
410  *
411  * @note we might need to relax the bound since in presolving the objective correction of an
412  * aggregation is still in progress
413  */
414  SCIP_CALL( primalSetCutoffbound(primal, blkmem, set, stat, transprob, eventqueue, tree, lp, upperbound) );
415 
416  /* set new upper bound (and decrease cutoff bound, if objective value is always integral) */
417  SCIP_CALL( primalSetUpperbound(primal, blkmem, set, stat, eventqueue, transprob, tree, lp, upperbound) );
418 
419  return SCIP_OKAY;
420 }
421 
422 /** adds additional objective offset in original space to all existing solution (in original space) */
424  SCIP_PRIMAL* primal, /**< primal data */
425  SCIP_SET* set, /**< global SCIP settings */
426  SCIP_Real addval /**< additional objective offset in original space */
427  )
428 {
429  int i;
430 
431  assert(primal != NULL);
432  assert(set != NULL);
433  assert(SCIPsetGetStage(set) == SCIP_STAGE_PROBLEM);
434 
435 #ifndef NDEBUG
436  assert(primal->nsols == 0 || SCIPsolGetOrigin(primal->sols[0]) == SCIP_SOLORIGIN_ORIGINAL);
437 
438  /* check current order of primal solutions */
439  for( i = 1; i < primal->nsols; ++i )
440  {
441  assert(SCIPsolGetOrigin(primal->sols[i]) == SCIP_SOLORIGIN_ORIGINAL);
442  assert(SCIPsetIsLE(set, SCIPsolGetOrigObj(primal->sols[i-1]), SCIPsolGetOrigObj(primal->sols[i])));
443  }
444 #endif
445 
446  /* check current order of primal solutions */
447  for( i = 0; i < primal->nexistingsols; ++i )
448  {
449  assert(primal->existingsols[i] != NULL);
450  SCIPsolOrigAddObjval(primal->existingsols[i], addval);
451  }
452 }
453 
454 /** returns whether the current primal bound is justified with a feasible primal solution; if not, the primal bound
455  * was set from the user as objective limit
456  */
458  SCIP_PRIMAL* primal, /**< primal data */
459  SCIP_SET* set, /**< global SCIP settings */
460  SCIP_PROB* transprob, /**< tranformed problem data */
461  SCIP_PROB* origprob /**< original problem data */
462  )
463 {
464  assert(primal != NULL);
465 
466  return (primal->nsols > 0 && SCIPsetIsEQ(set, primal->upperbound, SCIPsolGetObj(primal->sols[0], set, transprob, origprob)));
467 }
468 
469 /** adds primal solution to solution storage at given position */
470 static
472  SCIP_PRIMAL* primal, /**< primal data */
473  BMS_BLKMEM* blkmem, /**< block memory */
474  SCIP_SET* set, /**< global SCIP settings */
475  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
476  SCIP_STAT* stat, /**< problem statistics data */
477  SCIP_PROB* origprob, /**< original problem */
478  SCIP_PROB* transprob, /**< transformed problem after presolve */
479  SCIP_TREE* tree, /**< branch and bound tree */
480  SCIP_LP* lp, /**< current LP data */
481  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
482  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
483  SCIP_SOL** solptr, /**< pointer to primal CIP solution */
484  int insertpos, /**< position in solution storage to add solution to */
485  SCIP_Bool replace /**< should the solution at insertpos be replaced by the new solution? */
486  )
487 {
488  SCIP_SOL* sol;
489  SCIP_EVENT event;
490  SCIP_Real obj;
491  int pos;
492 
493  assert(primal != NULL);
494  assert(set != NULL);
495  assert(solptr != NULL);
496  assert(stat != NULL);
497  assert(transprob != NULL);
498  assert(origprob != NULL);
499  assert(0 <= insertpos && insertpos < set->limit_maxsol);
500  assert(tree == NULL || !SCIPtreeInRepropagation(tree));
501 
502  sol = *solptr;
503  assert(sol != NULL);
504  obj = SCIPsolGetObj(sol, set, transprob, origprob);
505 
506  SCIPdebugMessage("insert primal solution %p with obj %g at position %d (replace=%u):\n",
507  (void*)sol, obj, insertpos, replace);
508 
509  SCIPdebug( SCIP_CALL( SCIPsolPrint(sol, set, messagehdlr, stat, transprob, NULL, NULL, FALSE) ) );
510 
511 #if 0
512 #ifndef NDEBUG
513  /* check solution again completely
514  * (this may fail, because in the LP solver, the feasibility tolerance is a relative measure against the row's norm
515  */
516  if( !SCIPsolIsOriginal(sol) )
517  {
518  SCIP_Bool feasible;
519 
520  SCIP_CALL( SCIPsolCheck(sol, set, messagehdlr, blkmem, stat, transprob, TRUE, TRUE, TRUE, &feasible) );
521 
522  if( !feasible )
523  {
524  SCIPerrorMessage("infeasible solution accepted:\n");
525  SCIP_CALL( SCIPsolPrint(sol, set, stat, transprob, NULL, NULL, FALSE) );
526  }
527  assert(feasible);
528  }
529 #endif
530 #endif
531 
532  /* completely fill the solution's own value array to unlink it from the LP or pseudo solution */
533  SCIP_CALL( SCIPsolUnlink(sol, set, transprob) );
534 
535  /* allocate memory for solution storage */
536  SCIP_CALL( ensureSolsSize(primal, set, set->limit_maxsol) );
537 
538  /* if set->limit_maxsol was decreased in the meantime, free all solutions exceeding the limit */
539  for( pos = set->limit_maxsol; pos < primal->nsols; ++pos )
540  {
541  SCIP_CALL( SCIPsolFree(&primal->sols[pos], blkmem, primal) );
542  }
543  primal->nsols = MIN(primal->nsols, set->limit_maxsol);
544 
545  /* if the solution should replace an existing one, free this solution, otherwise,
546  * free the last solution if the solution storage is full;
547  */
548  if( replace )
549  {
550  SCIP_CALL( SCIPsolTransform(primal->sols[insertpos], solptr, blkmem, set, primal) );
551  sol = primal->sols[insertpos];
552  }
553  else
554  {
555  if( primal->nsols == set->limit_maxsol )
556  {
557  SCIP_CALL( SCIPsolFree(&primal->sols[set->limit_maxsol - 1], blkmem, primal) );
558  }
559  else
560  {
561  primal->nsols = primal->nsols + 1;
562  assert(primal->nsols <= set->limit_maxsol);
563  }
564 
565  /* move all solutions with worse objective value than the new solution */
566  for( pos = primal->nsols-1; pos > insertpos; --pos )
567  primal->sols[pos] = primal->sols[pos-1];
568 
569  /* insert solution at correct position */
570  assert(0 <= insertpos && insertpos < primal->nsols);
571  primal->sols[insertpos] = sol;
572  primal->nsolsfound++;
573 
574  /* check if solution is better than objective limit */
575  if( SCIPsetIsFeasLE(set, obj, SCIPprobInternObjval(transprob, origprob, set, SCIPprobGetObjlim(origprob, set))) )
576  primal->nlimsolsfound++;
577  }
578 
579  /* if its the first primal solution, store the relevant statistics */
580  if( primal->nsolsfound == 1 )
581  {
582  SCIP_Real primalsolval;
583 
585  stat->nrunsbeforefirst = SCIPsolGetRunnum(sol);
586  stat->firstprimalheur = SCIPsolGetHeur(sol);
587  stat->firstprimaltime = SCIPsolGetTime(sol);
588  stat->firstprimaldepth = SCIPsolGetDepth(sol);
589 
590  primalsolval = obj;
591  stat->firstprimalbound = SCIPprobExternObjval(transprob, origprob, set, primalsolval);
592 
593  SCIPdebugMessage("First Solution stored in problem specific statistics.\n");
594  SCIPdebugMessage("-> %"SCIP_LONGINT_FORMAT" nodes, %d runs, %.2g time, %d depth, %.15g objective\n", stat->nnodesbeforefirst, stat->nrunsbeforefirst,
596  }
597 
598  SCIPdebugMessage(" -> stored at position %d of %d solutions, found %"SCIP_LONGINT_FORMAT" solutions\n",
599  insertpos, primal->nsols, primal->nsolsfound);
600 
601  /* update the solution value sums in variables */
602  if( !SCIPsolIsOriginal(sol) )
603  {
604  SCIPsolUpdateVarsum(sol, set, stat, transprob,
605  (SCIP_Real)(primal->nsols - insertpos)/(SCIP_Real)(2.0*primal->nsols - 1.0));
606  }
607 
608  /* change color of node in VBC output */
609  SCIPvbcFoundSolution(stat->vbc, set, stat, SCIPtreeGetCurrentNode(tree));
610 
611  /* check, if the global upper bound has to be updated */
612  if( obj < primal->upperbound )
613  {
614  /* update the upper bound */
615  SCIP_CALL( SCIPprimalSetUpperbound(primal, blkmem, set, stat, eventqueue, transprob, tree, lp, obj) );
616 
617  /* issue BESTSOLFOUND event */
619  primal->nbestsolsfound++;
620  stat->bestsolnode = stat->nnodes;
621  }
622  else
623  {
624  /* issue POORSOLFOUND event */
626  }
627  SCIP_CALL( SCIPeventChgSol(&event, sol) );
628  SCIP_CALL( SCIPeventProcess(&event, set, NULL, NULL, NULL, eventfilter) );
629 
630  /* display node information line */
631  if( insertpos == 0 && !replace && set->stage >= SCIP_STAGE_SOLVING )
632  {
633  SCIP_CALL( SCIPdispPrintLine(set, messagehdlr, stat, NULL, TRUE, TRUE) );
634  }
635 
636  /* if an original solution was added during solving, try to transfer it to the transformed space */
637  if( SCIPsolIsOriginal(sol) && SCIPsetGetStage(set) == SCIP_STAGE_SOLVING && set->misc_transorigsols )
638  {
639  SCIP_Bool added;
640 
641  SCIP_CALL( SCIPprimalTransformSol(primal, sol, blkmem, set, messagehdlr, stat, origprob, transprob, tree, lp,
642  eventqueue, eventfilter, NULL, NULL, 0, &added) );
643 
644  SCIPdebugMessage("original solution %p was successfully transferred to the transformed problem space\n",
645  (void*)sol);
646 
647  }
648 
649  return SCIP_OKAY;
650 }
651 
652 /** adds primal solution to solution storage at given position */
653 static
655  SCIP_PRIMAL* primal, /**< primal data */
656  BMS_BLKMEM* blkmem, /**< block memory */
657  SCIP_SET* set, /**< global SCIP settings */
658  SCIP_PROB* prob, /**< original problem data */
659  SCIP_SOL* sol, /**< primal CIP solution */
660  int insertpos /**< position in solution storage to add solution to */
661  )
662 {
663  int pos;
664 
665  assert(primal != NULL);
666  assert(set != NULL);
667  assert(prob != NULL);
668  assert(sol != NULL);
669  assert(0 <= insertpos && insertpos < set->limit_maxorigsol);
670 
671  SCIPdebugMessage("insert primal solution candidate %p with obj %g at position %d:\n", (void*)sol, SCIPsolGetOrigObj(sol), insertpos);
672 
673  /* allocate memory for solution storage */
674  SCIP_CALL( ensureSolsSize(primal, set, set->limit_maxorigsol) );
675 
676  /* if the solution storage is full, free the last solution(s)
677  * more than one solution may be freed, if set->limit_maxorigsol was decreased in the meantime
678  */
679  for( pos = set->limit_maxorigsol-1; pos < primal->nsols; ++pos )
680  {
681  SCIP_CALL( SCIPsolFree(&primal->sols[pos], blkmem, primal) );
682  }
683 
684  /* insert solution at correct position */
685  primal->nsols = MIN(primal->nsols+1, set->limit_maxorigsol);
686  for( pos = primal->nsols-1; pos > insertpos; --pos )
687  primal->sols[pos] = primal->sols[pos-1];
688 
689  assert(0 <= insertpos && insertpos < primal->nsols);
690  primal->sols[insertpos] = sol;
691  primal->nsolsfound++;
692 
693  /* check if solution is better than objective limit */
694  if( SCIPsetIsFeasLE(set, SCIPsolGetOrigObj(sol), SCIPprobGetObjlim(prob, set)) )
695  primal->nlimsolsfound++;
696 
697  SCIPdebugMessage(" -> stored at position %d of %d solutions, found %"SCIP_LONGINT_FORMAT" solutions\n",
698  insertpos, primal->nsols, primal->nsolsfound);
699 
700  return SCIP_OKAY;
701 }
702 
703 /** uses binary search to find position in solution storage */
704 static
706  SCIP_PRIMAL* primal, /**< primal data */
707  SCIP_SET* set, /**< global SCIP settings */
708  SCIP_PROB* transprob, /**< tranformed problem data */
709  SCIP_PROB* origprob, /**< original problem data */
710  SCIP_SOL* sol /**< primal solution to search position for */
711  )
712 {
713  SCIP_SOL** sols;
714  SCIP_Real obj;
715  SCIP_Real middleobj;
716  int left;
717  int right;
718  int middle;
719 
720  assert(primal != NULL);
721 
722  obj = SCIPsolGetObj(sol, set, transprob, origprob);
723  sols = primal->sols;
724 
725  left = -1;
726  right = primal->nsols;
727  while( left < right-1 )
728  {
729  middle = (left+right)/2;
730  assert(left < middle && middle < right);
731  assert(0 <= middle && middle < primal->nsols);
732 
733  middleobj = SCIPsolGetObj(sols[middle], set, transprob, origprob);
734 
735  if( obj < middleobj )
736  right = middle;
737  else
738  left = middle;
739  }
740  assert(left == right-1);
741 
742  /* prefer solutions that live in the transformed space */
743  if( !SCIPsolIsOriginal(sol) )
744  {
745  while( right > 0 && SCIPsolIsOriginal(sols[right-1])
746  && SCIPsetIsEQ(set, SCIPsolGetObj(sols[right-1], set, transprob, origprob), obj) )
747  --right;
748  }
749 
750  return right;
751 }
752 
753 /** uses binary search to find position in solution storage */
754 static
756  SCIP_PRIMAL* primal, /**< primal data */
757  SCIP_SOL* sol /**< primal solution to search position for */
758  )
759 {
760  SCIP_Real obj;
761  SCIP_Real middleobj;
762  int left;
763  int right;
764  int middle;
765 
766  assert(primal != NULL);
767 
768  obj = SCIPsolGetOrigObj(sol);
769 
770  left = -1;
771  right = primal->nsols;
772  while( left < right-1 )
773  {
774  middle = (left+right)/2;
775  assert(left < middle && middle < right);
776  assert(0 <= middle && middle < primal->nsols);
777  middleobj = SCIPsolGetOrigObj(primal->sols[middle]);
778  if( obj < middleobj )
779  right = middle;
780  else
781  left = middle;
782  }
783  assert(left == right-1);
784 
785  return right;
786 }
787 
788 /** returns whether the given primal solution is already existent in the solution storage */
789 static
791  SCIP_PRIMAL* primal, /**< primal data */
792  SCIP_SET* set, /**< global SCIP settings */
793  SCIP_STAT* stat, /**< problem statistics data */
794  SCIP_PROB* origprob, /**< original problem */
795  SCIP_PROB* transprob, /**< transformed problem after presolve */
796  SCIP_SOL* sol, /**< primal solution to search position for */
797  int* insertpos, /**< pointer to insertion position returned by primalSearchSolPos(); the
798  * position might be changed if an existing solution should be replaced */
799  SCIP_Bool* replace /**< pointer to store whether the solution at insertpos should be replaced */
800  )
801 {
802  SCIP_Real obj;
803  int i;
804 
805  assert(primal != NULL);
806  assert(insertpos != NULL);
807  assert(replace != NULL);
808  assert(0 <= (*insertpos) && (*insertpos) <= primal->nsols);
809 
810  obj = SCIPsolGetObj(sol, set, transprob, origprob);
811 
812  assert(primal->sols != NULL || primal->nsols == 0);
813  assert(primal->sols != NULL || (*insertpos) == 0);
814 
815  /* search in the better solutions */
816  for( i = (*insertpos)-1; i >= 0; --i )
817  {
818  SCIP_Real solobj;
819 
820  solobj = SCIPsolGetObj(primal->sols[i], set, transprob, origprob);
821 
822  /* due to transferring the objective value of transformed solutions to the original space, small numerical errors might occur
823  * which can lead to SCIPsetIsLE() failing in case of high absolute numbers
824  */
825  assert(SCIPsetIsLE(set, solobj, obj) || (REALABS(obj) > 1e+13 * SCIPsetEpsilon(set) && SCIPsetIsFeasLE(set, solobj, obj)));
826 
827  if( SCIPsetIsLT(set, solobj, obj) )
828  break;
829 
830  if( SCIPsolsAreEqual(sol, primal->sols[i], set, stat, origprob, transprob) )
831  {
832  if( SCIPsolIsOriginal(primal->sols[i]) && !SCIPsolIsOriginal(sol) )
833  {
834  (*insertpos) = i;
835  (*replace) = TRUE;
836  }
837  return TRUE;
838  }
839  }
840 
841  /* search in the worse solutions */
842  for( i = (*insertpos); i < primal->nsols; ++i )
843  {
844  SCIP_Real solobj;
845 
846  solobj = SCIPsolGetObj(primal->sols[i], set, transprob, origprob);
847 
848  /* due to transferring the objective value of transformed solutions to the original space, small numerical errors might occur
849  * which can lead to SCIPsetIsLE() failing in case of high absolute numbers
850  */
851  assert( SCIPsetIsGE(set, solobj, obj) || (REALABS(obj) > 1e+13 * SCIPsetEpsilon(set) && SCIPsetIsFeasGE(set, solobj, obj)));
852 
853  if( SCIPsetIsGT(set, solobj, obj) )
854  break;
855 
856  if( SCIPsolsAreEqual(sol, primal->sols[i], set, stat, origprob, transprob) )
857  {
858  if( SCIPsolIsOriginal(primal->sols[i]) && !SCIPsolIsOriginal(sol) )
859  {
860  (*insertpos) = i;
861  (*replace) = TRUE;
862  }
863  return TRUE;
864  }
865  }
866 
867  return FALSE;
868 }
869 
870 /** returns whether the given primal solution is already existent in the original solution candidate storage */
871 static
873  SCIP_PRIMAL* primal, /**< primal data */
874  SCIP_SET* set, /**< global SCIP settings */
875  SCIP_STAT* stat, /**< problem statistics data */
876  SCIP_PROB* prob, /**< original problem */
877  SCIP_SOL* sol, /**< primal solution to search position for */
878  int insertpos /**< insertion position returned by primalSearchOrigSolPos() */
879  )
880 {
881  SCIP_Real obj;
882  int i;
883 
884  assert(primal != NULL);
885  assert(0 <= insertpos && insertpos <= primal->nsols);
886 
887  obj = SCIPsolGetOrigObj(sol);
888 
889  /* search in the better solutions */
890  for( i = insertpos-1; i >= 0; --i )
891  {
892  SCIP_Real solobj;
893 
894  solobj = SCIPsolGetOrigObj(primal->sols[i]);
895  assert( SCIPsetIsLE(set, solobj, obj) );
896 
897  if( SCIPsetIsLT(set, solobj, obj) )
898  break;
899 
900  if( SCIPsolsAreEqual(sol, primal->sols[i], set, stat, prob, NULL) )
901  return TRUE;
902  }
903 
904  /* search in the worse solutions */
905  for( i = insertpos; i < primal->nsols; ++i )
906  {
907  SCIP_Real solobj;
908 
909  solobj = SCIPsolGetOrigObj(primal->sols[i]);
910  assert( SCIPsetIsGE(set, solobj, obj) );
911 
912  if( SCIPsetIsGT(set, solobj, obj) )
913  break;
914 
915  if( SCIPsolsAreEqual(sol, primal->sols[i], set, stat, prob, NULL) )
916  return TRUE;
917  }
918 
919  return FALSE;
920 }
921 
922 /** check if we are willing to check the solution for feasibility */
923 static
925  SCIP_PRIMAL* primal, /**< primal data */
926  SCIP_SET* set, /**< global SCIP settings */
927  SCIP_STAT* stat, /**< problem statistics data */
928  SCIP_PROB* origprob, /**< original problem */
929  SCIP_PROB* transprob, /**< transformed problem after presolve */
930  SCIP_SOL* sol, /**< primal CIP solution */
931  int* insertpos, /**< pointer to store the insert position of that solution */
932  SCIP_Bool* replace /**< pointer to store whether the solution at insertpos should be replaced
933  * (e.g., because it lives in the original space) */
934  )
935 {
936  SCIP_Real obj;
937 
938  obj = SCIPsolGetObj(sol, set, transprob, origprob);
939 
940  /* check if we are willing to check worse solutions; a solution is better if the objective is smaller than the
941  * current cutoff bound; solutions with infinite objective value are never accepted
942  */
943  if( (!set->misc_improvingsols || obj < primal->cutoffbound) && !SCIPsetIsInfinity(set, obj) )
944  {
945  /* find insert position for the solution */
946  (*insertpos) = primalSearchSolPos(primal, set, transprob, origprob, sol);
947  (*replace) = FALSE;
948 
949  /* the solution should be added, if the insertpos is smaller than the maximum number of solutions to be stored
950  * and it does not already exist or it does exist, but the existing solution should be replaced by the new one
951  */
952  if( (*insertpos) < set->limit_maxsol &&
953  (!primalExistsSol(primal, set, stat, origprob, transprob, sol, insertpos, replace) || (*replace)) )
954  return TRUE;
955  }
956 
957  return FALSE;
958 }
959 
960 /** check if we are willing to store the solution candidate for later checking */
961 static
963  SCIP_PRIMAL* primal, /**< primal data */
964  SCIP_SET* set, /**< global SCIP settings */
965  SCIP_STAT* stat, /**< problem statistics data */
966  SCIP_PROB* origprob, /**< original problem */
967  SCIP_SOL* sol, /**< primal CIP solution */
968  int* insertpos /**< pointer to store the insert position of that solution */
969  )
970 {
971  assert(SCIPsolIsOriginal(sol));
972 
973  /* find insert position for the solution */
974  (*insertpos) = primalSearchOrigSolPos(primal, sol);
975 
976  if( (*insertpos) < set->limit_maxorigsol && !primalExistsOrigSol(primal, set, stat, origprob, sol, *insertpos) )
977  return TRUE;
978 
979  return FALSE;
980 }
981 
982 /** adds primal solution to solution storage by copying it */
984  SCIP_PRIMAL* primal, /**< primal data */
985  BMS_BLKMEM* blkmem, /**< block memory */
986  SCIP_SET* set, /**< global SCIP settings */
987  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
988  SCIP_STAT* stat, /**< problem statistics data */
989  SCIP_PROB* origprob, /**< original problem */
990  SCIP_PROB* transprob, /**< transformed problem after presolve */
991  SCIP_TREE* tree, /**< branch and bound tree */
992  SCIP_LP* lp, /**< current LP data */
993  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
994  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
995  SCIP_SOL* sol, /**< primal CIP solution */
996  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
997  )
998 {
999  SCIP_Bool replace;
1000  int insertpos;
1001 
1002  assert(primal != NULL);
1003  assert(transprob != NULL);
1004  assert(origprob != NULL);
1005  assert(sol != NULL);
1006  assert(stored != NULL);
1007 
1008  insertpos = -1;
1009 
1010  if( solOfInterest(primal, set, stat, origprob, transprob, sol, &insertpos, &replace) )
1011  {
1012  SCIP_SOL* solcopy;
1013 #ifdef SCIP_MORE_DEBUG
1014  int i;
1015 #endif
1016 
1017  assert(insertpos >= 0 && insertpos < set->limit_maxsol);
1018 
1019  /* create a copy of the solution */
1020  SCIP_CALL( SCIPsolCopy(&solcopy, blkmem, set, stat, primal, sol) );
1021 
1022  /* insert copied solution into solution storage */
1023  SCIP_CALL( primalAddSol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1024  tree, lp, eventqueue, eventfilter, &solcopy, insertpos, replace) );
1025 #ifdef SCIP_MORE_DEBUG
1026  for( i = 0; i < primal->nsols - 1; ++i )
1027  {
1028  assert(SCIPsetIsLE(set, SCIPsolGetObj(primal->sols[i], set, transprob, origprob), SCIPsolGetObj(primal->sols[i+1], set, transprob, origprob)));
1029  }
1030 #endif
1031  *stored = TRUE;
1032  }
1033  else
1034  *stored = FALSE;
1035 
1036  return SCIP_OKAY;
1037 }
1038 
1039 /** adds primal solution to solution storage, frees the solution afterwards */
1041  SCIP_PRIMAL* primal, /**< primal data */
1042  BMS_BLKMEM* blkmem, /**< block memory */
1043  SCIP_SET* set, /**< global SCIP settings */
1044  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1045  SCIP_STAT* stat, /**< problem statistics data */
1046  SCIP_PROB* origprob, /**< original problem */
1047  SCIP_PROB* transprob, /**< transformed problem after presolve */
1048  SCIP_TREE* tree, /**< branch and bound tree */
1049  SCIP_LP* lp, /**< current LP data */
1050  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1051  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1052  SCIP_SOL** sol, /**< pointer to primal CIP solution; is cleared in function call */
1053  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
1054  )
1055 {
1056  SCIP_Bool replace;
1057  int insertpos;
1058 
1059  assert(primal != NULL);
1060  assert(transprob != NULL);
1061  assert(origprob != NULL);
1062  assert(sol != NULL);
1063  assert(*sol != NULL);
1064  assert(stored != NULL);
1065 
1066  insertpos = -1;
1067 
1068  if( solOfInterest(primal, set, stat, origprob, transprob, *sol, &insertpos, &replace) )
1069  {
1070  assert(insertpos >= 0 && insertpos < set->limit_maxsol);
1071 
1072  /* insert solution into solution storage */
1073  SCIP_CALL( primalAddSol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1074  tree, lp, eventqueue, eventfilter, sol, insertpos, replace) );
1075 
1076  /* clear the pointer, such that the user cannot access the solution anymore */
1077  *sol = NULL;
1078 
1079  *stored = TRUE;
1080  }
1081  else
1082  {
1083  /* the solution is too bad -> free it immediately */
1084  SCIP_CALL( SCIPsolFree(sol, blkmem, primal) );
1085 
1086  *stored = FALSE;
1087  }
1088  assert(*sol == NULL);
1089 
1090  return SCIP_OKAY;
1091 }
1092 
1093 /** adds primal solution to solution candidate storage of original problem space */
1095  SCIP_PRIMAL* primal, /**< primal data */
1096  BMS_BLKMEM* blkmem, /**< block memory */
1097  SCIP_SET* set, /**< global SCIP settings */
1098  SCIP_STAT* stat, /**< problem statistics data */
1099  SCIP_PROB* prob, /**< original problem data */
1100  SCIP_SOL* sol, /**< primal CIP solution; is cleared in function call */
1101  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
1102  )
1103 {
1104  int insertpos;
1105 
1106  assert(primal != NULL);
1107  assert(sol != NULL);
1108  assert(SCIPsolIsOriginal(sol));
1109  assert(stored != NULL);
1110 
1111  insertpos = -1;
1112 
1113  if( origsolOfInterest(primal, set, stat, prob, sol, &insertpos) )
1114  {
1115  SCIP_SOL* solcopy;
1116 
1117  assert(insertpos >= 0 && insertpos < set->limit_maxorigsol);
1118 
1119  /* create a copy of the solution */
1120  SCIP_CALL( SCIPsolCopy(&solcopy, blkmem, set, stat, primal, sol) );
1121 
1122  /* insert solution into solution storage */
1123  SCIP_CALL( primalAddOrigSol(primal, blkmem, set, prob, solcopy, insertpos) );
1124 
1125  *stored = TRUE;
1126  }
1127  else
1128  *stored = FALSE;
1129 
1130  return SCIP_OKAY;
1131 }
1132 
1133 /** adds primal solution to solution candidate storage of original problem space, frees the solution afterwards */
1135  SCIP_PRIMAL* primal, /**< primal data */
1136  BMS_BLKMEM* blkmem, /**< block memory */
1137  SCIP_SET* set, /**< global SCIP settings */
1138  SCIP_STAT* stat, /**< problem statistics data */
1139  SCIP_PROB* prob, /**< original problem data */
1140  SCIP_SOL** sol, /**< pointer to primal CIP solution; is cleared in function call */
1141  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
1142  )
1143 {
1144  int insertpos;
1145 
1146  assert(primal != NULL);
1147  assert(sol != NULL);
1148  assert(*sol != NULL);
1149  assert(SCIPsolIsOriginal(*sol));
1150  assert(stored != NULL);
1151 
1152  insertpos = -1;
1153 
1154  if( origsolOfInterest(primal, set, stat, prob, *sol, &insertpos) )
1155  {
1156  assert(insertpos >= 0 && insertpos < set->limit_maxorigsol);
1157 
1158  /* insert solution into solution storage */
1159  SCIP_CALL( primalAddOrigSol(primal, blkmem, set, prob, *sol, insertpos) );
1160 
1161  /* clear the pointer, such that the user cannot access the solution anymore */
1162  *sol = NULL;
1163 
1164  *stored = TRUE;
1165  }
1166  else
1167  {
1168  /* the solution is too bad -> free it immediately */
1169  SCIP_CALL( SCIPsolFree(sol, blkmem, primal) );
1170 
1171  *stored = FALSE;
1172  }
1173  assert(*sol == NULL);
1174 
1175  return SCIP_OKAY;
1176 }
1177 
1178 /** links temporary solution of primal data to current solution */
1179 static
1181  SCIP_PRIMAL* primal, /**< primal data */
1182  BMS_BLKMEM* blkmem, /**< block memory */
1183  SCIP_SET* set, /**< global SCIP settings */
1184  SCIP_STAT* stat, /**< problem statistics data */
1185  SCIP_PROB* prob, /**< transformed problem data */
1186  SCIP_TREE* tree, /**< branch and bound tree */
1187  SCIP_LP* lp, /**< current LP data */
1188  SCIP_HEUR* heur /**< heuristic that found the solution (or NULL if it's from the tree) */
1189  )
1190 {
1191  assert(primal != NULL);
1192 
1193  if( primal->currentsol == NULL )
1194  {
1195  SCIP_CALL( SCIPsolCreateCurrentSol(&primal->currentsol, blkmem, set, stat, prob, primal, tree, lp, heur) );
1196  }
1197  else
1198  {
1199  SCIP_CALL( SCIPsolLinkCurrentSol(primal->currentsol, set, stat, prob, tree, lp) );
1200  SCIPsolSetHeur(primal->currentsol, heur);
1201  }
1202 
1203  return SCIP_OKAY;
1204 }
1205 
1206 /** adds current LP/pseudo solution to solution storage */
1208  SCIP_PRIMAL* primal, /**< primal data */
1209  BMS_BLKMEM* blkmem, /**< block memory */
1210  SCIP_SET* set, /**< global SCIP settings */
1211  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1212  SCIP_STAT* stat, /**< problem statistics data */
1213  SCIP_PROB* origprob, /**< original problem */
1214  SCIP_PROB* transprob, /**< transformed problem after presolve */
1215  SCIP_TREE* tree, /**< branch and bound tree */
1216  SCIP_LP* lp, /**< current LP data */
1217  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1218  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1219  SCIP_HEUR* heur, /**< heuristic that found the solution (or NULL if it's from the tree) */
1220  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
1221  )
1222 {
1223  assert(primal != NULL);
1224 
1225  /* link temporary solution to current solution */
1226  SCIP_CALL( primalLinkCurrentSol(primal, blkmem, set, stat, transprob, tree, lp, heur) );
1227 
1228  /* add solution to solution storage */
1229  SCIP_CALL( SCIPprimalAddSol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1230  tree, lp, eventqueue, eventfilter, primal->currentsol, stored) );
1231 
1232  return SCIP_OKAY;
1233 }
1234 
1235 /** checks primal solution; if feasible, adds it to storage by copying it */
1237  SCIP_PRIMAL* primal, /**< primal data */
1238  BMS_BLKMEM* blkmem, /**< block memory */
1239  SCIP_SET* set, /**< global SCIP settings */
1240  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1241  SCIP_STAT* stat, /**< problem statistics data */
1242  SCIP_PROB* origprob, /**< original problem */
1243  SCIP_PROB* transprob, /**< transformed problem after presolve */
1244  SCIP_TREE* tree, /**< branch and bound tree */
1245  SCIP_LP* lp, /**< current LP data */
1246  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1247  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1248  SCIP_SOL* sol, /**< primal CIP solution */
1249  SCIP_Bool printreason, /**< should all reasons of violations be printed? */
1250  SCIP_Bool checkbounds, /**< should the bounds of the variables be checked? */
1251  SCIP_Bool checkintegrality, /**< has integrality to be checked? */
1252  SCIP_Bool checklprows, /**< have current LP rows to be checked? */
1253  SCIP_Bool* stored /**< stores whether given solution was feasible and good enough to keep */
1254  )
1255 {
1256  SCIP_Bool feasible;
1257  SCIP_Bool replace;
1258  int insertpos;
1259 
1260  assert(primal != NULL);
1261  assert(set != NULL);
1262  assert(transprob != NULL);
1263  assert(origprob != NULL);
1264  assert(tree != NULL);
1265  assert(sol != NULL);
1266  assert(stored != NULL);
1267 
1268  /* if we want to solve exactly, the constraint handlers cannot rely on the LP's feasibility */
1269  checklprows = checklprows || set->misc_exactsolve;
1270 
1271  insertpos = -1;
1272 
1273  if( solOfInterest(primal, set, stat, origprob, transprob, sol, &insertpos, &replace) )
1274  {
1275  /* check solution for feasibility */
1276  SCIP_CALL( SCIPsolCheck(sol, set, messagehdlr, blkmem, stat, transprob, printreason, checkbounds, checkintegrality, checklprows, &feasible) );
1277  }
1278  else
1279  feasible = FALSE;
1280 
1281  if( feasible )
1282  {
1283  SCIP_SOL* solcopy;
1284 
1285  assert(insertpos >= 0 && insertpos < set->limit_maxsol);
1286 
1287  /* create a copy of the solution */
1288  SCIP_CALL( SCIPsolCopy(&solcopy, blkmem, set, stat, primal, sol) );
1289 
1290  /* insert copied solution into solution storage */
1291  SCIP_CALL( primalAddSol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1292  tree, lp, eventqueue, eventfilter, &solcopy, insertpos, replace) );
1293 
1294  *stored = TRUE;
1295  }
1296  else
1297  *stored = FALSE;
1298 
1299  return SCIP_OKAY;
1300 }
1301 
1302 /** checks primal solution; if feasible, adds it to storage; solution is freed afterwards */
1304  SCIP_PRIMAL* primal, /**< primal data */
1305  BMS_BLKMEM* blkmem, /**< block memory */
1306  SCIP_SET* set, /**< global SCIP settings */
1307  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1308  SCIP_STAT* stat, /**< problem statistics data */
1309  SCIP_PROB* origprob, /**< original problem */
1310  SCIP_PROB* transprob, /**< transformed problem after presolve */
1311  SCIP_TREE* tree, /**< branch and bound tree */
1312  SCIP_LP* lp, /**< current LP data */
1313  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1314  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1315  SCIP_SOL** sol, /**< pointer to primal CIP solution; is cleared in function call */
1316  SCIP_Bool printreason, /**< should all the reasons of violations be printed? */
1317  SCIP_Bool checkbounds, /**< should the bounds of the variables be checked? */
1318  SCIP_Bool checkintegrality, /**< has integrality to be checked? */
1319  SCIP_Bool checklprows, /**< have current LP rows to be checked? */
1320  SCIP_Bool* stored /**< stores whether solution was feasible and good enough to keep */
1321  )
1322 {
1323  SCIP_Bool feasible;
1324  SCIP_Bool replace;
1325  int insertpos;
1326 
1327  assert(primal != NULL);
1328  assert(transprob != NULL);
1329  assert(origprob != NULL);
1330  assert(tree != NULL);
1331  assert(sol != NULL);
1332  assert(*sol != NULL);
1333  assert(stored != NULL);
1334 
1335  *stored = FALSE;
1336 
1337  /* if we want to solve exactly, the constraint handlers cannot rely on the LP's feasibility */
1338  checklprows = checklprows || set->misc_exactsolve;
1339 
1340  insertpos = -1;
1341 
1342  if( solOfInterest(primal, set, stat, origprob, transprob, *sol, &insertpos, &replace) )
1343  {
1344  /* check solution for feasibility */
1345  SCIP_CALL( SCIPsolCheck(*sol, set, messagehdlr, blkmem, stat, transprob, printreason, checkbounds, checkintegrality, checklprows, &feasible) );
1346  }
1347  else
1348  feasible = FALSE;
1349 
1350  if( feasible )
1351  {
1352  assert(insertpos >= 0 && insertpos < set->limit_maxsol);
1353 
1354  /* insert solution into solution storage */
1355  SCIP_CALL( primalAddSol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1356  tree, lp, eventqueue, eventfilter, sol, insertpos, replace) );
1357 
1358  /* clear the pointer, such that the user cannot access the solution anymore */
1359  *sol = NULL;
1360  *stored = TRUE;
1361  }
1362  else
1363  {
1364  /* the solution is too bad or infeasible -> free it immediately */
1365  SCIP_CALL( SCIPsolFree(sol, blkmem, primal) );
1366  *stored = FALSE;
1367  }
1368  assert(*sol == NULL);
1369 
1370  return SCIP_OKAY;
1371 }
1372 
1373 /** checks current LP/pseudo solution; if feasible, adds it to storage */
1375  SCIP_PRIMAL* primal, /**< primal data */
1376  BMS_BLKMEM* blkmem, /**< block memory */
1377  SCIP_SET* set, /**< global SCIP settings */
1378  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1379  SCIP_STAT* stat, /**< problem statistics data */
1380  SCIP_PROB* origprob, /**< original problem */
1381  SCIP_PROB* transprob, /**< transformed problem after presolve */
1382  SCIP_TREE* tree, /**< branch and bound tree */
1383  SCIP_LP* lp, /**< current LP data */
1384  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1385  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1386  SCIP_HEUR* heur, /**< heuristic that found the solution (or NULL if it's from the tree) */
1387  SCIP_Bool printreason, /**< should all reasons of violations be printed? */
1388  SCIP_Bool checkintegrality, /**< has integrality to be checked? */
1389  SCIP_Bool checklprows, /**< have current LP rows to be checked? */
1390  SCIP_Bool* stored /**< stores whether given solution was good enough to keep */
1391  )
1392 {
1393  assert(primal != NULL);
1394 
1395  /* link temporary solution to current solution */
1396  SCIP_CALL( primalLinkCurrentSol(primal, blkmem, set, stat, transprob, tree, lp, heur) );
1397 
1398  /* add solution to solution storage */
1399  SCIP_CALL( SCIPprimalTrySol(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1400  tree, lp, eventqueue, eventfilter, primal->currentsol,
1401  printreason, FALSE, checkintegrality, checklprows, stored) );
1402 
1403  return SCIP_OKAY;
1404 }
1405 
1406 /** inserts solution into the global array of all existing primal solutions */
1408  SCIP_PRIMAL* primal, /**< primal data */
1409  SCIP_SET* set, /**< global SCIP settings */
1410  SCIP_SOL* sol /**< primal CIP solution */
1411  )
1412 {
1413  assert(primal != NULL);
1414  assert(sol != NULL);
1415  assert(SCIPsolGetPrimalIndex(sol) == -1);
1416 
1417  /* allocate memory for solution storage */
1418  SCIP_CALL( ensureExistingsolsSize(primal, set, primal->nexistingsols+1) );
1419 
1420  /* append solution */
1421  SCIPsolSetPrimalIndex(sol, primal->nexistingsols);
1422  primal->existingsols[primal->nexistingsols] = sol;
1423  primal->nexistingsols++;
1424 
1425  return SCIP_OKAY;
1426 }
1427 
1428 /** removes solution from the global array of all existing primal solutions */
1430  SCIP_PRIMAL* primal, /**< primal data */
1431  SCIP_SOL* sol /**< primal CIP solution */
1432  )
1433 {
1434  int idx;
1435 
1436  assert(primal != NULL);
1437  assert(sol != NULL);
1438 
1439 #ifndef NDEBUG
1440  for( idx = 0; idx < primal->nexistingsols; ++idx )
1441  {
1442  assert(idx == SCIPsolGetPrimalIndex(primal->existingsols[idx]));
1443  }
1444 #endif
1445 
1446  /* remove solution */
1447  idx = SCIPsolGetPrimalIndex(sol);
1448  assert(0 <= idx && idx < primal->nexistingsols);
1449  assert(sol == primal->existingsols[idx]);
1450  if( idx < primal->nexistingsols-1 )
1451  {
1452  primal->existingsols[idx] = primal->existingsols[primal->nexistingsols-1];
1453  SCIPsolSetPrimalIndex(primal->existingsols[idx], idx);
1454  }
1455  primal->nexistingsols--;
1456 }
1457 
1458 /** updates all existing primal solutions after a change in a variable's objective value */
1460  SCIP_PRIMAL* primal, /**< primal data */
1461  SCIP_VAR* var, /**< problem variable */
1462  SCIP_Real oldobj, /**< old objective value */
1463  SCIP_Real newobj /**< new objective value */
1464  )
1465 {
1466  int i;
1467 
1468  assert(primal != NULL);
1469 
1470  for( i = 0; i < primal->nexistingsols; ++i )
1471  {
1472  if( !SCIPsolIsOriginal(primal->existingsols[i]) )
1473  SCIPsolUpdateVarObj(primal->existingsols[i], var, oldobj, newobj);
1474  }
1475 }
1476 
1477 /** retransforms all existing solutions to original problem space */
1479  SCIP_PRIMAL* primal, /**< primal data */
1480  SCIP_SET* set, /**< global SCIP settings */
1481  SCIP_STAT* stat, /**< problem statistics data */
1482  SCIP_PROB* origprob, /**< original problem */
1483  SCIP_PROB* transprob /**< transformed problem */
1484  )
1485 {
1486  SCIP_Bool hasinfval;
1487  int i;
1488 
1489  assert(primal != NULL);
1490 
1491  for( i = 0; i < primal->nsols; ++i )
1492  {
1493  if( SCIPsolGetOrigin(primal->sols[i]) == SCIP_SOLORIGIN_ZERO )
1494  {
1495  SCIP_CALL( SCIPsolRetransform(primal->sols[i], set, stat, origprob, transprob, &hasinfval) );
1496  }
1497  }
1498 
1499  return SCIP_OKAY;
1500 }
1501 
1502 /** tries to transform original solution to the transformed problem space */
1504  SCIP_PRIMAL* primal, /**< primal data */
1505  SCIP_SOL* sol, /**< primal solution */
1506  BMS_BLKMEM* blkmem, /**< block memory */
1507  SCIP_SET* set, /**< global SCIP settings */
1508  SCIP_MESSAGEHDLR* messagehdlr, /**< message handler */
1509  SCIP_STAT* stat, /**< problem statistics data */
1510  SCIP_PROB* origprob, /**< original problem */
1511  SCIP_PROB* transprob, /**< transformed problem after presolve */
1512  SCIP_TREE* tree, /**< branch and bound tree */
1513  SCIP_LP* lp, /**< current LP data */
1514  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1515  SCIP_EVENTFILTER* eventfilter, /**< event filter for global (not variable dependent) events */
1516  SCIP_Real* solvals, /**< array for internal use to store solution values, or NULL;
1517  * if the method is called multiple times in a row, an array with size >=
1518  * number of active variables should be given for performance reasons */
1519  SCIP_Bool* solvalset, /**< array for internal use to store which solution values were set, or NULL;
1520  * if the method is called multiple times in a row, an array with size >=
1521  * number of active variables should be given for performance reasons */
1522  int solvalssize, /**< size of solvals and solvalset arrays, should be >= number of active
1523  * variables */
1524  SCIP_Bool* added /**< pointer to store whether the solution was added */
1525  )
1526 {
1527  SCIP_VAR** origvars;
1528  SCIP_VAR** transvars;
1529  SCIP_VAR* var;
1530  SCIP_Real* localsolvals;
1531  SCIP_Bool* localsolvalset;
1532  SCIP_Real solval;
1533  SCIP_Real scalar;
1534  SCIP_Real constant;
1535  SCIP_Bool localarrays;
1536  SCIP_Bool feasible;
1537  int norigvars;
1538  int ntransvars;
1539  int nvarsset;
1540  int v;
1541 
1542  assert(origprob != NULL);
1543  assert(transprob != NULL);
1544  assert(SCIPsolIsOriginal(sol));
1545  assert(solvalssize == 0 || solvals != NULL);
1546  assert(solvalssize == 0 || solvalset != NULL);
1547 
1548  origvars = origprob->vars;
1549  norigvars = origprob->nvars;
1550  transvars = transprob->vars;
1551  ntransvars = transprob->nvars;
1552  assert(solvalssize == 0 || solvalssize >= ntransvars);
1553 
1554  SCIPdebugMessage("try to transfer original solution %p with objective %g into the transformed problem space\n",
1555  (void*)sol, SCIPsolGetOrigObj(sol));
1556 
1557  /* if no solvals and solvalset arrays are given, allocate local ones, otherwise use the given ones */
1558  localarrays = (solvalssize == 0);
1559  if( localarrays )
1560  {
1561  SCIP_CALL( SCIPsetAllocBufferArray(set, &localsolvals, ntransvars) );
1562  SCIP_CALL( SCIPsetAllocBufferArray(set, &localsolvalset, ntransvars) );
1563  }
1564  else
1565  {
1566  localsolvals = solvals;
1567  localsolvalset = solvalset;
1568  }
1569 
1570  BMSclearMemoryArray(localsolvalset, ntransvars);
1571  feasible = TRUE;
1572  (*added) = FALSE;
1573  nvarsset = 0;
1574 
1575  /* for each original variable, get the corresponding active, fixed or multi-aggregated variable;
1576  * if it resolves to an active variable, we set its solution value or check whether an already stored solution value
1577  * is consistent; if it resolves to a fixed variable, we check that the fixing matches the original solution value;
1578  * multi-aggregated variables are skipped, because their value is defined by setting solution values for the active
1579  * variables, anyway
1580  */
1581  for( v = 0; v < norigvars && feasible; ++v )
1582  {
1583  var = origvars[v];
1584 
1585  solval = SCIPsolGetVal(sol, set, stat, var);
1586 
1587  /* get corresponding active, fixed, or multi-aggregated variable */
1588  scalar = 1.0;
1589  constant = 0.0;
1590  SCIP_CALL( SCIPvarGetProbvarSum(&var, set, &scalar, &constant) );
1593 
1594  /* check whether the fixing corresponds to the solution value of the original variable */
1595  if( scalar == 0.0 )
1596  {
1597  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_FIXED ||
1598  (SCIPsetIsInfinity(set, constant) || SCIPsetIsInfinity(set, -constant)));
1599 
1600  if( !SCIPsetIsEQ(set, solval, constant) )
1601  {
1602  SCIPdebugMessage("original variable <%s> (solval=%g) resolves to fixed variable <%s> (original solval=%g)\n",
1603  SCIPvarGetName(origvars[v]), solval, SCIPvarGetName(var), constant);
1604  feasible = FALSE;
1605  }
1606  }
1607  else if( SCIPvarIsActive(var) )
1608  {
1609  /* if we already assigned a solution value to the transformed variable, check that it corresponds to the
1610  * value obtained from the currently regarded original variable
1611  */
1612  if( localsolvalset[SCIPvarGetProbindex(var)] )
1613  {
1614  if( !SCIPsetIsEQ(set, solval, scalar * localsolvals[SCIPvarGetProbindex(var)] + constant) )
1615  {
1616  SCIPdebugMessage("original variable <%s> (solval=%g) resolves to active variable <%s> with assigned solval %g (original solval=%g)\n",
1617  SCIPvarGetName(origvars[v]), solval, SCIPvarGetName(var), localsolvals[SCIPvarGetProbindex(var)],
1618  scalar * localsolvals[SCIPvarGetProbindex(var)] + constant);
1619  feasible = FALSE;
1620  }
1621  }
1622  /* assign solution value to the transformed variable */
1623  else
1624  {
1625  assert(scalar != 0.0);
1626 
1627  localsolvals[SCIPvarGetProbindex(var)] = (solval - constant) / scalar;
1628  localsolvalset[SCIPvarGetProbindex(var)] = TRUE;
1629  ++nvarsset;
1630  }
1631  }
1632 #ifndef NDEBUG
1633  /* we do not have to handle multi-aggregated variables here, since by assigning values to all active variabes,
1634  * we implicitly assign values to the multi-aggregated variables, too
1635  */
1636  else
1637  assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
1638 #endif
1639  }
1640 
1641  /* if the solution values of fixed and active variables lead to no contradiction, construct solution and try it */
1642  if( feasible )
1643  {
1644  SCIP_SOL* transsol;
1645 
1646  SCIP_CALL( SCIPsolCreate(&transsol, blkmem, set, stat, primal, tree, SCIPsolGetHeur(sol)) );
1647 
1648  /* set solution values for variables to which we assigned a value */
1649  for( v = 0; v < ntransvars; ++v )
1650  {
1651  if( localsolvalset[v] )
1652  {
1653  SCIP_CALL( SCIPsolSetVal(transsol, set, stat, tree, transvars[v], localsolvals[v]) );
1654  }
1655  }
1656 
1657  SCIP_CALL( SCIPprimalTrySolFree(primal, blkmem, set, messagehdlr, stat, origprob, transprob,
1658  tree, lp, eventqueue, eventfilter, &transsol, FALSE, TRUE, TRUE, TRUE, added) );
1659 
1660  SCIPdebugMessage("solution transferred, %d/%d active variables set (stored=%u)\n", nvarsset, ntransvars, *added);
1661  }
1662  else
1663  (*added) = FALSE;
1664 
1665  /* free local arrays, if needed */
1666  if( localarrays )
1667  {
1668  SCIPsetFreeBufferArray(set, &localsolvalset);
1669  SCIPsetFreeBufferArray(set, &localsolvals);
1670  }
1671 
1672  return SCIP_OKAY;
1673 }
1674