From 27aa28399fa330e07605bb4f58bbc56347b26a82 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Wed, 25 Feb 2026 01:16:08 -0300 Subject: [PATCH 1/2] Fix names of cubic terms --- src/parametric_cubic_function.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/parametric_cubic_function.jl b/src/parametric_cubic_function.jl index 99578e77..24f54407 100644 --- a/src/parametric_cubic_function.jl +++ b/src/parametric_cubic_function.jl @@ -129,9 +129,9 @@ function ParametricCubicFunction(parsed::_ParsedCubicExpression{T}) where {T} end # Accessors for cubic terms by type (direct field access) -_cubic_pvv_terms(f::ParametricCubicFunction) = f.pvv -_cubic_ppv_terms(f::ParametricCubicFunction) = f.ppv -_cubic_ppp_terms(f::ParametricCubicFunction) = f.ppp +cubic_parameter_variable_variable_terms(f::ParametricCubicFunction) = f.pvv +cubic_parameter_parameter_variable_terms(f::ParametricCubicFunction) = f.ppv +cubic_parameter_parameter_parameter_terms(f::ParametricCubicFunction) = f.ppp """ _effective_param_value(model, pi::ParameterIndex) @@ -173,7 +173,7 @@ function _parametric_constant(model, f::ParametricCubicFunction{T}) where {T} end # From cubic ppp terms (all 3 indices are parameters) - for term in _cubic_ppp_terms(f) + for term in cubic_parameter_parameter_parameter_terms(f) p1 = term.index_1 p2 = term.index_2 p3 = term.index_3 @@ -210,7 +210,7 @@ function _parametric_affine_terms( end # Add contributions from ppv cubic terms - for term in _cubic_ppv_terms(f) + for term in cubic_parameter_parameter_variable_terms(f) var = term.index_3 p1_val = _effective_param_value(model, p_idx(term.index_1)) p2_val = _effective_param_value(model, p_idx(term.index_2)) @@ -235,7 +235,7 @@ function _parametric_quadratic_terms( terms_dict = copy(f.quadratic_data) # Add contributions from pvv cubic terms - for term in _cubic_pvv_terms(f) + for term in cubic_parameter_variable_variable_terms(f) p = term.index_1 first_is_greater = term.index_2.value > term.index_3.value v1 = ifelse(first_is_greater, term.index_3, term.index_2) @@ -351,7 +351,7 @@ function _delta_parametric_constant( end # From ppp cubic terms - for term in _cubic_ppp_terms(f) + for term in cubic_parameter_parameter_parameter_terms(f) pi1 = p_idx(term.index_1) pi2 = p_idx(term.index_2) pi3 = p_idx(term.index_3) @@ -411,7 +411,7 @@ function _delta_parametric_affine_terms( end # From ppv cubic terms - for term in _cubic_ppv_terms(f) + for term in cubic_parameter_parameter_variable_terms(f) var = term.index_3 pi1 = p_idx(term.index_1) pi2 = p_idx(term.index_2) @@ -449,7 +449,7 @@ function _delta_parametric_quadratic_terms( ) where {T} delta_dict = Dict{Tuple{MOI.VariableIndex,MOI.VariableIndex},T}() - for term in _cubic_pvv_terms(f) + for term in cubic_parameter_variable_variable_terms(f) p_i = p_idx(term.index_1) first_is_greater = term.index_2.value > term.index_3.value v1 = ifelse(first_is_greater, term.index_3, term.index_2) From 1af82a7201d47ead47f3a932c6eececdef22113e Mon Sep 17 00:00:00 2001 From: joaquimg Date: Thu, 26 Feb 2026 15:19:16 -0300 Subject: [PATCH 2/2] cleanup term access --- src/MOI_wrapper.jl | 30 ++++++++++++++++-------------- src/duals.jl | 24 ++++++++++++------------ src/parametric_cubic_function.jl | 15 +++++++++------ src/parametric_functions.jl | 17 ++++++++++++----- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index e54be934..5070b918 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -71,7 +71,7 @@ function _cache_multiplicative_params!( model::Optimizer{T}, f::ParametricQuadraticFunction{T}, ) where {T} - for term in f.pv + for term in quadratic_parameter_variable_terms(f) push!(model.multiplicative_parameters_pv, term.variable_1.value) end return @@ -81,7 +81,7 @@ function _cache_multiplicative_params!( model::Optimizer{T}, f::ParametricVectorQuadraticFunction{T}, ) where {T} - for term in f.pv + for term in vector_quadratic_parameter_variable_terms(f) push!( model.multiplicative_parameters_pv, term.scalar_term.variable_1.value, @@ -94,13 +94,13 @@ function _cache_multiplicative_params!( model::Optimizer{T}, f::ParametricCubicFunction{T}, ) where {T} - for term in f.pv + for term in cubic_parameter_variable_terms(f) push!(model.multiplicative_parameters_pv, term.variable_1.value) end - for term in f.pvv + for term in cubic_parameter_variable_variable_terms(f) push!(model.multiplicative_parameters_pv, term.index_1.value) end - for term in f.ppv + for term in cubic_parameter_parameter_variable_terms(f) push!(model.multiplicative_parameters_pv, term.index_1.value) push!(model.multiplicative_parameters_pv, term.index_2.value) end @@ -868,7 +868,8 @@ function _add_constraint_with_parameters_on_function( ) where {T,S} pf = ParametricAffineFunction(f) if model.constraints_interpretation == ONLY_BOUNDS - if length(pf.v) == 1 && isone(MOI.coefficient(pf.v[])) + if length(affine_variable_terms(pf)) == 1 && + isone(MOI.coefficient(affine_variable_terms(pf)[])) poi_ci = _add_vi_constraint(model, pf, set) else error( @@ -878,7 +879,8 @@ function _add_constraint_with_parameters_on_function( elseif model.constraints_interpretation == ONLY_CONSTRAINTS poi_ci = MOI.add_constraint(model, pf, set) elseif model.constraints_interpretation == BOUNDS_AND_CONSTRAINTS - if length(pf.v) == 1 && isone(MOI.coefficient(pf.v[])) + if length(affine_variable_terms(pf)) == 1 && + isone(MOI.coefficient(affine_variable_terms(pf)[])) poi_ci = _add_vi_constraint(model, pf, set) else poi_ci = MOI.add_constraint(model, pf, set) @@ -896,7 +898,7 @@ function MOI.add_constraint( _update_cache!(pf, model) inner_ci = MOI.add_constraint( model.optimizer, - MOI.ScalarAffineFunction{T}(pf.v, 0.0), + MOI.ScalarAffineFunction{T}(affine_variable_terms(pf), 0.0), _set_with_new_constant(set, pf.current_constant), ) model.last_affine_added += 1 @@ -919,7 +921,7 @@ function _add_vi_constraint( _update_cache!(pf, model) inner_ci = MOI.add_constraint( model.optimizer, - pf.v[].variable, + affine_variable_terms(pf)[].variable, _set_with_new_constant(set, pf.current_constant), ) model.last_affine_added += 1 @@ -1920,7 +1922,7 @@ function MOI.compute_conflict!(model::Optimizer) ) == MOI.NOT_IN_CONFLICT continue end - for term in pf.p + for term in affine_parameter_terms(pf) push!(model.parameters_in_conflict, term.variable) end end @@ -1936,14 +1938,14 @@ function MOI.compute_conflict!(model::Optimizer) ) == MOI.NOT_IN_CONFLICT continue end - for term in pf.p + for term in affine_parameter_terms(pf) push!(model.parameters_in_conflict, term.variable) end - for term in pf.pp + for term in quadratic_parameter_parameter_terms(pf) push!(model.parameters_in_conflict, term.variable_1) push!(model.parameters_in_conflict, term.variable_2) end - for term in pf.pv + for term in quadratic_parameter_variable_terms(pf) push!(model.parameters_in_conflict, term.variable_1) end end @@ -1959,7 +1961,7 @@ function MOI.compute_conflict!(model::Optimizer) ) == MOI.NOT_IN_CONFLICT continue end - for term in pf.p + for term in vector_affine_parameter_terms(pf) push!( model.parameters_in_conflict, term.scalar_term.variable, diff --git a/src/duals.jl b/src/duals.jl index d4600901..c70c0db8 100644 --- a/src/duals.jl +++ b/src/duals.jl @@ -71,7 +71,7 @@ function _compute_parameters_in_ci!( ci::MOI.ConstraintIndex{F,S}, ) where {F,S,T} cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci) - for term in pf.p + for term in affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.variable)] -= cons_dual * term.coefficient end @@ -84,11 +84,11 @@ function _compute_parameters_in_ci!( ci::MOI.ConstraintIndex{F,S}, ) where {F,S,T} cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci) - for term in pf.p + for term in affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.variable)] -= cons_dual * term.coefficient end - for term in pf.pp + for term in quadratic_parameter_parameter_terms(pf) mult = cons_dual * term.coefficient if term.variable_1 == term.variable_2 mult /= 2 @@ -107,7 +107,7 @@ function _compute_parameters_in_ci!( ci::MOI.ConstraintIndex{F,S}, ) where {F<:MOI.VectorAffineFunction{T},S} where {T} cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci) - for term in pf.p + for term in vector_affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.scalar_term.variable)] -= cons_dual[term.output_index] * term.scalar_term.coefficient end @@ -116,7 +116,7 @@ end function _update_duals_from_objective!(model::Optimizer{T}, pf) where {T} is_min = MOI.get(model.optimizer, MOI.ObjectiveSense()) == MOI.MIN_SENSE - for param in pf.p + for param in affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(param.variable)] += ifelse(is_min, 1, -1) * param.coefficient end @@ -130,12 +130,12 @@ function _update_duals_from_objective!( is_min = MOI.get(model.optimizer, MOI.ObjectiveSense()) == MOI.MIN_SENSE sign = ifelse(is_min, one(T), -one(T)) # p terms: ∂(c·p_i)/∂p_i = c - for term in pf.p + for term in affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.variable)] += sign * term.coefficient end # pp terms: ∂(c·p_i·p_j)/∂p_i = c·p_j - for term in pf.pp + for term in quadratic_parameter_parameter_terms(pf) mult = sign * term.coefficient if term.variable_1 == term.variable_2 mult /= 2 @@ -155,12 +155,12 @@ function _update_duals_from_objective!( is_min = MOI.get(model.optimizer, MOI.ObjectiveSense()) == MOI.MIN_SENSE sign = ifelse(is_min, one(T), -one(T)) # p terms: ∂(c·p_i)/∂p_i = c - for term in pf.p + for term in cubic_affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.variable)] += sign * term.coefficient end # pp terms: ∂(c·p_i·p_j)/∂p_i = c·p_j (diagonal: c/2·2·p_i = c·p_i) - for term in pf.pp + for term in cubic_parameter_parameter_terms(pf) mult = sign * term.coefficient if term.variable_1 == term.variable_2 mult /= 2 @@ -171,7 +171,7 @@ function _update_duals_from_objective!( mult * model.parameters[p_idx(term.variable_1)] end # ppp terms: ∂(c·p_i·p_j·p_k)/∂p_i = c·p_j·p_k - for term in pf.ppp + for term in cubic_parameter_parameter_parameter_terms(pf) coef = sign * term.coefficient p1_val = model.parameters[p_idx(term.index_1)] p2_val = model.parameters[p_idx(term.index_2)] @@ -225,11 +225,11 @@ function _compute_parameters_in_ci!( ci::MOI.ConstraintIndex{F,S}, ) where {F,S,T} cons_dual = MOI.get(model.optimizer, MOI.ConstraintDual(), ci) - for term in pf.p + for term in vector_affine_parameter_terms(pf) model.dual_value_of_parameters[p_val(term.scalar_term.variable)] -= cons_dual[term.output_index] * term.scalar_term.coefficient end - for t in pf.pp + for t in vector_quadratic_parameter_parameter_terms(pf) mult = cons_dual[t.output_index] * t.scalar_term.coefficient if t.scalar_term.variable_1 == t.scalar_term.variable_2 mult /= 2 diff --git a/src/parametric_cubic_function.jl b/src/parametric_cubic_function.jl index 24f54407..1005c911 100644 --- a/src/parametric_cubic_function.jl +++ b/src/parametric_cubic_function.jl @@ -129,6 +129,9 @@ function ParametricCubicFunction(parsed::_ParsedCubicExpression{T}) where {T} end # Accessors for cubic terms by type (direct field access) +cubic_affine_parameter_terms(f::ParametricCubicFunction) = f.p +cubic_parameter_variable_terms(f::ParametricCubicFunction) = f.pv +cubic_parameter_parameter_terms(f::ParametricCubicFunction) = f.pp cubic_parameter_variable_variable_terms(f::ParametricCubicFunction) = f.pvv cubic_parameter_parameter_variable_terms(f::ParametricCubicFunction) = f.ppv cubic_parameter_parameter_parameter_terms(f::ParametricCubicFunction) = f.ppp @@ -156,7 +159,7 @@ function _parametric_constant(model, f::ParametricCubicFunction{T}) where {T} constant = f.c # From affine parameter terms (p) - for term in f.p + for term in cubic_affine_parameter_terms(f) constant += term.coefficient * _effective_param_value(model, p_idx(term.variable)) @@ -164,7 +167,7 @@ function _parametric_constant(model, f::ParametricCubicFunction{T}) where {T} # From quadratic parameter-parameter terms (pp) # MOI convention: diagonal C means C/2*p^2, off-diagonal C means C*p1*p2 - for term in f.pp + for term in cubic_parameter_parameter_terms(f) divisor = term.variable_1 == term.variable_2 ? 2 : 1 constant += (term.coefficient / divisor) * @@ -202,7 +205,7 @@ function _parametric_affine_terms( # Add contributions from pv terms (parameter * variable) # These are always off-diagonal (p != v), so coefficient is used as-is - for term in f.pv + for term in cubic_parameter_variable_terms(f) var = term.variable_2 coef = term.coefficient p_val = _effective_param_value(model, p_idx(term.variable_1)) @@ -314,7 +317,7 @@ function _delta_parametric_constant( delta = zero(T) # From p terms - for term in f.p + for term in cubic_affine_parameter_terms(f) p_i = p_idx(term.variable) if haskey(model.updated_parameters, p_i) && !isnan(model.updated_parameters[p_i]) @@ -325,7 +328,7 @@ function _delta_parametric_constant( end # From pp terms - for term in f.pp + for term in cubic_parameter_parameter_terms(f) pi1 = p_idx(term.variable_1) pi2 = p_idx(term.variable_2) updated1 = @@ -397,7 +400,7 @@ function _delta_parametric_affine_terms( delta_dict = Dict{MOI.VariableIndex,T}() # From pv terms (parameter * variable, always off-diagonal) - for term in f.pv + for term in cubic_parameter_variable_terms(f) p_i = p_idx(term.variable_1) if haskey(model.updated_parameters, p_i) && !isnan(model.updated_parameters[p_i]) diff --git a/src/parametric_functions.jl b/src/parametric_functions.jl index 90488656..0a1a1347 100644 --- a/src/parametric_functions.jl +++ b/src/parametric_functions.jl @@ -189,7 +189,11 @@ function _current_function(f::ParametricQuadraticFunction{T}) where {T} for (v, c) in f.affine_data_np push!(affine, MOI.ScalarAffineTerm{T}(c, v)) end - return MOI.ScalarQuadraticFunction{T}(f.vv, affine, f.current_constant) + return MOI.ScalarQuadraticFunction{T}( + quadratic_variable_variable_terms(f), + affine, + f.current_constant, + ) end function _parametric_constant( @@ -720,7 +724,7 @@ function _delta_parametric_constant( delta_constants = zeros(T, length(f.current_constant)) # Handle parameter-only affine terms - for term in f.p + for term in vector_affine_parameter_terms(f) p_idx_val = p_idx(term.scalar_term.variable) output_idx = term.output_index @@ -733,7 +737,7 @@ function _delta_parametric_constant( end # Handle parameter-parameter quadratic terms - for term in f.pp + for term in vector_quadratic_parameter_parameter_terms(f) idx = term.output_index var1 = term.scalar_term.variable_1 var2 = term.scalar_term.variable_2 @@ -767,7 +771,7 @@ function _delta_parametric_affine_terms( ) # Handle parameter-variable quadratic terms (px) that become affine (x) when p is updated - for term in f.pv + for term in vector_quadratic_parameter_variable_terms(f) p_idx_val = p_idx(term.scalar_term.variable_1) var = term.scalar_term.variable_2 output_idx = term.output_index @@ -835,7 +839,10 @@ end function _current_function(f::ParametricVectorQuadraticFunction{T}) where {T} affine_terms = MOI.VectorAffineTerm{T}[] - sizehint!(affine_terms, length(f.current_constant) + length(f.v)) + sizehint!( + affine_terms, + length(f.current_constant) + length(vector_affine_variable_terms(f)), + ) for ((var, idx), coef) in f.current_terms_with_p push!( affine_terms,