@@ -529,3 +529,207 @@ function _update_cache!(f::ParametricVectorAffineFunction{T}, model) where {T}
529529 f. current_constant = _parametric_constant (model, f)
530530 return nothing
531531end
532+
533+ mutable struct ParametricVectorQuadraticFunction{T}
534+ # constant * parameter * variable (in this order)
535+ pv:: Vector{MOI.VectorQuadraticTerm{T}}
536+ # constant * parameter * parameter
537+ pp:: Vector{MOI.VectorQuadraticTerm{T}}
538+ # constant * variable * variable
539+ vv:: Vector{MOI.VectorQuadraticTerm{T}}
540+ # constant * parameter
541+ p:: Vector{MOI.VectorAffineTerm{T}}
542+ # constant * variable
543+ v:: Vector{MOI.VectorAffineTerm{T}}
544+ # constant
545+ c:: Vector{T}
546+ # to avoid unnecessary lookups in updates
547+ set_constant:: Vector{T}
548+ # cache to avoid slow getters
549+ current_constant:: Vector{T}
550+ end
551+
552+ function ParametricVectorQuadraticFunction (
553+ f:: MOI.VectorQuadraticFunction{T} ,
554+ ) where {T}
555+ v, p = _split_vector_affine_terms (f. affine_terms)
556+ pv, pp, vv = _split_vector_quadratic_terms (f. quadratic_terms)
557+
558+ # Find variables related to parameters in parameter-variable quadratic terms
559+ v_in_pv = Set {MOI.VariableIndex} ()
560+ sizehint! (v_in_pv, length (pv))
561+ for term in pv
562+ push! (v_in_pv, term. scalar_term. variable_2)
563+ end
564+
565+ # Only cache affine variable terms that are involved in parameter-variable quadratic terms
566+ v_filtered = Vector {MOI.VectorAffineTerm{T}} ()
567+ for term in v
568+ if term. scalar_term. variable in v_in_pv
569+ push! (v_filtered, term)
570+ end
571+ end
572+
573+ return ParametricVectorQuadraticFunction {T} (
574+ pv,
575+ pp,
576+ vv,
577+ p,
578+ v_filtered,
579+ copy (f. constants),
580+ zeros (T, length (f. constants)),
581+ zeros (T, length (f. constants)),
582+ )
583+ end
584+
585+ function vector_quadratic_parameter_variable_terms (f:: ParametricVectorQuadraticFunction )
586+ return f. pv
587+ end
588+
589+ function vector_quadratic_parameter_parameter_terms (f:: ParametricVectorQuadraticFunction )
590+ return f. pp
591+ end
592+
593+ function vector_quadratic_variable_variable_terms (f:: ParametricVectorQuadraticFunction )
594+ return f. vv
595+ end
596+
597+ function vector_affine_parameter_terms (f:: ParametricVectorQuadraticFunction )
598+ return f. p
599+ end
600+
601+ function vector_affine_variable_terms (f:: ParametricVectorQuadraticFunction )
602+ return f. v
603+ end
604+
605+ function _split_vector_quadratic_terms (
606+ terms:: Vector{MOI.VectorQuadraticTerm{T}} ,
607+ ) where {T}
608+ num_vv = 0
609+ num_pp = 0
610+ num_pv = 0
611+ for term in terms
612+ if _is_variable (term. scalar_term. variable_1)
613+ if _is_variable (term. scalar_term. variable_2)
614+ num_vv += 1
615+ else
616+ num_pv += 1
617+ end
618+ else
619+ if _is_variable (term. scalar_term. variable_2)
620+ num_pv += 1
621+ else
622+ num_pp += 1
623+ end
624+ end
625+ end
626+ vv = Vector {MOI.VectorQuadraticTerm{T}} (undef, num_vv)
627+ pp = Vector {MOI.VectorQuadraticTerm{T}} (undef, num_pp)
628+ pv = Vector {MOI.VectorQuadraticTerm{T}} (undef, num_pv)
629+ i_vv = 1
630+ i_pp = 1
631+ i_pv = 1
632+ for term in terms
633+ if _is_variable (term. scalar_term. variable_1)
634+ if _is_variable (term. scalar_term. variable_2)
635+ vv[i_vv] = term
636+ i_vv += 1
637+ else
638+ pv[i_pv] = MOI. VectorQuadraticTerm (
639+ term. output_index,
640+ MOI. ScalarQuadraticTerm (
641+ term. scalar_term. coefficient,
642+ term. scalar_term. variable_2,
643+ term. scalar_term. variable_1,
644+ ),
645+ )
646+ i_pv += 1
647+ end
648+ else
649+ if _is_variable (term. scalar_term. variable_2)
650+ pv[i_pv] = term
651+ i_pv += 1
652+ else
653+ pp[i_pp] = term
654+ i_pp += 1
655+ end
656+ end
657+ end
658+ return pv, pp, vv
659+ end
660+
661+ function _parametric_constant (
662+ model,
663+ f:: ParametricVectorQuadraticFunction{T} ,
664+ ) where {T}
665+ param_constant = copy (f. c)
666+ for term in vector_affine_parameter_terms (f)
667+ param_constant[term. output_index] +=
668+ term. scalar_term. coefficient *
669+ model. parameters[p_idx (term. scalar_term. variable)]
670+ end
671+ for term in vector_quadratic_parameter_parameter_terms (f)
672+ idx = term. output_index
673+ coef = term. scalar_term. coefficient /
674+ (term. scalar_term. variable_1 == term. scalar_term. variable_2 ? 2 : 1 )
675+ param_constant[idx] += coef *
676+ model. parameters[p_idx (term. scalar_term. variable_1)] *
677+ model. parameters[p_idx (term. scalar_term. variable_2)]
678+ end
679+ return param_constant
680+ end
681+
682+ function _delta_parametric_constant (
683+ model,
684+ f:: ParametricVectorQuadraticFunction{T} ,
685+ ) where {T}
686+ delta_constant = zeros (T, length (f. c))
687+ for term in vector_affine_parameter_terms (f)
688+ p = p_idx (term. scalar_term. variable)
689+ if ! isnan (model. updated_parameters[p])
690+ delta_constant[term. output_index] +=
691+ term. scalar_term. coefficient *
692+ (model. updated_parameters[p] - model. parameters[p])
693+ end
694+ end
695+ for term in vector_quadratic_parameter_parameter_terms (f)
696+ idx = term. output_index
697+ p1 = p_idx (term. scalar_term. variable_1)
698+ p2 = p_idx (term. scalar_term. variable_2)
699+ isnan_1 = isnan (model. updated_parameters[p1])
700+ isnan_2 = isnan (model. updated_parameters[p2])
701+ if ! isnan_1 || ! isnan_2
702+ new_1 = isnan_1 ? model. parameters[p1] : model. updated_parameters[p1]
703+ new_2 = isnan_2 ? model. parameters[p2] : model. updated_parameters[p2]
704+ coef = term. scalar_term. coefficient /
705+ (term. scalar_term. variable_1 == term. scalar_term. variable_2 ? 2 : 1 )
706+ delta_constant[idx] += coef * (new_1 * new_2 - model. parameters[p1] * model. parameters[p2])
707+ end
708+ end
709+ return delta_constant
710+ end
711+
712+ function _update_cache! (f:: ParametricVectorQuadraticFunction{T} , model) where {T}
713+ f. current_constant = _parametric_constant (model, f)
714+ return nothing
715+ end
716+
717+ function _original_function (f:: ParametricVectorQuadraticFunction{T} ) where {T}
718+ return MOI. VectorQuadraticFunction {T} (
719+ vcat (
720+ vector_quadratic_parameter_variable_terms (f),
721+ vector_quadratic_parameter_parameter_terms (f),
722+ vector_quadratic_variable_variable_terms (f),
723+ ),
724+ vcat (vector_affine_parameter_terms (f), vector_affine_variable_terms (f)),
725+ f. c,
726+ )
727+ end
728+
729+ function _current_function (f:: ParametricVectorQuadraticFunction{T} ) where {T}
730+ return MOI. VectorQuadraticFunction {T} (
731+ vector_quadratic_variable_variable_terms (f),
732+ vector_affine_variable_terms (f),
733+ f. current_constant,
734+ )
735+ end
0 commit comments