Initializing help system before first use

User Functions

Constant Derivatives

If a user function has constant derivatives with respect to one or more of its arguments, then it is possible to arrange that Xpress NonLinear bypasses the repeated evaluation of the function when calculating numerical derivatives for such arguments. There is no benefit in using this feature if the function offers analytic derivatives.

There are two ways of providing constant derivative information to Xpress NonLinear:

  • Implicit constant derivatives.
    In this case, Xpress NonLinear will initially calculate derivatives as normal. However, if it finds for a particular argument that the "upward" numerical derivative and the "downward" numerical derivative around a point are the same within tolerances, then the derivative for the argument will be marked as constant and will not be re-evaluated. The tolerances XSLP_CDTOL_A and XSLP_CDTOL_R are used to decide constancy.
  • Interrogate for constant derivatives.
    In this case, Xpress NonLinear will call the user function in a special way for each of the arguments in turn. The user function must recognize the special nature of the call and return a value indicating whether the derivative is constant. If the derivative is constant, it will be calculated once in the usual way (numerically), and the result will be used unchanged thereafter.

If a function is marked for interrogation for constant derivatives, then Xpress NonLinear will issue a series of special calls the first time that derivatives are required. The only difference from a normal call is that the number of derivatives requested (FunctionInfo[2]) will be negative; the absolute value of this number is the number of the argument for which information is required (counting from 1). The single value returned by the function (or in the first element of the return array, depending on the type of function) is zero if the derivative is not constant, or nonzero (normally 1) if the derivative is constant.

The following simple example in C shows how interrogation might be handled:

double XPRS_CC MyUserFunc(double *InputValues, int *FunctionInfo) {
  int iArg;
  if ( (iArg=FunctionInfo[2]) < 0) { /* interrogation */
    switch (-iArg) {
    case 1: /* constant with respect to first argument */
    case 4: /* constant with respect to fourth argument */
      return 1.0; /* constant derivative */
    default:
      return 0.0; /* not constant derivative */
    }
  }

/* normal call for evaluation */
  return MyCalc(InputValues);
}

Multi-purpose functions and the dependency matrix

If a complicated function taking multiple variables as input and capable of calculating different expressions as return values is used, it can be beneficial to explicitly declare the dependency relationship between the input variables and the various return values (in other words, defining which derivatives will always be zero). Even when a function would return its own derivatives, this feature can help to reduce the number of small perturbations appearing in the matrix (see XSLP_DELTA_Z). A complicated function is called multi-purpose if it can provide a dependency matrix.

To mark a user function multi-purposed, XSLP_UFEXETYPE needs to be specified to have bit XSLP_MULTIPURPOSE defined, or the appropriate field in the MPS file must have the 'P' identifier.

A user function being marked as multi-purpose will be called in a special way during augmentation (XSLPconstruct). This call will have the number of derivatives required ("nDelta" in XSLPgetfuncinfo) set to be a negative number, signaling that the nature of the call is to retrieve the dependency matrix. Assuming a user function with n input variables, and m output values, the value of nDelta will be (n+1)*m. For each return value, there will be n+1 values expected in the following order: the first value indicates whether for that specific return value, a dependency matrix is provided or not; 0 meaning no dependency matrix, nonzero meaning a dependency matrix is supplied. The following n values indicating whether the expression depends on the corresponding input value or not.

The following simple example shows how the dependency matrix is filled out:

Consider the following user function:
 MyFunc( x, y, z : ret1 ) := x + y
 MyFunc( x, y, z : ret2 ) := z * z
The dependency matrix for MyFunc would be
 [1, 1,1,0, 1, 0,0,1]

Callbacks and user functions

Callbacks and user functions both provide mechanisms for connecting user-written functions to Xpress NonLinear. However, they have different capabilities and are not interchangeable.

A callback is called at a specific point in the SLP optimization process (for example, at the start of each SLP iteration). It has full access to all the problem data and can, in principle, change the values of any items — although not all such changes will necessarily be acted upon immediately or at all.

A user function is essentially the same as any other mathematical function, used in a formula to calculate the current value of a coefficient. The function is called when a new value is needed; for efficiency, user functions are not usually called if the value is already known (for example, when the function arguments are the same as on the previous call). Therefore, there is no guarantee that a user function will be called at any specific point in the optimization procedure or at all.

Although a user function is normally free-standing and needs no access to problem or other data apart from that which it receives through its argument list, there are facilities to allow it to access the problem and its data if required. The following limitations should be observed:

  1. The function should not make use of any variable data which is not in its list of arguments;
  2. The function should not change any of the problem data.

The reasons for these restrictions are as follows:

  1. Xpress NonLinear determines which variables are linked to a formula by examining the list of variables and arguments to functions in the formula. If a function were to access and use the value of a variable not in this list, then incorrect relationships would be established, and incorrect or incomplete derivatives would be calculated. The predicted and actual values of the coefficient would then always be open to doubt.
  2. Xpress NonLinear generally allows problem data to be changed between function calls, and also by callbacks called from within an Xpress NonLinear function. However, user functions are called at various points during the optimization and no checks are generally made to see if any problem data has changed. The effects of any such changes will therefore at best be unpredictable.

For a description of how to access the problem data from within a user function, see the section on "More complicated user functions" later in this chapter.

User function interface

In its simplest form, a user function is exactly the same as any other mathematical function: it takes a set of arguments (constants or values of variables) and returns a value as its result. In this form, which is the usual implementation, the function needs no information apart from the values of its arguments. It is possible to create more complicated functions which do use external data in some form: these are discussed at the end of this section.

Xpress NonLinear supports two basic forms of user function. The simple form of function returns a single value, and is treated in essentially the same way as a normal mathematical function. The general form of function returns an array of values and may also perform automatic differentiation.

The main difference between the simple and general form of a user function is in the way the value is returned.

  • The simple function calculates and returns one value and is declared as such (for example, double in C).
  • The general function calculates an array of values. It can either return the array itself (and is declared as such: for example, double * in C), or it can return the results in one of the function arguments, in which case the function itself returns a single (double precision) status value (and is declared as such: for example double in C).

Values are passed to and from the function in a format dependent on the type of the function and the type of the argument.

  • NULL format provides a place-holder for the argument but it is a null or empty argument which cannot be used to access or return data. This differs from the omitted argument which does not appear at all.
  • INTEGER format is used only for the Function Information array (the second argument to the function).
  • DOUBLE format is used for passing and returning all other numeric values
  • CHAR format is used for passing character information to the function (input and return variable names)
  • VARIANT format is used for user functions written in Microsoft Excel, COM. All arguments in Xpress NonLinear are then of type VARIANT, which is the same as the Variant type in COM and Excel VBA. In the function source code, the function itself is declared with all its arguments and return value(s) as Variant. VARIANT is not available for user functions called through other linkage mechanisms.

Function Declaration in Xpress NonLinear

User functions are declared through the XSLPloaduserfuncs, XSLPadduserfuncs and XSLPchguserfunc functions, or in the SLPDATA section of the Extended MPS file format in UF type records. These declarations define which of the arguments will actually be made available to the function and (by implication) whether the function can perform automatic differentiation. Simple functions and general functions are declared in the same way. Xpress NonLinear recognizes the difference because of the way in which the functions are referenced in formulae.

Function declaration in Extended MPS format

In the SLPDATA section of Extended MPS format, the full UF record format is:

UF Function [ = Extname] ( InputValues , FunctionInfo ,
InputNames , ReturnNames , Deltas , ReturnArray )
Linkage = Param1 [ [ = Param2 ] = Param3 ]

The fields are as follows:

Function
The name of the user function. This is used in the formulae within the problem. A function which returns only one value must return it as a double-precision value. A function which returns multiple values must return a double-precision array, or return the values in the ReturnArray argument. In the latter case, the function must return a single double-precision status value.
Extname
This field is optional. If it is used, then it is the external name of the function or program when it is called. If the field is omitted, then the same name is used for the internal and external function name. If the name matches the name of a character variable, then the value of the character variable will be used instead. This allows the definition of external names which contain spaces.
InputValues
DOUBLE or VARIANT or NULL. This is the data type for the input argument list. Use NULL or omit the argument if the data is not required.
FunctionInfo
INTEGER or VARIANT or NULL. This is the data type for the array of function and argument information. Use NULL or omit the argument if the data is not required. Note that this argument is required if function objects are used by the function.
InputNames
CHAR or VARIANT or NULL. This is the data type for the names of the input arguments. Use NULL or omit the argument if the data is not required.
ReturnNames
CHAR or VARIANT or NULL. This is the data type for the names of the return arguments. Use NULL or omit the argument if the data is not required.
Deltas
DOUBLE or VARIANT or NULL. This is the data type for the perturbations (or differentiation flags). Use NULL or omit the argument if the data is not required.
ReturnArray
DOUBLE or VARIANT or NULL. This is the data type for the array of results from a multi-valued function. Use NULL or omit the argument if the results are returned directly by the function.
Linkage
This defines the linkage type and calling mechanism. The following are supported:
DLL
The function is compiled in a user library or DLL. The name of the file is in the Param1 field.
XLS
The function is in an Excel workbook and communicates through a sheet within the workbook. The name of the workbook is in the Param1 field and the name of the sheet is in the Param2 field.
If Extname is non-blank, it is the name of a macro on the workbook which is to be executed after the data is loaded.
XLF
The function is in an Excel workbook and communicates directly with Xpress NonLinear. The name of the workbook is in the Param1 field and the name of the sheet containing the function is in the Param2 field.
MOSEL
This can only be used in conjunction with Xpress-Mosel. See the Xpress Mosel User Guide (Xpress NonLinear section) for more information.
COM
This is used for a function compiled into an ActiveX DLL. The PROGID (typically of the form file.class) is in the Param1 field.
Optionally, the type can be suffixed with additional characters, indicating when the function is to be re-evaluated, what sort of numerical derivatives are to be calculated and what sort of calling mechanism is to be used. The possible types for re-evaluation are:
A
Function is re-evaluated when input variables change outside strict tolerance
R
Function is re-evaluated every time that input variables change
I
Function always generates function instances.
M
Function is multi-valued.
N
Function is non-differentiable
P
Function is multi-purpose, and can provide its dependency matrix.
V
Function can be interrogated to provide some constant derivatives
W
Function may have constant derivatives, which can be deduced by the calling program
If no re-evaluation suffix is provided, then re-evaluation will be determined from the setting of XSLP_FUNCEVAL, and function instances will be generated only if the function is "complicated". See the section on "More complicated user functions" for further details.
Normally, a user function is identified as multi-valued from the context in which it is used, and so the M suffix is not required. It must be used if the user function being defined is not used directly in any formulae.
Any formulae involving a non-differentiable function will always be evaluated using numerical derivatives.
The possible types for numerical derivatives are:
1
Forward derivatives
2
Tangential derivatives (calculated from forward and backward perturbation)
The suffix for numerical derivatives is not used if the function is defined as calculating its own derivatives. If no suffix is provided, then the method of calculating derivatives will be determined from the setting of XSLP_FUNCEVAL.
The possible types for the calling mechanism are:
S
STDCALL (the default under Windows)
C
CDECL (the alternative mechanism under Windows)
The setting of the calling mechanism has no effect on platforms other than Windows.
Param1
See Linkage
Param2
See Linkage
Param3
Name of return array for MOSEL linkage

Notes:

  1. If an argument is declared as NULL, then Xpress NonLinear will provide a dummy argument of the correct type, but it will contain no useful information.
  2. Arguments can be omitted entirely. This is achieved by leaving the space for the declaration of the argument empty (for example, by having two consecutive commas). In this case, Xpress NonLinear will omit the argument altogether. Trailing empty declarations can be omitted (that is, the closing bracket can immediately follow the last required argument).
  3. COM, XLS and XLF require VARIANT types for their arguments. A declaration of any other type will be treated as VARIANT for these linkage types. VARIANT cannot be used for other linkage types.
  4. Functions which do not perform their own differentiation must declare Deltas as NULL or omit it altogether.
  5. The Extname, Param1, Param2 and Param3 fields can contain the names of character variables (defined on CV records). This form is required if the data to go in the field contains spaces. If the data does not contain spaces, the data can be provided directly in the field.

If a function has a constant derivative with respect to any of its variables, Xpress NonLinear can save some time by not repeatedly evaluating the function to obtain the same result. Provided that there are no circumstances in which the function might return values which imply derivatives identical to within about 1.0E-08 over a range of ±0.0001 or so for a derivative which is not constant, then the suffix W can be used so that Xpress NonLinear will assume that where a derivative appears to be constant within tolerances XSLP_CDTOL_A or XSLP_CDTOL_R it is actually constant and does not need further re-evaluation. If there are some derivatives which might falsely appear to be constant, then it is better to use the suffix V and write the function so that it can be interrogated for constant derivatives.

See Constant Derivatives for a detailed explanation of constant derivatives.

Examples:

UF MyLog ( DOUBLE ) DLL = MyFuncs

This declares a simple function called MyLog which only needs the input arguments. Because FunctionInfo is omitted, the number of arguments is probably fixed, or can be determined from the input argument list itself. The function is compiled as a user function in the library file MyFuncs (depending on the platform, the file may have an extension).

UF MyCalc = Simulator ( VARIANT , VARIANT ) XLS = MyTests.xls = XSLPInOut

This declares a function called MyCalc in Xpress NonLinear formulae. It is implemented as an Excel macro called Simulator in the workbook MyTests.xls. Xpress NonLinear will place the input data in sheet XSLPInOut in columns A and B; this is because only the first two arguments are declared to be in use. Xpress NonLinear will expect the results in column I of the same sheet. Note that although the arguments are respectively of type DOUBLE and INTEGER, they are both declared as VARIANT because the linkage mechanism uses only VARIANT types.

UF MyFunc = AdvancedFunction ( VARIANT , VARIANT , VARIANT , VARIANT ) XLF = MyTests.xls = XSLPFunc

This declares a function called MyFunc in Xpress NonLinear formulae. It is implemented as an Excel function on sheet XSLPFunc in the Excel workbook MyTests.xls. It will take values from and return values directly to Xpress NonLinear without using a sheet as an intermediary.

UF MyFunc = CFunc ( DOUBLE , INTEGER , CHAR , , DOUBLE , DOUBLE ) DLL = MyLib

This declares a function called MyFunc in Xpress NonLinear formulae. It is implemented as the function CFunc compiled in the user library MyLib. It takes a list of input names as the third argument, so it can identify arguments by name instead of by position. The fourth argument in the declaration is empty, meaning that the ReturnNames argument is not used. The fourth argument to the function is therefore the Deltas array of perturbations. Because Deltas is specified, the function must produce its own array of derivatives if required. It returns the array of results into the array defined by its fifth argument. The function itself will return a single status value.

Function declaration through XSLPloaduserfuncs and XSLPadduserfuncs

The method for declaring a user function is the same for XSLPloaduserfuncs and XSLPadduserfuncs. In each case the user function declaration is made using a variant of the parsed formula structure. Given the UF record described in the previous section:

UF Function = Extname ( InputValues , FunctionInfo ,
InputNames , ReturnNames , Deltas , ReturnArray )
Linkage = Param1 = Param2 = Param3

the equivalent formula sequence is:

Type Value
XSLP_STRING index of Extname in string table
XSLP_UFARGTYPE bit map representing the number and type of the arguments (see below)
XSLP_UFEXETYPE bitmap representing the linkage type, calling mechanism, derivative and evaluation options (see below)
XSLP_STRING index of Param1 in string table
XSLP_STRING index of Param2 in string table
XSLP_STRING index of Param3 in string table
XSLP_EOF 0

Notes:

  1. The value of the XSLP_UFARGTYPE token holds the information for the existence and type of each of the 6 possible arguments. Bits 0-2 represent the first argument (InputValues), bits 3-5 represent the second argument (FunctionInfo) and so on. Each 3-bit field takes one of the following values, describing the existence and type of the argument:

    0
    argument is omitted
    1
    NULL (argument is present but has no information content
    2
    INTEGER
    3
    DOUBLE
    4
    VARIANT
    6
    CHAR
  2. The value of the XSLP_UFEXETYPE token holds the linkage type, the calling mechanism, and the options for evaluation and for calculating derivatives:
    Bits 0-2

    type of linkage:

    1
    DLL (User library or DLL)
    2
    XLS (Excel spreadsheet)
    3
    XLF (Excel macro)
    5
    MOSEL
    7
    COM
    Bits 3-4

    evaluation flags:

    0
    default
    1 (Bit 3)
    re-evaluation at each SLP iteration
    2 (Bit 4)
    re-evaluation when independent variables have changed outside tolerance
    Bits 6-7
    derivative flags:
    0
    default
    1 (Bit 6)
    tangential derivatives
    2 (Bit 7)
    forward derivatives
    Bit 8
    calling mechanism:
    0
    standard
    1
    CDECL (Windows only)
    Bit 13
    set if the function multi-purposed and can provide its dependency matrix
    Bit 24
    set if the function is multi-valued
    Bit 28
    set if the function is not differentiable
    Bits 11-12
    constant derivative flags:
    0
    default: no known constant derivatives
    1 (Bit 11)
    assume that derivatives which do not change outside the tolerance are constant
    2 (Bit 12)
    interrogate function for constant derivatives
  3. The following constants are provided for setting these bits:

    Setting bit 11 XSLP_DEDUCECONSTDERIVS
    Setting bit 12 XSLP_SOMECONSTDERIVS

    See Constant Derivatives for a detailed explanation of constant derivatives.

  4. The string arguments are interpreted in the order in which they appear. Therefore, if any of the function parameters Param1 to Param3 is required, there must be entries for the internal function name and any preceding function parameters. If the fields are blank, use an XSLP_STRING token with a zero value.
  5. The name of the function itself (Function in this case) is provided through the function XSLPaddnames.

Function declaration through XSLPchguserfunc

Functions can be declared individually using XSLPchguserfunc. The function information is passed in separate variables, rather than in an array of tokens. Given the UF record described earlier in Extended MPS format:

UF Function = Extname ( InputValues , FunctionInfo ,
InputNames , ReturnNames , Deltas , ReturnArray )
Linkage = Param1 = Param2 = Param3

the equivalent declaration is:

XSLPchguserfunc(Prob, 0, Extname, &ArgType, &ExeType,
       Param1, Param2, Param3)

where: Extname, Param1, Param2 and Param3 are character strings; ArgType and ExeType are integers.

An unused character string can be represented by an empty string or a NULL argument.

ArgType and ExeType are bitmaps with the same meaning as in the previous section.

Using zero as the second argument to XSLPchguserfunc forces the creation of a new user function definition. A positive integer will change the definition of an existing user function. In that case, a NULL argument means "no change".

Function declaration through SLPDATA in Mosel

In Mosel, a user function is declared to Xpress NonLinear using the SLPDATA function which mirrors the Extended MPS format declaration for file-based definitions.

SLPDATA(UF:string, Function:string, Extname:string, ArgList:string,
        ArgType:string [,Param1:string [,Param2:string [,Param3:string] ] ] )

Arguments:

UF
string containing UF, indicating the SLPDATA type.
Function
name of the function (as used within a Func() expression)
Extname
name of the function to be used when it is called. This may be different from Function (for example, it may be decorated or have a special prefix).
ArgList
list of the argument types to the function, as described in Extended MPS format. Effectively, it is the same as the list of argument types within the brackets in an Extended MPS format declaration: for example "DOUBLE,INTEGER". The argument types must match exactly the declaration of the function in its native language.
ArgType
the function type as described in Extended MPS format.
Param1-3
optional strings giving additional parameter information as required by the particular function type. Details are in Extended MPS format.

User Function declaration in native languages

This section describes how to declare a user function in C, Fortran and so on. The general shape of the declaration is shown. Not all the possible arguments will necessarily be used by any particular function, and the actual arguments required will depend on the way the function is declared to Xpress NonLinear.

User function declaration in C

The XPRS_CC calling convention (equivalent to __stdcall under Windows) must be used for the function. For example:

type XPRS_CC MyFunc(double *InputValues, int *FunctionInfo,
                    char *InputNames, char *ReturnNames
                    double *Deltas, double *ReturnArray);

where type is double or double* depending on the nature of the function.

In C++, the function should be declared as having a standard C-style linkage. For example, with Microsoft C++ under Windows:

extern "C" type _declspec(dllexport) XPRS_CC
                    MyFunc(double *InputValues, int *FunctionInfo,
                    char *InputNames, char *ReturnNames
                    double *Deltas, double *ReturnArray);

If the function is placed in a library, the function name may need to be externalized. If the compiler adds "decoration" to the name of the function, the function may also need to be given an alias which is the original name. For example, with the Microsoft compiler, a definition file can be used, containing the following items:

EXPORTS
MyFunc=_MyFunc@12

where the name after the equals sign is the original function name preceded by an underscore and followed by the @ sign and the number of bytes in the arguments. As all arguments in Xpress NonLinear external function calls are pointers, each argument represents 4 bytes on a 32-bit platform, and 8 bytes on a 64-bit platform.

A user function can be included in the executable program which calls Xpress NonLinear. In such a case, the user function is declared as usual, but the address of the program is provided using XSLPchguserfuncaddress or XSLPsetuserfuncaddress. The same technique can also be used when the function has been loaded by the main program and, again, its address is already known.

The InputNames and ReturnNames arrays, if used, contain a sequence of character strings which are the names, each terminated by a null character.

Any argument omitted from the declaration in Xpress NonLinear will be omitted from the function call.

Any argument declared in Xpress NonLinear as of type NULL will generally be passed as a null pointer to the program.

User function declaration in Excel (spreadsheet)

A user function written in formulae in a spreadsheet does not have a declaration as such. Instead, the values of the arguments supplied are placed in the sheet named in the Xpress NonLinear declaration as follows:

Column A InputValues
Column B FunctionInfo
Column C InputNames
Column D ReturnNames
Column E Deltas

The results are returned in the same sheet as follows:

Column I Return values
Column J Derivatives w.r.t. first required variable
Column K Derivatives w.r.t. second required variable
...

An Excel macro can also be executed as part of the calculation. If one is required, its name is gives as Extname in the Xpress NonLinear declaration of the user function.

Any argument omitted from the declaration in Xpress NonLinear will be omitted from the function call.

Any argument declared in Xpress NonLinear as of type NULL or omitted from the declaration will leave an empty column.

User function declaration in VBA (Excel macro)

All arguments to VBA functions are passed as arrays of type Variant. This includes integer or double precision arrays, which are handled as Variant arrays of integers or doubles. The following style of function declaration should be used:

Function MyFunc ( InputValues() as Variant, FunctionInfo() as Variant, _
                  InputNames() as Variant, ReturnNames as Variant, _
                  Deltas as Variant(), ReturnArray as Variant()) as Variant

For compatibility with earlier versions of Xpress NonLinear, a return type of Double (or Double() for a multi-valued function) is also accepted. The return should be set to the value or to the array of values. For example:

	Dim myDouble as Double
	...
	MyFunc = myDouble
	Dim myDouble(10) as Double
	...
	MyFunc = myDouble

The return type is always Variant, regardless of whether the function returns one value or an array of values. The return should be set to the value or to the array of values as described in the VBA (Excel) section above.

All arrays are indexed from zero.

Any argument omitted from the declaration in Xpress NonLinear will be omitted from the function call.

Any argument declared in Xpress NonLinear as of type NULL will generally be passed as an empty Variant.

User function declaration in Visual Basic

All arguments to VB functions are passed as arrays of type Variant. This includes integer or double precision arrays, which are handled as Variant arrays of integers or doubles. The following style of function declaration should be used:

Public Function MyFunc ( InputValues() as Variant, FunctionInfo() as Variant,
                  InputNames() as Variant, ReturnNames as Variant, _
                  Deltas as Variant(), ReturnArray as Variant()) as Variant

The return type is always Variant, regardless of whether the function returns one value or an array of values. The return should be set to the value or to the array of values as described in the VBA (Excel) section above.

All arrays are indexed from zero.

Any argument omitted from the declaration in Xpress NonLinear will be omitted from the function call.

Any argument declared in Xpress NonLinear as of type NULL will generally be passed as an empty Variant.

User function declaration in COM

This example uses Visual Basic. All arguments to COM functions are passed as arrays of type Variant. This includes integer or double precision arrays, which are handled as Variant arrays of integers or doubles. The function must be stored in a class module, whose name will be needed to make up the PROGID for the function. The PROGID is typically of the form file.class where file is the name of the ActiveX DLL which has been created, and class is the name of the class module in which the function has been stored. If you are not sure of the name, check the registry. The following style of function declaration should be used:

Public Function MyFunc ( InputValues() as Variant, FunctionInfo() as Variant,
                  InputNames() as Variant, ReturnNames as Variant, _
                  Deltas as Variant(), ReturnArray as Variant()) as Variant

The return type is always Variant, regardless of whether the function returns one value or an array of values. The return should be set to the value or to the array of values as described in the VBA (Excel) section above.

All arrays are indexed from zero.

Any argument omitted from the declaration in Xpress NonLinear will be omitted from the function call.

Any argument declared in Xpress NonLinear as of type NULL will generally be passed as an empty Variant.

User function declaration in MOSEL

A simple function taking one or more input values and returning a single result can be declared in Mosel using the following form:

function MyFunc (InputValues:array(aRange:range) of real, Num:integer) : real

where Num will hold the number of values in the array InputValues.
The single result is placed in the reserved returned variable.

If the function returns more than one value, or calculates derivatives, then the full form of the function is used:

function MyFunc (InputValues:array(vRange:range) of real,
                 FunctionInfo:(array(fRange:range) of integer,
                 InputNames:(array(iRange:range) of string,
                 ReturnNames:(array(rRange:range) of string,
                 Deltas:(array(dRange:range) of real,
                 ReturnArray:(array(aRange:range) of real) : real

The SLPDATA declaration of the function references an array (the transfer array) which is a string array containing the names of the arrays used as arguments to the function.

The results are placed in ReturnArray and the function should return zero for success or 1 for failure.

For more details about user functions in Mosel, see the Xpress Mosel SLP Reference Manual.

Simple functions and general functions

A simple function is one which returns a single value calculated from its arguments, and does not provide derivatives. A general function returns more than one value, because it calculates an array of results, or because it calculates derivatives, or both.

Because of restrictions in the various types of linkage, not all types of function can be declared and used in all languages. Any limitations are described in the appropriate sections.

For simplicity, the functions will be described using only examples in C. Implementation in other languages follows the same rules.

Simple user functions

A simple user function returns only one value and does not calculate derivatives. It therefore does not use the ReturnNames, Deltas or ReturnArray arguments.

The full form of the declaration is:

double XPRS_CC MyFunc(double *InputValues, int *FunctionInfo,
                    char *InputNames);

FunctionInfo can be omitted if the number of arguments is not required, and access to problem information and function objects is not required.
InputNames can be omitted if the input values are identified by position and not by name (see "Programming Techniques for User Functions" below).

The function supplies its single result as the return value of the function.

There is no provision for indicating that an error has occurred, so the function must always be able to calculate a value.

General user functions returning an array of values through a reference

General user functions calculate more than one value, and the results are returned as an array. In the first form of a general function, the values are supplied by returning the address of an array which holds the values. See the notes below for restrictions on the use of this method.

The full form of the declaration is:

double * XPRS_CC MyFunc(double *InputValues, int *FunctionInfo,
                    char *InputNames, char *ReturnNames
                    double *Deltas);

FunctionInfo can be omitted if the number of arguments is not required, no derivatives are being calculated, the number of return values is fixed, and access to problem information and function objects is not required. However, it is recommended that FunctionInfo is always included.

InputNames can be omitted if the input values are identified by position and not by name (see "Programming Techniques for User Functions" below).

ReturnNames can be omitted if the return values are identified by position and not by name (see "Programming Techniques for User Functions" below).

Deltas must be omitted if no derivatives are calculated.

The function supplies the address of an array of results. This array must be available after the function has returned to its caller, and so is normally a static array. This may mean that the function cannot be called from a multi-threaded optimization, or where multiple instances of the function are required, because the single copy of the array may be overwritten by another call to the function. An alternative method is to use a function object which refers to an array specific to the thread or problem being optimized.

Deltas is an array with the same number of items as InputValues. It is used as an indication of which derivatives (if any) are required on a particular function call. If Deltas[i] is zero then a derivative for input variable i is not required and must not be returned. If Deltas[i] is nonzero then a derivative for input variable i is required and must be returned. The total number of nonzero entries in Deltas is given in FunctionInfo[2]. In particular, if it is zero, then no derivatives are required at all.

When no derivatives are calculated, the array of return values simply contains the results (in the order specified by ReturnNames if used).
When derivatives are calculated, the array contains the values and the derivatives as follows (DVi is the ith variable for which derivatives are required, which may not be the same as the ith input value):
 Result1
 Derivative of Result1 w.r.t. DV1
 Derivative of Result1 w.r.t. DV2
 ...
 Derivative of Result1 w.r.t. DVn
 Result2
 Derivative of Result2 w.r.t. DV1
 Derivative of Result2 w.r.t. DV2
 ...
 Derivative of Result2 w.r.t. DVn
 ...
 Derivative of Resultm w.r.t. DVn

It is therefore important to check whether derivatives are required and, if so, how many.

This form must be used by user functions which are called through OLE automation (VBA (Excel) and COM) because they cannot directly access the memory areas of the main program.

This form cannot be used by Fortran programs because Fortran functions can only return a single value, not an array.

This form cannot be used by Mosel programs because Mosel functions can only return a single value, not an array.

General user functions returning an array of values through an argument

General user functions calculate more than one value, and the results are returned as an array. In the second form of a general function, the values are supplied by returning the values in an array provided as an argument to the function by the calling program. See the notes below for restrictions on the use of this method.

The full form of the declaration is:

double XPRS_CC MyFunc(double *InputValues, int *FunctionInfo,
                    char *InputNames, char *ReturnNames
                    double *Deltas, double *ReturnArray);

FunctionInfo can be omitted if the number of arguments is not required, no derivatives are being calculated, the number of return values is fixed, and access to problem information and function objects is not required. However, it is recommended that FunctionInfo is always included.

InputNames can be omitted if the input values are identified by position and not by name (see "Programming Techniques for User Functions" below).

ReturnNames can be omitted if the return values are identified by position and not by name (see "Programming Techniques for User Functions" below).

Deltas must be omitted if no derivatives are calculated.

The function must supply the results in the array ReturnArray. This array is guaranteed to be large enough to hold all the values requested by the calling program. No guarantee is given that the results will be retained between function calls.

Deltas is an array with the same number of items as InputValues. It is used as an indication of which derivatives (if any) are required on a particular function call. If Deltas[i] is zero then a derivative for input variable i is not required and must not be returned. If Deltas[i] is nonzero then a derivative for input variable i is required and must be returned. The total number of nonzero entries in Deltas is given in FunctionInfo[2]. In particular, if it is zero, then no derivatives are required at all.

When no derivatives are calculated, the array of return values simply contains the results (in the order specified by ReturnNames if used).
When derivatives are calculated, the array contains the values and the derivatives as follows (DVi is the ith variable for which derivatives are required, which may not be the same as the ith input value):
 Result1
 Derivative of Result1 w.r.t. DV1
 Derivative of Result1 w.r.t. DV2
 ...
 Derivative of Result1 w.r.t. DVn
 Result2
 Derivative of Result2 w.r.t. DV1
 Derivative of Result2 w.r.t. DV2
 ...
 Derivative of Result2 w.r.t. DVn
 ...
 Derivative of Resultm w.r.t. DVn

It is therefore important to check whether derivatives are required and, if so, how many.

The return value of the function is a status code indicating whether the function has completed normally. Possible values are:

0
No errors: the function has completed normally.
1
The function has encountered an error. This will terminate the optimization.
-1
The calling function must estimate the function value from the last set of values calculated. This will cause an error if no values are available.

This form must be not used by user functions which are called through OLE automation (VBA (Excel) and COM) because they cannot directly access the memory areas (in particular ReturnArray) in the main program.

This form must be used by Fortran programs because Fortran functions can only return a single value, not an array. An array of values must therefore be returned through ReturnArray.

This form must be used by Mosel programs because Mosel functions can only return a single value, not an array. An array of values must therefore be returned through ReturnArray.

Programming Techniques for User Functions

This section is principally concerned with the programming of large or complicated user functions, perhaps taking a potentially large number of input values and calculating a large number of results. However, some of the issues raised are also applicable to simpler functions.

The first part describes in more detail some of the possible arguments to the function. The remainder of the section looks at function instances, function objects and direct calls to user functions.

FunctionInfo

The array FunctionInfo is primarily used to provide the sizes of the arrays used as arguments to the functions, and to indicate how many derivatives are required.

In particular:
FunctionInfo[0] holds the number of input values supplied
FunctionInfo[1] holds the number of return values required
FunctionInfo[2] holds the number of sets of derivatives to be calculated.

In addition, it contains problem-specific information which allows the user function to access problem data such as control parameters and attributes, matrix elements and solution values. It also holds information about function objects and function instances.

See XSLPgetfuncobject for a more detailed description.

InputNames

The function may have the potential to take a very large number of input values but in practice, within a particular problem, not all of them are used. For example, a function representing the model of a distillation unit may have input values relating to external air temperature and pressure which are not known or which cannot be controlled by the optimization. In general, therefore, these will take default values except for very specialized studies.

Although it would be possible to require that every function call had every input value specified, it would be wasteful in processing time to do so. In such cases, it is worth considering using named input variables, so that only those which are not at default values are included. The user function then picks up the input values by name, and assigns default values to the remainder. InputNames is an array of character strings which contains the names of the input variables. The order of the input values is then determined by the order in InputNames. This may be different for each instance of the function (that is, for each different formula in which it appears) and so it is necessary for the function to check the order of the input values. If function instances are used, then it may be necessary to check only when the function instance is called for the first time, provided that the order can be stored for future calls to the same instance.

ReturnNames

The function may have the potential to calculate a very large number of results but in practice, within a particular problem, not all of them are used. For example, a detailed model of a process unit might calculate yields and qualities of streams, but also internal flow rates and catalyst usage which are not required for a basic planning problem (although they are very important for detailed engineering investigations).

Although it would be possible to calculate every value and pass it back to the calling function every time, it could be wasteful in processing time to do so. In such cases, it is worth considering using named return values, so that only those which are actually required are included. The user function then identifies which values are required and only passes those values to its caller (possibly, therefore, omitting some of the calculations in the process).

ReturnNames is an array of character strings which contains the names of the return variables. The order of the values is then determined by the order in ReturnNames. This order may be different for different instances of the function (that is, for different formulae in which it is used). If the function does use named return values, it must check the order. If function instances are used for the function, then it may be necessary to check the order only when the function instance is called for the first time, if the order can be stored for subsequent use.

If the user function is being called by Xpress NonLinear to calculate values during matrix generation or optimization, the list of return values required is created dynamically and the names will appear in the order in which they are first encountered. It is possible, therefore, that changes in the structure of a problem may change the order in which the names appear.

Deltas

The Deltas array has the same dimension as InputValues and is used to indicate which of the input variables should be used to calculate derivatives. If Deltas[i] is zero, then no derivative should be returned for input variable i. If Deltas[i] is nonzero, then a derivative is required for input variable i. The value of Deltas[i] can be used as a suggested perturbation for numerical differentiation (a negative sign indicates that if a one-sided derivative is calculated, then a backward one is preferred). If derivatives are calculated analytically, or without requiring a specific perturbation, then Deltas can be interpreted simply as an array of flags indicating which derivatives are required.

Return values and ReturnArray

The ReturnArray array is provided for those user functions which return more than one value, either because they do calculate more than one result, or because they also calculate derivatives. The function must either return the address of an array which holds the values, or pass the values to the calling program through the ReturnArray array.

The total number of values returned depends on whether derivatives are being calculated. The FunctionInfo array holds details of the number of input values supplied, the number of return values required (nRet) and the number of sets derivatives required (nDeriv). The total number of values (and hence the minimum size of the array) is nRet*(nDeriv+1). Xpress NonLinear guarantees that ReturnArray will be large enough to hold the total number of values requested.

A function which calculates and returns a single value can use the ReturnArray array provided that the declarations of the function in Xpress NonLinear and in the native language both include the appropriate argument definition.

functions which use the ReturnArray array must also return a status code as their return value. Zero is the normal return value. A value of 1 or greater is an error code which will cause any formula evaluation to stop and will normally interrupt any optimization or other procedure. A value of -1 asks Xpress NonLinear to estimate the function values from the last calculation of the values and partial derivatives. This will produce an error if there is no such set of values.

Returning Derivatives

A multi-valued function which does not calculate its own derivatives will return its results as a one-dimensional array.

As already described, when derivatives are calculated as well, the order is changed, so that the required derivatives follow the value for each result. That is, the order becomes:
A,

∂A
∂X1
,
∂A
∂X2
, ...
∂A
∂Xn
B,
∂B
∂X1
,
∂B
∂X2
, ...
∂B
∂Xn
, ...
∂Z
∂Xn

ABZX1X2Xn

Not all calls to a user function necessarily require derivatives to be calculated. Check FunctionInfo for the number of derivatives required (it will be zero if only a value calculation is needed), and Deltas for the indications as to which independent variables are required to produce derivatives. Xpress NonLinear will not ask for, nor will it expect to receive, derivatives for function arguments which are actually constant in a particular problem. A function which provides uncalled-for derivatives will cause errors in subsequent calculations and may cause other unexpected side-effects if it stores values outside the expected boundaries of the return array.

Function Instances

Xpress NonLinear defines an instance of a user function to be a unique combination of function and arguments. For functions which return an array of values, the specific return argument is ignored when determining instances. Thus, given the following formulae:
 f(x) + f(y) + g(x,y : 1)
 f(y)*f(x)*g(x,y : 2)
 f(z)
the following instances are created:
f(x)
f(y)
f(z)
g(x,y)
(A function reference of the form g(x,y:n) means that g is a multi-valued function of x and y, and we want the nth return value.)

Xpress NonLinear regards as complicated any user function which returns more than one value, which uses input or return names, or which calculates its own derivatives. All complicated functions give rise to function instances, so that each function is called only once for each distinct combination of arguments.

Functions which are not regarded as complicated are normally called each time a value is required. A function of this type can still be made to generate instances by defining its ExeType as creating instances (set bit 9 when using the normal library functions, or use the "I" suffix when using file-based input through XSLPreadprob or when using SLPDATA in Mosel).

Note that conditional re-evaluation of the function is only possible if it generates function instances.

Using function instances can improve the performance of a problem, because the function is called only once for each combination of arguments, and is not re-evaluated if the values have not changed significantly. If the function is computationally intensive, the improvement can be significant.

There are reasons for not wanting to use function instances:

  • When the function is fast. It may be as fast to recalculate the value as to work out if evaluation is required.
  • When the function is discontinuous. Small changes are estimated by using derivatives. These behave badly across a discontinuity and so it is usually better to evaluate the derivative of a formula by using the whole formula, rather than to calculate it from estimates of the derivatives of each term.
  • Function instances do use more memory. Each instance holds a full copy of the last input and output values, and a full set of first-order derivatives. However, the only time when function instances are optional is when there is only one return value, so the extra space is not normally significant.

Function Objects

Normally, a user function is effectively a free-standing program: that is, it requires only its argument list in order to calculate its result(s). However, there may be circumstances where a user function requires access to additional data, as in the following examples:

  1. The function is actually a simulator which needs access to specific (named) external files. In this case, the function needs to access a list of file names (or file handles if the files have been opened externally).
  2. The function uses named input or output values and, having established the order once, needs to save the order for future calls. In this case, the function needs to use an array which is external to the function, so that it is not destroyed when the function exits.
  3. The function returns an array of results and so the array must remain accessible after the function has returned. In this case, the function needs to use an array which is external to the function, so that it is not destroyed when the function exits.
  4. The function determines whether it needs to re-evaluate its results when the values of the arguments have not changed significantly, and so it needs to keep a copy of the previous input and output values. In this case, the function needs to use an array which is external to the function, so that it is not destroyed when the function exits.
  5. The function has to perform an initialization the first time it is called. In this case, the function needs to keep a reference to indicate whether it has been called before. It may be that a single initialization is required for the function, or it may be that it has to be initialized separately for each instance.

There is a potential difference between examples (3) and (4) above. In example (3), the array is needed only because Xpress NonLinear will pick up the values when the function has returned and so the array still needs to exist. However, once the values have been obtained, the array is no longer required, and so the next call to the same function can use the same array. In example (4), the argument values are really required for each instance of the function: for example, if f(x) and f(y) are both used in formulae, where f() is a user function and x and y are distinct variables, then it only makes sense to compare input argument values for f(x) (that is, the value of x) against the previous value for x; it does not make sense to compare against the previous value for y. In this case, a separate array is needed for each function instance.

Xpress NonLinear provides three levels of user function object. These are:

  • The Global Function Object. There is only one of these for each problem, which is accessible to all user functions.
  • The User Function Object. There is one of these for each defined user function.
  • The Instance Function Object. There is one of these for each instance of a function.

The library functions XSLPsetuserfuncobject, XSLPchguserfuncobject and XSLPgetuserfuncobject can be used to set, change and retrieve the values from a program or function which has access to the Xpress NonLinear problem pointer.
The library functions XSLPsetfuncobject, XSLPchgfuncobject and XSLPgetfuncobject can be used by a user function to set, change or retrieve the Global Function Object, the User Function Object for the function, and the Instance Function Object for the instance of the function.

XSLPgetfuncobject can also be used to obtain the Xpress NonLinear and Xpress Optimizer problem pointers. These can then be used to obtain any problem data, or to execute any allowable library function from within the user function.

Example:

A function which uses input or return names is regarded as a complicated function, and will therefore generate function instances. All the calls for a particular instance have the same set of inputs in the same order. It is therefore necessary to work out the order of the names only once, as long as the information can be retained for subsequent use. Because each instance may have a different order, as well as different variables, for its inputs, the information should be retained separately for each instance.

The following example shows the use of the Instance Function Object to retain the order of input values

NOTE
 1  typedef struct tagMyStruct {
       int InputFromArg[5];
     } MyStruct;

     static char *MyNames[] = {"SUL", "RVP", "ARO", "OLE", "BEN"};
     static double Defaults[] = {0, 8, 4, 1, 0.5};

     double XPRS_CC MyUserFunc(double *InputValues, int *FunctionInfo,
                               char *InputNames) {
       MyStruct *InstanceObject;
       void *Object;
       char *NextName;

       int i, iArg, nArg;
       double Inputs[5], Results[10];

 2    XSLPgetfuncobject(FunctionInfo,XSLP_INSTANCEFUNCOBJECT,&Object);
 3    if (Object == NULL) {
         Object = calloc(1,sizeof(MyStruct));
 4       XSLPsetfuncobject(FunctionInfo,XSLP_INSTANCEFUNCOBJECT,Object);
         InstanceObject = (MyStruct *) Object;
         NextName = InputNames;
         nArg = FunctionInfo[0];
 5       for (iArg = 1;iArg<=nArg;iArg++) {
           for (i=0;i<5;i++) {
             if (strcmp(NextName,MyNames[i])) continue;
             InstanceObject->InputFromArg[i] = iArg;
             break;
           }
           NextName = &NextName[strlen(NextName)+1];
         }
       }
       InstanceObject = (MyStruct *) Object;
 6     if (InstanceObject == NULL) {
 7       XSLPgetfuncobject(FunctionInfo,XSLP_XSLPPROBLEM,&Object);
 8       XSLPsetfunctionerror(Prob);
         return(1);
       }
 9     for (i=0;i<5;i++) {
         iArg=InstanceObject->InputFromArg[i];
        if (iArg) Inputs[i] = InputValues[iArg-1];
        else Inputs[i] = Defaults[i];
       }
       MyCalc(Inputs, Results);
       .....
     }

Notes:

  1. A structure for the instance function object is defined. This is a convenient way of starting, because it is easy to expand it if more information (such as results) needs to be retained.
  2. XSLPgetfuncobject recovers the instance function object reference from the FunctionInfo data.
  3. On the first call to the function, the object is NULL.
  4. After the object has been created, its address is stored as the instance function object.
  5. The names in InputNames are in a continuous sequence, each separated from the next by a null character. This section tests each name against the ordered list of internal names. When there is a match, the correspondence is stored in the InputFromArg array. A more sophisticated version might fault erroneous or duplicate input names.
  6. If InstanceObject is NULL then the initialization must have failed in some way. Depending on the circumstances, the user function may be able to proceed, or it may have to terminate in error. We will assume that it has to terminate.
  7. XSLPgetfuncobject recovers the Xpress NonLinear problem.
  8. XSLPsetfunctionerror sets the error flag for the problem which will stop the optimization.
  9. If the initialization was successful, the correspondence in InputFromArg is now available on each call to the function, because on subsequent calls, Object is not NULL and contains the address of the object for this particular instance.

If there are different instances for this function, or if several problems are in use simultaneously, each distinct call to the function will have its own object.

A similar method can be used to set up and retain a correspondence between the calculated results and those requested by the calling program.

The User Function Object can be used in a similar way, but there is only one such object for each function (not for each instance), so it is only appropriate for saving information which does not have to be kept separate at an instance level. One particular use for the User Function Object is to provide a return array which is not destroyed after the user function returns (an alternative is to use the ReturnArray argument to the function).

Note that one or more arrays may be allocated dynamically by each function using this type of approach. It may be necessary to release the memory if the problem is destroyed before the main program terminates. There is no built-in mechanism for this, because Xpress NonLinear cannot know how the objects are structured. However, there is a specific callback (XSLPsetcbdestroy) which is called when a problem is about to be destroyed. As a simple example, if each non-null object is the address of an allocated array, and there are no other arrays that need to be freed, the following code fragment will free the memory:

int i, n;
void *Object;
XSLPgetintattrib(Prob, XSLP_UFINSTANCES, &n);
for (i=1;i<=n;i++) {
  XSLPgetuserfuncobject(Prob, -i, &Object);
  if (Object) free(Object);
  XSLPsetuserfuncobject(Prob, -i, NULL);
}

When used in the "destroy" callback, it is not necessary to set the instance function object to NULL. However, if an object is being freed at some other time, then it should be reset to NULL so that any subsequent call that requires it will not try to use an unallocated area of memory.

Calling user functions

A user function written in a particular language (such as C) can be called directly from another function written in the same language, using the normal calling mechanism. All that is required is for the calling routine to provide the arguments in the form expected by the user function.

Xpress NonLinear provides a set of functions for calling between different languages so that, for example, it is possible for a program written in Mosel to call a user function written in C. Not all combinations of language are possible. The following table shows which are available:

User function Calling program
Mosel C/Fortran VBA (Excel)
Mosel 1 3 3 3
C/Fortran 1 1 1 1
VBA (Excel macro) 2 2 2 2
Excel spreadsheet 2 2 2 2
COM 2 2 2 2

1: User functions available with full functionality
2: User functions available, but with reduced functionality
3: User functions available if Mosel model is executed from main program
X: User functions not available.

In general, those user functions which are called using OLE automation (Excel macro, Excel spreadsheet and COM) do not have the full functionality of user functions as described below, because the calling mechanism works with a copy of the data from the calling program rather than the original. Mosel user functions can only be called from problems which are created in the same Mosel model; however, because Mosel can itself be called from another program, Mosel functions may still be accessible to programs written in other languages.

XSLPcalluserfunc provides the mechanism for calling user functions. The user function is declared to Xpress NonLinear as described earlier, so that its location, linkage and arguments are defined. In this section, we shall use three example user functions, defined in Extended MPS format as follows:

UF MyRealFunc ( DOUBLE , INTEGER ) .....
UF MyArrayFunc ( DOUBLE , INTEGER ) DLLM .....
UF MyRetArrayFunc ( DOUBLE , INTEGER , , , , DOUBLE ) .....

These all take as arguments an array of input values and the FunctionInfo array. MyArrayFunc is declared as multi-valued (using the suffix M on the linkage). MyRetArrayFunc returns its results in ReturnArray; thus usually means that it is multi-valued, or calculates its own derivatives.

double Values[100];
double ReturnArray[200];
integer FunctionInfo[XSLP_FUNCINFOSIZE];
integer RealFunc, ArrayFunc, RetArrayFunc;
double ReturnValue;

The calling program has to provide its own arrays for the function calls, which must be sufficient to hold the largest amount of data required for any call. In particular, ReturnArray may need to allow space for derivatives.
FunctionInfo should always be declared as shown.

XSLPgetindex(Prob, XSLP_USERFUNCNAMES, "MyRealFunc", RealFunc);
XSLPgetindex(Prob, XSLP_USERFUNCNAMES, "MyArrayFunc", ArrayFunc);
XSLPgetindex(Prob, XSLP_USERFUNCNAMES, "MyRetArrayFunc", RetArrayFunc);

As XSLPcalluserfunc needs the function number, we get this for each function by using the function XSLPgetindex. If you are not sure of the upper- or lower-case, then use XSLP_USERFUNCNAMESNOCASE instead. If the functions are set up using library functions, the function indices can be obtained at that time.

               ...
/*... set up Values array .....*/
               ...
XSLPsetuserfuncinfo(Prob,ArgInfo,1,n,1,0,0,0);

The input data for the function call is set up. The contents of the input array Values obviously depend on the nature of the function being called, so we do not include them here. The function information array FunctionInfo must be set up. XSLPsetuserfuncinfo will fill in the array with the items shown. The arguments after FunctionInfo are:

  • CallerFlag. This is always zero when the function is called directly by Xpress NonLinear, and so if set nonzero it indicates a call from the user application; its value can be used for any purpose in the calling and called functions.
  • The number of input variables: this is the number of elements used in the input array Values.
  • The number of return values required for each calculation.
  • The number of sets of partial derivatives required.
  • The number of items in the array of input argument names.
  • The number of items in the array of return value names.

This structure actually allows more flexibility than is used when the function is called directly by Xpress NonLinear because, for example, there is no requirement for the number of input names to be the same as the number of input arguments. However, such usage is beyond the scope of this manual.

ReturnValue = XSLPcalluserfunc(Prob,RealFunc,Values,FunctionInfo,
                               NULL,NULL,NULL,NULL);

XSLPcalluserfunc calls the function using the appropriate linkage and calling mechanism. The arguments to XSLPcalluserfunc are:

  • The Xpress NonLinear problem.
  • The index of the function being called.
  • Six arguments corresponding to the six possible arguments to a user function. If the user function requires an argument, then the corresponding argument in the call must contain the appropriate data in the correct format. If the user function does not require an argument, then it can be NULL in the call (in any case, it will be omitted from the call). The FunctionInfo argument is always required for function calls using XSLPcalluserfunc.

ReturnValue will contain the single value returned by the user function.

ReturnValue = XSLPcalluserfunc(Prob,ArrayFunc,Values,FunctionInfo,
                               NULL,NULL,NULL,NULL);

This time, ReturnValue will contain the first value in the array of results returned by the function. This is because the function is multi-valued and there is nowhere for the other values to go.

Multi-valued functions must be called using the ReturnArray argument. Even if the user function itself does not recognize it, XSLPcalluserfunc does, and will transfer the results into it.

ReturnValue = XSLPcalluserfunc(Prob,ArrayFunc,Values,FunctionInfo,
                               NULL,NULL,NULL,ReturnArray);

The difference between this call and the previous one is the presence of the additional argument ReturnArray. This will be used to hold all the values returned by the function. The function will behave in exactly the same way as in the previous example, and ReturnValue will also be the same, but ReturnArray will be filled in with the values from the function.

ReturnValue = XSLPcalluserfunc(Prob,RetArrayFunc,Values,FunctionInfo,
                               NULL,NULL,NULL,ReturnArray);

As MyRetArrayFunc is defined as returning its results in an array, the ReturnArray argument is a required argument for the function anyway. In this case, ReturnValue is the value returned by the function, which indicates success (zero), failure (1) or not calculated (-1).

Function Derivatives

Xpress NonLinear normally expects to obtain a set of partial derivatives from a user function at a particular base-point and then to use them as required, depending on the evaluation settings for the various functions. If for any reason this is not appropriate, then the integer control parameter XSLP_EVALUATE can be set to 1, which will force re-evaluation every time.
A function instance is not re-evaluated if all of its arguments are unchanged.
A simple function which does not have a function instance is evaluated every time.

If XSLP_EVALUATE is not set, then it is still possible to by-pass the re-evaluation of a function if the values have not changed significantly since the last evaluation. If the input values to a function have all converged to within their strict convergence tolerance (CTOL, ATOL_A, ATOL_R), and bit 4 of XSLP_FUNCEVAL is set to 1, then the existing values and derivatives will continue to be used. At the option of the user, an individual function, or all functions, can be re-evaluated in this way or at each SLP iteration. If a function is not re-evaluated, then all the required values will be calculated from the base point and the partial derivatives; the input and return values used in making the original function calculation are unchanged.

Bits 3-5 of integer control parameter XSLP_FUNCEVAL determine the nature of function evaluations. The meaning of each bit is as follows:

Bit 3
evaluate functions whenever independent variables change.
Bit 4
evaluate functions when independent variables change outside tolerances.
Bit 5
apply evaluation mode to all functions.

Examples:

Bits 3-5 = 1 (set bit 3)
Evaluate functions whenever their input arguments (independent variables) change, unless the functions already have their own evaluation options set.
Bits 3-5 = 5 (set bits 3 and 5)
Evaluate all functions whenever their input arguments (independent variables) change.
Bits 3-5 = 6 (set bits 4 and 5)
Evaluate functions whenever input arguments (independent variables) change outside tolerance. Use existing calculation to estimate values otherwise.

Bits 6-8 of integer control parameter XSLP_FUNCEVAL determine the nature of derivative calculations. The meaning of each bit is as follows:

Bit 6
tangential derivatives.
Bit 7
forward derivatives.
Bit 8
apply evaluation mode to all functions.

Examples:

Bits 6-8 = 1 (set bit 6)
Use tangential derivatives for all functions which do not already have their own derivative options set.
Bits 6-8 = 5 (set bits 6 and 8)
Use tangential derivatives for all functions.
Bits 6-8 = 6 (set bits 7 and 8)
Use forward derivatives for all functions.

The following constants are provided for setting these bits:

Setting bit 3 XSLP_RECALC
Setting bit 4 XSLP_TOLCALC
Setting bit 5 XSLP_ALLCALCS
Setting bit 6 XSLP_2DERIVATIVE
Setting bit 7 XSLP_1DERIVATIVE
Setting bit 8 XSLP_ALLDERIVATIVES

A function can make its own determination of whether to re-evaluate. If the function has already calculated and returned a full set of values and partial derivatives, then it can request Xpress NonLinear to estimate the values required from those already provided.

The function must be defined as using the ReturnArray argument, so that the return value from the function itself is a double precision status value as follows:

0
normal return. The function has calculated the values and they are in ReturnArray.
1
error return. The function has encountered an unrecoverable error. The values in ReturnArray are ignored and the optimization will normally terminate.
-1
no calculation. Xpress NonLinear should recalculate the values from the previous results. The values in ReturnArray are ignored.

Analytic Derivatives of Instantiated User Functions not Returning their own Derivatives

When analytical derivatives are used, SLP will calculate approximated derivatives using finite differences for instantiated functions and use these values when deriving analytical derivatives. Functions returning multiple arguments will always be instantiated, otherwise functions can be forced to be instantiated on a per function basis.