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   nlpi.c
26   	 * @ingroup OTHER_CFILES
27   	 * @brief  methods for handling NLP solver interface
28   	 * @author Stefan Vigerske
29   	 * @author Thorsten Gellermann
30   	 */
31   	
32   	/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33   	
34   	#include <stdio.h>
35   	#include <assert.h>
36   	#include <string.h>
37   	
38   	#include "scip/nlpi.h"
39   	#include "scip/pub_message.h"
40   	#include "scip/pub_nlpi.h"
41   	#include "scip/clock.h"
42   	#include "scip/struct_nlpi.h"
43   	#include "scip/struct_set.h"
44   	#include "scip/struct_stat.h"
45   	
46   	/** compares two NLPIs w.r.t. their priority */
47   	SCIP_DECL_SORTPTRCOMP(SCIPnlpiComp)
48   	{  /*lint --e{715}*/
49   	   return ((SCIP_NLPI*)elem2)->priority - ((SCIP_NLPI*)elem1)->priority;
50   	}
51   	
52   	/** creates an NLP solver interface */
53   	SCIP_RETCODE SCIPnlpiCreate(
54   	   SCIP_NLPI**                     nlpi,                        /**< pointer to NLP interface data structure */
55   	   const char*                     name,                        /**< name of NLP interface */
56   	   const char*                     description,                 /**< description of NLP interface */
57   	   int                             priority,                    /**< priority of NLP interface */
58   	   SCIP_DECL_NLPICOPY              ((*nlpicopy)),               /**< copying of NLPI, can be NULL */
59   	   SCIP_DECL_NLPIFREE              ((*nlpifree)),               /**< free NLPI user data */
60   	   SCIP_DECL_NLPIGETSOLVERPOINTER  ((*nlpigetsolverpointer)),   /**< get solver pointer, can be NULL */
61   	   SCIP_DECL_NLPICREATEPROBLEM     ((*nlpicreateproblem)),      /**< create a new problem instance */
62   	   SCIP_DECL_NLPIFREEPROBLEM       ((*nlpifreeproblem)),        /**< free a problem instance */
63   	   SCIP_DECL_NLPIGETPROBLEMPOINTER ((*nlpigetproblempointer)),  /**< get problem pointer, can be NULL */
64   	   SCIP_DECL_NLPIADDVARS           ((*nlpiaddvars)),            /**< add variables */
65   	   SCIP_DECL_NLPIADDCONSTRAINTS    ((*nlpiaddconstraints)),     /**< add constraints */
66   	   SCIP_DECL_NLPISETOBJECTIVE      ((*nlpisetobjective)),       /**< set objective */
67   	   SCIP_DECL_NLPICHGVARBOUNDS      ((*nlpichgvarbounds)),       /**< change variable bounds */
68   	   SCIP_DECL_NLPICHGCONSSIDES      ((*nlpichgconssides)),       /**< change constraint sides */
69   	   SCIP_DECL_NLPIDELVARSET         ((*nlpidelvarset)),          /**< delete a set of constraints */
70   	   SCIP_DECL_NLPIDELCONSSET        ((*nlpidelconsset)),         /**< delete a set of constraints */
71   	   SCIP_DECL_NLPICHGLINEARCOEFS    ((*nlpichglinearcoefs)),     /**< change coefficients in linear part of a constraint or objective */
72   	   SCIP_DECL_NLPICHGEXPR           ((*nlpichgexpr)),            /**< change nonlinear expression a constraint or objective */
73   	   SCIP_DECL_NLPICHGOBJCONSTANT    ((*nlpichgobjconstant)),     /**< change the constant offset in the objective */
74   	   SCIP_DECL_NLPISETINITIALGUESS   ((*nlpisetinitialguess)),    /**< set initial guess, can be NULL */
75   	   SCIP_DECL_NLPISOLVE             ((*nlpisolve)),              /**< solve NLP */
76   	   SCIP_DECL_NLPIGETSOLSTAT        ((*nlpigetsolstat)),         /**< get solution status */
77   	   SCIP_DECL_NLPIGETTERMSTAT       ((*nlpigettermstat)),        /**< get termination status */
78   	   SCIP_DECL_NLPIGETSOLUTION       ((*nlpigetsolution)),        /**< get solution */
79   	   SCIP_DECL_NLPIGETSTATISTICS     ((*nlpigetstatistics)),      /**< get solve statistics */
80   	   SCIP_NLPIDATA*                  nlpidata                     /**< NLP interface local data */
81   	   )
82   	{  /*lint --e{715}*/
83   	   SCIP_RETCODE retcode;
84   	
85   	   assert(nlpi != NULL);
86   	   assert(name != NULL);
87   	   assert(description != NULL);
88   	   assert(nlpifree != NULL);
89   	   assert(nlpicreateproblem != NULL);
90   	   assert(nlpifreeproblem != NULL);
91   	   assert(nlpiaddvars != NULL);
92   	   assert(nlpiaddconstraints != NULL);
93   	   assert(nlpisetobjective != NULL);
94   	   assert(nlpichgvarbounds != NULL);
95   	   assert(nlpichgconssides != NULL);
96   	   assert(nlpidelconsset != NULL);
97   	   assert(nlpichglinearcoefs != NULL);
98   	   assert(nlpichgobjconstant != NULL);
99   	   assert(nlpisolve != NULL);
100  	   assert(nlpigetsolstat != NULL);
101  	   assert(nlpigettermstat != NULL);
102  	   assert(nlpigetsolution != NULL);
103  	   assert(nlpigetstatistics != NULL);
104  	
105  	   SCIP_ALLOC( BMSallocClearMemory(nlpi) );
106  	
107  	   if( BMSduplicateMemoryArray(&(*nlpi)->name, name, strlen(name)+1) == NULL )
108  	   {
109  	      BMSfreeMemory(nlpi);
110  	      return SCIP_NOMEMORY;
111  	   }
112  	
113  	   if( BMSduplicateMemoryArray(&(*nlpi)->description, description, strlen(description)+1) == NULL )
114  	   {
115  	      BMSfreeMemoryArray(&(*nlpi)->name);
116  	      BMSfreeMemory(nlpi);
117  	      return SCIP_NOMEMORY;
118  	   }
119  	
120  	   (*nlpi)->priority = priority;
121  	   (*nlpi)->nlpicopy = nlpicopy;
122  	   (*nlpi)->nlpifree = nlpifree;
123  	   (*nlpi)->nlpigetsolverpointer = nlpigetsolverpointer;
124  	   (*nlpi)->nlpicreateproblem = nlpicreateproblem;
125  	   (*nlpi)->nlpifreeproblem = nlpifreeproblem;
126  	   (*nlpi)->nlpigetproblempointer = nlpigetproblempointer;
127  	   (*nlpi)->nlpiaddvars = nlpiaddvars;
128  	   (*nlpi)->nlpiaddconstraints = nlpiaddconstraints;
129  	   (*nlpi)->nlpisetobjective = nlpisetobjective;
130  	   (*nlpi)->nlpichgvarbounds = nlpichgvarbounds;
131  	   (*nlpi)->nlpichgconssides = nlpichgconssides;
132  	   (*nlpi)->nlpidelvarset = nlpidelvarset;
133  	   (*nlpi)->nlpidelconsset = nlpidelconsset;
134  	   (*nlpi)->nlpichglinearcoefs = nlpichglinearcoefs;
135  	   (*nlpi)->nlpichgobjconstant = nlpichgobjconstant;
136  	   (*nlpi)->nlpisetinitialguess = nlpisetinitialguess;
137  	   (*nlpi)->nlpisolve = nlpisolve;
138  	   (*nlpi)->nlpigetsolstat = nlpigetsolstat;
139  	   (*nlpi)->nlpigettermstat = nlpigettermstat;
140  	   (*nlpi)->nlpigetsolution = nlpigetsolution;
141  	   (*nlpi)->nlpigetstatistics = nlpigetstatistics;
142  	   (*nlpi)->nlpidata = nlpidata;
143  	
144  	   retcode = SCIPclockCreate(&(*nlpi)->problemtime, SCIP_CLOCKTYPE_DEFAULT);
145  	   if( retcode != SCIP_OKAY )
146  	   {
147  	      BMSfreeMemoryArray(&(*nlpi)->description);
148  	      BMSfreeMemoryArray(&(*nlpi)->name);
149  	      BMSfreeMemory(nlpi);
150  	   }
151  	
152  	   return retcode;
153  	}
154  	
155  	/** sets NLP solver priority */
156  	void SCIPnlpiSetPriority(
157  	   SCIP_NLPI*            nlpi,               /**< NLP interface structure */
158  	   int                   priority            /**< new priority of NLPI */
159  	   )
160  	{
161  	   assert(nlpi != NULL);
162  	
163  	   nlpi->priority = priority;
164  	}
165  	
166  	/** copies an NLPI and includes it into another SCIP instance */
167  	SCIP_RETCODE SCIPnlpiCopyInclude(
168  	   SCIP_NLPI*            sourcenlpi,         /**< the NLP interface to copy */
169  	   SCIP_SET*             targetset           /**< global SCIP settings where to include copy */
170  	   )
171  	{
172  	   assert(sourcenlpi != NULL);
173  	   assert(targetset != NULL);
174  	
175  	   if( sourcenlpi->nlpicopy != NULL )
176  	   {
177  	      SCIP_CALL( sourcenlpi->nlpicopy(targetset->scip, sourcenlpi) );
178  	   }
179  	
180  	   return SCIP_OKAY;
181  	}
182  	
183  	/** frees NLPI */
184  	SCIP_RETCODE SCIPnlpiFree(
185  	   SCIP_NLPI**           nlpi,               /**< pointer to NLPI data structure */
186  	   SCIP_SET*             set                 /**< global SCIP settings */
187  	   )
188  	{
189  	   assert(nlpi  != NULL);
190  	   assert(*nlpi != NULL);
191  	   assert(set   != NULL);
192  	
193  	   if( (*nlpi)->nlpifree != NULL )
194  	   {
195  	      SCIP_CALL( (*nlpi)->nlpifree(set->scip, *nlpi, &(*nlpi)->nlpidata) );
196  	      assert((*nlpi)->nlpidata == NULL);
197  	   }
198  	   BMSfreeMemoryArray(&(*nlpi)->name);
199  	   BMSfreeMemoryArray(&(*nlpi)->description);
200  	
201  	   SCIPclockFree(&(*nlpi)->problemtime);
202  	
203  	   BMSfreeMemory(nlpi);
204  	
205  	   assert(*nlpi == NULL);
206  	
207  	   return SCIP_OKAY;
208  	}
209  	
210  	/** initializes NLPI */
211  	void SCIPnlpiInit(
212  	   SCIP_NLPI*            nlpi                /**< solver interface */
213  	   )
214  	{
215  	   assert(nlpi != NULL);
216  	
217  	   nlpi->nproblems = 0;
218  	   nlpi->nsolves = 0;
219  	   SCIPclockReset(nlpi->problemtime);
220  	   nlpi->solvetime = 0.0;
221  	   nlpi->evaltime = 0.0;
222  	   nlpi->niter = 0L;
223  	   BMSclearMemoryArray(nlpi->ntermstat, (int)SCIP_NLPTERMSTAT_OTHER+1);
224  	   BMSclearMemoryArray(nlpi->nsolstat, (int)SCIP_NLPSOLSTAT_UNKNOWN+1);
225  	}
226  	
227  	/** gets pointer for NLP solver */
228  	void* SCIPnlpiGetSolverPointer(
229  	   SCIP_SET*             set,                /**< global SCIP settings */
230  	   SCIP_NLPI*            nlpi,               /**< solver interface */
231  	   SCIP_NLPIPROBLEM*     problem             /**< problem instance, or NULL */
232  	   )
233  	{
234  	   assert(set != NULL);
235  	   assert(nlpi != NULL);
236  	
237  	   if( nlpi->nlpigetsolverpointer != NULL )
238  	      return nlpi->nlpigetsolverpointer(set->scip, nlpi, problem);
239  	   else
240  	      return NULL;
241  	}
242  	
243  	/** creates a problem instance */
244  	SCIP_RETCODE SCIPnlpiCreateProblem(
245  	   SCIP_SET*             set,                /**< global SCIP settings */
246  	   SCIP_NLPI*            nlpi,               /**< solver interface */
247  	   SCIP_NLPIPROBLEM**    problem,            /**< problem pointer to store the problem data */
248  	   const char*           name                /**< name of problem, can be NULL */
249  	   )
250  	{
251  	   assert(set != NULL);
252  	   assert(nlpi != NULL);
253  	   assert(nlpi->nlpicreateproblem != NULL);
254  	   assert(problem != NULL);
255  	
256  	   SCIPclockStart(nlpi->problemtime, set);
257  	   SCIP_CALL( nlpi->nlpicreateproblem(set->scip, nlpi, problem, name) );
258  	   SCIPclockStop(nlpi->problemtime, set);
259  	
260  	   ++nlpi->nproblems;
261  	
262  	   return SCIP_OKAY;
263  	}
264  	
265  	/** frees a problem instance */
266  	SCIP_RETCODE SCIPnlpiFreeProblem(
267  	   SCIP_SET*             set,                /**< global SCIP settings */
268  	   SCIP_NLPI*            nlpi,               /**< solver interface */
269  	   SCIP_NLPIPROBLEM**    problem             /**< pointer where problem instance is stored */
270  	   )
271  	{
272  	   assert(set != NULL);
273  	   assert(nlpi != NULL);
274  	   assert(nlpi->nlpifreeproblem != NULL);
275  	   assert(problem != NULL);
276  	
277  	   SCIPclockStart(nlpi->problemtime, set);
278  	   SCIP_CALL( nlpi->nlpifreeproblem(set->scip, nlpi, problem) );
279  	   SCIPclockStop(nlpi->problemtime, set);
280  	
281  	   return SCIP_OKAY;
282  	}
283  	
284  	/** gets pointer to solver-internal problem instance */
285  	void* SCIPnlpiGetProblemPointer(
286  	   SCIP_SET*             set,                /**< global SCIP settings */
287  	   SCIP_NLPI*            nlpi,               /**< solver interface */
288  	   SCIP_NLPIPROBLEM*     problem             /**< problem instance */
289  	   )
290  	{
291  	   assert(set != NULL);
292  	   assert(nlpi != NULL);
293  	   assert(problem != NULL);
294  	
295  	   if( nlpi->nlpigetproblempointer != NULL )
296  	      return nlpi->nlpigetproblempointer(set->scip, nlpi, problem);
297  	   else
298  	      return NULL;
299  	}
300  	
301  	/** add variables to nlpi */
302  	SCIP_RETCODE SCIPnlpiAddVars(
303  	   SCIP_SET*             set,                /**< global SCIP settings */
304  	   SCIP_NLPI*            nlpi,               /**< solver interface */
305  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
306  	   int                   nvars,              /**< number of variables */
307  	   const SCIP_Real*      lbs,                /**< lower bounds of variables, can be NULL if -infinity */
308  	   const SCIP_Real*      ubs,                /**< upper bounds of variables, can be NULL if +infinity */
309  	   const char**          varnames            /**< names of variables, can be NULL */
310  	   )
311  	{
312  	   assert(set != NULL);
313  	   assert(nlpi != NULL);
314  	   assert(nlpi->nlpiaddvars != NULL);
315  	   assert(problem != NULL);
316  	
317  	   SCIPclockStart(nlpi->problemtime, set);
318  	   SCIP_CALL( nlpi->nlpiaddvars(set->scip, nlpi, problem, nvars, lbs, ubs, varnames) );
319  	   SCIPclockStop(nlpi->problemtime, set);
320  	
321  	   return SCIP_OKAY;
322  	}
323  	
324  	/** add constraints to nlpi */
325  	SCIP_RETCODE SCIPnlpiAddConstraints(
326  	   SCIP_SET*             set,                /**< global SCIP settings */
327  	   SCIP_NLPI*            nlpi,               /**< solver interface */
328  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
329  	   int                   nconss,             /**< number of constraints */
330  	   const SCIP_Real*      lhss,               /**< left hand sides of constraints, can be NULL if -infinity */
331  	   const SCIP_Real*      rhss,               /**< right hand sides of constraints, can be NULL if +infinity */
332  	   const int*            nlininds,           /**< number of linear coefficients for each constraint, may be NULL in case of no linear part */
333  	   int* const*           lininds,            /**< indices of variables for linear coefficients for each constraint, may be NULL in case of no linear part */
334  	   SCIP_Real* const*     linvals,            /**< values of linear coefficient for each constraint, may be NULL in case of no linear part */
335  	   SCIP_EXPR**           exprs,              /**< expressions for nonlinear part of constraints, entry of array may be NULL in case of no nonlinear part, may be NULL in case of no nonlinear part in any constraint */
336  	   const char**          names               /**< names of constraints, may be NULL or entries may be NULL */
337  	   )
338  	{
339  	   assert(set != NULL);
340  	   assert(nlpi != NULL);
341  	   assert(nlpi->nlpiaddconstraints != NULL);
342  	   assert(problem != NULL);
343  	
344  	   SCIPclockStart(nlpi->problemtime, set);
345  	   SCIP_CALL( nlpi->nlpiaddconstraints(set->scip, nlpi, problem, nconss, lhss, rhss, nlininds, lininds, linvals, exprs, names) );
346  	   SCIPclockStop(nlpi->problemtime, set);
347  	
348  	   return SCIP_OKAY;
349  	}
350  	
351  	/** sets or overwrites objective, a minimization problem is expected */
352  	SCIP_RETCODE SCIPnlpiSetObjective(
353  	   SCIP_SET*             set,                /**< global SCIP settings */
354  	   SCIP_NLPI*            nlpi,               /**< solver interface */
355  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
356  	   int                   nlins,              /**< number of linear variables */
357  	   const int*            lininds,            /**< variable indices, may be NULL in case of no linear part */
358  	   const SCIP_Real*      linvals,            /**< coefficient values, may be NULL in case of no linear part */
359  	   SCIP_EXPR*            expr,               /**< expression for nonlinear part of objective function, may be NULL in case of no nonlinear part */
360  	   const SCIP_Real       constant            /**< objective value offset */
361  	   )
362  	{
363  	   assert(set != NULL);
364  	   assert(nlpi != NULL);
365  	   assert(nlpi->nlpisetobjective != NULL);
366  	   assert(problem != NULL);
367  	
368  	   SCIPclockStart(nlpi->problemtime, set);
369  	   SCIP_CALL( nlpi->nlpisetobjective(set->scip, nlpi, problem, nlins, lininds, linvals, expr, constant) );
370  	   SCIPclockStop(nlpi->problemtime, set);
371  	
372  	   return SCIP_OKAY;
373  	}
374  	
375  	/** change variable bounds */
376  	SCIP_RETCODE SCIPnlpiChgVarBounds(
377  	   SCIP_SET*             set,                /**< global SCIP settings */
378  	   SCIP_NLPI*            nlpi,               /**< solver interface */
379  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
380  	   const int             nvars,              /**< number of variables to change bounds */
381  	   const int*            indices,            /**< indices of variables to change bounds */
382  	   const SCIP_Real*      lbs,                /**< new lower bounds */
383  	   const SCIP_Real*      ubs                 /**< new upper bounds */
384  	   )
385  	{
386  	   assert(set != NULL);
387  	   assert(nlpi != NULL);
388  	   assert(nlpi->nlpichgvarbounds != NULL);
389  	   assert(problem != NULL);
390  	
391  	   SCIPclockStart(nlpi->problemtime, set);
392  	   SCIP_CALL( nlpi->nlpichgvarbounds(set->scip, nlpi, problem, nvars, indices, lbs, ubs) );
393  	   SCIPclockStop(nlpi->problemtime, set);
394  	
395  	   return SCIP_OKAY;
396  	}
397  	
398  	/** change constraint sides */
399  	SCIP_RETCODE SCIPnlpiChgConsSides(
400  	   SCIP_SET*             set,                /**< global SCIP settings */
401  	   SCIP_NLPI*            nlpi,               /**< solver interface */
402  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
403  	   int                   nconss,             /**< number of constraints to change sides */
404  	   const int*            indices,            /**< indices of constraints to change sides */
405  	   const SCIP_Real*      lhss,               /**< new left hand sides */
406  	   const SCIP_Real*      rhss                /**< new right hand sides */
407  	   )
408  	{
409  	   assert(set != NULL);
410  	   assert(nlpi != NULL);
411  	   assert(nlpi->nlpichgconssides != NULL);
412  	   assert(problem != NULL);
413  	
414  	   SCIPclockStart(nlpi->problemtime, set);
415  	   SCIP_CALL( nlpi->nlpichgconssides(set->scip, nlpi, problem, nconss, indices, lhss, rhss) );
416  	   SCIPclockStop(nlpi->problemtime, set);
417  	
418  	   return SCIP_OKAY;
419  	}
420  	
421  	/** delete a set of variables */
422  	SCIP_RETCODE SCIPnlpiDelVarSet(
423  	   SCIP_SET*             set,                /**< global SCIP settings */
424  	   SCIP_NLPI*            nlpi,               /**< solver interface */
425  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
426  	   int*                  dstats,             /**< deletion status of vars; 1 if var should be deleted, 0 if not */
427  	   int                   dstatssize          /**< size of the dstats array */
428  	   )
429  	{
430  	   assert(set != NULL);
431  	   assert(nlpi != NULL);
432  	   assert(nlpi->nlpidelvarset != NULL);
433  	   assert(problem != NULL);
434  	
435  	   SCIPclockStart(nlpi->problemtime, set);
436  	   SCIP_CALL( nlpi->nlpidelvarset(set->scip, nlpi, problem, dstats, dstatssize) );
437  	   SCIPclockStop(nlpi->problemtime, set);
438  	
439  	   return SCIP_OKAY;
440  	}
441  	
442  	/** delete a set of constraints */
443  	SCIP_RETCODE SCIPnlpiDelConsSet(
444  	   SCIP_SET*             set,                /**< global SCIP settings */
445  	   SCIP_NLPI*            nlpi,               /**< solver interface */
446  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
447  	   int*                  dstats,             /**< deletion status of constraints; 1 if constraint should be deleted, 0 if not */
448  	   int                   dstatssize          /**< size of the dstats array */
449  	   )
450  	{
451  	   assert(set != NULL);
452  	   assert(nlpi != NULL);
453  	   assert(nlpi->nlpidelconsset != NULL);
454  	   assert(problem != NULL);
455  	
456  	   SCIPclockStart(nlpi->problemtime, set);
457  	   SCIP_CALL( nlpi->nlpidelconsset(set->scip, nlpi, problem, dstats, dstatssize) );
458  	   SCIPclockStop(nlpi->problemtime, set);
459  	
460  	   return SCIP_OKAY;
461  	}
462  	
463  	/** changes or adds linear coefficients in a constraint or objective */
464  	SCIP_RETCODE SCIPnlpiChgLinearCoefs(
465  	   SCIP_SET*             set,                /**< global SCIP settings */
466  	   SCIP_NLPI*            nlpi,               /**< solver interface */
467  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
468  	   int                   idx,                /**< index of constraint or -1 for objective */
469  	   int                   nvals,              /**< number of values in linear constraint to change */
470  	   const int*            varidxs,            /**< indices of variables which coefficient to change */
471  	   const SCIP_Real*      vals                /**< new values for coefficients */
472  	   )
473  	{
474  	   assert(set != NULL);
475  	   assert(nlpi != NULL);
476  	   assert(nlpi->nlpichglinearcoefs != NULL);
477  	   assert(problem != NULL);
478  	
479  	   SCIPclockStart(nlpi->problemtime, set);
480  	   SCIP_CALL( nlpi->nlpichglinearcoefs(set->scip, nlpi, problem, idx, nvals, varidxs, vals) );
481  	   SCIPclockStop(nlpi->problemtime, set);
482  	
483  	   return SCIP_OKAY;
484  	}
485  	
486  	/** change the expression in the nonlinear part */
487  	SCIP_RETCODE SCIPnlpiChgExpr(
488  	   SCIP_SET*             set,                /**< global SCIP settings */
489  	   SCIP_NLPI*            nlpi,               /**< solver interface */
490  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
491  	   int                   idxcons,            /**< index of constraint or -1 for objective */
492  	   SCIP_EXPR*            expr                /**< new expression for constraint or objective, or NULL to only remove previous tree */
493  	   )
494  	{
495  	   assert(set != NULL);
496  	   assert(nlpi != NULL);
497  	   assert(nlpi->nlpichgexpr != NULL);
498  	   assert(problem != NULL);
499  	
500  	   SCIPclockStart(nlpi->problemtime, set);
501  	   SCIP_CALL( nlpi->nlpichgexpr(set->scip, nlpi, problem, idxcons, expr) );
502  	   SCIPclockStop(nlpi->problemtime, set);
503  	
504  	   return SCIP_OKAY;
505  	}
506  	
507  	/** change the constant offset in the objective */
508  	SCIP_RETCODE SCIPnlpiChgObjConstant(
509  	   SCIP_SET*             set,                /**< global SCIP settings */
510  	   SCIP_NLPI*            nlpi,               /**< solver interface */
511  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
512  	   SCIP_Real             objconstant         /**< new value for objective constant */
513  	   )
514  	{
515  	   assert(set != NULL);
516  	   assert(nlpi != NULL);
517  	   assert(nlpi->nlpichgobjconstant != NULL);
518  	   assert(problem != NULL);
519  	
520  	   SCIPclockStart(nlpi->problemtime, set);
521  	   SCIP_CALL( nlpi->nlpichgobjconstant(set->scip, nlpi, problem, objconstant) );
522  	   SCIPclockStop(nlpi->problemtime, set);
523  	
524  	   return SCIP_OKAY;
525  	}
526  	
527  	/** sets initial guess for primal variables */
528  	SCIP_RETCODE SCIPnlpiSetInitialGuess(
529  	   SCIP_SET*             set,                /**< global SCIP settings */
530  	   SCIP_NLPI*            nlpi,               /**< solver interface */
531  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
532  	   SCIP_Real*            primalvalues,       /**< initial primal values for variables, or NULL to clear previous values */
533  	   SCIP_Real*            consdualvalues,     /**< initial dual values for constraints, or NULL to clear previous values */
534  	   SCIP_Real*            varlbdualvalues,    /**< initial dual values for variable lower bounds, or NULL to clear previous values */
535  	   SCIP_Real*            varubdualvalues     /**< initial dual values for variable upper bounds, or NULL to clear previous values */
536  	   )
537  	{
538  	   assert(set != NULL);
539  	   assert(nlpi != NULL);
540  	   assert(problem != NULL);
541  	
542  	   if( nlpi->nlpisetinitialguess != NULL )
543  	   {
544  	      SCIP_CALL( nlpi->nlpisetinitialguess(set->scip, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues) );
545  	   }
546  	
547  	   return SCIP_OKAY;
548  	}
549  	
550  	/** tries to solve NLP */
551  	SCIP_RETCODE SCIPnlpiSolve(
552  	   SCIP_SET*             set,                /**< global SCIP settings */
553  	   SCIP_STAT*            stat,               /**< problem statistics */
554  	   SCIP_NLPI*            nlpi,               /**< solver interface */
555  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
556  	   SCIP_NLPPARAM*        param               /**< solve parameters */
557  	   )
558  	{
559  	   SCIP_NLPSTATISTICS stats;
560  	
561  	   assert(set != NULL);
562  	   assert(nlpi != NULL);
563  	   assert(nlpi->nlpisolve != NULL);
564  	   assert(problem != NULL);
565  	   assert(param != NULL);
566  	
567  	   /* check that parameter values are in accepted range (if type allows more than we would accept) */
568  	   if( param->iterlimit < 0 )
569  	   {
570  	      SCIPerrorMessage("Value %d for parameter iteration limit must be non-negative.\n", param->iterlimit);
571  	      return SCIP_PARAMETERWRONGVAL;
572  	   }
573  	   if( param->feastol < 0.0 )
574  	   {
575  	      SCIPerrorMessage("Value %g for parameter feasibility tolerance cannot be negative\n", param->feastol);
576  	      return SCIP_PARAMETERWRONGVAL;
577  	   }
578  	   if( param->opttol < 0.0 )
579  	   {
580  	      SCIPerrorMessage("Value %g for parameter optimality tolerance cannot be negative\n", param->opttol);
581  	      return SCIP_PARAMETERWRONGVAL;
582  	   }
583  	   if( param->solvertol < 0.0 )
584  	   {
585  	      SCIPerrorMessage("Value %g for parameter solver tolerance cannot be negative\n", param->solvertol);
586  	      return SCIP_PARAMETERWRONGVAL;
587  	   }
588  	   if( param->timelimit < 0.0 )
589  	   {
590  	      SCIPerrorMessage("Value %g for parameter time limit cannot be negative\n", param->timelimit);
591  	      return SCIP_PARAMETERWRONGVAL;
592  	   }
593  	
594  	   if( param->timelimit == SCIP_REAL_MAX && set->istimelimitfinite )  /*lint !e777*/
595  	   {
596  	      /* set timelimit to time remaining if limits/time has been set */
597  	      param->timelimit = set->limit_time - SCIPclockGetTime(stat->solvingtime);
598  	      if( param->timelimit < 0.0 )
599  	         param->timelimit = 0.0;
600  	      /* still call NLP solver if no time left to ensure proper termination codes */
601  	   }
602  	
603  	   ++nlpi->nsolves;
604  	
605  	   SCIP_CALL( nlpi->nlpisolve(set->scip, nlpi, problem, *param) );
606  	
607  	   /* coverity[overrun] */
608  	   ++nlpi->ntermstat[nlpi->nlpigettermstat(set->scip, nlpi, problem)];
609  	   /* coverity[overrun] */
610  	   ++nlpi->nsolstat[nlpi->nlpigetsolstat(set->scip, nlpi, problem)];
611  	
612  	   SCIP_CALL( nlpi->nlpigetstatistics(set->scip, nlpi, problem, &stats) );
613  	   nlpi->solvetime += stats.totaltime;
614  	   nlpi->evaltime += stats.evaltime;
615  	   nlpi->niter += stats.niterations;
616  	
617  	   return SCIP_OKAY;
618  	}
619  	
620  	/** gives solution status */
621  	SCIP_NLPSOLSTAT SCIPnlpiGetSolstat(
622  	   SCIP_SET*             set,                /**< global SCIP settings */
623  	   SCIP_NLPI*            nlpi,               /**< solver interface */
624  	   SCIP_NLPIPROBLEM*     problem             /**< problem instance */
625  	   )
626  	{
627  	   assert(set != NULL);
628  	   assert(nlpi != NULL);
629  	   assert(nlpi->nlpigetsolstat != NULL);
630  	   assert(problem != NULL);
631  	
632  	   return nlpi->nlpigetsolstat(set->scip, nlpi, problem);
633  	}
634  	
635  	/** gives termination reason */
636  	SCIP_NLPTERMSTAT SCIPnlpiGetTermstat(
637  	   SCIP_SET*             set,                /**< global SCIP settings */
638  	   SCIP_NLPI*            nlpi,               /**< solver interface */
639  	   SCIP_NLPIPROBLEM*     problem             /**< problem instance */
640  	   )
641  	{
642  	   assert(set != NULL);
643  	   assert(nlpi != NULL);
644  	   assert(nlpi->nlpigettermstat != NULL);
645  	   assert(problem != NULL);
646  	
647  	   return nlpi->nlpigettermstat(set->scip, nlpi, problem);
648  	}
649  	
650  	/** gives primal and dual solution
651  	 * 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
652  	 */
653  	SCIP_RETCODE SCIPnlpiGetSolution(
654  	   SCIP_SET*             set,                /**< global SCIP settings */
655  	   SCIP_NLPI*            nlpi,               /**< solver interface */
656  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
657  	   SCIP_Real**           primalvalues,       /**< buffer to store pointer to array to primal values, or NULL if not needed */
658  	   SCIP_Real**           consdualvalues,     /**< buffer to store pointer to array to dual values of constraints, or NULL if not needed */
659  	   SCIP_Real**           varlbdualvalues,    /**< buffer to store pointer to array to dual values of variable lower bounds, or NULL if not needed */
660  	   SCIP_Real**           varubdualvalues,    /**< buffer to store pointer to array to dual values of variable lower bounds, or NULL if not needed */
661  	   SCIP_Real*            objval              /**< pointer to store the objective value, or NULL if not needed */
662  	   )
663  	{
664  	   assert(set != NULL);
665  	   assert(nlpi != NULL);
666  	   assert(nlpi->nlpigetsolution != NULL);
667  	   assert(problem != NULL);
668  	
669  	   SCIP_CALL( nlpi->nlpigetsolution(set->scip, nlpi, problem, primalvalues, consdualvalues, varlbdualvalues, varubdualvalues, objval) );
670  	
671  	   return SCIP_OKAY;
672  	}
673  	
674  	/** gives solve statistics */
675  	SCIP_RETCODE SCIPnlpiGetStatistics(
676  	   SCIP_SET*             set,                /**< global SCIP settings */
677  	   SCIP_NLPI*            nlpi,               /**< solver interface */
678  	   SCIP_NLPIPROBLEM*     problem,            /**< problem instance */
679  	   SCIP_NLPSTATISTICS*   statistics          /**< pointer to store statistics */
680  	   )
681  	{
682  	   assert(set != NULL);
683  	   assert(nlpi != NULL);
684  	   assert(nlpi->nlpigetstatistics != NULL);
685  	   assert(problem != NULL);
686  	
687  	   SCIP_CALL( nlpi->nlpigetstatistics(set->scip, nlpi, problem, statistics) );
688  	
689  	   return SCIP_OKAY;
690  	}
691  	
692  	/* from pub_nlpi.h */
693  	
694  	#ifdef NDEBUG
695  	/* Undo the defines from pub_nlpi.h, which exist if NDEBUG is defined. */
696  	#undef SCIPnlpiGetData
697  	#undef SCIPnlpiGetName
698  	#undef SCIPnlpiGetDesc
699  	#undef SCIPnlpiGetPriority
700  	#undef SCIPnlpiSetPriority
701  	#undef SCIPnlpiGetNProblems
702  	#undef SCIPnlpiGetProblemTime
703  	#undef SCIPnlpiGetNSolves
704  	#undef SCIPnlpiGetSolveTime
705  	#undef SCIPnlpiGetEvalTime
706  	#undef SCIPnlpiGetNIterations
707  	#undef SCIPnlpiGetNTermStat
708  	#undef SCIPnlpiGetNSolStat
709  	#endif
710  	
711  	/** gets data of an NLPI */
712  	SCIP_NLPIDATA* SCIPnlpiGetData(
713  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
714  	   )
715  	{
716  	   assert(nlpi != NULL);
717  	
718  	   return nlpi->nlpidata;
719  	}
720  	
721  	/** gets NLP solver name */
722  	const char* SCIPnlpiGetName(
723  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
724  	   )
725  	{
726  	   assert(nlpi != NULL);
727  	
728  	   return nlpi->name;
729  	}
730  	
731  	/** gets NLP solver description */
732  	const char* SCIPnlpiGetDesc(
733  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
734  	   )
735  	{
736  	   assert(nlpi != NULL);
737  	
738  	   return nlpi->description;
739  	}
740  	
741  	/** gets NLP solver priority */
742  	int SCIPnlpiGetPriority(
743  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
744  	   )
745  	{
746  	   assert(nlpi != NULL);
747  	
748  	   return nlpi->priority;
749  	}
750  	
751  	
752  	/**@name Statistics */
753  	/**@{ */
754  	
755  	/** gives number of problems created for NLP solver so far */
756  	int SCIPnlpiGetNProblems(
757  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
758  	   )
759  	{
760  	   assert(nlpi != NULL);
761  	   return nlpi->nproblems;
762  	}
763  	
764  	/** gives total time spend in problem creation/modification/freeing */
765  	SCIP_Real SCIPnlpiGetProblemTime(
766  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
767  	   )
768  	{
769  	   assert(nlpi != NULL);
770  	   return SCIPclockGetTime(nlpi->problemtime);
771  	}
772  	
773  	/** total number of NLP solves so far */
774  	int SCIPnlpiGetNSolves(
775  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
776  	   )
777  	{
778  	   assert(nlpi != NULL);
779  	   return nlpi->nsolves;
780  	}
781  	
782  	/** gives total time spend in NLP solves (as reported by solver) */
783  	SCIP_Real SCIPnlpiGetSolveTime(
784  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
785  	   )
786  	{
787  	   assert(nlpi != NULL);
788  	   return nlpi->solvetime;
789  	}
790  	
791  	/** gives total time spend in function evaluation during NLP solves
792  	 *
793  	 * If parameter `timing/nlpieval` is off (the default), depending on the NLP solver, this may just return 0.
794  	 */
795  	SCIP_Real SCIPnlpiGetEvalTime(
796  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
797  	   )
798  	{
799  	   assert(nlpi != NULL);
800  	   return nlpi->evaltime;
801  	}
802  	
803  	/** gives total number of iterations spend by NLP solver so far */
804  	SCIP_Longint SCIPnlpiGetNIterations(
805  	   SCIP_NLPI*            nlpi                /**< NLP interface structure */
806  	   )
807  	{
808  	   assert(nlpi != NULL);
809  	   return nlpi->niter;
810  	}
811  	
812  	/** gives number of times a solve ended with a specific termination status */
813  	int SCIPnlpiGetNTermStat(
814  	   SCIP_NLPI*            nlpi,               /**< NLP interface structure */
815  	   SCIP_NLPTERMSTAT      termstatus          /**< the termination status to query for */
816  	   )
817  	{
818  	   assert(nlpi != NULL);
819  	   return nlpi->ntermstat[termstatus];
820  	}
821  	
822  	/** gives number of times a solve ended with a specific solution status */
823  	int SCIPnlpiGetNSolStat(
824  	   SCIP_NLPI*            nlpi,               /**< NLP interface structure */
825  	   SCIP_NLPSOLSTAT       solstatus           /**< the solution status to query for */
826  	   )
827  	{
828  	   assert(nlpi != NULL);
829  	   return nlpi->nsolstat[solstatus];
830  	}
831  	
832  	/** adds statistics from one NLPI to another */
833  	void SCIPnlpiMergeStatistics(
834  	   SCIP_NLPI*            targetnlpi,         /**< NLP interface where to add statistics */
835  	   SCIP_NLPI*            sourcenlpi,         /**< NLP interface from which to add statistics */
836  	   SCIP_Bool             reset               /**< whether to reset statistics in sourcescip */
837  	   )
838  	{
839  	   int i;
840  	
841  	   assert(targetnlpi != NULL);
842  	   assert(sourcenlpi != NULL);
843  	
844  	   targetnlpi->nproblems += sourcenlpi->nproblems;
845  	   targetnlpi->nsolves += sourcenlpi->nsolves;
846  	   SCIPclockSetTime(targetnlpi->problemtime, SCIPclockGetTime(targetnlpi->problemtime) + SCIPclockGetTime(sourcenlpi->problemtime));
847  	   targetnlpi->solvetime += sourcenlpi->solvetime;
848  	   targetnlpi->evaltime += sourcenlpi->evaltime;
849  	   targetnlpi->niter += sourcenlpi->niter;
850  	
851  	   for( i = (int)SCIP_NLPTERMSTAT_OKAY; i <= (int)SCIP_NLPTERMSTAT_OTHER; ++i )
852  	      targetnlpi->ntermstat[i] += sourcenlpi->ntermstat[i];
853  	   for( i = (int)SCIP_NLPSOLSTAT_GLOBOPT; i <= (int)SCIP_NLPSOLSTAT_UNKNOWN; ++i )
854  	      targetnlpi->nsolstat[i] += sourcenlpi->nsolstat[i];
855  	
856  	   if( reset )
857  	   {
858  	      sourcenlpi->nproblems = 0;
859  	      sourcenlpi->nsolves = 0;
860  	      SCIPclockReset(sourcenlpi->problemtime);
861  	      sourcenlpi->solvetime = 0.0;
862  	      sourcenlpi->evaltime = 0.0;
863  	      sourcenlpi->niter = 0;
864  	
865  	      for( i = (int)SCIP_NLPTERMSTAT_OKAY; i <= (int)SCIP_NLPTERMSTAT_OTHER; ++i )
866  	         sourcenlpi->ntermstat[i] = 0;
867  	      for( i = (int)SCIP_NLPSOLSTAT_GLOBOPT; i <= (int)SCIP_NLPSOLSTAT_UNKNOWN; ++i )
868  	         sourcenlpi->nsolstat[i] = 0;
869  	   }
870  	}
871  	
872  	/**@} */ /* Statistics */
873