# External Functions in Constraints

Variable arguments

AIMMS allows you to use external functions in the constraints of a
mathematical program. To accommodate this, AIMMS makes a distinction
between function arguments of type `Parameter`

and arguments of type
`Variable`

. When a function is executed as part of an expression in an
ordinary assignment, AIMMS makes no distinction between both types of
arguments. In the context of a mathematical program, however, AIMMS will
provide the solver with the derivative information for all variable
arguments of the function, while it will not do so for parameter
arguments. The actual computation of the derivatives is explained in the
next section.

## Derivative Computation

Functions in constraints

Whenever you use external functions with variable arguments in constraints of a mathematical program, the following rules apply.

AIMMS requires that the mathematical program dependent on these constraints be declared as nonlinear.

All the actual variable arguments must correspond to formal arguments which have been locally declared as

`Variables`

.

If you fail to comply with these rules, a compiler error will result.

Providing derivatives

During the solution process of a mathematical program containing such functions, partial derivative information of the function with respect to all the variable arguments must be passed to the solver. AIMMS supports three methods to compute the derivatives of a function:

you provide the actual statements for computing the derivatives as a part of the function declaration,

AIMMS estimates the derivatives using a simple differencing scheme.

The `DerivativeCall`

attribute

In the `DerivativeCall`

attribute of an external function you can
specify the call to the DLL procedure or function, to which the
derivative computation must be relayed. The syntax of the
`DerivativeCall`

attribute is the same as that of the `BodyCall`

,
and is most conveniently completed using the wizard in the Model
Explorer.

Function value and derivative

If the nonlinear solver only needs a function value, AIMMS will simply
call the function specified in the `BodyCall`

attribute. If the
nonlinear solver requests derivative information as well, AIMMS will
only call the function specified in the `DerivativeCall`

attribute,
and require that this function compute the function value as well. By
combining these two computations in a single call, AIMMS allows you to
take advantage of any possible optimization that can be obtained in your
code from computing the function value and derivative at the same time.

The .Derivative suffix

For every function argument which is a variable, you must assign the partial derivative value(s) to the .Derivative suffix of that variable. Note that this will have an impact on the number of indices. If the result of a block-valued function is \(m\)-dimensional, the derivative information with respect to an \(n\)-dimensional variable argument will result in an \((m+n)\)-dimensional identifier holding the derivative.

Abstract example

Consider a function `f`

with an index domain \((i_1,\dots,i_m)\)
and a variable argument `x`

with index domain \((j_1,\dots,j_n)\).
Then the matrix with partial derivatives of `f`

with respect to the
argument `x`

must be provided as assignments to the suffix
\({\texttt{x.Derivative}}(i_1,\dots,i_m,j_1,\dots,j_n)\). Each
element of this identifier represents the partial derivative

Cobb-Douglas function revisited

Consider the Cobb-Douglas function discussed above. Although AIMMS is capable of computing its partial derivatives automatically, you may verify that the derivative with respect to argument \(c_i\) can also be written more compactly as follows:

Implementation in C

Consider the following `C`

function `Cobb_Douglas_Der`

which
computes the Cobb-Douglas function and, if required, also the partial
derivatives with respect to the input argument `c`

. The function
`Cobb_Douglas_No_Der`

is added to support computation of the
Cobb-Douglas function without derivatives.

```
double Cobb_Douglas_Der( int n, double *a, double *c, double *c_der ) {
int i;
double CD = 1.0 ;
for ( i = 0; i < n; i++ )
CD = CD * pow(c[i],a[i]) ;
/* Check if derivatives are needed */
if ( c_der )
for ( i = 0; i < n; i++ )
c_der[i] = CD * a[i] / c[i] ;
return CD;
}
double Cobb_Douglas_No_Der( int n, double *a, double *c ) {
return Cobb_Douglas_Der( n, a, c, NULL );
}
```

Always skip unwanted derivatives

Note that in the above example the derivative computation is skipped
whenever the pointer `c_der`

is null. You should *always* check for
this condition when implementing a derivative computation, because AIMMS
will pass a null pointer (and hence reserve no memory for storing the
derivative) whenever the corresponding actual argument is not a variable
but a parameter.

…in `FORTRAN`

code

When an internal function makes a call to a `FORTRAN`

procedure to
compute derivative values, then it is not so easy to discover the
presence of null pointer argument. To overcome this, you can call your
`FORTRAN`

procedure from within a wrapper function written in `C`

,
and provide your `FORTRAN`

code with the information whether or not
derivatives need to be computed for a particular variable argument via
an additional argument to your `FORTRAN`

routine.

Passing derivative arguments

To pass the partial derivatives computed in the external procedure back
to AIMMS, the argument list of the external procedure called in the
`Derivative`

attribute of the internal function should contain
arguments for the .Derivative suffices of all variable arguments.
AIMMS will implicitly consider such derivative arguments as `Output`

arguments. They can be passed either as a full array or as an integer
`handle`

. In the latter case AIMMS API functions have to be used to
pass back the relevant partial derivatives (see also The AIMMS Programming Interface).

Example continued

The following external function declaration provides an interface to the above Cobb-Douglas function with derivative computations, which is ready to be used both inside and outside the context of constraints.

```
ExternalFunction CobbDouglasPlusDerivative {
Arguments : (a,c);
Range : nonnegative;
DLLName : "Userfunc.dll";
ReturnValue : double;
BodyCall : Cobb_Douglas_No_Der( card : InputFactors, array: a, array: c );
DerivativeCall : {
Cobb_Douglas_Der( card : InputFactors, array: a,
array: c, array: c.Derivative );
}
}
```

Numerical differencing

When the `DerivativeCall`

attribute to compute the derivatives of an
external function has not been specified, AIMMS employs a simple
differencing scheme to estimate the derivatives. For example, if AIMMS
requires the derivative of a function \(f(x_1, x_2,\ldots, x_k)\) at
the point \((\bar x_1, \bar x_2, \ldots, \bar x_k)\), then AIMMS
will approximate each partial derivative as follows:

where \(\varepsilon\) is the current value of the global option
`Differencing_Delta`

.

Disadvantages of numerical differencing

While the numerical differencing scheme does not require any action from the user, there are two distinct disadvantages.

First of all, numerical differencing is not always a stable process, and the results may not be accurate enough. As a result, a nonlinear solver may have trouble converging to a solution.

Secondly, the process can be computationally very expensive.

In general, it is recommended that you do not rely on numerical differencing. This is especially the case when the function body is quite extensive, or when the function, at the individual level, has a lot of variable arguments or contains conditional loops.