diff --git a/lib/CanonicalMoments/src/CanonicalMoments.jl b/lib/CanonicalMoments/src/CanonicalMoments.jl index 273ce51..afe1125 100644 --- a/lib/CanonicalMoments/src/CanonicalMoments.jl +++ b/lib/CanonicalMoments/src/CanonicalMoments.jl @@ -14,12 +14,14 @@ import LinearAlgebra: issymmetric import DiscreteMeasures: support, weights function DEFAULT_ROOT_SOLVER(C, args...; kwargs...) + # The closed-form solvers take only the coefficient vector; any extra + # args/kwargs are solver options that only the generic fallback consumes. return if length(C) == 3 # 2nd order - quadratic_eq_sridhare(C, args...; kwargs...) + quadratic_eq_sridhare(C) elseif length(C) == 4 # 3rd order - simple_real_cubic_eq(C, args...; kwargs...) + simple_real_cubic_eq(C) elseif length(C) == 5 # 4th order - simple_real_quartic_eq(C, args...; kwargs...) + simple_real_quartic_eq(C) else Polynomials.roots(Polynomial(C), args...; kwargs...) end diff --git a/lib/OUQBase/src/interface.jl b/lib/OUQBase/src/interface.jl index fe2bc50..831dd9c 100644 --- a/lib/OUQBase/src/interface.jl +++ b/lib/OUQBase/src/interface.jl @@ -147,32 +147,48 @@ struct OUQSystem{A <: ObjectiveType, B <: AbstractReductionAlgorithm, P} <: Abst admissible_set::AdmissibleSet reduction_data::B parameters::P - function OUQSystem(; - objective, - admissible_set, - reduction_alg::B, - parameters = SciMLBase.NullParameters(), - ) where {B} - reduction_data = ReductionData(admissible_set, reduction_alg) # Note: reduction_data is the populated reduction_alg. - objective = process_objective(objective) - return new{typeof(objective), B, typeof(parameters)}( - objective, - admissible_set, - reduction_data, - parameters, - ) + function OUQSystem{A, B, P}( + objective::A, + admissible_set::AdmissibleSet, + reduction_data::B, + parameters::P, + ) where {A <: ObjectiveType, B <: AbstractReductionAlgorithm, P} + return new{A, B, P}(objective, admissible_set, reduction_data, parameters) end end +function OUQSystem(; + objective, + admissible_set, + reduction_alg::AbstractReductionAlgorithm, + parameters = SciMLBase.NullParameters(), + ) + reduction_data = ReductionData(admissible_set, reduction_alg) # Note: reduction_data is the populated reduction_alg. + # Function barrier: process_objective returns a Union, so build the concretely + # parameterized OUQSystem behind a dispatch on the realized objective type. + return _OUQSystem(process_objective(objective), admissible_set, reduction_data, parameters) +end + +function _OUQSystem( + objective::A, + admissible_set::AdmissibleSet, + reduction_data::B, + parameters::P, + ) where {A <: ObjectiveType, B <: AbstractReductionAlgorithm, P} + return OUQSystem{A, B, P}(objective, admissible_set, reduction_data, parameters) +end + objective(ouq_sys::OUQSystem) = ouq_sys.objective random_variable_map(ouq_sys::OUQSystem) = ouq_sys.admissible_set.random_variable_map constraints_map(ouq_sys::OUQSystem) = ouq_sys.reduction_data.constraints_map -raw_moments_map(ouq_sys::OUQSystem) = - ouq_sys.reduction_data isa StengerCanonicalMoments ? - ouq_sys.reduction_data.raw_moments_map : nothing -p_free_map(ouq_sys::OUQSystem) = - ouq_sys.reduction_data isa StengerCanonicalMoments ? ouq_sys.reduction_data.p_free_map : - nothing +# Dispatch on the (concretely typed) reduction_data so the accessors stay type +# stable: a StengerCanonicalMoments system returns its dict, anything else nothing. +raw_moments_map(ouq_sys::OUQSystem) = raw_moments_map(ouq_sys.reduction_data) +raw_moments_map(reduction_data::StengerCanonicalMoments) = reduction_data.raw_moments_map +raw_moments_map(::AbstractReductionAlgorithm) = nothing +p_free_map(ouq_sys::OUQSystem) = p_free_map(ouq_sys.reduction_data) +p_free_map(reduction_data::StengerCanonicalMoments) = reduction_data.p_free_map +p_free_map(::AbstractReductionAlgorithm) = nothing function get_group_name(var, admissible_set::AdmissibleSet) diff --git a/lib/OUQBase/src/reduction_transformations/canonical_moments.jl b/lib/OUQBase/src/reduction_transformations/canonical_moments.jl index b1dee6f..1ea4761 100644 --- a/lib/OUQBase/src/reduction_transformations/canonical_moments.jl +++ b/lib/OUQBase/src/reduction_transformations/canonical_moments.jl @@ -15,7 +15,7 @@ function get_raw_moment_order(equation::Union{Equation, Inequality}, random_var: return order end -function CanonicalMoments.RawMomentSequence( +function build_raw_moment_sequence( random_var::Num, constraints::Vector{Union{Equation, Inequality}}, ) @@ -36,7 +36,7 @@ function create_raw_moments_map(admissible_set::AbstractAdmissibleSet) length(admissible_set.random_variable_map[k]) == 1 || error("Group is not independent, cannot use canonical moments") random_var = only(admissible_set.random_variable_map[k]) - raw_moments_map[k] = RawMomentSequence(random_var, v) + raw_moments_map[k] = build_raw_moment_sequence(random_var, v) end return raw_moments_map end @@ -82,8 +82,8 @@ function discrete_measure_map( ::Symbolic, ) transformed_discrete_measure_map = OrderedDict{Symbol, DiscreteMeasure}() - _raw_moments_map = raw_moments_map(ouq_sys) - _p_free_map = p_free_map(ouq_sys) + _raw_moments_map = reduction_alg.raw_moments_map + _p_free_map = reduction_alg.p_free_map for (k, v) in constraints_map(ouq_sys) transform_functor = DiscreteMeasureTransform1(_raw_moments_map[k]) transformed_discrete_measure_map[k] = transform_functor( diff --git a/lib/OUQBase/test/qa/qa.jl b/lib/OUQBase/test/qa/qa.jl index 3a096b7..b9d53e3 100644 --- a/lib/OUQBase/test/qa/qa.jl +++ b/lib/OUQBase/test/qa/qa.jl @@ -3,9 +3,6 @@ using SciMLTesting, OUQBase, JET, Test run_qa( OUQBase; explicit_imports = true, - # piracies: OUQBase defines `CanonicalMoments.RawMomentSequence(::Symbolics.Num, ...)`, - # owning neither the type nor the arg types; resolving it is a design change. - aqua_broken = (:piracies,), # SciML/OptimalUncertaintyQuantification.jl#33 ei_kwargs = (; # Explicit imports of names that are non-public in the upstream majors OUQBase # actually resolves. OUQBase's [compat] caps SciMLBase 2.x / Symbolics 6.x /