Declaration of External Procedures and Functions
External procedures and functions
External procedures and functions are special types of nodes in the
model tree. They have the same attributes as internal procedures and
functions with the exception of the Body
and Derivative
attributes, which are replaced by the attributes in
this table.
Attribute |
Value-type |
See also page |
---|---|---|
|
string, file-identifier |
|
|
|
|
|
|
|
|
external-call |
|
|
external-call |
The DllName
attribute
With the mandatory DllName
attribute you can specify the name of the
DLL which contains the external procedure or function to which you want
to make a link in your AIMMS application. The value of the attribute
must be a string, a string parameter, or a File
identifier,
representing the path to the external DLL.
Search path
If you only specify a DLL name, AIMMS will search for the DLL in all
directories in the AIMMSUSERDLL
environment variable, and the
PATH
environment variable on Windows, or the LD_LIBRARY_PATH
environment variables on Linux, respectively. In addition, on Windows,
AIMMS will also search for the DLL in the project folder. If you specify
a relative path including a folder (possibly ./), AIMMS will take this
path relative to the project folder. If you specify an absolute path,
AIMMS will try to open the DLL at the specified location.
File
identifier and unit conventions
When you use a File
identifier to specify an external DLL name,
AIMMS will use the Convention
attribute of that File
identifier
(if specified) to pass numeric values to any procedure or function in
that DLL according to the specified unit convention (see also
Globally Overriding Units Through Conventions). When the DLL name has not been specified
through a File
identifier, or when its Convention
attribute is
left empty, AIMMS will use the unit convention specified for the main
model.
Default argument scaling
Without any such convention, AIMMS will use the default convention, i.e. arguments will be scaled according to the unit specified for each argument, and AIMMS will assume that the result of an external function is scaled according to the unit specified in its Unit attribute. Unit analysis for functions and procedures is discussed in full detail in Unit Analysis of Procedures and Functions.
The ReturnType
attribute
The ReturnType
indicates the type of any scalar numerical value
returned by the DLL function. The possible values are integer
and
double
. AIMMS will use the value returned by the DLL function either
as the return value of the ExternalProcedure
, or as the (numerical)
function value of the ExternalFunction
, whichever is applicable. If
you do not specify the ReturnType
attribute, AIMMS will discard any
value returned by the function.
Restricted use
You cannot directly use the returned value of a DLL function as the
function value of an ExternalFunction
when its return value is
either an indexed parameter, a set, a set element or a string. In such
cases you must pass the function name as an additional external argument
to the DLL function, and specify how the function value must be dealt
with.
Example
Consider a C
function Cobb_Douglas_Arg
with prototype
void Cobb_Douglas_Arg( int n, double *a, double *c, double *CDValue );
which passes the Cobb-Douglas function value through the argument
CDValue
instead of as the return value. In this example CDValue
is a scalar, which could have been passed as the result of the DLL
function as well. The following ExternalFunction
declaration
provides a link with Cobb_Douglas_Arg
and obtains its function value
via the argument list.
ExternalFunction CobbDouglasArgument {
Arguments : (a,c);
Range : nonnegative;
DllName : "Userfunc.dll";
BodyCall : {
Cobb_Douglas_Arg( card : InputFactors, array: a, array: c,
scalar: CobbDouglasArgument );
}
}
The Property
attribute
With the Property
attribute you can specify through the
FortranConventions
property whether the external function is based
on FORTRAN
calling conventions. By default, AIMMS will assume that
the DLL function is written in a C
-like languages such as C
, ++
or PASCAL
. The precise differences between both calling conventions
are explained in full detail in C Versus FORTRAN conventions. In addition,
for external procedures, you can specify the UndoSafe
property. The
semantics of the UndoSafe
property is discussed in
Internal Procedures.
Formal argument types
As with internal procedures and functions, all formal arguments of an external procedure or function must be declared as local identifiers. AIMMS supports the following identifier types for formal arguments of external procedures and functions:
simple sets and relations,
scalar and indexed
Parameters
,scalar and indexed
Variables
(external functions only), andHandles
(external procedures only).
Argument handling
Many details regarding the handling of arguments of internal procedures and functions also apply to external procedures and functions. Thus, arguments of external procedures and functions can be defined over global and local sets, and their associated units of measurement can be specified in terms of either global units or locally defined unit parameters, completely similar to internal procedures and functions (see Internal Procedures).
Handle
arguments
The Handle
identifier type is only supported for formal arguments of
external procedures, i.e. it is not possible to declare global
identifiers of type Handle
. The following rules apply:
Handle
arguments are always declared as scalar local identifiers,Handle
arguments can only be passed to the DLL function as an integerHandle
(see below), andthe actual argument in a call to the external procedure corresponding to a formal
Handle
argument can be a (sliced) reference to an identifier in your model of any type and of any dimension.
Handle
arguments allow you to completely circumvent any type
checking on actual arguments with respect to the dimension and the
respective index domains of the corresponding formal arguments in the
call to an external procedure. As a result of this, however, the actual
data transfer of Handle
arguments to the DLL function must
completely take place via the AIMMS API (see also The AIMMS Programming Interface).
Note
Unfortunately, in AIMMS versions lower than 4.90, in terms of compilation it did not matter whether you specified an argument as a Handle
or as a real typed argument, like, for example, a two-dimensional string parameter. In other words: because of the ‘handle’ in the actual body call, the argument itself implicitly acted as being of type Handle
. So, you did not get any type errors during compilation.
In AIMMS 4.90 you now get a warning when the actual passed-in argument to a procedure does not match the type or dimension of the argument declaration. However, compilation and execution will continue as it did in earlier versions.
It is recommended to have a look at these warnings and try to fix them. The easiest way is to make the argument a Handle
as well but perhaps you can make the argument really match and thus make the call more type safe. In a future version of AIMMS these warnings will be treated as errors and then you are forced to modify the code.
If you encounter these warnings in libraries that you cannot change yourself, for example in a repository library of AIMMS itself, then please have a look whether there exists a more recent and upgraded version of that library. If not, and it is a library provided by AIMMS, please let us know.
The BodyCall
attribute
In the mandatory BodyCall
attribute you must specify the call to the
DLL procedure or function, to which the execution of the
ExternalProcedure
or Function
must be relayed. Such an external
call specifies:
the name of the DLL function or procedure that must be called, and
how the actual AIMMS arguments must be translated into arguments suitable for the DLL function or procedure.
Any external call must be specified according to the syntax below. In
the Model Explorer, you can specify all components of the BodyCall
attribute using a wizard which will guide you through most of the
necessary detail.
Syntax
external-call:
external-argument:
Mandatory translation type
The mandatory translation type indicates the type of the external argument into which the actual argument must be translated before being passed to the external procedure. The following translation types are supported.
scalar
: the actual scalar AIMMS argument is passed on as a scalar of the indicated external data type.literal
: the literal specified in the external call is passed on as a scalar of the indicated external data type, i.e. aliteral
argument does never correspond to an actual AIMMS argument, but is specified directly in theBodyCall
attribute.array
: the AIMMS argument is passed on as an array of values according to the indicated translation type and external data type. The precise manner in which the translation takes place is discussed below.card
: the cardinality of a set argument is passed on as an integer value. The set argument can be either a set passed as an actual AIMMS argument or the domain set of a multi-dimensional parameter passed as an actual argument.handle
: an integer handle to a (sliced) set or parameter argument is passed on. Within the external procedure you must use functions from the AIMMS API (see also The AIMMS Programming Interface) to obtain the dimension, domain and range associated with the handle, or to retrieve or change its data values.work
: an array of the indicated type is passed as a temporary workspace to the external procedure. The actual argument must be an integer expression and is interpreted as the size of the array to be passed on. This translation type is useful for programmers of languages such as standard F77FORTRAN
which lack facilities for dynamic memory allocation.
Actual external argument
The actual external argument specified in an external argument of the
BodyCall
attribute can be
a reference to a formal argument of the
ExternalProcedure
at hand (for thescalar
,array
,card
,handle
andwork
translation types),a reference to a domain set of a formal multi-dimensional argument of the
ExternalProcedure
at hand (for thecard
translation type), oran integer, double or string literal (such as
12345
,123.45
or"This is a string"
) directly specified within theBodyCall
attribute (for theliteral
translation type).
Input-output type
For every formal argument of an ExternalProcedure
, you can specify
its associated input-output type through the Input
, InOut
(default) or Output
properties in the Propert
attribute of the
local argument declaration. With it, you indicate whether or not AIMMS
should consider any changes made to the argument by the DLL function.
For each input-output type, AIMMS performs the following actions:
Input
: AIMMS initializes the external argument, but discards all changes made to it by the DLL function,InOut
: AIMMS initializes the external argument, and passes back to the model the values returned by the DLL function, orOutput
: AIMMS allocates memory for the external argument, but does not initialize it; the values returned by the DLL function are passed back to the model.
As with internal functions, all ExternalFunction
arguments are
Input
by definition. The return value of an ExternalProcedure
and the function value of an ExternalFunction
are considered as an
(implicit) Output
argument when passed to the DLL
function as an
external argument.
External data type
In translating AIMMS arguments into values (or arrays of values) suitable as arguments for an external procedure or function, AIMMS supports the external data types listed in this table.
External data type |
Passed as |
---|---|
|
4-byte (signed) integer |
|
8-byte double precision floating number |
|
|
|
1-byte (signed) integer |
|
2-byte (signed) integer |
|
4-byte (signed) integer |
Allowed combinations
Not all combinations of input-output types, translation types and
external data types are supported (or even useful).
this table describes all allowed
combinations, as well as the resulting argument type that is passed on
to the external procedure. The external data types printed in bold are
the default, and can be omitted if appropriate. Throughout the table,
the data type integer
can be replaced by any of the other integer
types integer8
, integer16
or integer32
.
Allowed types |
AIMMS argument |
Passed as |
||
---|---|---|---|---|
Translation |
Input-Output |
Data |
||
|
|
|
scalar expression |
integer |
double |
double |
|||
|
string |
|||
inout,
|
|
scalar reference |
integer pointer |
|
double |
double pointer |
|||
|
string |
|||
|
n/a |
|
n/a |
integer |
double |
double |
|||
|
string |
|||
|
n/a |
n/a |
set, parameter |
integer |
|
|
|
parameter |
integer array |
double |
double array |
|||
integer |
element parameter |
integer array |
||
|
set |
string array |
||
string |
string/unit parameter |
string array |
||
|
|
n/a |
set, parameter, handle |
integer |
|
n/a |
|
integer expression |
integer array |
double |
double array |
Passing array arguments
When you are passing a multidimensional AIMMS identifier to an external
procedure or function as a array
argument, AIMMS passes a
one-dimensional buffer in which all values are stored in a manner that
is compatible with the storage of multidimensional arrays in the
language which you have specified through the Property
attribute.
The precise array numbering conventions for both C
-like and
FORTRAN
arrays are explained in C Versus FORTRAN conventions.
Encoding of string arguments
The strings communicated with your DLL have an encoding. This encoding
is set by the option external_string_character_encoding
, which has a
default of UTF8
. This option can be overridden by using the
Encoding
attribute of string parameters, similar to the Encoding
attribute of a File
, see The Encoding attribute. On Windows,
using the encoding UTF-16LE
and on Linux, using the encoding
UTF-32LE
, the strings are passed as a wchar_t*
array, otherwise
the strings are passed as a char *
array.
Output string arguments
When you pass a scalar or multidimensional output string argument, AIMMS
will pass a single char
buffer of fixed length, or an array of such
buffers. The length is determined by the option external
function
string
buf
size
. The default of this option is
2048. You must use the C
function strcpy
or a similar function
to copy the string data in your DLL to the appropriate char
buffer
associated with the output string argument.
Full versus sparse data transfer
When considering your options on how to pass a high-dimensional
parameter to an external procedure, you will find that passing it as an
array is often not the best solution. Not only will the memory
requirements grow rapidly for increasing dimension, but also running
over all elements in the array inside your DLL function may turn out to
be a very time-consuming process. In such a case, it is much better
practice to pass the argument as an integer handle
, and use the
AIMMS API functions discussed in Communicating Individual Identifier Values to retrieve only
the nondefault values associated with the handle. You can then set up
your own sparse data structures to deal with high-dimensional parameters
efficiently.
Translation modifiers …
In addition to the translation types, input-output types and external data types you can specify one or more translation modifiers for each external argument. Translation modifiers allow you to slightly modify the manner in which AIMMS will pass the arguments to the DLL function. AIMMS supports translation modifiers for specifying the precise manner in which
special values,
the data associated with handles, and
set elements,
are passed.
… for special values
When a parameter or variable that you want to pass to an external DLL
contains special values like ZERO
or INF
, AIMMS will, by
default, pass ZERO
as 0.0, INF
and -INF
as
\(\pm\)1.0e150, and will not pass any of the values NA
and
UNDF
. When you specify the translation modifier retainspecials
,
AIMMS will pass all special numbers by their internal representation as
a double precision floating point number. You can use the AIMMS API
functions discussed in Communicating Individual Identifier Values to obtain the MapVal
value (see also this table) associated with each
number. The translation modifier retainspecials
can be specified for
numeric arguments that are passed either as a full array or as an
integer handle.
… for handles
When passing a multidimensional identifier handle to an external DLL, AIMMS can provide several methods of access to the data associated with the handle by specifying one of the following translation modifiers:
ordered
: the data retrieval functions will pass the data values according to the particular ordering imposed any of the domain sets of the identifier associated with the handle. By default, AIMMS will use the natural ordering determined by the data entry order of all domain sets.raw
: the data retrieval functions will also pass inactive data (see also Data Control). By default, AIMMS will not pass inactive data.
The details of ordered versus unordered and raw data transfer are discussed in full detail in Communicating Individual Identifier Values.
… for set elements
AIMMS can pass set elements (in the context of element parameters and sets) to external procedures in various manners. More specifically, set elements can be translated into:
an
integer
external data type, ora
string
external data type.
When the external data type is string
, AIMMS will pass the element
name for each set element. Transfer of element names is always input
only. In general, when the external data type is integer
, AIMMS can
pass either
the ordinal number with respect to its associated subset domain (
ordinalnumber
modifier), orthe element number with respect to its associated root set (
elementnumber
modifier).
Alternatively, when set elements are passed in the context of a set you
can specify the indicator
modifier in combination with the
integer
external data type. This will result in the transfer of a
multidimensional binary parameter which indicates whether a particular
tuple is or is not contained in the set.
Passing element parameters
When you pass an element parameter as an integer scalar
or array
argument, AIMMS will assume the ordinalnumber
modifier by default.
When passed as integer, element parameters can be input, output or inout
arguments. When element parameters are passed as string arguments, they
can be input only.
When to use
Element numbers and ordinal numbers each can have their use within an DLL function. Element numbers remain identical throughout a modeling session using a single data set, regardless of addition and deletion of set elements, or any change in set ordering. For this reason, it is best to use element numbers when the set elements need to be used in multiple calls of the DLL function. Ordinal numbers, on the other hand, are the most convenient means for passing permutations that are used within the current external call only. With it, you can directly access a permuted reference in other array arguments.
Passing set arguments
Sets can be passed as array
arguments to an external DLL function.
When passing set arguments, you have to make a distinction between
one-dimensional root sets, one-dimensional subsets (both either simple
or relation), and multidimensional subsets and indexed sets. The
following rules apply.
Pass as onedimensional array
One-dimensional root sets and subsets can be passed as a one-dimensional array of length equal to the cardinality of the set. To accomplish this, you can must pass such a set as
an array of
integer
numbers, representing either the ordinal or element numbers of each element in the set (using theordinalnumber
orelementnumber
modifier), ora
string
array, representing the names of all elements in the set.
One-dimensional set arguments passed in this manner can only be input arguments. As a specific consequence, you cannot modify the contents of root sets passed as array arguments.
Pass as indicator parameter
You can pass any subset (whether it is simple, relation or indexed) as a
multidimensional integer indicator
array defined over its respective
domain sets, indicating whether a particular tuple of domain set
elements is contained in the subset (value equals 1) or not (value
equals 0). The dimension of such indicator parameters is given by the
following set of rules:
the dimension for a simple subset is 1,
the dimension for a multidimensional relation is the dimension of the Cartesian product of which the set is a subset,
the dimension of an indexed set is the dimension of the index domain of the set plus 1.
Set arguments passed as an indicator
argument can be of input,
output, or inout type. In the latter two cases modifications to the 0-1
values of the indicator parameter are translated back into the
corresponding element memberships of the subset.
Set argument defaults
When you pass set arguments to an external DLL, AIMMS will assume no
default translation methods when the set is passed as an integer
array, as each type of set does not allow every translation method. For
integer set arguments you should therefore always specify one of the
translation modifiers ordinalnumber
, elementnumber
or
indicator
.
Passing set handles
Sets can also be passed by an integer handle. AIMMS offers various API functions (see also Obtaining Identifier Attributes) to obtain information about the domain of the set, its cardinality and elements, and to add or remove elements to the set.