1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the program and library             */
4    	/*         SCIP --- Solving Constraint Integer Programs                      */
5    	/*                                                                           */
6    	/*    Copyright (C) 2002-2022 Konrad-Zuse-Zentrum                            */
7    	/*                            fuer Informationstechnik Berlin                */
8    	/*                                                                           */
9    	/*  SCIP is distributed under the terms of the ZIB Academic License.         */
10   	/*                                                                           */
11   	/*  You should have received a copy of the ZIB Academic License              */
12   	/*  along with SCIP; see the file COPYING. If not visit scipopt.org.         */
13   	/*                                                                           */
14   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15   	
16   	/**@file   scip_nlpi.c
17   	 * @ingroup OTHER_CFILES
18   	 * @brief  public methods for NLP interfaces
19   	 * @author Stefan Vigerske
20   	 * @author Thorsten Gellermann
21   	 *
22   	 * @todo check SCIP_STAGE_* switches
23   	 * @todo allow for optional callbacks
24   	 */
25   	
26   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
27   	
28   	#include "scip/scip_nlp.h"
29   	#include "blockmemshell/memory.h"
30   	#include "scip/scip_expr.h"
31   	#include "scip/scip_lp.h"
32   	#include "scip/scip_message.h"
33   	#include "scip/scip_mem.h"
34   	#include "scip/scip_nlpi.h"
35   	#include "scip/scip_numerics.h"
36   	#include "scip/scip_param.h"
37   	#include "scip/scip_prob.h"
38   	#include "scip/pub_expr.h"
39   	#include "scip/pub_lp.h"
40   	#include "scip/pub_var.h"
41   	#include "scip/expr_varidx.h"
42   	#include "scip/debug.h"
43   	#include "scip/nlpi.h"
44   	#include "scip/paramset.h"
45   	#include "scip/set.h"
46   	#include "scip/struct_scip.h"
47   	
48   	
49   	/** method to call, when the priority of an NLPI was changed */
50   	static
51   	SCIP_DECL_PARAMCHGD(paramChgdNlpiPriority)
52   	{  /*lint --e{715}*/
53   	   SCIP_PARAMDATA* paramdata;
54   	
55   	   paramdata = SCIPparamGetData(param);
56   	   assert(paramdata != NULL);
57   	
58   	   /* use SCIPsetSetPriorityNlpi() to mark the nlpis unsorted */
59   	   SCIP_CALL( SCIPsetNlpiPriority(scip, (SCIP_NLPI*)paramdata, SCIPparamGetInt(param)) );
60   	
61   	   return SCIP_OKAY;
62   	}
63   	
64   	/** create varidx expression for var expression
65   	 *
66   	 * called when expr is duplicated for addition to NLPI
67   	 */
68   	static
69   	SCIP_DECL_EXPR_MAPEXPR(mapvar2varidx)
70   	{
71   	   SCIP_HASHMAP* var2idx;
72   	   int varidx;
73   	
74   	   assert(sourcescip != NULL);
75   	   assert(sourcescip == targetscip);
76   	   assert(sourceexpr != NULL);
77   	   assert(targetexpr != NULL);
78   	   assert(*targetexpr == NULL);
79   	   assert(mapexprdata != NULL);
80   	
81   	   /* do not provide map if not variable */
82   	   if( !SCIPisExprVar(sourcescip, sourceexpr) )
83   	      return SCIP_OKAY;
84   	
85   	   assert(SCIPvarIsActive(SCIPgetVarExprVar(sourceexpr)));
86   	
87   	   var2idx = (SCIP_HASHMAP*)mapexprdata;
88   	   assert(SCIPhashmapExists(var2idx, SCIPgetVarExprVar(sourceexpr)));
89   	
90   	   varidx = SCIPhashmapGetImageInt(var2idx, SCIPgetVarExprVar(sourceexpr));
91   	
92   	   SCIP_CALL( SCIPcreateExprVaridx(targetscip, targetexpr, varidx, ownercreate, ownercreatedata) );
93   	
94   	   return SCIP_OKAY;
95   	}
96   	
97   	/** creates an NLPI and includes it into SCIP */
98   	SCIP_RETCODE SCIPincludeNlpi(
99   	   SCIP*                           scip,                        /**< SCIP data structure */
100  	   const char*                     name,                        /**< name of NLP interface */
101  	   const char*                     description,                 /**< description of NLP interface */
102  	   int                             priority,                    /**< priority of NLP interface */
103  	   SCIP_DECL_NLPICOPY              ((*nlpicopy)),               /**< copying an NLPI, can be NULL */
104  	   SCIP_DECL_NLPIFREE              ((*nlpifree)),               /**< free NLPI user data */
105  	   SCIP_DECL_NLPIGETSOLVERPOINTER  ((*nlpigetsolverpointer)),   /**< get solver pointer, can be NULL */
106  	   SCIP_DECL_NLPICREATEPROBLEM     ((*nlpicreateproblem)),      /**< create a new problem instance */
107  	   SCIP_DECL_NLPIFREEPROBLEM       ((*nlpifreeproblem)),        /**< free a problem instance */
108  	   SCIP_DECL_NLPIGETPROBLEMPOINTER ((*nlpigetproblempointer)),  /**< get problem pointer, can be NULL */
109  	   SCIP_DECL_NLPIADDVARS           ((*nlpiaddvars)),            /**< add variables */
110  	   SCIP_DECL_NLPIADDCONSTRAINTS    ((*nlpiaddconstraints)),     /**< add constraints */
111  	   SCIP_DECL_NLPISETOBJECTIVE      ((*nlpisetobjective)),       /**< set objective */
112  	   SCIP_DECL_NLPICHGVARBOUNDS      ((*nlpichgvarbounds)),       /**< change variable bounds */
113  	   SCIP_DECL_NLPICHGCONSSIDES      ((*nlpichgconssides)),       /**< change constraint sides */
114  	   SCIP_DECL_NLPIDELVARSET         ((*nlpidelvarset)),          /**< delete a set of constraints */
115  	   SCIP_DECL_NLPIDELCONSSET        ((*nlpidelconsset)),         /**< delete a set of constraints */
116  	   SCIP_DECL_NLPICHGLINEARCOEFS    ((*nlpichglinearcoefs)),     /**< change coefficients in linear part of a constraint or objective */
117  	   SCIP_DECL_NLPICHGEXPR           ((*nlpichgexpr)),            /**< change nonlinear expression a constraint or objective */
118  	   SCIP_DECL_NLPICHGOBJCONSTANT    ((*nlpichgobjconstant)),     /**< change the constant offset in the objective */
119  	   SCIP_DECL_NLPISETINITIALGUESS   ((*nlpisetinitialguess)),    /**< set initial guess, can be NULL */
120  	   SCIP_DECL_NLPISOLVE             ((*nlpisolve)),              /**< solve NLP */
121  	   SCIP_DECL_NLPIGETSOLSTAT        ((*nlpigetsolstat)),         /**< get solution status */
122  	   SCIP_DECL_NLPIGETTERMSTAT       ((*nlpigettermstat)),        /**< get termination status */
123  	   SCIP_DECL_NLPIGETSOLUTION       ((*nlpigetsolution)),        /**< get solution */
124  	   SCIP_DECL_NLPIGETSTATISTICS     ((*nlpigetstatistics)),      /**< get solve statistics */
125  	   SCIP_NLPIDATA*                  nlpidata                     /**< NLP interface local data */
126  	   )
127  	{
128  	   SCIP_NLPI* nlpi = NULL;
129  	   char paramname[SCIP_MAXSTRLEN];
130  	   char paramdesc[SCIP_MAXSTRLEN];
131  	
132  	   assert(scip != NULL);
133  	
(1) Event cond_false: Condition "(_restat_ = SCIP_OKAY) != SCIP_OKAY", taking false branch.
(2) Event if_end: End of if statement.
134  	   SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeNlpi", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) );
135  	
136  	   /* check whether NLPI of given name is already present */
(3) Event cond_false: Condition "SCIPfindNlpi(scip, name) != NULL", taking false branch.
137  	   if( SCIPfindNlpi(scip, name) != NULL )
138  	   {
139  	      SCIPerrorMessage("NLPI <%s> already included.\n", name);
140  	      return SCIP_INVALIDDATA;
(4) Event if_end: End of if statement.
141  	   }
142  	
(5) Event alloc_arg: "SCIPnlpiCreate" allocates memory that is stored into "nlpi". [details]
(6) Event cond_true: Condition "(_restat_ = SCIPnlpiCreate(&nlpi, name, description, priority, nlpicopy, nlpifree, nlpigetsolverpointer, nlpicreateproblem, nlpifreeproblem, nlpigetproblempointer, nlpiaddvars, nlpiaddconstraints, nlpisetobjective, nlpichgvarbounds, nlpichgconssides, nlpidelvarset, nlpidelconsset, nlpichglinearcoefs, nlpichgexpr, nlpichgobjconstant, nlpisetinitialguess, nlpisolve, nlpigetsolstat, nlpigettermstat, nlpigetsolution, nlpigetstatistics, nlpidata)) != SCIP_OKAY", taking true branch.
(7) Event leaked_storage: Variable "nlpi" going out of scope leaks the storage it points to.
143  	   SCIP_CALL( SCIPnlpiCreate(&nlpi, name, description, priority,
144  	      nlpicopy, nlpifree, nlpigetsolverpointer,
145  	      nlpicreateproblem, nlpifreeproblem, nlpigetproblempointer,
146  	      nlpiaddvars, nlpiaddconstraints, nlpisetobjective, nlpichgvarbounds, nlpichgconssides, nlpidelvarset, nlpidelconsset, nlpichglinearcoefs, nlpichgexpr, nlpichgobjconstant,
147  	      nlpisetinitialguess, nlpisolve, nlpigetsolstat, nlpigettermstat, nlpigetsolution, nlpigetstatistics,
148  	      nlpidata) );
149  	   assert(nlpi != NULL);
150  	
151  	   SCIP_CALL( SCIPsetIncludeNlpi(scip->set, nlpi) );
152  	
153  	   /* add parameters */
154  	   (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "nlpi/%s/priority", name);
155  	   (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "priority of NLPI <%s>", name);
156  	   SCIP_CALL( SCIPaddIntParam(scip, paramname, paramdesc,
157  	         NULL, FALSE, SCIPnlpiGetPriority(nlpi), INT_MIN/4, INT_MAX/4,
158  	         paramChgdNlpiPriority, (SCIP_PARAMDATA*)nlpi) ); /*lint !e740*/
159  	
160  	   return SCIP_OKAY;
161  	}
162  	
163  	/** returns the NLPI of the given name, or NULL if not existing */
164  	SCIP_NLPI* SCIPfindNlpi(
165  	   SCIP*                 scip,               /**< SCIP data structure */
166  	   const char*           name                /**< name of NLPI */
167  	   )
168  	{
169  	   assert(scip != NULL);
170  	   assert(scip->set != NULL);
171  	   assert(name != NULL);
172  	
173  	   return SCIPsetFindNlpi(scip->set, name);
174  	}
175  	
176  	/** returns the array of currently available NLPIs (sorted by priority) */
177  	SCIP_NLPI** SCIPgetNlpis(
178  	   SCIP*                 scip                /**< SCIP data structure */
179  	   )
180  	{
181  	   assert(scip != NULL);
182  	   assert(scip->set != NULL);
183  	
184  	   SCIPsetSortNlpis(scip->set);
185  	
186  	   return scip->set->nlpis;
187  	}
188  	
189  	/** returns the number of currently available NLPIs */
190  	int SCIPgetNNlpis(
191  	   SCIP*                 scip                /**< SCIP data structure */
192  	   )
193  	{
194  	   assert(scip != NULL);
195  	   assert(scip->set != NULL);
196  	
197  	   return scip->set->nnlpis;
198  	}
199  	
200  	/** sets the priority of an NLPI */
201  	SCIP_RETCODE SCIPsetNlpiPriority(
202  	   SCIP*                 scip,               /**< SCIP data structure */
203  	   SCIP_NLPI*            nlpi,               /**< NLPI */
204  	   int                   priority            /**< new priority of the NLPI */
205  	   )
206  	{
207  	   assert(scip != NULL);
208  	   assert(scip->set != NULL);
209  	
210  	   SCIPsetSetPriorityNlpi(scip->set, nlpi, priority);
211  	
212  	   return SCIP_OKAY;
213  	}
214  	
215  	/** gets internal pointer to NLP solver */
216  	SCIP_DECL_NLPIGETSOLVERPOINTER(SCIPgetNlpiSolverPointer)
217  	{
218  	   assert(scip != NULL);
219  	
220  	   return SCIPnlpiGetSolverPointer(scip->set, nlpi, problem);
221  	}
222  	
223  	/** creates an empty problem instance */
224  	SCIP_DECL_NLPICREATEPROBLEM(SCIPcreateNlpiProblem)
225  	{
226  	   assert(scip != NULL);
227  	
228  	   SCIP_CALL( SCIPnlpiCreateProblem(scip->set, nlpi, problem, name) );
229  	
230  	   return SCIP_OKAY;
231  	}
232  	
233  	/** frees a problem instance */
234  	SCIP_DECL_NLPIFREEPROBLEM(SCIPfreeNlpiProblem)
235  	{
236  	   assert(scip != NULL);
237  	
238  	   SCIP_CALL( SCIPnlpiFreeProblem(scip->set, nlpi, problem) );
239  	
240  	   return SCIP_OKAY;
241  	}
242  	
243  	/** gets internal pointer to solver-internal problem instance */
244  	SCIP_DECL_NLPIGETPROBLEMPOINTER(SCIPgetNlpiProblemPointer)
245  	{
246  	   assert(scip != NULL);
247  	
248  	   return SCIPnlpiGetProblemPointer(scip->set, nlpi, problem);
249  	}
250  	
251  	/** add variables to nlpi */
252  	SCIP_DECL_NLPIADDVARS(SCIPaddNlpiVars)
253  	{
254  	   assert(scip != NULL);
255  	
256  	   SCIP_CALL( SCIPnlpiAddVars(scip->set, nlpi, problem, nvars, lbs, ubs, varnames) );
257  	
258  	   return SCIP_OKAY;
259  	}
260  	
261  	/** add constraints to nlpi */
262  	SCIP_DECL_NLPIADDCONSTRAINTS(SCIPaddNlpiConstraints)
263  	{
264  	   assert(scip != NULL);
265  	
266  	   SCIP_CALL( SCIPnlpiAddConstraints(scip->set, nlpi, problem, nconss, lhss, rhss, nlininds, lininds, linvals, exprs, names) );
267  	
268  	   return SCIP_OKAY;
269  	}
270  	
271  	/** sets or overwrites objective, a minimization problem is expected */
272  	SCIP_DECL_NLPISETOBJECTIVE(SCIPsetNlpiObjective)
273  	{
274  	   assert(scip != NULL);
275  	
276  	   SCIP_CALL( SCIPnlpiSetObjective(scip->set, nlpi, problem, nlins, lininds, linvals, expr, constant) );
277  	
278  	   return SCIP_OKAY;
279  	}
280  	
281  	/** change variable bounds */
282  	SCIP_DECL_NLPICHGVARBOUNDS(SCIPchgNlpiVarBounds)
283  	{
284  	   assert(scip != NULL);
285  	
286  	   SCIP_CALL( SCIPnlpiChgVarBounds(scip->set, nlpi, problem, nvars, indices, lbs, ubs) );
287  	
288  	   return SCIP_OKAY;
289  	}
290  	
291  	/** change constraint sides */
292  	SCIP_DECL_NLPICHGCONSSIDES(SCIPchgNlpiConsSides)
293  	{
294  	   assert(scip != NULL);
295  	
296  	   SCIP_CALL( SCIPnlpiChgConsSides(scip->set, nlpi, problem, nconss, indices, lhss, rhss) );
297  	
298  	   return SCIP_OKAY;
299  	}
300  	
301  	/** delete a set of variables */
302  	SCIP_DECL_NLPIDELVARSET(SCIPdelNlpiVarSet)
303  	{
304  	   assert(scip != NULL);
305  	
306  	   SCIP_CALL( SCIPnlpiDelVarSet(scip->set, nlpi, problem, dstats, dstatssize) );
307  	
308  	   return SCIP_OKAY;
309  	}
310  	
311  	/** delete a set of constraints */
312  	SCIP_DECL_NLPIDELCONSSET(SCIPdelNlpiConsSet)
313  	{
314  	   assert(scip != NULL);
315  	
316  	   SCIP_CALL( SCIPnlpiDelConsSet(scip->set, nlpi, problem, dstats, dstatssize) );
317  	
318  	   return SCIP_OKAY;
319  	}
320  	
321  	/** changes or adds linear coefficients in a constraint or objective */
322  	SCIP_DECL_NLPICHGLINEARCOEFS(SCIPchgNlpiLinearCoefs)
323  	{
324  	   assert(scip != NULL);
325  	
326  	   SCIP_CALL( SCIPnlpiChgLinearCoefs(scip->set, nlpi, problem, idx, nvals, varidxs, vals) );
327  	
328  	   return SCIP_OKAY;
329  	}
330  	
331  	/** change the expression in the nonlinear part */
332  	SCIP_DECL_NLPICHGEXPR(SCIPchgNlpiExpr)
333  	{
334  	   assert(scip != NULL);
335  	
336  	   SCIP_CALL( SCIPnlpiChgExpr(scip->set, nlpi, problem, idxcons, expr) );
337  	
338  	   return SCIP_OKAY;
339  	}
340  	
341  	/** change the constant offset in the objective */
342  	SCIP_DECL_NLPICHGOBJCONSTANT(SCIPchgNlpiObjConstant)
343  	{
344  	   assert(scip != NULL);
345  	
346  	   SCIP_CALL( SCIPnlpiChgObjConstant(scip->set, nlpi, problem, objconstant) );
347  	
348  	   return SCIP_OKAY;
349  	}
350  	
351  	/** sets initial guess */
352  	SCIP_DECL_NLPISETINITIALGUESS(SCIPsetNlpiInitialGuess)
353  	{
354  	   assert(scip != NULL);
355  	
356  	   SCIP_CALL( SCIPnlpiSetInitialGuess(scip->set, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues) );
357  	
358  	   return SCIP_OKAY;
359  	}
360  	
361  	/** try to solve NLP with all parameters given as SCIP_NLPPARAM struct
362  	 *
363  	 * Typical use is
364  	 *
365  	 *     SCIP_NLPPARAM nlparam = { SCIP_NLPPARAM_DEFAULT(scip); }
366  	 *     nlpparam.iterlim = 42;
367  	 *     SCIP_CALL( SCIPsolveNlpiParam(scip, nlpi, nlpiproblem, nlpparam) );
368  	 *
369  	 * or, in "one" line:
370  	 *
371  	 *     SCIP_CALL( SCIPsolveNlpiParam(scip, nlpi, nlpiproblem,
372  	 *        (SCIP_NLPPARAM){ SCIP_NLPPARAM_DEFAULT(scip), .iterlimit = 42 }) );
373  	 *
374  	 * To get the latter, also \ref SCIPsolveNlpi can be used.
375  	 */
376  	SCIP_DECL_NLPISOLVE(SCIPsolveNlpiParam)
377  	{
378  	   assert(scip != NULL);
379  	
380  	   SCIP_CALL( SCIPnlpiSolve(scip->set, scip->stat, nlpi, problem, &param) );
381  	
382  	   return SCIP_OKAY;
383  	}
384  	
385  	#if defined(_MSC_VER) && _MSC_VER < 1800
386  	/* warn that SCIPsolveNlpi() macro isn't perfect with ancient MSVC */
387  	#pragma message ( "Warning: designated initializers not supported by this version of MSVC. Parameters given to NLP solves will be ignored." )
388  	#endif
389  	
390  	/** gives solution status */
391  	SCIP_DECL_NLPIGETSOLSTAT(SCIPgetNlpiSolstat)
392  	{
393  	   assert(scip != NULL);
394  	
395  	   return SCIPnlpiGetSolstat(scip->set, nlpi, problem);
396  	}
397  	
398  	/** gives termination reason */
399  	SCIP_DECL_NLPIGETTERMSTAT(SCIPgetNlpiTermstat)
400  	{
401  	   assert(scip != NULL);
402  	
403  	   return SCIPnlpiGetTermstat(scip->set, nlpi, problem);
404  	}
405  	
406  	/** gives primal and dual solution
407  	 * for a ranged constraint, the dual variable is positive if the right hand side is active and negative if the left hand side is active
408  	 */
409  	SCIP_DECL_NLPIGETSOLUTION(SCIPgetNlpiSolution)
410  	{
411  	   assert(scip != NULL);
412  	
413  	   SCIP_CALL( SCIPnlpiGetSolution(scip->set, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues, objval) );
414  	
415  	   return SCIP_OKAY;
416  	}
417  	
418  	/** gives solve statistics */
419  	SCIP_DECL_NLPIGETSTATISTICS(SCIPgetNlpiStatistics)
420  	{
421  	   assert(scip != NULL);
422  	
423  	   SCIP_CALL( SCIPnlpiGetStatistics(scip->set, nlpi, problem, statistics) );
424  	
425  	   return SCIP_OKAY;
426  	}
427  	
428  	/** creates a NLPI problem from given nonlinear rows
429  	 *
430  	 * The function computes for each variable the number of non-linear occurrences and stores it in the nlscore array.
431  	 *
432  	 * @note the first row corresponds always to the cutoff row (even if cutoffbound is SCIPinfinity(scip))
433  	 **/
434  	SCIP_RETCODE SCIPcreateNlpiProblemFromNlRows(
435  	   SCIP*                 scip,               /**< SCIP data structure */
436  	   SCIP_NLPI*            nlpi,               /**< interface to NLP solver */
437  	   SCIP_NLPIPROBLEM**    nlpiprob,           /**< buffer to store pointer to created nlpi problem */
438  	   const char*           name,               /**< name to give to problem */
439  	   SCIP_NLROW**          nlrows,             /**< nonlinear rows */
440  	   int                   nnlrows,            /**< number of nonlinear rows */
441  	   SCIP_HASHMAP*         var2idx,            /**< empty hash map to store mapping between variables and indices in nlpiprob */
442  	   SCIP_HASHMAP*         nlrow2idx,          /**< empty hash map to store mapping between variables and indices in nlpiprob, can be NULL */
443  	   SCIP_Real*            nlscore,            /**< array to store the score of each nonlinear variable (NULL if not needed) */
444  	   SCIP_Real             cutoffbound,        /**< cutoff bound */
445  	   SCIP_Bool             setobj,             /**< whether the objective function should be set to one of the SCIP problem */
446  	   SCIP_Bool             onlyconvex          /**< filter only for convex constraints */
447  	   )
448  	{
449  	   SCIP_EXPR** exprs;
450  	   SCIP_Real** linvals;
451  	   int** lininds;
452  	   int* nlininds;
453  	   SCIP_Real* lhss;
454  	   SCIP_Real* rhss;
455  	   const char** names;
456  	   SCIP_VAR** vars;
457  	   int nvars;
458  	   SCIP_Real* lbs;
459  	   SCIP_Real* ubs;
460  	   SCIP_Real* objvals = NULL;
461  	   int* objinds = NULL;
462  	   const char** varnames;
463  	   int nobjinds;
464  	   int nconss;
465  	   SCIP_EXPRITER* it = NULL;
466  	   int i;
467  	
468  	   assert(nlpiprob != NULL);
469  	   assert(name != NULL);
470  	   assert(var2idx != NULL);
471  	   assert(nlrows != NULL);
472  	   assert(nnlrows > 0);
473  	   assert(nlpi != NULL);
474  	
475  	   SCIPdebugMsg(scip, "SCIPcreateNlpiProblemFromNlRows() called with cutoffbound %g\n", cutoffbound);
476  	
477  	   SCIP_CALL( SCIPnlpiCreateProblem(scip->set, nlpi, nlpiprob, name) );
478  	
479  	   if( nlscore != NULL )
480  	   {
481  	      BMSclearMemoryArray(nlscore, SCIPgetNVars(scip));
482  	   }
483  	   vars = SCIPgetVars(scip);
484  	   nvars = SCIPgetNVars(scip);
485  	   nconss = 0;
486  	
487  	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nnlrows + 1) );
488  	   SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nnlrows + 1) );
489  	   SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nnlrows + 1) );
490  	   SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nnlrows + 1) );
491  	   SCIP_CALL( SCIPallocBufferArray(scip, &names, nnlrows + 1) );
492  	   SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nnlrows + 1) );
493  	   SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nnlrows + 1) );
494  	
495  	   if( setobj )
496  	   {
497  	      SCIP_CALL( SCIPallocBufferArray(scip, &objvals, nvars) );
498  	      SCIP_CALL( SCIPallocBufferArray(scip, &objinds, nvars) );
499  	   }
500  	
501  	   SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nvars) );
502  	   SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nvars) );
503  	   SCIP_CALL( SCIPallocBufferArray(scip, &varnames, nvars) );
504  	
505  	   /* create a unique mapping between variables and {0,..,nvars-1} */
506  	   nobjinds = 0;
507  	   for( i = 0; i < nvars; ++i )
508  	   {
509  	      assert(vars[i] != NULL);
510  	      SCIP_CALL( SCIPhashmapInsertInt(var2idx, (void*)vars[i], i) );
511  	
512  	      lbs[i] = SCIPvarGetLbLocal(vars[i]);
513  	      ubs[i] = SCIPvarGetUbLocal(vars[i]);
514  	      varnames[i] = SCIPvarGetName(vars[i]);
515  	
516  	      /* collect non-zero objective coefficients */
517  	      if( setobj && !SCIPisZero(scip, SCIPvarGetObj(vars[i])) )
518  	      {
519  	         assert(objvals != NULL);
520  	         assert(objinds != NULL);
521  	
522  	         objvals[nobjinds] = SCIPvarGetObj(vars[i]);
523  	         objinds[nobjinds] = i;
524  	         ++nobjinds;
525  	      }
526  	   }
527  	
528  	   /* add variables */
529  	   SCIP_CALL( SCIPaddNlpiVars(scip, nlpi, *nlpiprob, nvars, lbs, ubs, varnames) );
530  	   SCIPfreeBufferArray(scip, &varnames);
531  	   SCIPfreeBufferArray(scip, &ubs);
532  	   SCIPfreeBufferArray(scip, &lbs);
533  	
534  	   /* set the objective function */
535  	   if( setobj )
536  	   {
537  	      if( nobjinds > 0 )
538  	      {
539  	         SCIP_CALL( SCIPsetNlpiObjective(scip, nlpi, *nlpiprob, nobjinds, objinds, objvals, NULL, 0.0) );
540  	      }
541  	
542  	      SCIPfreeBufferArray(scip, &objinds);
543  	      SCIPfreeBufferArray(scip, &objvals);
544  	   }
545  	
546  	   /* add row for cutoff bound even if cutoffbound == SCIPinfinity() */
547  	   lhss[nconss] = -SCIPinfinity(scip);
548  	   rhss[nconss] = cutoffbound;
549  	   names[nconss] = "objcutoff";
550  	   lininds[nconss] = NULL;
551  	   linvals[nconss] = NULL;
552  	   nlininds[nconss] = 0;
553  	   exprs[nconss] = NULL;
554  	
555  	   SCIP_CALL( SCIPallocBufferArray(scip, &lininds[nconss], nvars) ); /*lint !e866*/
556  	   SCIP_CALL( SCIPallocBufferArray(scip, &linvals[nconss], nvars) ); /*lint !e866*/
557  	
558  	   for( i = 0; i < nvars; ++i )
559  	   {
560  	      if( !SCIPisZero(scip, SCIPvarGetObj(vars[i])) )
561  	      {
562  	         linvals[nconss][nlininds[nconss]] = SCIPvarGetObj(vars[i]);
563  	         lininds[nconss][nlininds[nconss]] = i;
564  	         ++nlininds[nconss];
565  	      }
566  	   }
567  	   ++nconss;
568  	
569  	   if( nlscore != NULL )
570  	   {
571  	      SCIP_CALL( SCIPcreateExpriter(scip, &it) );
572  	   }
573  	
574  	   /* add convex nonlinear rows to NLPI problem */
575  	   for( i = 0; i < nnlrows; ++i )
576  	   {
577  	      SCIP_Bool userhs;
578  	      SCIP_Bool uselhs;
579  	      int k;
580  	      SCIP_NLROW* nlrow;
581  	
582  	      nlrow = nlrows[i];
583  	      assert(nlrow != NULL);
584  	
585  	      uselhs = FALSE;
586  	      userhs = FALSE;
587  	
588  	      /* check curvature together with constraint sides of a nonlinear row */
589  	      if( SCIPnlrowGetExpr(nlrow) == NULL )
590  	      {
591  	         uselhs = TRUE;
592  	         userhs = TRUE;
593  	      }
594  	      else
595  	      {
596  	         if( (!onlyconvex || SCIPnlrowGetCurvature(nlrow) == SCIP_EXPRCURV_CONVEX)
597  	            && !SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)) )
598  	            userhs = TRUE;
599  	         if( (!onlyconvex || SCIPnlrowGetCurvature(nlrow) == SCIP_EXPRCURV_CONCAVE)
600  	            && !SCIPisInfinity(scip, SCIPnlrowGetLhs(nlrow)) )
601  	            uselhs = TRUE;
602  	      }
603  	
604  	      if( !uselhs && !userhs )
605  	         continue;
606  	
607  	      lhss[nconss] = uselhs ? SCIPnlrowGetLhs(nlrow) - SCIPnlrowGetConstant(nlrow) : -SCIPinfinity(scip);
608  	      rhss[nconss] = userhs ? SCIPnlrowGetRhs(nlrow) - SCIPnlrowGetConstant(nlrow) :  SCIPinfinity(scip);
609  	      names[nconss] = SCIPnlrowGetName(nlrow);
610  	      nlininds[nconss] = 0;
611  	      lininds[nconss] = NULL;
612  	      linvals[nconss] = NULL;
613  	
614  	      /* copy linear part */
615  	      if( SCIPnlrowGetNLinearVars(nlrow) > 0 )
616  	      {
617  	         SCIP_VAR* var;
618  	
619  	         nlininds[nconss] = SCIPnlrowGetNLinearVars(nlrow);
620  	
621  	         SCIP_CALL( SCIPallocBufferArray(scip, &lininds[nconss], nlininds[nconss]) ); /*lint !e866*/
622  	         SCIP_CALL( SCIPallocBufferArray(scip, &linvals[nconss], nlininds[nconss]) ); /*lint !e866*/
623  	
624  	         for( k = 0; k < nlininds[nconss]; ++k )
625  	         {
626  	            var = SCIPnlrowGetLinearVars(nlrow)[k];
627  	            assert(var != NULL);
628  	            assert(SCIPhashmapExists(var2idx, (void*)var));
629  	
630  	            lininds[nconss][k] = SCIPhashmapGetImageInt(var2idx, (void*)var);
631  	            assert(var == vars[lininds[nconss][k]]);
632  	            linvals[nconss][k] = SCIPnlrowGetLinearCoefs(nlrow)[k];
633  	         }
634  	      }
635  	
636  	      if( SCIPnlrowGetExpr(nlrow) != NULL )
637  	      {
638  	         /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
639  	         SCIP_CALL( SCIPduplicateExpr(scip, SCIPnlrowGetExpr(nlrow), &exprs[nconss], mapvar2varidx, var2idx, NULL, NULL) );
640  	      }
641  	      else
642  	      {
643  	         exprs[nconss] = NULL;
644  	      }
645  	
646  	      /* update nlscore */
647  	      if( nlscore != NULL && exprs[nconss] != NULL )
648  	      {
649  	         SCIP_EXPR* expr;
650  	         int varidx;
651  	
652  	         SCIP_CALL( SCIPexpriterInit(it, exprs[nconss], SCIP_EXPRITER_DFS, FALSE) );
653  	         for( expr = exprs[nconss]; !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it) )  /*lint !e441*/ /*lint !e440*/
654  	         {
655  	            if( !SCIPisExprVaridx(scip, expr) )
656  	               continue;
657  	
658  	            varidx = SCIPgetIndexExprVaridx(expr);
659  	            assert(varidx >= 0);
660  	            assert(varidx < nvars);
661  	
662  	            /* update nlscore */
663  	            nlscore[varidx] += 1.0;
664  	         }
665  	      }
666  	
667  	      /* if the row to index hash map is provided, we need to store the row index */
668  	      if( nlrow2idx != NULL )
669  	      {
670  	         SCIP_CALL( SCIPhashmapInsertInt(nlrow2idx, nlrow, nconss) );
671  	      }
672  	
673  	      ++nconss;
674  	   }
675  	   assert(nconss > 0);
676  	
677  	   /* pass all constraint information to nlpi */
678  	   SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, *nlpiprob, nconss, lhss, rhss, nlininds, lininds, linvals,
679  	         exprs, names) );
680  	
681  	   if( it != NULL )
682  	   {
683  	      SCIPfreeExpriter(&it);
684  	   }
685  	
686  	   /* free memory */
687  	   for( i = nconss - 1; i > 0; --i )
688  	   {
689  	      if( nlininds[i] > 0 )
690  	      {
691  	         assert(linvals[i] != NULL);
692  	         assert(lininds[i] != NULL);
693  	         SCIPfreeBufferArray(scip, &linvals[i]);
694  	         SCIPfreeBufferArray(scip, &lininds[i]);
695  	      }
696  	      if( exprs[i] != NULL )
697  	      {
698  	         SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
699  	      }
700  	   }
701  	   /* free row for cutoff bound even if objective is 0 */
702  	   SCIPfreeBufferArray(scip, &linvals[i]);
703  	   SCIPfreeBufferArray(scip, &lininds[i]);
704  	
705  	   SCIPfreeBufferArray(scip, &rhss);
706  	   SCIPfreeBufferArray(scip, &lhss);
707  	   SCIPfreeBufferArray(scip, &names);
708  	   SCIPfreeBufferArray(scip, &nlininds);
709  	   SCIPfreeBufferArray(scip, &lininds);
710  	   SCIPfreeBufferArray(scip, &linvals);
711  	   SCIPfreeBufferArray(scip, &exprs);
712  	
713  	   return SCIP_OKAY;
714  	}
715  	
716  	/** updates variable bounds and the cutoff row in a NLPI problem
717  	 *
718  	 * The NLPI problem must have been setup by SCIPcreateNlpiProblemFromNlRows().
719  	 */
720  	SCIP_RETCODE SCIPupdateNlpiProblem(
721  	   SCIP*                 scip,               /**< SCIP data structure */
722  	   SCIP_NLPI*            nlpi,               /**< interface to NLP solver */
723  	   SCIP_NLPIPROBLEM*     nlpiprob,           /**< nlpi problem representing the convex NLP relaxation */
724  	   SCIP_HASHMAP*         var2nlpiidx,        /**< mapping between variables and nlpi indices */
725  	   SCIP_VAR**            nlpivars,           /**< array containing all variables of the nlpi */
726  	   int                   nlpinvars,          /**< total number of nlpi variables */
727  	   SCIP_Real             cutoffbound         /**< new cutoff bound */
728  	   )
729  	{
730  	   SCIP_Real* lbs;
731  	   SCIP_Real* ubs;
732  	   SCIP_Real lhs;
733  	   SCIP_Real rhs;
734  	   int* inds;
735  	   int i;
736  	
737  	   SCIPdebugMsg(scip, "SCIPupdateNlpiProblem() called\n");
738  	
739  	   /* update variable bounds */
740  	   SCIP_CALL( SCIPallocBufferArray(scip, &lbs, nlpinvars) );
741  	   SCIP_CALL( SCIPallocBufferArray(scip, &ubs, nlpinvars) );
742  	   SCIP_CALL( SCIPallocBufferArray(scip, &inds, nlpinvars) );
743  	
744  	   for( i = 0; i < nlpinvars; ++i )
745  	   {
746  	      assert(nlpivars[i] != NULL);
747  	      assert(SCIPhashmapExists(var2nlpiidx, (void*)nlpivars[i]));
748  	
749  	      lbs[i] = SCIPvarGetLbLocal(nlpivars[i]);
750  	      ubs[i] = SCIPvarGetUbLocal(nlpivars[i]);
751  	      inds[i] = SCIPhashmapGetImageInt(var2nlpiidx, (void*)nlpivars[i]);
752  	      assert(inds[i] >= 0 && inds[i] < nlpinvars);
753  	   }
754  	
755  	   SCIP_CALL( SCIPchgNlpiVarBounds(scip, nlpi, nlpiprob, nlpinvars, inds, lbs, ubs) );
756  	
757  	   SCIPfreeBufferArray(scip, &inds);
758  	   SCIPfreeBufferArray(scip, &ubs);
759  	   SCIPfreeBufferArray(scip, &lbs);
760  	
761  	   /* update cutoff row */
762  	   lhs = -SCIPinfinity(scip);
763  	   rhs = cutoffbound;
764  	   i = 0;
765  	
766  	   SCIP_CALL( SCIPchgNlpiConsSides(scip, nlpi, nlpiprob, 1, &i, &lhs, &rhs) );
767  	
768  	   return SCIP_OKAY;
769  	}
770  	
771  	/** adds SCIP_ROWs to a NLPI problem */
772  	SCIP_RETCODE SCIPaddNlpiProblemRows(
773  	   SCIP*                 scip,               /**< SCIP data structure */
774  	   SCIP_NLPI*            nlpi,               /**< interface to NLP solver */
775  	   SCIP_NLPIPROBLEM*     nlpiprob,           /**< nlpi problem */
776  	   SCIP_HASHMAP*         var2idx,            /**< empty hash map to store mapping between variables and indices in nlpiprob */
777  	   SCIP_ROW**            rows,               /**< rows to add */
778  	   int                   nrows               /**< number of rows to add */
779  	   )
780  	{
781  	   const char** names;
782  	   SCIP_Real* lhss;
783  	   SCIP_Real* rhss;
784  	   SCIP_Real** linvals;
785  	   int** lininds;
786  	   int* nlininds;
787  	   int i;
788  	
789  	   assert(nlpi != NULL);
790  	   assert(nlpiprob != NULL);
791  	   assert(var2idx != NULL);
792  	   assert(nrows == 0 || rows != NULL);
793  	
794  	   SCIPdebugMsg(scip, "SCIPaddNlpiProblemRows() called with %d rows\n", nrows);
795  	
796  	   if( nrows <= 0 )
797  	      return SCIP_OKAY;
798  	
799  	   SCIP_CALL( SCIPallocBufferArray(scip, &names, nrows) );
800  	   SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nrows) );
801  	   SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nrows) );
802  	   SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nrows) );
803  	   SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nrows) );
804  	   SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nrows) );
805  	
806  	   for( i = 0; i < nrows; ++i )
807  	   {
808  	      int k;
809  	
810  	      assert(rows[i] != NULL);
811  	      assert(SCIProwGetNNonz(rows[i]) <= SCIPgetNVars(scip));
812  	
813  	      names[i] = SCIProwGetName(rows[i]);
814  	      lhss[i] = SCIProwGetLhs(rows[i]) - SCIProwGetConstant(rows[i]);
815  	      rhss[i] = SCIProwGetRhs(rows[i]) - SCIProwGetConstant(rows[i]);
816  	      nlininds[i] = SCIProwGetNNonz(rows[i]);
817  	      linvals[i] = SCIProwGetVals(rows[i]);
818  	      lininds[i] = NULL;
819  	
820  	      SCIP_CALL( SCIPallocBufferArray(scip, &lininds[i], SCIProwGetNNonz(rows[i])) ); /*lint !e866*/
821  	
822  	      for( k = 0; k < SCIProwGetNNonz(rows[i]); ++k )
823  	      {
824  	         SCIP_VAR* var;
825  	
826  	         var = SCIPcolGetVar(SCIProwGetCols(rows[i])[k]);
827  	         assert(var != NULL);
828  	         assert(SCIPhashmapExists(var2idx, (void*)var));
829  	
830  	         lininds[i][k] = SCIPhashmapGetImageInt(var2idx, (void*)var);
831  	         assert(lininds[i][k] >= 0 && lininds[i][k] < SCIPgetNVars(scip));
832  	      }
833  	   }
834  	
835  	   /* pass all linear rows to the nlpi */
836  	   SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, nlpiprob, nrows, lhss, rhss, nlininds, lininds, linvals,
837  	         NULL, names) );
838  	
839  	   /* free memory */
840  	   for( i = nrows - 1; i >= 0; --i )
841  	   {
842  	      SCIPfreeBufferArray(scip, &lininds[i]);
843  	   }
844  	   SCIPfreeBufferArray(scip, &nlininds);
845  	   SCIPfreeBufferArray(scip, &lininds);
846  	   SCIPfreeBufferArray(scip, &linvals);
847  	   SCIPfreeBufferArray(scip, &rhss);
848  	   SCIPfreeBufferArray(scip, &lhss);
849  	   SCIPfreeBufferArray(scip, &names);
850  	
851  	   return SCIP_OKAY;
852  	}
853  	
854  	/** adds SCIP_NLROWs to a NLPI problem */
855  	SCIP_RETCODE SCIPaddNlpiProblemNlRows(
856  	   SCIP*                 scip,               /**< SCIP data structure */
857  	   SCIP_NLPI*            nlpi,               /**< interface to NLP solver */
858  	   SCIP_NLPIPROBLEM*     nlpiprob,           /**< nlpi problem */
859  	   SCIP_HASHMAP*         var2idx,            /**< empty hash map to store mapping between variables and indices in nlpiprob */
860  	   SCIP_NLROW**          nlrows,             /**< rows to add */
861  	   int                   nnlrows             /**< number of rows to add */
862  	   )
863  	{
864  	   const char** names;
865  	   SCIP_Real* lhss;
866  	   SCIP_Real* rhss;
867  	   SCIP_Real** linvals;
868  	   int** lininds;
869  	   int* nlininds;
870  	   SCIP_EXPR** exprs;
871  	   int i;
872  	
873  	   assert(nlpi != NULL);
874  	   assert(nlpiprob != NULL);
875  	   assert(var2idx != NULL);
876  	   assert(nnlrows == 0 || nlrows != NULL);
877  	
878  	   SCIPdebugMsg(scip, "SCIPaddNlpiProblemNlRows() called with %d rows\n", nnlrows);
879  	
880  	   if( nnlrows <= 0 )
881  	      return SCIP_OKAY;
882  	
883  	   SCIP_CALL( SCIPallocBufferArray(scip, &names, nnlrows) );
884  	   SCIP_CALL( SCIPallocBufferArray(scip, &lhss, nnlrows) );
885  	   SCIP_CALL( SCIPallocBufferArray(scip, &rhss, nnlrows) );
886  	   SCIP_CALL( SCIPallocBufferArray(scip, &linvals, nnlrows) );
887  	   SCIP_CALL( SCIPallocBufferArray(scip, &lininds, nnlrows) );
888  	   SCIP_CALL( SCIPallocBufferArray(scip, &nlininds, nnlrows) );
889  	   SCIP_CALL( SCIPallocBufferArray(scip, &exprs, nnlrows) );
890  	
891  	   for( i = 0; i < nnlrows; ++i )
892  	   {
893  	      SCIP_NLROW* nlrow;
894  	
895  	      nlrow = nlrows[i];
896  	      assert(nlrow != NULL);
897  	
898  	      lhss[i] = !SCIPisInfinity(scip, -SCIPnlrowGetLhs(nlrow)) ? SCIPnlrowGetLhs(nlrow) - SCIPnlrowGetConstant(nlrow) : -SCIPinfinity(scip);
899  	      rhss[i] = !SCIPisInfinity(scip, SCIPnlrowGetRhs(nlrow)) ? SCIPnlrowGetRhs(nlrow) - SCIPnlrowGetConstant(nlrow) :  SCIPinfinity(scip);
900  	      names[i] = SCIPnlrowGetName(nlrow);
901  	      nlininds[i] = 0;
902  	      lininds[i] = NULL;
903  	      linvals[i] = NULL;
904  	
905  	      /* copy linear part */
906  	      if( SCIPnlrowGetNLinearVars(nlrow) > 0 )
907  	      {
908  	         SCIP_VAR* var;
909  	         int k;
910  	
911  	         nlininds[i] = SCIPnlrowGetNLinearVars(nlrow);
912  	
913  	         SCIP_CALL( SCIPallocBufferArray(scip, &lininds[i], nlininds[i]) ); /*lint !e866*/
914  	         SCIP_CALL( SCIPallocBufferArray(scip, &linvals[i], nlininds[i]) ); /*lint !e866*/
915  	
916  	         for( k = 0; k < nlininds[i]; ++k )
917  	         {
918  	            var = SCIPnlrowGetLinearVars(nlrow)[k];
919  	            assert(var != NULL);
920  	            assert(SCIPhashmapExists(var2idx, (void*)var));
921  	
922  	            lininds[i][k] = SCIPhashmapGetImageInt(var2idx, (void*)var);
923  	            linvals[i][k] = SCIPnlrowGetLinearCoefs(nlrow)[k];
924  	         }
925  	      }
926  	
927  	      if( SCIPnlrowGetExpr(nlrow) != NULL )
928  	      {
929  	         /* create copy of expr that uses varidx expressions corresponding to variables indices in NLPI */
930  	         SCIP_CALL( SCIPduplicateExpr(scip, SCIPnlrowGetExpr(nlrow), &exprs[i], mapvar2varidx, var2idx, NULL, NULL) );
931  	      }
932  	      else
933  	      {
934  	         exprs[i] = NULL;
935  	      }
936  	   }
937  	
938  	   /* pass all rows to the nlpi */
939  	   SCIP_CALL( SCIPaddNlpiConstraints(scip, nlpi, nlpiprob, nnlrows, lhss, rhss, nlininds, lininds, linvals, exprs, names) );
940  	
941  	   /* free memory */
942  	   for( i = nnlrows - 1; i >= 0; --i )
943  	   {
944  	      SCIPfreeBufferArrayNull(scip, &linvals[i]);
945  	      SCIPfreeBufferArrayNull(scip, &lininds[i]);
946  	      if( exprs[i] != NULL )
947  	      {
948  	         SCIP_CALL( SCIPreleaseExpr(scip, &exprs[i]) );
949  	      }
950  	   }
951  	   SCIPfreeBufferArray(scip, &exprs);
952  	   SCIPfreeBufferArray(scip, &nlininds);
953  	   SCIPfreeBufferArray(scip, &lininds);
954  	   SCIPfreeBufferArray(scip, &linvals);
955  	   SCIPfreeBufferArray(scip, &rhss);
956  	   SCIPfreeBufferArray(scip, &lhss);
957  	   SCIPfreeBufferArray(scip, &names);
958  	
959  	   return SCIP_OKAY;
960  	}
961