Internal Procedures
AIMMS and internal procedures
Internal procedures are pieces of execution code to perform a dedicated task. For most tasks, and particularly large ones, it is strongly recommended that you use procedures to break your task into smaller, purpose-specific tasks. This provides code structure which is easier to maintain and run. Often it is appropriate to write procedures to obtain input data from users, databases and files, to execute data consistency checks, to perform side computations, to solve a mathematical program, and to create selected reports. Procedures can be called both inside the model text and inside the graphical user interface.
Declaration and attributes
Procedures are added by inserting a special type of node in the model
tree. The attributes of a Procedure
specify its arguments and
execution code. All possible attributes of a Procedure
node are
given in this table.
Attribute |
Value-type |
See also page |
---|---|---|
|
argument-list |
|
|
|
|
|
list of comma-separated runtime libraries prefices |
|
|
statements |
|
|
comment string |
Formal arguments
The arguments of a procedure are given as a parenthesized, comma-separated list of formal argument names. These argument names are only the formal identifier names without reference to their index domains. AIMMS allows formal arguments of the following types:
simple sets and relations, and
scalar and indexed parameters (either element-valued, string-valued or numerical).
The type and dimension of every formal argument is not part of the argument list, and must be specified as part of the argument’s (mandatory) local declaration in a declaration subnode of the procedure.
Interactive support
When you add new formal arguments to a procedure in the AIMMS Model
Explorer, AIMMS provides support to automatically add these arguments as
local identifiers to the procedure. For all formal arguments which have
not yet been declared as local identifiers, AIMMS will pop up a dialog
box to let you choose from all supported identifier types. After
finishing the dialog box, all new arguments will be added as (scalar)
local identifiers of the indicated type. When an argument is indexed,
you still need to add the proper IndexDomain
manually in the
attribute form of the argument declaration.
Range checking
If the declaration of a formal argument of a procedure contains a numerical range, AIMMS will automatically perform a range check on the actual arguments based on the specified range of the formal argument.
Input or output
In the declaration of each argument you can specify its type by setting one of the properties
Input
,Output
,InOut
(default), orOptional
.
AIMMS passes the values of any Input
and InOut
arguments when
entering the procedure, and passes back the values of Output
and
InOut
arguments. For this reason an actual Input
argument can be
any expression, but actual Output
and InOut
arguments must be
parameter references or set references.
Optional arguments
An argument can be made optional by setting the property Optional
in
its declaration. Optional arguments are always input, and must be
scalar. When an optional argument is not provided in a procedure call,
AIMMS will pass its default value as specified in its declaration.
The Body
attribute
In the Body
attribute you can specify the sequence of AIMMS
execution statements that you want to be executed when the procedure is
run. All statements in the body of a procedure are executed in their
order of appearance.
Example
The following example illustrates the declaration of a simple procedure in AIMMS. The body of the procedure has only been outlined.
Procedure ComputeShortestDistance {
Arguments : (City, DistanceMatrix, Distance);
Comment : {
"This procedure computes the distance along the shortest path
from City to any other city j, given DistanceMatrix."
Body: {
Distance(j) := DistanceMatrix(City,j);
for ( j | not Distance(j) ) do
/*
* Compute the shortest path and the corresponding distance
* for cities j without a direct connection to City.
*/
endfor
}
}
The procedure ComputeShortestDistance
has three formal arguments,
which must be declared in a declaration subnode of the procedure. Their
declarations within this subnode could be as follows.
ElementParameter City {
Range : Cities;
Property : Input;
}
Parameter DistanceMatrix {
IndexDomain : (i,j);
Property : Input;
}
Parameter Distance {
IndexDomain : j;
Property : Output;
}
From these declarations (and not from the argument list itself) AIMMS can deduce that
the first actual (input) argument in a call to
ComputeShortestDistance
must be an element of the (global) setCities
,the second (input) argument must be a two-dimensional parameter over
Cities
\({}\times{}\)Cities
, andthe third (output) arguments must be a one-dimensional parameter over
Cities
.
Arguments declared over global sets
As in the example above, arguments of procedures can be indexed identifiers declared over global sets. An advantage is that no local sets need to be defined. A disadvantage is that the corresponding procedure is not generic. Procedures with arguments declared over global sets are preferred when the procedure is uniquely designed for the application at hand, and direct references to global sets add to the overall understandability and maintainability.
Arguments declared over local sets
The index domain or range of a procedure argument need not always be defined in terms of global sets. Also sets that are declared locally within the procedure can be used as index domain or range of that procedure. When a procedure with such arguments is called, AIMMS will examine the actual arguments, and pass the global domain set to the local set identifier by reference. This allows you to implement procedures performing generic functionality for which a priori knowledge of the index domain or range of the arguments is not relevant.
Local sets are read-only
When you pass arguments defined over local sets, AIMMS does not allow you to modify the contents of these local sets during the execution of the procedure. Because such local sets are passed by reference, this will prevent you from inadvertently modifying the contents of the global domain sets. When you do want to modify the contents of the global domain sets, you should pass these sets as explicit arguments as well.
Unit analysis of arguments
Whenever your model contains one or more Quantity
declarations (see
The Quantity Declaration), AIMMS allows you to associate units of
measurements with every argument. Similarly as the index domains of
multidimensional arguments can be expressed either in terms of global
sets, or in terms of local sets that are determined at runtime, the
units of measurements of function and procedure arguments can also be
expressed either in terms of globally defined units, or in terms of
local unit parameters that are determined runtime by AIMMS. The unit
analysis of procedure arguments is discussed in full detail in
Unit Analysis of Procedures and Functions.
Local identifiers
Besides the arguments, you can also declare other local scalar or indexed identifiers in a declaration subnode of a procedure or function in AIMMS. Local identifiers cannot have a definition, and their scope is limited to the procedure or function itself.
The property RetainsValue
For each local identifier of a procedure or function that is not a
formal argument, you can specify the option RetainsValue
. With it
you can indicate that such a local identifier must retain its last
assigned value between successive calls to that procedure or function.
You can use this feature, for instance, to retain local data that must
be initialized once and can be used during every subsequent call to the
procedure, or to keep track of the number of calls to a procedure.
Top-down implementation
By partitioning the body of a long procedure into several execution subnodes, you can effectively implement the procedure in a self-documenting top-down approach. While the body can just contain the outermost structure of the procedure’s execution, the implementation details can be hidden behind subnode references with meaningful names.
The RETURN
statement
In some situations, you may want to return from a procedure or function
before the end of its execution has been reached. You use the RETURN
statement for this purpose. It can be subject to a conditional WHEN
clause similar to the SKIP
and BREAK
statements in loops. The
syntax follows.
Syntax
return-statement:
Return value
Procedures in AIMMS can have an (integer) return value, which you can
pass by means of the RETURN
statement. You can use the return value
only in a limited sense: you can assign it to a scalar parameter, or use
it in a logical condition in, for instance, an IF
statement. You
cannot use the return value in a compound numerical expression. For more
details, refer to Calls to Procedures and Functions.
The Property
attribute
In the Property
attribute of internal procedures you can specify a
single property, UndoSafe
. With the UndoSafe
property you can
indicate that the procedure, when called from a page within the
graphical end-user interface of a model, should leave the stack of
end-user undo actions intact. Normally, procedure calls made from within
the end-user interface will clear the undo stack, because such calls
usually make additional modifications to (global) data based on end-user
edits.
The Uses Runtime libs
attribute
This attribute is available for non-predefined procedures. It is a comma-separated list of prefices of runtime libraries, identifiers from which are used in the procedure. For more information please refer to the section Runtime Libraries and the Model Edit Functions and in particular rubric Access to Runtime Identifiers in non-runtime Procedures
Procedures summarized
The following list summarizes the main characteristics of AIMMS procedures.
The arguments of a procedure can be sets, set elements and parameters.
The arguments, together with their attributes, must be declared in a local declaration subnode.
The domain and range of indexed arguments can be in terms of either global or local sets.
Each argument is of type
Input
,Output
,Optional
orInOut
(default).Optional arguments must be scalar, and you must specify a default value. Optional arguments are always of type
Input
.AIMMS performs range checking on the actual arguments at runtime, based on the specified range of the formal arguments.