1 |
/* |
2 |
ASCEND modelling environment |
3 |
Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly, Kirk Andre Abbott |
4 |
Copyright (C) 2006 Benjamin Allan |
5 |
Copyright (C) 2006 Carnegie Mellon University |
6 |
|
7 |
This program is free software; you can redistribute it and/or modify |
8 |
it under the terms of the GNU General Public License as published by |
9 |
the Free Software Foundation; either version 2, or (at your option) |
10 |
any later version. |
11 |
|
12 |
This program is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
16 |
|
17 |
You should have received a copy of the GNU General Public License |
18 |
along with this program; if not, write to the Free Software |
19 |
Foundation, Inc., 59 Temple Place - Suite 330, |
20 |
Boston, MA 02111-1307, USA. |
21 |
*//** |
22 |
@file |
23 |
External Functions Module. |
24 |
|
25 |
This module implements the ExternalFunc structure referenced by the |
26 |
ExtCallNode structure, and allows syntax for black box and glass box |
27 |
relations to be implemented, as well as external method calls. |
28 |
|
29 |
The ExternalFunc structure stores the number of input and output parameters |
30 |
as well as 'help' string and 'name' string' for each of these 'calls'. |
31 |
|
32 |
This header also provides functions for ExternalFunc library maintenance. |
33 |
This allows ASCEND to maintain a list of the ExternalFunc requests derived |
34 |
from statements in the model(s). When compilation completes, I suppose |
35 |
it should be possible to alert the user about any external functions |
36 |
that were not able to be resolved. |
37 |
|
38 |
@todo Complete documentation of compiler/extfunc.h. |
39 |
|
40 |
Requires: |
41 |
#include "utilities/ascConfig.h" |
42 |
#include "compiler/instance_enum.h" |
43 |
#include "general/list.h" |
44 |
#include "compiler/compiler.h" |
45 |
*//* |
46 |
by Kirk Andre Abbott and Ben Allan |
47 |
Created: July 4, 1994. |
48 |
Version: $Revision: 1.5 $ |
49 |
Version control file: $RCSfile: extfunc.h,v $ |
50 |
Date last modified: $Date: 1997/07/18 12:29:30 $ |
51 |
Last modified by: $Author: mthomas $ |
52 |
*/ |
53 |
|
54 |
#ifndef ASC_EXTFUNC_H |
55 |
#define ASC_EXTFUNC_H |
56 |
|
57 |
#include <utilities/ascConfig.h> |
58 |
#include "relation_util.h" |
59 |
|
60 |
/*------------------------------------------------------------------------------ |
61 |
type definitions and forward decls |
62 |
*/ |
63 |
|
64 |
/** |
65 |
ExtEvalFunc type is a function pointer. It's only being used in the |
66 |
GlassBox stuff at this stage I think -- JP |
67 |
|
68 |
@see rootfind.c:51 |
69 |
|
70 |
@param mode 'to pass to the eval function' (?) |
71 |
@param m relation index |
72 |
@param n variable index |
73 |
@param x 'x' vector (?) |
74 |
@param u 'u' vector (?) |
75 |
@param f vector of residuals |
76 |
@param g vector of gradients |
77 |
*/ |
78 |
typedef int ExtEvalFunc(int *mode, int *m, int *n, |
79 |
double *x, double *u, double *f, double *g); |
80 |
|
81 |
/** |
82 |
This is an enum to clarify and make type-safer the |
83 |
the variation of external functions circa 1995. |
84 |
Blackboxes might be callable from methods as well (@TODO), but |
85 |
this is dependent on their code registration to setup. |
86 |
*/ |
87 |
enum ExternalFuncType { |
88 |
efunc_ERR = 0, /**< err value (Traps old mode errors too) */ |
89 |
efunc_BlackBox = 10, /**< remainder of struct is blackbox */ |
90 |
efunc_GlassBox = 20, /**< remainder of struct is glassbox */ |
91 |
efunc_Method = 30 /**< remainder of struct is method */ |
92 |
}; |
93 |
|
94 |
struct GlassBoxExternalFunc { |
95 |
ExtEvalFunc *initial; |
96 |
ExtEvalFunc **value; /**< array of relation residual functions. */ |
97 |
ExtEvalFunc **deriv; /**< array of relation gradient functions. */ |
98 |
ExtEvalFunc **deriv2; /**< array of relation hessian functions. */ |
99 |
ExtEvalFunc *final; /**< cleanup function. */ |
100 |
}; |
101 |
|
102 |
|
103 |
/** values a blackbox (or ?) can report when returning. */ |
104 |
enum Calc_status { |
105 |
calc_converged, |
106 |
calc_diverged, |
107 |
calc_fp_error, |
108 |
calc_incorrect_args, |
109 |
calc_error, |
110 |
calc_all_ok |
111 |
}; |
112 |
|
113 |
/** |
114 |
Things that a blackbox can be asked to do. |
115 |
|
116 |
@NOTE Rhetorical question: Why do we want this? See comments in Slv_Interp. |
117 |
*/ |
118 |
enum Request_type { |
119 |
bb_none, /**< do nothing. should never be sent. */ |
120 |
bb_first_call, /**< will be given when the initial function pointer is called. */ |
121 |
bb_last_call, /**< will be given when the final function pointer is called. */ |
122 |
bb_check_args, /**< do any argument checking of the variables, data */ |
123 |
bb_recalculate, /**< the caller thinks the input may have changed: recalc if reqd */ |
124 |
bb_func_eval, /**< the caller needs the residual function pointer. */ |
125 |
bb_deriv_eval, /**< the caller needs the deriv function pointer. */ |
126 |
bb_hess_eval, /**< the caller needs the hessian function pointer. */ |
127 |
bb_single_step /**< the caller would like one step toward the solution; |
128 |
usually this is meaningless and should be answered with calc_diverged. */ |
129 |
}; |
130 |
|
131 |
/** |
132 |
Each blackbox equation may show up more than once in a simulation |
133 |
if models repeat in the structure. For each occurence of the |
134 |
blackbox, a unique Slv_Interp object is given when the set of |
135 |
corresponding relations is created. |
136 |
It is used for the blackbox to communicate to the rest of the system. |
137 |
If the blackbox retains internal state between evaluation calls, |
138 |
it should store this state in the user_data pointer. |
139 |
*/ |
140 |
struct Slv_Interp { |
141 |
/** status is set by blackbox calls before returning. */ |
142 |
enum Calc_status status; |
143 |
|
144 |
/** user_data is set by the blackbox if it has any persistent state |
145 |
during calls to ExtBBoxInitFunc initial and final given in |
146 |
CreateUserFunctionBlackBox. |
147 |
*/ |
148 |
void *user_data; |
149 |
|
150 |
/** unique identifier tied to instance tree. Set by system. */ |
151 |
int nodestamp; |
152 |
|
153 |
/** What the caller wants done on a given call. |
154 |
|
155 |
As black boxes are represented with 5 function pointers, |
156 |
one might think this is not needed. Providing the 'task' here allows |
157 |
one to implement only one function and have it handle all types of |
158 |
calls. It also facilitates cases where there is checking rather than |
159 |
evaluation. |
160 |
|
161 |
@NOTE Problem? Don't init functions and evaluation functions have |
162 |
different signatures? |
163 |
*/ |
164 |
enum Request_type task; |
165 |
}; |
166 |
|
167 |
typedef int ExtBBoxInitFunc(struct Slv_Interp *, |
168 |
struct Instance *, |
169 |
struct gl_list_t *); |
170 |
|
171 |
/** |
172 |
External black box equations are of the block form |
173 |
y_out = f(x_in). This block expands to N_outputs equations |
174 |
of the form y_out[i] = f_i(x_in), where the functional details |
175 |
of f are assumed to be smooth enough but otherwise totally hidden |
176 |
and x_in, y_out are non-overlapping sets of variables. |
177 |
|
178 |
Note that solvers are not psychic; if this blackbox is embedded |
179 |
in a larger model such that some of y_out are fixed variables, |
180 |
the odds of convergence are small. Cleverer solvers may issue |
181 |
a warning. |
182 |
|
183 |
@param interp the control information is exchanged in interp; interp->task |
184 |
should be consulted. |
185 |
@param ninputs the length of the inputs, xi_in. |
186 |
@param noutputs, the length of the outputs, y_out. |
187 |
@param jacobian, the partial derivative df/dx, where |
188 |
each row is df[i]/dx[j] over each j for the y_out[i] of |
189 |
matching index. The jacobian array is 1-D, row major, i.e. |
190 |
df[i]/dx[j] -> jacobian[i*ninputs+j]. |
191 |
|
192 |
@TODO this one may need splitting/rework for hessian. |
193 |
*/ |
194 |
typedef int ExtBBoxFunc(struct Slv_Interp *interp, |
195 |
int ninputs, int noutputs, |
196 |
double *inputs, double *outputs, double *jacobian); |
197 |
|
198 |
struct BlackBoxExternalFunc { |
199 |
ExtBBoxInitFunc *initial; |
200 |
ExtBBoxFunc *value; /**< relation residual function. */ |
201 |
ExtBBoxFunc *deriv; /**< relation gradient function. */ |
202 |
ExtBBoxFunc *deriv2; /**< relation hessian function. */ |
203 |
ExtBBoxInitFunc *final; /**< cleanup function. */ |
204 |
}; |
205 |
|
206 |
|
207 |
/** |
208 |
Function pointer (type) to implement an external method on a particular |
209 |
instance |
210 |
|
211 |
@param context the instance on which the method is run. |
212 |
context may also appear explicitly in the arg list as SELF. |
213 |
@param args Each element of args is a list of instances; each |
214 |
name in the ascend-language argument list is expanded to a list |
215 |
(which may contain 0 or more Instances) and appended to args. |
216 |
*/ |
217 |
typedef int ExtMethodRun( struct Instance *context, struct gl_list_t *args); |
218 |
|
219 |
struct MethodExternalFunc { |
220 |
ExtMethodRun *run; /**< the method invoked. */ |
221 |
#if 0 /* have no use for these currently. */ |
222 |
ExtMethodInit *initial; /**< allowed to be null if not needed. */ |
223 |
ExtMethodInit *final; /**< allowed to be null if not needed. */ |
224 |
#endif |
225 |
}; |
226 |
|
227 |
struct ExternalFunc { |
228 |
enum ExternalFuncType etype; |
229 |
CONST char *name; /**< a string we own. */ |
230 |
CONST char *help; /**< a string we own. */ |
231 |
unsigned long n_inputs; /**< expected # of inputs. */ |
232 |
unsigned long n_outputs; /**< expected # of outputs. */ |
233 |
union { |
234 |
struct GlassBoxExternalFunc glass; |
235 |
struct BlackBoxExternalFunc black; |
236 |
struct MethodExternalFunc method; |
237 |
} u; |
238 |
}; |
239 |
|
240 |
/*------------------------------------------------------------------------------ |
241 |
REGISTRATION / LOOKUP FUNCTIONS |
242 |
*/ |
243 |
|
244 |
/* deleted: RetiredExternalFunc -- JP */ |
245 |
|
246 |
extern void InitExternalFuncLibrary(void); |
247 |
/**< |
248 |
The main external functions library initialization routine. This |
249 |
function must be called before all others. |
250 |
*/ |
251 |
|
252 |
extern void DestroyExtFuncLibrary(void); |
253 |
/**< |
254 |
Destroys the external function library and deallocates all the |
255 |
information associated with it. |
256 |
*/ |
257 |
|
258 |
|
259 |
extern int AddExternalFunc(struct ExternalFunc *efunc, int force); |
260 |
/**< |
261 |
Adds an external function node to the external function library. |
262 |
We look up the external function before adding it to the |
263 |
library. If force is zero and the function exists then nothing |
264 |
is done and 0 is returned. If force is true, then the old entry is |
265 |
removed and the new one is added; 1 is returned. If the name is not |
266 |
found then the information is added to the library. |
267 |
|
268 |
@return 1 if an element is added to ExternalFunctionLibrary Table, |
269 |
or 0 if no addition is made. |
270 |
*/ |
271 |
|
272 |
extern struct ExternalFunc *LookupExtFunc(CONST char *funcname); |
273 |
/**< |
274 |
Returns the external function having the given name, or NULL if |
275 |
not found. |
276 |
*/ |
277 |
|
278 |
|
279 |
extern struct ExternalFunc *RemoveExternalFunc(char *name); |
280 |
/**< |
281 |
Removes the external function having the given name from the |
282 |
External function library. |
283 |
*/ |
284 |
|
285 |
extern void DestroyExternalFunc(struct ExternalFunc *name); |
286 |
/**< |
287 |
Destroys an external function, but does *not* remove it from the |
288 |
library. Use the RemoveExternalFunc library first to retrieve the |
289 |
information, then call this function. |
290 |
*/ |
291 |
|
292 |
|
293 |
extern void PrintExtFuncLibrary(FILE *f); |
294 |
/**< |
295 |
Prints the contents of the external function library to the given |
296 |
file. The file must be opened for writing. |
297 |
*/ |
298 |
|
299 |
ASC_DLLSPEC(char *) WriteExtFuncLibraryString(void); |
300 |
/**< |
301 |
Returns a string of formatted information about the external functions |
302 |
defined. the string looks like "{{name1} {help1}} {{name2} {help2}} " |
303 |
The string may be empty/NULL if there are no external functions loaded. |
304 |
*/ |
305 |
|
306 |
/** |
307 |
This provides a way for other code to visit the external function list |
308 |
*/ |
309 |
ASC_DLLSPEC(void) TraverseExtFuncLibrary(void (*)(void *,void *),void *secondparam); |
310 |
|
311 |
|
312 |
/** fetch the required input count for glass, black, or method. */ |
313 |
ASC_DLLSPEC(unsigned long) NumberInputArgs(CONST struct ExternalFunc *efunc); |
314 |
/** fetch the required output count for glass, black, or method. */ |
315 |
ASC_DLLSPEC(unsigned long) NumberOutputArgs(CONST struct ExternalFunc *efunc); |
316 |
|
317 |
|
318 |
ASC_DLLSPEC(CONST char*) ExternalFuncName(CONST struct ExternalFunc *efunc); |
319 |
/**< |
320 |
Returns the name of an external function. |
321 |
*/ |
322 |
|
323 |
/*------------------------------------------------------------------------------ |
324 |
EXTERNAL METHOD STUFF |
325 |
*/ |
326 |
|
327 |
/** |
328 |
Setup/teardown, if any needed, for a particular instance. |
329 |
|
330 |
We don't actually support this method anywhere right now, as |
331 |
we're not sure what it can logically be used for that the |
332 |
init function in dlopening shouldn't be doing. |
333 |
In principal, we could add and cache a client-data pointer |
334 |
in each instance so that the external method may be stateful. |
335 |
Presently, the external methods must be clever to do that |
336 |
on their own or must use ascend instances for state instead. |
337 |
@param context the instance on which the method may be run. |
338 |
*/ |
339 |
typedef int ExtMethodInit( struct Instance *context); |
340 |
|
341 |
ASC_DLLSPEC(int) CreateUserFunctionMethod(CONST char *name, |
342 |
/* ExtMethodInit *initial, */ |
343 |
ExtMethodRun *run, |
344 |
/* ExtMethodInit *final, */ |
345 |
CONST long n_args, |
346 |
CONST char *help); |
347 |
/**< |
348 |
* Adds an external method call to the ASCEND system. |
349 |
* The name of the function is looked up. If it already exists, the |
350 |
* information will be updated. If the name was not found in the |
351 |
* external function library, then an external function node will be |
352 |
* created and added to the external function library. We make a |
353 |
* *copy* of the help string if it is provided. We also make a copy |
354 |
* of the name. Anyone desirous of ASCEND knowing about their |
355 |
* external methods must use this protocol. |
356 |
* |
357 |
* @param name Name of the function being added (or updated). |
358 |
* @param initial Pointer to initialisation function, or NULL if none. |
359 |
* @param run Pointer to the method. |
360 |
* @param final Pointer to cleanup function, or NULL if none. |
361 |
* @param n_args number of arguments expected as input, or -1 if any number is allowed. |
362 |
* @return Returns 0 if the function was successfully added, |
363 |
* non-zero otherwise. |
364 |
*/ |
365 |
|
366 |
/** Fetch method run function. */ |
367 |
extern ExtMethodRun *GetExtMethodRun(struct ExternalFunc *efunc); |
368 |
|
369 |
/*------------------------------------------------------------------------------ |
370 |
BLACK BOX STUFF |
371 |
*/ |
372 |
|
373 |
/** Fetch black initialization function. */ |
374 |
extern ExtBBoxInitFunc *GetInitFunc(struct ExternalFunc *efunc); |
375 |
/** Fetch black residual function. */ |
376 |
extern ExtBBoxFunc *GetValueFunc(struct ExternalFunc *efunc); |
377 |
/** Fetch black sensitivity gradient function. */ |
378 |
extern ExtBBoxFunc *GetDerivFunc(struct ExternalFunc *efunc); |
379 |
/** Fetch black hessian function. */ |
380 |
extern ExtBBoxFunc *GetDeriv2Func(struct ExternalFunc *efunc); |
381 |
/** Fetch black cleanup function. */ |
382 |
extern ExtBBoxInitFunc *GetFinalFunc(struct ExternalFunc *efunc); |
383 |
|
384 |
|
385 |
ASC_DLLSPEC(int) CreateUserFunctionBlackBox(CONST char *name, |
386 |
ExtBBoxInitFunc *init, |
387 |
ExtBBoxFunc *value, |
388 |
ExtBBoxFunc *deriv, |
389 |
ExtBBoxFunc *deriv2, |
390 |
ExtBBoxInitFunc *final, |
391 |
CONST unsigned long n_inputs, CONST unsigned long n_outputs, |
392 |
CONST char *help |
393 |
); |
394 |
/**< |
395 |
Adds an external function to the ASCEND system. |
396 |
The name of the function is looked up. If it already exists, the |
397 |
information will be updated. If the name was not found in the |
398 |
external function library, then an external function node will be |
399 |
created and added to the external function library. We make a |
400 |
*copy* of the help string if it is provided. We also make a copy |
401 |
of the name. Anyone desirous of ASCEND knowing about their |
402 |
functions must use this protocol. |
403 |
|
404 |
Note: most blackboxes |
405 |
|
406 |
@param name Name of the function being added (or updated). |
407 |
@param init Pointer to initialisation function, or NULL if none. |
408 |
@param final Pointer to shutdown function. May be same as init. |
409 |
@param value evaluation function pointers, or NULL if none. |
410 |
@param deriv first partial derivative functions, or NULL if none. |
411 |
@param deriv2 second derivative functions, or NULL if none. |
412 |
@return Returns 0 if the function was successfully added, |
413 |
non-zero otherwise. |
414 |
*/ |
415 |
|
416 |
|
417 |
/** |
418 |
Evaluate blackbox relation. |
419 |
*/ |
420 |
double blackbox_evaluate_residual(struct relation *r); |
421 |
|
422 |
/*----------------------------------------------------------------------------- |
423 |
GLASS BOX STUFF |
424 |
*/ |
425 |
|
426 |
ASC_DLLSPEC(int) CreateUserFunctionGlassBox(CONST char *name, |
427 |
ExtEvalFunc *init, |
428 |
ExtEvalFunc **value, |
429 |
ExtEvalFunc **deriv, |
430 |
ExtEvalFunc **deriv2, |
431 |
ExtEvalFunc *final, |
432 |
CONST unsigned long n_inputs, CONST unsigned long n_outputs, |
433 |
CONST char *help |
434 |
); |
435 |
/**< |
436 |
Adds an external function to the ASCEND system. |
437 |
The name of the function is looked up. If it already exists, the |
438 |
information will be updated. If the name was not found in the |
439 |
external function library, then an external function node will be |
440 |
created and added to the external function library. We make a |
441 |
*copy* of the help string if it is provided. We also make a copy |
442 |
of the name. Anyone desirous of ASCEND knowing about their |
443 |
functions must use this protocol. |
444 |
|
445 |
@param name Name of the function being added (or updated). |
446 |
@param init Pointer to initialisation function, or NULL if none. |
447 |
@param value array of evaluation function pointers, |
448 |
or NULL if none. |
449 |
@param deriv array of first partial |
450 |
derivative functions, or NULL if none. |
451 |
@param deriv2 array of second derivative |
452 |
functions, or NULL if none. |
453 |
@return Returns 0 if the function was successfully added, |
454 |
non-zero otherwise. |
455 |
*/ |
456 |
|
457 |
/** Fetch glass initialization function. */ |
458 |
extern ExtEvalFunc *GetGlassBoxInit(struct ExternalFunc *efunc); |
459 |
/** Get glass box residual function array. */ |
460 |
extern ExtEvalFunc **GetValueJumpTable(struct ExternalFunc *efunc); |
461 |
/** Get glass box gradient function array. */ |
462 |
extern ExtEvalFunc **GetDerivJumpTable(struct ExternalFunc *efunc); |
463 |
/** Get glass box hessian function array. */ |
464 |
extern ExtEvalFunc **GetDeriv2JumpTable(struct ExternalFunc *efunc); |
465 |
/** Fetch black initialization function. */ |
466 |
extern ExtEvalFunc *GetGlassBoxFinal(struct ExternalFunc *efunc); |
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
#endif /* ASC_EXTFUNC_H */ |