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