SCIP-SDP  2.1.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
branch_sdpinfobjective.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of SCIPSDP - a solving framework for mixed-integer */
4 /* semidefinite programms based on SCIP. */
5 /* */
6 /* Copyright (C) 2011-2013 Discrete Optimization, TU Darmstadt */
7 /* EDOM, FAU Erlangen-Nürnberg */
8 /* 2014-2016 Discrete Optimization, TU Darmstadt */
9 /* */
10 /* */
11 /* This program is free software; you can redistribute it and/or */
12 /* modify it under the terms of the GNU Lesser General Public License */
13 /* as published by the Free Software Foundation; either version 3 */
14 /* of the License, or (at your option) any later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
18 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
19 /* GNU Lesser General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with this program; if not, write to the Free Software */
23 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
24 /* */
25 /* */
26 /* Based on SCIP - Solving Constraint Integer Programs */
27 /* Copyright (C) 2002-2016 Zuse Institute Berlin */
28 /* SCIP is distributed under the terms of the SCIP Academic Licence, */
29 /* see file COPYING in the SCIP distribution. */
30 /* */
31 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 
40 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
41 
42 /* #define SCIP_DEBUG */
43 
44 #include <assert.h>
45 #include <string.h>
46 
47 #include "branch_sdpinfobjective.h"
48 
49 /* turn off lint warnings for whole file: */
50 /*lint --e{788,818}*/
51 
52 #define BRANCHRULE_NAME "sdpinfobjective"
53 #define BRANCHRULE_DESC "branch on variable with highest product of fractionality/integral-infeasibility and absolute objective of the SDP"
54 #define BRANCHRULE_PRIORITY 2000000
55 #define BRANCHRULE_MAXDEPTH -1
56 #define BRANCHRULE_MAXBOUNDDIST 1.0
57 #define DEFAULT_COUPLEDVARS FALSE
59 #define DEFAULT_SINGLECOUPLEDVARS FALSE
63 struct SCIP_BranchruleData
64 {
65  SCIP_Bool coupledvars;
67  SCIP_Bool singlecoupledvars;
69 };
70 
71 
72 /*
73  * Data structures
74  */
75 
76 /*
77  * Local methods
78  */
79 
80 /* put your local methods here, and declare them static */
81 
82 
83 /*
84  * Callback methods of branching rule
85  */
86 
88 static
89 SCIP_DECL_BRANCHCOPY(branchCopySdpinfobjective)
90 { /*lint --e{715}*/
91  assert(scip != NULL);
92  assert(branchrule != NULL);
93  assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
94 
95  /* call inclusion method of branchrule */
96  SCIP_CALL( SCIPincludeBranchruleSdpinfobjective(scip) );
97 
98  return SCIP_OKAY;
99 }
100 
102 static
103 SCIP_DECL_BRANCHEXECEXT(branchExecextSdpinfobjective)
104 {/*lint --e{715}*/
105  SCIP_BRANCHRULEDATA* branchruledata;
106  SCIP_VAR** cands = NULL;
107  SCIP_Real* candssol; /* solution values of all candidates */
108  SCIP_Real* candsscore; /* scores of all candidates */
109  SCIP_VAR* maxtargetvar = NULL; /* variable with currently highest target value, i.e., product of integer infeasibility and absolute objective */
110  SCIP_Real maxtargettarget = -1.0; /* target value of current candidate with highest target value, i.e., product of integer infeasibility and absolute objective */
111  SCIP_Real maxtargetval = 0.0; /* value of current candidate with highest target value, i.e., product of integer infeasibility and absolute objective */
112  SCIP_Real maxtargetscore = 0.0; /* score of current candidate with highest target value, i.e., product of integer infeasibility and absolute objective */
113  SCIP_Real currentfrac; /* fractionality of the current candidate */
114  SCIP_Real currenttarget; /* target value, i.e., product of integer infeasibility and absolute objective, of the current candidate */
115  int ncands;
116  int i;
117 
118  assert( scip != NULL );
119  assert( branchrule != NULL );
120  assert( result != NULL );
121 
122  SCIPdebugMessage("Executing External Branching method of SDP-integer-infeasibility-objective!\n");
123 
124  /* Get the external candidates, as we use the score only as a tiebreaker, we aren't interested in the number of
125  * variables of different types with maximal score, so these return values are set to NULL. */
126  SCIP_CALL( SCIPgetExternBranchCands(scip, &cands, &candssol, &candsscore, &ncands, NULL, NULL, NULL, NULL) );
127 
128  assert( ncands > 0 ); /* branchExecext should only be called if the list of extern branching candidate is non-empty */
129 
130  SCIPdebugMessage("branching candidates for SDP-objective:\n");
131 
132  /* iterate over all candidates and find the one with the highest absolute objective times integral infeasibility, use score as tiebreaker */
133  for (i = 0; i < ncands; i++)
134  {
135  /* compute the infeasibility for the integrality constraint */
136  currentfrac = SCIPfeasFrac(scip, candssol[i]);
137  currenttarget = (currentfrac <= 0.5) ? (currentfrac * REALABS(SCIPvarGetObj(cands[i]))) : ((1.0 - currentfrac) * REALABS(SCIPvarGetObj(cands[i])));
138 
139  SCIPdebugMessage("%s, value = %f, objective = %f, objective * integer infeasibility = %f, score = %f\n",
140  SCIPvarGetName(cands[i]), candssol[i], SCIPvarGetObj(cands[i]), currenttarget, candsscore[i]);
141 
142  /* a candidate is better than the current one if:
143  * - the absolute objective * integer infeasibility is (epsilon-)bigger than before or
144  * - the absolute objective * integer infeasibility is (epsilon-)equal and the score is (epsilon-)bigger or
145  * - both are (epsilon-)equal and the index is smaller */
146  if ( SCIPisGT(scip, currenttarget, maxtargettarget) ||
147  ( SCIPisEQ(scip, currenttarget, maxtargettarget) && SCIPisGT(scip, candsscore[i], maxtargetscore) ) ||
148  ( SCIPisEQ(scip, currenttarget, maxtargettarget) && SCIPisEQ(scip, candsscore[i], maxtargetscore) &&
149  SCIPvarGetIndex(cands[i]) < SCIPvarGetIndex(maxtargetvar) ) )
150  {
151  maxtargetvar = cands[i];
152  maxtargettarget = currenttarget;
153  maxtargetval = candssol[i];
154  maxtargetscore = candsscore[i];
155  }
156  }
157 
158  assert( SCIPisGE(scip, maxtargettarget, 0.0) );
159 
160  branchruledata = SCIPbranchruleGetData(branchrule);
161  assert( branchruledata != NULL );
162 
163  /* If all candidates have objective zero, we look for other variables that are coupled with the candidates and check
164  * their objective values if the coupledvars or singlecoupledvars parameter is set to true. */
165  if ( SCIPisEQ(scip, maxtargettarget, 0.0) && (branchruledata->coupledvars || branchruledata->singlecoupledvars) )
166  {
167  SCIP_VAR** vars;
168  int nconss;
169  SCIP_CONS** conss;
170  int nvarsincons;
171  SCIP_VAR** varsincons;
172  SCIP_Bool** coupledvars; /* is there a constraint coupling candidate i and variable j ? */
173  SCIP_Bool** singlecoupledvars; /* is variable j coupled with candidate i AND with no other candidate */
174  int** candsincons; /* candsincons[i] gives a list of all candidates (indexed as in cands) appearing in cons i */
175  int* ncandsincons; /* ncandsincons[i] gives the length of candsincons[i] */
176  SCIP_Bool success;
177  int coupledcand;
178  SCIP_Real currentobj;
179  int cand;
180  int candpos;
181  int nvars;
182  int j;
183  int c;
184  int v;
185 
186  SCIPdebugMessage("All branching candidates have objective 0.0, combined integral infeasibility and objective branching proceeds to check coupled "
187  "variables, updated values for candidates:\n");
188 
189  nvars = SCIPgetNVars(scip);
190  vars = SCIPgetVars(scip);
191  assert( vars != NULL );
192  nconss = SCIPgetNConss(scip);
193  conss = SCIPgetConss(scip);
194  assert( conss != NULL );
195 
196  /* allocate memory to save the coupled variables and initialize the arrays */
197  SCIP_CALL( SCIPallocBufferArray(scip, &ncandsincons, nconss) );
198  for (i = 0; i < nconss; i++)
199  ncandsincons[i] = 0;
200 
201  SCIP_CALL( SCIPallocBufferArray(scip, &candsincons, nconss) );
202  for (i = 0; i < nconss; i++)
203  {
204  SCIP_CALL( SCIPallocBufferArray(scip, &(candsincons[i]), ncands) );
205  }
206 
207  SCIP_CALL( SCIPallocBufferArray(scip, &coupledvars, ncands) );
208  for (i = 0; i < ncands; i++)
209  {
210  SCIP_CALL( SCIPallocBufferArray(scip, &(coupledvars[i]), nvars) );
211  for (j = 0; j < nvars; j++)
212  coupledvars[i][j] = FALSE;
213  }
214  SCIP_CALL( SCIPallocBufferArray(scip, &varsincons, nvars) );
215 
216  /* find all variables that are coupled to a candidate */
217  for (c = 0; c < nconss; c++)
218  {
219  /* first check which candidates appear in which constraints */
220  SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nvarsincons, &success) );
221  if ( ! success )
222  {
223  SCIPdebugMessage("couldn't get variable information from constraint %s, so ignoring it for computing coupled variables\n", SCIPconsGetName(conss[c]));
224  continue; /* if we can't get the variables of this constraint, we can't include variables coupled through this constraint */
225  }
226 
227  /* nothing to do for this constraint if there are no variables (this can happen if all vars are fixed, as the constraint is non-trivial to check) */
228  if ( nvarsincons == 0)
229  continue;
230 
231  SCIP_CALL( SCIPgetConsVars(scip, conss[c], varsincons, nvarsincons, &success) );
232  assert( success ); /* we allocated enough memory */
233  assert( varsincons != NULL );
234 
235  for (v = 0; v < nvarsincons; v++)
236  {
237  for (cand = 0; cand < ncands; cand++)
238  {
239  if ( varsincons[v] == cands[cand] )
240  {
241  candsincons[c][ncandsincons[c]] = cand;
242  ncandsincons[c]++;
243  }
244  }
245  }
246 
247  /* now save which variables are coupled to each candidate by adding all those that appear in this constraint to
248  * all candidates appearing in this constraint */
249  for (candpos = 0; candpos < ncandsincons[c]; candpos++)
250  {
251  for (v = 0; v < nvarsincons; v++)
252  {
253  /* the coupledvars-index corresponding to a variable is its variable index - nvars, because we work on the transformed variables which
254  * have indices nvars to 2*nvars - 1, as their indices start after those of the original variables */
255  coupledvars[candsincons[c][candpos]][SCIPvarGetIndex(varsincons[v]) - nvars] = TRUE; /*lint !e679*/
256  }
257  }
258  }
259 
260  if ( branchruledata->singlecoupledvars )
261  {
262  /* allocate memory for singlecoupledvars */
263  SCIP_CALL( SCIPallocBufferArray(scip, &singlecoupledvars, ncands) );
264  for (i = 0; i < ncands; i++)
265  {
266  SCIP_CALL( SCIPallocBufferArray(scip, &(singlecoupledvars[i]), nvars) );
267  for (j = 0; j < nvars; j++)
268  singlecoupledvars[i][j] = FALSE;
269  }
270  /* finally remove all variables, that are coupled to multiple candidates */
271  for (v = 0; v < nvars; v++)
272  {
273  /* we use coupledcand to save if we have already found a candidate this variable is coupled with (otherwise coupledcand = -1), if we find one,
274  * we set coupledcand to that index, to easily set the corresponding entry to TRUE if we don't find another candidate it is coupled with */
275  coupledcand = -1;
276  for (cand = 0; cand < ncands; cand++)
277  {
278  if ( coupledvars[cand][v] )
279  {
280  /* check if this is the first or the second found candidate for this variable */
281  if ( coupledcand == -1 )
282  {
283  /* this is the first candidate this is coupled with, so it might be the only one and we save it to
284  * potentially later set singlecoupledvars to true */
285  coupledcand = cand;
286  }
287  else
288  {
289  /* we found a second candidate, so this variable won't be taken into account for the branching rule, so we set coupledcand
290  * to -2 to not set the corresponding entry in singlecoupledvars to TRUE and continue with the next variable */
291  coupledcand = -2;
292  break;
293  }
294  }
295  }
296  if ( coupledcand > -1 )
297  {
298  /* as we found exactly one candidate this variable is coupled with, we set the corresponding singlecoupledvars-entry to TRUE */
299  singlecoupledvars[coupledcand][v] = TRUE;
300  }
301  }
302  }
303 
304  /* iterate over all variables and compute the total absolute objective multiplied of all coupled variables */
305  for (cand = 0; cand < ncands; cand++)
306  {
307  currentobj = 0.0;
308  for (v = 0; v < nvars; v++)
309  {
310  if ( branchruledata->singlecoupledvars && singlecoupledvars[cand][v] ) /*lint !e644*/
311  currentobj += REALABS(SCIPvarGetObj(vars[v]));
312  else if ( coupledvars[cand][v] )
313  currentobj += REALABS(SCIPvarGetObj(vars[v]));
314  }
315 
316  /* multiply it with the integral infeasibility of the candidate */
317  currentfrac = SCIPfeasFrac(scip, candssol[cand]);
318  currenttarget = (currentfrac <= 0.5) ? (currentfrac * currentobj) : ((1 - currentfrac) * currentobj);
319 
320  assert( SCIPisGE(scip, currentobj, 0.0) );
321 
322 #ifdef SCIP_DEBUG
323  SCIPdebugMessage("candidate %s, coupled with ", SCIPvarGetName(cands[cand]));
324  for (v = 0; v < nvars; v++)
325  {
326  if (coupledvars[cand][v])
327  SCIPdebugMessage("%s, ", SCIPvarGetName(vars[v]));
328  }
329  SCIPdebugMessage("out of those ");
330  for (v = 0; v < nvars; v++)
331  {
332  if (singlecoupledvars[cand][v])
333  SCIPdebugMessage("%s, ", SCIPvarGetName(vars[v]));
334  }
335  SCIPdebugMessage("are only coupled with this candidate, total objective = %f, integral infeasibility = %f, total objective * candidate's fractionality = %f,"
336  "score = %f\n", currentobj, (currentfrac <= 0.5) ? currentfrac : (1 - currentfrac), currenttarget, candsscore[cand]);
337 #endif
338 
339  /* a candidate is better than the current one if:
340  * - the absolute objective * integer infeasibility is (epsilon-)bigger than before or
341  * - the absolute objective * integer infeasibility is (epsilon-)equal and the score is (epsilon-)bigger or
342  * - both are (epsilon-)equal and the index is smaller */
343  if ( SCIPisGT(scip, currenttarget, maxtargettarget) ||
344  (SCIPisEQ(scip, currenttarget, maxtargettarget) && SCIPisGT(scip, candsscore[cand], maxtargetscore)) ||
345  (SCIPisEQ(scip, currenttarget, maxtargettarget) && SCIPisEQ(scip, candsscore[cand], maxtargetscore) &&
346  SCIPvarGetIndex(cands[cand]) < SCIPvarGetIndex(maxtargetvar)) )
347  {
348  maxtargetvar = cands[cand];
349  maxtargettarget = currenttarget;
350  maxtargetval = candssol[cand];
351  maxtargetscore = candsscore[cand];
352  }
353  }
354 
355  /* free Memory */
356  if ( branchruledata->singlecoupledvars )
357  {
358  for (i = 0; i < ncands; i++)
359  {
360  SCIPfreeBufferArray(scip, &(singlecoupledvars[i]));
361  }
362  SCIPfreeBufferArray(scip, &singlecoupledvars);
363  }
364  SCIPfreeBufferArray(scip, &varsincons);
365  for (i = 0; i < ncands; i++)
366  {
367  SCIPfreeBufferArray(scip, &(coupledvars[i]));
368  }
369  SCIPfreeBufferArray(scip, &coupledvars);
370  for (i = 0; i < nconss; i++)
371  {
372  SCIPfreeBufferArray(scip, &(candsincons[i]));
373  }
374  SCIPfreeBufferArray(scip, &candsincons);
375  SCIPfreeBufferArray(scip, &ncandsincons);
376  }
377 
378  /* if the objective values of all integer variables (and all coupled variables, if this settings was used) is zero, skip this branching rule */
379  if ( SCIPisGT(scip, maxtargettarget, 0.0) )
380  {
381  /* branch */
382  SCIPdebugMessage("branching on variable %s with value %f, absolute objective * integer infeasibility = %f and score %f\n",
383  SCIPvarGetName(maxtargetvar), maxtargetval, maxtargettarget, maxtargetscore);
384  SCIP_CALL( SCIPbranchVarVal(scip, maxtargetvar, maxtargetval, NULL, NULL, NULL) );
385 
386  *result = SCIP_BRANCHED;
387  }
388  else
389  {
390  /* skip */
391  *result = SCIP_DIDNOTRUN;
392  }
393 
394  return SCIP_OKAY;
395 }
396 
398 static
399 SCIP_DECL_BRANCHFREE(branchFreeSdpinfobjective)
400 { /*lint --e{715}*/
401  SCIP_BRANCHRULEDATA* branchruledata;
402 
403  /* free branching rule data */
404  branchruledata = SCIPbranchruleGetData(branchrule);
405  SCIPfreeMemory(scip, &branchruledata);
406  SCIPbranchruleSetData(branchrule, NULL);
407 
408  return SCIP_OKAY;
409 }
410 
411 /*
412  * branching rule specific interface methods
413  */
414 
417  SCIP* scip
418  )
419 {
420  SCIP_BRANCHRULEDATA* branchruledata;
421  SCIP_BRANCHRULE* branchrule;
422 
423  /* create branching rule data */
424  SCIP_CALL( SCIPallocMemory(scip, &branchruledata) );
425 
426  branchrule = NULL;
427 
428  /* include branching rule */
429  SCIP_CALL( SCIPincludeBranchruleBasic(scip, &branchrule, BRANCHRULE_NAME, BRANCHRULE_DESC, BRANCHRULE_PRIORITY,
430  BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
431 
432  assert(branchrule != NULL);
433 
434  /* set non fundamental callbacks via setter functions */
435  SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopySdpinfobjective) );
436  SCIP_CALL( SCIPsetBranchruleExecExt(scip, branchrule, branchExecextSdpinfobjective) );
437  SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeSdpinfobjective) );
438 
439  /* add parameters for the branching rule */
440  SCIP_CALL( SCIPaddBoolParam(scip,
441  "branching/sdpinfobjective/coupledvars",
442  "if all branching candidates have objective zero, should we use the sum of the absolute objectives of all continuous variables coupled with the "
443  "candidate through constraints ?",
444  &branchruledata->coupledvars, TRUE, DEFAULT_COUPLEDVARS, NULL, NULL) );
445  SCIP_CALL( SCIPaddBoolParam(scip,
446  "branching/sdpinfobjective/singlecoupledvars",
447  "if all branching candidates have objective zero, should we use the sum of the absolute objectives of all continuous variables coupled with the "
448  "candidate through constraints in which no other candidate appears ?",
449  &branchruledata->singlecoupledvars, TRUE, DEFAULT_SINGLECOUPLEDVARS, NULL, NULL) );
450 
451  return SCIP_OKAY;
452 }
static SCIP_DECL_BRANCHCOPY(branchCopySdpinfobjective)
#define BRANCHRULE_PRIORITY
#define BRANCHRULE_NAME
static SCIP_DECL_BRANCHFREE(branchFreeSdpinfobjective)
combined infeasibility and absolute objective branching rule for SCIP-SDP
#define DEFAULT_SINGLECOUPLEDVARS
#define BRANCHRULE_MAXBOUNDDIST
#define DEFAULT_COUPLEDVARS
SCIP_RETCODE SCIPincludeBranchruleSdpinfobjective(SCIP *scip)
#define BRANCHRULE_MAXDEPTH
static SCIP_DECL_BRANCHEXECEXT(branchExecextSdpinfobjective)
#define BRANCHRULE_DESC