diff --git a/src/MOI_wrapper.jl b/src/MOI_wrapper.jl index 3d1d319..e54be93 100644 --- a/src/MOI_wrapper.jl +++ b/src/MOI_wrapper.jl @@ -746,6 +746,8 @@ function MOI.get( elseif haskey(model.affine_outer_to_inner, ci) inner_ci = model.affine_outer_to_inner[ci] return _original_function(model.affine_constraint_cache[inner_ci]) + elseif haskey(model.vector_affine_constraint_cache, ci) + return _original_function(model.vector_affine_constraint_cache[ci]) else MOI.throw_if_not_valid(model, ci) return MOI.get(model.optimizer, attr, ci) diff --git a/src/parametric_functions.jl b/src/parametric_functions.jl index d0f1dee..9048865 100644 --- a/src/parametric_functions.jl +++ b/src/parametric_functions.jl @@ -62,7 +62,7 @@ function ParametricQuadraticFunction( affine_data = Dict{MOI.VariableIndex,T}() sizehint!(affine_data, length(v_in_pv)) affine_data_np = Dict{MOI.VariableIndex,T}() - sizehint!(affine_data, length(v)) + sizehint!(affine_data_np, length(v)) for term in v if term.variable in v_in_pv base = get(affine_data, term.variable, zero(T)) @@ -276,12 +276,11 @@ function _delta_parametric_affine_terms( # remember a variable may appear more than once in pv for term in quadratic_parameter_variable_terms(f) p = p_idx(term.variable_1) - if !isnan(model.updated_parameters[p]) + new_p = model.updated_parameters[p] + if !isnan(new_p) base = get(delta_terms_dict, term.variable_2, zero(T)) delta_terms_dict[term.variable_2] = - base + - term.coefficient * - (model.updated_parameters[p] - model.parameters[p]) + base + term.coefficient * (new_p - model.parameters[p]) end end return delta_terms_dict @@ -725,9 +724,9 @@ function _delta_parametric_constant( p_idx_val = p_idx(term.scalar_term.variable) output_idx = term.output_index - if !isnan(model.updated_parameters[p_idx_val]) + new_param_val = model.updated_parameters[p_idx_val] + if !isnan(new_param_val) old_param_val = model.parameters[p_idx_val] - new_param_val = model.updated_parameters[p_idx_val] delta_constants[output_idx] += term.scalar_term.coefficient * (new_param_val - old_param_val) end @@ -772,10 +771,9 @@ function _delta_parametric_affine_terms( p_idx_val = p_idx(term.scalar_term.variable_1) var = term.scalar_term.variable_2 output_idx = term.output_index - if haskey(model.updated_parameters, p_idx_val) && - !isnan(model.updated_parameters[p_idx_val]) + new_param_val = model.updated_parameters[p_idx_val] + if !isnan(new_param_val) old_param_val = model.parameters[p_idx_val] - new_param_val = model.updated_parameters[p_idx_val] delta_coef = term.scalar_term.coefficient * (new_param_val - old_param_val) base = get(delta_terms_dict, (var, output_idx), zero(T)) diff --git a/test/test_MathOptInterface.jl b/test/test_MathOptInterface.jl index cc9d005..bc15cf5 100644 --- a/test/test_MathOptInterface.jl +++ b/test/test_MathOptInterface.jl @@ -2276,6 +2276,25 @@ function test_get_constraint_function_vector() return end +function test_get_constraint_function_vector_affine() + # MOI.get(ConstraintFunction) for a parametric + # VectorAffineFunction constraint must return the original function + # (with parameter VariableIndex terms), not the solver-side function + # (with parameters already substituted into constants). + model = POI.Optimizer(MOI.Utilities.Model{Float64}()) + x = MOI.add_variable(model) + p, pc = MOI.add_constrained_variable(model, MOI.Parameter(3.0)) + terms = [ + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(2.0, x)), + MOI.VectorAffineTerm(1, MOI.ScalarAffineTerm(5.0, p)), + ] + f = MOI.VectorAffineFunction(terms, [0.0]) + ci = MOI.add_constraint(model, f, MOI.Zeros(1)) + f2 = MOI.get(model, MOI.ConstraintFunction(), ci) + @test canonical_compare(f, f2) + return +end + function test_multiplicative_dual_error() model = POI.Optimizer(MOI.Utilities.Model{Float64}()) x = MOI.add_variable(model)