1 |
/* ASCEND modelling environment |
2 |
Copyright (C) 2006, 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 |
This file allows CONOPT to be dlopened at runtime. |
21 |
*//* |
22 |
By John Pye |
23 |
Based on conopt.c by Vicente Rico Ramirez (created 05/97) |
24 |
*/ |
25 |
|
26 |
#include <ascend/utilities/config.h> |
27 |
#include <ascend/general/platform.h> |
28 |
#include <ascend/utilities/error.h> |
29 |
#include <ascend/utilities/ascEnvVar.h> |
30 |
#include <ascend/general/env.h> |
31 |
#include "conopt_dl.h" |
32 |
|
33 |
#ifndef ASC_WITH_CONOPT |
34 |
#ifdef __GNUC__ |
35 |
# warning "Shouldn't compile this file unless ASC_WITH_CONOPT set" |
36 |
#endif |
37 |
#else |
38 |
|
39 |
#ifndef ASC_LINKED_CONOPT |
40 |
# include <ctype.h> |
41 |
# include <ascend/general/ascMalloc.h> |
42 |
# include <ascend/utilities/ascDynaLoad.h> |
43 |
|
44 |
/*------------------------------------------------------------------------------ |
45 |
DLOPENING CONOPT SUPPORT FUNCTIONS |
46 |
*/ |
47 |
|
48 |
# define INTINT (int*cntvect,int*v) |
49 |
# define INTINT1 (cntvect,v) |
50 |
# define INTDOUBLE (int*cntvect,double*v) |
51 |
# define INTDOUBLE1 (cntvect,v) |
52 |
# define SEMICOLON ; |
53 |
# define SPACE |
54 |
|
55 |
/* |
56 |
Typedefs for the various function pointers |
57 |
*/ |
58 |
# define FN_TYPE_DECL(T,A,V,L) \ |
59 |
typedef int COI_CALL (T##_fn_t) A |
60 |
|
61 |
CONOPT_FNS(FN_TYPE_DECL,SEMICOLON); |
62 |
# undef FN_TYPE_DECL |
63 |
|
64 |
/* |
65 |
Define a struct to hold all the function pointers, then |
66 |
declare it as a global variable. |
67 |
*/ |
68 |
# define FN_PTR_DECL(T,A,V,L) \ |
69 |
T##_fn_t* T##_ptr |
70 |
|
71 |
typedef struct{ |
72 |
CONOPT_FNS(FN_PTR_DECL,SEMICOLON); |
73 |
} conopt_fptrs_t; |
74 |
# undef FN_PTR_DECL |
75 |
|
76 |
conopt_fptrs_t conopt_fptrs; |
77 |
|
78 |
|
79 |
/* |
80 |
Declare local functions to hook into the DLL |
81 |
*/ |
82 |
# define FN_PTR_EXEC(T,A,V,L) \ |
83 |
int COI_CALL T A{ \ |
84 |
if(conopt_fptrs.T##_ptr==NULL){ \ |
85 |
return 1; \ |
86 |
} \ |
87 |
return (* conopt_fptrs.T##_ptr) V ; \ |
88 |
} |
89 |
|
90 |
CONOPT_FNS(FN_PTR_EXEC,SPACE) |
91 |
|
92 |
# undef FN_PTR_EXEC |
93 |
|
94 |
/** |
95 |
This funciton will load the DLL and resolve all the required symbols |
96 |
*/ |
97 |
int asc_conopt_load(){ |
98 |
# ifdef ASC_LINKED_CONOPT |
99 |
# error "We don't use this if we've got linked CONOPT!" |
100 |
# endif |
101 |
static int loaded=0; |
102 |
char *libpath; |
103 |
int status; |
104 |
char fnsymbol[400], *c; |
105 |
const char *libname=ASC_CONOPT_LIB; |
106 |
const char *envvar; |
107 |
|
108 |
if(loaded) { |
109 |
return 0; /* already loaded */ |
110 |
} |
111 |
|
112 |
/* CONSOLE_DEBUG("LOADING CONOPT..."); */ |
113 |
|
114 |
envvar = ASC_CONOPT_ENVVAR; |
115 |
|
116 |
/* need to import this variable into the ascend 'environment' */ |
117 |
if(-1!=env_import(ASC_CONOPT_ENVVAR,getenv,Asc_PutEnv)){ |
118 |
CONSOLE_DEBUG("Searching in path '%s' (from env var '%s')",getenv(envvar),envvar); |
119 |
}/*else{ |
120 |
CONSOLE_DEBUG("Default conopt search path: %s", ASC_CONOPT_DLPATH); |
121 |
}*/ |
122 |
|
123 |
/** @TODO replace with a direct call to ospath and/or importhandler? */ |
124 |
libpath = SearchArchiveLibraryPath(libname, ASC_CONOPT_DLPATH, envvar); |
125 |
|
126 |
if(libpath==NULL){ |
127 |
ERROR_REPORTER_NOLINE(ASC_PROG_ERR |
128 |
, "Library '%s' could not be located (check value of env var '%s' and/or default path '%s')" |
129 |
, libname, envvar, ASC_CONOPT_DLPATH |
130 |
); |
131 |
return 1; |
132 |
} |
133 |
|
134 |
status = Asc_DynamicLoad(libpath, NULL); |
135 |
if (status != 0) { |
136 |
ASC_FREE(libpath); |
137 |
return 1; /* failed to load */ |
138 |
} |
139 |
|
140 |
# if defined(FNAME_UCASE_NODECOR) || defined(FNAME_UCASE_DECOR) || defined(FNAME_UCASE_PREDECOR) |
141 |
# define FNCASE(C) C=toupper(C) |
142 |
# elif defined(FNAME_LCASE_NODECOR) || defined(FNAME_LCASE_DECOR) |
143 |
# define FNCASE(C) C=tolower(C) |
144 |
# else |
145 |
# error "CONOPT case rule not defined" |
146 |
# endif |
147 |
|
148 |
# if defined(FNAME_UCASE_DECOR) || defined(FNAME_LCASE_DECOR) |
149 |
# define FNDECOR(S,L) strcat(S,"_") |
150 |
# elif defined(FNAME_UCASE_PREDECOR) /* on windows, precede with _ and append @L (integer value of L) */ |
151 |
# define FNDECOR(S,L) strcat(S,L);for(c=S+strlen(S)+1;c>S;--c){*c=*(c-1);} *S='_'; |
152 |
# else |
153 |
# define FNDECOR(S,L) (void)0 |
154 |
# endif |
155 |
|
156 |
# define FN_PTR_GET(T,A,V,L) \ |
157 |
sprintf(fnsymbol,"%s",#T); \ |
158 |
for(c=fnsymbol;*c!='\0';++c){ \ |
159 |
FNCASE(*c); \ |
160 |
} \ |
161 |
FNDECOR(fnsymbol,L); \ |
162 |
conopt_fptrs.T##_ptr = (T##_fn_t *)Asc_DynamicFunction(libpath,fnsymbol); \ |
163 |
if(conopt_fptrs.T##_ptr==NULL)status+=1; |
164 |
|
165 |
CONOPT_FNS(FN_PTR_GET,SPACE) |
166 |
|
167 |
# undef FN_PTR_GET |
168 |
# undef FNDECOR |
169 |
# undef FNCASE |
170 |
|
171 |
ASC_FREE(libpath); |
172 |
|
173 |
if(status!=0){ |
174 |
return 1; /* faile to result all symbols */ |
175 |
} |
176 |
|
177 |
loaded = 1; |
178 |
return 0; |
179 |
} |
180 |
|
181 |
#endif |
182 |
|
183 |
/*----------------------------------------------------------------------------- |
184 |
std.c |
185 |
|
186 |
This file has some 'standard' implementations for the mandatory |
187 |
callback routines Message, ErrMsg, Status, and Solution. |
188 |
The routines use global file pointers, so they are only intended |
189 |
as examples that can be used for further refinements. |
190 |
*/ |
191 |
|
192 |
#define MAXLINE 133 /* maximum line length plus an extra character |
193 |
for the null terminator */ |
194 |
|
195 |
int COI_CALL asc_conopt_progress( int* LEN_INT, int* INT |
196 |
, int* LEN_RL, double* RL, double* X, double* USRMEM |
197 |
){ |
198 |
/*(void)CONSOLE_DEBUG("Iteration %d, phase %d: %d infeasible, %d non-optimal; objective = %e" |
199 |
, INT[0], INT[1], INT[2], INT[3], RL[1] |
200 |
);*/ |
201 |
/* NEED TO IMPLEMENT SOME KIND OF CALLBACK TO THE SOLVERREPORTER */ |
202 |
return 0; |
203 |
} |
204 |
|
205 |
int COI_CALL asc_conopt_message( int* SMSG, int* DMSG, int* NMSG, int* LLEN |
206 |
,double* USRMEM, char* MSGV, int MSGLEN |
207 |
){ |
208 |
/* This implementation is writing the screen file to stdout |
209 |
the documentation file to a file opened in main with the name |
210 |
document.txt and the status file to a file with the name |
211 |
status.txt. */ |
212 |
int i,j,k,l; |
213 |
char line[MAXLINE]; |
214 |
k = 0; |
215 |
for( i=0; i<*SMSG;i++ ){ |
216 |
j = LLEN[i]; |
217 |
for( l= 0; l<j; l++ ) line[l] = MSGV[k+l]; |
218 |
line[j] = '\0'; |
219 |
CONSOLE_DEBUG("%s", line); |
220 |
k += MSGLEN; |
221 |
} |
222 |
/* k = 0; |
223 |
for( i=0; i<*DMSG;i++ ){ |
224 |
j = LLEN[i]; |
225 |
for( l= 0; l<j; l++ ) line[l] = MSGV[k+l]; |
226 |
line[j] = '\0'; |
227 |
ERROR_REPORTER_NOLINE(ASC_PROG_NOTE,"%s\n", line); |
228 |
k += MSGLEN; |
229 |
} |
230 |
*/ |
231 |
k = 0; |
232 |
for( i=0; i<*NMSG;i++ ){ |
233 |
j = LLEN[i]; |
234 |
for( l= 0; l<j; l++ ) line[l] = MSGV[k+l]; |
235 |
line[j] = '\0'; |
236 |
ERROR_REPORTER_NOLINE(ASC_USER_NOTE,"(CONOPT) %s", line); |
237 |
k += MSGLEN; |
238 |
} |
239 |
return 0; |
240 |
} |
241 |
|
242 |
int COI_CALL asc_conopt_errmsg( int* ROWNO, int* COLNO, int* POSNO, int* MSGLEN |
243 |
, double* USRMEM, char* MSG, int LENMSG |
244 |
){ |
245 |
/* Standard ErrMsg routine. Write to Documentation and Status file*/ |
246 |
int j,l; |
247 |
char line[MAXLINE]; |
248 |
ERROR_REPORTER_START_NOLINE(ASC_PROG_ERR); |
249 |
if ( *ROWNO == -1 ) { |
250 |
FPRINTF(ASCERR,"Variable %d : ",*COLNO); } |
251 |
else if ( *COLNO == -1 ) { |
252 |
FPRINTF(ASCERR,"Equation %d : ",*ROWNO); } |
253 |
else { |
254 |
FPRINTF(ASCERR,"Variable %d appearing in Equation %d : ",*COLNO, *ROWNO); } |
255 |
j = *MSGLEN; |
256 |
for( l= 0; l<j; l++ ) line[l] = MSG[l]; |
257 |
line[j] = '\0'; |
258 |
FPRINTF(ASCERR,"%s\n", line); |
259 |
error_reporter_end_flush(); |
260 |
return 0; |
261 |
} |
262 |
|
263 |
int COI_CALL asc_conopt_status(int* MODSTA, int* SOLSTA |
264 |
, int* ITER, double* OBJVAL, double* USRMEM |
265 |
){ |
266 |
/* Standard Status routine. Write to all files */ |
267 |
CONSOLE_DEBUG("CONOPT has finished Optimizing"); |
268 |
CONSOLE_DEBUG("Model status = %8d", *MODSTA); |
269 |
CONSOLE_DEBUG("Solver status = %8d", *SOLSTA); |
270 |
CONSOLE_DEBUG("Iteration count = %8d", *ITER); |
271 |
CONSOLE_DEBUG("Objective value = %10f", *OBJVAL); |
272 |
|
273 |
const char *modsta; |
274 |
error_severity_t t = ASC_USER_SUCCESS; |
275 |
switch(*MODSTA){ |
276 |
case 1: modsta = "optimal"; break; |
277 |
case 2: modsta = "locally optimal"; break; |
278 |
case 3: t = ASC_USER_ERROR; modsta = "unbounded"; break; |
279 |
case 4: t = ASC_USER_ERROR; modsta = "infeasible"; break; |
280 |
case 5: modsta = "locally infeasible"; break; |
281 |
case 6: modsta = "intermediate infeasible"; break; |
282 |
case 7: modsta = "intermediate non-optimal"; break; |
283 |
case 12: modsta = "unknown type of error"; break; |
284 |
case 13: modsta = "error no solution"; break; |
285 |
case 15: modsta = "solved unique"; break; |
286 |
case 16: modsta = "solved"; break; |
287 |
case 17: modsta = "solved singular"; break; |
288 |
default: t = ASC_PROG_ERR; modsta = "UNKNOWN MODSTA"; |
289 |
} |
290 |
const char *solsta; |
291 |
switch(*SOLSTA){ |
292 |
case 1: solsta = "normal completion"; break; |
293 |
case 2: t = ASC_USER_NOTE; solsta = "iteration interrupted"; break; |
294 |
case 3: t = ASC_PROG_NOTE; solsta = "time limit exceeded"; break; |
295 |
case 4: t = ASC_PROG_ERR; solsta = "failed (terminated by solver)"; break; |
296 |
case 5: t = ASC_PROG_ERR; solsta = "Error evaluation limit"; break; |
297 |
case 8: t = ASC_USER_NOTE; solsta = "User interrupt"; break; |
298 |
case 9: t = ASC_PROG_ERR; solsta = "Error: setup failure"; break; |
299 |
case 10:t = ASC_PROG_ERR; solsta = "Error: solver failure"; break; |
300 |
case 11:t = ASC_PROG_ERR; solsta = "Error: internal solver error"; break; |
301 |
case 15:t = ASC_PROG_ERR; solsta = "Terminated by Quick Mode"; break; |
302 |
default: t = ASC_PROG_ERR; solsta = "UNKNOWN SOLSTA"; |
303 |
} |
304 |
|
305 |
CONSOLE_DEBUG("CONOPT %s (%d): %s (%d)", solsta, *SOLSTA, modsta, *MODSTA); |
306 |
ERROR_REPORTER_NOLINE(t,"CONOPT %s: %s", solsta, modsta); |
307 |
|
308 |
return 0; |
309 |
} |
310 |
|
311 |
int COI_CALL asc_conopt_solution( double* XVAL, double* XMAR, int* XBAS |
312 |
, int* XSTA, double* YVAL, double* YMAR, int* YBAS, int* YSTA |
313 |
, int* N, int* M, double* USRMEM |
314 |
){ |
315 |
/* Standard Solution routine */ |
316 |
int i; |
317 |
char *status[4] = {"Lower","Upper","Basic","Super"}; |
318 |
FILE *fd = stderr; |
319 |
|
320 |
fprintf(fd,"\n Variable Solution value Reduced cost Status\n\n"); |
321 |
for ( i=0; i<*N; i++ ) |
322 |
fprintf(fd,"%6d%18f%18f%10s\n", i, XVAL[i], XMAR[i], status[XBAS[i]] ); |
323 |
fprintf(fd,"\n Constrnt Activity level Marginal cost Status\n\n"); |
324 |
for ( i=0; i<*M; i++ ) |
325 |
fprintf(fd,"%6d%18f%18f%10s\n", i, YVAL[i], YMAR[i], status[YBAS[i]] ); |
326 |
|
327 |
return 0; |
328 |
} |
329 |
|
330 |
#endif /* ASC_WITH_CONOPT */ |