Initializing help system before first use

xpress.user

Purpose

Creates an expression that is computed by means of a user-specified function. The user function can be defined to either provide or not provide the value of all derivatives w.r.t. the variables.


Synopsis

def f(a1, a2, ..., an[, *deltas]):

[...]

a = xpress.user(f, t1, t2, ..., tn)


Arguments
User function; must be a Python function with as many (possibly optional) arguments as specified in the declaration.
t1,...,tn 
Arguments of the user function.
derivatives 
"never" 
f does not return derivatives;
"always" 
f always returns derivatives;
"ondemand" 
f returns derivatives when they are requested by the solver (see notes below).
Example
The following code shows how to define user functions and use them in an optimization problem:
import math

def mynorm(*v):
  return math.sqrt(sum(e**2 for e in v))

def weighted_sum(t1, t2, t3):
  return (2*t1 + 3*t2 + 4*t1*t3,
  2 + 4*t3, 3, 4*t1)

def ondemand_derivatives(t1, t2, *deltas):
  val = 2*t1 + 4*t1*t2
  if not deltas:
    # No derivatives needed
    return val
  else:
    # Calculate whichever derivatives are needed
    d1, d2 = deltas
    return (val,
      2 + 4*t2 if d1 != 0 else None,
      4*t1 if d2 != 0 else None)

x = [xp.var() for i in range(20)]

f1 = xp.user(mynorm, *x)
f2 = xp.user(weighted_sum, x[4], x[5], x[6], derivatives="always")
f3 = xp.user(ondemand_derivatives, x[0], x[1], derivatives="ondemand")

p = xp.problem()

p.addVariable(x)
p.addConstraint(f3 >= 4)
p.addConstraint(f2 == 1)
p.setObjective(f1)
p.optimize()
print('solution:', p.getSolution(x))
Further information
1. User functions must produce a Float, as the behaviour is otherwise undefined. If the derivatives parameter is set to "never" (the default), then the function should simply return the function value. If derivatives="always", the function must return a tuple consisting of the function value and the derivatives of the function w.r.t. all variables in the list of arguments. If derivatives="ondemand", the function will either be called with numArgs arguments, or with 2 * numArgs arguments, depending on whether derivatives are required by the solver. When derivatives are not required, only the input values will be passed to the function, and the function can simply return the function value. When derivatives are required, the function will be passed the input value arguments followed by a delta argument for every input argument, and the function must return a tuple, as when derivatives="always". Note that for this reason, the delta arguments must be declared as optional, either by providing default values, or by using variable-length arguments syntax ( *deltas). The function only needs to populate the tuple with a derivative where the corresponding delta argument is nonzero. (Where the delta argument is zero, the function should provide some placeholder value such as None or zero.) The delta 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).
2. The variables on which the function is defined cannot be passed as lists or numpy arrays. Lists of variables can be passed by unpacking the list: xpress.user(lambda *y: sum(y), *list_of_vars) Note that in this case the wrapped function must be variadic.
Related topics

© 2001-2022 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.