next up previous contents
Next: Gradient Evaluation Methods Up: Using OSInstance Methods: High Previous: Sparsity Methods   Contents

Function Evaluation Methods

There are several overloaded methods for calculating objective and constraint values. The method

double *calculateAllConstraintFunctionValues(double* x, bool new_x)
will return a double pointer to an array of constraint function values evaluated at x. If the value of x has not changed since the last function call, then newFx should be set to false and the most recent function values are returned. When using this method, with this signature, all function values are calculated in double using an OSExpressionTree object.

A second signature for the calculateAllConstraintFunctionValues is

double *calculateAllConstraintFunctionValues(double* x, double *objLambda,
    double *conLambda, bool new_x, int highestOrder)
In this signature, x is a pointer to the current primal values, objLambda is a vector of dual multipliers, conLambda is a vector of dual multipliers on the constraints, newFx is true if any components of x have changed since the last evaluation, and highestOrder is the highest order of derivative to be calculated at this iteration. The following code snippet illustrates defining a set of variable values for the example we are using and then the function call.
double* x = new double[4]; //primal variables
double* z = new double[2]; //Lagrange multipliers on constraints
double* w = new double[1]; //Lagrange multiplier on objective
x[ 0] = 1;    // primal variable 0
x[ 1] = 5;    // primal variable 1
x[ 2] = 10;   // primal variable 2
x[ 3] = 5;    // primal variable 3
z[ 0] = 2;    // Lagrange multiplier on constraint 0
z[ 1] = 1;    // Lagrange multiplier on constraint 1
w[ 0] = 1;    // Lagrange multiplier on the objective function
calculateAllConstraintFunctionValues(x, w, z,  true, 0);
When making all high level calls for function, gradient, and Hessian evaluations we pass all the primal variables in the x argument, not just the nonlinear variables. Underneath the call, the nonlinear variables are identified and used in AD function calls.

The use of the parameters newFx and highestOrder is important and requires further explanation. The parameter highestOrder is an integer variable that will take on the value 0, 1, or 2 (actually higher values if we want third derivatives etc.). The value of this variable is the highest order derivative that is required of the current iterate. For example, if a callback requires a function evaluation and highestOrder = 0 then only the function is evaluated at the current iterate. However, if highestOrder = 2 then the function call

calculateAllConstraintFunctionValues(x, w, z, true, 2)
will trigger first and second derivative evaluations in addition to the function evaluations.

In the OSInstance class code, every time a forward (forwardAD) or reverse sweep (reverseAD) is executed a private member, mFiHighestOrderEvaluated is set to the order of the sweep. For example, forwardAD(1, x) will result in mFiHighestOrderEvaluated = 1. Just knowing the value of newFx alone is not sufficient. It is also necessary to know highestOrder and compare it with mFiHighestOrderEvaluated. For example, if newFx is false, but mFiHighestOrderEvaluated = 0, and the callback requires a Hessian calculation, then it is necessary to calculate the first and second derivatives at the current iterate.

There are exactly two conditions that require a new function or derivative evaluation. A new evaluation is required if and only if

1.
The value of newFx is true

-OR-

2.
For the callback function the value of the input parameter highestOrder is strictly greater than the current value of mFiHhighestOrderEvaluated.

For an efficient implementation of AD it is important to be able to get the Lagrange multipliers and highest order derivative that is required from inside any callback - not just the Hessian evaluation callback. For example, in Ipopt, if evalFg or evalFf are called, and for the current iterate, evalFjac and evalFhess are also going to be called, then a more efficient AD implementation is possible if the Lagrange multipliers are available for evalFg and evalFf.

Currently, whenever newFx = true in the underlying AD implementation we do not retape (record into the CppAD data structure) the function. This is because we currently throw an exception if there are any logical operators involved in the AD calculations. This may change in a future implementation.

There are also similar methods for objective function evaluations. The method

double calculateFunctionValue(int idx, double* x, bool new_x);
will return the value of any constraint or objective function indexed by idx. This method works strictly with double data using an OSExpressionTree object.

There is also a public variable, bUseExpTreeForFunEval that, if set to true, will cause the method

calculateAllConstraintFunctionValues(x, objLambda,  conLambda, true, highestOrder)
to also use the OS expression tree for function evaluations when highestOrder = 0 rather than use the operator overloading in the CppAD tape.


next up previous contents
Next: Gradient Evaluation Methods Up: Using OSInstance Methods: High Previous: Sparsity Methods   Contents
Kipp Martin 2008-01-16