Multiple Variable Types in JuMP Extensions

With JuMP 0.21 I was wondering what the might be the recommended way to extend it to allow for mixed variable types? In other words, I am trying to figure out which functions I should extend to permit this behavior. For example, let’s suppose I have the variable reference types MyVariableRef1 <: MyAbstractVariableRef and MyVariableRef2 <: MyAbstractVariableRef, where MyAbstractVariableRef <: JuMP.AbstractVariableRef. Natively, JuMP will support building expressions that only contain one of these 2 reference types, thus some sort of extension is necessary to permit expressions containing both. These extensions would invoke some sort of conversion rule that would ensure the expression struct uses MyAbstractVariableRef (e.g., GenericAffExpr{Float64, MyAbstractVaribableRef}) when necessary and use the explicit types otherwise.

With JuMP 0.20 I accomplished this by extending Base.:+, Base.:-, and Base.:* as needed for the possible operations and that did the trick. However, now the dependence on MutableAirthmetics.jl and the associated changes to parsing macro expressions has made this approach not work entirely.

In particular, I am hoping it might be possible to do this without extending all of the add_to_expression! methods, but rather invoke the conversion rule prior to calling the appropriate add_to_expression! method. Perhaps by extending _MA.mutable_operate!.

What are you trying to do with your JuMP extension?

The process of building a JuMP extension is not well documented, and there might be a better way to do what you intend.

The extension I am writing is InfiniteOpt.jl. Which is designed as a general modeling interface for infinite dimensional optimization problems (e.g., dynamic, stochastic, etc.). It employs InfiniteModel <: JuMP.AbstractModel that uses multiple variable types such as infinite variables, point variables, and hold variables which are used to form constraints. These each have their own variable references with a certain hierarchy to keep track if constraints are infinite or not. This hierarchical information is then used to efficiently dispatch methods to ultimately discretize and solve the model. The documentation describes everything in detail (especially on the expressions page).

Previously, I tried implementing a single variable reference type that stored the variable type as an attribute (thus negating this thread), but this led to severe performance degradation since the hierarchical type information was lost and each expression had to be searched to determine what variable types it contained.

Interesting! I’ll take a look. We should probably continue the discussion as an issue in that repo.

You should come to JuMP-dev: https://jump.dev/meetings/louvain2020/. I think you’d benefit from the discussions and we’d be keen to hear what you’ve been up to.

Thanks for your interest. There is an existing issue here. Any suggestions are more than welcome since like you said there is very little info on how to “properly” extend JuMP.

I have a busy summer, but JuMP-dev is on my radar…

As an update to this issue, I was able to extend JuMP v0.21 to allow for mixed variable reference types following a certain inheritance hierarchy by doing the following:

  1. Implement a promoting method to return the common variable type reference between 2 references. (See https://github.com/pulsipher/InfiniteOpt.jl/blob/master/src/expressions.jl#L1-L49)
  2. Extend Base.convert to change the variable reference type of GenericAffExprs and GenericQuadExprs. (See https://github.com/pulsipher/InfiniteOpt.jl/blob/master/src/utilities.jl#L1-L30)
  3. Extend Base.:+, Base.:-, and Base.:* for operations that can involve mixed types. This enables expression definitions outside of macros. (See https://github.com/pulsipher/InfiniteOpt.jl/blob/master/src/operators.jl)
  4. Extend MutableArithmetics.mutable_operate! for the methods that can involve mixed types. This enables the definition of expressions in macros. (See https://github.com/pulsipher/InfiniteOpt.jl/blob/master/src/mutable_arithmetics.jl)

Note that I have not yet figured how to extend nonlinear expressions that involve mixed variable reference types. The above approach only works for affine and quadratic expressions.

Nonlinear expressions are treated very differently. It’s a sore point that is on our radar to correct, but is unlikely to happen pre JuMP 1.0. After releasing JuMP 1.0, we have plans for a big NLP re-write.