Scippy

GCG

Branch-and-Price & Column Generation for Everyone

solver_cliquer.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program */
4 /* GCG --- Generic Column Generation */
5 /* a Dantzig-Wolfe decomposition based extension */
6 /* of the branch-cut-and-price framework */
7 /* SCIP --- Solving Constraint Integer Programs */
8 /* */
9 /* Copyright (C) 2010-2021 Operations Research, RWTH Aachen University */
10 /* Zuse Institute Berlin (ZIB) */
11 /* */
12 /* This program is free software; you can redistribute it and/or */
13 /* modify it under the terms of the GNU Lesser General Public License */
14 /* as published by the Free Software Foundation; either version 3 */
15 /* of the License, or (at your option) any later version. */
16 /* */
17 /* This program is distributed in the hope that it will be useful, */
18 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
19 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
20 /* GNU Lesser General Public License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with this program; if not, write to the Free Software */
24 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
25 /* */
26 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27 
28 /**@file solver_cliquer.c
29  * @brief heuristic solver for pricing problems that solves independent set problems with cliquer
30  * @author Henri Lotze
31  * @author Christian Puchert
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include <assert.h>
37 
38 #include "solver_cliquer.h"
39 #include "scip/cons_linear.h"
40 #include "scip/cons_varbound.h"
41 #include "pub_solver.h"
42 #include "pricer_gcg.h"
43 #include "relax_gcg.h"
44 #include "pub_gcgcol.h"
45 #include "pub_gcgvar.h"
46 
47 #include "cliquer/cliquer.h"
48 
49 
50 #define SOLVER_NAME "cliquer"
51 #define SOLVER_DESC "heuristic solver for pricing problems that solves independent set problems with cliquer"
52 #define SOLVER_PRIORITY 150
53 
54 #define SOLVER_HEURENABLED TRUE /**< indicates whether the solver should be enabled */
55 #define SOLVER_EXACTENABLED FALSE /**< indicates whether the solver should be enabled */
56 
57 #define DEFAULT_DENSITY 0.00
58 
60 {
61  SCIP_Real density; /**< graph density threshold above which to use solver */
62 };
63 
64 
65 /*
66  * Local methods
67  */
68 
69 /** Returns whether the given var is linked in some way with other variables */
70 static
71 SCIP_Bool isVarLinked(
72  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
73  int nlinkedvars, /**< Index of linkedvars array */
74  SCIP_VAR* var /**< Variable whose membership in the linkedvars array is to be checked */
75  )
76 {
77  SCIP_Bool islinked;
78  int i;
79 
80  islinked = FALSE;
81  for( i = 0; i < nlinkedvars; ++i )
82  {
83  if( linkedvars[i] == var )
84  {
85  islinked = TRUE;
86  }
87  }
88  return islinked;
89 }
90 
91 /** Returns whether 2 variables are linked, either simply or in a transitive way in respect to a given linkmatrix matrix.
92  * Use of the wrapper function areVarsLinked(..) is recommended
93  */
94 static
95 SCIP_Bool areVarsLinkedRec(
96  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
97  int vindex1, /**< Problem index of the first variable in the pair that is to be checked */
98  int vindex2, /**< Problem index of the second variable in the pair that is to be checked */
99  int* vartrace, /**< Array to keep track of which nodes have already been visited during recursion */
100  int traceindex, /**< Index to keep track of the number of visited nodes during recursion */
101  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
102  int nlinkedvars /**< Index of linkedvars array */
103  )
104 {
105  SCIP_Bool varintrace;
106  int i,j;
107 
108  varintrace = FALSE;
109  /* Simple, direct link? (Matrix is symmetric) */
110  if( linkmatrix[vindex1][vindex2] )
111  {
112  return TRUE;
113  }
114  /* More complex link by transitivity? */
115  else
116  {
117  for( i = 0; i < nlinkedvars; ++i )
118  {
119  if( linkmatrix[vindex1][SCIPvarGetProbindex(linkedvars[i])] )
120  {
121  /* To ensure termination, we have to keep track of the visited vars */
122  for( j = 0; j < traceindex; ++j )
123  {
124  if( vartrace[j] == SCIPvarGetProbindex(linkedvars[i]) )
125  {
126  varintrace = TRUE;
127  }
128  }
129  if( !varintrace )
130  {
131  vartrace[traceindex] = vindex1;
132  ++traceindex;
133  return areVarsLinkedRec(linkmatrix,SCIPvarGetProbindex(linkedvars[i]),vindex2,vartrace,traceindex,linkedvars,nlinkedvars);
134  }
135  }
136  }
137  }
138  return FALSE;
139 }
140 
141 /** Wrapper function for areVarsLinkedRec, mallocs and cleans up the necessary memory and passes through the result */
142 static
143 SCIP_Bool areVarsLinked(
144  SCIP* scip, /**< The problem instance */
145  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
146  SCIP_VAR* var1, /**< The first variable in the pair that is to be checked */
147  SCIP_VAR* var2, /**< The second variable in the pair that is to be checked */
148  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
149  int nlinkedvars /**< Index of linkedvars array */
150  )
151 {
152  int* vartrace;
153  int traceindex;
154  int i;
155  int vindex1;
156  int vindex2;
157  SCIP_Bool varslinked;
158 
159  vindex1 = SCIPvarGetProbindex(var1);
160  vindex2 = SCIPvarGetProbindex(var2);
161 
162  /* We can save effort if a direct link is present */
163  if( linkmatrix[vindex1][vindex2] )
164  {
165  return TRUE;
166  }
167 
168  SCIP_CALL( SCIPallocBufferArray(scip,&vartrace,nlinkedvars) );
169  traceindex = 0;
170  for( i = 0; i < nlinkedvars; ++i )
171  {
172  vartrace[i] = -1;
173  }
174 
175  varslinked = areVarsLinkedRec(linkmatrix,vindex1,vindex2,vartrace,traceindex,linkedvars,nlinkedvars);
176 
177  SCIPfreeBufferArray(scip,&vartrace);
178 
179  return varslinked;
180 }
181 
182 /** Update transitivity in the linkmatrix matrix between 2 variables that are to be linked and all linked variables */
183 static
185  SCIP* scip, /**< The Problem instance */
186  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
187  SCIP_VAR* var1, /**< The first variable in the pair that is to be checked */
188  SCIP_VAR* var2, /**< The second variable in the pair that is to be checked */
189  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
190  int* nlinkedvars /**< Index of linkedvars array */
191  )
192 {
193  int varindex1,varindex2;
194  int i;
195  SCIP_Bool newvar1;
196  SCIP_Bool newvar2;
197 
198  newvar1 = TRUE;
199  newvar2 = TRUE;
200 
201  /* Check if the variables are part of a link already, add them elsewise to the linkedvars array */
202  for( i = 0; i < *nlinkedvars; ++i )
203  {
204  if( linkedvars[i] == var1 )
205  {
206  newvar1 = FALSE;
207  }
208  else if( linkedvars[i] == var2 )
209  {
210  newvar2 = FALSE;
211  }
212  }
213  if( newvar1 )
214  {
215  linkedvars[*nlinkedvars] = var1;
216  ++(*nlinkedvars);
217  }
218  if( newvar2 )
219  {
220  linkedvars[*nlinkedvars] = var2;
221  ++(*nlinkedvars);
222  }
223 
224  varindex1 = SCIPvarGetProbindex(var1);
225  varindex2 = SCIPvarGetProbindex(var2);
226 
227  /* Variables may have not been simply linked before */
228  linkmatrix[varindex1][varindex2] = 1;
229  linkmatrix[varindex2][varindex1] = 1;
230 
231  for( i = 0; i < *nlinkedvars; ++i )
232  {
233  /* It is sufficient to check the links between var1 and all other vars, since var1 and var2 are linked */
234  if( varindex1 != SCIPvarGetProbindex(linkedvars[i]) )
235  {
236  if( areVarsLinked(scip,linkmatrix,var1,linkedvars[i],linkedvars,*nlinkedvars) )
237  {
238  /* Add links to both var1 and var2 */
239  linkmatrix[varindex1][SCIPvarGetProbindex(linkedvars[i])] = 1;
240  linkmatrix[SCIPvarGetProbindex(linkedvars[i])][varindex1] = 1;
241  linkmatrix[varindex2][SCIPvarGetProbindex(linkedvars[i])] = 1;
242  linkmatrix[SCIPvarGetProbindex(linkedvars[i])][varindex2] = 1;
243  }
244  }
245  }
246 }
247 
248 /** Get the node index of a given variable in the bijection if mapped, else return -1 */
249 static
251  SCIP_VAR* var, /**< Variable for which the node index is to be determined */
252  SCIP_VAR** indsetvars, /**< Array of variables that are mapped to a node of the graph */
253  int indexcount /**< Number of variables that are mapped in the graph */
254  )
255 {
256  for( int i = 0; i < indexcount; ++i )
257  {
258  if( var == indsetvars[i] )
259  {
260  return i;
261  }
262  }
263  return -1;
264 }
265 
266 /** Returns the node index of a given variable in the bijection or that of a linked variable, if any. */
267 static
269  SCIP* scip, /**< The problem instance */
270  SCIP_VAR* var, /**< Variable for which the node index is to be determined */
271  SCIP_VAR** indsetvars, /**< Array of variables that are mapped to a node of the graph */
272  int indexcount, /**< Number of variables that are mapped in the graph */
273  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
274  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
275  int nlinkedvars /**< Index of linkedvars array */
276  )
277 {
278  int nodeindex;
279  int i;
280 
281  nodeindex = getNodeIndex(var,indsetvars,indexcount);
282  if( nodeindex == -1 && isVarLinked(linkedvars,nlinkedvars,var) )
283  {
284  for( i = 0; i < nlinkedvars; ++i )
285  {
286  if( linkedvars[i] != var )
287  {
288  if( areVarsLinked(scip,linkmatrix,var,linkedvars[i],linkedvars,nlinkedvars) )
289  {
290  nodeindex = getNodeIndex(linkedvars[i],indsetvars,indexcount);
291  if( nodeindex != -1 )
292  {
293  return nodeindex;
294  }
295  }
296  }
297  }
298  }
299  else
300  {
301  return nodeindex;
302  }
303  return -1;
304 }
305 
306 /** Add a variable to the bijection graph g and indsetvars array. Returns the index of the corresponding node in the graph. */
307 static
309  SCIP* scip, /**< The problem instance */
310  graph_t* g, /**< Graph into which to insert the new variable as a node */
311  SCIP_VAR* consvar, /**< The variable that is to be assigned a node in the graph */
312  int* indexcount, /**< Pointer to Index of the next unassigned node in the graph */
313  SCIP_Real scalingfactor, /**< Factor for scaling the weight of newly mapped nodes */
314  SCIP_VAR** indsetvars, /**< Array that keeps track of variables that are part of the graph */
315  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
316  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
317  int nlinkedvars /**< Index of linkedvars array */
318  )
319 {
320  int nodeindex;
321  if( isVarLinked(linkedvars,nlinkedvars,consvar) )
322  {
323  nodeindex = getLinkedNodeIndex(scip,consvar,indsetvars,*indexcount,linkmatrix,linkedvars,nlinkedvars);
324  }
325  else
326  {
327  nodeindex = getNodeIndex(consvar,indsetvars,*indexcount);
328  }
329  if( nodeindex == -1 )
330  {
331  /* Var not yet part of graph, add it with its corresponding weight */
332  indsetvars[*indexcount] = consvar;
333  if( !(SCIPvarGetObj(indsetvars[*indexcount]) > 0) )
334  {
335  g->weights[*indexcount] = 1 + abs((int) (scalingfactor * SCIPvarGetObj(indsetvars[*indexcount])));
336  }
337  else
338  {
339  g->weights[*indexcount] = 1;
340  }
341  nodeindex = *indexcount;
342  ++(*indexcount);
343  }
344  return nodeindex;
345 }
346 
347 /** Set the solvals of a variable and of all its linked variables, if any */
348 static
350  SCIP* scip, /**< The problem instance */
351  SCIP_Real* solvals, /**< Array holding the current solution values of all variables of the problem */
352  int** linkmatrix, /**< Matrix indicating which variables are linked by a node */
353  SCIP_VAR** linkedvars, /**< Array of variables that are linked by eq-constraints */
354  int nlinkedvars, /**< Index of linkedvars array */
355  SCIP_VAR* var, /**< Var that may be linked that itself should be set to the value val */
356  SCIP_Real val /**< Value to which all linked vars are supposed to be set to */
357  )
358 {
359  int i;
360 
361  solvals[SCIPvarGetProbindex(var)] = val;
362 
363  for( i = 0; i < nlinkedvars; ++i )
364  {
365  if( var != linkedvars[i] )
366  {
367  if( areVarsLinked(scip,linkmatrix,var,linkedvars[i],linkedvars,nlinkedvars) )
368  {
369  solvals[SCIPvarGetProbindex(linkedvars[i])] = val;
370  }
371  }
372  }
373 }
374 
375 /** Check if the objective coefficients of the variables are already Integral */
376 static
378  SCIP* scip /**< The problem instance */
379  )
380 {
381  SCIP_Real objval;
382  SCIP_Real nvars;
383  SCIP_VAR** vars;
384  int i;
385 
386  nvars = SCIPgetNVars(scip);
387  vars = SCIPgetVars(scip);
388 
389  for( i = 0; i < nvars; ++i )
390  {
391  objval = SCIPvarGetObj(vars[i]);
392  if( !SCIPisZero(scip,objval-((int)objval)) )
393  {
394  return FALSE;
395  }
396  }
397  return TRUE;
398 }
399 
400 /** Scale the objective coefficients of the variables maximally s.t. they become integral and the sum of values does not exceed INT_MAX */
401 static
403  SCIP* scip /**< The problem instance */
404  )
405 {
406  SCIP_Real scalingfactor;
407  SCIP_Real varval;
408  SCIP_Real biggestobj;
409  SCIP_Real nvars;
410  SCIP_VAR** vars;
411  int i;
412 
413  nvars = SCIPgetNVars(scip);
414  vars = SCIPgetVars(scip);
415 
416  scalingfactor = (INT_MAX / nvars) - nvars;
417 
418  /* Check for the biggest objective value to safely adjust the scalingfactor */
419  biggestobj = 0.0;
420  for( i = 0; i < nvars; ++i )
421  {
422  varval = SCIPvarGetObj(vars[i]);
423  if( SCIPisLT(scip,varval,biggestobj) )
424  {
425  biggestobj = varval;
426  }
427  }
428  if( SCIPisLT(scip,biggestobj,-1.0) )
429  {
430  /* Ensure that INT_MAX is never reached by the sum of all scaled weights */
431  scalingfactor = fabs(scalingfactor / biggestobj);
432  }
433  return scalingfactor;
434 }
435 
436 /* Basic idea of the heuristic solver: The biggest independent set in a graph corresponds to the biggest clique
437  * of the complement graph, for which we use the cliquer library to find it. We therefore transform the variables
438  * into graph nodes and delete the edge between two nodes if there is an independent set constraint involving both.
439  * By doing this, they cannot both be part of the maximum clique and thus not be both part of the independent set.
440  * The correspondence between variables and graph nodes is done by a bijection using the indsetvars array:
441  * The variable indsetvars[i] is the i-th node of the graph, indexcount keeps track of the next unmapped graph node.
442  * There is also the possibility that two variables x and y are linked with an equality constraint x-y = 0 due to
443  * Ryan-Foster-Branching. In this case, all linked variables are mapped to the same node. There are functions
444  * to get the corresponding node index.
445  *
446  * Since we want to add a column with the best reduced cost, we take the objective coefficient of variables into
447  * account by giving their graph nodes corresponding weights and searching for a weight-maximal clique.
448  *
449  * If you would like to add the handling of more types of constraints, please note that the current code
450  * assumes that at no point edges are added to the graph, except during initialisation.
451  *
452  * This solver is currently able to handle the following type of constraints:
453  * IS-Constraints, i.e. c*x + d*y <= 1*e
454  * Coupling-Constraints, i.e. v + w + x -c*y <= 0
455  * Clique-Constraints, i.e. v + w + x + y <= 1
456  * Same-Constraints, i.e. x - y = 0 for varbound-constraints.
457  * Vbd-constraints of type x - c*y <= 0 for c <= -1
458  */
459 
460 /** Solve the pricing problem as an independent set problem, in an approximate way. */
461 static
462 SCIP_RETCODE solveCliquer(
463  SCIP_Bool exactly, /**< should the pricing problem be solved to optimality or heuristically? */
464  SCIP* scip, /**< master problem SCIP data structure */
465  SCIP* pricingprob, /**< pricing problem SCIP data structure */
466  GCG_SOLVERDATA* solver, /**< solver data structure */
467  int probnr, /**< problem number */
468  SCIP_Real* lowerbound, /**< pointer to store lower bound */
469  GCG_PRICINGSTATUS* status /**< pointer to store pricing problem status */
470  )
471 { /*lint -e715 */
472  SCIP_CONS** constraints;
473  SCIP_CONS** markedconstraints;
474  SCIP_CONSHDLR* conshdlr;
475  SCIP_VAR** lconsvars;
476  SCIP_VAR** vconsvars;
477  SCIP_VAR** indsetvars;
478  SCIP_VAR** pricingprobvars;
479  SCIP_VAR** linkedvars;
480  SCIP_Real* solvals;
481  SCIP_Real* consvals;
482  SCIP_Real scalingfactor;
483  SCIP_Bool retcode;
484  set_t clique;
485  graph_t* g;
486  clique_options cl_opts;
487  int** linkmatrix;
488  int nlinkedvars;
489  int npricingprobvars;
490  int nvars;
491  int nconss;
492  int nedges;
493  int markedcount;
494  int indexcount;
495  int nodeindex0;
496  int nodeindex1;
497  int coefindex;
498  GCG_COL* col;
499 
500  int i;
501  int j;
502  int k;
503 
504  assert(scip != NULL);
505  assert(pricingprob != NULL);
506  assert(solver != NULL);
507  assert(lowerbound != NULL);
508  assert(status != NULL);
509 
510  pricingprobvars = SCIPgetVars(pricingprob);
511  npricingprobvars = SCIPgetNVars(pricingprob);
512 
513  constraints = SCIPgetConss(pricingprob);
514  nconss = SCIPgetNConss(pricingprob);
515 
516  /* All variables of the problem are expected to be binary */
517  if( SCIPgetNBinVars(pricingprob) < npricingprobvars )
518  {
519  SCIPdebugMessage("Exit: Nonbinary variables.\n");
521  return SCIP_OKAY;
522  }
523 
524  /* Cliquer library explicitly demands the node weights to be positive integers.
525  * Additionally, the sum of node weights needs to be smaller than INT_MAX.
526  * We restrict our scaling factor to always honor this constraint.
527  */
528  if( !areObjectivesIntegral(pricingprob) )
529  {
530  scalingfactor = scaleRelativeToMax(pricingprob);
531  }
532  else
533  {
534  scalingfactor = 1.0;
535  }
536 
537  SCIP_CALL( SCIPallocBufferArray(pricingprob,&markedconstraints,nconss) );
538  SCIP_CALL( SCIPallocBufferArray(pricingprob,&indsetvars,npricingprobvars) );
539  SCIP_CALL( SCIPallocBufferArray(pricingprob,&solvals,npricingprobvars) );
540  SCIP_CALL( SCIPallocBufferArray(pricingprob,&vconsvars,2) );
541  SCIP_CALL( SCIPallocBufferArray(pricingprob,&linkedvars,npricingprobvars) );
542  SCIP_CALL( SCIPallocBufferArray(pricingprob,&linkmatrix,npricingprobvars) );
543  for( i = 0; i < npricingprobvars; ++i )
544  {
545  SCIP_CALL( SCIPallocBufferArray(pricingprob,&linkmatrix[i],npricingprobvars) );
546  }
547 
548  /* Used to keep track of node indizes for bijection while building the graph */
549  indexcount = 0;
550 
551  /* Use to handle a rare combination of IS and varbound constraints */
552  markedcount = 0;
553 
554  /* Used to keep track of the index of the linkedvars array */
555  nlinkedvars = 0;
556 
557  /* Build complementary graph by first creating a complete graph and then deleting edges of IS constraints. */
558  /* Size is first chosen to be maximal and then later cropped down to the actual number of nodes. */
559  /* Initialize the linkmatrix array. */
560  /* Initialize the solvals array. */
561  g = graph_new(npricingprobvars);
562  for( i = 0; i < npricingprobvars; ++i )
563  {
564  for( j = 0; j < npricingprobvars; ++j )
565  {
566  if( i != j )
567  {
568  GRAPH_ADD_EDGE(g,i,j);
569  }
570  linkmatrix[i][j] = 0;
571  }
572  solvals[i] = -1.0; /* To later determine whether a variable was constrained */
573  }
574 
575  /* Check for "same"-constraints present in Ryan-Foster-Branching and save the links between the variables. */
576  for( i = 0; i < nconss; ++i )
577  {
578  assert(constraints[i] != NULL);
579  conshdlr = SCIPconsGetHdlr(constraints[i]);
580  assert(conshdlr != NULL);
581  if( strcmp(SCIPconshdlrGetName(conshdlr), "varbound") == 0 )
582  {
583  /* Varbound constraint of type x + cy == rhs */
584  if( SCIPisEQ(pricingprob, SCIPgetLhsVarbound(pricingprob,constraints[i]), SCIPgetRhsVarbound(pricingprob,constraints[i])) )
585  {
586  /* c == -1, thus variables have to become both 0 or both 1 */
587  if( (SCIPgetRhsVarbound(pricingprob,constraints[i]) == 0) && (SCIPgetVbdcoefVarbound(pricingprob,constraints[i]) == -1) )
588  {
589  vconsvars[0] = SCIPgetVarVarbound(pricingprob,constraints[i]);
590  vconsvars[1] = SCIPgetVbdvarVarbound(pricingprob,constraints[i]);
591  updateVarLinks(pricingprob,linkmatrix,vconsvars[0],vconsvars[1],linkedvars,&nlinkedvars);
592  /* Since the vars may not be part of the graph, we have to be able to set their solval later, thus we save the constraint */
593  markedconstraints[markedcount] = constraints[i];
594  ++markedcount;
595  }
596  }
597  }
598  }
599 
600  /* All links have to be established first before we can add nodes to the graph, else pairs (a,b) and (c,d) would be mapped to different nodes */
601  /* if link (b,c) is present but later in the list. We have to run through the constraints again as the linked variables need to be assigned to nodes */
602  /* in order for the rest of the logic to work out (node indizes are fetched during runtime) */
603  for( i = 0; i < markedcount; ++i )
604  {
605  /* Varbound constraint of type x + cy == rhs */
606  if( SCIPisEQ(pricingprob, SCIPgetLhsVarbound(pricingprob,markedconstraints[i]), SCIPgetRhsVarbound(pricingprob,markedconstraints[i])) )
607  {
608  /* c == -1, thus variables have to become both 0 or both 1 */
609  if( (SCIPgetRhsVarbound(pricingprob,markedconstraints[i]) == 0) && (SCIPgetVbdcoefVarbound(pricingprob,markedconstraints[i]) == -1) )
610  {
611  vconsvars[0] = SCIPgetVarVarbound(pricingprob,markedconstraints[i]);
612  nodeindex0 = addVarToGraph(pricingprob,g,vconsvars[0],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
613  }
614  }
615  }
616 
617  /* Main loop to check the nature of each constraint */
618  for( i = 0; i < nconss; ++i )
619  {
620  assert(constraints[i] != NULL);
621  conshdlr = SCIPconsGetHdlr(constraints[i]);
622  assert(conshdlr != NULL);
623 
624  /* The constraint may not be of type 'linear' */
625  if( strcmp(SCIPconshdlrGetName(conshdlr),"linear") == 0 )
626  {
627  lconsvars = SCIPgetVarsLinear(pricingprob,constraints[i]);
628  consvals = SCIPgetValsLinear(pricingprob,constraints[i]);
629  if( !SCIPisEQ(pricingprob,SCIPgetLhsLinear(pricingprob,constraints[i]),SCIPgetRhsLinear(pricingprob,constraints[i])) )
630  {
631  /* Check if we have an IS constraint */
632  if( SCIPgetNVarsLinear(pricingprob,constraints[i]) == 2 &&
633  SCIPisEQ(pricingprob,SCIPgetRhsLinear(pricingprob,constraints[i]),1) )
634  {
635  /* Preprocessing: Constraint is only relevant for pricing if one of the variables has an objective value < 0 */
636  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[0]),0) || SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[1]),0)
637  || (getLinkedNodeIndex(pricingprob,lconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1 &&
638  getLinkedNodeIndex(pricingprob,lconsvars[1],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1) )
639  {
640  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[0]),0) )
641  {
642  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[0],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
643  }
644  else
645  {
646  nodeindex0 = getLinkedNodeIndex(pricingprob,lconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
647  }
648 
649  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[1]),0) )
650  {
651  nodeindex1 = addVarToGraph(pricingprob,g,lconsvars[1],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
652  }
653  else
654  {
655  nodeindex1 = getLinkedNodeIndex(pricingprob,lconsvars[1],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
656  }
657 
658  if( nodeindex0 >= 0 && nodeindex1 >= 0 )
659  {
660  if( GRAPH_IS_EDGE(g,nodeindex0,nodeindex1) )
661  {
662  GRAPH_DEL_EDGE(g,nodeindex0,nodeindex1);
663  }
664  else if( nodeindex0 == nodeindex1 )
665  {
666  /* nodeindex0 and nodeindex1 are linked, thus calling the setter for one is sufficient */
667  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,lconsvars[0],0.0);
668  }
669  }
670  }
671  }
672  /* Handle other constraints that behave like IS constraints, i.e. cx+dy<=rhs with c+d>rhs, c>0, d>0 */
673  else if( SCIPgetNVarsLinear(pricingprob,constraints[i]) == 2 && consvals[0] > 0 && consvals[1] > 0
674  && SCIPisLT(pricingprob, SCIPgetRhsLinear(pricingprob,constraints[i]),consvals[0] + consvals[1])
675  && !SCIPisLT(pricingprob, SCIPgetRhsLinear(pricingprob,constraints[i]),consvals[0])
676  && !SCIPisLT(pricingprob, SCIPgetRhsLinear(pricingprob,constraints[i]),consvals[1]))
677  {
678  /* As before, the constraint is only regarded if it is relevant for pricing */
679  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[0]),0) )
680  {
681  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[0],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
682  }
683  else
684  {
685  nodeindex0 = getLinkedNodeIndex(pricingprob,lconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
686  }
687 
688  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[1]),0) )
689  {
690  nodeindex1 = addVarToGraph(pricingprob,g,lconsvars[1],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
691  }
692  else
693  {
694  nodeindex1 = getLinkedNodeIndex(pricingprob,lconsvars[1],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
695  }
696  if( nodeindex0 >= 0 && nodeindex1 >= 0 )
697  {
698  if( GRAPH_IS_EDGE(g,nodeindex0,nodeindex1) )
699  {
700  GRAPH_DEL_EDGE(g,nodeindex0,nodeindex1);
701  }
702  else if( nodeindex0 == nodeindex1 )
703  {
704  /* nodeindex0 and nodeindex1 are linked, thus calling the setter for one is sufficient */
705  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,lconsvars[0],0.0);
706  }
707  }
708  }
709  else
710  {
711  /* The current constraint is no linear IS constraint */
712  SCIPgetConsNVars(pricingprob,constraints[i],&nvars,&retcode);
713  coefindex = -1;
714 
715  /* Check the coefficients of the variables in the constraint */
716  for( j = 0; j < nvars; ++j )
717  {
718  if( consvals[j] != 1 && (coefindex == -1) )
719  {
720  coefindex = j;
721  }
722  else if( consvals[j] != 1 && coefindex != -1 )
723  {
724  /* More than one variable has a coefficient unequal to 1 */
725  SCIPdebugMessage("Exit: More than one coefficient unequal 1.\n");
727  goto TERMINATE;
728  }
729  }
730  /* Check if we have a clique constraint (rhs 1 and coefficients 1) */
731  if( !(coefindex == -1) && SCIPisEQ(pricingprob,SCIPgetRhsLinear(pricingprob,constraints[i]),1) )
732  {
733  /* Delete the edges between all the variables of the constraint.
734  This way, at most one can be part of the maximum clique */
735  for( j = 0; j < nvars; ++j )
736  {
737  /* We are only interested in vars potentially relevant for pricing (obj < 0) */
738  if( SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[j]),0) || getLinkedNodeIndex(pricingprob,lconsvars[j],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1 )
739  {
740  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[j],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
741 
742  for( k = j + 1; k < nvars; ++k )
743  {
744  if( (SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[k]),0)
745  || getLinkedNodeIndex(pricingprob,lconsvars[k],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1))
746  {
747  nodeindex1 = addVarToGraph(pricingprob,g,lconsvars[k],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
748 
749  if( nodeindex0 != nodeindex1 )
750  {
751  if( GRAPH_IS_EDGE(g,nodeindex0,nodeindex1) )
752  {
753  GRAPH_DEL_EDGE(g,nodeindex0,nodeindex1);
754  }
755  }
756  }
757  }
758  }
759  }
760  }
761  /* Check if we have a coupling constraint (rhs 0) */
762  else if( !(coefindex == -1) && SCIPisEQ(pricingprob,SCIPgetRhsLinear(pricingprob,constraints[i]), 0.0) )
763  {
764  /* Special case: The coupling constraint is purely decorative (coefficient + 1 of coupling var >= #vars)*/
765  if( abs(consvals[coefindex]) + 1 >= nvars )
766  {
767  /* We cannot guarantee that there is no constraint of the form x+CouplingVar <= 1 */
768  /* If the node is part of the maximum clique, it is safe to set it to one, so we simply add it to the graph */
769  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[coefindex],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
770 
771  /* We additionally have to mark the variable to later set it to one */
772  solvals[SCIPvarGetProbindex(lconsvars[coefindex])] = -2.0;
773  }
774  /* Special case: The coefficient is -1, we treat the case like a clique constraint. */
775  else if( abs(consvals[coefindex]) == 1 )
776  {
777  /* We cannot guarantee that there is no constraint of the form x+CouplingVar <= 1 */
778  /* If the node is part of the maximum clique, it is safe to set it to one, so we simply add it to the graph */
779  /* We additionally have to mark the variable to later set it to one */
780  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[coefindex],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
781 
782  /* We additionally have to mark the variable to later set it to one */
783  solvals[SCIPvarGetProbindex(lconsvars[coefindex])] = -2.0;
784 
785  /* Delete the edges between all the variables of the constraint that are not the coupling variable.
786  This way, at most one can be part of the maximum clique */
787  for( j = 0; j < nvars; ++j )
788  {
789  /* We are only interested in vars potentially relevant for pricing (obj < 0) */
790  if( j != coefindex && (SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[j]),0)
791  || getLinkedNodeIndex(pricingprob,lconsvars[j],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1) )
792  {
793  /* Determine nodeindex0 */
794  nodeindex0 = addVarToGraph(pricingprob,g,lconsvars[j],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
795  /* Determine nodeindex1 */
796  for( k = j + 1; k < nvars; ++k )
797  {
798  if( k != coefindex && (SCIPisLT(pricingprob,SCIPvarGetObj(lconsvars[k]),0)
799  || getLinkedNodeIndex(pricingprob,lconsvars[k],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1))
800  {
801  nodeindex1 = addVarToGraph(pricingprob,g,lconsvars[k],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
802  if( nodeindex0 != nodeindex1 )
803  {
804  if( GRAPH_IS_EDGE(g,nodeindex0,nodeindex1) )
805  {
806  GRAPH_DEL_EDGE(g,nodeindex0,nodeindex1);
807  }
808  }
809  }
810  }
811  }
812  }
813  }
814  else
815  {
816  /* Coupling coefficient is between 1 and npricingprobvars. */
817  SCIPdebugMessage("Exit: Coupling coefficient unhandled, coef: %g.\n",consvals[coefindex]);
819  goto TERMINATE;
820  }
821  }
822  else
823  {
824  /* Constraint is neither a coupling nor a clique constraint */
825  SCIPdebugMessage("Exit: Unhandled linear constraint.\n");
827  goto TERMINATE;
828  }
829  }
830  }
831  else
832  {
833  /* Constraint is a linear equality constraint */
834  SCIPdebugMessage("Exit: Unhandled linear constraint: Equality constraint.\n");
836  goto TERMINATE;
837  }
838  }
839  /* Constraint may be of type varbound: lhs <= x + c*y <= rhs */
840  else if( strcmp(SCIPconshdlrGetName(conshdlr), "varbound") == 0 )
841  {
842  vconsvars[0] = SCIPgetVarVarbound(pricingprob,constraints[i]);
843  vconsvars[1] = SCIPgetVbdvarVarbound(pricingprob,constraints[i]);
844  /* Check value of rhs to be 0 and of c to be <= -1 */
845  if ( SCIPisInfinity(pricingprob, -SCIPgetLhsVarbound(pricingprob,constraints[i])) )
846  {
847  if( SCIPisEQ(pricingprob,SCIPgetRhsVarbound(pricingprob,constraints[i]),0) )
848  {
849  if( SCIPisLT(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,constraints[i]),-1) || SCIPisEQ(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,constraints[i]),-1) )
850  {
851  /* if x may be relevant, add both x and y to graph */
852  if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[0]),0) || getLinkedNodeIndex(pricingprob,vconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1 )
853  {
854  nodeindex0 = addVarToGraph(pricingprob,g,vconsvars[0],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
855  nodeindex1 = addVarToGraph(pricingprob,g,vconsvars[1],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
856  /* It may be the case, that both the constraints x - y <= 0 and x + y <= 1 are part of the problem */
857  /* Although rare, we later ensure that we do not set x to 1 while y is set to 0 */
858  markedconstraints[markedcount] = constraints[i];
859  ++markedcount;
860  }
861  /* If only y may be relevant, add only y to the graph */
862  else if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[1]),0) )
863  {
864  if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[1]),0) )
865  {
866  nodeindex1 = addVarToGraph(pricingprob,g,vconsvars[1],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
867  }
868  }
869  /* If none of the nodes are relevant, force x to be zero, since the constraint would be violated if x = 1 and y = 0 */
870  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,vconsvars[0],0.0);
871  }
872  else
873  {
874  /* Coefficient c of varbound is > -1 and we do not have an IS constraint*/
875  SCIPdebugMessage("Exit: Coefficient of Varbound unhandled Rhs: %g, Coeff: %g.\n",SCIPgetRhsVarbound(pricingprob,constraints[i]),SCIPgetVbdcoefVarbound(pricingprob,constraints[i]));
877  goto TERMINATE;
878  }
879  }
880  /* Rhs of varbound unequal to 0.
881  * It may still be the case that we have an IS constraint with a non-linear handler.
882  * The constraint may also be of the form c + 1 > rhs and c < rhs, i.e. a non-standard IS-constraint.
883  * We treat these cases like a regular IS constraint.
884  */
885  else if( (SCIPisEQ(pricingprob,SCIPgetRhsVarbound(pricingprob,constraints[i]),1) && SCIPisEQ(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,constraints[i]),1))
886  || (SCIPisLT(pricingprob,SCIPgetRhsVarbound(pricingprob,constraints[i]),SCIPgetVbdcoefVarbound(pricingprob,constraints[i]) + 1)
887  && SCIPisLT(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,constraints[i]), SCIPgetRhsVarbound(pricingprob,constraints[i]))) )
888  {
889  /* Preprocessing: Constraint is only relevant for pricing if one of the variables has an objective value < 0 */
890  if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[0]),0) || SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[1]),0)
891  || (getLinkedNodeIndex(pricingprob,vconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1 &&
892  getLinkedNodeIndex(pricingprob,vconsvars[1],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars) != -1) )
893  {
894  if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[0]),0) )
895  {
896  nodeindex0 = addVarToGraph(pricingprob,g,vconsvars[0],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
897  }
898  else
899  {
900  nodeindex0 = getLinkedNodeIndex(pricingprob,vconsvars[0],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
901  }
902 
903  if( SCIPisLT(pricingprob,SCIPvarGetObj(vconsvars[1]),0) )
904  {
905  nodeindex1 = addVarToGraph(pricingprob,g,vconsvars[1],&indexcount,scalingfactor,indsetvars,linkmatrix,linkedvars,nlinkedvars);
906  }
907  else
908  {
909  nodeindex1 = getLinkedNodeIndex(pricingprob,vconsvars[1],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
910  }
911 
912  if( nodeindex0 >= 0 && nodeindex1 >= 0 )
913  {
914  if( GRAPH_IS_EDGE(g,nodeindex0,nodeindex1) )
915  {
916  GRAPH_DEL_EDGE(g,nodeindex0,nodeindex1);
917  }
918  else if( nodeindex0 == nodeindex1 )
919  {
920  /* nodeindex0 and nodeindex1 are linked, thus calling the setter for one is sufficient */
921  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,vconsvars[0],0.0);
922  }
923  }
924  }
925  }
926  else
927  {
928  /* Rhs of varbound unequal to 0 and no IS constraint*/
929  SCIPdebugMessage("Exit: Rhs of Varbound unhandled, Rhs: %g, Coeff:%g.\n",SCIPgetRhsVarbound(pricingprob,constraints[i]),SCIPgetVbdcoefVarbound(pricingprob,constraints[i]));
931  goto TERMINATE;
932  }
933  }
934  /* We may have a varbound constraint of type x + cy == rhs */
935  else if( SCIPisEQ(pricingprob, SCIPgetLhsVarbound(pricingprob,constraints[i]), SCIPgetRhsVarbound(pricingprob,constraints[i])) )
936  {
937  /* If the rhs is 0 and c == -1, both variables have to be set to 0 or to 1 */
938  if( !((SCIPgetRhsVarbound(pricingprob,constraints[i]) == 0) && (SCIPgetVbdcoefVarbound(pricingprob,constraints[i]) == -1)) )
939  {
940  /* RHS is unequal 0 and unequal 1 */
941  SCIPdebugMessage("Exit: Unhandled equality constraint, c: %g, rhs: %g.\n", SCIPgetVbdcoefVarbound(pricingprob,constraints[i]), SCIPgetRhsVarbound(pricingprob,constraints[i]));
943  goto TERMINATE;
944  }
945  }
946  else
947  {
948  /* We have a varbound of type lhs <= x + c*y */
949  SCIPdebugMessage("Exit: Varbound of type lhs <= x+c*y, c: %g, rhs: %g.\n", SCIPgetVbdcoefVarbound(pricingprob,constraints[i]), SCIPgetRhsVarbound(pricingprob,constraints[i]));
950  SCIPdebugMessage("Constraint handler: %s\n", SCIPconshdlrGetName(conshdlr));
952  goto TERMINATE;
953  }
954  }
955  else
956  {
957  /* Constraint handler neither linear nor varbound */
958  SCIPdebugMessage("Exit: Unhandled constraint handler: %s \n", SCIPconshdlrGetName(conshdlr));
960  goto TERMINATE;
961  }
962  }
963 
964 
965  /* Assert that the graph was built in a proper way */
966  ASSERT(graph_test(g,NULL));
967 
968  /* Determine number of edges for graph density calculation */
969  nedges = 0;
970  for ( i = 0; i < g->n; i++ )
971  {
972  for ( j = 0; j < g->n; j++ )
973  {
974  if( SET_CONTAINS_FAST(g->edges[i],j) )
975  {
976  nedges++;
977  }
978  }
979  }
980  nedges /= 2;
981 
982  /* Test if the density criteria is met */
983  if( SCIPisLT(pricingprob, (float)nedges/((float)(g->n - 1) * (g->n) / 2), solver->density) )
984  {
985  SCIPdebugMessage("Exit: Density criteria not met,density: %g.\n",(float)nedges / ((float)(g->n - 1) * (g->n) / 2));
987  goto TERMINATE;
988  }
989 
990  SCIPdebugMessage("Graph size: %d.\n", indexcount);
991  ASSERT( indexcount <= npricingprobvars );
992 
993  /* indexcount now holds the actual number of unique IS variables, thus we truncate the graph */
994  if( indexcount > 0 )
995  {
996  graph_resize(g,indexcount);
997  }
998 
999  /* Clean up the graph. If a variable's solval has been set to 0, it should not be part of the max clique */
1000  /* We enforce this by isolating the node and setting its weight to 1 as nodes cannot be deleted */
1001  for( i = 0; i < npricingprobvars; ++i )
1002  {
1003  if( solvals[SCIPvarGetProbindex(pricingprobvars[i])] == 0 )
1004  {
1005  nodeindex0 = getLinkedNodeIndex(pricingprob,pricingprobvars[i],indsetvars,indexcount,linkmatrix,linkedvars,nlinkedvars);
1006  /* The var is part of the graph if its index is unequal to -1 */
1007  if( nodeindex0 != -1 )
1008  {
1009  for( j = 0; j < indexcount; ++j )
1010  {
1011  if( GRAPH_IS_EDGE(g,nodeindex0,j) )
1012  {
1013  GRAPH_DEL_EDGE(g,nodeindex0,j);
1014  }
1015  }
1016  g->weights[nodeindex0] = 1;
1017  }
1018  }
1019  }
1020 
1021  /* Set cliquer options */
1022  cl_opts.reorder_function = reorder_by_default; /* default: reorder_by_default */
1023  cl_opts.reorder_map = NULL;
1024  cl_opts.time_function = NULL; /* default: clique_print_time */
1025  cl_opts.output = NULL;
1026  cl_opts.user_function = NULL;
1027  cl_opts.user_data = NULL;
1028  cl_opts.clique_list = NULL;
1029  cl_opts.clique_list_length = 0;
1030 
1031  /* Find maximum weight clique using the cliquer library */
1032  clique = clique_find_single(g,0,0,FALSE,&cl_opts);
1033 
1034  /* Set all members of the maximum clique with objective coefficient < 0 to 1 */
1035  for( i = 0; i < indexcount; ++i )
1036  {
1037  /* Coupling variables were pre-set to -2.0, if they are part of the maximum clique, we enable them.
1038  * If we have already set a variable to 0, this was intended and should not be reverted.
1039  */
1040  if( SET_CONTAINS(clique,i) && (SCIPisLT(pricingprob,SCIPvarGetObj(indsetvars[i]),0) || solvals[SCIPvarGetProbindex(indsetvars[i])] == -2.0)
1041  && solvals[SCIPvarGetProbindex(indsetvars[i])] != 0.0 )
1042  {
1043  /* Set all linked variables, if any */
1044  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,indsetvars[i],1.0);
1045  }
1046  else
1047  {
1048  /* We may have set some variables manually already, e.g. coupling variables */
1049  if( solvals[SCIPvarGetProbindex(indsetvars[i])] != 1.0)
1050  {
1051  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,indsetvars[i],0.0);
1052  }
1053  }
1054  }
1055 
1056  for( i = 0; i < markedcount; ++i )
1057  {
1058  vconsvars[0] = SCIPgetVarVarbound(pricingprob,markedconstraints[i]);
1059  vconsvars[1] = SCIPgetVbdvarVarbound(pricingprob,markedconstraints[i]);
1060 
1061  /* Handle the case of marked inequality constraints of type x - y <= 0 in combination with x + y <= 1 -Constraints */
1062  if( SCIPisEQ(pricingprob,SCIPgetRhsVarbound(pricingprob,markedconstraints[i]),0)
1063  && (SCIPisLT(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,markedconstraints[i]),-1)
1064  || SCIPisEQ(pricingprob,SCIPgetVbdcoefVarbound(pricingprob,markedconstraints[i]),-1)) )
1065  {
1066  /* Check if a violating assignment was made and correct it */
1067  if( (solvals[SCIPvarGetProbindex(vconsvars[0])] == 1) && (solvals[SCIPvarGetProbindex(vconsvars[1])] == 0) )
1068  {
1069  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,vconsvars[0],0.0);
1070  }
1071  }
1072 
1073  /* Handle the case that there are still solvals of equality constraints that do not agree.
1074  * This may occur if one is unset (solval:-1) and the other one is already set (solval 0 or 1)
1075  */
1076  if( solvals[SCIPvarGetProbindex(vconsvars[0])] != solvals[SCIPvarGetProbindex(vconsvars[1])]
1077  && SCIPisEQ(pricingprob, SCIPgetLhsVarbound(pricingprob,markedconstraints[i]), SCIPgetRhsVarbound(pricingprob,markedconstraints[i])) )
1078  {
1079  if( solvals[SCIPvarGetProbindex(vconsvars[0])] == 0 || solvals[SCIPvarGetProbindex(vconsvars[1])] == 0 )
1080  {
1081  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,vconsvars[0],0.0);
1082  }
1083  else
1084  {
1085  /* One or both of the vars are unset and the other one, if not -1, is forced to be 1, thus we can set both to 1 */
1086  setLinkedSolvals(pricingprob,solvals,linkmatrix,linkedvars,nlinkedvars,vconsvars[0],1.0);
1087  }
1088  }
1089  }
1090 
1091  /* There may be variables left which are unconstrained. We set these to 1 manually if they have an objective value < 0*/
1092  for( i = 0; i < npricingprobvars; ++i )
1093  {
1094  if( solvals[i] == -1.0 )
1095  {
1096  if( SCIPisLT(pricingprob,SCIPvarGetObj(pricingprobvars[i]),0) )
1097  {
1098  solvals[i] = 1.0;
1099  }
1100  else
1101  {
1102  solvals[i] = 0.0;
1103  }
1104  }
1105  }
1106 
1107  /* Create a column corresponding to our clique result */
1108  SCIP_CALL( GCGcreateGcgCol(pricingprob, &col, probnr, pricingprobvars, solvals, npricingprobvars, FALSE, SCIPinfinity(pricingprob)) );
1109  SCIP_CALL( GCGpricerAddCol(scip, col) );
1110  *status = GCG_PRICINGSTATUS_UNKNOWN;
1111  set_free(clique); /* clique can only be freed if non-empty */
1112 
1113  TERMINATE:
1114  for( i = 0; i < npricingprobvars; ++i )
1115  {
1116  SCIPfreeBufferArray(pricingprob,&linkmatrix[i]);
1117  }
1118  SCIPfreeBufferArray(pricingprob,&linkmatrix);
1119  SCIPfreeBufferArray(pricingprob,&linkedvars);
1120  SCIPfreeBufferArray(pricingprob,&vconsvars);
1121  SCIPfreeBufferArray(pricingprob,&solvals);
1122  SCIPfreeBufferArray(pricingprob,&indsetvars);
1123  SCIPfreeBufferArray(pricingprob,&markedconstraints);
1124  graph_free(g);
1125 
1126  return SCIP_OKAY;
1127 }
1128 
1129 /*
1130  * Callback methods for pricing problem solver
1131  */
1132 
1133 /** destructor of pricing solver to free user data (called when SCIP is exiting) */
1134 static
1135 GCG_DECL_SOLVERFREE(solverFreeCliquer)
1136 {
1137  GCG_SOLVERDATA* solverdata;
1138 
1139  assert(scip != NULL);
1140  assert(solver != NULL);
1141 
1142  solverdata = GCGsolverGetData(solver);
1143  assert(solverdata != NULL);
1144 
1145  SCIPfreeMemory(scip, &solverdata);
1146 
1147  GCGsolverSetData(solver, NULL);
1148 
1149  return SCIP_OKAY;
1150 }
1151 
1152 #define solverInitsolCliquer NULL
1153 #define solverExitsolCliquer NULL
1154 #define solverInitCliquer NULL
1155 #define solverExitCliquer NULL
1156 #define solverUpdateCliquer NULL
1157 #define solverSolveCliquer NULL
1158 
1159 /** heuristic solving method of independent set solver */
1160 static
1161 GCG_DECL_SOLVERSOLVEHEUR(solverSolveHeurCliquer)
1162 { /*lint --e{715}*/
1163  GCG_SOLVERDATA* solverdata;
1164 
1165  solverdata = GCGsolverGetData(solver);
1166  assert(solverdata != NULL);
1167 
1168  /* solve the independent set problem approximately */
1169  SCIP_CALL( solveCliquer(FALSE, scip, pricingprob, solverdata, probnr, lowerbound, status) );
1170 
1171  return SCIP_OKAY;
1172 }
1173 
1174 /** creates the cliquer solver for pricing problems and includes it in GCG */
1176  SCIP* scip /**< SCIP data structure */
1177  )
1178 {
1179  SCIP* origprob;
1180  GCG_SOLVERDATA* solverdata;
1181 
1182  origprob = GCGmasterGetOrigprob(scip);
1183  assert(origprob != NULL);
1184 
1185  SCIP_CALL( SCIPallocMemory(scip, &solverdata) );
1186 
1189  solverUpdateCliquer, solverSolveCliquer, solverSolveHeurCliquer,
1190  solverFreeCliquer, solverInitCliquer, solverExitCliquer,
1192 
1193  SCIP_CALL( SCIPaddRealParam(origprob, "pricingsolver/cliquer/density",
1194  "graph density threshold above which to use solver",
1195  &solverdata->density, TRUE, DEFAULT_DENSITY, 0.0, 1.0, NULL, NULL) );
1196 
1197  return SCIP_OKAY;
1198 }
static int addVarToGraph(SCIP *scip, graph_t *g, SCIP_VAR *consvar, int *indexcount, SCIP_Real scalingfactor, SCIP_VAR **indsetvars, int **linkmatrix, SCIP_VAR **linkedvars, int nlinkedvars)
SCIP_RETCODE GCGcreateGcgCol(SCIP *pricingprob, GCG_COL **gcgcol, int probnr, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Bool isray, SCIP_Real redcost)
Definition: gcgcol.c:52
#define SOLVER_PRIORITY
#define solverInitCliquer
static GCG_DECL_SOLVERSOLVEHEUR(solverSolveHeurCliquer)
#define SOLVER_EXACTENABLED
static SCIP_Real scaleRelativeToMax(SCIP *scip)
#define solverSolveCliquer
static int getLinkedNodeIndex(SCIP *scip, SCIP_VAR *var, SCIP_VAR **indsetvars, int indexcount, int **linkmatrix, SCIP_VAR **linkedvars, int nlinkedvars)
SCIP_EXPORT void GCGsolverSetData(GCG_SOLVER *solver, GCG_SOLVERDATA *solverdata)
Definition: solver.c:387
heuristic solver for pricing problems that solves independent set problems with cliquer
public methods for working with gcg columns
SCIP_Real density
static SCIP_Bool areObjectivesIntegral(SCIP *scip)
#define SOLVER_DESC
GCG variable pricer.
static SCIP_Bool isVarLinked(SCIP_VAR **linkedvars, int nlinkedvars, SCIP_VAR *var)
enum GCG_PricingStatus GCG_PRICINGSTATUS
@ GCG_PRICINGSTATUS_NOTAPPLICABLE
#define solverExitsolCliquer
#define DEFAULT_DENSITY
static void setLinkedSolvals(SCIP *scip, SCIP_Real *solvals, int **linkmatrix, SCIP_VAR **linkedvars, int nlinkedvars, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE GCGincludeSolverCliquer(SCIP *scip)
SCIP_EXPORT GCG_SOLVERDATA * GCGsolverGetData(GCG_SOLVER *solver)
Definition: solver.c:377
static GCG_DECL_SOLVERFREE(solverFreeCliquer)
static SCIP_Bool areVarsLinked(SCIP *scip, int **linkmatrix, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_VAR **linkedvars, int nlinkedvars)
SCIP_RETCODE GCGpricerIncludeSolver(SCIP *scip, const char *name, const char *desc, int priority, SCIP_Bool heurenabled, SCIP_Bool exactenabled, GCG_DECL_SOLVERUPDATE((*solverupdate)), GCG_DECL_SOLVERSOLVE((*solversolve)), GCG_DECL_SOLVERSOLVEHEUR((*solversolveheur)), GCG_DECL_SOLVERFREE((*solverfree)), GCG_DECL_SOLVERINIT((*solverinit)), GCG_DECL_SOLVEREXIT((*solverexit)), GCG_DECL_SOLVERINITSOL((*solverinitsol)), GCG_DECL_SOLVEREXITSOL((*solverexitsol)), GCG_SOLVERDATA *solverdata)
SCIP * GCGmasterGetOrigprob(SCIP *scip)
#define SOLVER_HEURENABLED
GCG relaxator.
#define solverExitCliquer
@ GCG_PRICINGSTATUS_UNKNOWN
#define solverInitsolCliquer
SCIP_RETCODE GCGpricerAddCol(SCIP *scip, GCG_COL *col)
#define SOLVER_NAME
public methods for GCG variables
static SCIP_Bool areVarsLinkedRec(int **linkmatrix, int vindex1, int vindex2, int *vartrace, int traceindex, SCIP_VAR **linkedvars, int nlinkedvars)
static SCIP_RETCODE solveCliquer(SCIP_Bool exactly, SCIP *scip, SCIP *pricingprob, GCG_SOLVERDATA *solver, int probnr, SCIP_Real *lowerbound, GCG_PRICINGSTATUS *status)
static void updateVarLinks(SCIP *scip, int **linkmatrix, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_VAR **linkedvars, int *nlinkedvars)
static int getNodeIndex(SCIP_VAR *var, SCIP_VAR **indsetvars, int indexcount)
#define solverUpdateCliquer