/[ascend]/trunk/base/generic/solver/solver.c
ViewVC logotype

Contents of /trunk/base/generic/solver/solver.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1775 - (show annotations) (download) (as text)
Wed May 21 09:51:59 2008 UTC (14 years, 4 months ago) by jpye
File MIME type: text/x-csrc
File size: 15405 byte(s)
Silenced som runtime debug output for datareader and solver.
Added first shot at canvas gui code using Gaphas.
1 /* ASCEND modelling environment
2 Copyright (C) 2007 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, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA.
18 *//**
19 @file
20 Solver API for ASCEND, for solving NLA, LP, NLP, MINLP problems (anything
21 without derivatives).
22 *//*
23 by John Pye, May 2006
24 based on parts of slv_stdcalls.c, modified to provide dynamic loading
25 support, and aiming to improve the separation of 'system' and 'solver',
26 the former being a collection of equations and variables, and the latter
27 being all the methods and data storage that allows a solution to be
28 found and reported.
29 */
30
31 #include "solver.h"
32
33 #include <system/system_impl.h>
34 #include <general/list.h>
35 #include <utilities/ascMalloc.h>
36 #include <utilities/ascPanic.h>
37 #include <compiler/packages.h>
38
39 #define SOLVER_DEBUG 0
40
41 /**
42 Local function that holds the list of available solvers. The value
43 returned is NOT owned by the called.
44
45 @param free_space if 0, call as normal. if 1, free the list and maybe do some
46 cleaning up etc. Should be called whenever a simulation is destroyed.
47 */
48 static struct gl_list_t *solver_get_list(int free_space){
49 static int init = 0;
50 static struct gl_list_t *L;
51 if(free_space){
52 if(init && L)ASC_FREE(L);
53 init = 0;
54 return NULL;
55 }
56 if(!init){
57 L = gl_create(10);
58 init = 1;
59 }
60 return L;
61 }
62
63 /**
64 Return gl_list of SlvFunctionsT. C++ will use this to produce a
65 nice little list of integrator names that can be used in Python :-/
66 */
67 const struct gl_list_t *solver_get_engines(){
68 return solver_get_list(0);
69 }
70
71 const SlvFunctionsT *solver_engine(const int number){
72 const struct gl_list_t *L = solver_get_engines();
73 int i;
74 const SlvFunctionsT *S, *Sfound=NULL;
75 /* CONSOLE_DEBUG("Searching for solver #%d in list of %d solvers",number,gl_length(L)); */
76 for(i=1; i <= gl_length(L); ++i){
77 S = gl_fetch(L,i);
78 /* CONSOLE_DEBUG("Looking at %s (%d)",S->name,S->number); */
79 if(S->number==number){
80 /* CONSOLE_DEBUG("Match!"); */
81 Sfound = S;
82 break;
83 }
84 }
85 /* CONSOLE_DEBUG("Returning %d",Sfound); */
86 return Sfound;
87 }
88
89 const SlvFunctionsT *solver_engine_named(const char *name){
90 const struct gl_list_t *L = solver_get_engines();
91 int i;
92 const SlvFunctionsT *S, *Sfound=NULL;
93 for(i=1; i <= gl_length(L); ++i){
94 S = gl_fetch(L,i);
95 if(strcmp(S->name,name)==0){
96 Sfound = S;
97 break;
98 }
99 }
100 return Sfound;
101 }
102
103 int slv_lookup_client(const char *name){
104 #if 0
105 int i;
106
107 if(name == NULL)return -1;
108
109 for(i = 0; i < NORC; i++) {
110 if(strcmp( SCD(i).name, name)==0) {
111 return i;
112 }
113 }
114 return -1;
115 #endif
116 const struct gl_list_t *L = solver_get_engines();
117 int i;
118 const SlvFunctionsT *S, *Sfound=NULL;
119 for(i=1; i <= gl_length(L); ++i){
120 S = gl_fetch(L,i);
121 if(strcmp(S->name,name)==0){
122 Sfound = S;
123 break;
124 }
125 }
126 if(Sfound){
127 return S->number;
128 }else{
129 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Invalid engine name '%s'",name);
130 return -1;
131 }
132 }
133
134
135 /**
136 Register a new solver.
137
138 @TODO This needs work still, particularly of the dynamic loading
139 sort. it would be good if here we farmed out the dynamic loading
140 to another file so we don't have to crap this one all up.
141
142 old args:
143 (SlvRegistration registerfunc, CONST char *func
144 ,CONST char *file, int *new_client_id
145 */
146 int solver_register(const SlvFunctionsT *solver){
147 #if 0
148 int status;
149
150 status = registerfunc(&( SlvClientsData[NORC]));
151 if (!status) { /* ok */
152 SlvClientsData[NORC].number = NORC;
153 *new_client_id = NORC;
154 NORC++;
155 } else {
156 *new_client_id = -2;
157 ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Client %d registration failure (%d)!",NORC,status);
158 }
159 return status;
160 #endif
161
162 /* get the current list of registered engines */
163 const struct gl_list_t *L;
164 L = solver_get_engines();
165
166 #if 0
167 CONSOLE_DEBUG("REGISTERING SOLVER");
168 CONSOLE_DEBUG("There were %lu registered solvers", gl_length(solver_get_list(0)));
169 #endif
170
171 int i;
172 const SlvFunctionsT *S;
173 for(i=1; i < gl_length(L); ++i){
174 S = (const SlvFunctionsT *)gl_fetch(L,i);
175 if(strcmp(solver->name,S->name)==0){
176 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Solver with name '%s' is already registered",solver->name);
177 return 0;
178 }
179 if(solver->number == S->number){
180 ERROR_REPORTER_HERE(ASC_USER_WARNING,"Solver with ID '%d' is already registered",solver->number);
181 return 0;
182 }
183 }
184
185 #if 0
186 CONSOLE_DEBUG("Adding engine '%s'",solver->name);
187 #endif
188
189 gl_append_ptr(L,(SlvFunctionsT *)solver);
190
191 #if 0
192 CONSOLE_DEBUG("There are now %lu registered solvers", gl_length(solver_get_list(0)));
193 #endif
194 return 0;
195 }
196
197
198 /*------------------------------------------------------------------------------
199 SOLVER REGISTRATION
200 */
201
202 /* rewrote this stuff to get rid of all the #ifdefs -- JP */
203
204 struct StaticSolverRegistration{
205 const char *importname;
206 };
207
208 /*
209 The names here are only used to provide information in the case where
210 solver registration fails. The definitive solver names are in the slv*.c
211 files.
212 */
213 static const struct StaticSolverRegistration slv_reg[]={
214 {"qrslv"}
215 ,{"conopt"}
216 ,{"lrslv"}
217 ,{"cmslv"}
218 /* ,{"ipopt"} */
219 ,{NULL}
220 #if 0
221 /* {0,"SLV",&slv0_register} */
222 /* ,{0,"MINOS",&slv1_register} */
223 /* ,{0,"CSLV",&slv4_register} */
224 /* ,{0,"LSSLV",&slv5_register} */
225 /* ,{0,"MPS",&slv6_register} */
226 /* ,{0,"NGSLV",&slv7_register} */
227 /* ,{0,"OPTSQP",&slv2_register} */
228 #endif
229 };
230
231 int SlvRegisterStandardClients(void){
232 int nclients = 0;
233 //int newclient=0;
234 int error;
235 int i;
236
237 /* CONSOLE_DEBUG("REGISTERING STANDARD SOLVER ENGINES"); */
238 for(i=0; slv_reg[i].importname!=NULL;++i){
239 error = package_load(slv_reg[i].importname,NULL);
240 if(error){
241 ERROR_REPORTER_HERE(ASC_PROG_ERR
242 ,"Unable to register solver '%s' (error %d)."
243 ,slv_reg[i].importname,error
244 );
245 }else{
246 /* CONSOLE_DEBUG("Solver '%s' registered OK",slv_reg[i].importname); */
247 nclients++;
248 }
249 }
250 return nclients;
251 }
252
253 /*------------------------------------------------------*/
254
255 static void printwarning(const char * fname, slv_system_t sys)
256 {
257 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,
258 "%s called with bad registered client (%s).",fname,
259 slv_solver_name(slv_get_selected_solver(sys)));
260 }
261
262 static void printinfo(slv_system_t sys, const char *rname){
263 asc_assert(sys->internals);
264 if(sys->internals->name) {
265 ERROR_REPORTER_NOLINE(ASC_PROG_NOTE,
266 "Client %s does not support function '%s'.",
267 sys->internals->name,rname);
268 }
269 }
270
271 /*-----------------------------------------------------------
272 These macros do some more elimination of repetition. Here we're
273 trying to replace some more complex 'method-like' calls on
274 slv_system_t:
275
276 These macros use macro-argument-concatenation and macro stringification.
277 Verified that the former works with Visual C++.
278 http://www.codeproject.com/macro/metamacros.asp
279 */
280
281 /** Define a method like 'void slv_METHODNAME(sys)' */
282 #define DEFINE_SLV_PROXY_METHOD_VOID(METHOD) \
283 void slv_ ## METHOD (slv_system_t sys){ \
284 if(CF(sys,METHOD)==NULL){ \
285 printwarning(#METHOD,sys); \
286 return; \
287 } \
288 SF(sys,METHOD)(sys,sys->ct); \
289 }
290
291 /** Define a method like 'RETURNTYPE slv_METHOD(sys)'; */
292 #define DEFINE_SLV_PROXY_METHOD(METHOD,PROP,RETTYPE,ERRVAL) \
293 RETTYPE slv_ ## METHOD (slv_system_t sys){ \
294 /* CONSOLE_DEBUG("slv_" #METHOD);*/ \
295 asc_assert(sys->internals); \
296 /*CONSOLE_DEBUG("internals OK");*/ \
297 if(sys->internals->PROP==NULL){ \
298 /*CONSOLE_DEBUG("method is NULL");*/ \
299 printinfo(sys, #METHOD); \
300 return ERRVAL; \
301 } \
302 /*CONSOLE_DEBUG("running method " #PROP " in solver %d",sys->internals->number);*/ \
303 return (sys->internals->PROP)(sys,sys->ct); \
304 }
305
306 /** Define a method like 'void slv_METHOD(sys,TYPE PARAMNAME)'; */
307 #define DEFINE_SLV_PROXY_METHOD_PARAM(METHOD,PROP,PARAMTYPE,PARAMNAME) \
308 void slv_ ## METHOD (slv_system_t sys, PARAMTYPE PARAMNAME){ \
309 if(!sys->internals || !sys->internals->PROP){ \
310 printwarning(#METHOD,sys); \
311 return; \
312 } \
313 (sys->internals->PROP)(sys,sys->ct, PARAMNAME); \
314 }
315
316 DEFINE_SLV_PROXY_METHOD_PARAM(get_parameters,get_parameters,slv_parameters_t*,parameters) /*;*/
317
318 void slv_set_parameters(slv_system_t sys,slv_parameters_t *parameters)
319 {
320 asc_assert(sys->internals);
321 if(sys->internals->setparam == NULL ) {
322 printwarning("slv_set_parameters",sys);
323 return;
324 }
325 if (parameters->whose != sys->solver) {
326 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,
327 "slv_set_parameters cannot pass parameters from one solver to a"
328 " another.");
329 return;
330 }
331 (sys->internals->setparam)(sys,sys->ct,parameters);
332 }
333
334 int slv_get_status(slv_system_t sys, slv_status_t *status){
335 static const SlvFunctionsT *lastsolver = 0;
336 if(!sys->internals)return -1;
337 if(sys->internals->getstatus==NULL){
338 if(lastsolver==0 || lastsolver != sys->internals){
339 printinfo(sys,"get_status");
340 lastsolver = sys->internals;
341 }
342 return -1;
343 }
344 return (sys->internals->getstatus)(sys,sys->ct,status);
345 }
346
347 DEFINE_SLV_PROXY_METHOD_PARAM(dump_internals,dumpinternals,int,level) /*;*/
348
349 DEFINE_SLV_PROXY_METHOD(get_linsolqr_sys, getlinsys, linsolqr_system_t, NULL) /*;*/
350
351 DEFINE_SLV_PROXY_METHOD(get_sys_mtx, get_sys_mtx, mtx_matrix_t, NULL) /*;*/
352 DEFINE_SLV_PROXY_METHOD(presolve,presolve,int,-1) /*;*/
353 DEFINE_SLV_PROXY_METHOD(resolve,resolve,int,-1) /*;*/
354 DEFINE_SLV_PROXY_METHOD(iterate,iterate,int,-1) /*;*/
355 DEFINE_SLV_PROXY_METHOD(solve,solve,int,-1) /*;*/
356
357 int slv_eligible_solver(slv_system_t sys)
358 {
359 asc_assert(sys->internals);
360 if(sys->internals->celigible == NULL ) {
361 printwarning("slv_eligible_solver",sys);
362 return 0;
363 }
364 return (sys->internals->celigible)(sys);
365 }
366
367 //-------------
368
369
370 int slv_select_solver(slv_system_t sys,int solver){
371
372 int status_index;
373 SlvClientDestroyF *destroy;
374 const SlvFunctionsT *S;
375
376 if(sys ==NULL) {
377 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"slv_select_solver called with NULL system.");
378 return -1;
379 }
380
381 /* CONSOLE_DEBUG("CHECKING FOR SOLVER %d", solver); */
382
383 if(solver_engine(solver)){
384 /* CONSOLE_DEBUG("SOLVER FOUND"); */
385 if(sys->ct != NULL && solver != sys->solver){
386 /* CONSOLE_DEBUG("DIFFERENT SOLVER"); */
387 //CONSOLE_DEBUG("g_SlvNumberOfRegisteredClients = %d, sys->solver = %d", g_SlvNumberOfRegisteredClients, sys->solver);
388 asc_assert(sys->solver >= -1);
389 //asc_assert(g_SlvNumberOfRegisteredClients > 0);
390 //asc_assert(sys->solver < g_SlvNumberOfRegisteredClients);
391 S = solver_engine(sys->solver);
392 destroy = S->cdestroy;
393 if(destroy!=NULL) {
394 (destroy)(sys,sys->ct);
395 sys->ct = NULL;
396 }else{
397 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"slv_select_solver: 'cdestroy' is undefined on solver '%s' (index %d).",
398 S->name, sys->solver);
399 }
400 }
401
402 /* CONSOLE_DEBUG("PREVIOUS SOLVER IS CLEAR"); */
403
404 if(sys->ct != NULL) {
405 #if SOLVER_DEBUG
406 CONSOLE_DEBUG("CURRENT SOLVER UNCHANGED");
407 #endif
408 return sys->solver;
409 }
410
411 status_index = solver;
412 sys->solver = solver;
413 sys->internals = solver_engine(solver);
414 if(sys->internals->ccreate != NULL){
415 sys->ct = (sys->internals->ccreate)(sys,&status_index);
416 }else{
417 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"slv_select_solver create failed due to bad client '%s'.",
418 slv_solver_name(sys->solver));
419 return sys->solver;
420 }
421 if(sys->ct==NULL){
422 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"SlvClientCreate failed in slv_select_solver.");
423 sys->solver = -1;
424 }else{
425 if (status_index){
426 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"SlvClientCreate succeeded with warning %d %s.",
427 status_index," in slv_select_solver");
428 }
429 /* we could do a better job explaining the client warnings... */
430 sys->solver = solver;
431 }
432 }else{
433 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"slv_select_solver: invalid solver index '%d'.",
434 solver);
435 return -1;
436 }
437 return sys->solver;
438 }
439
440 /**
441 @TODO looks buggy
442 */
443 int slv_switch_solver(slv_system_t sys,int solver)
444 {
445 int status_index;
446
447 if(sys ==NULL){
448 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"slv_switch_solver called with NULL system.");
449 return -1;
450 }
451
452 /* CONSOLE_DEBUG("CHECKING FOR SOLVER %d", solver); */
453
454 if(solver_engine(solver)){
455 status_index = solver;
456 sys->solver = solver;
457 sys->internals = solver_engine(solver);
458 CONSOLE_DEBUG("SWITCHING TO SOLVER '%s'",sys->internals->name);
459 if(sys->internals->ccreate != NULL) {
460 sys->ct = (sys->internals->ccreate)(sys,&status_index);
461 } else {
462 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"slv_switch_solver create failed due to bad client '%s'.",
463 slv_solver_name(sys->solver));
464 return sys->solver;
465 }
466 if (sys->ct==NULL) {
467 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"SlvClientCreate failed in slv_switch_solver.");
468 sys->solver = -1;
469 }else{
470 if (status_index) {
471 ERROR_REPORTER_NOLINE(ASC_PROG_WARNING,"SlvClientCreate succeeded with warning %d %s.",
472 status_index," in slv_switch_solver");
473 }
474 sys->solver = solver;
475 }
476 }else{
477 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"Unknown client '%d'.",solver);
478 return -1;
479 }
480 return sys->solver;
481 }
482
483 /*--------------------------------*/
484
485 int slv_get_selected_solver(slv_system_t sys){
486 if (sys!=NULL) return sys->solver;
487 return -1;
488 }
489
490
491 int32 slv_get_default_parameters(int sindex,
492 slv_parameters_t *parameters)
493 {
494 SlvFunctionsT *S;
495 S = solver_engine(sindex);
496 if(S){
497 if(S->getdefparam == NULL ) {
498 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"slv_get_default_parameters called with parameterless index.");
499 return 0;
500 }else{
501 /* send NULL system when setting up interface */
502 (S->getdefparam)(NULL,NULL,parameters);
503 return 1;
504 }
505 }else{
506 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"slv_get_default_parameters called with unregistered index.");
507 return 0;
508 }
509 }
510
511
512 /*-----------------------------------------------------------*/
513
514 SlvClientToken slv_get_client_token(slv_system_t sys)
515 {
516 if (sys==NULL) {
517 FPRINTF(stderr,"slv_get_client_token called with NULL system.");
518 return NULL;
519 }
520 return sys->ct;
521 }
522
523
524 void slv_set_client_token(slv_system_t sys, SlvClientToken ct)
525 {
526 if (sys==NULL) {
527 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"slv_set_client_token called with NULL system.");
528 return;
529 }
530 sys->ct = ct;
531 }
532
533 void slv_set_solver_index(slv_system_t sys, int solver)
534 {
535 if (sys==NULL) {
536 ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"slv_set_solver_index called with NULL system.");
537 return;
538 }
539 sys->solver = solver;
540 sys->internals = solver_engine(solver);
541 }
542
543
544 const char *slv_solver_name(int sindex){
545 static char errname[] = "ErrorSolver";
546 const SlvFunctionsT *S = solver_engine(sindex);
547 if(S!=NULL){
548 if(S->name == NULL) {
549 ERROR_REPORTER_HERE(ASC_PROG_WARNING,"unnamed solver: index='%d'",sindex);
550 return errname;
551 }else{
552 return S->name;
553 }
554 }else{
555 ERROR_REPORTER_HERE(ASC_PROG_ERROR,"invalid solver index '%d'", sindex);
556 return errname;
557 }
558 }
559

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