NLPModelsJuMP.jl icon indicating copy to clipboard operation
NLPModelsJuMP.jl copied to clipboard

Add documentation about the order of variables and constraints

Open tmigot opened this issue 2 years ago • 4 comments
trafficstars

compare to JuMP.all_variables

tmigot avatar Feb 02 '23 15:02 tmigot

It would be useful to be able to get vectors of ConstrainRef/VariableRef in the order they appear in the Jacobian. I'm currently using the following code for this:

import JuMP
import MathOptInterface as MOI
import NLPModelsJuMP

_shape(::MOI.VariableIndex) = JuMP.ScalarShape()
_shape(::MOI.ScalarAffineFunction) = JuMP.ScalarShape()
_shape(::MOI.ScalarQuadraticFunction) = JuMP.ScalarShape()
_shape(::MOI.ScalarNonlinearFunction) = JuMP.ScalarShape()
_shape(::MOI.VectorAffineFunction) = JuMP.VectorShape()
_shape(::MOI.VectorQuadraticFunction) = JuMP.VectorShape()
_shape(::MOI.VectorNonlinearFunction) = JuMP.VectorShape()

function get_var_con_order(
    model::JuMP.Model
)::Tuple{Vector{JuMP.VariableRef}, Vector{JuMP.ConstraintRef}}
    moimodel = JuMP.backend(model)
    var_indices, con_indices = get_var_con_order(moimodel)
    vars = [JuMP.VariableRef(model, i) for i in var_indices]
    cons = Vector{JuMP.ConstraintRef}()
    for idx in con_indices
        fcn = MOI.get(moimodel, MOI.ConstraintFunction(), idx)
        con = JuMP.ConstraintRef(model, idx, _shape(fcn))
        push!(cons, con)
    end
    return vars, cons
end

function get_con_indices(model::MOI.ModelLike)
    linear = Vector{MOI.ConstraintIndex}()
    quadratic = Vector{MOI.ConstraintIndex}()
    nonlinear = Vector{MOI.ConstraintIndex}()
    contypes = MOI.get(model, MOI.ListOfConstraintTypesPresent())
    for (F, S) in contypes
        if F == MOI.VariableIndex
            continue
        end
        indices = MOI.get(model, MOI.ListOfConstraintIndices{F,S}())
        for idx in indices
            fcn = MOI.get(model, MOI.ConstraintFunction(), idx)
            if fcn isa MOI.ScalarAffineFunction || fcn isa MOI.VectorAffineFunction
                push!(linear, idx)
            elseif fcn isa MOI.ScalarQuadraticFunction || fcn isa MOI.VectorQuadraticFunction
                push!(quadratic, idx)
            elseif fcn isa MOI.ScalarNonlinearFunction
                push!(nonlinear, idx)
            else
                error("Unsupported constraint function $F")
            end
        end
    end
    return (; linear, quadratic, nonlinear)
end

function get_var_con_order(
    model::MOI.ModelLike
)::Tuple{Vector{MOI.VariableIndex}, Vector{MOI.ConstraintIndex}}
    var_indices = MOI.get(model, MOI.ListOfVariableIndices())
    con_indices = get_con_indices(model)
    con_indices = vcat(con_indices...)
    return var_indices, con_indices
end

It would be nice if something like this was part of the package.

Robbybp avatar Apr 17 '25 16:04 Robbybp

@Robbybp If you do a PR, I can include it in the package if you want.

amontoison avatar Apr 17 '25 16:04 amontoison

What would be the difference compared to


function get_var_con_order(
    model::JuMP.Model
)::Tuple{Vector{JuMP.VariableRef}, Vector{JuMP.ConstraintRef}}
    return JuMP.all_variables(model), JuMP.all_constraints(model, include_variable_in_set_constraints = true)
end

blegat avatar Apr 18 '25 09:04 blegat

I don't really know, I just tried to reproduce what this package does to put the variables/constraints in order for the NLPModel. Does all_variables(model) have the same order as get(backend(model), ListOfVariableIndices())? Assuming so, I guess the only difference would be that NLPModelsJuMP orders constraints as (linear, quadratic, nonlinear). (Although maybe all_constraints does this too...)

Robbybp avatar Apr 18 '25 16:04 Robbybp