/[ascend]/trunk/solvers/ipopt/asc_ipopt.c
ViewVC logotype

Contents of /trunk/solvers/ipopt/asc_ipopt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3258 - (show annotations) (download) (as text)
Wed Nov 15 04:57:56 2017 UTC (5 years, 4 months ago) by jpye
File MIME type: text/x-csrc
File size: 46118 byte(s)
Merged relerrorlist branch back to trunk.

1 /* ASCEND modelling environment
2 Copyright (C) 2007-2010 Carnegie Mellon University
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *//**
17 @file
18 Connection of the IPOPT optimisation solver into ASCEND.
19
20 THIS IS STILL VERY MUCH UNDER DEVELOPMENT AND INCOMPLETE.
21
22 The IPOPT solver is documented at http://projects.coin-or.org/Ipopt/
23 *//*
24 ASCEND wrapper for IPOPT originally by John Pye, Jun 2007 onwards. Further
25 contributions from Mahesh Narayanamurthi 2009.
26 */
27
28 #include <ascend/utilities/config.h>
29
30 #ifndef ASC_WITH_IPOPT
31 # error "ASC_WITH_IPOPT must be defined in order to build this."
32 #endif
33
34 #include <math.h>
35
36 #include <ascend/solver/solver.h>
37
38 #include <ascend/system/calc.h>
39 #include <ascend/system/relman.h>
40 #include <ascend/system/slv_stdcalls.h>
41 #include <ascend/system/block.h>
42
43 #include <ascend/general/platform.h>
44 #include <ascend/general/panic.h>
45 #include <ascend/general/ascMalloc.h>
46 #include <ascend/utilities/ascDynaLoad.h>
47 #include <ascend/general/mem.h>
48 #include <ascend/utilities/ascEnvVar.h>
49 #include <ascend/general/tm_time.h>
50 #include <ascend/general/env.h>
51
52 #include <ascend/general/ltmatrix.h>
53
54 #include <coin/IpStdCInterface.h>
55
56 ASC_DLLSPEC SolverRegisterFn ipopt_register;
57
58 /*------------------------------------------------------------------------------
59 DATA STRUCTURES AND FORWARD DEFS
60 */
61
62 /**
63 Documentation of solver options for IPOPT is at
64 http://www.coin-or.org/Ipopt/documentation/node1.html
65 */
66 enum{
67 /** ASCEND OPTIONS */
68 ASCEND_PARAM_SAFEEVAL
69 /** OUTPUT OPTIONS */
70 ,IPOPT_PARAM_PRINT_LEVEL
71 ,IPOPT_PARAM_PRINT_USER_OPTIONS
72 /** TERMINATION OPTIONS */
73 ,IPOPT_PARAM_TOL
74 ,IPOPT_PARAM_MAX_ITER
75 ,IPOPT_PARAM_MAX_CPU_TIME
76 ,IPOPT_PARAM_DIVERGING_ITERATES_TOL
77 ,IPOPT_PARAM_CONSTR_VIOL_TOL
78 ,IPOPT_PARAM_DUAL_INFEASIBILITY_TOL
79 ,IPOPT_PARAM_ACCEPTABLE_TOL
80 ,IPOPT_PARAM_ACCEPTABLE_ITER
81 /** LINEAR SOLVER OPTIONS */
82 ,IPOPT_PARAM_LINEAR_SOLVER
83 /** BARRIER PARAMETER OPTIONS */
84 ,IPOPT_PARAM_MU_STRATEGY
85 /** DERIVATIVE TEST OPTIONS */
86 ,IPOPT_PARAM_DERIVATIVE_TEST
87 /** QUASI-NEWTON OPTIONS */
88 ,IPOPT_PARAM_HESS_APPROX
89 /** OPTIONS COUNT */
90 ,IPOPT_PARAMS
91 };
92
93 #define SYS(s) ((IpoptSystem *)(s))
94
95 struct IpoptSystemStruct{
96
97 /*
98 Problem definition
99 */
100 slv_system_t slv; /* slv_system_t back-link */
101 struct rel_relation *obj; /* Objective function: NULL = none */
102 struct rel_relation *old_obj;/* Objective function: NULL = none */
103 struct var_variable **vlist; /* Variable list (NULL terminated) */
104 struct rel_relation **rlist; /* Relation list (NULL terminated) */
105
106 var_filter_t vfilt;
107 rel_filter_t rfilt;
108
109 /*
110 Solver information
111 */
112 int32 presolved; /* ? Has the system been presolved */
113 int32 resolve; /* ? Has the system been resolved */
114 slv_parameters_t p; /* Parameters */
115 slv_status_t s; /* Status (as of iteration end) */
116
117 int32 cap; /* Order of matrix/vectors */
118 int32 rank; /* Symbolic rank of problem */
119 int32 vused; /* Free and incident variables */
120 int32 vtot; /* length of varlist */
121 int32 rused; /* Included relations */
122 int32 rtot; /* length of rellist */
123 double clock; /* CPU time */
124
125 int32 calc_ok;
126 double obj_val;
127
128 #if 0
129 void *parm_array[IPOPT_PARAMS];
130 #endif
131 struct slv_parameter pa[IPOPT_PARAMS];
132
133 /*
134 IPOPT DATA
135 */
136 Index n; /* number of variables */
137 Index m; /* number of constraints (excl the 'objective relation')*/
138
139 Index nnzJ; /* number of non zeros in the jacobian of the constraints */
140 Index nnzH; /* number of non-zeros in the hessian of the objective */
141
142 #if 0
143 Number* x_L; /* lower bounds on x */
144 Number* x_U; /* upper bounds on x */
145 Number* g_L; /* lower bounds on g */
146 Number* g_U; /* upper bounds on g */
147 #endif
148
149 IpoptProblem nlp; /* IpoptProblem */
150
151 enum ApplicationReturnStatus status; /* Solve return code */
152 #if 0
153 Number* x; /* starting point and solution vector */
154 Number* mult_x_L; /* lower bound multipliers at the solution */
155 Number* mult_x_U; /* upper bound multipliers at the solution */
156 #endif
157 Index i; /* generic counter */
158 };
159
160 typedef struct IpoptSystemStruct IpoptSystem;
161
162 static int ipopt_get_default_parameters(slv_system_t server, SlvClientToken asys, slv_parameters_t *parameters);
163
164 static void ipopt_iteration_begins(IpoptSystem *sys);
165 static void ipopt_iteration_ends(IpoptSystem *sys);
166
167 /*------------------------------------------------------------------------------
168 SYSTEM SETUP/DESTROY, STATUS AND SOLVER ELIGIBILITY
169 */
170
171 static SlvClientToken ipopt_create(slv_system_t server, int32 *statusindex){
172 IpoptSystem *sys;
173
174 sys = ASC_NEW_CLEAR(IpoptSystem);
175 if(sys==NULL){
176 *statusindex = 1;
177 return sys;
178 }
179
180 sys->p.parms = sys->pa;
181 sys->p.dynamic_parms = 0;
182 ipopt_get_default_parameters(server,(SlvClientToken)sys,&(sys->p));
183 sys->p.whose = (*statusindex);
184
185 sys->presolved = 0;
186 sys->resolve = 0;
187
188 sys->n = -1;
189 sys->m = -1;
190
191 sys->s.ok = TRUE;
192 sys->s.calc_ok = TRUE;
193 sys->s.costsize = 0;
194 sys->s.cost = NULL; /*redundant, but sanity preserving */
195 sys->s.block.number_of = 1;
196 sys->s.block.current_block = 0;
197 sys->s.block.current_reordered_block = 0;
198 sys->s.block.current_size = 0;
199 sys->s.block.previous_total_size = 0;
200 sys->s.block.iteration = 0;
201 sys->s.block.funcs = 0;
202 sys->s.block.jacs = 0;
203 sys->s.block.cpu_elapsed = 0;
204 sys->s.block.functime = 0;
205 sys->s.block.jactime = 0;
206 sys->s.block.residual = 0;
207
208 sys->rfilt.matchbits = (REL_INCLUDED | REL_ACTIVE);
209 sys->rfilt.matchvalue = (REL_INCLUDED | REL_ACTIVE);
210 sys->vfilt.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR | VAR_FIXED);
211 sys->vfilt.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
212
213 sys->vlist = slv_get_solvers_var_list(server);
214 sys->rlist = slv_get_solvers_rel_list(server);
215
216 sys->rtot = slv_get_num_solvers_rels(server);
217 sys->vtot = slv_get_num_solvers_vars(server);
218
219 sys->obj = slv_get_obj_relation(server);
220
221 sys->slv = server;
222
223 /*char *tmp = rel_make_name(sys->slv,sys->obj);
224 //CONSOLE_DEBUG("Objective relation is '%s'",tmp);
225 ASC_FREE(tmp);*/
226
227 //CONSOLE_DEBUG("There are %d constraint relations.", sys->rtot);
228
229 if(sys->vlist == NULL) {
230 ASC_FREE(sys);
231 ERROR_REPORTER_HERE(ASC_PROG_ERR,"IPOPT called with no variables.");
232 *statusindex = -2;
233 return NULL;
234 }
235
236 if(sys->rlist == NULL && sys->obj == NULL) {
237 ASC_FREE(sys);
238 ERROR_REPORTER_HERE(ASC_PROG_ERR,"IPOPT called with no relations or objective.");
239 *statusindex = -1;
240 return NULL;
241 }
242
243
244 /* do nothing with the objective list, pars, bounds, extrels, etc etc */
245
246 slv_check_var_initialization(server);
247 *statusindex = 0;
248 return((SlvClientToken)sys);
249 }
250
251 static int32 ipopt_destroy(slv_system_t server, SlvClientToken asys){
252 IpoptSystem *sys;
253 UNUSED_PARAMETER(server);
254 sys = SYS(asys);
255 slv_destroy_parms(&(sys->p));
256 if(sys->s.cost) ascfree(sys->s.cost);
257 ASC_FREE(sys);
258 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"ipopt_destroy still needs debugging");
259 return 0;
260 }
261
262
263 static int ipopt_get_status(slv_system_t server, SlvClientToken asys
264 ,slv_status_t *status
265 ){
266 IpoptSystem *sys;
267 (void)server; /* stop gcc whine about unused parameter */
268
269 sys = SYS(asys);
270 //if (check_system(sys)) return 1;
271 mem_copy_cast(&(sys->s),status,sizeof(slv_status_t));
272 return 0;
273 }
274
275 /**
276 Update the solver status. FIXME can't we get rid of this silly function
277 somehot?
278 */
279 static void update_status(IpoptSystem *sys){
280 boolean unsuccessful;
281
282 sys->s.time_limit_exceeded = FALSE; /* can't do this one with IPOPT */
283 sys->s.iteration_limit_exceeded = FALSE; /* IPOPT handles this one internally */
284
285 unsuccessful = sys->s.diverged || sys->s.inconsistent ||
286 sys->s.iteration_limit_exceeded || sys->s.time_limit_exceeded;
287
288 sys->s.ready_to_solve = !unsuccessful && !sys->s.converged;
289 sys->s.ok = !unsuccessful && sys->s.calc_ok && !sys->s.struct_singular;
290 }
291
292 static int32 ipopt_eligible_solver(slv_system_t server){
293 struct rel_relation **rp;
294 struct var_variable **vp;
295 rel_filter_t rfilt;
296 var_filter_t vfilt;
297
298 rfilt.matchbits = (REL_CONDITIONAL | REL_INWHEN);
299 rfilt.matchvalue = (REL_CONDITIONAL | REL_INWHEN);
300
301 vfilt.matchbits = (VAR_BINARY);
302 vfilt.matchvalue = (VAR_BINARY);
303
304 /// @todo check that there is a MAXIMIZE or MINIMIZE statement
305 if (slv_get_obj_relation(server) == NULL)
306 ERROR_REPORTER_HERE(ASC_USER_ERROR,"No objective function found");
307
308 /// @todo check that there are no WHENs or CONDITIONALs
309 for( rp=slv_get_solvers_rel_list(server); *rp != NULL ; ++rp ) {
310 if(rel_apply_filter(*rp,&rfilt)){
311 ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"WHEN and CONDITIONAL Statements are not supported.");
312 return(FALSE);
313 }
314 }
315
316 /// @todo check that there are no discrete-valued variables
317 for( vp=slv_get_solvers_var_list(server); *vp != NULL ; ++vp ) {
318 if(var_apply_filter(*vp,&vfilt)){
319 ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"Discrete Variables not supported.");
320 return(FALSE);
321 }
322 }
323
324 /// @todo check anything else?
325
326 return 1;
327 }
328
329 /*------------------------------------------------------------------------------
330 SOLVER PARAMETERS
331 */
332
333 static
334 int32 ipopt_get_default_parameters(slv_system_t server, SlvClientToken asys
335 ,slv_parameters_t *parameters
336 ){
337 IpoptSystem *sys = NULL;
338 struct slv_parameter *new_parms = NULL;
339 int32 make_macros = 0;
340
341 if(server != NULL && asys != NULL) {
342 sys = SYS(asys);
343 make_macros = 1;
344 }
345
346 if(parameters->parms == NULL) {
347 new_parms = ASC_NEW_ARRAY_OR_NULL(struct slv_parameter,IPOPT_PARAMS);
348 if(new_parms == NULL) {
349 return -1;
350 }
351 parameters->parms = new_parms;
352 parameters->dynamic_parms = 1;
353 }
354
355 parameters->num_parms = 0;
356
357 /** ASCEND Options */
358
359 slv_param_bool(parameters,ASCEND_PARAM_SAFEEVAL
360 ,(SlvParameterInitBool){{"safeeval"
361 ,"Use safe evaluation?",1
362 ,"Use 'safe' function evaluation routines (TRUE) or allow ASCEND to "
363 "throw SIGFPE errors which will then halt integration (FALSE)."
364 }, FALSE}
365 );
366
367
368 /** Output Options */
369
370 slv_param_int(parameters,IPOPT_PARAM_PRINT_LEVEL
371 ,(SlvParameterInitInt){{"print_level"
372 ,"Output verbosity level",2
373 ,"Sets the default verbosity level for console output."
374 " The larger this value the more detailed is the output."
375 " Default value is 5 and range is 0 to 12."
376 }, 5, 0, 12}
377 );
378
379
380 slv_param_char(parameters,IPOPT_PARAM_PRINT_USER_OPTIONS
381 ,(SlvParameterInitChar){{"print_user_options"
382 ,"Print all options set by the user.",2
383 ,"If selected, the algorithm will print the list of all options"
384 " set by the user including their values and whether they have"
385 " been used. In some cases this information might be incorrect,"
386 " due to the internal program flow. The default value for this "
387 " string option is 'no'. "
388 }, "yes"}, (char *[]){
389 "no","yes",NULL
390 }
391 );
392
393
394
395 /** Termination Options */
396
397 slv_param_int(parameters,IPOPT_PARAM_MAX_ITER
398 ,(SlvParameterInitInt){{"max_iter"
399 ,"Maximum number of iterations",3
400 ,"The algorithm terminates with an error message if the number of iterations exceeded this number."
401 }, 3000, 0, 100000000}
402 );
403
404 slv_param_real(parameters,IPOPT_PARAM_TOL
405 ,(SlvParameterInitReal){{"tol"
406 ,"Desired convergence tolerance (relative)",3
407 ,"Determines the convergence tolerance for the algorithm. The algorithm"
408 " terminates successfully, if the (scaled) NLP error becomes smaller"
409 " than this value, and if the (absolute) criteria according to "
410 " 'dual_inf_tol', 'primal_inf_tol', and 'cmpl_inf_tol' are met. (This"
411 " is epsilon_tol in Eqn. (6) in implementation paper). See also "
412 " 'acceptable_tol' as a second termination criterion. Note, some other"
413 " algorithmic features also use this quantity to determine thresholds"
414 " etc."
415 }, 1.e-8, 0, 1.e20}
416 );
417
418 slv_param_real(parameters,IPOPT_PARAM_MAX_CPU_TIME
419 ,(SlvParameterInitReal){{"max_cpu_time"
420 ,"Maximum CPU time allowed per problem (seconds)",3
421 ,"The algorithm terminates with an error message if the CPU time exceeds this value."
422 }, 1.e6, 0, 1.e7}
423 );
424
425 slv_param_real(parameters,IPOPT_PARAM_DIVERGING_ITERATES_TOL
426 ,(SlvParameterInitReal){{"diverging_iterates_tol"
427 ,"Threshold for maximal value of primal iterates",3
428 ,"If any component of the primal iterates exceeded this value"
429 " (in absolute terms), the optimization is aborted with the "
430 "exit message that the iterates seem to be diverging"
431 }, 1.e20, 0, 1.e50}
432 );
433
434
435 slv_param_real(parameters,IPOPT_PARAM_DUAL_INFEASIBILITY_TOL
436 ,(SlvParameterInitReal){{"dual_inf_tol"
437 ,"Desired threshold for the dual infeasibility.",3
438 ,"Absolute tolerance on the dual infeasibility. Successful "
439 "termination requires that the max-norm of the (unscaled) "
440 "dual infeasibility is less than this threshold. The valid "
441 "range for this real option is 0 < dual_inf_tol < +inf and"
442 " its default value is 1."
443 }, 1, 0, 1.e50}
444 );
445
446
447 slv_param_real(parameters,IPOPT_PARAM_CONSTR_VIOL_TOL
448 ,(SlvParameterInitReal){{"constr_viol_tol"
449 ,"Desired threshold for the constraint violation.",3
450 ,"Absolute tolerance on the constraint violation. Successful"
451 "termination requires that the max-norm of the (unscaled) "
452 " constraint violation is less than this threshold. The valid"
453 " range for this real option is 0 < constr_viol_tol < +inf and"
454 " its default value is 0.0001"
455 }, 1e-4, 0, 1.e50}
456 );
457
458 slv_param_real(parameters,IPOPT_PARAM_ACCEPTABLE_TOL
459 ,(SlvParameterInitReal){{"acceptable_tol"
460 ,"Acceptable convergence tolerance (relative).",3
461 ,"Determines which (scaled) overall optimality error is"
462 " considered to be 'acceptable.' There are two levels of"
463 " termination criteria. If the usual 'desired' tolerances"
464 " (see tol, dual_inf_tol etc) are satisfied at an iteration,"
465 " the algorithm immediately terminates with a success message."
466 " On the other hand, if the algorithm encounters 'acceptable_iter'"
467 " many iterations in a row that are considered 'acceptable', it will"
468 " terminate before the desired convergence tolerance is met. This is"
469 " useful in cases where the algorithm might not be able to achieve the"
470 "'desired' level of accuracy. The valid range for this real option is "
471 "0 < acceptable_tol < +inf and its default value is 1e-06"
472 }, 1e-6, 0, 1.e50}
473 );
474
475 slv_param_int(parameters,IPOPT_PARAM_ACCEPTABLE_ITER
476 ,(SlvParameterInitInt){{"acceptable_iter"
477 ,"Num. of 'acceptable' iters before triggering stop.",3
478 ,"If the algorithm encounters this many successive 'acceptable' "
479 "iterates (see 'acceptable_tol'), it terminates, assuming that "
480 "the problem has been solved to best possible accuracy given round-off."
481 " If it is set to zero, this heuristic is disabled. The valid range for"
482 " this integer option is 0 < acceptable_iter < +inf and its default "
483 "value is 15."
484 }, 15, 0, 100000000}
485 );
486
487
488 /** Linear Solver Options*/
489
490 /* see http://www.coin-or.org/Ipopt/documentation/node139.html */
491 slv_param_char(parameters,IPOPT_PARAM_LINEAR_SOLVER
492 ,(SlvParameterInitChar){{"linear_solver"
493 ,"Linear solver used for step computations.",4
494 ,"Determines which linear algebra package is to be used for the"
495 " solution of the augmented linear system (for obtaining the search"
496 " directions). Note, the code must have been compiled with the"
497 " linear solver you want to choose. Depending on your Ipopt"
498 " installation, not all options are available. The default value"
499 " for this string option is 'ma27'."
500 " Available options *may* include: ma27, ma57, pardiso, wsmp,"
501 " mumps, custom."
502 }, "mumps"}, (char *[]){
503 "ma27","ma57","pardiso","wsmp","mumps","custom",NULL
504 }
505 );
506
507
508 /** Barrier Parameter Options*/
509
510 slv_param_char(parameters,IPOPT_PARAM_MU_STRATEGY
511 ,(SlvParameterInitChar){{"mu_strategy"
512 ,"Update strategy for barrier parameter",5
513 ,"Determines which barrier parameter update strategy is to be used."
514 " 'monotone' is the monotone (Fiacco-McCormick) strategy;"
515 " 'adaptive' is the adaptive update strategy."
516 }, "monotone"}, (char *[]){
517 "monotone","adaptive",NULL
518 }
519 );
520
521 /** Derivative Test Options */
522
523 slv_param_char(parameters,IPOPT_PARAM_DERIVATIVE_TEST
524 ,(SlvParameterInitChar){{"derivative_test"
525 ,"Use Derivative Checker?",6
526 ,"A finite-difference derivative checker is provided by IPOPT, which"
527 " will check Jacobian and gradient functions ('first-order') or"
528 " all first-order derivatives as well as the Hessian matrix"
529 " ('second-order'). The default is to perform no checks ('none')."
530 }, "none"}, (char *[]){
531 "none","first-order","second-order",NULL
532 }
533 );
534
535 /** Quasi-Newton Options*/
536
537 slv_param_char(parameters,IPOPT_PARAM_HESS_APPROX
538 ,(SlvParameterInitChar){{"hessian_approximation"
539 ,"Hessian calculation method",7
540 ,"Use either an exact Hessian matrix based on symbolic derivatives"
541 " computed from the equations in the model ('exact'), or else use"
542 " a limited-memory quasi-Newton approximation ('limited-memory')."
543 " The default is 'limited-memory'."
544 }, "exact"}, (char *[]){
545 "exact","limited-memory",NULL
546 }
547 );
548
549
550 asc_assert(parameters->num_parms==IPOPT_PARAMS);
551
552 return 1;
553 }
554
555 static void ipopt_get_parameters(slv_system_t server, SlvClientToken asys
556 , slv_parameters_t *parameters
557 ){
558 IpoptSystem *sys;
559 UNUSED_PARAMETER(server);
560
561 sys = SYS(asys);
562 //if(check_system(sys)) return;
563 mem_copy_cast(&(sys->p),parameters,sizeof(slv_parameters_t));
564 }
565
566
567 static void ipopt_set_parameters(slv_system_t server, SlvClientToken asys
568 ,slv_parameters_t *parameters
569 ){
570 IpoptSystem *sys;
571 UNUSED_PARAMETER(server);
572
573 sys = SYS(asys);
574 //if (check_system(sys)) return;
575 mem_copy_cast(parameters,&(sys->p),sizeof(slv_parameters_t));
576 }
577
578 /*------------------------------------------------------------------------------
579 EVALUATION AND RESULT HOOK FUNCTIONS
580 */
581
582 /**
583 update the model with new 'x' vector.
584 @return 0 on success.
585 */
586 int ipopt_update_model(IpoptSystem *sys, const double *x){
587 unsigned j;
588
589 //CONSOLE_DEBUG("Updating Model ...");
590
591 asc_assert(sys);
592 asc_assert(sys->vlist);
593
594 /* FIXME do we need to update any other stuff? */
595 for(j = 0; j < sys->n; ++j){
596 //CONSOLE_DEBUG("value of var[%d] = %g", j, x[j]);
597 asc_assert(!isnan(x[j]));
598 var_set_value(sys->vlist[j], x[j]);
599 }
600
601 return 0;
602 }
603
604 /** Function to evaluate the objective function f(x).
605 @return 1 on success, 0 on failure
606
607 @param n (in), the number of variables in the problem (dimension of 'x').
608 @param x (in), the values for the primal variables, 'x' , at which 'f(x)' is to be evaluated.
609 @param new_x (in), false if any evaluation method was previously called with the same values in 'x', true otherwise.
610 @param obj_value (out) the value of the objective function ('f(x)').
611 */
612 Bool ipopt_eval_f(Index n, Number *x, Bool new_x, Number *obj_value, void *user_data){
613 IpoptSystem *sys;
614 sys = SYS(user_data);
615 int res;
616
617 //CONSOLE_DEBUG("ipopt_eval_f");
618
619 asc_assert(n==sys->n);
620 asc_assert(sys->obj!=NULL);
621
622 if(new_x){
623 res = ipopt_update_model(sys,x);
624 if(res)return 0; /* fail model update */
625 }
626
627 sys->calc_ok = TRUE;
628
629
630 /* char *relname;
631 relname = rel_make_name(sys->slv,sys->obj);
632 //CONSOLE_DEBUG("%s", relname);
633 ascfree(relname);*/
634 *obj_value = relman_eval(sys->obj,&(sys->calc_ok),SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL));
635 asc_assert(!isnan(*obj_value));
636 //CONSOLE_DEBUG("sys->obj_value = %g",*obj_value);
637 //CONSOLE_DEBUG("done ipopt_eval_f");
638 return sys->calc_ok;
639 }
640
641 /**
642 @return 1 on success
643 */
644 Bool ipopt_eval_grad_f(Index n, Number* x, Bool new_x, Number* grad_f, void *user_data){
645 IpoptSystem *sys;
646 int j, res, len;
647 int count;
648 double *derivatives;
649 int *variables;
650
651 sys = SYS(user_data);
652
653 //CONSOLE_DEBUG("ipopt_eval_grad_f");
654
655 asc_assert(n==sys->n);
656 asc_assert(sys->obj);
657 asc_assert(sys->slv);
658
659 if(new_x){
660 res = ipopt_update_model(sys,x);
661 if(res)return 0; /* fail model update */
662 }
663
664
665 /* evaluate grad_f(x) somehow */
666 for(j=0; j<n; ++j){
667 grad_f[j] = 0;
668 }
669
670 len = rel_n_incidences(sys->obj);
671 variables = ASC_NEW_ARRAY_CLEAR(int,len);
672 derivatives = ASC_NEW_ARRAY_CLEAR(double,len);
673 /** @todo Check if memory allocation was successful and flag error if otherwise */
674 //CONSOLE_DEBUG("Length of incidences: %d",len);
675 //CONSOLE_DEBUG("allocated variables,derivatives");
676
677 /*relman_diff2(
678 sys->obj,&vfilter,derivatives,variables
679 , &count,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL)
680 );*/
681
682 relman_diff2_rev(
683 sys->obj,&(sys->vfilt),derivatives,variables
684 , &count,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL)
685 );
686
687
688 for(j=0; j<len; ++j){
689 //asc_assert(!isnan(derivatives[j]));
690 grad_f[variables[j]] = derivatives[j];
691 char *tmp = var_make_name(sys->slv, sys->vlist[variables[j]]);
692 //CONSOLE_DEBUG("var %d ('%s'): varindex = %d, x = %g, df/dx = %f", j, tmp, variables[j], var_value(sys->vlist[variables[j]]), derivatives[j]);
693 ASC_FREE(tmp);
694 }
695
696 if(variables)ASC_FREE(variables);
697 if(derivatives)ASC_FREE(derivatives);
698
699 //CONSOLE_DEBUG("done ipopt_eval_grad_f");
700 return 1; /* success, presumably */
701 }
702
703 Bool ipopt_eval_g(Index n, Number* x, Bool new_x, Index m, Number *g, void *user_data){
704 IpoptSystem *sys;
705 sys = SYS(user_data);
706 int i, res;
707 struct rel_relation *rel;
708 int calc_ok = 1;
709
710 //CONSOLE_DEBUG("ipopt_eval_g (n=%d, m=%d)",sys->n, sys->m);
711
712 asc_assert(n==sys->n);
713 asc_assert(m==sys->m);
714
715 if(new_x){
716 res = ipopt_update_model(sys,x);
717 if(res)return 0; /* fail model update */
718 }
719
720 for(i=0;i<m;++i){
721 //CONSOLE_DEBUG("rel %d: %s.",i,(sys->rlist[i] == sys->obj ? "OBJECTIVE" : "constraint")); //minor fix was rlist[0] -- MNM
722 }
723
724 /** @todo constraint rels are all relations except the objective rel. do we need to sort the objective to the end? */
725 for(i=0; i<m; ++i){
726 rel = sys->rlist[i];
727 asc_assert(rel!=NULL);
728 //if(rel == sys->obj) continue; /* I think this completes the function for the time being */
729 g[i] = relman_eval(rel, &calc_ok,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL));
730 asc_assert(!isnan(g[i]));
731 //CONSOLE_DEBUG("g[%d] = %f",i,g[i]);
732 }
733
734 return calc_ok; /* fail: not yet implemented */
735 }
736
737 Bool ipopt_eval_jac_g(Index n, Number* x, Bool new_x, Index m
738 , Index nele_jac, Index* iRow, Index *jCol, Number* values
739 , void *user_data
740 ){
741 IpoptSystem *sys;
742 sys = SYS(user_data);
743 int i,res,j,k,len,count;
744 struct var_variable **incidence_list;
745 int *variables;
746 double *derivatives;
747
748 //CONSOLE_DEBUG("ipopt_eval_jac_g... nnzJ = %d",sys->nnzJ);
749 //CONSOLE_DEBUG("ipopt_eval_jac_g... n = %d",sys->n);
750 //CONSOLE_DEBUG("ipopt_eval_jac_g... m = %d",sys->m);
751
752 asc_assert(sys!=NULL);
753 asc_assert(n==sys->n);
754 asc_assert(nele_jac==sys->nnzJ);
755 asc_assert(m==sys->m);
756
757 if(new_x){
758 res = ipopt_update_model(sys,x);
759 if(res)return 0; /* fail model update */
760 }
761
762 if(values == NULL){
763 CONSOLE_DEBUG("sparsity structure requested");
764 k=0;
765 for(i=0; i<m;++i){
766 /* looping through rows, one per relation */
767 if(rel_apply_filter(sys->rlist[i], &(sys->rfilt))){
768 incidence_list = (struct var_variable**) rel_incidence_list(sys->rlist[i]);
769 len=rel_n_incidences(sys->rlist[i]);
770 for(j=0;j<len;j++){
771 /* looping through incident variables in current relation */
772 if(var_apply_filter(incidence_list[j], &(sys->vfilt))){
773 CONSOLE_DEBUG("Non-zero #%d at [%d,%d]",k, i,incidence_list[j]->sindex);
774
775 /* valgrind says invalid write of size 4 here... */
776 iRow[k]=i; // should i use sindex of row here or is this ok?
777 jCol[k++]=incidence_list[j]->sindex;
778 }
779 }
780 }else{
781 CONSOLE_DEBUG("Filter removes relation %d",i);
782 }
783 }
784 CONSOLE_DEBUG("Found %d non-zero elements in jacobian", k);
785 }else{
786 //CONSOLE_DEBUG("Calculating jacobian...");
787 k=0;
788 /** @TODO make use of some temporary allocated memory for these arrays... */
789 variables = ASC_NEW_ARRAY(int,n);
790 derivatives = ASC_NEW_ARRAY_CLEAR(double,n);
791 for(i=0; i<m;++i){
792 if(rel_apply_filter(sys->rlist[i], &(sys->rfilt))){
793 incidence_list = (struct var_variable**) rel_incidence_list(sys->rlist[i]);
794 len = rel_n_incidences(sys->rlist[i]);
795
796 #if 0
797 relman_diff2(sys->rlist[i],&(sys->vfilt),derivatives,variables
798 ,&count,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL)
799 );
800 #else
801 relman_diff2_rev(sys->rlist[i], &(sys->vfilt), derivatives
802 ,variables, &count, SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL)
803 );
804 #endif
805
806 for(j=0;j<count;j++){ /* loop through only the returned (filtered) incidences, not all of them */
807 asc_assert(k < sys->nnzJ);
808 //CONSOLE_DEBUG("Recording values[%d] = derivatives[%d]",k,j);
809 asc_assert(!isnan(derivatives[j]));
810 values[k++] = derivatives[j];
811 }
812 }
813 }
814 if(variables)ASC_FREE(variables);
815 if(derivatives)ASC_FREE(derivatives);
816 //CONSOLE_DEBUG("Filled in values of Jacobian");
817 }
818 //CONSOLE_DEBUG("done ipopt_eval_jac_g");
819 return TRUE;
820 }
821
822 Bool ipopt_eval_h(Index n, Number* x, Bool new_x
823 , Number obj_factor, Index m, Number* lambda
824 , Bool new_lambda, Index nele_hess, Index* iRow
825 , Index* jCol, Number* values
826 , void *user_data
827 ){
828 IpoptSystem *sys;
829 sys = SYS(user_data);
830
831 int res,count;
832
833 struct var_variable **incidence_list;
834
835 ltmatrix *hess_matrix;
836
837 unsigned long i;
838
839 Index row;
840 Index col;
841 Index idx;
842
843 //CONSOLE_DEBUG("IN FUNCTION ipopt_eval_h");
844 //CONSOLE_DEBUG("nnzH = %d",sys->nnzH);
845 //CONSOLE_DEBUG("n = %d, m = %d",sys->n, sys->m);
846
847 asc_assert(sys!=NULL);
848 asc_assert(n==sys->n);
849 asc_assert(nele_hess==sys->nnzH);
850
851 if(new_x){
852 res = ipopt_update_model(sys,x);
853 if(res)return FALSE; /* fail model update */
854 }
855
856 if(values == NULL){
857 asc_assert(iRow !=NULL && jCol != NULL);
858
859 CONSOLE_DEBUG("Determining sparsity structure of the hessian of the lagrangian");
860
861 /* identify the sparsity structure of the Hessian (note: only the lower-
862 left part is required by IPOPT , because the Hessian is symmetric) */
863 //CONSOLE_DEBUG("Analysing of Hessian matrix sparsity structure not implemented");
864 //CONSOLE_DEBUG("Dense Hessian Calculations being performed");
865
866 idx = 0;
867
868 for (row = 0; row < n; row++) {
869 for (col = 0; col <= row; col++) {
870 iRow[idx] = row;
871 jCol[idx] = col;
872 idx++;
873 }
874 }
875 asc_assert(idx == nele_hess);
876
877 CONSOLE_DEBUG("Done with sparsity calc, there are %d elements",idx);
878 }
879 else{
880 asc_assert(jCol==NULL && iRow==NULL);
881 asc_assert(lambda!=NULL);
882
883 /** Array of LT matrix */
884 hess_matrix = ltmatrix_create(LTMATRIX_LOWER,n);
885
886 //CONSOLE_DEBUG("Order of Hessian MATRIX [%d x %d]",n,n);
887
888 /** Correction for objective function **/
889 //CONSOLE_DEBUG("Correction for Objective Relation underway");
890 relman_hess(sys->obj,&(sys->vfilt),hess_matrix,&count,n,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL));
891
892 idx = 0;
893
894 for (row = 0; row < n; row++) {
895 for (col = 0; col <= row; col++) {
896 values[idx] = ltmatrix_get_element(hess_matrix,row,col) * (obj_factor);
897 idx++;
898 }
899 }
900 asc_assert(idx == nele_hess);
901
902
903 /** Correction for m-relations **/
904
905
906 for(i=0; i<m; i++){
907 /** @TODO Initialize the Hess Matrix Elements to zero */
908 ltmatrix_clear(hess_matrix);
909
910 incidence_list = (struct var_variable**) rel_incidence_list(sys->rlist[i]);
911 if(incidence_list!=NULL){
912 //CONSOLE_DEBUG("Correction for Constraint Relation [%lu] underway",i);
913 relman_hess(sys->rlist[i],&(sys->vfilt),hess_matrix,&count,n,SLV_PARAM_BOOL(&(sys->p),ASCEND_PARAM_SAFEEVAL));
914
915 idx=0;
916
917 for (row = 0; row < n; row++) {
918 for (col = 0; col <= row; col++) {
919 values[idx] += ltmatrix_get_element(hess_matrix,row,col) * (lambda[i]);
920 idx++;
921 }
922 }
923 asc_assert(idx == nele_hess);
924
925 }
926 else{
927 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Unused Relation???");
928 ltmatrix_destroy(hess_matrix);
929 return FALSE; //I'm not sure about the action to take.
930 }
931 }
932
933 //CONSOLE_DEBUG("Hessian Matrix evaluation successful");
934
935 ltmatrix_destroy(hess_matrix);
936
937 /* evaluate the Hessian matrix */
938 //CONSOLE_DEBUG("Evaluation of Hessian matrix Completed");
939 }
940
941 return TRUE; /* fail: not yet implemented */
942 }
943
944 /*------------------------------------------------------------------------------
945 SOLVE ROUTINES
946 */
947
948 static int ipopt_presolve(slv_system_t server, SlvClientToken asys){
949 IpoptSystem *sys;
950 int max, i;
951 struct var_variable *var;
952
953 //CONSOLE_DEBUG("PRESOLVE");
954
955 sys = SYS(asys);
956 ipopt_iteration_begins(sys);
957 //check_system(sys);
958
959 asc_assert(sys->vlist && sys->rlist);
960
961 /** @todo work out if matrix creation is not again needed */
962
963 slv_sort_rels_and_vars(server,&(sys->m),&(sys->n));
964 #if 0
965 /* ignore any errors here; if it fails, we may just have a single objective function and no constraining relations */
966 if(-1 == sys->n){
967 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to find any optimisable vars");
968 return -4;
969 }
970 if(-1 == sys->m){
971 sys->m = 0; /* no relations found, but that's OK if there's an objective? */
972 }
973 if(-1 == sys->m)sys->m = 0;
974 if(-1 == sys->n)sys->n = 0;
975 #endif
976
977 CONSOLE_DEBUG("Got %d rels and %d vars",sys->m, sys->n);
978
979 #if 1
980 /* count the number of optimisation variables */
981 sys->n = 0;
982 for(i = 0; i < sys->vtot; i++){
983 var = sys->vlist[i];
984 if(var_apply_filter(var,&(sys->vfilt))){
985 sys->n++;
986 }
987 }
988 #endif
989
990 /* set all relations as being 'unsatisfied' to start with... */
991 for(i=0; i < sys->rtot; ++i){
992 rel_set_satisfied(sys->rlist[i],FALSE);
993 }
994
995 sys->obj = slv_get_obj_relation(server); /*may have changed objective*/
996
997
998 if(!sys->obj){
999 ERROR_REPORTER_HERE(ASC_PROG_ERR,"No objective function was specified");
1000 return -3;
1001 }
1002 //CONSOLE_DEBUG("got objective rel %p",sys->obj);
1003 /* @todo check if old_obj == obj ? */
1004
1005 #if 1
1006 /* TODO are there cases where these should be different: answer: NO. they are always the same -- JP */
1007 sys->m = sys->rtot;
1008 #endif
1009
1010 //CONSOLE_DEBUG("Numbers of constraints = %d",sys->m);
1011
1012 /** @todo we need to move the objective relation to the end of the list */
1013
1014 /*for(i=0;i<sys->rtot-1;++i){
1015 //CONSOLE_DEBUG("%d",i);
1016 if(sys->rlist[i] == sys->obj)
1017 //CONSOLE_DEBUG("<-------------------------------This Check Works------------------------>");
1018
1019 }*/
1020
1021 //CONSOLE_DEBUG("got objective rel %p",sys->obj);
1022
1023 /* calculate nnz for hessian matrix @todo FIXME */
1024
1025 if(strcmp(SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_HESS_APPROX),"exact")==0){
1026 /** @todo fix rtot to be 'm' instead */
1027 sys->nnzH = ((sys->n)*((sys->n)+1))/2; //dense Hessian count
1028 }else{
1029 //CONSOLE_DEBUG("Skipping relman_hessian_count as hessian method is not exact.");
1030 //sys->nnzH = sys->n * sys->m;
1031 }
1032
1033 /* need to provide sparsity structure for hessian matrix? */
1034
1035 #if 0
1036 /** @SEE http://www.coin-or.org/Ipopt/documentation/node37.html */
1037 ipopt_eval_h(number_of_variables, NULL/*x at which to evaluate*/, TRUE /* new x */
1038 , 1.0/*obj_factor*/, number_of_constraints, lambda/* values of the constraint multipliers */
1039 , TRUE /* new lambda */, 0 /* number of nonzero elements in the Hessian */, Index* iRow
1040 , Index* jCol, Number* values
1041 , void *user_data
1042 );
1043 #endif
1044
1045
1046 max = relman_obj_direction(sys->obj);
1047 if(max==-1){
1048 //CONSOLE_DEBUG("this is a MINIMIZE problem");
1049 }else{
1050 //CONSOLE_DEBUG("this is a MAXIMIZE problem");
1051 }
1052
1053 //CONSOLE_DEBUG("got %d constraints and %d vars in system", sys->m, sys->n);
1054 /* calculate number of non-zeros in the Jacobian matrix for the constraint equations */
1055
1056 /* @todo make sure objective rel moved to end */
1057
1058 CONSOLE_DEBUG("About to call relman_jacobian_count");
1059 sys->nnzJ = relman_jacobian_count(sys->rlist, sys->m, &(sys->vfilt), &(sys->rfilt), &max);
1060 /*sys->nnzJ=0;
1061 for(i=0;i<sys->m;++i){
1062 sys->nnzJ += rel_n_incidences(sys->rlist[i]);
1063 }*/
1064
1065 CONSOLE_DEBUG("got %d non-zeros in constraint Jacobian", sys->nnzJ);
1066
1067 /* need to provide sparsity structure for jacobian? */
1068
1069
1070
1071 #if 0
1072 if(sys->presolved > 0) { /* system has been presolved before */
1073 if(!conopt_dof_changed(sys) /*no changes in fixed or included flags*/
1074 && sys->p.partition == sys->J.old_partition
1075 && sys->obj == sys->old_obj
1076 ){
1077 matrix_creation_needed = 0;
1078 CONOPT_//CONSOLE_DEBUG("YOU JUST AVOIDED MATRIX DESTRUCTION/CREATION");
1079 }
1080 }
1081 #endif
1082
1083 #if 0
1084 // check all this...
1085
1086 sys->presolved = 1; /* full presolve recognized here */
1087 sys->resolve = 0; /* initialize resolve flag */
1088
1089 sys->J.old_partition = sys->p.partition;
1090 sys->old_obj = sys->obj;
1091
1092 slv_sort_rels_and_vars(server,&(sys->con.m),&(sys->con.n));
1093 CONOPT_//CONSOLE_DEBUG("FOUND %d CONSTRAINTS AND %d VARS",sys->con.m,sys->con.n);
1094 if (sys->obj != NULL) {
1095 CONOPT_//CONSOLE_DEBUG("ADDING OBJECT AS A ROW");
1096 sys->con.m++; /* treat objective as a row */
1097 }
1098
1099 cntvect = ASC_NEW_ARRAY(int,COIDEF_Size());
1100 COIDEF_Ini(cntvect);
1101 sys->con.cntvect = cntvect;
1102 CONOPT_//CONSOLE_DEBUG("NUMBER OF CONSTRAINTS = %d",sys->con.m);
1103 COIDEF_NumVar(cntvect, &(sys->con.n));
1104 COIDEF_NumCon(cntvect, &(sys->con.m));
1105 sys->con.nz = num_jacobian_nonzeros(sys, &(sys->con.maxrow));
1106 COIDEF_NumNZ(cntvect, &(sys->con.nz));
1107 COIDEF_NumNlNz(cntvect, &(sys->con.nz));
1108
1109 sys->con.base = 0;
1110 COIDEF_Base(cntvect,&(sys->con.base));
1111 COIDEF_ErrLim(cntvect, &(DOMLIM));
1112 COIDEF_ItLim(cntvect, &(ITER_LIMIT));
1113
1114 if(sys->obj!=NULL){
1115 sys->con.optdir = relman_obj_direction(sys->obj);
1116 sys->con.objcon = sys->con.m - 1; /* objective will be last row */
1117 CONOPT_//CONSOLE_DEBUG("SETTING OBJECTIVE CONSTRAINT TO BE %d",sys->con.objcon);
1118 }else{
1119 sys->con.optdir = 0;
1120 sys->con.objcon = 0;
1121 }
1122 COIDEF_OptDir(cntvect, &(sys->con.optdir));
1123 COIDEF_ObjCon(cntvect, &(sys->con.objcon));
1124
1125 temp = 0;
1126 COIDEF_StdOut(cntvect, &temp);
1127
1128 int debugfv = 1;
1129 COIDEF_DebugFV(cntvect, &debugfv);
1130
1131 destroy_vectors(sys);
1132 destroy_matrices(sys);
1133 create_matrices(server,sys);
1134 create_vectors(sys);
1135
1136 sys->s.block.current_reordered_block = -2;
1137 }
1138
1139 //...
1140
1141 if( matrix_creation_needed ) {
1142 destroy_array(sys->s.cost);
1143 sys->s.cost = create_zero_array(sys->s.costsize,struct slv_block_cost);
1144 for( ind = 0; ind < sys->s.costsize; ++ind ) {
1145 sys->s.cost[ind].reorder_method = -1;
1146 }
1147 } else {
1148 reset_cost(sys->s.cost,sys->s.costsize);
1149 }
1150
1151 #endif
1152
1153 /* Reset status */
1154 sys->s.iteration = 0;
1155 sys->s.cpu_elapsed = 0.0;
1156 sys->s.converged = sys->s.diverged = sys->s.inconsistent = FALSE;
1157 sys->s.block.previous_total_size = 0;
1158 sys->s.costsize = 1+sys->s.block.number_of;
1159
1160
1161 /* set to go to first unconverged block */
1162 sys->s.block.current_block = -1;
1163 sys->s.block.current_size = 0;
1164 sys->s.calc_ok = TRUE;
1165 sys->s.block.iteration = 0;
1166 sys->obj_val = MAXDOUBLE/2000.0;
1167 //CONSOLE_DEBUG("sys->obj_val=%g",sys->obj_val);
1168 update_status(sys);
1169
1170 ipopt_iteration_ends(sys);
1171
1172 //CONSOLE_DEBUG("Reset status");
1173
1174 /* sys->s.cost[sys->s.block.number_of].time=sys->s.cpu_elapsed; */
1175
1176 //ERROR_REPORTER_HERE(ASC_USER_SUCCESS,"presolve completed");
1177 return 0;
1178 }
1179
1180
1181 static int ipopt_solve(slv_system_t server, SlvClientToken asys){
1182 IpoptSystem *sys;
1183 UNUSED_PARAMETER(server);
1184 enum ApplicationReturnStatus status;
1185 int ret, i, j;
1186 struct var_variable *var;
1187 enum rel_enum type_of_rel;
1188 sys = SYS(asys);
1189
1190 double *x, *x_L, *x_U, *g_L, *g_U, *mult_x_L, *mult_x_U;
1191
1192 CONSOLE_DEBUG("SOLVING: sys->n = %d, sys->m = %d...",sys->n,sys->m);
1193 asc_assert(sys->n!=-1);
1194
1195 /* set the number of variables and allocate space for the bounds */
1196 x_L = ASC_NEW_ARRAY(Number,sys->n);
1197 x_U = ASC_NEW_ARRAY(Number,sys->n);
1198
1199 //CONSOLE_DEBUG("SETTING BOUNDS...");
1200
1201 /* @todo set the values for the variable bounds */
1202 int jj = 0;
1203 for(j = 0; j < sys->vtot; j++){
1204 //CONSOLE_DEBUG("j = %d, vtot = %d, vlist = %p",j,sys->vtot,sys->vlist);
1205 var = sys->vlist[j];
1206 if(var_apply_filter(var,&(sys->vfilt))){
1207 //CONSOLE_DEBUG("setting x_L[%d] = %e",jj,var_lower_bound(var));
1208 assert(jj<sys->n);
1209 x_L[jj] = var_lower_bound(var);
1210 //CONSOLE_DEBUG("setting x_U[%d] = %e",jj,var_upper_bound(var));
1211 x_U[jj] = var_upper_bound(var);
1212 jj++;
1213 }
1214 }
1215
1216 //CONSOLE_DEBUG("jj = %d, sys->n = %d", jj, sys->n);
1217 assert(jj==sys->n);
1218
1219 /** @todo set bounds on the constraints? */
1220 /* is it possible to identify f(x)<a; f(x) >b and fold them into one? */
1221 /* then find the constant parts and make then g_L or g_U accordingly */
1222 /* what to do about other bounds? */
1223 /* set the number of variables and allocate space for the bounds */
1224 g_L = ASC_NEW_ARRAY(Number,sys->m);
1225 g_U = ASC_NEW_ARRAY(Number,sys->m);
1226 //CONSOLE_DEBUG("Allocated arrays for bounds of relations");
1227 if(g_L!=NULL && g_U!=NULL)
1228 for(j = 0; j < sys->m; j++){
1229 type_of_rel = rel_relop(sys->rlist[j]);
1230 if (type_of_rel == e_rel_less || type_of_rel == e_rel_lesseq){
1231 g_L[j] = -2.0e19; //refer to IPOPT Manual "The C Interface"
1232 g_U[j] = 0;
1233 }
1234 else if (type_of_rel == e_rel_greatereq || type_of_rel == e_rel_greater){
1235 g_L[j] = 0;
1236 g_U[j] = 2.0e19; //refer to IPOPT Manual "the C Interface"
1237 }
1238 else{
1239 g_L[j] = 0;
1240 g_U[j] = 0;
1241 }
1242 //CONSOLE_DEBUG("set g_L[%d] = %e",j,g_L[j]);
1243 //CONSOLE_DEBUG("set g_U[%d] = %e",j,g_U[j]);
1244 }
1245 else
1246 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to allocate arrays for bounds of relations");
1247
1248
1249 //CONSOLE_DEBUG("CREATING PROBLEM...");
1250
1251 /* create the IpoptProblem */
1252 //CONSOLE_DEBUG("n = %d, m = %d, nnzJ = %d, nnzH = %d",sys->n, sys->m, sys->nnzJ, sys->nnzH);
1253 sys->nlp = CreateIpoptProblem(sys->n, x_L, x_U, sys->m, g_L, g_U, sys->nnzJ, sys->nnzH, 0/*index style=C*/,
1254 &ipopt_eval_f, &ipopt_eval_g, &ipopt_eval_grad_f,
1255 &ipopt_eval_jac_g, &ipopt_eval_h
1256 );
1257
1258 //CONSOLE_DEBUG("FREEING INTERNAL STUFF");
1259
1260 /* We can free the memory now - the values for the bounds have been
1261 copied internally in CreateIpoptProblem */
1262 ASC_FREE(x_L);
1263 ASC_FREE(x_U);
1264 ASC_FREE(g_L);
1265 ASC_FREE(g_U);
1266
1267 //CONSOLE_DEBUG("SETTING OPTIONS...");
1268 /* set some options */
1269 /** OUTPUT OPTIONS */
1270 AddIpoptIntOption(sys->nlp, "print_level", SLV_PARAM_INT(&(sys->p),IPOPT_PARAM_PRINT_LEVEL));
1271 AddIpoptStrOption(sys->nlp, "print_user_options", SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_PRINT_USER_OPTIONS));
1272 /** TERMINATION OPTIONS */
1273 AddIpoptIntOption(sys->nlp, "max_iter", SLV_PARAM_INT(&(sys->p),IPOPT_PARAM_MAX_ITER));
1274 AddIpoptNumOption(sys->nlp, "tol", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_TOL));
1275 AddIpoptNumOption(sys->nlp, "max_cpu_time", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_MAX_CPU_TIME));
1276 AddIpoptNumOption(sys->nlp, "diverging_iterates_tol", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_DIVERGING_ITERATES_TOL));
1277 AddIpoptNumOption(sys->nlp, "dual_inf_tol", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_DUAL_INFEASIBILITY_TOL));
1278 AddIpoptNumOption(sys->nlp, "constr_viol_tol", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_CONSTR_VIOL_TOL));
1279 AddIpoptNumOption(sys->nlp, "acceptable_tol", SLV_PARAM_REAL(&(sys->p),IPOPT_PARAM_ACCEPTABLE_TOL));
1280 AddIpoptIntOption(sys->nlp, "acceptable_iter", SLV_PARAM_INT(&(sys->p),IPOPT_PARAM_ACCEPTABLE_ITER));
1281 /** BARRIER PARAMETER OPTIONS */
1282 AddIpoptStrOption(sys->nlp, "mu_strategy", SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_MU_STRATEGY));
1283 /** DERIVATIVE TEST OPTIONS */
1284 AddIpoptStrOption(sys->nlp, "derivative_test", SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_DERIVATIVE_TEST));
1285 /** QUASI-NEWTON OPTIONS */
1286 AddIpoptStrOption(sys->nlp, "hessian_approximation", SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_HESS_APPROX));
1287 /** LINEAR SOLVER OPTIONS */
1288 AddIpoptStrOption(sys->nlp, "linear_solver", SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_LINEAR_SOLVER));
1289
1290
1291 //CONSOLE_DEBUG("Hessian method: %s",SLV_PARAM_CHAR(&(sys->p),IPOPT_PARAM_HESS_APPROX));
1292
1293 //CONSOLE_DEBUG("number of vars n = %d, number of rels m = %d",sys->n, sys->m);
1294
1295 /* initial values */
1296 x = ASC_NEW_ARRAY(Number, sys->n);
1297 /*setting initial values here.*/
1298 //CONSOLE_DEBUG("Setting starting values for free variables.");
1299 for(i=0;i<sys->n;++i){
1300 //CONSOLE_DEBUG("set x[%d] = %g",i,var_value(sys->vlist[i])); // need to set the default values
1301 x[i]=var_value(sys->vlist[i]);
1302 }
1303 /** @todo get values of 'x' from the model */
1304
1305 /* allocate space to store the bound multipliers at the solution */
1306 mult_x_L = ASC_NEW_ARRAY(Number, sys->n);
1307 mult_x_U = ASC_NEW_ARRAY(Number, sys->n);
1308
1309 //CONSOLE_DEBUG("Calling IpoptSolve...");
1310
1311 //CONSOLE_DEBUG("sys->objval = %g", sys->obj_val);
1312
1313 /* solve the problem */
1314 status = IpoptSolve(sys->nlp, x, NULL, &sys->obj_val, NULL, mult_x_L, mult_x_U, (void*)sys);
1315
1316 //CONSOLE_DEBUG("Done IpoptSolve...");
1317
1318 /** @todo update the sys->s.xxxxx flags based on value of 'status' */
1319
1320 ret = 1; /* default case is failure */
1321 switch(status){
1322 case Solve_Succeeded:
1323 sys->s.converged = TRUE;
1324
1325 sys->s.block.current_block = -1; //is this 1??
1326 sys->s.cost = ASC_NEW_ARRAY(struct slv_block_cost,1);
1327 sys->s.cost->size=sys->s.block.current_size=sys->n;
1328 sys->s.cost->iterations=sys->s.block.iteration;
1329 sys->s.cost->funcs=sys->s.block.funcs;
1330 sys->s.cost->jacs=sys->s.block.jacs;
1331 sys->s.cost->time=sys->s.block.cpu_elapsed;
1332 sys->s.cost->functime=sys->s.block.functime;
1333 sys->s.cost->jactime=sys->s.block.jactime;
1334
1335
1336 //CONSOLE_DEBUG("Solution of the primal variables, x");
1337 for (i=0; i<sys->n; i++) {
1338 //CONSOLE_DEBUG(" x[%d] = %e\n", i, x[i]);
1339 }
1340
1341 //CONSOLE_DEBUG("Solution of the bound multipliers, z_L and z_U");
1342 for (i=0; i<sys->n; i++) {
1343 //CONSOLE_DEBUG(" z_L[%d] = %e", i, mult_x_L[i]);
1344 }
1345 for (i=0; i<sys->n; i++) {
1346 //CONSOLE_DEBUG(" z_U[%d] = %e", i, mult_x_U[i]);
1347 }
1348
1349 //CONSOLE_DEBUG("Objective value");
1350 //CONSOLE_DEBUG(" f(x*) = %e", sys->obj_val);
1351
1352 ret = 0; /* success */
1353 ipopt_iteration_ends(sys);
1354 update_status(sys);
1355
1356 break;
1357 case Search_Direction_Becomes_Too_Small:
1358 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Solve direction becomes too small");
1359 break;
1360 case Feasible_Point_Found:
1361 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Feasible point not found");
1362 break;
1363 case NonIpopt_Exception_Thrown:
1364 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Non-IPOPT exception thrown");
1365 break;
1366 case Solved_To_Acceptable_Level:
1367 /** @todo What should be done here? */
1368 ERROR_REPORTER_HERE(ASC_USER_NOTE,"Solved to acceptable level");
1369 break;
1370 case Infeasible_Problem_Detected:
1371 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Infeasible Problem Detected");
1372 break;
1373 case Diverging_Iterates:
1374 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Diverging iterations found.");
1375 break;
1376 case User_Requested_Stop:
1377 ERROR_REPORTER_HERE(ASC_USER_WARNING,"User Requested Stop.");
1378 break;
1379 case Maximum_Iterations_Exceeded:
1380 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Maximum Iterations Exceeded.");
1381 break;
1382 case Restoration_Failed:
1383 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Restoration Failed.");
1384 break;
1385 case Error_In_Step_Computation:
1386 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Error in Step Computation.");
1387 break;
1388 case Maximum_CpuTime_Exceeded:
1389 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Maximum CPU Time exceeded.");
1390 break;
1391 case Not_Enough_Degrees_Of_Freedom:
1392 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Not enough degrees of freedom.");
1393 break;
1394 case Invalid_Problem_Definition:
1395 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Invalid problem definition.");
1396 break;
1397 case Invalid_Option:
1398 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Invalid Option.");
1399 break;
1400 case Invalid_Number_Detected:
1401 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Invalid Number Detected.");
1402 break;
1403 case Unrecoverable_Exception:
1404 ERROR_REPORTER_HERE(ASC_PROG_FATAL,"Unrecoverable_Exception.");
1405 break;
1406 case Insufficient_Memory:
1407 ERROR_REPORTER_HERE(ASC_PROG_FATAL,"Insufficient Memory.");
1408 break;
1409 case Internal_Error:
1410 ERROR_REPORTER_HERE(ASC_PROG_FATAL,"Internal Error.");
1411 break;
1412 default:
1413 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"Unhanded return state %d from IPOPT",status);
1414 }
1415
1416 /* free allocated memory */
1417 FreeIpoptProblem(sys->nlp);
1418 ASC_FREE(x);
1419 ASC_FREE(mult_x_L);
1420 ASC_FREE(mult_x_U);
1421
1422 return ret;
1423 }
1424
1425 /**
1426 Prepare sys for entering an iteration, increasing the iteration counts
1427 and starting the clock.
1428 */
1429 static void ipopt_iteration_begins(IpoptSystem *sys){
1430 sys->clock = tm_cpu_time();
1431 ++(sys->s.block.iteration);
1432 ++(sys->s.iteration);
1433 }
1434
1435
1436 /*
1437 Prepare sys for exiting an iteration, stopping the clock and recording
1438 the cpu time.
1439 */
1440 static void ipopt_iteration_ends(IpoptSystem *sys){
1441 double cpu_elapsed; /* elapsed this iteration */
1442
1443 cpu_elapsed = (double)(tm_cpu_time() - sys->clock);
1444 sys->s.block.cpu_elapsed += cpu_elapsed;
1445 sys->s.cpu_elapsed += cpu_elapsed;
1446 }
1447
1448
1449
1450 static int ipopt_iterate(slv_system_t server, SlvClientToken asys){
1451 //CONSOLE_DEBUG("ipopt_iterate about to call ipopt_solve...");
1452 return ipopt_solve(server,asys);
1453 }
1454
1455 static int ipopt_resolve(slv_system_t server, SlvClientToken asys){
1456 IpoptSystem *sys;
1457 sys = SYS(asys);
1458
1459 /** @todo if implementing this, use the 'warm start' thing in IPOPT */
1460
1461 /** @todo provide initial values of the 'multipliers' */
1462
1463 sys->resolve = 1; /* resolved recognized here */
1464
1465 /* Reset status */
1466 sys->s.iteration = 0;
1467 sys->s.cpu_elapsed = 0.0;
1468 sys->s.converged = sys->s.diverged = sys->s.inconsistent = FALSE;
1469 sys->s.block.previous_total_size = 0;
1470
1471 /* go to first unconverged block */
1472 sys->s.block.current_block = -1;
1473 sys->s.block.current_size = 0;
1474 sys->s.calc_ok = TRUE;
1475 sys->s.block.iteration = 0;
1476 sys->obj_val = MAXDOUBLE/2000.0;
1477
1478 update_status(sys);
1479 return 1;
1480 }
1481
1482 static const SlvFunctionsT ipopt_internals = {
1483 67
1484 ,"IPOPT"
1485 ,ipopt_create
1486 ,ipopt_destroy
1487 ,ipopt_eligible_solver
1488 ,ipopt_get_default_parameters
1489 ,ipopt_get_parameters
1490 ,ipopt_set_parameters
1491 ,ipopt_get_status
1492 ,ipopt_solve
1493 ,ipopt_presolve
1494 ,ipopt_iterate
1495 ,ipopt_resolve
1496 ,NULL
1497 ,NULL
1498 ,NULL
1499 };
1500
1501 int ipopt_register(void){
1502 return solver_register(&ipopt_internals);
1503 }

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22