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