Indexing on Vectorized Constraints in JuMP

I was looking at the example for vectorized constraints in the docs (Constraints · JuMP), which creates the constraint:

@constraint(model, con, A * x .== b)

2-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
 con : x[1] + 2 x[2] = 5.0
 con : 3 x[1] + 4 x[2] = 6.0

I am curious as to why the constraint name does not get indexed (i.e., con[1], con[2]), as would be the case if indexing were used instead of the dot notation to create the constraint:

@constraint(model, con1[i=1:2], A[i,:]' * x == b[i])

2-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
 con1[1] : x[1] + 2 x[2] == 5.0
 con1[2] : 3 x[1] + 4 x[2] == 6.0

Would it make more sense to index it so that both don’t have the same name associated with it?

See set constraint names from @constraint macro · Issue #1166 · jump-dev/JuMP.jl · GitHub. You can always call set_name to change the name of each constraint if you like.

Thanks for the link. However, this may discourage users from using vectorized constraints if you can’t distinguish the name unless you set them in a separate line.

1 Like

may discourage users from using vectorized constraints if you can’t distinguish the name unless you set them in a separate line.

A few things:

  • Changing the name at this point would be a breaking change, so we won’t be doing that

  • Calling set_name is pretty trivial, but there’s more than one way to do things, so if users would prefer to use the con[i=1:n] syntax instead of vectorized, that’s perfectly okay.

    julia> @constraint(model, con, A * x .== b)
    2-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
     con : x[1] + 2 x[2] = 5.0
     con : 3 x[1] + 4 x[2] = 6.0
    
    julia> for i in 1:length(con)
               set_name(con[i], name(con[i]) * "[$i]")
           end
    
    julia> con
    2-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
     con[1] : x[1] + 2 x[2] = 5.0
     con[2] : 3 x[1] + 4 x[2] = 6.0
    
  • The answer isn’t as obvious as it seems. What would you do in this case?

julia> model = Model()
A JuMP Model
Feasibility problem with:
Variables: 0
Model mode: AUTOMATIC
CachingOptimizer state: NO_OPTIMIZER
Solver name: No optimizer attached.

julia> S = ["1", "2"]
2-element Vector{String}:
 "1"
 "2"

julia> @variable(model, x[S])
1-dimensional DenseAxisArray{VariableRef,1,...} with index sets:
    Dimension 1, ["1", "2"]
And data, a 2-element Vector{VariableRef}:
 x[1]
 x[2]

julia> @constraint(model, con, x .== 0)
1-dimensional DenseAxisArray{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape},1,...} with index sets:
    Dimension 1, ["1", "2"]
And data, a 2-element Vector{ConstraintRef{Model, MathOptInterface.ConstraintIndex{MathOptInterface.ScalarAffineFunction{Float64}, MathOptInterface.EqualTo{Float64}}, ScalarShape}}:
 con : x[1] = 0.0
 con : x[2] = 0.0

We probably shouldn’t name the constraints con[1] and con[2], but con["1"]?

1 Like

That example makes sense.

1 Like