Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ JuMP = "1"
LazyArrays = "1, 2"
MathOptInterface = "1.18"
MathOptSetDistances = "0.2.9"
ParametricOptInterface = "=0.15.1"
ParametricOptInterface = "0.15.2"
julia = "1.6"
9 changes: 9 additions & 0 deletions src/ConicProgram/ConicProgram.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ function MOI.supports_constraint(
return false
end

# Disambiguate when T = Float64
function MOI.supports_constraint(
::Model,
::Type{MOI.VectorAffineFunction{Float64}},
::Type{MOI.PositiveSemidefiniteConeSquare},
)
return false
end

function MOI.set(
model::Model,
::MOI.ConstraintPrimalStart,
Expand Down
82 changes: 82 additions & 0 deletions src/bridges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,88 @@ function MOI.set(
return MOI.set(model, attr, bridge.constraint, mapped_func)
end

"""
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @blegat

_square_offset(s::MOI.AbstractSymmetricMatrixSetSquare)

Number of extra entries before the matrix in a square-form set.
Own implementation to avoid depending on the private
`MOI.Bridges.Constraint._square_offset`.
"""
_square_offset(::MOI.AbstractSymmetricMatrixSetSquare) = 0
_square_offset(::MOI.RootDetConeSquare) = 1
_square_offset(::MOI.LogDetConeSquare) = 2

function _square_to_triangle_indices(
bridge::MOI.Bridges.Constraint.SquareBridge,
)
s = bridge.square_set
dim = MOI.side_dimension(s)
offset = _square_offset(s)
upper_triangle_indices = collect(1:offset)
sizehint!(upper_triangle_indices, offset + div(dim * (dim + 1), 2))
k = offset
for j in 1:dim
for i in 1:j
k += 1
push!(upper_triangle_indices, k)
end
k += dim - j
end
return upper_triangle_indices
end

"""
_triangle_to_square_scalars(tri_scalars, s)

Expand triangle-vectorized scalars to square column-major form, mirroring
off-diagonal entries. `s` is the square set (e.g. `PositiveSemidefiniteConeSquare`).
"""
function _triangle_to_square_scalars(tri_scalars, s)
dim = MOI.side_dimension(s)
offset = _square_offset(s)
square_dim = offset + dim * dim
square = Vector{eltype(tri_scalars)}(undef, square_dim)
for i in 1:offset
square[i] = tri_scalars[i]
end
tri_k = offset
for j in 1:dim
for i in 1:j
tri_k += 1
ij = offset + i + (j - 1) * dim
square[ij] = tri_scalars[tri_k]
if i != j
ji = offset + j + (i - 1) * dim
square[ji] = tri_scalars[tri_k]
end
end
end
return square
end

function MOI.set(
model::MOI.ModelLike,
attr::DiffOpt.ForwardConstraintFunction,
bridge::MOI.Bridges.Constraint.SquareBridge{T},
func::MOI.VectorAffineFunction{T},
) where {T}
indices = _square_to_triangle_indices(bridge)
tri_func = MOI.Utilities.eachscalar(func)[indices]
return MOI.set(model, attr, bridge.triangle, tri_func)
Copy link
Copy Markdown
Member

@blegat blegat Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ForwardConstraintFunction is set like ConstraintPrimalStart is set so you should imitate
https://github.com/jump-dev/MathOptInterface.jl/blob/b5778d01ec690e5514630ff2a2fe51ae0bd480f0/src/Bridges/Constraint/bridges/SquareBridge.jl#L328-L352
So you should also set functions to sym.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I followed very closely the MOI code

end

function MOI.get(
model::MOI.ModelLike,
attr::DiffOpt.ReverseConstraintFunction,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I followed very closely the MOI code

bridge::MOI.Bridges.Constraint.SquareBridge{T},
) where {T}
tri_func_raw = MOI.get(model, attr, bridge.triangle)
tri_func = DiffOpt.standard_form(tri_func_raw)
tri_scalars = MOI.Utilities.eachscalar(tri_func)
square_scalars = _triangle_to_square_scalars(tri_scalars, bridge.square_set)
return MOI.Utilities.operate(vcat, T, square_scalars...)
end

function _variable_to_index_map(bridge)
return Dict{MOI.VariableIndex,MOI.VariableIndex}(
v => MOI.VariableIndex(i) for
Expand Down
20 changes: 20 additions & 0 deletions src/jump_moi_overloads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# done after the model is optimized, so we add function to bypass the
# dirty state.

# DEPRECATE
function MOI.set(
model::JuMP.Model,
attr::ForwardObjectiveFunction,
Expand All @@ -37,6 +38,7 @@ function MOI.set(
return MOI.set(JuMP.backend(model), attr, allow)
end

# DEPRECATE
function MOI.set(
model::JuMP.Model,
attr::ForwardObjectiveFunction,
Expand All @@ -45,6 +47,7 @@ function MOI.set(
return MOI.set(model, attr, JuMP.AffExpr(func))
end

# DEPRECATE
function MOI.set(
model::JuMP.Model,
attr::ForwardConstraintFunction,
Expand All @@ -55,6 +58,7 @@ function MOI.set(
return MOI.set(model, attr, con_ref, JuMP.moi_function(func))
end

# DEPRECATE
function MOI.set(
model::JuMP.Model,
attr::ForwardConstraintFunction,
Expand All @@ -64,6 +68,7 @@ function MOI.set(
return MOI.set(model, attr, con_ref, JuMP.AffExpr(func))
end

# DEPRECATE - then modify
function MOI.get(
model::JuMP.Model,
attr::ForwardConstraintDual,
Expand All @@ -74,11 +79,13 @@ function MOI.get(
return JuMP.jump_function(model, moi_func)
end

# DEPRECATE - then modify
function MOI.get(model::JuMP.Model, attr::ReverseObjectiveFunction)
func = MOI.get(JuMP.backend(model), attr)
return JuMP.jump_function(model, func)
end

# DEPRECATE - then modify
function MOI.get(
model::JuMP.Model,
attr::ReverseConstraintFunction,
Expand Down Expand Up @@ -106,6 +113,7 @@ function _moi_get_result(model::MOI.Utilities.CachingOptimizer, args...)
return MOI.get(model, args...)
end

# DEPRECATE
function MOI.get(
model::JuMP.Model,
attr::ForwardVariablePrimal,
Expand All @@ -115,6 +123,7 @@ function MOI.get(
return _moi_get_result(JuMP.backend(model), attr, JuMP.index(var_ref))
end

# REVIEW
function MOI.get(
model::JuMP.Model,
attr::ReverseConstraintSet,
Expand All @@ -134,6 +143,9 @@ function MOI.set(
return MOI.set(JuMP.backend(model), attr, JuMP.index(con_ref), set)
end

# there is no set_forward_constraint_set because there is set_forward_parameter

# DEPRECATE
function MOI.set(
model::JuMP.Model,
attr::ForwardConstraintSet,
Expand Down Expand Up @@ -255,6 +267,14 @@ function JuMP.coefficient(func::IndexMappedFunction, vi::MOI.VariableIndex)
return JuMP.coefficient(func.func, func.index_map[vi])
end

function JuMP.coefficient(
func::IndexMappedFunction,
vi::MOI.VariableIndex,
output_index::Int,
)
return JuMP.coefficient(func.func, func.index_map[vi], output_index)
end

function quad_sym_half(
func::IndexMappedFunction,
vi1::MOI.VariableIndex,
Expand Down
Loading
Loading