Scippy

SCIP

Solving Constraint Integer Programs

sepa_lagromory.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file sepa_lagromory.c
26  * @ingroup DEFPLUGINS_SEPA
27  * @brief Lagromory separator
28  * @author Suresh Bolusani
29  * @author Mark Ruben Turner
30  * @author Mathieu Besançon
31  *
32  * This separator is based on the following article that discusses Lagromory separation using the relax-and-cut
33  * framework. Multiple enhancements have been implemented on top of the basic algorithm described in the article.
34  *
35  * Fischetti M. and Salvagnin D. (2011).@n
36  * A relax-and-cut framework for Gomory mixed-integer cuts.@n
37  * Mathematical Programming Computation, 3, 79-102.
38  *
39  * Consider the following linear relaxation at a node:
40  *
41  * \f[
42  * \begin{array}{rrl}
43  * \min & c^T x &\\
44  * & x & \in P,
45  * \end{array}
46  * \f]
47  *
48  * where \f$P\f$ is the feasible region of the relaxation. Let the following be the cuts generated so far in the current
49  * separation round.
50  *
51  * \f[
52  * {\alpha^i}^T x \leq \alpha^i_0, i = 1, 2, \ldots, M
53  * \f]
54  *
55  * Then, the following is the Lagrangian dual problem considered in the relax-and-cut framework used in the separator.
56  *
57  * \f[
58  * z_D := \max\limits_{u \geq 0} \left\{L(u) := \min \left\{c^T x + \sum\limits_{i = 1}^{M} \left(u_i
59  * \left({\alpha^i}^T x - \alpha^i_0\right) \right) \mid x \in P\right\} \right\},
60  * \f]
61  *
62  * where \f$u\f$ are the Lagrangian multipliers (referred to as \a dualvector in this separator) used for penalizing the
63  * violation of the generated cuts, and \f$z_D\f$ is the optimal objective value (which is approximated via \a ubparam in this separator).
64  * Then, the following are the steps of the relax-and-cut algorithm implemented in this separator.
65  *
66  * - Generate an initial pool of cuts to build the initial Lagrangian dual problem.
67  * - Select initial values for Lagrangian multipliers \f$u^0\f$ (e.g., all zeroes vector).
68  * - In the outer main loop \f$i\f$ of the algorithm:
69  * 1. Solve the Lagrangian dual problem until certain termination criterion is met. This results in an inner
70  * subgradient loop, whose iteration \f$j\f$ is described below.
71  * 1. Fix \f$u^j\f$, and solve the LP corresponding to the Lagrangian dual with fixed multipliers.
72  * Gather its optimal simplex tableau and optimal objective value (i.e., the Lagrangian value)
73  * \f$L(u^j)\f$.
74  * 2. Update \f$u^j\f$ to \f$u^{j+1}\f$ as follows.
75  * \f[
76  * u^{j+1} = \left(u^j + \lambda_j s^k\right)_+,
77  * \f]
78  * where \f$\lambda_j\f$ is the step length:
79  * \f[
80  * \lambda_j = \frac{\mu_j (UB - L(u^j))}{\|s^j\|^2_2},
81  * \f]
82  * where \f$mu_j\f$ is a factor (i.e., \a muparam) such that \f$0 < \mu_j \leq 2\f$, UB is \p ubparam,
83  * and \f$s^j\f$ is the subgradient vector defined as:
84  * \f[
85  * s^j_k = \left({\alpha^k}^T x - \alpha^k_0\right), k = 1, 2, \ldots, M.
86  * \f]
87  * The factor \f$mu_j\f$ is updated as below.
88  * \f[
89  * mu_j = \begin{cases}
90  * mubacktrackfactor * mu_j & \text{if } L(u^j) < bestLB - \delta\\
91  * \begin{cases}
92  * muslab1factor * mu_j & \text{if } bestLB - avgLB < deltaslab1ub * delta\\
93  * muslab2factor * mu_j & \text{if } deltaslab1ub * \delta \leq bestLB - avgLB < deltaslab2ub * delta\\
94  * muslab3factor * mu_j & \text{otherwise}
95  * \end{cases} & \text{otherwise},
96  * \end{cases}
97  * \f]
98  * where \f$bestLB\f$ and \f$avgLB\f$ are best and average Lagrangian values found so far, and
99  * \f$\delta = UB - bestLB\f$.
100  * 3. Stabilize \f$u^{j+1}\f$ by projecting onto a norm ball followed by taking a convex combination
101  * with a core vector of Lagrangian multipliers.
102  * 4. Generate GMI cuts based on the optimal simplex tableau.
103  * 5. Relax the newly generated cuts by penalizing and adding them to the objective function.
104  * 6. Go to the next iteration \f$j+1\f$.
105  * 2. Gather all the generated cuts and build an LP by adding all these cuts to the node relaxation.
106  * 3. Solve this LP to obtain its optimal primal and dual solutions.
107  * 4. If this primal solution is MIP primal feasible, then add this solution to the solution pool, add all
108  * the generated cuts to the cutpool or sepastore as needed, and exit the separator.
109  * 5. Otherwise, update the Lagrangian multipliers based on this optimal dual solution, and go to the next
110  * iteration \f$i+1\f$.
111  *
112  * @todo store all LP sols in a data structure, and send them to fix-and-propagate at the end.
113  *
114  * @todo test heuristics such as feasibility pump with multiple input solutions.
115  *
116  * @todo find dual degenerate problems and test the separator on these problems.
117  *
118  * @todo identify instance classes where these cuts work better.
119  *
120  * @todo add termination criteria based on failed efforts.
121  *
122  * @todo for warm starting, if there are additional rows/cols, set their basis status to non-basic and then set WS info.
123  *
124  * @todo filter cuts using multiple explored LP solutions.
125  *
126  * @todo for bases on optimal face only, aggregate to get a new basis and separate it.
127  *
128  * @todo generate other separators in addition to GMI cuts (0-1/2).
129  *
130  * @todo convert iters from int to SCIP_Longint.
131  */
132 
133 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
134 
135 #include "scip/heur_trysol.h"
136 #include "scip/sepa_lagromory.h"
137 
138 #define SEPA_NAME "lagromory"
139 #define SEPA_DESC "separator for Lagromory cuts for MIP relaxations"
140 #define SEPA_PRIORITY -8000
141 #define SEPA_FREQ -1
142 #define SEPA_MAXBOUNDDIST 1.0
143 #define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
144 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
145 
146 /* generic parameters */
147 #define DEFAULT_AWAY 0.01 /**< minimal integrality violation of a basis variable to try separation */
148 #define DEFAULT_DELAYEDCUTS FALSE /**< should cuts be added to the delayed cut pool? */
149 #define DEFAULT_SEPARATEROWS TRUE /**< separate rows with integral slack? */
150 #define DEFAULT_SORTCUTOFFSOL TRUE /**< sort fractional integer columns based on fractionality? */
151 #define DEFAULT_SIDETYPEBASIS TRUE /**< choose side types of row (lhs/rhs) based on basis information? */
152 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
153 #define DEFAULT_MAKEINTEGRAL FALSE /**< try to scale all cuts to integral coefficients? */
154 #define DEFAULT_FORCECUTS FALSE /**< force cuts to be added to the LP? */
155 #define DEFAULT_ALLOWLOCAL FALSE /**< should locally valid cuts be generated? */
156 
157 /* parameters related to the separator's termination check */
158 #define DEFAULT_MAXROUNDSROOT 1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
159 #define DEFAULT_MAXROUNDS 1 /**< maximal number of separation rounds per node (-1: unlimited) */
160 #define DEFAULT_DUALDEGENERACYRATETHRESHOLD 0.5 /**< minimum dual degeneracy rate for separator execution */
161 #define DEFAULT_VARCONSRATIOTHRESHOLD 1.0 /**< minimum variable-constraint ratio on optimal face for separator execution */
162 #define DEFAULT_MINRESTART 1 /**< minimum restart round for separator execution (0: from beginning of the
163  * instance solving, >= n with n >= 1: from restart round n) */
164 #define DEFAULT_PERLPMAXCUTSROOT 50 /**< maximal number of cuts separated per Lagromory LP in the root node */
165 #define DEFAULT_PERLPMAXCUTS 10 /**< maximal number of cuts separated per Lagromory LP in the non-root node */
166 #define DEFAULT_PERROUNDLPITERLIMITFACTOR -1.0 /**< factor w.r.t. root node LP iterations for maximal separating LP iterations
167  * per separation round (negative for no limit) */
168 #define DEFAULT_ROOTLPITERLIMITFACTOR -1.0 /**< factor w.r.t. root node LP iterations for maximal separating LP iterations
169  * in the root node (negative for no limit) */
170 #define DEFAULT_TOTALLPITERLIMITFACTOR -1.0 /**< factor w.r.t. root node LP iterations for maximal separating LP iterations
171  * in the tree (negative for no limit) */
172 #define DEFAULT_PERROUNDMAXLPITERS 50000 /**< maximal number of separating LP iterations per separation round (-1: unlimited) */
173 #define DEFAULT_PERROUNDCUTSFACTORROOT 1.0 /**< factor w.r.t. number of integer columns for number of cuts separated per
174  * separation round in root node */
175 #define DEFAULT_PERROUNDCUTSFACTOR 0.5 /**< factor w.r.t. number of integer columns for number of cuts separated per
176  * separation round at a non-root node */
177 #define DEFAULT_TOTALCUTSFACTOR 50.0 /**< factor w.r.t. number of integer columns for total number of cuts separated */
178 #define DEFAULT_MAXMAINITERS 4 /**< maximal number of main loop iterations of the relax-and-cut algorithm */
179 #define DEFAULT_MAXSUBGRADIENTITERS 6 /**< maximal number of subgradient loop iterations of the relax-and-cut algorithm */
181 /* parameters related to the relax-and-cut algorithm */
182 #define DEFAULT_MUPARAMCONST TRUE /**< is the mu parameter (factor for step length) constant? */
183 #define DEFAULT_MUPARAMINIT 0.01 /**< initial value of the mu parameter (factor for step length) */
184 #define DEFAULT_MUPARAMLB 0.0 /**< lower bound for the mu parameter (factor for step length) */
185 #define DEFAULT_MUPARAMUB 2.0 /**< upper bound for the mu parameter (factor for step length) */
186 #define DEFAULT_MUBACKTRACKFACTOR 0.5 /**< factor of mu while backtracking the mu parameter (factor for step length) -
187  * see updateMuSteplengthParam() */
188 #define DEFAULT_MUSLAB1FACTOR 10.0 /**< factor of mu parameter (factor for step length) for larger increment - see
189  * updateMuSteplengthParam() */
190 #define DEFAULT_MUSLAB2FACTOR 2.0 /**< factor of mu parameter (factor for step length) for smaller increment - see
191  * updateMuSteplengthParam() */
192 #define DEFAULT_MUSLAB3FACTOR 0.5 /**< factor of mu parameter (factor for step length) for reduction - see
193  * updateMuSteplengthParam() */
194 #define DEFAULT_DELTASLAB1UB 0.001 /**< factor of delta deciding larger increment of mu parameter (factor for step
195  * length) - see updateMuSteplengthParam() */
196 #define DEFAULT_DELTASLAB2UB 0.01 /**< factor of delta deciding smaller increment of mu parameter (factor for step
197  * length) - see updateMuSteplengthParam() */
198 #define DEFAULT_UBPARAMPOSFACTOR 2.0 /**< factor for positive upper bound used as an estimate for the optimal
199  * Lagrangian dual value */
200 #define DEFAULT_UBPARAMNEGFACTOR 0.5 /**< factor for negative upper bound used as an estimate for the optimal
201  * Lagrangian dual value */
202 #define DEFAULT_MAXLAGRANGIANVALSFORAVG 2 /**< maximal number of iterations for rolling average of Lagrangian value */
203 #define DEFAULT_MAXCONSECITERSFORMUUPDATE 10 /**< consecutive number of iterations used to determine if mu needs to be backtracked */
204 #define DEFAULT_PERROOTLPITERFACTOR 0.2 /**< factor w.r.t. root node LP iterations for iteration limit of each separating
205  * LP (negative for no limit) */
206 #define DEFAULT_PERLPITERFACTOR 0.1 /**< factor w.r.t. non-root node LP iterations for iteration limit of each
207  * separating LP (negative for no limit) */
208 #define DEFAULT_CUTGENFREQ 1 /**< frequency of subgradient iterations for generating cuts */
209 #define DEFAULT_CUTADDFREQ 1 /**< frequency of subgradient iterations for adding cuts to objective function */
210 #define DEFAULT_CUTSFILTERFACTOR 1.0 /**< fraction of generated cuts per explored basis to accept from separator */
211 #define DEFAULT_OPTIMALFACEPRIORITY 2 /**< priority of the optimal face for separator execution (0: low priority, 1:
212  * medium priority, 2: high priority) */
213 #define DEFAULT_AGGREGATECUTS TRUE /**< aggregate all generated cuts using the Lagrangian multipliers? */
214 
215 /* parameters for stabilization of the Lagrangian multipliers */
216 #define DEFAULT_PROJECTIONTYPE 2 /**< the ball into which the Lagrangian multipliers are projected for
217  * stabilization (0: no projection, 1: L1-norm ball projection, 2: L2-norm ball
218  * projection, 3: L_inf-norm ball projection) */
219 #define DEFAULT_STABILITYCENTERTYPE 1 /**< type of stability center for taking weighted average of Lagrangian multipliers for
220  * stabilization (0: no weighted stabilization, 1: best Lagrangian multipliers) */
221 #define DEFAULT_RADIUSINIT 0.5 /**< initial radius of the ball used in stabilization of Lagrangian multipliers */
222 #define DEFAULT_RADIUSMAX 20.0 /**< maximum radius of the ball used in stabilization of Lagrangian multipliers */
223 #define DEFAULT_RADIUSMIN 1e-6 /**< minimum radius of the ball used in stabilization of Lagrangian multipliers */
224 #define DEFAULT_CONST 2.0 /**< a constant for stablity center based stabilization of Lagrangian multipliers */
225 #define DEFAULT_RADIUSUPDATEWEIGHT 0.98 /**< multiplier to evaluate cut violation score used for updating ball radius */
227 /* macros that are used directly */
228 #define RANDSEED 42 /**< random seed */
229 #define MAKECONTINTEGRAL FALSE /**< convert continuous variable to integral variables in SCIPmakeRowIntegral()? */
230 #define POSTPROCESS TRUE /**< apply postprocessing after MIR calculation? - see SCIPcalcMIR() */
231 #define BOUNDSWITCH 0.9999 /**< threshold for bound switching - see SCIPcalcMIR() */
232 #define USEVBDS TRUE /**< use variable bounds? - see SCIPcalcMIR() */
233 #define FIXINTEGRALRHS FALSE /**< try to generate an integral rhs? - see SCIPcalcMIR() */
234 #define MAXAGGRLEN(ncols) (0.1*(ncols)+1000) /**< maximal length of base inequality */
235 
236 /*
237  * Data structures
238  */
239 
240 /** separator data */
241 struct SCIP_SepaData
242 {
243  /* generic variables */
244  SCIP_Real away; /**< minimal integrality violation of a basis variable to try separation */
245  SCIP_Bool delayedcuts; /**< should cuts be added to the delayed cut pool? */
246  SCIP_Bool separaterows; /**< separate rows with integral slack? */
247  SCIP_Bool sortcutoffsol; /**< sort fractional integer columns based on fractionality? */
248  SCIP_Bool sidetypebasis; /**< choose side types of row (lhs/rhs) based on basis information? */
249  SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
250  SCIP_Bool makeintegral; /**< try to scale all cuts to integral coefficients? */
251  SCIP_Bool forcecuts; /**< force cuts to be added to the LP? */
252  SCIP_Bool allowlocal; /**< should locally valid cuts be generated? */
253  SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
254  SCIP_HEUR* heurtrysol; /**< a pointer to the trysol heuristic, if available */
255 
256  /* used to define separating LPs */
257  SCIP_LPI* lpiwithsoftcuts; /**< pointer to the lpi interface of Lagrangian dual with fixed multipliers */
258  SCIP_LPI* lpiwithhardcuts; /**< pointer to the lpi interface of LP with all generated cuts */
259  int nrowsinhardcutslp; /**< nrows of \a lpiwithhardcuts */
260  int nrunsinsoftcutslp; /**< number of branch-and-bound runs on current instance */
261 
262  /* used for termination checks */
263  SCIP_Longint ncalls; /**< number of calls to the separator */
264  int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
265  int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
266  SCIP_Real dualdegeneracyratethreshold; /**< minimum dual degeneracy rate for separator execution */
267  SCIP_Real varconsratiothreshold; /**< minimum variable-constraint ratio on optimal face for separator execution */
268  int minrestart; /**< minimum restart round for separator execution (0: from beginning of the instance
269  * solving, >= n with n >= 1: from restart round n) */
270  int nmaxcutsperlproot; /**< maximal number of cuts separated per Lagromory LP in the root node */
271  int nmaxcutsperlp; /**< maximal number of cuts separated per Lagromory LP in the non-root node */
272  SCIP_Real perroundlpiterlimitfactor; /**< factor w.r.t. root node LP iterations for maximal separating LP iterations per
273  * separation round (negative for no limit) */
274  SCIP_Real rootlpiterlimitfactor; /**< factor w.r.t. root node LP iterations for maximal separating LP iterations in the
275  * root node (negative for no limit) */
276  SCIP_Real totallpiterlimitfactor; /**< factor w.r.t. root node LP iterations for maximal separating LP iterations in the
277  * tree (negative for no limit) */
278  int perroundnmaxlpiters; /**< maximal number of separating LP iterations per separation round (-1: unlimited) */
279  SCIP_Real perroundcutsfactorroot; /**< factor w.r.t. number of integer columns for number of cuts separated per
280  * separation round in root node */
281  SCIP_Real perroundcutsfactor; /**< factor w.r.t. number of integer columns for number of cuts separated per
282  * separation round at a non-root node */
283  SCIP_Real totalcutsfactor; /**< factor w.r.t. number of integer columns for total number of cuts separated */
284  int nmaxmainiters; /**< maximal number of main loop iterations of the relax-and-cut algorithm */
285  int nmaxsubgradientiters; /**< maximal number of subgradient loop iterations of the relax-and-cut algorithm */
286  int nmaxperroundlpiters; /**< maximal number of separating LP iterations per separation round */
287  int nmaxrootlpiters; /**< maximal number of separating LP iterations in the root node */
288  int nrootlpiters; /**< number of separating LP iterations in the root node */
289  int nmaxtotallpiters; /**< maximal number of separating LP iterations in the tree */
290  int ntotallpiters; /**< number of separating LP iterations in the tree */
291  int nmaxperroundcutsroot; /**< maximal number of cuts separated per separation round in root node */
292  int nmaxperroundcuts; /**< maximal number of cuts separated per separation round */
293  int nmaxtotalcuts; /**< maximal number of cuts separated in the tree */
294  int ntotalcuts; /**< number of cuts separated in the tree */
295 
296  /* used for the relax-and-cut algorithm */
297  SCIP_Bool muparamconst; /**< is the mu parameter (factor for step length) constant? */
298  SCIP_Real muparaminit; /**< initial value of the mu parameter (factor for step length) */
299  SCIP_Real muparamlb; /**< lower bound for the mu parameter (factor for step length) */
300  SCIP_Real muparamub; /**< upper bound for the mu parameter (factor for step length) */
301  SCIP_Real mubacktrackfactor; /**< factor of mu while backtracking the mu parameter (factor for step length) - see
302  * updateMuSteplengthParam() */
303  SCIP_Real muslab1factor; /**< factor of mu parameter (factor for step length) for larger increment - see
304  * updateMuSteplengthParam() */
305  SCIP_Real muslab2factor; /**< factor of mu parameter (factor for step length) for smaller increment - see
306  * updateMuSteplengthParam() */
307  SCIP_Real muslab3factor; /**< factor of mu parameter (factor for step length) for reduction - see updateMuSteplengthParam() */
308  SCIP_Real deltaslab1ub; /**< factor of delta deciding larger increment of mu parameter (factor for step
309  * length) - see updateMuSteplengthParam() */
310  SCIP_Real deltaslab2ub; /**< factor of delta deciding smaller increment of mu parameter (factor for step
311  * length) - see updateMuSteplengthParam() */
312  SCIP_Real ubparamposfactor; /**< factor for positive upper bound used as an estimate for the optimal Lagrangian
313  * dual value */
314  SCIP_Real ubparamnegfactor; /**< factor for negative upper bound used as an estimate for the optimal Lagrangian
315  * dual value */
316  int nmaxlagrangianvalsforavg; /**< maximal number of iterations for rolling average of Lagrangian value */
317  int nmaxconsecitersformuupdate; /**< consecutive number of iterations used to determine if mu needs to be backtracked */
318  SCIP_Real perrootlpiterfactor; /**< factor w.r.t. root node LP iterations for iteration limit of each separating LP
319  * (negative for no limit) */
320  SCIP_Real perlpiterfactor; /**< factor w.r.t. non-root node LP iterations for iteration limit of each separating
321  * LP (negative for no limit) */
322  int cutgenfreq; /**< frequency of subgradient iterations for generating cuts */
323  int cutaddfreq; /**< frequency of subgradient iterations for adding cuts to objective function */
324  SCIP_Real cutsfilterfactor; /**< fraction of generated cuts per explored basis to accept from separator */
325  int optimalfacepriority; /**< priority of the optimal face for separator execution (0: low priority, 1: medium
326  * priority, 2: high priority) */
327  SCIP_Bool aggregatecuts; /**< aggregate all generated cuts using the Lagrangian multipliers? */
328 
329  /* for stabilization of Lagrangian multipliers */
330  int projectiontype; /**< the ball into which the Lagrangian multipliers are projected for stabilization
331  * (0: no projection, 1: L1-norm ball projection, 2: L2-norm ball projection, 3:
332  * L_inf-norm ball projection) */
333  int stabilitycentertype; /**< type of stability center for taking weighted average of Lagrangian multipliers for
334  * stabilization (0: no weighted stabilization, 1: best Lagrangian multipliers) */
335  SCIP_Real radiusinit; /**< initial radius of the ball used in stabilization of Lagrangian multipliers */
336  SCIP_Real radiusmax; /**< maximum radius of the ball used in stabilization of Lagrangian multipliers */
337  SCIP_Real radiusmin; /**< minimum radius of the ball used in stabilization of Lagrangian multipliers */
338  SCIP_Real constant; /**< a constant for stablity center based stabilization of Lagrangian multipliers */
339  SCIP_Real radiusupdateweight; /**< multiplier to evaluate cut violation score used for updating ball radius */
340 };
341 
342 
343 /*
344  * Local methods
345  */
346 
347 /** start the diving mode for solving LPs corresponding to the Lagrangian dual with fixed multipliers in the subgradient
348  * loop of the separator, and update some sepadata values */
349 static
351  SCIP* scip, /**< SCIP data structure */
352  SCIP_SEPADATA* sepadata /**< separator data structure */
353  )
354 {
355  SCIP_ROW** rows;
356  SCIP_COL** cols;
357  int nruns;
358  int runnum;
359  int nrows;
360  int ncols;
361  unsigned int nintcols;
362  SCIP_Longint nrootlpiters;
363  int i;
364 
365  assert(scip != NULL);
366  assert(sepadata != NULL);
367 
368  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
369  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
370  runnum = SCIPgetNRuns(scip); /* current run number of SCIP (starts from 1) indicating restarts */
371  nruns = sepadata->nrunsinsoftcutslp; /* previous run number of SCIP in which the diving LP was created */
372  nintcols = 0;
373 
374  /* start diving mode so that the diving LP can be used for all subgradient iterations */
375  SCIP_CALL( SCIPstartDive(scip) );
376 
377  /* store LPI pointer to be able to use LPI functions directly (e.g., setting time limit) */
378  SCIP_CALL( SCIPgetLPI(scip, &(sepadata->lpiwithsoftcuts)) );
379 
380  /* if called for the first time in a restart (including the initial run), set certain sepadata values */
381  if( nruns != runnum )
382  {
383  /* get number of LP iterations of root node's first LP solving */
384  nrootlpiters = SCIPgetNRootFirstLPIterations(scip);
385 
386  /* calculate maximum number of LP iterations allowed for all separation calls in the root node */
387  if( (sepadata->rootlpiterlimitfactor >= 0.0) && !SCIPisInfinity(scip, sepadata->rootlpiterlimitfactor) )
388  sepadata->nmaxrootlpiters = (int)(sepadata->rootlpiterlimitfactor * nrootlpiters);
389  else
390  sepadata->nmaxrootlpiters = -1; /* no finite limit */
391 
392  /* calculate maximum number of LP iterations allowed for all separation calls in the entire tree */
393  if( (sepadata->totallpiterlimitfactor >= 0.0) && !SCIPisInfinity(scip, sepadata->totallpiterlimitfactor) )
394  sepadata->nmaxtotallpiters = (int)(sepadata->totallpiterlimitfactor * nrootlpiters);
395  else
396  sepadata->nmaxtotallpiters = -1; /* no finite limit */
397 
398  /* calculate maximum number of LP iterations allowed per separation call */
399  if( (sepadata->perroundlpiterlimitfactor >= 0.0) && !SCIPisInfinity(scip, sepadata->perroundlpiterlimitfactor) )
400  sepadata->nmaxperroundlpiters = (int)(sepadata->perroundlpiterlimitfactor * nrootlpiters);
401  else
402  sepadata->nmaxperroundlpiters = -1; /* no finite limit */
403 
404  /* update maximum number of LP iterations allowed per separation call using absolute limits */
405  if( sepadata->perroundnmaxlpiters > 0 )
406  sepadata->nmaxperroundlpiters = ((sepadata->nmaxperroundlpiters >= 0) ? MIN(sepadata->nmaxperroundlpiters,
407  sepadata->perroundnmaxlpiters) : sepadata->perroundnmaxlpiters);
408 
409  /* set maximum number of cuts allowed to generate per round in root and non-root nodes as well as the total tree */
410  for( i = 0; i < ncols; ++i )
411  nintcols += SCIPcolIsIntegral(cols[i]);
412 
413  sepadata->nmaxperroundcutsroot = (int)(sepadata->perroundcutsfactorroot * nintcols);
414  sepadata->nmaxperroundcuts = (int)(sepadata->perroundcutsfactor * nintcols);
415 
416  if( sepadata->ncalls == 0 )
417  {
418  sepadata->nmaxtotalcuts = (int)(sepadata->totalcutsfactor * nintcols);
419  sepadata->ntotalcuts = 0;
420  }
421 
422  /* update the run number of solving to represent the restart number in which the above limits were set */
423  sepadata->nrunsinsoftcutslp = runnum;
424  }
425 
426  return SCIP_OKAY;
427 }
428 
429 /** end the diving mode that was used for solving LPs corresponding to the Lagrangian dual with fixed multipliers */
430 static
432  SCIP* scip, /**< SCIP data structure */
433  SCIP_SEPADATA* sepadata /**< separator data structure */
434  )
435 {
436  assert(scip != NULL);
437  assert(sepadata != NULL);
438 
439  SCIP_CALL( SCIPendDive(scip) );
440 
441  return SCIP_OKAY;
442 }
443 
444 /** set up LP interface to solve LPs in the (outer) main loop of the relax-and-cut algorithm; these LPs are built by
445  * adding all the generated cuts to the node relaxation */
446 /* @todo add lpi iters to global statistics */
447 static
449  SCIP* scip, /**< SCIP data structure */
450  SCIP_SEPADATA* sepadata, /**< separator data structure */
451  SCIP_ROW** cuts, /**< generated cuts to be added to the LP */
452  int ncuts /**< number of generated cuts to be added to the LP */
453  )
454 {
455  SCIP_ROW** rows;
456  SCIP_COL** cols;
457  SCIP_Real* collb;
458  SCIP_Real* colub;
459  SCIP_Real* colobj;
460  SCIP_Real* rowlhs;
461  SCIP_Real* rowrhs;
462  SCIP_Real rowconst;
463  SCIP_Real* rowvals;
464  SCIP_Real* rowval;
465  SCIP_COL** rowcols;
466  SCIP_LPI* wslpi;
467  SCIP_LPISTATE* lpistate;
468  BMS_BLKMEM* blkmem;
469  SCIP_Real pinf;
470  SCIP_Real ninf;
471  int nrows;
472  int ncols;
473  int nrownonz;
474  int collppos;
475  int* rowcolinds;
476  int* rowbegs;
477  int i;
478  int j;
479 
480  assert(scip != NULL);
481  assert(sepadata != NULL);
482 
483  SCIP_LPI** lpi = &(sepadata->lpiwithhardcuts);
484  blkmem = SCIPblkmem(scip);
485 
486  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
487  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
488 
489  /* if this function is called for the first time in this separation round, then create an LPI and add cols & rows */
490  if( ncuts == 0 )
491  {
492  if( *lpi != NULL )
493  {
494  SCIP_CALL( SCIPlpiFree(lpi) );
495  *lpi = NULL;
496  }
497  assert(*lpi == NULL);
498 
499  /* create an LPI */
500  SCIP_CALL( SCIPlpiCreate(lpi, SCIPgetMessagehdlr(scip), "node LP with generated cuts", SCIP_OBJSEN_MINIMIZE) );
501 
502  /* add cols to the LP interface */
503  SCIP_CALL( SCIPallocBufferArray(scip, &colobj, ncols) );
504  SCIP_CALL( SCIPallocBufferArray(scip, &collb, ncols) );
505  SCIP_CALL( SCIPallocBufferArray(scip, &colub, ncols) );
506 
507  /* gather required column information */
508  for( i = 0; i < ncols; ++i )
509  {
510  colobj[i] = SCIPcolGetObj(cols[i]);
511  collb[i] = SCIPcolGetLb(cols[i]);
512  colub[i] = SCIPcolGetUb(cols[i]);
513  }
514  /* add cols */
515  SCIP_CALL( SCIPlpiAddCols(*lpi, ncols, colobj, collb, colub, NULL, 0, NULL, NULL, NULL) );
516  SCIPfreeBufferArray(scip, &colub);
517  SCIPfreeBufferArray(scip, &collb);
518  SCIPfreeBufferArray(scip, &colobj);
519 
520  /* add rows to the LP interface */
521  /* find number of nonzeroes in rows */
522  nrownonz = 0;
523  for( i = 0; i < nrows; ++i )
524  {
525  assert(!(SCIPisInfinity(scip, -SCIProwGetLhs(rows[i])) && SCIPisInfinity(scip, SCIProwGetRhs(rows[i]))));
526  nrownonz += SCIProwGetNLPNonz(rows[i]);
527  }
528  SCIP_CALL( SCIPallocBufferArray(scip, &rowcolinds, nrownonz) );
529  SCIP_CALL( SCIPallocBufferArray(scip, &rowvals, nrownonz) );
530  SCIP_CALL( SCIPallocBufferArray(scip, &rowbegs, nrows + 1) );
531  SCIP_CALL( SCIPallocBufferArray(scip, &rowlhs, nrows) );
532  SCIP_CALL( SCIPallocBufferArray(scip, &rowrhs, nrows) );
533 
534  /* gather required row information */
535  rowbegs[0] = 0;
536  pinf = SCIPlpiInfinity(*lpi);
537  ninf = -SCIPlpiInfinity(*lpi);
538  for( i = 0; i < nrows; ++i )
539  {
540  nrownonz = SCIProwGetNLPNonz(rows[i]);
541  assert(nrownonz <= ncols);
542  rowval = SCIProwGetVals(rows[i]);
543  rowcols = SCIProwGetCols(rows[i]);
544 
545  rowbegs[i + 1] = rowbegs[i] + nrownonz;
546  rowconst = SCIProwGetConstant(rows[i]);
547  rowlhs[i] = SCIPisInfinity(scip, -SCIProwGetLhs(rows[i])) ? ninf : SCIProwGetLhs(rows[i]) - rowconst;
548  rowrhs[i] = SCIPisInfinity(scip, SCIProwGetRhs(rows[i])) ? pinf : SCIProwGetRhs(rows[i]) - rowconst;
549 
550  for( j = 0; j < nrownonz; ++j )
551  {
552  collppos = SCIPcolGetLPPos(rowcols[j]);
553  assert(collppos >= 0);
554  assert(collppos <= ncols);
555 
556  rowcolinds[rowbegs[i] + j] = collppos;
557  rowvals[rowbegs[i] + j] = rowval[j];
558  }
559  }
560 
561  /* add rows */
562  SCIP_CALL( SCIPlpiAddRows(*lpi, nrows, rowlhs, rowrhs, NULL, rowbegs[nrows], rowbegs, rowcolinds, rowvals) );
563 
564  /* get warm starting info */
565  SCIP_CALL( SCIPgetLPI(scip, &wslpi) );
566  SCIP_CALL( SCIPlpiGetState(wslpi, blkmem, &lpistate) );
567  }
568  /* if there are any cuts, then add the cuts that were not added earlier to the LPI */
569  else
570  {
571  assert(nrows + ncuts >= sepadata->nrowsinhardcutslp);
572 
573  /* get warm starting info */
574  wslpi = *lpi;
575  SCIP_CALL( SCIPlpiGetState(wslpi, blkmem, &lpistate) );
576 
577  /* find number of nonzeros in cuts and allocate memory */
578  nrownonz = 0;
579  pinf = SCIPlpiInfinity(*lpi);
580  ninf = -SCIPlpiInfinity(*lpi);
581 
582  for( i = sepadata->nrowsinhardcutslp - nrows; i < ncuts; ++i )
583  {
584  assert(!(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && SCIPisInfinity(scip, SCIProwGetRhs(cuts[i]))));
585  assert(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])));
586  assert(!SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])));
587  nrownonz += SCIProwGetNNonz(cuts[i]);
588  }
589  SCIP_CALL( SCIPallocBufferArray(scip, &rowcolinds, nrownonz) );
590  SCIP_CALL( SCIPallocBufferArray(scip, &rowvals, nrownonz) );
591  SCIP_CALL( SCIPallocBufferArray(scip, &rowbegs, (ncuts - sepadata->nrowsinhardcutslp + nrows) + 1) );
592  SCIP_CALL( SCIPallocBufferArray(scip, &rowlhs, (ncuts - sepadata->nrowsinhardcutslp + nrows)) );
593  SCIP_CALL( SCIPallocBufferArray(scip, &rowrhs, (ncuts - sepadata->nrowsinhardcutslp + nrows)) );
594 
595  /* gather required cut information */
596  rowbegs[0] = 0;
597  for( i = sepadata->nrowsinhardcutslp - nrows; i < ncuts; ++i )
598  {
599  nrownonz = SCIProwGetNNonz(cuts[i]);
600  assert(nrownonz <= ncols);
601  rowval = SCIProwGetVals(cuts[i]);
602  rowcols = SCIProwGetCols(cuts[i]);
603 
604  rowbegs[i - sepadata->nrowsinhardcutslp + nrows + 1] = rowbegs[i - sepadata->nrowsinhardcutslp + nrows] +
605  nrownonz;
606  rowconst = SCIProwGetConstant(cuts[i]);
607  rowlhs[i - sepadata->nrowsinhardcutslp + nrows] = SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) ? ninf :
608  SCIProwGetLhs(cuts[i]) - rowconst;
609  rowrhs[i - sepadata->nrowsinhardcutslp + nrows] = SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])) ? pinf :
610  SCIProwGetRhs(cuts[i]) - rowconst;
611 
612  for( j = 0; j < nrownonz; ++j )
613  {
614  collppos = SCIPcolGetLPPos(rowcols[j]);
615  assert(collppos >= 0);
616  assert(collppos <= ncols);
617 
618  rowcolinds[rowbegs[i - sepadata->nrowsinhardcutslp + nrows] + j] = collppos;
619  rowvals[rowbegs[i - sepadata->nrowsinhardcutslp + nrows] + j] = rowval[j];
620  }
621  }
622 
623  /* add cuts */
624  SCIP_CALL( SCIPlpiAddRows(*lpi, (ncuts - sepadata->nrowsinhardcutslp + nrows), rowlhs, rowrhs, NULL,
625  rowbegs[(ncuts - sepadata->nrowsinhardcutslp + nrows)], rowbegs, rowcolinds, rowvals) );
626  }
627 
628  /* set warm starting basis */
629  SCIP_CALL( SCIPlpiSetState(*lpi, blkmem, lpistate) );
630 
631  /* reset remaining sepadata values */
632  sepadata->nrowsinhardcutslp = nrows + ncuts;
633 
634  /* free memory */
635  SCIP_CALL( SCIPlpiFreeState(*lpi, blkmem, &lpistate) );
636  SCIPfreeBufferArray(scip, &rowrhs);
637  SCIPfreeBufferArray(scip, &rowlhs);
638  SCIPfreeBufferArray(scip, &rowbegs);
639  SCIPfreeBufferArray(scip, &rowvals);
640  SCIPfreeBufferArray(scip, &rowcolinds);
641 
642  return SCIP_OKAY;
643 }
644 
645 /** free separator data */
646 static
648  SCIP* scip, /**< SCIP data structure */
649  SCIP_SEPADATA** sepadata /**< separator data structure */
650  )
651 {
652  assert(scip != NULL);
653  assert(sepadata != NULL);
654  assert(*sepadata != NULL);
655 
656  if( (*sepadata)->lpiwithhardcuts != NULL )
657  {
658  SCIP_CALL( SCIPlpiFree(&((*sepadata)->lpiwithhardcuts)) );
659  }
660 
661  (*sepadata)->nrowsinhardcutslp = 0;
662  (*sepadata)->nrunsinsoftcutslp = 0;
663  (*sepadata)->ncalls = 0;
664  (*sepadata)->nmaxperroundlpiters = 0;
665  (*sepadata)->nmaxrootlpiters = 0;
666  (*sepadata)->nrootlpiters = 0;
667  (*sepadata)->nmaxtotallpiters = 0;
668  (*sepadata)->ntotallpiters = 0;
669  (*sepadata)->nmaxperroundcutsroot = 0;
670  (*sepadata)->nmaxperroundcuts = 0;
671  (*sepadata)->nmaxtotalcuts = 0;
672  (*sepadata)->ntotalcuts = 0;
673 
674  SCIPfreeBlockMemory(scip, sepadata);
675 
676  return SCIP_OKAY;
677 }
678 
679 /** update mu parameter which is used as a factor in the step length calculation; refer to the top of the file for a
680  * description of the formula. */
681 /* @todo some adaptive strategy like constant after certain changes? */
682 static
684  SCIP* scip, /**< SCIP data structure */
685  SCIP_SEPADATA* sepadata, /**< separator data structure */
686  int subgradientiternum, /**< subgradient iteration number */
687  SCIP_Real ubparam, /**< estimate of the optimal Lagrangian dual value */
688  SCIP_Real* lagrangianvals, /**< vector of Lagrangian values found so far */
689  SCIP_Real bestlagrangianval, /**< best Lagrangian value found so far */
690  SCIP_Real avglagrangianval, /**< rolling average of the Lagrangian values found so far */
691  SCIP_Real* muparam, /**< mu parameter to be updated */
692  SCIP_Bool* backtrack /**< whether mu parameter has been backtracked */
693  )
694 {
695  SCIP_Real delta;
696  SCIP_Real deltaslab1ub;
697  SCIP_Real deltaslab2ub;
698  SCIP_Real muslab1factor;
699  SCIP_Real muslab2factor;
700  SCIP_Real muslab3factor;
701  int maxiters;
702  int i;
704  assert( backtrack != NULL );
705 
706  *backtrack = FALSE;
707 
708  /* update the mu parameter only if it is not set to be a constant value */
709  if( !sepadata->muparamconst )
710  {
711  delta = ubparam - bestlagrangianval;
712  deltaslab1ub = MIN(sepadata->deltaslab1ub, sepadata->deltaslab2ub);
713  deltaslab2ub = MAX(sepadata->deltaslab1ub, sepadata->deltaslab2ub);
714 
715  /* ensure that the ordering of different user input parameters is as expected */
716  if( SCIPisPositive(scip, sepadata->muslab1factor - sepadata->muslab2factor) )
717  {
718  if( SCIPisPositive(scip, sepadata->muslab2factor - sepadata->muslab3factor) )
719  {
720  muslab1factor = sepadata->muslab1factor;
721  muslab2factor = sepadata->muslab2factor;
722  muslab3factor = sepadata->muslab3factor;
723  }
724  else
725  {
726  if( SCIPisPositive(scip, sepadata->muslab1factor - sepadata->muslab3factor) )
727  {
728  muslab1factor = sepadata->muslab1factor;
729  muslab2factor = sepadata->muslab3factor;
730  muslab3factor = sepadata->muslab2factor;
731  }
732  else
733  {
734  muslab1factor = sepadata->muslab3factor;
735  muslab2factor = sepadata->muslab1factor;
736  muslab3factor = sepadata->muslab2factor;
737  }
738  }
739  }
740  else
741  {
742  if( SCIPisPositive(scip, sepadata->muslab1factor - sepadata->muslab3factor) )
743  {
744  muslab1factor = sepadata->muslab2factor;
745  muslab2factor = sepadata->muslab1factor;
746  muslab3factor = sepadata->muslab3factor;
747  }
748  else
749  {
750  if( SCIPisPositive(scip, sepadata->muslab2factor - sepadata->muslab3factor) )
751  {
752  muslab1factor = sepadata->muslab2factor;
753  muslab2factor = sepadata->muslab3factor;
754  muslab3factor = sepadata->muslab1factor;
755  }
756  else
757  {
758  muslab1factor = sepadata->muslab3factor;
759  muslab2factor = sepadata->muslab2factor;
760  muslab3factor = sepadata->muslab1factor;
761  }
762  }
763  }
764 
765  maxiters = MIN(sepadata->nmaxconsecitersformuupdate, sepadata->nmaxlagrangianvalsforavg);
766  i = -1;
767 
768  /* if certain number of iterations are done, then check for a possibility of backtracking and apply accordingly */
769  if( subgradientiternum >= maxiters )
770  {
771  for( i = subgradientiternum - maxiters; i < subgradientiternum; i++ )
772  {
773  if( SCIPisGE(scip, lagrangianvals[i], bestlagrangianval - delta) )
774  break;
775  }
776 
777  if( i == subgradientiternum )
778  {
779  *muparam *= sepadata->mubacktrackfactor;
780  *backtrack = TRUE;
781  }
782  }
783 
784  /* update mu parameter based on the different between best and average Lagrangian values */
785  if( (subgradientiternum < maxiters) || (i >= 0 && i < subgradientiternum) )
786  {
787  if( bestlagrangianval - avglagrangianval < deltaslab1ub * delta )
788  *muparam *= muslab1factor;
789  else if( bestlagrangianval - avglagrangianval < deltaslab2ub * delta )
790  *muparam *= muslab2factor;
791  else
792  *muparam *= muslab3factor;
793  }
794 
795  /* reset the mu parameter to within its bounds */
796  *muparam = MAX(*muparam, sepadata->muparamlb);
797  *muparam = MIN(*muparam, sepadata->muparamub);
798  }
799 
800  return SCIP_OKAY;
801 }
802 
803 /** update subgradient, i.e., residuals of generated cuts
804  * @note assuming that \f$i^{th}\f$ cut is of the form \f${\alpha^i}^T x \leq {\alpha^i_0}\f$.
805  */
806 static
807 void updateSubgradient(
808  SCIP* scip, /**< SCIP data structure */
809  SCIP_SOL* sol, /**< LP solution used in updating subgradient vector */
810  SCIP_ROW** cuts, /**< cuts generated so far */
811  int ncuts, /**< number of cuts generated so far */
812  SCIP_Real* subgradient, /**< vector of subgradients to be updated */
813  SCIP_Real* dualvector, /**< Lagrangian multipliers */
814  SCIP_Bool* subgradientzero, /**< whether the subgradient vector is all zero */
815  int* ncutviols, /**< number of violations of generated cuts */
816  SCIP_Real* maxcutviol, /**< maximum violation of generated cuts */
817  int* nnzsubgradientdualprod, /**< number of nonzero products of subgradient vector and Lagrangian multipliers (i.e.,
818  * number of complementarity slackness violations) */
819  SCIP_Real* maxnzsubgradientdualprod /**< maximum value of nonzero products of subgradient vector and Lagrangian multipliers
820  * (i.e., maximum value of complementarity slackness violations) */
821  )
822 {
823  int nzerosubgradient;
824  SCIP_Real term;
825  int i;
826 
827  assert(subgradientzero != NULL);
828  assert(ncutviols != NULL);
829  assert(maxcutviol != NULL);
830  assert(nnzsubgradientdualprod != NULL);
831  assert(maxnzsubgradientdualprod != NULL);
832 
833  *ncutviols = 0;
834  *maxcutviol = 0.0;
835  *nnzsubgradientdualprod = 0;
836  *maxnzsubgradientdualprod = 0.0;
837  nzerosubgradient = 0;
838  *subgradientzero = FALSE;
839 
840  /* for each cut, calculate the residual along with various violation metrics */
841  for( i = 0; i < ncuts; i++ )
842  {
843  assert(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])));
844  assert(!SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])));
845  subgradient[i] = SCIPgetRowSolActivity(scip, cuts[i], sol) + SCIProwGetConstant(cuts[i]) - SCIProwGetRhs(cuts[i]);
846 
847  if( SCIPisFeasZero(scip, subgradient[i]) )
848  {
849  subgradient[i] = 0.0;
850  nzerosubgradient++;
851  }
852  else
853  {
854  /* check for cut violation */
855  if( SCIPisFeasPositive(scip, subgradient[i]) )
856  {
857  (*ncutviols)++;
858  *maxcutviol = MAX(*maxcutviol, subgradient[i]);
859  }
860 
861  /* check for violation of complementarity slackness associated with the cut */
862  if( !SCIPisZero(scip, subgradient[i] * dualvector[i]) )
863  {
864  (*nnzsubgradientdualprod)++;
865  term = REALABS(subgradient[i] * dualvector[i]);
866  *maxnzsubgradientdualprod = MAX(*maxnzsubgradientdualprod, term);
867  }
868  }
869  }
870 
871  /* indicator for all zero subgradient vector */
872  if( nzerosubgradient == ncuts )
873  *subgradientzero = TRUE;
874 }
875 
876 /** update Lagrangian value, i.e., optimal value of the Lagrangian dual with fixed multipliers */
877 static
879  SCIP* scip, /**< SCIP data structure */
880  SCIP_Real objval, /**< objective value of the Lagrangian dual with fixed multipliers */
881  SCIP_Real* dualvector, /**< Lagrangian multipliers */
882  SCIP_ROW** cuts, /**< cuts generated so far */
883  int ncuts, /**< number of cuts generated so far */
884  SCIP_Real* lagrangianval /**< Lagrangian value to be updated */
885  )
886 {
887  int i;
888 
889  assert(lagrangianval != NULL);
890 
891  *lagrangianval = objval;
892 
893  for( i = 0; i < ncuts; i++ )
894  {
895  assert(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])));
896  assert(!SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])));
897  *lagrangianval += dualvector[i] * (SCIProwGetConstant(cuts[i]) - SCIProwGetRhs(cuts[i]));
898  }
899 }
900 
901 /** update step length based on various input arguments; refer to the top of the file for an expression */
902 static
903 void updateStepLength(
904  SCIP* scip, /**< SCIP data structure */
905  SCIP_Real muparam, /**< mu parameter used as a factor for step length */
906  SCIP_Real ubparam, /**< estimate of the optimal Lagrangian dual value */
907  SCIP_Real lagrangianval, /**< Lagrangian value */
908  SCIP_Real* subgradient, /**< subgradient vector */
909  int ncuts, /**< number of cuts generated so far */
910  SCIP_Real* steplength /**< step length to be updated */
911  )
912 {
913  SCIP_Real normsquared = 0.0;
914  int i;
915 
916  for( i = 0; i < ncuts; i++ )
917  normsquared += SQR(subgradient[i]);
918 
919  if( !SCIPisFeasZero(scip, normsquared) )
920  *steplength = (muparam * (ubparam - lagrangianval))/(normsquared); /*lint !e795*/
921 }
922 
923 /** update the ball radius (based on various violation metrics) that is used for stabilization of Lagrangian multipliers */
924 static
925 void updateBallRadius(
926  SCIP* scip, /**< SCIP data structure */
927  SCIP_SEPADATA* sepadata, /**< separator data structure */
928  SCIP_Real maxviolscore, /**< weighted average of maximum value of generated cut violations and maximum value of
929  * complementarity slackness violations, in the current iteration */
930  SCIP_Real maxviolscoreold, /**< weighted average of maximum value of generated cut violations and maximum value of
931  * complementarity slackness violations, in the previous iteration */
932  SCIP_Real nviolscore, /**< weighted average of number of generated cut violations and number of complementarity
933  * slackness violations, in the current iteration */
934  SCIP_Real nviolscoreold, /**< weighted average of number of generated cut violations and number of complementarity
935  * slackness violations, in the previous iteration */
936  int nlpiters, /**< number of LP iterations taken for solving the Lagrangian dual with fixed multipliers in
937  * current iteration */
938  SCIP_Real* ballradius /**< norm ball radius to be updated */
939  )
940 {
941  SCIP_Bool maxviolscoreimproved;
942  SCIP_Bool nviolscoreimproved;
943 
944  assert(ballradius != NULL);
946  maxviolscoreimproved = !SCIPisNegative(scip, maxviolscoreold - maxviolscore);
947  nviolscoreimproved = !SCIPisNegative(scip, nviolscoreold - nviolscore);
948 
949  if( maxviolscoreimproved && nviolscoreimproved )
950  {
951  /* both the maximum violation and number of violations scores have become better, so, increase the radius */
952  if( sepadata->optimalfacepriority <= 1 )
953  {
954  *ballradius *= 2.0;
955  *ballradius = MIN(*ballradius, sepadata->radiusmax);
956  }
957  else
958  {
959  *ballradius *= 1.5;
960  *ballradius = MIN(*ballradius, sepadata->radiusmax/2.0);
961  }
962  }
963  else if( !maxviolscoreimproved && !nviolscoreimproved )
964  {
965  /* both the maximum violation and number of violations scores have become worse, so, decrease the radius */
966  *ballradius *= 0.5;
967  *ballradius = MAX(*ballradius, sepadata->radiusmin);
968  }
969  else if( nlpiters == 0 )
970  {
971  /* only one among the maximum violation and number of violations scores has become better, and the LP basis did
972  * not change (i.e., nlpters = 0), so, increase the radius slightly */
973  if( sepadata->optimalfacepriority <= 1 )
974  {
975  *ballradius *= 1.5;
976  *ballradius = MIN(*ballradius, sepadata->radiusmax);
977  }
978  else
979  {
980  *ballradius *= 1.2;
981  *ballradius = MIN(*ballradius, sepadata->radiusmax/2.0);
982  }
983  }
984 }
985 
986 /** projection of Lagrangian multipliers onto L1-norm ball. This algorithm is based on the following article
987  *
988  * Condat L. (2016).@n
989  * Fast projection onto the simplex and the \f$l_1\f$ ball.@n
990  * Mathematical Programming, 158, 1-2, 575-585.
991  *
992  */
993 static
995  SCIP* scip, /**< SCIP data structure */
996  SCIP_Real* dualvector, /**< Lagrangian multipliers to be projected onto L1-norm vall */
997  int dualvectorlen, /**< length of the Lagrangian multipliers vector */
998  SCIP_Real radius /**< radius of the L1-norm ball */
999  )
1000 {
1001  SCIP_Real* temp1vals;
1002  SCIP_Real* temp2vals;
1003  SCIP_Real pivotparam;
1004  SCIP_Real val;
1005  SCIP_Real term;
1006  SCIP_Bool temp1changed;
1007  int ntemp1removed;
1008  int* temp1inds;
1009  int* temp2inds;
1010  int temp1len;
1011  int temp2len;
1012  int i;
1013  int j;
1015  assert(!SCIPisNegative(scip, radius));
1016  val = REALABS(dualvector[0]);
1017 
1018  /* calculate the L1-norm of the Lagrangian multipliers */
1019  for( i = 1; i < dualvectorlen; i++ )
1020  val += REALABS(dualvector[i]);
1021 
1022  /* if the vector of Lagrangian multipliers lies outside the L1-norm ball, then do the projection */
1023  if( SCIPisGT(scip, val, radius) )
1024  {
1025  SCIP_CALL( SCIPallocCleanBufferArray(scip, &temp1vals, dualvectorlen) );
1026  SCIP_CALL( SCIPallocCleanBufferArray(scip, &temp2vals, dualvectorlen) );
1027  SCIP_CALL( SCIPallocBufferArray(scip, &temp1inds, dualvectorlen) );
1028  SCIP_CALL( SCIPallocBufferArray(scip, &temp2inds, dualvectorlen) );
1029  for( i = 0; i < dualvectorlen; i++ )
1030  {
1031  temp1inds[i] = -1;
1032  temp2inds[i] = -1;
1033  }
1034  temp2len = 0;
1035 
1036  temp1vals[0] = REALABS(dualvector[0]);
1037  temp1inds[0] = 0;
1038  temp1len = 1;
1039  pivotparam = REALABS(dualvector[0]) - radius;
1040 
1041  for( i = 1; i < dualvectorlen; i++ )
1042  {
1043  if( SCIPisGT(scip, REALABS(dualvector[i]), pivotparam) )
1044  {
1045  pivotparam += ((REALABS(dualvector[i]) - pivotparam) / (temp1len + 1));
1046  if( SCIPisGT(scip, pivotparam, REALABS(dualvector[i]) - radius) )
1047  {
1048  temp1vals[temp1len] = REALABS(dualvector[i]);
1049  temp1inds[temp1len] = i;
1050  temp1len++;
1051  }
1052  else
1053  {
1054  for( j = 0; j < temp1len; j++ )
1055  {
1056  temp2vals[temp2len + j] = temp1vals[j];
1057  temp2inds[temp2len + j] = temp1inds[j];
1058  }
1059  temp2len += temp1len;
1060  temp1vals[0] = REALABS(dualvector[i]);
1061  temp1inds[0] = i;
1062  temp1len = 1;
1063  pivotparam = REALABS(dualvector[i]) - radius;
1064  }
1065  }
1066  }
1067 
1068  for( i = 0; i < temp2len; i++ )
1069  {
1070  if( SCIPisGT(scip, temp2vals[i], pivotparam) )
1071  {
1072  temp1vals[temp1len] = temp2vals[i];
1073  temp1inds[temp1len] = temp2inds[i];
1074  temp1len++;
1075  pivotparam += ((temp2vals[i] - pivotparam) / temp1len);
1076  }
1077  }
1078 
1079  temp1changed = TRUE;
1080  ntemp1removed = 0;
1081  while( temp1changed )
1082  {
1083  temp1changed = FALSE;
1084 
1085  for( i = 0; i < temp1len; i++ )
1086  {
1087  /* @note the third condition (temp1len - ntemp1removed > 0) is true as long as the first condition
1088  * (temp1inds[i] >= 0) is true.
1089  */
1090  if( (temp1inds[i] >= 0) && SCIPisLE(scip, temp1vals[i], pivotparam) )
1091  {
1092  temp1inds[i] = -1;
1093  temp1changed = TRUE;
1094  ntemp1removed++;
1095  assert(temp1len - ntemp1removed > 0);
1096  /* coverity[divide_by_zero] */
1097  pivotparam += ((pivotparam - temp1vals[i]) / (temp1len - ntemp1removed));
1098  }
1099  }
1100  }
1101 
1102  for( i = 0; i < dualvectorlen; i++ )
1103  {
1104  term = REALABS(dualvector[i]);
1105  val = MAX(term - pivotparam, 0.0);
1106 
1107  if( SCIPisPositive(scip, dualvector[i]) )
1108  {
1109  dualvector[i] = val;
1110  }
1111  else if( SCIPisNegative(scip, dualvector[i]) )
1112  {
1113  dualvector[i] = -val;
1114  }
1115  }
1116 
1117  /* free memory */
1118  for( i = 0; i < dualvectorlen; i++ )
1119  {
1120  temp2vals[i] = 0.0;
1121  temp1vals[i] = 0.0;
1122  }
1123  SCIPfreeBufferArray(scip, &temp2inds);
1124  SCIPfreeBufferArray(scip, &temp1inds);
1125  SCIPfreeCleanBufferArray(scip, &temp2vals);
1126  SCIPfreeCleanBufferArray(scip, &temp1vals);
1127  }
1128 
1129  return SCIP_OKAY;
1130 }
1131 
1132 /** projection of Lagrangian multipliers onto L2-norm ball */
1133 static
1134 void l2BallProjection(
1135  SCIP* scip, /**< SCIP data structure */
1136  SCIP_Real* dualvector, /**< Lagrangian multipliers to be projected onto L2-norm vall */
1137  int dualvectorlen, /**< length of the Lagrangian multipliers vector */
1138  SCIP_Real radius /**< radius of the L2-norm ball */
1139  )
1140 {
1141  SCIP_Real l2norm;
1142  SCIP_Real factor;
1143  int i;
1144 
1145  assert(!SCIPisNegative(scip, radius));
1146 
1147  l2norm = 0.0;
1148 
1149  /* calculate the L2-norm of the Lagrangian multipliers */
1150  for( i = 0; i < dualvectorlen; i++ )
1151  l2norm += SQR(dualvector[i]);
1152  l2norm = sqrt(l2norm);
1153  factor = radius/(1.0 + l2norm);
1155  /* if the vector of Lagrangian multipliers is outside the L2-norm ball, then do the projection */
1156  if( SCIPisGT(scip, l2norm, radius) && SCIPisLT(scip, factor, 1.0) )
1157  {
1158  for( i = 0; i < dualvectorlen; i++ )
1159  dualvector[i] *= factor;
1160  }
1161 }
1162 
1163 /** projection of Lagrangian multipliers onto L_infinity-norm ball */
1164 static
1165 void linfBallProjection(
1166  SCIP* scip, /**< SCIP data structure */
1167  SCIP_Real* dualvector, /**< Lagrangian multipliers to be projected onto L_infinity-norm vall */
1168  int dualvectorlen, /**< length of the Lagrangian multipliers vector */
1169  SCIP_Real radius /**< radius of the L_infinity-norm ball */
1170  )
1171 {
1172  int i;
1173 
1174  assert(!SCIPisNegative(scip, radius));
1175 
1176  /* if the vector of Lagrangian multipliers is outside the L_infinity-norm ball, then do the projection */
1177  for( i = 0; i < dualvectorlen; i++ )
1178  {
1179  if( SCIPisLT(scip, dualvector[i], -radius) )
1180  dualvector[i] = -radius;
1181  else if( SCIPisGT(scip, dualvector[i], radius) )
1182  dualvector[i] = radius;
1183  }
1184 }
1186 /** weighted Lagrangian multipliers based on a given vector as stability center */
1187 /* @todo calculate weight outside this function and pass it (so that this function becomes generic and independent of
1188  * the terminology related to best Lagrangian multipliers)
1189  */
1190 static
1191 void weightedDualVector(
1192  SCIP_SEPADATA* sepadata, /**< separator data structure */
1193  SCIP_Real* dualvector, /**< Lagrangian multipliers */
1194  int dualvectorlen, /**< length of the Lagrangian multipliers vector */
1195  SCIP_Real* stabilitycenter, /**< stability center (i.e., core vector of Lagrangian multipliers) */
1196  int stabilitycenterlen, /**< length of the stability center */
1197  int nbestdualupdates, /**< number of best Lagrangian values found so far */
1198  int totaliternum /**< total number of iterations of the relax-and-cut algorithm performed so far */
1199  )
1200 {
1201  SCIP_Real constant;
1202  SCIP_Real weight;
1203  SCIP_Real alpha;
1204  int i;
1205 
1206  constant = MAX(2.0, sepadata->constant);
1207 
1208  /* weight factor from the literature on Dantzig-Wolfe decomposition stabilization schemes */
1209  weight = MIN(constant, (totaliternum + 1 + nbestdualupdates) / 2.0);
1210  alpha = 1.0 / weight;
1212  assert(dualvectorlen >= stabilitycenterlen);
1213 
1214  /* weighted Lagrangian multipliers */
1215  for( i = 0; i < stabilitycenterlen; i++ )
1216  dualvector[i] = alpha * dualvector[i] + (1 - alpha) * stabilitycenter[i];
1217 
1218  for( i = stabilitycenterlen; i < dualvectorlen; i++ )
1219  dualvector[i] = alpha * dualvector[i];
1220 }
1221 
1222 /** stabilize Lagrangian multipliers */
1223 static
1225  SCIP* scip, /**< SCIP data structure */
1226  SCIP_SEPADATA* sepadata, /**< separator data structure */
1227  SCIP_Real* dualvector, /**< Lagrangian multipliers */
1228  int dualvectorlen, /**< length of the Lagrangian multipliers vector */
1229  SCIP_Real* bestdualvector, /**< best Lagrangian multipliers found so far */
1230  int bestdualvectorlen, /**< length of the best Lagrangian multipliers vector */
1231  int nbestdualupdates, /**< number of best Lagrangian values found so far */
1232  int subgradientiternum, /**< iteration number of the subgradient algorithm */
1233  int totaliternum, /**< total number of iterations of the relax-and-cut algorithm performed so far */
1234  SCIP_Real maxviolscore, /**< weighted average of maximum value of generated cut violations and maximum value of
1235  * complementarity slackness violations, in the current iteration */
1236  SCIP_Real maxviolscoreold, /**< weighted average of maximum value of generated cut violations and maximum value of
1237  * complementarity slackness violations, in the previous iteration */
1238  SCIP_Real nviolscore, /**< weighted average of number of generated cut violations and number of complementarity
1239  * slackness violations, in the current iteration */
1240  SCIP_Real nviolscoreold, /**< weighted average of number of generated cut violations and number of complementarity
1241  * slackness violations, in the previous iteration */
1242  int nlpiters, /**< number of LP iterations taken for solving the Lagrangian dual with fixed multipliers in
1243  * current iteration */
1244  SCIP_Real* ballradius /**< norm ball radius */
1245  )
1246 {
1247  if( sepadata->projectiontype > 0 )
1248  {
1249  if( subgradientiternum >= 1 )
1250  {
1251  /* update the ball radius */
1252  updateBallRadius(scip, sepadata, maxviolscore, maxviolscoreold, nviolscore, nviolscoreold, nlpiters,
1253  ballradius);
1254  }
1255 
1256  if( sepadata->projectiontype == 1 )
1257  {
1258  /* projection of Lagrangian multipliers onto L1-norm ball */
1259  SCIP_CALL( l1BallProjection(scip, dualvector, dualvectorlen, *ballradius) );
1260  }
1261  else if( sepadata->projectiontype == 2 )
1262  {
1263  /* projection of Lagrangian multipliers onto L2-norm ball */
1264  l2BallProjection(scip, dualvector, dualvectorlen, *ballradius);
1265  }
1266  else if( sepadata->projectiontype == 3 )
1267  {
1268  /* projection of Lagrangian multipliers onto L_inf-norm ball */
1269  linfBallProjection(scip, dualvector, dualvectorlen, *ballradius);
1270  }
1271  }
1272 
1273  if( sepadata->stabilitycentertype == 1 )
1274  {
1275  /* weighted Lagrangian multipliers based on best Langrangian multipliers as stability center */
1276  weightedDualVector(sepadata, dualvector, dualvectorlen, bestdualvector, bestdualvectorlen, nbestdualupdates, totaliternum);
1277  }
1278 
1279  return SCIP_OKAY;
1280 }
1281 
1282 /** update Lagrangian multipliers */
1283 static
1285  SCIP* scip, /**< SCIP data structure */
1286  SCIP_SEPADATA* sepadata, /**< separator data structure */
1287  SCIP_Real* dualvector1, /**< Lagrangian multipliers vector to be updated */
1288  SCIP_Real* dualvector2, /**< Lagrangian multipliers vector used for backtracking */
1289  int dualvector2len, /**< length of the Lagrangian multipliers vector used for backtracking */
1290  int ndualvector2updates,/**< number of best Lagrangian values found so far */
1291  int subgradientiternum, /**< iteration number of the subgradient algorithm */
1292  int totaliternum, /**< total number of iterations of the relax-and-cut algorithm performed so far */
1293  SCIP_Real steplength, /**< step length used for updating Lagrangian multipliers */
1294  SCIP_Real* subgradient, /**< subgradient vector */
1295  int ncuts, /**< number of generated cuts so far */
1296  SCIP_Bool backtrack, /**< whether the Lagrangian multipliers need to be backtracked */
1297  SCIP_Real maxviolscore, /**< weighted average of maximum value of generated cut violations and maximum value of
1298  * complementarity slackness violations, in the current iteration */
1299  SCIP_Real maxviolscoreold, /**< weighted average of maximum value of generated cut violations and maximum value of
1300  * complementarity slackness violations, in the previous iteration */
1301  SCIP_Real nviolscore, /**< weighted average of number of generated cut violations and number of complementarity
1302  * slackness violations, in the current iteration */
1303  SCIP_Real nviolscoreold, /**< weighted average of number of generated cut violations and number of complementarity
1304  * slackness violations, in the previous iteration */
1305  int nlpiters, /**< number of LP iterations taken for solving the Lagrangian dual with fixed multipliers in
1306  * current iteration */
1307  SCIP_Bool* dualvecsdiffer, /**< whether the updated Lagrangian multipliers differ from the old one */
1308  SCIP_Real* ballradius /**< norm ball radius */
1309  )
1310 {
1311  SCIP_Real* dualvector1copy;
1312  int i;
1313 
1314  assert(dualvector2len <= ncuts);
1315  assert(dualvecsdiffer != NULL);
1316 
1317  *dualvecsdiffer = FALSE;
1318 
1319  /* @todo do allocation and free operations outside only once instead of every time this function is called? */
1320  /* copy of the Lagrangian multipliers to be used to check if the updated vector is different than this */
1321  SCIP_CALL( SCIPallocCleanBufferArray(scip, &dualvector1copy, ncuts) );
1322  for( i = 0; i < ncuts; i++ )
1323  dualvector1copy[i] = dualvector1[i];
1324 
1325  /* if backtracking was not identified at the time of the mu parameter update, then update the Lagrangian multipliers
1326  * based on the given subgradient vector
1327  */
1328  if( !backtrack )
1329  {
1330  assert((subgradient != NULL) || (ncuts == 0));
1331  assert(subgradientiternum >= 0);
1332 
1333  /* update Lagrangian multipliers */
1334  for( i = 0; i < ncuts; i++ )
1335  {
1336  assert(subgradient != NULL); /* for lint */
1337  dualvector1[i] += steplength * subgradient[i];
1338  }
1339 
1340  /* projection onto non-negative orthant */
1341  for( i = 0; i < ncuts; i++ )
1342  {
1343  assert(dualvector1 != NULL); /* for lint */
1344  dualvector1[i] = MAX(dualvector1[i], 0.0);
1345  }
1346 
1347  /* stabilization of Lagrangian multipliers */
1348  SCIP_CALL( stabilizeDualVector(scip, sepadata, dualvector1, ncuts, dualvector2, dualvector2len,
1349  ndualvector2updates, subgradientiternum, totaliternum, maxviolscore, maxviolscoreold, nviolscore,
1350  nviolscoreold, nlpiters, ballradius) );
1351 
1352  /* projection onto non-negative orthant again in case stabilization changed some components negative*/
1353  for( i = 0; i < ncuts; i++ )
1354  dualvector1[i] = MAX(dualvector1[i], 0.0);
1355  }
1356  /* if backtracking was identified at the time of the mu parameter update, then backtrack the Lagrangian multipliers
1357  * based on the given backtracking multipliers
1358  */
1359  else
1360  {
1361  for( i = 0; i < dualvector2len; i++ )
1362  dualvector1[i] = dualvector2[i];
1363 
1364  for( i = dualvector2len; i < ncuts; i++ )
1365  dualvector1[i] = 0.0;
1366  }
1367 
1368  /* identify if the vector of Lagrangian multipliers is indeed different after updating */
1369  for( i = 0; i < ncuts; i++ )
1370  {
1371  if( !SCIPisEQ(scip, dualvector1[i], dualvector1copy[i]) )
1372  {
1373  *dualvecsdiffer = TRUE;
1374  break;
1375  }
1376  }
1377 
1378  /* free memory */
1379  for( i = 0; i < ncuts; i++ )
1380  dualvector1copy[i] = 0.0;
1381 
1382  SCIPfreeCleanBufferArray(scip, &dualvector1copy);
1383 
1384  return SCIP_OKAY;
1385 }
1386 
1387 /** check different termination criteria
1388  * @note the criterion based on objvecsdiffer assumes deterministic solving process (i.e., we would get same LP solution
1389  * for "Lagrangian dual with fixed Lagrangian multipliers" when the objective vector remains the same across iterations).
1390  */
1391 /* @todo nlpssolved criterion? */
1392 static
1394  SCIP_SEPADATA* sepadata, /**< separator data structure */
1395  int nnewaddedsoftcuts, /**< number of cuts that were recently penalized and added to the Lagrangian dual's
1396  * objective function */
1397  int nyettoaddsoftcuts, /**< number of cuts that are yet to be penalized and added to the Lagrangian dual's
1398  * objective function */
1399  SCIP_Bool objvecsdiffer, /**< whether the Lagrangian dual's objective function has changed */
1400  int ngeneratedcurrroundcuts, /**< number of cuts generated in the current separation round */
1401  int nmaxgeneratedperroundcuts, /**< maximal number of cuts allowed to generate per separation round */
1402  int ncurrroundlpiters, /**< number of separating LP iterations in the current separation round */
1403  int depth, /**< depth of the current node */
1404  SCIP_Bool* terminate /**< whether to terminate the subgradient algorithm loop */
1405  )
1406 {
1407  *terminate = FALSE;
1408 
1409  /* check if no new cuts were added to the Lagrangian dual, no cuts are remaining to be added, and the objective
1410  * function of the Lagrangian dual with fixed multipliers had not changed from the previous iteration
1411  */
1412  if( (nnewaddedsoftcuts == 0) && (nyettoaddsoftcuts == 0) && !objvecsdiffer )
1413  *terminate = TRUE;
1414 
1415  /* check if allowed number of cuts in this separation round have already been generated */
1416  if( ngeneratedcurrroundcuts >= nmaxgeneratedperroundcuts )
1417  *terminate = TRUE;
1418 
1419  /* check if allowed number of cuts in the tree have already been generated */
1420  if( sepadata->ntotalcuts >= sepadata->nmaxtotalcuts )
1421  *terminate = TRUE;
1422 
1423  /* check if allowed number of simplex iterations in this separation round have already been used up */
1424  if( (sepadata->nmaxperroundlpiters >= 0) && (ncurrroundlpiters >= sepadata->nmaxperroundlpiters) )
1425  *terminate = TRUE;
1426 
1427  /* check if allowed number of simplex iterations in the root node have already been used up */
1428  if( (depth == 0) && (sepadata->nmaxrootlpiters >= 0) && (sepadata->nrootlpiters >= sepadata->nmaxrootlpiters) )
1429  *terminate = TRUE;
1430 
1431  /* check if allowed number of simplex iterations in the tree have already been used up */
1432  if( (sepadata->nmaxtotallpiters >= 0) && (sepadata->ntotallpiters >= sepadata->nmaxtotallpiters) )
1433  *terminate = TRUE;
1434 
1435  return SCIP_OKAY;
1436 }
1437 
1438 /** solve the LP corresponding to the Lagrangian dual with fixed Lagrangian multipliers */
1439 static
1441  SCIP* scip, /**< SCIP data structure */
1442  SCIP_SEPADATA* sepadata, /**< separator data structure */
1443  int depth, /**< depth of the current node in the tree */
1444  SCIP_Real origobjoffset, /**< objective offset in the current node's relaxation */
1445  SCIP_Bool* solfound, /**< whether an LP optimal solution has been found */
1446  SCIP_SOL* sol, /**< data structure to store LP optimal solution, if found */
1447  SCIP_Real* solvals, /**< values of the LP optimal solution, if found */
1448  SCIP_Real* objval, /**< optimal objective value of the LP optimal solution, if found */
1449  int* ncurrroundlpiters /**< number of LP iterations taken for solving Lagrangian dual problems with fixed multipliers
1450  * in the current separator round */
1451  )
1452 {
1453  SCIP_Real timelimit;
1454  SCIP_COL** cols;
1455  SCIP_COL* col;
1456  SCIP_VAR* var;
1457  SCIP_LPI* lpi;
1458  SCIP_Bool lperror;
1459  SCIP_Bool cutoff;
1461  SCIP_Longint ntotallpiters;
1462  SCIP_Longint nlpiters;
1463  int ncols;
1464  int iterlimit;
1465 
1466  assert(solfound != NULL);
1467  assert(sol != NULL);
1468  assert(solvals != NULL);
1469  assert(ncurrroundlpiters != NULL);
1470  assert(objval != NULL);
1471 
1472  *solfound = FALSE;
1473  lperror = FALSE;
1474  cutoff = FALSE;
1475  iterlimit = -1;
1476  lpi = sepadata->lpiwithsoftcuts;
1477 
1478  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1479 
1480  /* set time limit */
1481  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1482  if( !SCIPisInfinity(scip, timelimit) )
1483  {
1484  timelimit -= SCIPgetSolvingTime(scip);
1485  if( timelimit <= 0.0 )
1486  {
1487  SCIPdebugMsg(scip, "skip Lagromory cut generation since no time left\n");
1488  goto TERMINATE;
1489  }
1490 
1491  /* @note the following direct LPI call is being used because of the lack of an equivalent function call in
1492  * scip_lp.c (lpSetRealpar exists in lp.c though)
1493  */
1494  SCIP_CALL( SCIPlpiSetRealpar(lpi, SCIP_LPPAR_LPTILIM, timelimit) );
1495  }
1496 
1497  /* find iteration limit */
1498  if( (depth == 0) &&
1499  (sepadata->perrootlpiterfactor >= 0.0 && !SCIPisInfinity(scip, sepadata->perrootlpiterfactor)) )
1500  {
1501  iterlimit = (int)(sepadata->perrootlpiterfactor * SCIPgetNRootFirstLPIterations(scip));
1502  }
1503  else if( (depth > 0) &&
1504  (sepadata->perlpiterfactor >= 0.0 && !SCIPisInfinity(scip, sepadata->perlpiterfactor)) )
1505  {
1506  iterlimit = (int)(sepadata->perlpiterfactor * SCIPgetNNodeInitLPIterations(scip));
1507  }
1508  if( sepadata->nmaxperroundlpiters >= 0 )
1509  {
1510  if( sepadata->nmaxperroundlpiters - *ncurrroundlpiters >= 0 )
1511  {
1512  if( iterlimit >= 0 )
1513  iterlimit = MIN(iterlimit, sepadata->nmaxperroundlpiters - *ncurrroundlpiters);
1514  else
1515  iterlimit = sepadata->nmaxperroundlpiters - *ncurrroundlpiters;
1516  }
1517  else
1518  iterlimit = 0;
1519  }
1520  /* @todo impose a finite iteration limit only when the dualvector changes from zero to non-zero for the first time because
1521  * many simplex pivots are performed in this case even with warm starting (compared to the case when the
1522  * dualvector changes from non-zero to non-zero)
1523  */
1524 
1525  /* solve the LP with an iteration limit and get number of simplex iterations taken */
1526  ntotallpiters = SCIPgetNLPIterations(scip);
1527 
1528  SCIP_CALL( SCIPsolveDiveLP(scip, iterlimit, &lperror, &cutoff) );
1529 
1530  nlpiters = SCIPgetNLPIterations(scip) - ntotallpiters;
1531 
1532  /* get the solution and objective value if optimal */
1533  stat = SCIPgetLPSolstat(scip);
1534 
1535  /* @todo is there any way to accept terminations due to iterlimit and timelimit as well? It is not possible
1536  * currently because primal sol is not saved in these cases.
1537  */
1538  /* @note ideally, only primal feasibility is sufficient. But, there is no such option with SCIPgetLPSolstat. */
1539  if( stat == SCIP_LPSOLSTAT_OPTIMAL )
1540  {
1541  if( SCIPisLPSolBasic(scip) )
1542  {
1543  int i;
1544 
1545  *solfound = TRUE;
1546 
1547  /* update sol */
1548  for( i = 0; i < ncols; ++i )
1549  {
1550  col = cols[i];
1551  assert(col != NULL);
1552 
1553  var = SCIPcolGetVar(col);
1554 
1555  solvals[i] = SCIPcolGetPrimsol(col);
1556  SCIP_CALL( SCIPsetSolVal(scip, sol, var, solvals[i]) );
1557  }
1558 
1559  *objval = SCIPgetLPObjval(scip);
1560  *objval = *objval + origobjoffset;
1561  }
1562  }
1563 
1564  /* update some statistics */
1565  if( depth == 0 )
1566  sepadata->nrootlpiters += (int)nlpiters;
1567 
1568  sepadata->ntotallpiters += (int)nlpiters;
1569  *ncurrroundlpiters += (int)nlpiters;
1570 
1571 TERMINATE:
1572  return SCIP_OKAY;
1573 }
1574 
1575 /** solve the LP corresponding to the node relaxation upon adding all the generated cuts */
1576 static
1578  SCIP* scip, /**< SCIP data structure */
1579  SCIP_SEPADATA* sepadata, /**< separator data structure */
1580  SCIP_Bool* solfound, /**< whether an LP optimal solution has been found */
1581  SCIP_SOL* sol, /**< data structure to store LP optimal solution, if found */
1582  SCIP_Real* solvals /**< values of the LP optimal solution, if found */
1583  )
1584 {
1585  SCIP_Real timelimit;
1586  SCIP_COL** cols;
1587  SCIP_COL* col;
1588  SCIP_VAR* var;
1589  int ncols;
1590 
1591  assert(solfound != NULL);
1592  assert(sol != NULL);
1593  assert(solvals != NULL);
1594 
1595  *solfound = FALSE;
1596 
1597  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1598 
1599  /* set time limit */
1600  SCIP_CALL( SCIPgetRealParam(scip, "limits/time", &timelimit) );
1601  if( !SCIPisInfinity(scip, timelimit) )
1602  {
1603  timelimit -= SCIPgetSolvingTime(scip);
1604  if( timelimit <= 0.0 )
1605  {
1606  SCIPdebugMsg(scip, "skip Lagromory cut generation since no time left\n");
1607  goto TERMINATE;
1608  }
1609  SCIP_CALL( SCIPlpiSetRealpar(sepadata->lpiwithhardcuts, SCIP_LPPAR_LPTILIM, timelimit) );
1610  }
1611 
1612  /* solve the LP */
1613  SCIP_CALL( SCIPlpiSolvePrimal(sepadata->lpiwithhardcuts) );
1614 
1615  /* get the solution if primal feasible */
1616  if( SCIPlpiIsPrimalFeasible(sepadata->lpiwithhardcuts) )
1617  {
1618  int i;
1619 
1620  *solfound = TRUE;
1621  SCIP_CALL( SCIPlpiGetSol(sepadata->lpiwithhardcuts, NULL, solvals, NULL, NULL, NULL) );
1622 
1623  /* update sol */
1624  for( i = 0; i < ncols; ++i )
1625  {
1626  col = cols[i];
1627  assert(col != NULL);
1628 
1629  var = SCIPcolGetVar(col);
1630 
1631  SCIP_CALL( SCIPsetSolVal(scip, sol, var, solvals[i]) );
1632  }
1633  }
1634 
1635 TERMINATE:
1636  return SCIP_OKAY;
1637 }
1638 
1639 /** construct a cut based on the input cut coefficients, sides, etc */
1640 static
1642  SCIP* scip, /**< SCIP data structure */
1643  SCIP_SEPA* sepa, /**< pointer to the separator */
1644  SCIP_SEPADATA* sepadata, /**< separator data structure */
1645  int mainiternum, /**< iteration number of the outer loop of the relax-and-cut algorithm */
1646  int subgradientiternum, /**< iteration number of the subgradient algorithm */
1647  int cutnnz, /**< number of nonzeros in cut */
1648  int* cutinds, /**< column indices in cut */
1649  SCIP_Real* cutcoefs, /**< cut cofficients */
1650  SCIP_Real cutefficacy, /**< cut efficacy */
1651  SCIP_Real cutrhs, /**< RHS of cut */
1652  SCIP_Bool cutislocal, /**< whether cut is local */
1653  int cutrank, /**< rank of cut */
1654  SCIP_ROW** generatedcuts, /**< array of generated cuts */
1655  SCIP_Real* generatedcutefficacies, /**< array of generated cut efficacies w.r.t. the respective LP bases used for cut
1656  * generations */
1657  int ngeneratedcurrroundcuts, /**< number of cuts generated until the previous basis in the current separation round */
1658  int* ngeneratednewcuts, /**< number of new cuts generated using the current basis */
1659  SCIP_Bool* cutoff /**< should the current node be cutoff? */
1660  )
1662  SCIP_COL** cols;
1663  SCIP_Real minactivity;
1664  SCIP_Real maxactivity;
1665  SCIP_Real lhs;
1666  SCIP_Real rhs;
1667 
1668  assert(scip != NULL);
1669  assert(mainiternum >= 0);
1670  assert(ngeneratednewcuts != NULL);
1671  assert(cutoff != NULL);
1672 
1673  *cutoff = FALSE;
1674 
1675  if( cutnnz == 0 && SCIPisFeasNegative(scip, cutrhs) ) /*lint !e644*/
1676  {
1677  SCIPdebugMsg(scip, " -> Lagromory cut detected node infeasibility with cut 0 <= %g.\n", cutrhs);
1678  *cutoff = TRUE;
1679  return SCIP_OKAY;
1680  }
1681 
1682  /* only take efficient cuts */
1683  if( SCIPisEfficacious(scip, cutefficacy) )
1684  {
1685  SCIP_ROW* cut;
1686  SCIP_VAR* var;
1687  char cutname[SCIP_MAXSTRLEN];
1688  int v;
1689 
1690  /* construct cut name */
1691  if( subgradientiternum >= 0 )
1692  {
1693  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_%" SCIP_LONGINT_FORMAT "_%d" "_%d" "_%d", SCIPsepaGetName(sepa),
1694  sepadata->ncalls, mainiternum, subgradientiternum, ngeneratedcurrroundcuts + *ngeneratednewcuts);
1695  }
1696  else
1697  {
1698  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s_%" SCIP_LONGINT_FORMAT "_%d" "_%d", SCIPsepaGetName(sepa),
1699  sepadata->ncalls, mainiternum, ngeneratedcurrroundcuts + *ngeneratednewcuts);
1700  }
1701 
1702  /* create empty cut */
1703  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE,
1704  sepadata->dynamiccuts) );
1705 
1706  /* set cut rank */
1707  SCIProwChgRank(cut, cutrank); /*lint !e644*/
1708 
1709  /* cache the row extension and only flush them if the cut gets added */
1710  SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );
1711 
1712  cols = SCIPgetLPCols(scip);
1713 
1714  /* collect all non-zero coefficients */
1715  for( v = 0; v < cutnnz; ++v )
1716  {
1717  var = SCIPcolGetVar(cols[cutinds[v]]);
1718  SCIP_CALL( SCIPaddVarToRow(scip, cut, var, cutcoefs[v]) );
1719  }
1720 
1721  /* flush all changes before adding the cut */
1722  SCIP_CALL( SCIPflushRowExtensions(scip, cut) );
1723 
1724  if( SCIProwGetNNonz(cut) == 0 )
1725  {
1726  assert( SCIPisFeasNegative(scip, cutrhs) );
1727  SCIPdebugMsg(scip, " -> Lagromory cut detected node infeasibility with cut 0 <= %g.\n", cutrhs);
1728  *cutoff = TRUE;
1729  return SCIP_OKAY;
1730  }
1731  else
1732  {
1733  /* gathering lhs and rhs again in case the separator is extended later to add other cuts/constraints that may
1734  * have non-inf lhs or inf rhs */
1735  lhs = SCIProwGetLhs(cut);
1736  rhs = SCIProwGetRhs(cut);
1737  assert(SCIPisInfinity(scip, -lhs));
1738  assert(!SCIPisInfinity(scip, rhs));
1739 
1740  SCIPdebugMsg(scip, " -> %s cut <%s>: rhs=%f, eff=%f\n", "lagromory", cutname, cutrhs, cutefficacy);
1741 
1742  /* check if the cut leads to infeasibility (i.e., *cutoff = TRUE) */
1743  {
1744  /* modifiable cuts cannot be declared infeasible, since we don't know all coefficients */
1745  if( SCIProwIsModifiable(cut) )
1746  *cutoff = FALSE;
1747 
1748  /* check for activity infeasibility */
1749  minactivity = SCIPgetRowMinActivity(scip, cut);
1750  maxactivity = SCIPgetRowMaxActivity(scip, cut);
1751 
1752  if( (!SCIPisInfinity(scip, rhs) && SCIPisFeasPositive(scip, minactivity - rhs)) ||
1753  (!SCIPisInfinity(scip, -lhs) && SCIPisFeasNegative(scip, maxactivity - lhs)) )
1754  {
1755  SCIPdebugMsg(scip, "cut <%s> is infeasible (sides=[%g,%g], act=[%g,%g])\n",
1756  SCIProwGetName(cut), lhs, rhs, minactivity, maxactivity);
1757  *cutoff = TRUE;
1758  }
1759  }
1760 
1761  /* store the newly generated cut in an array and update some statistics */
1762  generatedcuts[ngeneratedcurrroundcuts + *ngeneratednewcuts] = cut;
1763  generatedcutefficacies[ngeneratedcurrroundcuts + *ngeneratednewcuts] = cutefficacy;
1764  ++(*ngeneratednewcuts);
1765  }
1766  }
1767 
1768  return SCIP_OKAY;
1769 }
1770 
1771 /** aggregated generated cuts based on the best Lagrangian multipliers */
1772 static
1774  SCIP* scip, /**< SCIP data structure */
1775  SCIP_SEPA* sepa, /**< pointer to the separator */
1776  SCIP_SEPADATA* sepadata, /**< separator data structure */
1777  SCIP_ROW** generatedcuts, /**< cuts generated in the current separation round */
1778  SCIP_Real* bestdualvector, /**< best Lagrangian multipliers vector */
1779  int bestdualvectorlen, /**< length of the best Lagrangian multipliers vector */
1780  SCIP_ROW** aggrcuts, /**< aggregated cuts generated so far in the current separation round */
1781  int* naggrcuts, /**< number of aggregated cuts generated so far in the current separation round */
1782  SCIP_Bool* cutoff /**< should the current node be cutoff? */
1783  )
1784 {
1785  SCIP_Real* cutvals; /* cut cofficients */
1786  SCIP_COL** cutcols;
1787  SCIP_COL** cols;
1788  SCIP_VAR* var;
1789  SCIP_ROW* cut;
1790  SCIP_ROW* aggrcut;
1791  SCIP_Real minactivity;
1792  SCIP_Real maxactivity;
1793  SCIP_Real cutlhs;
1794  SCIP_Real cutrhs;
1795  SCIP_Real cutconst;
1796  SCIP_Real aggrcutlhs;
1797  SCIP_Real aggrcutrhs;
1798  SCIP_Real aggrcutconst;
1799  SCIP_Real* aggrcutvals;
1800  SCIP_Real* aggrcutcoefs;
1801  SCIP_Real multiplier;
1802  SCIP_Bool aggrcutislocal;
1803  SCIP_Bool aggrindicator;
1804  SCIP_Real* tmpcutvals;
1805  SCIP_Real QUAD(quadterm);
1806  SCIP_Real QUAD(tmpcutconst);
1807  SCIP_Real QUAD(tmpcutrhs);
1808  SCIP_Real QUAD(quadprod);
1809  char aggrcutname[SCIP_MAXSTRLEN];
1810  int cutnnz; /* number of nonzeros in cut */
1811  int aggrcutnnz;
1812  int* aggrcutinds; /* column indices in cut */
1813  int aggrcutrank; /* rank of cut */
1814  int cutrank;
1815  int ncols;
1816  int collppos;
1817  int nlocalcuts;
1818  int i;
1819  int j;
1820 
1821  assert(scip != NULL);
1822  assert(naggrcuts != NULL);
1823  assert(cutoff != NULL);
1824 
1825  *cutoff = FALSE;
1826  aggrcutlhs = -SCIPinfinity(scip);
1827  aggrcutnnz = 0;
1828  aggrcutrank = -1;
1829  nlocalcuts = 0;
1830  aggrindicator = FALSE;
1831 
1832  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
1833 
1834  /* allocate memory */
1835  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tmpcutvals, QUAD_ARRAY_SIZE(ncols)) );
1836  QUAD_ASSIGN(tmpcutconst, 0.0);
1837  QUAD_ASSIGN(tmpcutrhs, 0.0);
1838  SCIP_CALL( SCIPallocCleanBufferArray(scip, &aggrcutvals, ncols) );
1839  SCIP_CALL( SCIPallocBufferArray(scip, &aggrcutcoefs, ncols) );
1840  SCIP_CALL( SCIPallocBufferArray(scip, &aggrcutinds, ncols) );
1841 
1842  /* aggregate cuts based on the input Lagrangian multipliers */
1843  for( i = 0; i < bestdualvectorlen; i++ )
1844  {
1845  multiplier = bestdualvector[i];
1846  if( SCIPisGE(scip, multiplier, 1e-4) )
1847  {
1848  cut = generatedcuts[i];
1849  cutnnz = SCIProwGetNNonz(cut);
1850  cutlhs = SCIProwGetLhs(cut);
1851  cutrhs = SCIProwGetRhs(cut);
1852  assert(SCIPisInfinity(scip, -cutlhs));
1853  assert(!SCIPisInfinity(scip, cutrhs));
1854  cutvals = SCIProwGetVals(cut);
1855  cutcols = SCIProwGetCols(cut);
1856  cutconst = SCIProwGetConstant(cut);
1857 
1858  for( j = 0; j < cutnnz; j++ )
1859  {
1860  collppos = SCIPcolGetLPPos(cutcols[j]);
1861  assert(collppos >= 0);
1862  assert(collppos <= ncols);
1863 
1864  QUAD_ARRAY_LOAD(quadterm, tmpcutvals, collppos);
1865  SCIPquadprecProdDD(quadprod, multiplier, cutvals[j]);
1866  SCIPquadprecSumQQ(quadterm, quadterm, quadprod);
1867  QUAD_ARRAY_STORE(tmpcutvals, collppos, quadterm);
1868  }
1869 
1870  SCIPquadprecProdDD(quadprod, multiplier, cutconst);
1871  SCIPquadprecSumQQ(tmpcutconst, tmpcutconst, quadprod);
1872  SCIPquadprecProdDD(quadprod, multiplier, cutrhs);
1873  SCIPquadprecSumQQ(tmpcutrhs, tmpcutrhs, quadprod);
1874 
1875  cutrank = SCIProwGetRank(cut);
1876  aggrcutrank = MAX(aggrcutrank, cutrank);
1877  nlocalcuts += (SCIProwIsLocal(cut) ? 1 : 0);
1878  aggrindicator = TRUE;
1879  }
1880  }
1881  /* if at least one cut is local, then the aggregated cut is local */
1882  aggrcutislocal = (nlocalcuts > 0 ? TRUE : FALSE);
1883 
1884  /* if the aggregation was successful, then create an empty row and build a cut */
1885  if( aggrindicator )
1886  {
1887  aggrcutconst = QUAD_TO_DBL(tmpcutconst);
1888  aggrcutrhs = QUAD_TO_DBL(tmpcutrhs);
1889 
1890  /* build sparse representation of the aggregated cut */
1891  for( i = 0; i < ncols; i++ )
1892  {
1893  QUAD_ARRAY_LOAD(quadterm, tmpcutvals, i);
1894  aggrcutvals[i] = QUAD_TO_DBL(quadterm);
1895  if( !SCIPisZero(scip, aggrcutvals[i]) )
1896  {
1897  aggrcutcoefs[aggrcutnnz] = aggrcutvals[i];
1898  aggrcutinds[aggrcutnnz] = i;
1899  aggrcutnnz++;
1900  }
1901  }
1902 
1903  if( aggrcutnnz == 0 && SCIPisFeasNegative(scip, aggrcutrhs) ) /*lint !e644*/
1904  {
1905  SCIPdebugMsg(scip, " -> Lagromory cut detected node infeasibility with cut 0 <= %g.\n", aggrcutrhs);
1906  *cutoff = TRUE;
1907  goto TERMINATE;
1908  }
1909 
1910  /* construct aggregated cut name */
1911  (void) SCIPsnprintf(aggrcutname, SCIP_MAXSTRLEN, "%s_%" SCIP_LONGINT_FORMAT "_aggregated", SCIPsepaGetName(sepa),
1912  sepadata->ncalls);
1913 
1914  /* create empty cut */
1915  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &aggrcut, sepa, aggrcutname, aggrcutlhs - aggrcutconst, aggrcutrhs -
1916  aggrcutconst, aggrcutislocal, FALSE, sepadata->dynamiccuts) );
1917 
1918  /* set cut rank */
1919  SCIProwChgRank(aggrcut, aggrcutrank); /*lint !e644*/
1920 
1921  /* cache the row extension and only flush them if the cut gets added */
1922  SCIP_CALL( SCIPcacheRowExtensions(scip, aggrcut) );
1923 
1924  /* collect all non-zero coefficients */
1925  for( i = 0; i < aggrcutnnz; i++ )
1926  {
1927  var = SCIPcolGetVar(cols[aggrcutinds[i]]);
1928  SCIP_CALL( SCIPaddVarToRow(scip, aggrcut, var, aggrcutcoefs[i]) );
1929  }
1930 
1931  /* flush all changes before adding the cut */
1932  SCIP_CALL( SCIPflushRowExtensions(scip, aggrcut) );
1933 
1934  if( SCIProwGetNNonz(aggrcut) == 0 )
1935  {
1936  assert( SCIPisFeasNegative(scip, aggrcutrhs) );
1937  SCIPdebugMsg(scip, " -> Lagromory cut detected node infeasibility with cut 0 <= %g.\n", aggrcutrhs);
1938  *cutoff = TRUE;
1939  goto TERMINATE;
1940  }
1941  else
1942  {
1943  /* gathering lhs and rhs again in case the separator is extended later to add other cuts/constraints that may
1944  * have non-inf lhs or inf rhs */
1945  cutlhs = SCIProwGetLhs(aggrcut);
1946  cutrhs = SCIProwGetRhs(aggrcut);
1947  assert(SCIPisInfinity(scip, -cutlhs));
1948  assert(!SCIPisInfinity(scip, cutrhs));
1949 
1950  SCIPdebugMsg(scip, " -> %s cut <%s>: rhs=%f\n", "lagromory", aggrcutname, aggrcutrhs);
1951 
1952  /* check if the cut leads to infeasibility (i.e., *cutoff = TRUE) */
1953  {
1954  /* modifiable cuts cannot be declared infeasible, since we don't know all coefficients */
1955  if( SCIProwIsModifiable(aggrcut) )
1956  *cutoff = FALSE;
1957 
1958  /* check for activity infeasibility */
1959  minactivity = SCIPgetRowMinActivity(scip, aggrcut);
1960  maxactivity = SCIPgetRowMaxActivity(scip, aggrcut);
1961 
1962  if( (!SCIPisInfinity(scip, cutrhs) && SCIPisFeasPositive(scip, minactivity - cutrhs)) ||
1963  (!SCIPisInfinity(scip, -cutlhs) && SCIPisFeasNegative(scip, maxactivity - cutlhs)) )
1964  {
1965  SCIPdebugMsg(scip, "cut <%s> is infeasible (sides=[%g,%g], act=[%g,%g])\n",
1966  SCIProwGetName(aggrcut), cutlhs, cutrhs, minactivity, maxactivity);
1967  *cutoff = TRUE;
1968  }
1969  }
1970 
1971  /* add the aggregated cut to a separate data structure */
1972  aggrcuts[*naggrcuts] = aggrcut;
1973  (*naggrcuts)++;
1974  }
1975 
1976  QUAD_ASSIGN(quadterm, 0.0);
1977  for( i = 0; i < ncols; i++ )
1978  {
1979  aggrcutvals[i] = 0.0;
1980  QUAD_ARRAY_STORE(tmpcutvals, i, quadterm);
1981  }
1982  }
1983 
1984 TERMINATE:
1985  /* free memory */
1986  SCIPfreeBufferArray(scip, &aggrcutinds);
1987  SCIPfreeBufferArray(scip, &aggrcutcoefs);
1988  SCIPfreeCleanBufferArray(scip, &aggrcutvals);
1989  SCIPfreeCleanBufferArray(scip, &tmpcutvals);
1990 
1991  return SCIP_OKAY;
1992 }
1993 
1994 /** main method: LP solution separation method of separator */
1995 static
1997  SCIP* scip, /**< SCIP data structure */
1998  SCIP_SEPA* sepa, /**< pointer to the separator */
1999  SCIP_SEPADATA* sepadata, /**< separator data structure */
2000  int mainiternum, /**< iteration number of the outer loop of the relax-and-cut algorithm */
2001  int subgradientiternum, /**< iteration number of the subgradient algorithm */
2002  SCIP_SOL* sol, /**< LP solution to be used for cut generation */
2003  SCIP_Real* solvals, /**< values of the LP solution to be used for cut generation */
2004  int nmaxgeneratedperroundcuts, /**< maximal number of cuts allowed to generate per separation round */
2005  SCIP_Bool allowlocal, /**< should locally valid cuts be generated? */
2006  SCIP_ROW** generatedcurrroundcuts, /**< cuts generated in the current separation round */
2007  SCIP_Real* generatedcutefficacies, /**< array of generated cut efficacies w.r.t. the respective LP bases used for cut
2008  * generations */
2009  int ngeneratedcurrroundcuts, /**< number of cuts generated until the previous basis in the current separation round */
2010  int* ngeneratednewcuts, /**< number of new cuts generated using the current basis */
2011  int depth, /**< depth of the current node in the tree */
2012  SCIP_Bool* cutoff /**< should the current node be cutoff? */
2013  )
2014 {
2015  SCIP_Real minfrac;
2016  SCIP_Real maxfrac;
2017  SCIP_Real frac;
2018  SCIP_Real* basisfrac;
2019  SCIP_Real* binvrow;
2020  SCIP_AGGRROW* aggrrow;
2021  SCIP_Bool success;
2022  SCIP_Real* cutcoefs;
2023  SCIP_Real cutrhs;
2024  SCIP_Real cutefficacy;
2025  SCIP_Bool cutislocal;
2026  SCIP_ROW** rows;
2027  SCIP_COL** cols;
2028  SCIP_VAR* var;
2029  SCIP_ROW* row;
2030  int cutrank;
2031  int cutnnz;
2032  int* cutinds;
2033  int* basisind;
2034  int* inds;
2035  int nrows;
2036  int ncols;
2037  int* basisperm;
2038  int k;
2039  int c;
2040  int ninds;
2041  int nmaxcutsperlp;
2042  int i;
2043 
2044  assert(ngeneratednewcuts != NULL);
2045 
2046  minfrac = sepadata->away;
2047  maxfrac = 1.0 - sepadata->away;
2048  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
2049  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
2050  *ngeneratednewcuts = 0;
2051  nmaxcutsperlp = ((depth == 0) ? sepadata->nmaxcutsperlproot : sepadata->nmaxcutsperlp);
2052 
2053  /* allocate memory */
2054  SCIP_CALL( SCIPallocBufferArray(scip, &basisperm, nrows) );
2055  SCIP_CALL( SCIPallocBufferArray(scip, &basisfrac, nrows) );
2056  SCIP_CALL( SCIPallocBufferArray(scip, &binvrow, nrows) );
2057  SCIP_CALL( SCIPallocBufferArray(scip, &inds, nrows) );
2058  SCIP_CALL( SCIPallocBufferArray(scip, &basisind, nrows) );
2059  SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, ncols) );
2060  SCIP_CALL( SCIPallocBufferArray(scip, &cutinds, ncols) );
2061  SCIP_CALL( SCIPaggrRowCreate(scip, &aggrrow) );
2062 
2063  SCIP_CALL( SCIPgetLPBasisInd(scip, basisind) );
2064 
2065  /* check if the rows of the simplex tableau are suitable for cut generation and build an array of fractions */
2066  for( i = 0; i < nrows; ++i )
2067  {
2068  frac = 0.0;
2069 
2070  c = basisind[i];
2071 
2072  basisperm[i] = i;
2073 
2074  /* if the simplex tableau row corresponds to an LP column */
2075  if( c >= 0 )
2076  {
2077  assert(c < ncols);
2078 
2079  var = SCIPcolGetVar(cols[c]);
2080  /* if the column is non-continuous one */
2082  {
2083  frac = SCIPfeasFrac(scip, solvals[c]);
2084  frac = MIN(frac, 1.0 - frac);
2085  }
2086  }
2087  /* if the simplex tableau row corresponds to an LP row and separation on rows is allowed */
2088  else if( sepadata->separaterows )
2089  {
2090  assert(0 <= -c-1);
2091  assert(-c-1 < nrows);
2092 
2093  row = rows[-c-1];
2094  /* if the row is suitable for cut generation */
2095  if( SCIProwIsIntegral(row) && !SCIProwIsModifiable(row) )
2096  {
2097  frac = SCIPfeasFrac(scip, SCIPgetRowActivity(scip, row));
2098  frac = MIN(frac, 1.0 - frac);
2099  }
2100  }
2101 
2102  if( frac >= minfrac )
2103  {
2104  /* slightly change fractionality to have random order for equal fractions */
2105  basisfrac[i] = frac + SCIPrandomGetReal(sepadata->randnumgen, -1e-6, 1e-6);
2106  }
2107  else
2108  {
2109  basisfrac[i] = 0.0;
2110  }
2111  }
2112 
2113  /* if there is a need to sort the fractionalities */
2114  if( sepadata->sortcutoffsol )
2115  {
2116  /* sort basis indices by fractionality */
2117  SCIPsortDownRealInt(basisfrac, basisperm, nrows);
2118  }
2119 
2120  /* for all basic columns belonging to integer variables, try to generate a GMI cut */
2121  for( i = 0; i < nrows && !SCIPisStopped(scip) && !*cutoff; ++i )
2122  {
2123  if( (ngeneratedcurrroundcuts + *ngeneratednewcuts >= nmaxgeneratedperroundcuts) ||
2124  (sepadata->ntotalcuts + *ngeneratednewcuts >= sepadata->nmaxtotalcuts) ||
2125  (*ngeneratednewcuts >= nmaxcutsperlp) )
2126  break;
2127 
2128  ninds = -1;
2129  cutefficacy = 0.0;
2130 
2131  /* either break the loop or proceed to the next iteration if the fractionality is zero */
2132  if( basisfrac[i] == 0.0 )
2133  {
2134  if( sepadata->sortcutoffsol )
2135  break;
2136  else
2137  continue;
2138  }
2139 
2140  k = basisperm[i];
2141 
2142  /* get the row of B^-1 for this basic integer variable with fractional solution value and call aggregate function */
2143  SCIP_CALL( SCIPgetLPBInvRow(scip, k, binvrow, inds, &ninds) );
2144 
2145  SCIP_CALL( SCIPaggrRowSumRows(scip, aggrrow, binvrow, inds, ninds, sepadata->sidetypebasis, allowlocal, 2,
2146  (int) MAXAGGRLEN(ncols), &success) );
2147 
2148  if( !success )
2149  continue;
2150 
2151  /* @todo Currently we are using the SCIPcalcMIR() function to compute the coefficients of the Gomory
2152  * cut. Alternatively, we could use the direct version (see thesis of Achterberg formula (8.4)) which
2153  * leads to cut a of the form \sum a_i x_i \geq 1. Rumor has it that these cuts are better.
2154  */
2155 
2156  /* try to create GMI cut out of the aggregation row */
2158  NULL, minfrac, maxfrac, 1.0, aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank,
2159  &cutislocal, &success) );
2160 
2161  if( success )
2162  {
2163  assert(allowlocal || !cutislocal); /*lint !e644*/
2164 
2165  SCIP_CALL( constructCutRow(scip, sepa, sepadata, mainiternum, subgradientiternum, cutnnz, cutinds, cutcoefs,
2166  cutefficacy, cutrhs, cutislocal, cutrank, generatedcurrroundcuts, generatedcutefficacies,
2167  ngeneratedcurrroundcuts, ngeneratednewcuts, cutoff));
2168  }
2169  }
2170 
2171  /* free temporary memory */
2172  SCIPfreeBufferArray(scip, &cutinds);
2173  SCIPfreeBufferArray(scip, &cutcoefs);
2174  SCIPfreeBufferArray(scip, &basisind);
2175  SCIPfreeBufferArray(scip, &inds);
2176  SCIPfreeBufferArray(scip, &binvrow);
2177  SCIPfreeBufferArray(scip, &basisfrac);
2178  SCIPfreeBufferArray(scip, &basisperm);
2179  SCIPaggrRowFree(scip, &aggrrow);
2180 
2181  return SCIP_OKAY;
2182 }
2183 
2184 /** update objective vector w.r.t. the fixed Lagrangian multipliers */
2185 static
2187  SCIP* scip, /**< SCIP data structure */
2188  SCIP_Real* dualvector, /**< Lagrangian multipliers vector */
2189  SCIP_ROW** cuts, /**< cuts generated so far in the current separation round */
2190  int ncuts, /**< number of cuts generated so far in the current separation round */
2191  SCIP_Real* origobjcoefs, /**< original objective function coefficients of the node linear relaxation */
2192  SCIP_Bool* objvecsdiffer /**< whether the updated objective function coefficients differ from the old ones */
2193  )
2194 {
2195  SCIP_Real* objvals;
2196  SCIP_Real* prod;
2197  SCIP_Real* oldobjvals;
2198  SCIP_Real* cutvals;
2199  SCIP_COL** cutcols;
2200  SCIP_COL** cols;
2201  SCIP_VAR* var;
2202  int cutnnz;
2203  int collppos;
2204  int ncols;
2205  int i;
2206  int j;
2207 
2208  assert(objvecsdiffer != NULL);
2209  assert(ncuts > 0);
2210 
2211  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
2212 
2213  /* allocate memory */
2214  SCIP_CALL( SCIPallocBufferArray(scip, &objvals, ncols) );
2215  SCIP_CALL( SCIPallocBufferArray(scip, &oldobjvals, ncols) );
2216  SCIP_CALL( SCIPallocCleanBufferArray(scip, &prod, ncols) );
2217  *objvecsdiffer = FALSE;
2218 
2219  /* find the product of Lagrangian multipliers and cut coefficients */
2220  for( i = 0; i < ncuts; i++ )
2221  {
2222  if( !SCIPisZero(scip, dualvector[i]) )
2223  {
2224  assert(!(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && SCIPisInfinity(scip, SCIProwGetRhs(cuts[i]))));
2225  assert(SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])));
2226  assert(!SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])));
2227 
2228  cutnnz = SCIProwGetNNonz(cuts[i]);
2229  assert(cutnnz <= ncols);
2230  cutvals = SCIProwGetVals(cuts[i]);
2231  cutcols = SCIProwGetCols(cuts[i]);
2232 
2233  for( j = 0; j < cutnnz; ++j )
2234  {
2235  collppos = SCIPcolGetLPPos(cutcols[j]);
2236  assert(collppos >= 0);
2237  assert(collppos <= ncols);
2238 
2239  prod[collppos] += dualvector[i] * cutvals[j];
2240  }
2241  }
2242  }
2243 
2244  /* change objective coefficients */
2245  for( i = 0; i < ncols; i++ )
2246  {
2247  var = SCIPcolGetVar(cols[i]);
2248  oldobjvals[i] = SCIPgetVarObjDive(scip, var);
2249  objvals[i] = origobjcoefs[i] + prod[i];
2250 
2251  SCIP_CALL( SCIPchgVarObjDive(scip, var, objvals[i]) );
2252 
2253  /* identify if the updated objective vector is indeed different from the previous one */
2254  if( !(*objvecsdiffer) && !SCIPisEQ(scip, oldobjvals[i], objvals[i]) )
2255  *objvecsdiffer = TRUE;
2256  }
2257 
2258  for( i = 0; i < ncols; i++)
2259  prod[i] = 0.0;
2260 
2261  /* free memory */
2262  SCIPfreeCleanBufferArray(scip, &prod);
2263  SCIPfreeBufferArray(scip, &oldobjvals);
2264  SCIPfreeBufferArray(scip, &objvals);
2265 
2266  return SCIP_OKAY;
2267 }
2268 
2269 /** add GMI cuts to the objective function of the Lagrangian dual problem by introducing new Lagrangian multipliers */
2270 static
2272  SCIP_Real* dualvector, /**< Lagrangian multipliers vector */
2273  int ngeneratedcuts, /**< number of cuts generated so far in the current separation round */
2274  int* naddedcuts, /**< number of cuts added so far in the current separation round to the Lagrangian dual problem
2275  * upon penalization */
2276  int* nnewaddedsoftcuts /**< number of cuts added newly to the Lagrangian dual problem upon penalization */
2277  )
2278 {
2279  int i;
2280 
2281  assert(*naddedcuts <= ngeneratedcuts);
2282 
2283  /* set the initial penalty of the newly penalized cuts as zero */
2284  for( i = *naddedcuts; i < ngeneratedcuts; i++ )
2285  dualvector[i] = 0.0;
2286 
2287  *nnewaddedsoftcuts = ngeneratedcuts - *naddedcuts;
2288  *naddedcuts = ngeneratedcuts;
2289 
2290  return SCIP_OKAY;
2292 
2293 /** solve the Lagrangian dual problem */
2294 static
2296  SCIP* scip, /**< SCIP data structure */
2297  SCIP_SEPA* sepa, /**< pointer to the separator */
2298  SCIP_SEPADATA* sepadata, /**< separator data structure */
2299  SCIP_SOL* sol, /**< data structure to store an LP solution upon solving a Lagrangian dual problem with
2300  * fixed Lagrangian multipliers */
2301  SCIP_Real* solvals, /**< values of the LP solution obtained upon solving a Lagrangian dual problem with fixed
2302  * Lagrangian multipliers */
2303  int mainiternum, /**< iteration number of the outer loop of the relax-and-cut algorithm */
2304  SCIP_Real ubparam, /**< estimate of the optimal Lagrangian dual value */
2305  int depth, /**< depth of the current node in the tree */
2306  SCIP_Bool allowlocal, /**< should locally valid cuts be generated? */
2307  int nmaxgeneratedperroundcuts,/**< maximal number of cuts allowed to generate per separation round */
2308  SCIP_Real* origobjcoefs, /**< original objective function coefficients of the node linear relaxation */
2309  SCIP_Real origobjoffset, /**< original objective function offset of the node linear relaxation */
2310  SCIP_Real* dualvector, /**< Lagrangian multipliers vector */
2311  int* nsoftcuts, /**< number of generated cuts that were penalized and added to the Lagrangian dual problem */
2312  SCIP_ROW** generatedcurrroundcuts, /**< cuts generated in the current separation round */
2313  SCIP_Real* generatedcutefficacies, /**< array of generated cut efficacies w.r.t. the respective LP bases used for cut
2314  * generations */
2315  int* ngeneratedcutsperiter, /**< number of cuts generated per subgradient iteration in the current separation round */
2316  int* ngeneratedcurrroundcuts, /**< number of cuts generated so far in the current separation round */
2317  int* ncurrroundlpiters, /**< number of LP iterations taken for solving Lagrangian dual problems with fixed
2318  * multipliers in the current separator round */
2319  SCIP_Bool* cutoff, /**< should the current node be cutoff? */
2320  SCIP_Real* bestlagrangianval, /**< best Lagrangian value found so far */
2321  SCIP_Real* bestdualvector, /**< Lagrangian multipliers corresponding to the best Lagrangian value found so far */
2322  int* bestdualvectorlen, /**< length of the Lagrangian multipliers corresponding to the best Lagrangian value
2323  * found so far */
2324  int* nbestdualupdates, /**< number of best Lagrangian values found so far */
2325  int* totaliternum /**< total number of iterations of the relax-and-cut algorithm performed so far */
2326  )
2327 {
2328  SCIP_Real* subgradient;
2329  SCIP_Real muparam;
2330  SCIP_Real steplength;
2331  SCIP_Real objval;
2332  SCIP_Real lagrangianval;
2333  SCIP_Real* lagrangianvals;
2334  SCIP_Real avglagrangianval;
2335  SCIP_Real maxsoftcutviol;
2336  SCIP_Real maxnzsubgradientdualprod;
2337  SCIP_Real maxviolscore;
2338  SCIP_Real maxviolscoreold;
2339  SCIP_Real nviolscore;
2340  SCIP_Real nviolscoreold;
2341  SCIP_Real scoreweight;
2342  SCIP_Real ballradius;
2343  SCIP_Bool solfound;
2344  SCIP_Bool backtrack;
2345  SCIP_Bool terminate;
2346  SCIP_Bool subgradientzero;
2347  SCIP_Bool objvecsdiffer;
2348  SCIP_Bool dualvecsdiffer;
2349  SCIP_Bool solvelp;
2350  int ncurrroundlpiterslast;
2351  int nlpiters;
2352  int ngeneratednewcuts;
2353  int nnewaddedsoftcuts;
2354  int nsoftcutviols;
2355  int nnzsubgradientdualprod;
2356  int i;
2357  int j;
2358 
2359  SCIP_CALL( SCIPallocBufferArray(scip, &lagrangianvals, sepadata->nmaxsubgradientiters) );
2360  SCIP_CALL( SCIPallocCleanBufferArray(scip, &subgradient, nmaxgeneratedperroundcuts) );
2361 
2362  muparam = sepadata->muparaminit;
2363  steplength = 0.0;
2364  objval = 0.0;
2365  avglagrangianval = 0.0;
2366  maxsoftcutviol = 0.0;
2367  maxnzsubgradientdualprod = 0.0;
2368  maxviolscore = 0.0;
2369  nviolscore = 0.0;
2370  scoreweight = 1.0;
2371  ballradius = sepadata->radiusinit;
2372  ngeneratednewcuts = 0;
2373  nsoftcutviols = 0;
2374  nnzsubgradientdualprod = 0;
2375  terminate = FALSE;
2376  subgradientzero = FALSE;
2377  objvecsdiffer = FALSE;
2378  dualvecsdiffer = FALSE;
2379  solvelp = TRUE;
2380 
2381  /* update objective vector based on input Lagrangian multipliers */
2382  if( *nsoftcuts > 0 )
2383  {
2384  SCIP_CALL( updateObjectiveVector(scip, dualvector, generatedcurrroundcuts, *nsoftcuts, origobjcoefs, &objvecsdiffer) );
2385  }
2386 
2387  /* termination check */
2388  SCIP_CALL( checkLagrangianDualTermination(sepadata, -1, -1, FALSE, *ngeneratedcurrroundcuts,
2389  nmaxgeneratedperroundcuts, *ncurrroundlpiters, depth, &terminate) );
2390 
2391  /* the subgradient algorithm loop */
2392  for( i = 0; i < sepadata->nmaxsubgradientiters && !SCIPisStopped(scip) && !terminate; i++ )
2393  {
2394  solfound = FALSE;
2395  subgradientzero = FALSE;
2396  objvecsdiffer = FALSE;
2397  dualvecsdiffer = FALSE;
2398  nnewaddedsoftcuts = 0;
2399  scoreweight *= sepadata->radiusupdateweight;
2400 
2401  ncurrroundlpiterslast = *ncurrroundlpiters;
2402  if( solvelp )
2403  {
2404  /* solve Lagrangian dual for fixed Lagrangian multipliers */
2405  SCIP_CALL( solveLagromoryLP(scip, sepadata, depth, origobjoffset, &solfound, sol, solvals, &objval,
2406  ncurrroundlpiters) );
2407  }
2408  nlpiters = *ncurrroundlpiters - ncurrroundlpiterslast;
2409 
2410  /* if an optimal solution has been found, then generate cuts and do other operations */
2411  if( solfound )
2412  {
2413  /* generate GMI cuts if a new basis solution is found */
2414  if( (nlpiters >= 1) && (i % sepadata->cutgenfreq == 0) )
2415  {
2416  ngeneratednewcuts = 0;
2417  SCIP_CALL( generateGMICuts(scip, sepa, sepadata, mainiternum, i, sol, solvals,
2418  nmaxgeneratedperroundcuts, allowlocal, generatedcurrroundcuts, generatedcutefficacies,
2419  *ngeneratedcurrroundcuts, &ngeneratednewcuts, depth, cutoff));
2420  sepadata->ntotalcuts += ngeneratednewcuts;
2421  *ngeneratedcurrroundcuts += ngeneratednewcuts;
2422  ngeneratedcutsperiter[mainiternum * sepadata->nmaxsubgradientiters + i + 1] = ngeneratednewcuts;
2423  }
2424 
2425  /* update subgradient, i.e., find the residuals of the penalized cuts, and determine various violations */
2426  updateSubgradient(scip, sol, generatedcurrroundcuts, *nsoftcuts, subgradient, dualvector, &subgradientzero,
2427  &nsoftcutviols, &maxsoftcutviol, &nnzsubgradientdualprod, &maxnzsubgradientdualprod);
2428 
2429  /* calculate Lagrangian value for the fixed Lagrangian multipliers, and update best and avg values */
2430  updateLagrangianValue(scip, objval, dualvector, generatedcurrroundcuts, *nsoftcuts, &lagrangianval);
2431  if( SCIPisPositive(scip, lagrangianval - *bestlagrangianval) )
2432  {
2433  *bestlagrangianval = lagrangianval;
2434 
2435  for( j = 0; j < *nsoftcuts; j++ )
2436  bestdualvector[j] = dualvector[j];
2437 
2438  *bestdualvectorlen = *nsoftcuts;
2439  (*nbestdualupdates)++;
2440  }
2441  lagrangianvals[i] = lagrangianval;
2442  if( i < sepadata->nmaxlagrangianvalsforavg )
2443  avglagrangianval = (avglagrangianval * i + lagrangianval)/(i+1);
2444  else
2445  {
2446  avglagrangianval = (avglagrangianval * sepadata->nmaxlagrangianvalsforavg -
2447  lagrangianvals[i - sepadata->nmaxlagrangianvalsforavg] +
2448  lagrangianval)/(sepadata->nmaxlagrangianvalsforavg);
2449  }
2450 
2451  /* if the subgradient vector is non-zero, then update the mu parameter and the Lagrangian multipliers */
2452  if( !subgradientzero )
2453  {
2454  /* update mu param */
2455  SCIP_CALL( updateMuSteplengthParam(scip, sepadata, i, ubparam, lagrangianvals, *bestlagrangianval, avglagrangianval,
2456  &muparam, &backtrack) );
2457 
2458  /* update step length */
2459  updateStepLength(scip, muparam, ubparam, lagrangianval, subgradient, *nsoftcuts, &steplength);
2460 
2461  /* update scores to determine how to update the stabilization ball radius */
2462  maxviolscoreold = maxviolscore;
2463  nviolscoreold = nviolscore;
2464  maxviolscore = (1.0 - scoreweight) * maxsoftcutviol + scoreweight * maxnzsubgradientdualprod;
2465  nviolscore = (1.0 - scoreweight) * nsoftcutviols + scoreweight * nnzsubgradientdualprod;
2466 
2467  /* update Lagrangian multipliers */
2468  SCIP_CALL( updateDualVector(scip, sepadata, dualvector, bestdualvector, *bestdualvectorlen,
2469  *nbestdualupdates, i, *totaliternum, steplength, subgradient, *nsoftcuts, backtrack, maxviolscore,
2470  maxviolscoreold, nviolscore, nviolscoreold, nlpiters, &dualvecsdiffer, &ballradius) );
2471 
2472  /* update objective vector based on updated Lagrangian multipliers */
2473  if( dualvecsdiffer )
2474  {
2475  SCIP_CALL( updateObjectiveVector(scip, dualvector, generatedcurrroundcuts, *nsoftcuts, origobjcoefs, &objvecsdiffer) );
2476  }
2477  }
2478  /* if the subgradient vector if zero, then simply mark that the Lagrangian multipliers and the objective
2479  * function of the Lagrangian dual did not change */
2480  else
2481  {
2482  dualvecsdiffer = FALSE;
2483  objvecsdiffer = FALSE;
2484  }
2485 
2486  /* add generated GMI cuts to the objective function of the Lagrangian dual problem by introducing new
2487  * Lagrangian multipliers */
2488  if( (i % sepadata->cutaddfreq == 0) || (!dualvecsdiffer && !objvecsdiffer &&
2489  (*ngeneratedcurrroundcuts - *nsoftcuts > 0)) )
2490  {
2491  SCIP_CALL( addGMICutsAsSoftConss(dualvector, *ngeneratedcurrroundcuts, nsoftcuts, &nnewaddedsoftcuts) );
2492  }
2493  }
2494  else
2495  {
2496  /* add any remaining generated GMI cuts to the objective function of the Lagrangian dual problem by introducing
2497  * new Lagrangian multipliers */
2498  if( (*ngeneratedcurrroundcuts - *nsoftcuts) > 0 )
2499  {
2500  SCIP_CALL( addGMICutsAsSoftConss(dualvector, *ngeneratedcurrroundcuts, nsoftcuts, &nnewaddedsoftcuts) );
2501  }
2502 
2503  solvelp = FALSE;
2504  }
2505 
2506  /* termination check */
2507  SCIP_CALL( checkLagrangianDualTermination(sepadata, nnewaddedsoftcuts, *ngeneratedcurrroundcuts - *nsoftcuts,
2508  objvecsdiffer, *ngeneratedcurrroundcuts, nmaxgeneratedperroundcuts, *ncurrroundlpiters, depth,
2509  &terminate) );
2510 
2511  (*totaliternum)++;
2512  }
2513 
2514  /* add any remaining generated GMI cuts to the objective function of the Lagrangian dual problem by introducing new
2515  * Lagrangian multipliers */
2516  if( (*ngeneratedcurrroundcuts - *nsoftcuts) > 0 )
2517  {
2518  SCIP_CALL( addGMICutsAsSoftConss(dualvector, *ngeneratedcurrroundcuts, nsoftcuts, &nnewaddedsoftcuts) );
2519  }
2520 
2521  /* free memory */
2522  for( i = 0; i < nmaxgeneratedperroundcuts; i++)
2523  subgradient[i] = 0.0;
2524 
2525  SCIPfreeCleanBufferArray(scip, &subgradient);
2526  SCIPfreeBufferArray(scip, &lagrangianvals);
2527 
2528  return SCIP_OKAY;
2529 }
2530 
2531 /** generates initial cut pool before solving the Lagrangian dual */
2532 static
2534  SCIP* scip, /**< SCIP data structure */
2535  SCIP_SEPA* sepa, /**< separator */
2536  SCIP_SEPADATA* sepadata, /**< separator data structure */
2537  int mainiternum, /**< iteration number of the outer loop of the relax-and-cut algorithm */
2538  SCIP_SOL* sol, /**< LP solution to be used for cut generation */
2539  SCIP_Real* solvals, /**< values of the LP solution to be used for cut generation */
2540  int nmaxgeneratedperroundcuts,/**< maximal number of cuts allowed to generate per separation round */
2541  SCIP_Bool allowlocal, /**< should locally valid cuts be generated? */
2542  SCIP_ROW** generatedcurrroundcuts, /**< cuts generated in the current separation round */
2543  SCIP_Real* generatedcutefficacies, /**< array of generated cut efficacies w.r.t. the respective LP bases used for cut
2544  * generations */
2545  int* ngeneratedcutsperiter, /**< number of cuts generated per subgradient iteration in the current separation round */
2546  int* ngeneratedcurrroundcuts, /**< number of cuts generated so far in the current separation round */
2547  int depth, /**< depth of the current node in the tree */
2548  SCIP_Bool* cutoff /**< should the current node be cutoff? */
2549  )
2550 {
2551  int ngeneratednewcuts;
2552 
2553  ngeneratednewcuts = 0;
2554 
2555  /* generate initial set of cuts */
2556  SCIP_CALL( generateGMICuts(scip, sepa, sepadata, mainiternum, -1, sol, solvals, nmaxgeneratedperroundcuts,
2557  allowlocal, generatedcurrroundcuts, generatedcutefficacies, *ngeneratedcurrroundcuts, &ngeneratednewcuts,
2558  depth, cutoff) );
2559 
2560  /* update certain statistics */
2561  sepadata->ntotalcuts += ngeneratednewcuts;
2562  *ngeneratedcurrroundcuts += ngeneratednewcuts;
2563  ngeneratedcutsperiter[sepadata->nmaxsubgradientiters * mainiternum] = ngeneratednewcuts;
2564 
2565  return SCIP_OKAY;
2566 }
2567 
2568 /** add cuts to SCIP */
2569 static
2571  SCIP* scip, /**< SCIP data structure */
2572  SCIP_SEPADATA* sepadata, /**< separator data structure */
2573  SCIP_ROW** cuts, /**< cuts generated so far in the current separation round */
2574  int ncuts, /**< number of cuts generated so far in the current separation round */
2575  SCIP_Longint maxdnom, /**< maximum denominator in the rational representation of cuts */
2576  SCIP_Real maxscale, /**< maximal scale factor to scale the cuts to integral values */
2577  int* naddedcuts, /**< number of cuts added to either global cutpool or sepastore */
2578  SCIP_Bool* cutoff /**< should the current node be cutoff? */
2579  )
2580 {
2581  SCIP_ROW* cut;
2582  SCIP_Bool madeintegral;
2583  int i;
2584 
2585  assert(scip != NULL);
2586  assert(sepadata != NULL);
2587  assert(naddedcuts != NULL);
2588  assert(cutoff != NULL);
2589 
2590  *cutoff = FALSE;
2591  madeintegral = FALSE;
2592 
2593  for( i = 0; i < ncuts && !*cutoff; i++ )
2594  {
2595  cut = cuts[i];
2596 
2597  if( SCIProwGetNNonz(cut) == 1 )
2598  {
2599  /* Add the bound change as cut to avoid that the LP gets modified. This would mean that the LP is not flushed
2600  * and the method SCIPgetLPBInvRow() fails; SCIP internally will apply this bound change automatically. */
2601  SCIP_CALL( SCIPaddRow(scip, cut, TRUE, cutoff) );
2602  ++(*naddedcuts);
2603  }
2604  else
2605  {
2606  if( sepadata->makeintegral && SCIPgetRowNumIntCols(scip, cut) == SCIProwGetNNonz(cut) )
2607  {
2608  /* try to scale the cut to integral values */
2609  SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
2610  maxdnom, maxscale, MAKECONTINTEGRAL, &madeintegral) );
2611 
2612  /* if RHS = plus infinity (due to scaling), the cut is useless, so we are not adding it */
2613  if( madeintegral && SCIPisInfinity(scip, SCIProwGetRhs(cut)) )
2614  return SCIP_OKAY;
2615  }
2616 
2617  if( SCIPisCutNew(scip, cut) )
2618  {
2619  /* add global cuts which are not implicit bound changes to the cut pool */
2620  if( !SCIProwIsLocal(cut) )
2621  {
2622  if( sepadata->delayedcuts )
2623  {
2624  SCIP_CALL( SCIPaddDelayedPoolCut(scip, cut) );
2625  }
2626  else
2627  {
2628  SCIP_CALL( SCIPaddPoolCut(scip, cut) );
2629  }
2630  }
2631  else
2632  {
2633  /* local cuts we add to the sepastore */
2634  SCIP_CALL( SCIPaddRow(scip, cut, sepadata->forcecuts, cutoff) );
2635  }
2636  ++(*naddedcuts);
2637  }
2638  }
2639  }
2640 
2641  return SCIP_OKAY;
2642 }
2643 
2644 /** check different termination criteria */
2645 /* @todo nlpssolved criterion? */
2646 static
2648  SCIP_SEPADATA* sepadata, /**< separator data structure */
2649  SCIP_Bool cutoff, /**< should the current node be cutoff? */
2650  SCIP_Bool dualvecsdiffer, /**< whether the updated Lagrangian multipliers differ from the old one */
2651  int ngeneratedcurrroundcuts, /**< number of cuts generated in the current separation round */
2652  int nsoftcuts, /**< number of generated cuts that were penalized and added to the Lagrangian dual problem */
2653  int nmaxgeneratedperroundcuts, /**< maximal number of cuts allowed to generate per separation round */
2654  int ncurrroundlpiters, /**< number of LP iterations taken for solving Lagrangian dual problems with fixed
2655  * multipliers in the current separator round */
2656  int depth, /**< depth of the current node in the tree */
2657  SCIP_Bool* terminate /**< whether to terminate the relax-and-cut algorithm */
2658  )
2659 {
2660  *terminate = FALSE;
2661 
2662  /* check if the node has been identified to be cutoff */
2663  if( cutoff )
2664  *terminate = TRUE;
2665 
2666  /* check if the Lagrangian multipliers do not differ from the previous iteration and no new cuts exist for penalizing */
2667  if( !dualvecsdiffer && (ngeneratedcurrroundcuts == nsoftcuts) )
2668  *terminate = TRUE;
2669 
2670  /* check if allowed number of cuts in this separation round have already been generated */
2671  if( ngeneratedcurrroundcuts >= nmaxgeneratedperroundcuts )
2672  *terminate = TRUE;
2673 
2674  /* check if allowed number of cuts in the tree have already been generated */
2675  if( sepadata->ntotalcuts >= sepadata->nmaxtotalcuts )
2676  *terminate = TRUE;
2677 
2678  /* check if allowed number of simplex iterations in this separation round have already been used up */
2679  if( (sepadata->nmaxperroundlpiters >= 0) && (ncurrroundlpiters >= sepadata->nmaxperroundlpiters) )
2680  *terminate = TRUE;
2681 
2682  /* check if allowed number of simplex iterations in the root node have already been used up */
2683  if( (depth == 0) && (sepadata->nmaxrootlpiters >= 0) && (sepadata->nrootlpiters >= sepadata->nmaxrootlpiters) )
2684  *terminate = TRUE;
2685 
2686  /* check if allowed number of simplex iterations in the tree have already been used up */
2687  if( (sepadata->nmaxtotallpiters >= 0) && (sepadata->ntotallpiters >= sepadata->nmaxtotallpiters) )
2688  *terminate = TRUE;
2689 
2690  return SCIP_OKAY;
2691 }
2692 
2693 /** searches and tries to add Lagromory cuts */
2694 static
2696  SCIP* scip, /**< SCIP data structure */
2697  SCIP_SEPA* sepa, /**< separator */
2698  SCIP_SEPADATA* sepadata, /**< separator data structure */
2699  SCIP_Real ubparam, /**< estimate of the optimal Lagrangian dual value */
2700  int depth, /**< depth of the current node in the tree */
2701  SCIP_Bool allowlocal, /**< should locally valid cuts be generated? */
2702  SCIP_RESULT* result /**< final result of the separation round */
2703  )
2704 {
2705  SCIP_ROW** generatedcurrroundcuts;
2706  SCIP_ROW** aggregatedcurrroundcuts;
2707  SCIP_Real* generatedcutefficacies;
2708  SCIP_Bool solfound;
2709  SCIP_SOL* softcutslpsol;
2710  SCIP_Real* softcutslpsolvals;
2711  SCIP_SOL* hardcutslpsol;
2712  SCIP_Real* hardcutslpsolvals;
2713  SCIP_Real* dualsol;
2714  SCIP_Real* dualvector;
2715  SCIP_Real* bestdualvector;
2716  SCIP_Real bestlagrangianval;
2717  SCIP_Real* origobjcoefs;
2718  SCIP_Real origobjoffset;
2719  SCIP_Real objval;
2720  SCIP_Real maxscale;
2721  SCIP_Longint maxdnom;
2722  SCIP_Bool cutoff;
2723  SCIP_Bool cutoff2;
2724  SCIP_Bool dualvecsdiffer;
2725  SCIP_Bool terminate;
2726  SCIP_COL** cols;
2727 
2728  int* ngeneratedcutsperiter;
2729  int bestdualvectorlen;
2730  int nbestdualupdates;
2731  int totaliternum;
2732  int* cutindsperm;
2733  int nprocessedcuts;
2734  int ncols;
2735  int nrows;
2736  int ngeneratedcurrroundcuts;
2737  int nselectedcurrroundcuts;
2738  int nselectedcuts;
2739  int naddedcurrroundcuts;
2740  int naggregatedcurrroundcuts;
2741  int nmaxgeneratedperroundcuts;
2742  int ncurrroundlpiters;
2743  int nsoftcuts;
2744  int nsoftcutsold;
2745  int maxdepth;
2746  int i;
2747  int j;
2748 
2749  assert(*result == SCIP_DIDNOTRUN);
2750  assert(sepadata != NULL);
2751  sepadata->ncalls = SCIPsepaGetNCalls(sepa);
2752  objval = SCIPinfinity(scip);
2753  bestlagrangianval = -SCIPinfinity(scip);
2754  bestdualvectorlen = 0;
2755  nbestdualupdates = 0;
2756  totaliternum = 0;
2757  ngeneratedcurrroundcuts = 0;
2758  naddedcurrroundcuts = 0;
2759  naggregatedcurrroundcuts = 0;
2760  ncurrroundlpiters = 0;
2761  nsoftcuts = 0;
2762  solfound = FALSE;
2763  cutoff = FALSE;
2764  cutoff2 = FALSE;
2765  dualvecsdiffer = FALSE;
2766  terminate = FALSE;
2767 
2768  SCIPdebugMsg(scip, "Separating cuts...\n");
2769 
2770  /* initialize the LP that will be used to solve the Lagrangian dual with fixed Lagrangian multipliers */
2771  SCIP_CALL( createLPWithSoftCuts(scip, sepadata) );
2772  /* create the LP that represents the node relaxation including all the generated cuts in this separator */
2773  SCIP_CALL( createLPWithHardCuts(scip, sepadata, NULL, 0) );
2774 
2775  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
2776  nrows = SCIPgetNLPRows(scip);
2777 
2778  /* get the maximal number of cuts allowed in a separation round */
2779  nmaxgeneratedperroundcuts = ((depth == 0) ? sepadata->nmaxperroundcutsroot : sepadata->nmaxperroundcuts);
2780 
2781  /* allocate memory */
2782  SCIP_CALL( SCIPallocBufferArray(scip, &generatedcurrroundcuts, nmaxgeneratedperroundcuts) );
2783  SCIP_CALL( SCIPallocBufferArray(scip, &aggregatedcurrroundcuts, nmaxgeneratedperroundcuts) );
2784  SCIP_CALL( SCIPallocBufferArray(scip, &generatedcutefficacies, nmaxgeneratedperroundcuts) );
2785  SCIP_CALL( SCIPallocBufferArray(scip, &cutindsperm, nmaxgeneratedperroundcuts) );
2786  SCIP_CALL( SCIPallocCleanBufferArray(scip, &ngeneratedcutsperiter, sepadata->nmaxmainiters *
2787  (sepadata->nmaxsubgradientiters + 1)) );
2788  SCIP_CALL( SCIPallocCleanBufferArray(scip, &dualsol, nrows + nmaxgeneratedperroundcuts) );
2789  SCIP_CALL( SCIPallocCleanBufferArray(scip, &dualvector, nmaxgeneratedperroundcuts) );
2790  SCIP_CALL( SCIPallocCleanBufferArray(scip, &bestdualvector, nmaxgeneratedperroundcuts) );
2791  SCIP_CALL( SCIPallocBufferArray(scip, &softcutslpsolvals, ncols) );
2792  SCIP_CALL( SCIPcreateSol(scip, &softcutslpsol, NULL) );
2793  SCIP_CALL( SCIPallocBufferArray(scip, &hardcutslpsolvals, ncols) );
2794  SCIP_CALL( SCIPcreateSol(scip, &hardcutslpsol, NULL) );
2795  SCIP_CALL( SCIPallocBufferArray(scip, &origobjcoefs, ncols) );
2796 
2797  /* store current objective function */
2798  for( i = 0; i < ncols; i++ )
2799  origobjcoefs[i] = SCIPcolGetObj(cols[i]);
2800 
2801  origobjoffset = SCIPgetTransObjoffset(scip);
2802 
2803  /* solve node LP relaxation to have an initial simplex tableau */
2804  SCIP_CALL( solveLagromoryLP(scip, sepadata, depth, origobjoffset, &solfound, softcutslpsol, softcutslpsolvals, &objval,
2805  &ncurrroundlpiters));
2806 
2807  /* generate initial cut pool */
2808  SCIP_CALL( generateInitCutPool(scip, sepa, sepadata, 0, softcutslpsol, softcutslpsolvals, nmaxgeneratedperroundcuts, allowlocal,
2809  generatedcurrroundcuts, generatedcutefficacies, ngeneratedcutsperiter, &ngeneratedcurrroundcuts, depth,
2810  &cutoff) );
2811 
2812  /* termination check */
2813  SCIP_CALL( checkMainLoopTermination(sepadata, cutoff, TRUE, ngeneratedcurrroundcuts, nsoftcuts,
2814  nmaxgeneratedperroundcuts, ncurrroundlpiters, depth, &terminate) );
2815 
2816  /* compute cuts for each integer col with fractional val */
2817  for( i = 0; i < sepadata->nmaxmainiters && !SCIPisStopped(scip) && !terminate; ++i )
2818  {
2819  nsoftcutsold = nsoftcuts;
2820  nsoftcuts = ngeneratedcurrroundcuts;
2821  dualvecsdiffer = FALSE;
2822 
2823  /* solve Lagrangain dual */
2824  SCIP_CALL( solveLagrangianDual(scip, sepa, sepadata, softcutslpsol, softcutslpsolvals, i, ubparam, depth, allowlocal,
2825  nmaxgeneratedperroundcuts, origobjcoefs, origobjoffset, dualvector, &nsoftcuts, generatedcurrroundcuts,
2826  generatedcutefficacies, ngeneratedcutsperiter, &ngeneratedcurrroundcuts, &ncurrroundlpiters, &cutoff,
2827  &bestlagrangianval, bestdualvector, &bestdualvectorlen, &nbestdualupdates, &totaliternum) );
2828 
2829  /* @todo filter cuts before adding them to the new LP that was created based on the node relaxation? */
2830 
2831  /* update the LP representing the node relaxation by adding newly generated cuts */
2832  if( !cutoff && (ngeneratedcurrroundcuts - nsoftcutsold > 0) )
2833  {
2834  SCIP_CALL( createLPWithHardCuts(scip, sepadata, generatedcurrroundcuts, ngeneratedcurrroundcuts) );
2835 
2836  /* solve the LP and get relevant information */
2837  SCIP_CALL( solveLPWithHardCuts(scip, sepadata, &solfound, hardcutslpsol, hardcutslpsolvals) );
2838 
2839  /* if primal solution is found, then pass it to trysol heuristic */
2840  /* @note if trysol heuristic is was not present, then the solution found above, which can potentially be a MIP
2841  * primal feasible solution, will go to waste.
2842  */
2843  if( solfound && sepadata->heurtrysol != NULL )
2844  {
2845  SCIP_CALL( SCIPheurPassSolTrySol(scip, sepadata->heurtrysol, hardcutslpsol) );
2846  }
2847 
2848  /* if dual feasible, then fetch dual solution and reset Lagrangian multipliers based on it. otherwise, retain the
2849  * Lagrangian multipliers and simply initialize the new multipliers to zeroes. */
2850  if( SCIPlpiIsDualFeasible(sepadata->lpiwithhardcuts) )
2851  {
2852  SCIP_CALL( SCIPlpiGetSol(sepadata->lpiwithhardcuts, NULL, NULL, dualsol, NULL, NULL) );
2853  SCIP_CALL( updateDualVector(scip, sepadata, dualvector, &(dualsol[nrows]),
2854  ngeneratedcurrroundcuts, 0, -1, -1, 0.0, NULL, ngeneratedcurrroundcuts, TRUE, 0.0, 0.0, 0.0, 0.0, -1,
2855  &dualvecsdiffer, NULL) );
2856  }
2857  else
2858  {
2859  SCIP_CALL( updateDualVector(scip, sepadata, dualvector, dualvector, nsoftcuts, 0, -1, -1, 0.0, NULL,
2860  ngeneratedcurrroundcuts, TRUE, 0.0, 0.0, 0.0, 0.0, -1, &dualvecsdiffer, NULL) );
2861  }
2862  }
2863 
2864  /* termination check */
2865  SCIP_CALL( checkMainLoopTermination(sepadata, cutoff, dualvecsdiffer, ngeneratedcurrroundcuts, nsoftcuts,
2866  nmaxgeneratedperroundcuts, ncurrroundlpiters, depth, &terminate) );
2867  }
2868 
2869  /* set the maximal denominator in rational representation of gomory cut and the maximal scale factor to
2870  * scale resulting cut to integral values to avoid numerical instabilities
2871  */
2872  /* @todo find better but still stable gomory cut settings: look at dcmulti, gesa3, khb0525, misc06, p2756 */
2873  /* @note above todo was copied from sepa_gomory.c. So, if gomory code is changed, same changes can be done here. */
2874  maxdepth = SCIPgetMaxDepth(scip);
2875  if( depth == 0 )
2876  {
2877  maxdnom = 1000;
2878  maxscale = 1000.0;
2879  }
2880  else if( depth <= maxdepth/4 )
2881  {
2882  maxdnom = 1000;
2883  maxscale = 1000.0;
2884  }
2885  else if( depth <= maxdepth/2 )
2886  {
2887  maxdnom = 100;
2888  maxscale = 100.0;
2889  }
2890  else
2891  {
2892  maxdnom = 10;
2893  maxscale = 10.0;
2894  }
2895 
2896  /* filter cuts by calling cut selection algorithms and add cuts accordingly */
2897  /* @todo an idea is to filter cuts after every main iter */
2898  /* @todo we can remove !cutoff criterion by adding forcedcuts */
2899  if( !cutoff && (ngeneratedcurrroundcuts > 0) )
2900  {
2901  if( SCIPisGE(scip, sepadata->cutsfilterfactor, 1.0) )
2902  {
2903  nselectedcurrroundcuts = ngeneratedcurrroundcuts;
2904  SCIP_CALL( addCuts(scip, sepadata, generatedcurrroundcuts, nselectedcurrroundcuts, maxdnom, maxscale,
2905  &naddedcurrroundcuts, &cutoff2) );
2906  cutoff = cutoff2;
2907  }
2908  else if( SCIPisPositive(scip, sepadata->cutsfilterfactor) )
2909  {
2910  nprocessedcuts = 0;
2911  for( i = 0; i < sepadata->nmaxmainiters * (sepadata->nmaxsubgradientiters + 1); i++ )
2912  {
2913  if( ngeneratedcutsperiter[i] != 0 )
2914  {
2915  for( j = 0; j < ngeneratedcutsperiter[i]; j++ )
2916  cutindsperm[j] = j + nprocessedcuts;
2917 
2918  /* sort cut efficacies by fractionality */
2919  SCIPsortDownRealInt(&generatedcutefficacies[nprocessedcuts], cutindsperm, ngeneratedcutsperiter[i]);
2920 
2921  nselectedcuts = (int)SCIPceil(scip, sepadata->cutsfilterfactor * ngeneratedcutsperiter[i]);
2922 
2923  SCIP_CALL( addCuts(scip, sepadata, &generatedcurrroundcuts[nprocessedcuts], nselectedcuts, maxdnom,
2924  maxscale, &naddedcurrroundcuts, &cutoff2) );
2925  cutoff = cutoff2;
2926 
2927  nprocessedcuts += ngeneratedcutsperiter[i];
2928  }
2929  }
2930  }
2931  }
2932  else if( ngeneratedcurrroundcuts > 0 )
2933  {
2934  nselectedcurrroundcuts = ngeneratedcurrroundcuts;
2935  SCIP_CALL( addCuts(scip, sepadata, generatedcurrroundcuts, nselectedcurrroundcuts, maxdnom, maxscale,
2936  &naddedcurrroundcuts, &cutoff2) );
2937  }
2938 
2939  /* add an aggregated cut based on best Lagrangian multipliers */
2940  if( sepadata->aggregatecuts && (ngeneratedcurrroundcuts > 0) && (bestdualvectorlen > 0) )
2941  {
2942  assert(bestdualvectorlen <= ngeneratedcurrroundcuts);
2943  SCIP_CALL( aggregateGeneratedCuts(scip, sepa, sepadata, generatedcurrroundcuts, bestdualvector, bestdualvectorlen,
2944  aggregatedcurrroundcuts, &naggregatedcurrroundcuts, &cutoff2) );
2945  cutoff = (!cutoff ? cutoff2 : cutoff);
2946  if( naggregatedcurrroundcuts > 0 )
2947  {
2948  SCIP_CALL( addCuts(scip, sepadata, aggregatedcurrroundcuts, naggregatedcurrroundcuts, maxdnom, maxscale,
2949  &naddedcurrroundcuts, &cutoff2) );
2950  cutoff = (!cutoff ? cutoff2 : cutoff);
2951  }
2952  }
2953 
2954  if( cutoff )
2955  {
2956  *result = SCIP_CUTOFF;
2957  }
2958  else if( naddedcurrroundcuts > 0 )
2959  {
2960  *result = SCIP_SEPARATED;
2961  }
2962  else
2963  {
2964  *result = SCIP_DIDNOTFIND;
2965  }
2966 
2967  /* delete the LP representing the Lagrangian dual problem with fixed Lagrangian multipliers */
2968  SCIP_CALL( deleteLPWithSoftCuts(scip, sepadata) );
2969 
2970  /* release the rows in aggregatedcurrroundcuts */
2971  for( i = 0; i < naggregatedcurrroundcuts; ++i )
2972  {
2973  SCIP_CALL( SCIPreleaseRow(scip, &(aggregatedcurrroundcuts[i])) );
2974  }
2975 
2976  /* release the rows in generatedcurrroundcuts */
2977  for( i = 0; i < ngeneratedcurrroundcuts; ++i )
2978  {
2979  SCIP_CALL( SCIPreleaseRow(scip, &(generatedcurrroundcuts[i])) );
2980  }
2981 
2982  for( i = 0; i < sepadata->nmaxmainiters * (sepadata->nmaxsubgradientiters + 1); i++ )
2983  ngeneratedcutsperiter[i] = 0;
2984 
2985  for( i = 0; i < nrows; i++ )
2986  dualsol[i] = 0.0;
2987 
2988  for( i = 0; i < nmaxgeneratedperroundcuts; i++ )
2989  {
2990  dualsol[nrows + i] = 0.0;
2991  dualvector[i] = 0.0;
2992  bestdualvector[i] = 0.0;
2993  }
2994 
2995  /* free memory */
2996  SCIPfreeBufferArray(scip, &origobjcoefs);
2997  SCIPfreeBufferArray(scip, &hardcutslpsolvals);
2998  SCIP_CALL( SCIPfreeSol(scip, &hardcutslpsol) );
2999  SCIPfreeBufferArray(scip, &softcutslpsolvals);
3000  SCIP_CALL( SCIPfreeSol(scip, &softcutslpsol) );
3001  SCIPfreeCleanBufferArray(scip, &ngeneratedcutsperiter);
3002  SCIPfreeBufferArray(scip, &cutindsperm);
3003  SCIPfreeBufferArray(scip, &generatedcutefficacies);
3004  SCIPfreeBufferArray(scip, &aggregatedcurrroundcuts);
3005  SCIPfreeBufferArray(scip, &generatedcurrroundcuts);
3006  SCIPfreeCleanBufferArray(scip, &dualvector);
3007  SCIPfreeCleanBufferArray(scip, &bestdualvector);
3008  SCIPfreeCleanBufferArray(scip, &dualsol);
3009 
3010  return SCIP_OKAY;
3011 }
3012 
3013 /** creates separator data */
3014 static
3016  SCIP* scip, /**< SCIP data structure */
3017  SCIP_SEPADATA** sepadata /**< separator data structure */
3018  )
3019 {
3020  assert(scip != NULL);
3021  assert(sepadata != NULL);
3022 
3023  SCIP_CALL( SCIPallocBlockMemory(scip, sepadata) );
3024  BMSclearMemory(*sepadata);
3025 
3026  return SCIP_OKAY;
3027 }
3028 
3029 
3030 /*
3031  * Callback methods of separator
3032  */
3033 
3034 /** copy method for separator plugins (called when SCIP copies plugins) */
3035 static
3036 SCIP_DECL_SEPACOPY(sepaCopyLagromory)
3037 { /*lint --e{715}*/
3038  assert(scip != NULL);
3039  assert(sepa != NULL);
3040  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
3041 
3042  /* call inclusion method of constraint handler */
3044 
3045  return SCIP_OKAY;
3046 }
3047 
3048 
3049 /** destructor of separator to free user data (called when SCIP is exiting) */
3050 static
3051 SCIP_DECL_SEPAFREE(sepaFreeLagromory)
3052 {
3053  SCIP_SEPADATA* sepadata;
3054 
3055  sepadata = SCIPsepaGetData(sepa);
3056  assert(sepadata != NULL);
3057 
3058  SCIP_CALL( sepadataFree(scip, &sepadata) );
3059  SCIPsepaSetData(sepa, NULL);
3060 
3061  return SCIP_OKAY;
3062 }
3063 
3064 
3065 /** initialization method of separator (called after problem was transformed) */
3066 static
3067 SCIP_DECL_SEPAINIT(sepaInitLagromory)
3068 {
3069  SCIP_SEPADATA* sepadata;
3070 
3071  sepadata = SCIPsepaGetData(sepa);
3072  assert(scip != NULL);
3073  assert(sepadata != NULL);
3074 
3075  /* create and initialize random number generator */
3076  SCIP_CALL( SCIPcreateRandom(scip, &(sepadata->randnumgen), RANDSEED, TRUE) );
3077 
3078  /* find trysol heuristic */
3079  if ( sepadata->heurtrysol == NULL )
3080  sepadata->heurtrysol = SCIPfindHeur(scip, "trysol");
3081 
3082  return SCIP_OKAY;
3083 }
3084 
3085 /** deinitialization method of separator (called before transformed problem is freed) */
3086 static
3087 SCIP_DECL_SEPAEXIT(sepaExitLagromory)
3088 { /*lint --e{715}*/
3089  SCIP_SEPADATA* sepadata;
3090 
3091  sepadata = SCIPsepaGetData(sepa);
3092  assert(sepadata != NULL);
3093 
3094  SCIPfreeRandom(scip, &(sepadata->randnumgen));
3095 
3096  return SCIP_OKAY;
3097 }
3098 
3099 /** LP solution separation method of separator */
3100 static
3101 SCIP_DECL_SEPAEXECLP(sepaExeclpLagromory)
3102 {
3103  /*lint --e{715}*/
3104 
3105  SCIP_SEPADATA* sepadata;
3106  SCIP_SOL* bestsol;
3107  SCIP_COL** cols;
3108  SCIP_COL* col;
3109  SCIP_VAR* var;
3110  SCIP_Real ubparam;
3111  SCIP_Real dualdegeneracyrate;
3112  SCIP_Real varconsratio;
3113  SCIP_Real threshold1;
3114  SCIP_Real threshold2;
3115  int nrows;
3116  int ncols;
3117  int ncalls;
3118  int runnum;
3119  int i;
3120 
3121  assert(sepa != NULL);
3122  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
3123  sepadata = SCIPsepaGetData(sepa);
3124  assert(sepadata != NULL);
3125 
3126  assert(result != NULL);
3127  *result = SCIP_DIDNOTRUN;
3128 
3129  assert(scip != NULL);
3130 
3131  ncalls = SCIPsepaGetNCallsAtNode(sepa);
3132  runnum = SCIPgetNRuns(scip);
3133  dualdegeneracyrate = 0.0;
3134  varconsratio = 0.0;
3135 
3136  /* only generate Lagromory cuts if we are not close to terminating */
3137  if( SCIPisStopped(scip) )
3138  return SCIP_OKAY;
3139 
3140  /* only call the separator starting sepadata->minrestart runs */
3141  if( (sepadata->minrestart >= 1) && (runnum < sepadata->minrestart + 1) )
3142  return SCIP_OKAY;
3143 
3144  /* only call the separator a given number of times at each node */
3145  if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
3146  || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
3147  return SCIP_OKAY;
3148 
3149  /* only generate cuts if an optimal LP solution is at hand */
3151  return SCIP_OKAY;
3152 
3153  /* only generate cuts if the LP solution is basic */
3154  if( ! SCIPisLPSolBasic(scip) )
3155  return SCIP_OKAY;
3156 
3157  /* get LP data */
3158  SCIP_CALL( SCIPgetLPColsData(scip, &cols, &ncols) );
3159  assert(cols != NULL);
3160 
3161  nrows = SCIPgetNLPRows(scip);
3162 
3163  /* return if LP has no columns or no rows */
3164  if( ncols == 0 || nrows == 0 )
3165  return SCIP_OKAY;
3166 
3167  /* return if dual degeneracy metrics are below threshold values */
3168  threshold1 = sepadata->dualdegeneracyratethreshold;
3169  threshold2 = sepadata->varconsratiothreshold;
3170  SCIP_CALL( SCIPgetLPDualDegeneracy(scip, &dualdegeneracyrate, &varconsratio) );
3171  if( (dualdegeneracyrate < threshold1) && (varconsratio < threshold2) )
3172  return SCIP_OKAY;
3173 
3174  bestsol = SCIPgetBestSol(scip);
3175  ubparam = 0.0;
3176 
3177  /* if a MIP primal solution exists, use it to estimate the optimal value of the Lagrangian dual problem */
3178  if( bestsol != NULL )
3179  {
3180  for( i = 0; i < ncols; ++i )
3181  {
3182  col = cols[i];
3183  assert(col != NULL);
3184 
3185  var = SCIPcolGetVar(col);
3186 
3187  ubparam += SCIPgetSolVal(scip, bestsol, var) * SCIPcolGetObj(col);
3188  }
3189 
3190  ubparam += SCIPgetTransObjoffset(scip);
3191  }
3192  /* if a MIP primal solution does not exist, then use the node relaxation's LP solutin to estimate the optimal value
3193  * of the Lagrangian dual problem
3194  */
3195  else
3196  {
3197  for( i = 0; i < ncols; ++i )
3198  {
3199  col = cols[i];
3200  assert(col != NULL);
3201 
3202  ubparam += SCIPcolGetPrimsol(col) * SCIPcolGetObj(col);
3203  }
3204 
3205  ubparam += SCIPgetTransObjoffset(scip);
3206  ubparam *= SCIPisPositive(scip, ubparam) ? sepadata->ubparamposfactor : sepadata->ubparamnegfactor;
3207  }
3208 
3209  /* the main separation function of the separator */
3210  SCIP_CALL( separateCuts(scip, sepa, sepadata, ubparam, depth, (allowlocal && sepadata->allowlocal), result) );
3211 
3212  return SCIP_OKAY;
3213 }
3214 
3215 
3216 /*
3217  * separator specific interface methods
3218  */
3219 
3220 /** creates the Lagromory separator and includes it in SCIP */
3222  SCIP* scip /**< SCIP data structure */
3223  )
3224 {
3225  SCIP_SEPADATA* sepadata;
3226  SCIP_SEPA* sepa;
3227 
3228  /* create separator data */
3229  SCIP_CALL( sepadataCreate(scip, &sepadata) );
3230 
3231  sepadata->heurtrysol = NULL;
3232 
3233  /* include separator */
3235  SEPA_USESSUBSCIP, SEPA_DELAY, sepaExeclpLagromory, NULL, sepadata) );
3236 
3237  assert(sepa != NULL);
3238 
3239  /* set non fundamental callbacks via setter functions */
3240  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyLagromory) );
3241  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeLagromory) );
3242  SCIP_CALL( SCIPsetSepaInit(scip, sepa, sepaInitLagromory) );
3243  SCIP_CALL( SCIPsetSepaExit(scip, sepa, sepaExitLagromory) );
3244 
3245  /* add separator parameters */
3246  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/away", "minimal integrality violation of a basis "
3247  "variable to try separation", &sepadata->away, FALSE, DEFAULT_AWAY, 0.0, 1.0, NULL, NULL) );
3248 
3249  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/rootlpiterlimitfactor", "factor w.r.t. root node LP "
3250  "iterations for maximal separating LP iterations in the root node (negative for no limit)",
3251  &sepadata->rootlpiterlimitfactor, TRUE, DEFAULT_ROOTLPITERLIMITFACTOR, -1.0, SCIP_REAL_MAX, NULL, NULL) );
3252 
3253  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/totallpiterlimitfactor", "factor w.r.t. root node LP "
3254  "iterations for maximal separating LP iterations in the tree (negative for no limit)",
3255  &sepadata->totallpiterlimitfactor, TRUE, DEFAULT_TOTALLPITERLIMITFACTOR, -1.0, SCIP_REAL_MAX, NULL, NULL) );
3256 
3257  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/perroundlpiterlimitfactor", "factor w.r.t. root node LP "
3258  "iterations for maximal separating LP iterations per separation round (negative for no limit)",
3259  &sepadata->perroundlpiterlimitfactor, TRUE, DEFAULT_PERROUNDLPITERLIMITFACTOR, -1.0, SCIP_REAL_MAX, NULL,
3260  NULL) );
3261 
3262  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/perroundcutsfactorroot", "factor w.r.t. number of integer "
3263  "columns for number of cuts separated per separation round in root node", &sepadata->perroundcutsfactorroot,
3265 
3266  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/perroundcutsfactor", "factor w.r.t. number of integer "
3267  "columns for number of cuts separated per separation round at a non-root node",
3268  &sepadata->perroundcutsfactor, TRUE, DEFAULT_PERROUNDCUTSFACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3269 
3270  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/totalcutsfactor", "factor w.r.t. number of integer "
3271  "columns for total number of cuts separated", &sepadata->totalcutsfactor, TRUE, DEFAULT_TOTALCUTSFACTOR, 0.0,
3272  SCIP_REAL_MAX, NULL, NULL) );
3273 
3274  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muparaminit", "initial value of the mu parameter (factor "
3275  "for step length)", &sepadata->muparaminit, TRUE, DEFAULT_MUPARAMINIT, 0.0, 100.0, NULL, NULL) );
3276 
3277  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muparamlb", "lower bound of the mu parameter (factor for "
3278  "step length)", &sepadata->muparamlb, TRUE, DEFAULT_MUPARAMLB, 0.0, 1.0, NULL, NULL) );
3279 
3280  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muparamub", "upper bound of the mu parameter (factor for "
3281  "step length)", &sepadata->muparamub, TRUE, DEFAULT_MUPARAMUB, 1.0, 10.0, NULL, NULL) );
3282 
3283  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/mubacktrackfactor", "factor of mu while backtracking the "
3284  "mu parameter (factor for step length)", &sepadata->mubacktrackfactor, TRUE, DEFAULT_MUBACKTRACKFACTOR,
3285  0.0, 1.0, NULL, NULL) );
3286 
3287  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muslab1factor", "factor of mu parameter (factor for step "
3288  "length) for larger increment" , &sepadata->muslab1factor, TRUE, DEFAULT_MUSLAB1FACTOR, 0.0, SCIP_REAL_MAX, NULL,
3289  NULL));
3290 
3291  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muslab2factor", "factor of mu parameter (factor for step "
3292  "length) for smaller increment", &sepadata->muslab2factor, TRUE, DEFAULT_MUSLAB2FACTOR, 0.0, SCIP_REAL_MAX, NULL,
3293  NULL) );
3294 
3295  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/muslab3factor", "factor of mu parameter (factor for step "
3296  "length) for reduction", &sepadata->muslab3factor, TRUE, DEFAULT_MUSLAB3FACTOR, 0.0, SCIP_REAL_MAX, NULL, NULL) );
3297 
3298  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/deltaslab1ub", "factor of delta deciding larger increment "
3299  "of mu parameter (factor for step length)", &sepadata->deltaslab1ub, TRUE, DEFAULT_DELTASLAB1UB, 0.0, 1.0,
3300  NULL, NULL) );
3301 
3302  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/deltaslab2ub", "factor of delta deciding smaller "
3303  "increment of mu parameter (factor for step length)", &sepadata->deltaslab2ub, TRUE, DEFAULT_DELTASLAB2UB,
3304  0.0, 1.0, NULL, NULL) );
3305 
3306  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/ubparamposfactor", "factor for positive upper bound used "
3307  "as an estimate for the optimal Lagrangian dual value", &sepadata->ubparamposfactor, TRUE, DEFAULT_UBPARAMPOSFACTOR,
3308  1.0, 100.0, NULL, NULL) );
3309 
3310  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/ubparamnegfactor", "factor for negative upper bound used "
3311  "as an estimate for the optimal Lagrangian dual value", &sepadata->ubparamnegfactor, TRUE, DEFAULT_UBPARAMNEGFACTOR,
3312  0.0, 1.0, NULL, NULL) );
3313 
3314  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/perrootlpiterfactor", "factor w.r.t. root node LP "
3315  "iterations for iteration limit of each separating LP (negative for no limit)",
3316  &sepadata->perrootlpiterfactor, TRUE, DEFAULT_PERROOTLPITERFACTOR, -1.0, SCIP_REAL_MAX, NULL, NULL) );
3317 
3318  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/perlpiterfactor", "factor w.r.t. non-root node LP "
3319  "iterations for iteration limit of each separating LP (negative for no limit)", &sepadata->perlpiterfactor, TRUE,
3321 
3322  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/cutsfilterfactor", "fraction of generated cuts per "
3323  "explored basis to accept from separator", &sepadata->cutsfilterfactor, TRUE, DEFAULT_CUTSFILTERFACTOR, 0.0,
3324  1.0, NULL, NULL) );
3325 
3326  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/radiusinit", "initial radius of the ball used in "
3327  "stabilization of Lagrangian multipliers", &sepadata->radiusinit, TRUE, DEFAULT_RADIUSINIT, 0.0, 1.0, NULL,
3328  NULL) );
3329 
3330  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/radiusmax", "maximum radius of the ball used in "
3331  "stabilization of Lagrangian multipliers", &sepadata->radiusmax, TRUE, DEFAULT_RADIUSMAX, 0.0, SCIP_REAL_MAX,
3332  NULL, NULL) );
3333 
3334  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/radiusmin", "minimum radius of the ball used in "
3335  "stabilization of Lagrangian multipliers", &sepadata->radiusmin, TRUE, DEFAULT_RADIUSMIN, 0.0, SCIP_REAL_MAX,
3336  NULL, NULL) );
3337 
3338  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/constant", "a constant for stablity center based "
3339  "stabilization of Lagrangian multipliers", &sepadata->constant, TRUE, DEFAULT_CONST, 2.0, SCIP_REAL_MAX,
3340  NULL, NULL) );
3341 
3342  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/radiusupdateweight", "multiplier to evaluate cut "
3343  "violation score used for updating ball radius", &sepadata->radiusupdateweight, TRUE,
3344  DEFAULT_RADIUSUPDATEWEIGHT, 0.0, 1.0, NULL, NULL) );
3345 
3346  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/dualdegeneracyratethreshold", "minimum dual degeneracy "
3347  "rate for separator execution", &sepadata->dualdegeneracyratethreshold, FALSE,
3349 
3350  SCIP_CALL( SCIPaddRealParam(scip, "separating/" SEPA_NAME "/varconsratiothreshold", "minimum variable-constraint "
3351  "ratio on optimal face for separator execution", &sepadata->varconsratiothreshold, FALSE,
3353 
3354  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/muparamconst", "is the mu parameter (factor for step "
3355  "length) constant?" , &sepadata->muparamconst, TRUE, DEFAULT_MUPARAMCONST, NULL, NULL) );
3356 
3357  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/separaterows", "separate rows with integral slack?",
3358  &sepadata->separaterows, TRUE, DEFAULT_SEPARATEROWS, NULL, NULL) );
3359 
3360  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/sortcutoffsol", "sort fractional integer columns"
3361  "based on fractionality?" , &sepadata->sortcutoffsol, TRUE, DEFAULT_SORTCUTOFFSOL, NULL, NULL) );
3362 
3363  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/sidetypebasis", "choose side types of row (lhs/rhs) "
3364  "based on basis information?", &sepadata->sidetypebasis, TRUE, DEFAULT_SIDETYPEBASIS, NULL, NULL) );
3365 
3366  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/dynamiccuts", "should generated cuts be removed from "
3367  "LP if they are no longer tight?", &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
3368 
3369  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/makeintegral", "try to scale all cuts to integral "
3370  "coefficients?", &sepadata->makeintegral, TRUE, DEFAULT_MAKEINTEGRAL, NULL, NULL) );
3371 
3372  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/forcecuts", "force cuts to be added to the LP?",
3373  &sepadata->forcecuts, TRUE, DEFAULT_FORCECUTS, NULL, NULL) );
3374 
3375  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/delayedcuts", "should cuts be added to the delayed cut "
3376  "pool", &sepadata->delayedcuts, TRUE, DEFAULT_DELAYEDCUTS, NULL, NULL) );
3377 
3378  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/allowlocal", "should locally valid cuts be generated?",
3379  &sepadata->allowlocal, TRUE, DEFAULT_ALLOWLOCAL, NULL, NULL) );
3380 
3381  SCIP_CALL( SCIPaddBoolParam(scip, "separating/" SEPA_NAME "/aggregatecuts", "aggregate all generated cuts using the "
3382  "Lagrangian multipliers?", &sepadata->aggregatecuts, TRUE, DEFAULT_AGGREGATECUTS, NULL, NULL) );
3383 
3384  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxrounds", "maximal number of separation rounds per node "
3385  "(-1: unlimited)", &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
3386 
3387  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/maxroundsroot", "maximal number of separation rounds in "
3388  "the root node (-1: unlimited)", &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL,
3389  NULL) );
3390 
3391  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/perroundnmaxlpiters", "maximal number of separating LP "
3392  "iterations per separation round (-1: unlimited)", &sepadata->perroundnmaxlpiters, FALSE,
3393  DEFAULT_PERROUNDMAXLPITERS, -1, INT_MAX, NULL, NULL) );
3394 
3395  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxcutsperlp", "maximal number of cuts separated per "
3396  "Lagromory LP in the non-root node", &sepadata->nmaxcutsperlp, FALSE, DEFAULT_PERLPMAXCUTS, 0, INT_MAX, NULL,
3397  NULL) );
3398 
3399  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxcutsperlproot", "maximal number of cuts separated per "
3400  "Lagromory LP in the root node", &sepadata->nmaxcutsperlproot, FALSE, DEFAULT_PERLPMAXCUTSROOT, 0, INT_MAX,
3401  NULL, NULL) );
3402 
3403  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxmainiters", "maximal number of main loop iterations of "
3404  "the relax-and-cut algorithm", &sepadata->nmaxmainiters, TRUE, DEFAULT_MAXMAINITERS, 0, INT_MAX, NULL, NULL) );
3405 
3406  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxsubgradientiters", "maximal number of subgradient loop "
3407  "iterations of the relax-and-cut algorithm", &sepadata->nmaxsubgradientiters, TRUE,
3408  DEFAULT_MAXSUBGRADIENTITERS, 0, INT_MAX, NULL, NULL) );
3409 
3410  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/cutgenfreq", "frequency of subgradient iterations for "
3411  "generating cuts", &sepadata->cutgenfreq, TRUE, DEFAULT_CUTGENFREQ, 0, INT_MAX, NULL, NULL) );
3412 
3413  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/cutaddfreq", "frequency of subgradient iterations for "
3414  "adding cuts to objective function", &sepadata->cutaddfreq, TRUE, DEFAULT_CUTADDFREQ, 0, INT_MAX, NULL, NULL) );
3415 
3416  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxlagrangianvalsforavg", "maximal number of iterations "
3417  "for rolling average of Lagrangian value", &sepadata->nmaxlagrangianvalsforavg, TRUE,
3418  DEFAULT_MAXLAGRANGIANVALSFORAVG, 0, INT_MAX, NULL, NULL) );
3419 
3420  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/nmaxconsecitersformuupdate", "consecutive number of "
3421  "iterations used to determine if mu needs to be backtracked", &sepadata->nmaxconsecitersformuupdate, TRUE,
3422  DEFAULT_MAXCONSECITERSFORMUUPDATE, 0, INT_MAX, NULL, NULL) );
3423 
3424  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/projectiontype", "the ball into which the Lagrangian multipliers "
3425  "are projected for stabilization (0: no projection, 1: L1-norm ball projection, 2: L2-norm ball projection, 3: "
3426  "L_inf-norm ball projection)", &sepadata->projectiontype, TRUE, DEFAULT_PROJECTIONTYPE, 0, 3, NULL, NULL));
3427 
3428  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/stabilitycentertype", "type of stability center for "
3429  "taking weighted average of Lagrangian multipliers for stabilization (0: no weighted stabilization, 1: best "
3430  "Lagrangian multipliers)", &sepadata->stabilitycentertype, TRUE, DEFAULT_STABILITYCENTERTYPE, 0, 1, NULL,
3431  NULL) );
3432 
3433  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/optimalfacepriority", "priority of the optimal face for "
3434  "separator execution (0: low priority, 1: medium priority, 2: high priority)",
3435  &sepadata->optimalfacepriority, TRUE, DEFAULT_OPTIMALFACEPRIORITY, 0, 2, NULL, NULL) );
3436 
3437  SCIP_CALL( SCIPaddIntParam(scip, "separating/" SEPA_NAME "/minrestart", "minimum restart round for separator "
3438  "execution (0: from beginning of the instance solving, >= n with n >= 1: from restart round n)",
3439  &sepadata->minrestart, TRUE, DEFAULT_MINRESTART, 0, INT_MAX, NULL, NULL) );
3440 
3441  return SCIP_OKAY;
3442 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
#define DEFAULT_FORCECUTS
static SCIP_RETCODE checkLagrangianDualTermination(SCIP_SEPADATA *sepadata, int nnewaddedsoftcuts, int nyettoaddsoftcuts, SCIP_Bool objvecsdiffer, int ngeneratedcurrroundcuts, int nmaxgeneratedperroundcuts, int ncurrroundlpiters, int depth, SCIP_Bool *terminate)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1763
SCIP_RETCODE SCIPgetLPBInvRow(SCIP *scip, int r, SCIP_Real *coefs, int *inds, int *ninds)
Definition: scip_lp.c:714
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
#define NULL
Definition: def.h:267
SCIP_RETCODE SCIPlpiFree(SCIP_LPI **lpi)
Definition: lpi_clp.cpp:643
primal heuristic that tries a given solution
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_RETCODE SCIPlpiSetState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, const SCIP_LPISTATE *lpistate)
Definition: lpi_clp.cpp:3429
#define DEFAULT_PERROUNDCUTSFACTOR
static SCIP_RETCODE l1BallProjection(SCIP *scip, SCIP_Real *dualvector, int dualvectorlen, SCIP_Real radius)
SCIP_Longint SCIPgetNLPIterations(SCIP *scip)
static void updateSubgradient(SCIP *scip, SCIP_SOL *sol, SCIP_ROW **cuts, int ncuts, SCIP_Real *subgradient, SCIP_Real *dualvector, SCIP_Bool *subgradientzero, int *ncutviols, SCIP_Real *maxcutviol, int *nnzsubgradientdualprod, SCIP_Real *maxnzsubgradientdualprod)
#define DEFAULT_PERROUNDCUTSFACTORROOT
#define SEPA_PRIORITY
static SCIP_RETCODE addGMICutsAsSoftConss(SCIP_Real *dualvector, int ngeneratedcuts, int *naddedcuts, int *nnewaddedsoftcuts)
static SCIP_DECL_SEPAINIT(sepaInitLagromory)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
SCIP_RETCODE SCIPlpiGetSol(SCIP_LPI *lpi, SCIP_Real *objval, SCIP_Real *primsol, SCIP_Real *dualsol, SCIP_Real *activity, SCIP_Real *redcost)
Definition: lpi_clp.cpp:2788
#define DEFAULT_DELAYEDCUTS
SCIP_RETCODE SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
#define SCIP_MAXSTRLEN
Definition: def.h:288
SCIP_RETCODE SCIPlpiSolvePrimal(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:1805
static SCIP_RETCODE generateGMICuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int mainiternum, int subgradientiternum, SCIP_SOL *sol, SCIP_Real *solvals, int nmaxgeneratedperroundcuts, SCIP_Bool allowlocal, SCIP_ROW **generatedcurrroundcuts, SCIP_Real *generatedcutefficacies, int ngeneratedcurrroundcuts, int *ngeneratednewcuts, int depth, SCIP_Bool *cutoff)
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17213
#define SQR(x)
Definition: def.h:214
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetLPDualDegeneracy(SCIP *scip, SCIP_Real *degeneracy, SCIP_Real *varconsratio)
Definition: scip_lp.c:2792
#define QUAD_ARRAY_STORE(a, idx, x)
Definition: dbldblarith.h:55
static SCIP_RETCODE createLPWithSoftCuts(SCIP *scip, SCIP_SEPADATA *sepadata)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static SCIP_RETCODE solveLagrangianDual(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_SOL *sol, SCIP_Real *solvals, int mainiternum, SCIP_Real ubparam, int depth, SCIP_Bool allowlocal, int nmaxgeneratedperroundcuts, SCIP_Real *origobjcoefs, SCIP_Real origobjoffset, SCIP_Real *dualvector, int *nsoftcuts, SCIP_ROW **generatedcurrroundcuts, SCIP_Real *generatedcutefficacies, int *ngeneratedcutsperiter, int *ngeneratedcurrroundcuts, int *ncurrroundlpiters, SCIP_Bool *cutoff, SCIP_Real *bestlagrangianval, SCIP_Real *bestdualvector, int *bestdualvectorlen, int *nbestdualupdates, int *totaliternum)
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17351
#define DEFAULT_AGGREGATECUTS
#define DEFAULT_SORTCUTOFFSOL
#define DEFAULT_RADIUSMAX
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPgetLPI(SCIP *scip, SCIP_LPI **lpi)
Definition: scip_lp.c:985
SCIP_RETCODE SCIPaddDelayedPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:641
int SCIPgetMaxDepth(SCIP *scip)
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17227
static SCIP_RETCODE sepadataCreate(SCIP *scip, SCIP_SEPADATA **sepadata)
static SCIP_RETCODE generateInitCutPool(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int mainiternum, SCIP_SOL *sol, SCIP_Real *solvals, int nmaxgeneratedperroundcuts, SCIP_Bool allowlocal, SCIP_ROW **generatedcurrroundcuts, SCIP_Real *generatedcutefficacies, int *ngeneratedcutsperiter, int *ngeneratedcurrroundcuts, int depth, SCIP_Bool *cutoff)
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
#define FALSE
Definition: def.h:94
SCIP_Bool SCIPcolIsIntegral(SCIP_COL *col)
Definition: lp.c:17072
SCIP_Real SCIPcolGetUb(SCIP_COL *col)
Definition: lp.c:16973
SCIP_Real SCIPcolGetObj(SCIP_COL *col)
Definition: lp.c:16953
#define SEPA_DESC
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
#define TRUE
Definition: def.h:93
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:743
static SCIP_DECL_SEPAFREE(sepaFreeLagromory)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
#define DEFAULT_CUTSFILTERFACTOR
SCIP_RETCODE SCIPlpiSetRealpar(SCIP_LPI *lpi, SCIP_LPPARAM type, SCIP_Real dval)
Definition: lpi_clp.cpp:3833
SCIP_Longint SCIPgetNRootFirstLPIterations(SCIP *scip)
static SCIP_RETCODE constructCutRow(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int mainiternum, int subgradientiternum, int cutnnz, int *cutinds, SCIP_Real *cutcoefs, SCIP_Real cutefficacy, SCIP_Real cutrhs, SCIP_Bool cutislocal, int cutrank, SCIP_ROW **generatedcuts, SCIP_Real *generatedcutefficacies, int ngeneratedcurrroundcuts, int *ngeneratednewcuts, SCIP_Bool *cutoff)
static void updateBallRadius(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real maxviolscore, SCIP_Real maxviolscoreold, SCIP_Real nviolscore, SCIP_Real nviolscoreold, int nlpiters, SCIP_Real *ballradius)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
static SCIP_RETCODE solveLagromoryLP(SCIP *scip, SCIP_SEPADATA *sepadata, int depth, SCIP_Real origobjoffset, SCIP_Bool *solfound, SCIP_SOL *sol, SCIP_Real *solvals, SCIP_Real *objval, int *ncurrroundlpiters)
#define DEFAULT_MAXROUNDS
SCIP_MESSAGEHDLR * SCIPgetMessagehdlr(SCIP *scip)
Definition: scip_message.c:88
static SCIP_RETCODE updateObjectiveVector(SCIP *scip, SCIP_Real *dualvector, SCIP_ROW **cuts, int ncuts, SCIP_Real *origobjcoefs, SCIP_Bool *objvecsdiffer)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define QUAD_ASSIGN(a, constant)
Definition: dbldblarith.h:51
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:51
#define DEFAULT_MAXSUBGRADIENTITERS
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_RETCODE SCIPgetLPColsData(SCIP *scip, SCIP_COL ***cols, int *ncols)
Definition: scip_lp.c:471
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:151
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
#define DEFAULT_SEPARATEROWS
SCIP_RETCODE SCIPlpiCreate(SCIP_LPI **lpi, SCIP_MESSAGEHDLR *messagehdlr, const char *name, SCIP_OBJSEN objsen)
Definition: lpi_clp.cpp:531
#define DEFAULT_DELTASLAB1UB
SCIP_Real SCIPepsilon(SCIP *scip)
#define QUAD_TO_DBL(x)
Definition: dbldblarith.h:49
SCIP_RETCODE SCIPlpiAddCols(SCIP_LPI *lpi, int ncols, const SCIP_Real *obj, const SCIP_Real *lb, const SCIP_Real *ub, char **colnames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:758
#define DEFAULT_DELTASLAB2UB
#define MAKECONTINTEGRAL
SCIP_Real SCIPgetRowMaxActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1956
#define DEFAULT_CUTGENFREQ
#define DEFAULT_AWAY
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:633
static SCIP_RETCODE stabilizeDualVector(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *dualvector, int dualvectorlen, SCIP_Real *bestdualvector, int bestdualvectorlen, int nbestdualupdates, int subgradientiternum, int totaliternum, SCIP_Real maxviolscore, SCIP_Real maxviolscoreold, SCIP_Real nviolscore, SCIP_Real nviolscoreold, int nlpiters, SCIP_Real *ballradius)
SCIP_RETCODE SCIPheurPassSolTrySol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:252
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
#define DEFAULT_ROOTLPITERLIMITFACTOR
SCIP_Bool SCIPisLPSolBasic(SCIP *scip)
Definition: scip_lp.c:667
#define SEPA_USESSUBSCIP
SCIP_RETCODE SCIPlpiAddRows(SCIP_LPI *lpi, int nrows, const SCIP_Real *lhs, const SCIP_Real *rhs, char **rownames, int nnonz, const int *beg, const int *ind, const SCIP_Real *val)
Definition: lpi_clp.cpp:914
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16996
#define DEFAULT_MAXCONSECITERSFORMUUPDATE
#define SEPA_FREQ
#define DEFAULT_MUSLAB2FACTOR
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition: scip_heur.c:258
static void updateLagrangianValue(SCIP *scip, SCIP_Real objval, SCIP_Real *dualvector, SCIP_ROW **cuts, int ncuts, SCIP_Real *lagrangianval)
SCIP_RETCODE SCIPsolveDiveLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_lp.c:2678
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPsetSepaExit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXIT((*sepaexit)))
Definition: scip_sepa.c:199
SCIP_RETCODE SCIPincludeSepaLagromory(SCIP *scip)
#define DEFAULT_MAXLAGRANGIANVALSFORAVG
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17401
#define DEFAULT_MUPARAMUB
#define FIXINTEGRALRHS
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:880
SCIP_RETCODE SCIPlpiFreeState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
Definition: lpi_clp.cpp:3503
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
static SCIP_RETCODE aggregateGeneratedCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_ROW **generatedcuts, SCIP_Real *bestdualvector, int bestdualvectorlen, SCIP_ROW **aggrcuts, int *naggrcuts, SCIP_Bool *cutoff)
#define QUAD(x)
Definition: dbldblarith.h:47
static SCIP_RETCODE checkMainLoopTermination(SCIP_SEPADATA *sepadata, SCIP_Bool cutoff, SCIP_Bool dualvecsdiffer, int ngeneratedcurrroundcuts, int nsoftcuts, int nmaxgeneratedperroundcuts, int ncurrroundlpiters, int depth, SCIP_Bool *terminate)
SCIP_Real SCIPcolGetLb(SCIP_COL *col)
Definition: lp.c:16963
SCIP_Bool SCIProwIsIntegral(SCIP_ROW *row)
Definition: lp.c:17391
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:643
static SCIP_RETCODE updateDualVector(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *dualvector1, SCIP_Real *dualvector2, int dualvector2len, int ndualvector2updates, int subgradientiternum, int totaliternum, SCIP_Real steplength, SCIP_Real *subgradient, int ncuts, SCIP_Bool backtrack, SCIP_Real maxviolscore, SCIP_Real maxviolscoreold, SCIP_Real nviolscore, SCIP_Real nviolscoreold, int nlpiters, SCIP_Bool *dualvecsdiffer, SCIP_Real *ballradius)
#define DEFAULT_MUSLAB1FACTOR
#define REALABS(x)
Definition: def.h:197
static SCIP_DECL_SEPACOPY(sepaCopyLagromory)
int SCIPgetNLPRows(SCIP *scip)
Definition: scip_lp.c:626
#define QUAD_ARRAY_LOAD(r, a, idx)
Definition: dbldblarith.h:54
#define SCIP_CALL(x)
Definition: def.h:380
static SCIP_RETCODE solveLPWithHardCuts(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Bool *solfound, SCIP_SOL *sol, SCIP_Real *solvals)
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
#define DEFAULT_OPTIMALFACEPRIORITY
#define SCIPquadprecProdDD(r, a, b)
Definition: dbldblarith.h:58
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17411
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17238
#define DEFAULT_TOTALLPITERLIMITFACTOR
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip_sepa.c:109
static void weightedDualVector(SCIP_SEPADATA *sepadata, SCIP_Real *dualvector, int dualvectorlen, SCIP_Real *stabilitycenter, int stabilitycenterlen, int nbestdualupdates, int totaliternum)
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
SCIP_Longint SCIPsepaGetNCalls(SCIP_SEPA *sepa)
Definition: sepa.c:860
#define DEFAULT_MINRESTART
SCIP_RETCODE SCIPcalcMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, SCIP_Bool fixintegralrhs, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_Real scale, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:3881
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1077
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17248
#define DEFAULT_MUBACKTRACKFACTOR
#define DEFAULT_TOTALCUTSFACTOR
#define DEFAULT_DUALDEGENERACYRATETHRESHOLD
#define DEFAULT_PERROUNDMAXLPITERS
#define SCIP_Bool
Definition: def.h:91
static SCIP_DECL_SEPAEXIT(sepaExitLagromory)
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
#define QUAD_ARRAY_SIZE(size)
Definition: dbldblarith.h:53
static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, SCIP_Real ubparam, int depth, SCIP_Bool allowlocal, SCIP_RESULT *result)
#define DEFAULT_MAXROUNDSROOT
#define DEFAULT_MUPARAMLB
#define DEFAULT_PROJECTIONTYPE
#define DEFAULT_PERLPMAXCUTS
lagromory separator
SCIP_Real SCIPlpiInfinity(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:3919
#define DEFAULT_RADIUSUPDATEWEIGHT
SCIP_Bool SCIPlpiIsDualFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2609
SCIP_RETCODE SCIPlpiGetState(SCIP_LPI *lpi, BMS_BLKMEM *blkmem, SCIP_LPISTATE **lpistate)
Definition: lpi_clp.cpp:3389
int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1886
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:361
#define MIN(x, y)
Definition: def.h:243
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1453
static void l2BallProjection(SCIP *scip, SCIP_Real *dualvector, int dualvectorlen, SCIP_Real radius)
static SCIP_RETCODE createLPWithHardCuts(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_ROW **cuts, int ncuts)
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:841
#define SEPA_DELAY
#define DEFAULT_STABILITYCENTERTYPE
int SCIPgetNRuns(SCIP *scip)
#define DEFAULT_PERLPITERFACTOR
#define POSTPROCESS
SCIP_RETCODE SCIPgetLPBasisInd(SCIP *scip, int *basisind)
Definition: scip_lp.c:686
SCIP_COL ** SCIPgetLPCols(SCIP *scip)
Definition: scip_lp.c:506
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define DEFAULT_UBPARAMPOSFACTOR
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2144
#define BMSclearMemory(ptr)
Definition: memory.h:129
SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:343
static void linfBallProjection(SCIP *scip, SCIP_Real *dualvector, int dualvectorlen, SCIP_Real radius)
#define SCIPquadprecSumQQ(r, a, b)
Definition: dbldblarith.h:67
#define DEFAULT_MAKEINTEGRAL
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10130
int SCIProwGetRank(SCIP_ROW *row)
Definition: lp.c:17381
#define SCIP_REAL_MAX
Definition: def.h:174
#define SEPA_MAXBOUNDDIST
#define MAXAGGRLEN(ncols)
#define DEFAULT_CUTADDFREQ
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
SCIP_Real SCIProwGetConstant(SCIP_ROW *row)
Definition: lp.c:17258
SCIP_Real SCIPgetTransObjoffset(SCIP *scip)
Definition: scip_prob.c:1367
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
SCIP_Longint SCIPgetNNodeInitLPIterations(SCIP *scip)
#define SEPA_NAME
#define MAX(x, y)
Definition: def.h:239
#define DEFAULT_ALLOWLOCAL
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:167
SCIP_RETCODE SCIPsetSepaInit(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAINIT((*sepainit)))
Definition: scip_sepa.c:183
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:247
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2169
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPaggrRowSumRows(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real *weights, int *rowinds, int nrowinds, SCIP_Bool sidetypebasis, SCIP_Bool allowlocal, int negslack, int maxaggrlen, SCIP_Bool *valid)
Definition: cuts.c:2287
SCIP_RETCODE SCIPchgVarObjDive(SCIP *scip, SCIP_VAR *var, SCIP_Real newobj)
Definition: scip_lp.c:2378
#define DEFAULT_UBPARAMNEGFACTOR
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17042
#define DEFAULT_DYNAMICCUTS
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition: lp.c:17534
static SCIP_RETCODE addCuts(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_ROW **cuts, int ncuts, SCIP_Longint maxdnom, SCIP_Real maxscale, int *naddedcuts, SCIP_Bool *cutoff)
#define DEFAULT_PERROOTLPITERFACTOR
#define RANDSEED
#define DEFAULT_VARCONSRATIOTHRESHOLD
static SCIP_RETCODE sepadataFree(SCIP *scip, SCIP_SEPADATA **sepadata)
#define DEFAULT_MAXMAINITERS
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
#define DEFAULT_MUPARAMINIT
#define DEFAULT_MUPARAMCONST
static void updateStepLength(SCIP *scip, SCIP_Real muparam, SCIP_Real ubparam, SCIP_Real lagrangianval, SCIP_Real *subgradient, int ncuts, SCIP_Real *steplength)
#define SCIP_Real
Definition: def.h:173
#define DEFAULT_MUSLAB3FACTOR
SCIP_Bool SCIPlpiIsPrimalFeasible(SCIP_LPI *lpi)
Definition: lpi_clp.cpp:2521
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
SCIP_Real SCIPgetRowMinActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1939
#define DEFAULT_CONST
static SCIP_RETCODE updateMuSteplengthParam(SCIP *scip, SCIP_SEPADATA *sepadata, int subgradientiternum, SCIP_Real ubparam, SCIP_Real *lagrangianvals, SCIP_Real bestlagrangianval, SCIP_Real avglagrangianval, SCIP_Real *muparam, SCIP_Bool *backtrack)
#define DEFAULT_RADIUSMIN
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1731
#define SCIP_Longint
Definition: def.h:158
#define DEFAULT_PERROUNDLPITERLIMITFACTOR
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17585
SCIP_RETCODE SCIPstartDive(SCIP *scip)
Definition: scip_lp.c:2242
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define BOUNDSWITCH
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:570
static SCIP_RETCODE deleteLPWithSoftCuts(SCIP *scip, SCIP_SEPADATA *sepadata)
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
SCIP_RETCODE SCIPendDive(SCIP *scip)
Definition: scip_lp.c:2291
#define USEVBDS
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
#define DEFAULT_SIDETYPEBASIS
int SCIPcolGetLPPos(SCIP_COL *col)
Definition: lp.c:17093
SCIP_RETCODE SCIPmakeRowIntegral(SCIP *scip, SCIP_ROW *row, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool usecontvars, SCIP_Bool *success)
Definition: scip_lp.c:1844
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
#define DEFAULT_PERLPMAXCUTSROOT
SCIP_Real SCIPgetVarObjDive(SCIP *scip, SCIP_VAR *var)
Definition: scip_lp.c:2587
#define DEFAULT_RADIUSINIT
static SCIP_DECL_SEPAEXECLP(sepaExeclpLagromory)
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:52
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_Real SCIPgetRowActivity(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2104
SCIP_RETCODE SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:184