Extending JuMP @variable

Hi,

I am planning to extend JuMP @variable macro by defining a new struct to replace the VariableInfo struct defined in JuMP, the code below is following the extension page:

struct My_var <: JuMP.AbstractVariable

    bound::Vector{Real}
end


function JuMP.build_variable(
    _err::Function,
    tb::Vector{Real},
    ::Type{My_var};
    kwargs...
)
    println("Can also use $kwargs here.")
    return My_var(tb)
end

function JuMP.add_variable(
    model::JuMP.Model,
    duplicate::My_var,
    name::String,
)
    a = JuMP.add_variable(
        model,
        duplicate,
        "$(name)_a",
    )
    b = JuMP.add_variable(
        model,
        duplicate,
        "$(name)_b",
    )
    return (a, b)
end

m = JuMP.Model()
JuMP.@variable(m, x[i=1:2], variable_type = Dy_var)

In the example, the user-defined struct only has a field with the type of VariableInfo, but I want to use my own type such as the struct My_var in the above code, and in the add_variable() function I am directly putting the My_var type as the argument, since I also do not want to use JuMP.ScalarVariable shown in the example, but this error always appears:

ERROR: LoadError: `@variable(m, x[i = 1:2], variable_type = Dy_var)`: Unrecognized positional arguments: (Main.My_var,). (You may have passed it as a positional argument, or as a keyword value to `variable_type`.)

If you're trying to create a JuMP extension, you need to implement `build_variable`. Read the docstring for more details.

May I ask if I can only use fields with VariableInfo and not my own types? If not then what have I done wrong? Thank you.

Hi @shawn_T, I guess you’re following Extensions · JuMP.

Can you explain what your end goal is?

The flow is:

  • the variable_type keyword will call JuMP.build_variable(error_fn::Function, info::JuMP.VariableInfo, ::Type{MyVar}; kwargs...)
  • build_variable should return an instance that is passed to add_variable(::Model, thing, ::String)

Your code needs some changes because:

  • You must accept VariableInfo in the build_variable signature.
  • Your add_variable function recursively calls itself.

But it’ll be easier to offer advice if I know what you’re trying to achieve.

Thank you,

The thing is that I would like to use dynamic variables, which is time-dependent hence it should have different fields than in “VariableInfo” so I cannot accept this struct type, according to your advice, I think it is better to not extending this macro then.

What is your ideal API? Can you provide a small example of what you would like to have working?

Something like @variable(model, x, t) and the user could also specify the bounds of the variable x and t directly inside the macro, it is quite similar to JuMP only that the VariableInfo cannot be directly used

What is t? How would you specify the bounds?

Have you seen: GitHub - infiniteopt/InfiniteOpt.jl: An intuitive modeling interface for infinite-dimensional optimization problems.

I should have a look, you mean I can learn from the way they do the extension.

Yes, @pulsipher has extended the JuMP macros.

But InfiniteOpt also supports time-staged problems.

So far though, its not obvious to me why you need to write a JuMP extension. Can you elaborate more on your example?

1 Like