User functions
In this example, the most complicated function is the area calculation, and it is not a problem to model it explicitly as a formula. However, there are cases when it is not possible to do so, or when it is undesirable to do so – for example, when the formula is very large or contains conditional evaluations, or when it is simply easier to write it as an iterative calculation (in a do-loop) rather than explicitly. This section of the User Guide shows how to extend the Polygon model to calculate the area using a "user function".
A user function is essentially a function which is not built in to Xpress NonLinear. It can be written in a language such as C, and compiled into a DLL; it can be written as a set of formulae in an Excel spreadsheet (with or without a macro as well); it can be written entirely within an Excel macro. This example shows the area function written as an Excel macro.
A user function in an Excel macro
This is a function written as an Excel macro, in the sheet Sheet1 of the Excel workbook C:\xpressmp\examples\slp\spreadsheet\Polygon.xls.
Function Area(Values() As Variant, nArgs() As Variant) As Double n = nArgs(0) i = 3 Total = 0 For Count = 1 To n Rho1 = Values(i - 3) Theta1 = Values(i - 2) Rho2 = Values(i - 1) Theta2 = Values(i) Total = Total + 0.5 * Rho1 * Rho2 * Sin(Theta2 - Theta1) i = i + 2 If i > n Then Exit For Next Count Area = Total End Function
It takes two arguments, both arrays of type Variant (a general-purpose type which can contain any type of data). It returns a single value of type Double.
This calculates the area for a polygon with any number of sides, by iterating through all the adjacent triangles. The array Values contains pairs of items in the order RHO1, THETA1, RHO2, THETA2, etc. The first loop calculates the area between (RHO2,THETA2) and (RHO1,THETA1). Subsequent loops then add the area of the next triangle.
Notice that all the arrays which communicate with Xpress NonLinear count from zero.
In this example, we are calculating only one value, and so there is only one item to return. A more complicated function might calculate and return more than one value (for example, the circumference and the area). In such a case, the function must return an array of type Double, as in the abbreviated example below:
Dim DArray(1) As Double Function ArrayArea(Values() As Variant, nArgs() As Variant) As Double() ... DArray(0) = Total DArray(1) = Circum Area = DArray End Function
Extending the polygon model
The model needs to be modified slightly in order to use the new function. There are two parts – using the function in the model; and declaring the function and explaining how the interface works.
To use the function in the model, we give it a name – say "PolyArea". We can then use it like any other function.
PolyArea ( RHO1 , THETA1 , RHO2 , THETA2 , RHO3 , THETA3 , RHO4 , THETA4 )
The arguments RHO1 up to THETA4 are in the order that the function expects.
If the function returns an array, then we have to specify which item in the array is the one we want. In our case, there is only one value, and it is the first. The formula for the area would then become:
PolyArea ( RHO1 , THETA1 , RHO2 , THETA2 , RHO3 , THETA3 , RHO4 , THETA4 : 1 )
The colon (":") indicates that the next item specifies which array value is required. The number "1" indicates the first item.
The OBJEQ constraint will now have only two items – the OBJX entry and the new PolyArea function, which will be a coefficient of the special equals column. The relevant piece of the MPS file is:
OBJX OBJEQ -1 = OBJEQ = PolyArea ( RHO1 , THETA1 , RHO2 , THETA2 , RHO3 , THETA3 , RHO4 , THETA4 )
The function declaration is made in the SLPDATA section, using a record of type UF. There are several fields which can be used, but not all of them are necessary in this case.
UF PolyArea = Area ( VARIANT , VARIANT ) XLF = C:\Xpress...\Polygon.xls = Sheet1
The fields we have are as follows:
UF | indicates this is a user function declaration. |
PolyArea | the name of the function as used within the model. |
Area | the name of the function as used in the spreadsheet. If it is the same as that used in the model, it can be omitted (in which case the "=" sign is omitted as well). |
VARIANT | the arguments in brackets indicate the number and type of the arguments. For Excel macros, the type is always VARIANT, and the first two arguments are the array of values and the number of items in the array. |
XLF | indicates an Excel macro function (as opposed to spreadsheet formulae or a DLL). |
C:\Xpress.. | the name of the spreadsheet containing the macro (we've had to abbreviate the full path to fit on the page – the full name is in the file in the examples. |
Sheet1 | the name of the sheet containing the macro. |
Notice that the declaration does not itself say whether the function returns an array or a single item. Xpress NonLinear deduces this from the form of the function reference itself (whether or not there is a return item number).
The model can now be run using the Excel macro to calculate the values instead of using a formula inside the model itself.