diff --git a/lib/CanonicalMoments/src/CanonicalMoments.jl b/lib/CanonicalMoments/src/CanonicalMoments.jl index a178929..c785dc3 100644 --- a/lib/CanonicalMoments/src/CanonicalMoments.jl +++ b/lib/CanonicalMoments/src/CanonicalMoments.jl @@ -11,12 +11,14 @@ import DiscreteMeasures: support, weights import Polynomials: denominator, numerator 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/Project.toml b/lib/OUQBase/Project.toml index 3b3a53e..a3c6051 100644 --- a/lib/OUQBase/Project.toml +++ b/lib/OUQBase/Project.toml @@ -12,7 +12,6 @@ ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" -PolynomialRoots = "3a141323-8675-5d76-9d11-e1df1406c778" Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462" @@ -31,7 +30,6 @@ Optimization = "5" OptimizationBBO = "0.4" OrderedCollections = "1.7.0" Pkg = "1.10" -PolynomialRoots = "1" Polynomials = "4.0.13" Reexport = "1.2.2" SciMLBase = "2.153" diff --git a/lib/OUQBase/src/interface.jl b/lib/OUQBase/src/interface.jl index c8c36db..0ee4cc8 100644 --- a/lib/OUQBase/src/interface.jl +++ b/lib/OUQBase/src/interface.jl @@ -149,32 +149,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 cd5d4b8..176c1cf 100644 --- a/lib/OUQBase/src/reduction_transformations/canonical_moments.jl +++ b/lib/OUQBase/src/reduction_transformations/canonical_moments.jl @@ -26,7 +26,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}}, ) @@ -47,7 +47,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 @@ -93,8 +93,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( @@ -271,7 +271,7 @@ function construct_optimization_problem( (rand_var_vec) -> substitute(~f, Dict(constituent_random_variables .=> rand_var_vec)) # QN: Will variables always be passed in right order? Should be correct since this order is preserved in getting the induced_discrete_measure. - ouq_obj_f = simplify(obj_expression; rewriter = extract_f_rule) + ouq_obj_f = Symbolics.simplify(obj_expression; rewriter = extract_f_rule) else error("Objective is not a ProbabilityObjective or ExpectationObjective") end diff --git a/lib/OUQBase/src/reduction_transformations/winkler_extremal_measures.jl b/lib/OUQBase/src/reduction_transformations/winkler_extremal_measures.jl index ee9673a..8e499bf 100644 --- a/lib/OUQBase/src/reduction_transformations/winkler_extremal_measures.jl +++ b/lib/OUQBase/src/reduction_transformations/winkler_extremal_measures.jl @@ -370,8 +370,8 @@ function construct_optimization_problem( oracle_or_symbolic::Symbolic; kwargs..., ) - @debug "Objective: $objective.objective" objective = ouq_sys.objective + @debug "Objective: $(objective._obj)" extract_condition_rule = @rule ℙ(~condition) => ~condition condition = Symbolics.simplify(objective._obj; rewriter = extract_condition_rule) _discrete_measure_map =