/[ascend]/branches/pallav/ascend/solver/solver.c
ViewVC logotype

Annotation of /branches/pallav/ascend/solver/solver.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2823 - (hide annotations) (download) (as text)
Tue Feb 17 06:38:36 2015 UTC (4 years, 9 months ago) by jpye
File MIME type: text/x-csrc
File size: 15629 byte(s)
restored files from non-svn backup

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

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