Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 16 additions & 14 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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,
Expand Down
24 changes: 12 additions & 12 deletions src/duals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)]
Expand Down Expand Up @@ -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
Expand Down
33 changes: 18 additions & 15 deletions src/parametric_cubic_function.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,12 @@ 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_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

"""
_effective_param_value(model, pi::ParameterIndex)
Expand All @@ -156,15 +159,15 @@ 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))
end

# 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) *
Expand All @@ -173,7 +176,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
Expand Down Expand Up @@ -202,15 +205,15 @@ 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))
terms_dict[var] = get(terms_dict, var, zero(T)) + coef * p_val
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))
Expand All @@ -235,7 +238,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)
Expand Down Expand Up @@ -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])
Expand All @@ -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 =
Expand All @@ -351,7 +354,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)
Expand Down Expand Up @@ -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])
Expand All @@ -411,7 +414,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)
Expand Down Expand Up @@ -449,7 +452,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)
Expand Down
17 changes: 12 additions & 5 deletions src/parametric_functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Loading