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