SCIP-SDP  2.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
branch_sdpobjective.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-2015 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-2015 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 
38 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
39 
40 /*#define SCIP_DEBUG */
41 
42 #include <assert.h>
43 #include <string.h>
44 
45 #include "branch_sdpobjective.h"
46 
47 
48 #define BRANCHRULE_NAME "sdpobjective"
49 #define BRANCHRULE_DESC "branch on variable with highest absolute objective of the SDP"
50 #define BRANCHRULE_PRIORITY 0
51 #define BRANCHRULE_MAXDEPTH -1
52 #define BRANCHRULE_MAXBOUNDDIST 1.0
53 #define DEFAULT_COUPLEDVARS FALSE
55 #define DEFAULT_SINGLECOUPLEDVARS FALSE
59 struct SCIP_BranchruleData
60 {
61  SCIP_Bool coupledvars;
63  SCIP_Bool singlecoupledvars;
66 };
67 
68 
69 /*
70  * Data structures
71  */
72 
73 /*
74  * Local methods
75  */
76 
77 /* put your local methods here, and declare them static */
78 
79 
80 /*
81  * Callback methods of branching rule
82  */
83 
85 static
86 SCIP_DECL_BRANCHCOPY(branchCopySdpobjective)
87 { /*lint --e{715}*/
88  assert(scip != NULL);
89  assert(branchrule != NULL);
90  assert(strcmp(SCIPbranchruleGetName(branchrule), BRANCHRULE_NAME) == 0);
91 
92  /* call inclusion method of branchrule */
93  SCIP_CALL( SCIPincludeBranchruleSdpobjective(scip) );
94 
95  return SCIP_OKAY;
96 }
97 
99 static
100 SCIP_DECL_BRANCHEXECEXT(branchExecextSdpobjective)
101 {/*lint --e{715}*/
102  int i;
103  int ncands;
104  SCIP_VAR** cands = NULL;
105  SCIP_Real* candssol; /* solution values of all candidates */
106  SCIP_Real* candsscore; /* scores of all candidates */
107  SCIP_Real currentfrac; /* fractionality of the current candidate */
108  SCIP_Real currentinf; /* infeasibility of the current candidate */
109  SCIP_VAR* maxobjvar = NULL; /* variable with currently highest absolute objective */
110  SCIP_Real maxobjobj; /* objective of the current candidate with highest absolute objective */
111  SCIP_Real maxobjinf; /* infeasibility of the current candidate with highest absolute objective */
112  SCIP_Real maxobjval; /* value of the current candidate with highest absolute objective */
113  SCIP_Real maxobjscore; /* score of the current candidate with highest absolute objective */
114  SCIP_BRANCHRULEDATA* branchruledata;
115 
116  assert( scip != NULL );
117  assert( branchrule != NULL );
118  assert( result != NULL );
119 
120  SCIPdebugMessage("Executing External Branching method of SDP-objective!\n");
121 
122  /* get the external candidates, as we use the score only as a tiebreaker, we aren't interested in the number of variables of different types with maximal
123  * score, so these return values are set to NULL */
124  SCIP_CALL( SCIPgetExternBranchCands(scip, &cands, &candssol, &candsscore, &ncands, NULL, NULL, NULL, NULL) );
125 
126  assert( ncands > 0 ); /* branchExecext should only be called if the list of extern branching candidate is non-empty */
127 
128 #ifdef SCIP_DEBUG
129  printf("branching candidates for SDP-objective:\n");
130  for (i = 0; i < ncands; i++)
131  printf("%s, value = %f, objective = %f, score = %f\n", SCIPvarGetName(cands[i]), candssol[i], SCIPvarGetObj(cands[i]), candsscore[i]);
132 #endif
133 
134  maxobjobj = -1.0;
135  maxobjscore = 0.0;
136  maxobjval = 0.0;
137  maxobjinf = -1.0;
138 
139  /* iterate over all candidates and find the one with the highest absolute objective, use score as tiebreaker */
140  for (i = 0; i < ncands; i++)
141  {
142  currentfrac = SCIPfeasFrac(scip, candssol[i]);
143  currentinf = (currentfrac <= 0.5) ? currentfrac : 1 - currentfrac;
144 
145  /* a candidate is better than the current one if:
146  * - the absolute objective is (epsilon-)bigger than before or
147  * - the absolute objective is (epsilon-)equal and the score is (epsilon-)bigger or
148  * - the absolute objective and score are (epsilon-)equal and the current integral-infeasibility is highter */
149  if ( SCIPisGT(scip, REALABS(SCIPvarGetObj(cands[i])), maxobjobj) ||
150  (SCIPisEQ(scip, REALABS(SCIPvarGetObj(cands[i])), maxobjobj) && SCIPisGT(scip, candsscore[i], maxobjscore)) ||
151  (SCIPisEQ(scip, REALABS(SCIPvarGetObj(cands[i])), maxobjobj) && SCIPisEQ(scip, candsscore[i], maxobjscore) && currentinf > maxobjinf ) )
152  {
153  maxobjvar = cands[i];
154  maxobjobj = REALABS(SCIPvarGetObj(cands[i]));
155  maxobjinf = currentinf;
156  maxobjval = candssol[i];
157  maxobjscore = candsscore[i];
158  }
159  }
160 
161  assert( SCIPisGE(scip, maxobjobj, 0.0) );
162 
163  branchruledata = SCIPbranchruleGetData(branchrule);
164  assert( branchruledata != NULL );
165 
166  /* if all candidates have objective zero, we look for other variables that are coupled with the candidates and check their objective values if the
167  * coupledvars or singlecoupledvars parameter is set to true */
168  if ( SCIPisEQ(scip, maxobjobj, 0.0) && (branchruledata->coupledvars || branchruledata->singlecoupledvars) )
169  {
170  int j;
171  int c;
172  int v;
173  int cand;
174  int candpos;
175  int nvars;
176  SCIP_VAR** vars;
177  int nconss;
178  SCIP_CONS** conss;
179  int nvarsincons;
180  SCIP_VAR** varsincons;
181  SCIP_Bool** coupledvars; /* is there a constraint coupling candidate i and variable j ? */
182  SCIP_Bool** singlecoupledvars; /* is variable j coupled with candidate i AND with no other candidate */
183  int** candsincons; /* candsincons[i] gives a list of all candidates (indexed as in cands) appearing in cons i */
184  int* ncandsincons; /* ncandsincons[i] gives the length of candsincons[i] */
185  SCIP_Real currentobj;
186  SCIP_Bool success;
187  int coupledcand;
188 
189  SCIPdebugMessage("All branching candidates have objective 0.0, objective branching proceeds to check coupled variables, updated values for candidates: \n");
190 
191  nvars = SCIPgetNVars(scip);
192  vars = SCIPgetVars(scip);
193  assert( vars != NULL );
194  nconss = SCIPgetNConss(scip);
195  conss = SCIPgetConss(scip);
196  assert( conss != NULL );
197 
198  /* allocate memory to save the coupled variables and initialize the arrays */
199  SCIP_CALL( SCIPallocBufferArray(scip, &ncandsincons, nconss) );
200  for (i = 0; i < nconss; i++)
201  ncandsincons[i] = 0;
202 
203  SCIP_CALL( SCIPallocBufferArray(scip, &candsincons, nconss) );
204  for (i = 0; i < nconss; i++)
205  {
206  SCIP_CALL( SCIPallocBufferArray(scip, &(candsincons[i]), ncands) );
207  }
208 
209  SCIP_CALL( SCIPallocBufferArray(scip, &coupledvars, ncands) );
210  for (i = 0; i < ncands; i++)
211  {
212  SCIP_CALL( SCIPallocBufferArray(scip, &(coupledvars[i]), nvars) );
213  for (j = 0; j < nvars; j++)
214  coupledvars[i][j] = FALSE;
215  }
216  SCIP_CALL( SCIPallocBufferArray(scip, &varsincons, nvars) );
217 
218  /* find all variables that are coupled to a candidate */
219  for (c = 0; c < nconss; c++)
220  {
221  /* first check which candidates appear in which constraints */
222  SCIP_CALL( SCIPgetConsNVars(scip, conss[c], &nvarsincons, &success) );
223  if ( ! success )
224  {
225  SCIPdebugMessage("couldn't get variable information from constraint %s, so ignoring it for computing coupled variables\n", SCIPconsGetName(conss[c]));
226  continue; /* if we can't get the variables of this constraint, we can't include variables coupled through this constraint */
227  }
228  /* 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) */
229  if ( nvarsincons == 0)
230  continue;
231  SCIP_CALL( SCIPgetConsVars(scip, conss[c], varsincons, nvarsincons, &success) );
232  assert( success ); /* we allocated enough memory */
233  assert( varsincons != NULL );
234  for (v = 0; v < nvarsincons; v++)
235  {
236  for (cand = 0; cand < ncands; cand++)
237  {
238  if ( varsincons[v] == cands[cand] )
239  {
240  candsincons[c][ncandsincons[c]] = cand;
241  ncandsincons[c]++;
242  }
243  }
244  }
245 
246  /* now save which variables are coupled to each candidate by adding all those that appear in this constraint to
247  * all candidates appearing in this constraint */
248  for (candpos = 0; candpos < ncandsincons[c]; candpos++)
249  {
250  for (v = 0; v < nvarsincons; v++)
251  {
252  /* the coupledvars-index corresponding to a variable is its variable index - nvars, because we work on the transformed variables which
253  * have indices nvars to 2*nvars - 1, as their indices start after those of the original variables */
254  coupledvars[candsincons[c][candpos]][SCIPvarGetIndex(varsincons[v]) - nvars] = TRUE; /*lint !e679*/
255  }
256  }
257  }
258 
259  if ( branchruledata->singlecoupledvars )
260  {
261  /* allocate memory for singlecoupledvars */
262  SCIP_CALL( SCIPallocBufferArray(scip, &singlecoupledvars, ncands) );
263  for (i = 0; i < ncands; i++)
264  {
265  SCIP_CALL( SCIPallocBufferArray(scip, &(singlecoupledvars[i]), nvars) );
266  for (j = 0; j < nvars; j++)
267  singlecoupledvars[i][j] = FALSE;
268  }
269  /* finally remove all variables, that are coupled to multiple candidates */
270  for (v = 0; v < nvars; v++)
271  {
272  /* we use coupledcand to save if we have already found a candidate this variable is coupled with (otherwise coupledcand = -1), if we find one,
273  * 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 */
274  coupledcand = -1;
275  for (cand = 0; cand < ncands; cand++)
276  {
277  if ( coupledvars[cand][v] )
278  {
279  /* check if this is the first or the second found candidate for this variable */
280  if ( coupledcand == -1 )
281  {
282  /* this is the first candidate this is coupled with, so it might be the only one and we save it to
283  * potentially later set singlecoupledvars to true */
284  coupledcand = cand;
285  }
286  else
287  {
288  /* we found a second candidate, so this variable won't be taken into account for the branching rule, so we set coupledcand
289  * to -2 to not set the corresponding entry in singlecoupledvars to TRUE and continue with the next variable */
290  coupledcand = -2;
291  break;
292  }
293  }
294  }
295  if ( coupledcand > -1 )
296  {
297  /* as we found exactly one candidate this variable is coupled with, we set the corresponding singlecoupledvars-entry to TRUE */
298  singlecoupledvars[coupledcand][v] = TRUE;
299  }
300  }
301  }
302 
303  /* iterate over all variables and compute the total absolute objective of all coupled variables */
304  for (cand = 0; cand < ncands; cand++)
305  {
306  currentobj = 0.0;
307  for (v = 0; v < nvars; v++)
308  {
309  if ( branchruledata->singlecoupledvars && singlecoupledvars[cand][v] )
310  currentobj += REALABS(SCIPvarGetObj(vars[v]));
311  else if ( coupledvars[cand][v] )
312  currentobj += REALABS(SCIPvarGetObj(vars[v]));
313  }
314 
315  assert( SCIPisGE(scip, currentobj, 0.0) );
316 
317  currentfrac = SCIPfeasFrac(scip, candssol[i]);
318  currentinf = (currentfrac <= 0.5) ? currentfrac : 1 - currentfrac;
319 
320 #ifdef SCIP_DEBUG
321  printf("candidate %s, coupled with ", SCIPvarGetName(cands[cand]));
322  for (v = 0; v < nvars; v++)
323  {
324  if (coupledvars[cand][v])
325  printf("%s, ", SCIPvarGetName(vars[v]));
326  }
327  printf("out of those ");
328  for (v = 0; v < nvars; v++)
329  {
330  if (singlecoupledvars[cand][v])
331  printf("%s, ", SCIPvarGetName(vars[v]));
332  }
333  printf("are only coupled with this candidate, total objective = %f, score = %f\n", currentobj, candsscore[cand]);
334 
335 #endif
336 
337  /* a candidate is better than the current one if:
338  * - the total absolute objective is (epsilon-)bigger than before or
339  * - the total absolute objective is (epsilon-)equal and the score is (epsilon-)bigger or
340  * - the score is (epsilon-)equal and the total absolute objective is (less than epsilon) bigger
341  * - the total absolute objective is (exactly) equal and the score is (less than epsilon) bigger
342  */
343  if ( SCIPisGT(scip, currentobj, maxobjobj) ||
344  (SCIPisEQ(scip, currentobj, maxobjobj) && SCIPisGT(scip, candsscore[i], maxobjscore)) ||
345  (SCIPisEQ(scip, currentobj, maxobjobj) && SCIPisEQ(scip, candsscore[i], maxobjscore) && currentinf > maxobjinf ) )
346  {
347  maxobjvar = cands[cand];
348  maxobjobj = currentobj;
349  maxobjinf = currentinf;
350  maxobjval = candssol[cand];
351  maxobjscore = 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  /* branch */
379  SCIPdebugMessage("branching on variable %s with value %f, absolute objective %f and score %f\n", SCIPvarGetName(maxobjvar), maxobjval, maxobjobj, maxobjscore);
380  SCIP_CALL( SCIPbranchVarVal(scip, maxobjvar, maxobjval, NULL, NULL, NULL) );
381 
382  *result = SCIP_BRANCHED;
383 
384  return SCIP_OKAY;
385 }
386 
388 static
389 SCIP_DECL_BRANCHFREE(branchFreeSdpobjective)
390 { /*lint --e{715}*/
391  SCIP_BRANCHRULEDATA* branchruledata;
392 
393  /* free branching rule data */
394  branchruledata = SCIPbranchruleGetData(branchrule);
395  SCIPfreeMemory(scip, &branchruledata);
396  SCIPbranchruleSetData(branchrule, NULL);
397 
398  return SCIP_OKAY;
399 }
400 
401 /*
402  * branching rule specific interface methods
403  */
404 
407  SCIP* scip
408 )
409 {
410  SCIP_BRANCHRULEDATA* branchruledata;
411  SCIP_BRANCHRULE* branchrule;
412 
413  /* create branching rule data */
414  SCIP_CALL( SCIPallocMemory(scip, &branchruledata) );
415 
416  branchrule = NULL;
417 
418  /* include branching rule */
419  SCIP_CALL( SCIPincludeBranchruleBasic(scip, &branchrule, BRANCHRULE_NAME, BRANCHRULE_DESC, BRANCHRULE_PRIORITY,
420  BRANCHRULE_MAXDEPTH, BRANCHRULE_MAXBOUNDDIST, branchruledata) );
421 
422  assert(branchrule != NULL);
423 
424  /* set non fundamental callbacks via setter functions */
425  SCIP_CALL( SCIPsetBranchruleCopy(scip, branchrule, branchCopySdpobjective) );
426  SCIP_CALL( SCIPsetBranchruleExecExt(scip, branchrule, branchExecextSdpobjective) );
427  SCIP_CALL( SCIPsetBranchruleFree(scip, branchrule, branchFreeSdpobjective) );
428 
429  /* add parameters for the branching rule */
430  SCIP_CALL( SCIPaddBoolParam(scip,
431  "branching/sdpobjective/coupledvars",
432  "if all branching candidates have objective zero, should we use the sum of the absolute objectives of all continuous variables coupled with the "
433  "candidate through constraints ?",
434  &branchruledata->coupledvars, TRUE, DEFAULT_COUPLEDVARS, NULL, NULL) );
435  SCIP_CALL( SCIPaddBoolParam(scip,
436  "branching/sdpobjective/singlecoupledvars",
437  "if all branching candidates have objective zero, should we use the sum of the absolute objectives of all continuous variables coupled with the "
438  "candidate through constraints in which no other candidate appears ?",
439  &branchruledata->singlecoupledvars, TRUE, DEFAULT_SINGLECOUPLEDVARS, NULL, NULL) );
440 
441  return SCIP_OKAY;
442 }
static SCIP_DECL_BRANCHFREE(branchFreeSdpobjective)
#define DEFAULT_SINGLECOUPLEDVARS
#define DEFAULT_COUPLEDVARS
highest absolute objective branching rule for SCIPSDP
#define BRANCHRULE_DESC
#define BRANCHRULE_NAME
static SCIP_DECL_BRANCHCOPY(branchCopySdpobjective)
#define BRANCHRULE_MAXBOUNDDIST
SCIP_RETCODE SCIPincludeBranchruleSdpobjective(SCIP *scip)
#define BRANCHRULE_PRIORITY
static SCIP_DECL_BRANCHEXECEXT(branchExecextSdpobjective)
#define BRANCHRULE_MAXDEPTH