Scippy

SCIP

Solving Constraint Integer Programs

heur_octane.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 heur_octane.c
17  * @brief octane primal heuristic based on Balas, Ceria, Dawande, Margot, and Pataki
18  * @author Timo Berthold
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <assert.h>
24 #include <string.h>
25 #include <math.h>
26 #include "scip/heur_octane.h"
27 
28 #define HEUR_NAME "octane"
29 #define HEUR_DESC "octane primal heuristic for pure {0;1}-problems based on Balas et al."
30 #define HEUR_DISPCHAR 'O'
31 #define HEUR_PRIORITY -1008000
32 #define HEUR_FREQ -1
33 #define HEUR_FREQOFS 0
34 #define HEUR_MAXDEPTH -1
35 #define HEUR_TIMING SCIP_HEURTIMING_AFTERLPNODE
36 #define HEUR_USESSUBSCIP FALSE /**< does the heuristic use a secondary SCIP instance? */
37 
38 #define DEFAULT_FMAX 100 /**< {0,1}-points to be checked */
39 #define DEFAULT_FFIRST 10 /**< {0,1}-points to be generated at first */
40 #define DEFAULT_USEFRACSPACE TRUE /**< use heuristic for the space of fractional variables or for whole space? */
41 
42 /** primal heuristic data */
43 struct SCIP_HeurData
44 {
45  SCIP_SOL* sol; /**< working solution */
46  int f_max; /**< {0,1}-points to be checked */
47  int f_first; /**< {0,1}-points to be generated at first in order to check whether restart is necessary */
48  int lastrule; /**< last ray selection rule that was performed */
49  SCIP_Bool usefracspace; /**< use heuristic for the space of fractional variables or for the whole space? */
50  SCIP_Bool useobjray; /**< should the inner normal of the objective be used as one ray direction? */
51  SCIP_Bool useavgray; /**< should the average ray of the basic cone be used as one ray direction? */
52  SCIP_Bool usediffray; /**< should difference between root sol and current LP sol be used as one ray direction? */
53  SCIP_Bool useavgwgtray; /**< should the weighted average ray of the basic cone be used as one ray direction? */
54  SCIP_Bool useavgnbray; /**< should the average ray of the nonbasic cone be used as one ray direction? */
55  int nsuccess; /**< number of runs that produced at least one feasible solution */
56 };
57 
58 /*
59  * Local methods
60  */
61 
62 
63 /** tries to insert the facet obtained from facet i flipped in component j into the list of the fmax nearest facets */
64 static
66  SCIP* scip, /**< SCIP data structure */
67  SCIP_Bool** facets, /**< facets got so far */
68  SCIP_Real* lambda, /**< distances of the facets */
69  int i, /**< current facet */
70  int j, /**< component to flip */
71  int f_max, /**< maximal number of facets to create */
72  int nsubspacevars, /**< dimension of the fractional space */
73  SCIP_Real lam, /**< distance of the current facet */
74  int* nfacets /**< number of facets */
75  )
76 {
77  SCIP_Bool* lastfacet;
78  int k;
79 
80  assert(scip != NULL);
81  assert(facets != NULL);
82  assert(lambda != NULL);
83  assert(nfacets != NULL);
84 
85  if( SCIPisFeasLE(scip, lam, 0.0) || SCIPisFeasGE(scip, lam, lambda[f_max-1]) )
86  return;
87 
88  lastfacet = facets[f_max];
89 
90  /* shifting lam through lambda, lambda keeps increasingly sorted */
91  for( k = f_max; k > 0 && SCIPisFeasGT(scip, lambda[k-1], lam); --k )
92  {
93  lambda[k] = lambda[k-1];
94  facets[k] = facets[k-1];
95  }
96  assert(i < k && k < f_max );
97 
98  /* inserting new facet into list, new facet is facet at position i flipped in coordinate j, new distance lam */
99  facets[k] = lastfacet;
100  lambda[k] = lam;
101 
102  /*lint --e{866}*/
103  BMScopyMemoryArray(facets[k], facets[i], nsubspacevars);
104  facets[k][j] = !facets[k][j];
105  (*nfacets)++;
106 }
107 
108 /** constructs a solution from a given facet paying attention to the transformations made at the beginning of OCTANE */
109 static
111  SCIP* scip, /**< SCIP data structure */
112  SCIP_Bool* facet, /**< current facet */
113  SCIP_SOL* sol, /**< solution to create */
114  SCIP_Bool* sign, /**< marker for retransformation */
115  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
116  int nsubspacevars /**< dimension of fractional space */
117  )
118 {
119  int v;
120 
121  assert(scip != NULL);
122  assert(facet != NULL);
123  assert(sol != NULL);
124  assert(sign != NULL);
125  assert(subspacevars != NULL);
126 
127  SCIP_CALL( SCIPlinkLPSol(scip, sol) );
128  for( v = nsubspacevars - 1; v >= 0; --v )
129  {
130  /* after permutation, a variable should be set to 1, iff there was no reflection in this coordinate and the hit
131  * facet has coordinate + or there was a reflection and the facet has coordinate - */
132  if( facet[v] == sign[v] )
133  {
134  SCIP_CALL( SCIPsetSolVal(scip, sol, subspacevars[v], 1.0) );
135  }
136  else
137  {
138  SCIP_CALL( SCIPsetSolVal(scip, sol, subspacevars[v], 0.0) );
139  }
140  }
141 
142  return SCIP_OKAY;
143 }
144 
145 /** generates the direction of the shooting ray as the inner normal of the objective function */
146 static
148  SCIP* scip, /**< SCIP data structure */
149  SCIP_Real* raydirection, /**< shooting ray */
150  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
151  int nsubspacevars /**< dimension of fractional space */
152  )
153 {
154  int v;
155 
156  assert(scip != NULL);
157  assert(raydirection != NULL);
158  assert(subspacevars != NULL);
159 
160  for( v = nsubspacevars - 1; v >= 0; --v )
161  raydirection[v] = SCIPvarGetObj(subspacevars[v]);
162  return SCIP_OKAY;
163 }
164 
165 /** generates the direction of the shooting ray as the difference between the root and the current LP solution */
166 static
168  SCIP* scip, /**< SCIP data structure */
169  SCIP_Real* raydirection, /**< shooting ray */
170  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
171  int nsubspacevars /**< dimension of fractional space */
172  )
173 {
174  int v;
175 
176  assert(scip != NULL);
177  assert(raydirection != NULL);
178  assert(subspacevars != NULL);
179 
180  for( v = nsubspacevars - 1; v >= 0; --v )
181  raydirection[v] = SCIPvarGetLPSol(subspacevars[v]) - SCIPvarGetRootSol(subspacevars[v]);
182 
183  return SCIP_OKAY;
184 }
185 
186 
187 /** generates the direction of the shooting ray as the average of the extreme rays of the basic cone */
188 static
190  SCIP* scip, /**< SCIP data structure */
191  SCIP_Real* raydirection, /**< shooting ray */
192  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
193  int nsubspacevars, /**< dimension of fractional space */
194  SCIP_Bool weighted /**< should the rays be weighted? */
195  )
196 {
197  SCIP_ROW** rows;
198  SCIP_Real** tableaurows;
199  SCIP_Real* rownorm;
200  SCIP_Real rowweight;
201 
202  int nrows;
203  int i;
204  int j;
205 
206  assert(scip != NULL);
207  assert(raydirection != NULL);
208  assert(subspacevars != NULL);
209 
210  /* get data */
211  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
212 
213  /* allocate memory */
214  SCIP_CALL( SCIPallocBufferArray(scip, &tableaurows, nsubspacevars) );
215  for( j = nsubspacevars - 1; j >= 0; --j )
216  {
217  /*lint --e{866}*/
218  SCIP_CALL( SCIPallocBufferArray(scip, &tableaurows[j], nrows) );
219  }
220 
221  SCIP_CALL( SCIPallocBufferArray(scip, &rownorm, nrows) );
222  for( i = nrows - 1; i >= 0; --i )
223  rownorm[i] = 0;
224 
225  /* get the relevant columns of the simplex tableau */
226  for( j = nsubspacevars-1; j >= 0; --j )
227  {
228  assert(SCIPcolGetLPPos(SCIPvarGetCol(subspacevars[j])) >= 0);
229  SCIP_CALL( SCIPgetLPBInvACol(scip, SCIPcolGetLPPos(SCIPvarGetCol(subspacevars[j])), tableaurows[j]) );
230  for( i = nrows - 1; i >= 0; --i )
231  rownorm[i] += tableaurows[j][i] * tableaurows[j][i];
232  }
233 
234  /* take average over all rows of the tableau */
235  for( i = nrows - 1; i >= 0; --i )
236  {
237  if( SCIPisFeasZero(scip, rownorm[i]) )
238  continue;
239  else
240  rownorm[i] = SQRT(rownorm[i]);
241 
242  rowweight = 0.0;
243  if( weighted )
244  {
245  rowweight = SCIProwGetDualsol(rows[i]);
246  if( SCIPisFeasZero(scip, rowweight) )
247  continue;
248  }
249  else
250  rowweight = 1.0;
251 
252  for( j = nsubspacevars - 1; j >= 0; --j )
253  {
254  raydirection[j] += tableaurows[j][i] / (rownorm[i] * rowweight);
255  assert(SCIP_REAL_MIN <= raydirection[j] && raydirection[j] <= SCIP_REAL_MAX);
256  }
257  }
258 
259  /* free memory */
260  SCIPfreeBufferArray(scip, &rownorm);
261  for( j = nsubspacevars - 1; j >= 0; --j )
262  {
263  SCIPfreeBufferArray(scip, &tableaurows[j]);
264  }
265  SCIPfreeBufferArray(scip, &tableaurows);
266 
267  return SCIP_OKAY;
268 }
269 
270 
271 /** generates the direction of the shooting ray as the average of the normalized non-basic vars and rows */
272 static
274  SCIP* scip, /**< SCIP data structure */
275  SCIP_Real* raydirection, /**< shooting ray */
276  int* fracspace, /**< index set of fractional variables */
277  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
278  int nsubspacevars /**< dimension of fractional space */
279  )
280 {
281  SCIP_ROW** rows;
282  SCIP_COL** cols;
283  int nrows;
284  int ncols;
285  int i;
286 
287  assert(scip != NULL);
288  assert(raydirection != NULL);
289  assert(fracspace != NULL);
290  assert(subspacevars != NULL);
291 
292  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
293  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
294 
295  /* add up non-basic variables */
296  for( i = nsubspacevars - 1; i >= 0; --i )
297  {
298  SCIP_Real solval;
299 
300  solval = SCIPvarGetLPSol(subspacevars[i]);
301 
302  if( SCIPisFeasEQ(scip, solval, SCIPvarGetLbLocal(subspacevars[i])) )
303  raydirection[i] = +1.0;
304  else if( SCIPisFeasEQ(scip, solval, SCIPvarGetUbLocal(subspacevars[i])) )
305  raydirection[i] = -1.0;
306  else
307  raydirection[i] = 0.0;
308  }
309 
310  /* add up non-basic rows */
311  for( i = nrows - 1; i >= 0; --i )
312  {
313  SCIP_Real dualsol;
314  SCIP_Real factor;
315  SCIP_Real* coeffs;
316  SCIP_Real rownorm;
317  int j;
318  int nnonz;
319 
320  dualsol = SCIProwGetDualsol(rows[i]);
321  if( SCIPisFeasPositive(scip, dualsol) )
322  factor = 1.0;
323  else if( SCIPisFeasNegative(scip, dualsol) )
324  factor = -1.0;
325  else
326  continue;
327 
328  /* get the row's data */
329  coeffs = SCIProwGetVals(rows[i]);
330  cols = SCIProwGetCols(rows[i]);
331 
332  nnonz = SCIProwGetNNonz(rows[i]);
333 
334  rownorm = 0.0;
335  for( j = nnonz - 1; j >= 0; --j )
336  {
337  SCIP_VAR* var;
338  var = SCIPcolGetVar(cols[j]);
339  if( fracspace[SCIPvarGetProbindex(var)] >= 0 )
340  rownorm += coeffs[j] * coeffs[j];
341  }
342 
343  if( SCIPisFeasZero(scip,rownorm) )
344  continue;
345  else
346  {
347  assert(rownorm > 0);
348  rownorm = SQRT(rownorm);
349  }
350 
351  for( j = nnonz - 1; j >= 0; --j )
352  {
353  SCIP_VAR* var;
354  int f;
355 
356  var = SCIPcolGetVar(cols[j]);
357  f = fracspace[SCIPvarGetProbindex(var)];
358 
359  if( f >= 0 )
360  {
361  raydirection[f] += factor * coeffs[j] / rownorm;
362  assert(SCIP_REAL_MIN <= raydirection[f] && raydirection[f] <= SCIP_REAL_MAX);
363  }
364  }
365  }
366  return SCIP_OKAY;
367 }
368 
369 /** generates the starting point for the shooting ray in original coordinates */
370 static
372  SCIP* scip, /**< SCIP data structure */
373  SCIP_Real* rayorigin, /**< origin of the shooting ray */
374  SCIP_VAR** subspacevars, /**< pointer to fractional space variables */
375  int nsubspacevars /**< dimension of fractional space */
376  )
377 {
378  int v;
379 
380  assert(scip != NULL);
381  assert(rayorigin != NULL);
382  assert(subspacevars != NULL);
383 
384  for( v = nsubspacevars - 1; v >= 0; --v )
385  rayorigin[v] = SCIPvarGetLPSol(subspacevars[v]);
386 
387  return SCIP_OKAY;
388 }
389 
390 /** translates the inner point of the LP to an inner point rayorigin of the unit hyper octahedron and
391  * transforms raydirection and rayorigin by reflections stored in sign
392  */
393 static
395  SCIP_Real* rayorigin, /**< origin of the shooting ray */
396  SCIP_Real* raydirection, /**< direction of the shooting ray */
397  SCIP_Bool* sign, /**< marker for flipped coordinates */
398  int nsubspacevars /**< dimension of fractional space */
399  )
400 {
401  int v;
402 
403  assert(rayorigin != NULL);
404  assert(raydirection != NULL);
405  assert(sign != NULL);
406 
407  for( v = nsubspacevars - 1; v >= 0; --v )
408  {
409  /* if raydirection[v] is negative, flip its sign */
410  if( raydirection[v] < 0 )
411  {
412  sign[v] = FALSE;
413  raydirection[v] *= -1.0;
414  rayorigin[v] *= -1.0; /* flip starting point in the same way like raydirection */
415  }
416  else
417  sign[v] = TRUE;
418  }
419 }
420 
421 /** generates all facets, from which facet i could be obtained by a decreasing + to - flip
422  * or a nonincreasing - to + flip and tests whether they are among the fmax nearest ones
423  */
424 static
426  SCIP* scip, /**< SCIP data structure */
427  SCIP_Bool** facets, /**< facets got so far */
428  SCIP_Real* lambda, /**< distances of the facets */
429  SCIP_Real* rayorigin, /**< origin of the shooting ray */
430  SCIP_Real* raydirection, /**< direction of the shooting ray */
431  SCIP_Real* negquotient, /**< array by which coordinates are sorted */
432  int nsubspacevars, /**< dimension of fractional space */
433  int f_max, /**< maximal number of facets to create */
434  int i, /**< current facet */
435  int* nfacets /**< number of facets */
436  )
437 {
438  SCIP_Real p;
439  SCIP_Real q;
440  SCIP_Real lam;
441  int minplus;
442  int j;
443 
444  assert(scip != NULL);
445  assert(facets != NULL);
446  assert(facets[i] != NULL);
447  assert(lambda != NULL);
448  assert(rayorigin != NULL);
449  assert(raydirection != NULL);
450  assert(negquotient != NULL);
451  assert(nfacets != NULL);
452  assert(0 <= i && i < f_max);
453 
454  /* determine the p and q values of the next facet to fix as a closest one */
455  p = 0.5 * nsubspacevars;
456  q = 0.0;
457  for( j = nsubspacevars - 1; j >= 0; --j )
458  {
459  if( facets[i][j] )
460  {
461  p -= rayorigin[j];
462  q += raydirection[j];
463  }
464  else
465  {
466  p += rayorigin[j];
467  q -= raydirection[j];
468  }
469  }
470 
471  /* get the first + entry of the facet */
472  minplus = -1;
473  for( j = 0; j < nsubspacevars; ++j )
474  {
475  if( facets[i][j] )
476  {
477  minplus = j;
478  break;
479  }
480  }
481 
482  /* facet (- - ... -) cannot be hit, because raydirection >= 0 */
483  assert(minplus >= 0);
484  assert(q != 0.0);
485  assert(SCIPisFeasEQ(scip, lambda[i], p/q));
486  assert(lambda[i] >= 0.0);
487 
488  /* reverse search for facets from which the actual facet can be got by a single, decreasing + to - flip */
489  /* a facet will be inserted into the queue, iff it is one of the fmax closest ones already found */
490  for( j = 0; j < nsubspacevars && !facets[i][j] && SCIPisFeasGT(scip, negquotient[j], lambda[i]); ++j )
491  {
492  if( SCIPisFeasPositive(scip, q + 2*raydirection[j]) )
493  {
494  lam = (p - 2*rayorigin[j]) / (q + 2*raydirection[j]);
495  tryToInsert(scip, facets, lambda, i, j, f_max, nsubspacevars, lam, nfacets);
496  }
497  }
498 
499  /* reverse search for facets from which the actual facet can be got by a single, nonincreasing - to + flip */
500  /* a facet will be inserted into the queue, iff it is one of the fmax closest ones already found */
501  for( j = nsubspacevars - 1; j >= 0 && facets[i][j] && SCIPisFeasLE(scip, negquotient[j], lambda[i]); --j )
502  {
503  if( SCIPisFeasPositive(scip, q - 2*raydirection[j]) )
504  {
505  lam = (p + 2*rayorigin[j]) / (q - 2*raydirection[j]);
506  if( negquotient[minplus] <= lam )
507  tryToInsert(scip, facets, lambda, i, j, f_max, nsubspacevars, lam, nfacets);
508  }
509  }
510 #ifndef NDEBUG
511  for( j = 1; j < f_max; j++)
512  assert(SCIPisFeasGE(scip, lambda[j], lambda[j-1]));
513 #endif
514 }
515 
516 /** tests, whether an array is completely zero */
517 static
519  SCIP* scip, /**< SCIP data structure */
520  SCIP_Real* raydirection, /**< array to be checked */
521  int nsubspacevars /**< size of array */
522  )
523 {
524  int v;
525  SCIP_Bool iszero;
526 
527  assert(scip != NULL);
528  assert(raydirection != NULL);
529  iszero = TRUE;
530  for( v = nsubspacevars - 1; v >= 0; --v )
531  {
532  if( !SCIPisFeasZero(scip, raydirection[v]/100) )
533  iszero = FALSE;
534  else
535  raydirection[v] = 0.0;
536  }
537  return iszero;
538 }
539 
540 
541 /*
542  * Callback methods of primal heuristic
543  */
544 
545 /** copy method for primal heuristic plugins (called when SCIP copies plugins) */
546 static
547 SCIP_DECL_HEURCOPY(heurCopyOctane)
548 { /*lint --e{715}*/
549  assert(scip != NULL);
550  assert(heur != NULL);
551  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
552 
553  /* call inclusion method of primal heuristic */
555 
556  return SCIP_OKAY;
557 }
558 
559 /** destructor of primal heuristic to free user data (called when SCIP is exiting) */
560 static
561 SCIP_DECL_HEURFREE(heurFreeOctane)
562 { /*lint --e{715}*/
563  SCIP_HEURDATA* heurdata;
564 
565  assert(heur != NULL);
566  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
567  assert(scip != NULL);
568 
569  /* free heuristic data */
570  heurdata = SCIPheurGetData(heur);
571  assert(heurdata != NULL);
572  SCIPfreeMemory(scip, &heurdata);
573  SCIPheurSetData(heur, NULL);
574 
575  return SCIP_OKAY;
576 }
577 
578 
579 /** initialization method of primal heuristic (called after problem was transformed) */
580 static
581 SCIP_DECL_HEURINIT(heurInitOctane)
582 { /*lint --e{715}*/
583  SCIP_HEURDATA* heurdata;
584 
585  assert(heur != NULL);
586  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
587 
588  /* get heuristic data */
589  heurdata = SCIPheurGetData(heur);
590  assert(heurdata != NULL);
591 
592  /* create working solution */
593  SCIP_CALL( SCIPcreateSol(scip, &heurdata->sol, heur) );
594 
595  /* initialize data */
596  heurdata->lastrule = 0;
597  heurdata->nsuccess = 0;
598 
599  return SCIP_OKAY;
600 }
601 
602 
603 /** deinitialization method of primal heuristic (called before transformed problem is freed) */
604 
605 static
606 SCIP_DECL_HEUREXIT(heurExitOctane)
607 { /*lint --e{715}*/
608  SCIP_HEURDATA* heurdata;
609 
610  assert(heur != NULL);
611  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
612 
613  /* get heuristic data */
614  heurdata = SCIPheurGetData(heur);
615  assert(heurdata != NULL);
616 
617  /* free working solution */
618  SCIP_CALL( SCIPfreeSol(scip, &heurdata->sol) );
619 
620  return SCIP_OKAY;
621 }
622 
623 
624 /** execution method of primal heuristic */
625 static
626 SCIP_DECL_HEUREXEC(heurExecOctane)
627 { /*lint --e{715}*/
628  SCIP_HEURDATA* heurdata;
629  SCIP_SOL* sol;
630  SCIP_SOL** first_sols; /* stores the first ffirst sols in order to check for common violation of a row */
631 
632  SCIP_VAR** vars; /* the variables of the problem */
633  SCIP_VAR** fracvars; /* variables, that are fractional in current LP solution */
634  SCIP_VAR** subspacevars; /* the variables on which the search is performed. Either coinciding with vars or with the
635  * space of all fractional variables of the current LP solution */
636 
637  SCIP_Real p; /* n/2 - <delta,x> ( for some facet delta ) */
638  SCIP_Real q; /* <delta,a> */
639 
640  SCIP_Real* rayorigin; /* origin of the ray, vector x in paper */
641  SCIP_Real* raydirection; /* direction of the ray, vector a in paper */
642  SCIP_Real* negquotient; /* negated quotient of rayorigin and raydirection, vector v in paper */
643  SCIP_Real* lambda; /* stores the distance of the facets (s.b.) to the origin of the ray */
644 
645  SCIP_Bool usefracspace; /* determines whether the search concentrates on fractional variables and fixes integer ones */
646  SCIP_Bool cons_viol; /* used for checking whether a linear constraint is violated by one of the possible solutions */
647  SCIP_Bool success;
648  SCIP_Bool* sign; /* signature of the direction of the ray */
649  SCIP_Bool** facets; /* list of extended facets */
650 
651  int nvars; /* number of variables */
652  int nbinvars; /* number of 0-1-variables */
653  int nfracvars; /* number of fractional variables in current LP solution */
654  int nsubspacevars; /* dimension of the subspace on which the search is performed */
655  int nfacets; /* number of facets hidden by the ray that where already found */
656  int i; /* counter */
657  int j; /* counter */
658  int f_max; /* {0,1}-points to be checked */
659  int f_first; /* {0,1}-points to be generated at first in order to check whether a restart is necessary */
660  int r; /* counter */
661  int firstrule;
662 
663  int* perm; /* stores the way in which the coordinates were permuted */
664  int* fracspace; /* maps the variables of the subspace to the original variables */
665 
666  assert(heur != NULL);
667  assert(strcmp(SCIPheurGetName(heur), HEUR_NAME) == 0);
668  assert(scip != NULL);
669  assert(result != NULL);
670  assert(SCIPhasCurrentNodeLP(scip));
671 
672  *result = SCIP_DELAYED;
673 
674  /* do not call heuristic of node was already detected to be infeasible */
675  if( nodeinfeasible )
676  return SCIP_OKAY;
677 
678  /* only call heuristic, if an optimal LP solution is at hand */
680  return SCIP_OKAY;
681 
682  /* only call heuristic, if the LP objective value is smaller than the cutoff bound */
683  if( SCIPisGE(scip, SCIPgetLPObjval(scip), SCIPgetCutoffbound(scip)) )
684  return SCIP_OKAY;
685 
686  *result = SCIP_DIDNOTRUN;
687 
688  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, NULL, NULL, NULL) );
689 
690  /* OCTANE is for use in 0-1 programs only */
691  if( nvars != nbinvars )
692  return SCIP_OKAY;
693 
694  /* get heuristic's data */
695  heurdata = SCIPheurGetData(heur);
696  assert( heurdata != NULL );
697 
698  /* don't call heuristic, if it was not successful enough in the past */
699  /*lint --e{647}*/
700  if( SCIPgetNNodes(scip) % (SCIPheurGetNCalls(heur) / (100 * SCIPheurGetNBestSolsFound(heur) + 10*heurdata->nsuccess + 1) + 1) != 0 )
701  return SCIP_OKAY;
702 
703  SCIP_CALL( SCIPgetLPBranchCands(scip, &fracvars, NULL, NULL, &nfracvars, NULL, NULL) );
704 
705  /* don't use integral starting points */
706  if( nfracvars == 0 )
707  return SCIP_OKAY;
708 
709  /* get working pointers from heurdata */
710  sol = heurdata->sol;
711  assert( sol != NULL );
712  f_max = heurdata->f_max;
713  f_first = heurdata->f_first;
714  usefracspace = heurdata->usefracspace;
715 
716  SCIP_CALL( SCIPallocBufferArray(scip, &fracspace, nvars) );
717 
718  /* determine the space one which OCTANE should work either as the whole space or as the space of fractional variables */
719  if( usefracspace )
720  {
721  nsubspacevars = nfracvars;
722  SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) );
723  BMScopyMemoryArray(subspacevars, fracvars, nsubspacevars);
724  for( i = nvars - 1; i >= 0; --i )
725  fracspace[i] = -1;
726  for( i = nsubspacevars - 1; i >= 0; --i )
727  fracspace[SCIPvarGetProbindex(subspacevars[i])] = i;
728  }
729  else
730  {
731  int currentindex;
732 
733  nsubspacevars = nvars;
734  SCIP_CALL( SCIPallocBufferArray(scip, &subspacevars, nsubspacevars) );
735 
736  /* only copy the variables which are in the current LP */
737  currentindex = 0;
738  for( i = 0; i < nvars; ++i )
739  {
740  if( SCIPcolGetLPPos(SCIPvarGetCol(vars[i])) >= 0 )
741  {
742  subspacevars[currentindex] = vars[i];
743  fracspace[i] = currentindex;
744  ++currentindex;
745 
746  }
747  else
748  {
749  fracspace[i] = -1;
750  --nsubspacevars;
751  }
752  }
753  }
754 
755  /* nothing to do for empty search space */
756  if( nsubspacevars == 0 )
757  return SCIP_OKAY;
758 
759  assert(0 < nsubspacevars && nsubspacevars <= nvars);
760 
761  for( i = 0; i < nsubspacevars; i++)
762  assert(fracspace[SCIPvarGetProbindex(subspacevars[i])] == i);
763 
764  /* at most 2^(n-1) facets can be hit */
765  if( nsubspacevars < 30 )
766  {
767  /*lint --e{701}*/
768  assert(f_max > 0);
769  f_max = MIN(f_max, 1 << (nsubspacevars - 1) );
770  }
771 
772  f_first = MIN(f_first, f_max);
773 
774  /* memory allocation */
775  SCIP_CALL( SCIPallocBufferArray(scip, &rayorigin, nsubspacevars) );
776  SCIP_CALL( SCIPallocBufferArray(scip, &raydirection, nsubspacevars) );
777  SCIP_CALL( SCIPallocBufferArray(scip, &negquotient, nsubspacevars) );
778  SCIP_CALL( SCIPallocBufferArray(scip, &sign, nsubspacevars) );
779  SCIP_CALL( SCIPallocBufferArray(scip, &perm, nsubspacevars) );
780  SCIP_CALL( SCIPallocBufferArray(scip, &lambda, f_max + 1) );
781  SCIP_CALL( SCIPallocBufferArray(scip, &facets, f_max + 1) );
782 
783  /* clear raydirection array first for not accidentally using it uninitialized */
784  BMSclearMemoryArray(raydirection, nsubspacevars);
785 
786  for( i = f_max; i >= 0; --i )
787  {
788  /*lint --e{866}*/
789  SCIP_CALL( SCIPallocBufferArray(scip, &facets[i], nsubspacevars) );
790  }
791  SCIP_CALL( SCIPallocBufferArray(scip, &first_sols, f_first) );
792 
793  *result = SCIP_DIDNOTFIND;
794 
795  /* starting OCTANE */
796  SCIPdebugMessage("run Octane heuristic on %s variables, which are %d vars, generate at most %d facets, using rule number %d\n",
797  usefracspace ? "fractional" : "all", nsubspacevars, f_max, (heurdata->lastrule+1)%5);
798 
799  /* generate starting point in original coordinates */
800  SCIP_CALL( generateStartingPoint(scip, rayorigin, subspacevars, nsubspacevars) );
801  for( i = nsubspacevars - 1; i >= 0; --i )
802  rayorigin[i] -= 0.5;
803 
804  firstrule = heurdata->lastrule;
805  ++firstrule;
806  for( r = firstrule; r <= firstrule + 10 && !SCIPisStopped(scip); r++ )
807  {
808  SCIP_ROW** rows;
809  int nrows;
810 
811  /* generate shooting ray in original coordinates by certain rules */
812  switch(r % 5)
813  {
814  case 1:
815  if( heurdata->useavgnbray )
816  {
817  SCIP_CALL( generateAverageNBRay(scip, raydirection, fracspace, subspacevars, nsubspacevars) );
818  }
819  break;
820  case 2:
821  if( heurdata->useobjray )
822  {
823  SCIP_CALL( generateObjectiveRay(scip, raydirection, subspacevars, nsubspacevars) );
824  }
825  break;
826  case 3:
827  if( heurdata->usediffray )
828  {
829  SCIP_CALL( generateDifferenceRay(scip, raydirection, subspacevars, nsubspacevars) );
830  }
831  break;
832  case 4:
833  if( heurdata->useavgwgtray && SCIPisLPSolBasic(scip) )
834  {
835  SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, TRUE) );
836  }
837  break;
838  case 0:
839  if( heurdata->useavgray && SCIPisLPSolBasic(scip) )
840  {
841  SCIP_CALL( generateAverageRay(scip, raydirection, subspacevars, nsubspacevars, FALSE) );
842  }
843  break;
844  default:
845  SCIPerrorMessage("invalid ray rule identifier\n");
846  SCIPABORT();
847  }
848 
849  /* there must be a feasible direction for the shooting ray */
850  if( isZero(scip, raydirection, nsubspacevars) )
851  continue;
852 
853  /* transform coordinates such that raydirection >= 0 */
854  flipCoords(rayorigin, raydirection, sign, nsubspacevars);
855 
856  for( i = f_max - 1; i >= 0; --i)
857  lambda[i] = SCIPinfinity(scip);
858 
859  /* calculate negquotient, initialize perm, facets[0], p, and q */
860  p = 0.5 * nsubspacevars;
861  q = 0.0;
862  for( i = nsubspacevars - 1; i >= 0; --i )
863  {
864  /* calculate negquotient, the ratio of rayorigin and raydirection, paying special attention to the case raydirection[i] == 0 */
865  if( SCIPisFeasZero(scip, raydirection[i]) )
866  {
867  if( rayorigin[i] < 0 )
868  negquotient[i] = SCIPinfinity(scip);
869  else
870  negquotient[i] = -SCIPinfinity(scip);
871  }
872  else
873  negquotient[i] = - (rayorigin[i] / raydirection[i]);
874 
875  perm[i] = i;
876 
877  /* initialization of facets[0] to the all-one facet with p and q its characteristic values */
878  facets[0][i] = TRUE;
879  p -= rayorigin[i];
880  q += raydirection[i];
881  }
882 
883  assert(SCIPisPositive(scip, q));
884 
885  /* resort the coordinates in nonincreasing order of negquotient */
886  SCIPsortDownRealRealRealBoolPtr( negquotient, raydirection, rayorigin, sign, (void**) subspacevars, nsubspacevars);
887 
888 #ifndef NDEBUG
889  for( i = 0; i < nsubspacevars; i++ )
890  assert( raydirection[i] >= 0 );
891  for( i = 1; i < nsubspacevars; i++ )
892  assert( negquotient[i - 1] >= negquotient[i] );
893 #endif
894  /* finished initialization */
895 
896  /* find the first facet of the octahedron hit by a ray shot from rayorigin into direction raydirection */
897  for( i = 0; i < nsubspacevars && negquotient[i] * q > p; ++i )
898  {
899  facets[0][i] = FALSE;
900  p += 2 * rayorigin[i];
901  q -= 2 * raydirection[i];
902  assert(SCIPisPositive(scip, p));
903  assert(SCIPisPositive(scip, q));
904  }
905 
906  /* avoid dividing by values close to 0.0 */
907  if( !SCIPisFeasPositive(scip, q) )
908  continue;
909 
910  /* assert necessary for flexelint */
911  assert(q != 0.0);
912  lambda[0] = p / q;
913 
914  nfacets = 1;
915 
916  /* find the first facets hit by the ray */
917  for( i = 0; i < nfacets && i < f_first; ++i)
918  generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets);
919 
920  /* construct the first ffirst possible solutions */
921  for( i = 0; i < nfacets && i < f_first; ++i )
922  {
923  SCIP_CALL( SCIPcreateSol(scip, &first_sols[i], heur) );
924  SCIP_CALL( getSolFromFacet(scip, facets[i], first_sols[i], sign, subspacevars, nsubspacevars) );
925  assert( first_sols[i] != NULL );
926  }
927 
928  /* try, whether there is a row violated by all of the first ffirst solutions */
929  cons_viol = FALSE;
930  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
931  for( i = nrows - 1; i >= 0; --i )
932  {
933  if( !SCIProwIsLocal(rows[i]) )
934  {
935  SCIP_COL** cols;
936  SCIP_Real constant;
937  SCIP_Real lhs;
938  SCIP_Real rhs;
939  SCIP_Real rowval;
940  SCIP_Real* coeffs;
941  int nnonzerovars;
942  int k;
943 
944  /* get the row's data */
945  constant = SCIProwGetConstant(rows[i]);
946  lhs = SCIProwGetLhs(rows[i]);
947  rhs = SCIProwGetRhs(rows[i]);
948  coeffs = SCIProwGetVals(rows[i]);
949  nnonzerovars = SCIProwGetNNonz(rows[i]);
950  cols = SCIProwGetCols(rows[i]);
951  rowval = constant;
952 
953  for( j = nnonzerovars - 1; j >= 0; --j )
954  rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[0], SCIPcolGetVar(cols[j]));
955 
956  /* if the row's lhs is violated by the first sol, test, whether it is violated by the next ones, too */
957  if( lhs > rowval )
958  {
959  cons_viol = TRUE;
960  for( k = MIN(f_first, nfacets) - 1; k > 0; --k )
961  {
962  rowval = constant;
963  for( j = nnonzerovars - 1; j >= 0; --j )
964  rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j]));
965  if( lhs <= rowval )
966  {
967  cons_viol = FALSE;
968  break;
969  }
970  }
971  }
972  /* dito for the right hand side */
973  else if( rhs < rowval )
974  {
975  cons_viol = TRUE;
976  for( k = MIN(f_first, nfacets) - 1; k > 0; --k )
977  {
978  rowval = constant;
979  for( j = nnonzerovars - 1; j >= 0; --j )
980  rowval += coeffs[j] * SCIPgetSolVal(scip, first_sols[k], SCIPcolGetVar(cols[j]));
981  if( rhs >= rowval )
982  {
983  cons_viol = FALSE;
984  break;
985  }
986  }
987  }
988  /* break as soon as one row is violated by all of the ffirst solutions */
989  if( cons_viol )
990  break;
991  }
992  }
993 
994 
995  if( !cons_viol )
996  {
997  /* if there was no row violated by all solutions, try whether one or more of them are feasible */
998  for( i = MIN(f_first, nfacets) - 1; i >= 0; --i )
999  {
1000  assert(first_sols[i] != NULL);
1001  SCIP_CALL( SCIPtrySol(scip, first_sols[i], FALSE, TRUE, FALSE, TRUE, &success) );
1002  if( success )
1003  *result = SCIP_FOUNDSOL;
1004  }
1005  /* search for further facets and construct and try solutions out of facets fixed as closest ones */
1006  for( i = f_first; i < f_max; ++i)
1007  {
1008  if( i >= nfacets )
1009  break;
1010  generateNeighborFacets(scip, facets, lambda, rayorigin, raydirection, negquotient, nsubspacevars, f_max, i, &nfacets);
1011  SCIP_CALL( getSolFromFacet(scip, facets[i], sol, sign, subspacevars, nsubspacevars) );
1012  SCIP_CALL( SCIPtrySol(scip, sol, FALSE, TRUE, FALSE, TRUE, &success) );
1013  if( success )
1014  *result = SCIP_FOUNDSOL;
1015  }
1016  }
1017 
1018  /* finished OCTANE */
1019  for( i = MIN(f_first, nfacets) - 1; i >= 0; --i )
1020  {
1021  SCIP_CALL( SCIPfreeSol(scip, &first_sols[i]) );
1022  }
1023  }
1024  heurdata->lastrule = r;
1025 
1026  if( *result == SCIP_FOUNDSOL )
1027  ++(heurdata->nsuccess);
1028 
1029  /* free temporary memory */
1030  SCIPfreeBufferArray(scip, &first_sols);
1031  for( i = f_max; i >= 0; --i )
1032  SCIPfreeBufferArray(scip, &facets[i]);
1033  SCIPfreeBufferArray(scip, &facets);
1034  SCIPfreeBufferArray(scip, &lambda);
1035  SCIPfreeBufferArray(scip, &perm);
1036  SCIPfreeBufferArray(scip, &sign);
1037  SCIPfreeBufferArray(scip, &negquotient);
1038  SCIPfreeBufferArray(scip, &raydirection);
1039  SCIPfreeBufferArray(scip, &rayorigin);
1040  SCIPfreeBufferArray(scip, &subspacevars);
1041  SCIPfreeBufferArray(scip, &fracspace);
1042 
1043  return SCIP_OKAY;
1044 }
1045 
1046 
1047 /*
1048  * primal heuristic specific interface methods
1049  */
1050 
1051 /** creates the octane primal heuristic and includes it in SCIP */
1053  SCIP* scip /**< SCIP data structure */
1054  )
1055 {
1056  SCIP_HEURDATA* heurdata;
1057  SCIP_HEUR* heur;
1058 
1059  /* create Octane primal heuristic data */
1060  SCIP_CALL( SCIPallocMemory(scip, &heurdata) );
1061 
1062  /* include primal heuristic */
1063  SCIP_CALL( SCIPincludeHeurBasic(scip, &heur,
1065  HEUR_MAXDEPTH, HEUR_TIMING, HEUR_USESSUBSCIP, heurExecOctane, heurdata) );
1066 
1067  assert(heur != NULL);
1068 
1069  /* set non-NULL pointers to callback methods */
1070  SCIP_CALL( SCIPsetHeurCopy(scip, heur, heurCopyOctane) );
1071  SCIP_CALL( SCIPsetHeurFree(scip, heur, heurFreeOctane) );
1072  SCIP_CALL( SCIPsetHeurInit(scip, heur, heurInitOctane) );
1073  SCIP_CALL( SCIPsetHeurExit(scip, heur, heurExitOctane) );
1074 
1075  /* add octane primal heuristic parameters */
1076  SCIP_CALL( SCIPaddIntParam(scip,
1077  "heuristics/octane/fmax",
1078  "number of 0-1-points to be tested as possible solutions by OCTANE",
1079  &heurdata->f_max, TRUE, DEFAULT_FMAX, 1, INT_MAX, NULL, NULL) );
1080 
1081  SCIP_CALL( SCIPaddIntParam(scip,
1082  "heuristics/octane/ffirst",
1083  "number of 0-1-points to be tested at first whether they violate a common row",
1084  &heurdata->f_first, TRUE, DEFAULT_FFIRST, 1, INT_MAX, NULL, NULL) );
1085 
1087  "heuristics/octane/usefracspace",
1088  "execute OCTANE only in the space of fractional variables (TRUE) or in the full space?",
1089  &heurdata->usefracspace, TRUE, DEFAULT_USEFRACSPACE, NULL, NULL) );
1090 
1092  "heuristics/octane/useobjray",
1093  "should the inner normal of the objective be used as one ray direction?",
1094  &heurdata->useobjray, TRUE, TRUE, NULL, NULL) );
1095 
1097  "heuristics/octane/useavgray",
1098  "should the average of the basic cone be used as one ray direction?",
1099  &heurdata->useavgray, TRUE, TRUE, NULL, NULL) );
1100 
1102  "heuristics/octane/usediffray",
1103  "should the difference between the root solution and the current LP solution be used as one ray direction?",
1104  &heurdata->usediffray, TRUE, FALSE, NULL, NULL) );
1105 
1107  "heuristics/octane/useavgwgtray",
1108  "should the weighted average of the basic cone be used as one ray direction?",
1109  &heurdata->useavgwgtray, TRUE, TRUE, NULL, NULL) );
1110 
1112  "heuristics/octane/useavgnbray",
1113  "should the weighted average of the nonbasic cone be used as one ray direction?",
1114  &heurdata->useavgnbray, TRUE, TRUE, NULL, NULL) );
1115 
1116  return SCIP_OKAY;
1117 }
1118