japseow
japseow

Reputation: 203

Pyomo function that returns a default value whenever an index error occurs

I want to make a function that returns a default value (=0) whenever I try to access an indexed variable with an invalid index. This is what I've got so far.

def SafeguardIdx(object, index_set):
    print("Guarded {} with index {}".format(object.name, index_set), index_set in object.index_set())
    return base.expr.Expr_if(IF=index_set in object.index_set(), THEN=object[index_set], ELSE=0)

This is what I'm getting:

Guarded ENDINVW_jwt with index (1, 1, 0) False
KeyError: "Error accessing indexed component: Index '(1, 1, 0)' is not valid for array component 'ENDINVW_jwt'"

Why does access the index even if the "IF=" evaluates as False?

EDIT: I'd also like to ask if my implementation of a min() function is correct:

def PyomoMin(a, b):
    return base.expr.Expr_if(IF=(a > b), THEN=(a), ELSE=(b))

Thanks in advance!

Upvotes: 0

Views: 666

Answers (2)

japseow
japseow

Reputation: 203

I found a working solution for the original post.

def SafeIdx(item, *index_set, default=0):
    return item[index_set] if index_set in item.index_set() else default

Upvotes: 0

jsiirola
jsiirola

Reputation: 2634

What you want doesn't really make sense. The Expr_if construct adds a 3-argument node into the expression graph. That is, to define the expression, the IF, the THEN, and the ELSE clauses must all be valid Pyomo expressions. If the expression can be evaluated when you are generating the model (e.g., an index doesn't exist), then you shouldn't use Expr_if. The SafeguardIdx can be implemented with a simple python if.

As for implementing min(), your implementation

def PyomoMin(a, b):
    return base.expr.Expr_if(IF=(a > b), THEN=(a), ELSE=(b))

Actually implements a max(). If you want min(), you would need to either reverse the comparison or specify THEN=b, ELSE=a. That said, this is generally not the recommended way to implement a min(). There are several problems with this formulation (see also Constraints involving max in a linear program?):

  1. Expr_if is only available through the NL interface (so you cannot send it to the LP/MIP solvers).
  2. min() is not smooth (which most NL solvers require), so the NL solver may have convergence problems (especially if the solution is near where a == b)

There are alternatives to formulating the min, but they all involve adding additional variables / constraints and the "best" depends on the rest of you model. The simplest is to introduce an extra variable (e.g., minab) and then constraint it to be less than a and b. If objective pressure is trying to maximize minab, then you are OK. However, if the objective wants to minimize minab, then your problem could become unbounded or return a nonsensical answer. In this case, you would need to also implement the constraint minab >= min(a,b), which is tricky. For MIPs, a common solution is to introduce a binary variable and relax the constraints, for example:

minab >= a - M*y
minab >= b - M*(1-y)

For nonlinear models you frequently want to avoid introducing binaries if your model does not already have them. There are options that can go through things like complimentarity constraints or through smooth approximations of abs().

Upvotes: 2

Related Questions