From addeb2baf393787199ad6b7b31578d959d70e1b0 Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 25 Mar 2026 14:29:45 -0700 Subject: [PATCH 01/36] first port from PR 376 typos add pkgs encoder_kwargs in nice form remove dim criterion for now docstring API refinement add example builds encoder, but mcmc bug examples run, bugs for dimensionality and product order resolved noise injection reduced add some get_encoded_dim functions add consistency for both in-and-out dimensions for li, when using multiple distributions runs through with output reduction, logic simplified for now --- Project.toml | 4 + examples/DimensionReduction/Project.toml | 17 + .../DimensionReduction/calibrate_linlinexp.jl | 72 ++++ .../emulate_sample_linlinexp.jl | 140 +++++++ examples/DimensionReduction/models.jl | 50 +++ src/Emulator.jl | 12 +- src/Utilities.jl | 202 ++++++++-- src/Utilities/likelihood_informed.jl | 372 ++++++++++++++++++ 8 files changed, 838 insertions(+), 31 deletions(-) create mode 100644 examples/DimensionReduction/Project.toml create mode 100644 examples/DimensionReduction/calibrate_linlinexp.jl create mode 100644 examples/DimensionReduction/emulate_sample_linlinexp.jl create mode 100644 examples/DimensionReduction/models.jl create mode 100644 src/Utilities/likelihood_informed.jl diff --git a/Project.toml b/Project.toml index 1dec3bc15..fa5969b5e 100644 --- a/Project.toml +++ b/Project.toml @@ -19,6 +19,8 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LinearMaps = "7a12625a-238d-50fd-b39a-03d52299707e" LowRankApprox = "898213cb-b102-5a47-900c-97e73b919f73" MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" +Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" +Manopt = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" ProgressBars = "49802e3a-d2f1-5c88-81d8-b72133a6f568" @@ -47,6 +49,8 @@ KernelFunctions = "0.10.64, 0.11" LinearMaps = "3.11.4" LowRankApprox = "0.5.5" MCMCChains = "7" +Manifolds = "0.11.19" +Manopt = "0.5.34" Plots = "1.41.1" Printf = "1" ProgressBars = "1" diff --git a/examples/DimensionReduction/Project.toml b/examples/DimensionReduction/Project.toml new file mode 100644 index 000000000..a1b195d9d --- /dev/null +++ b/examples/DimensionReduction/Project.toml @@ -0,0 +1,17 @@ +[deps] +AdvancedMH = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170" +CalibrateEmulateSample = "95e48a1f-0bec-4818-9538-3db4340308e3" +ChunkSplitters = "ae650224-84b6-46f8-82ea-d812ca08434e" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" +FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" +Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" +Manopt = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" \ No newline at end of file diff --git a/examples/DimensionReduction/calibrate_linlinexp.jl b/examples/DimensionReduction/calibrate_linlinexp.jl new file mode 100644 index 000000000..ac68b9b00 --- /dev/null +++ b/examples/DimensionReduction/calibrate_linlinexp.jl @@ -0,0 +1,72 @@ +using Distributions +using EnsembleKalmanProcesses +using JLD2 +using LinearAlgebra +using Random + +include("./models.jl") + +datadir = joinpath(@__DIR__,"datafiles") +if !isdir(datadir) + mkpath(datadir) +end + +rng = Random.MersenneTwister(41) +input_dim = 100 +output_dim = 100 + +num_trials = 5 +for trial in 1:num_trials + @info "Trial $trial" + + prior_cov, y, obs_noise_cov, model, true_parameter = linlinexp(input_dim, output_dim, rng) + prior_obj = ParameterDistribution( + Parameterized(MvNormal(zeros(size(prior_cov, 1)), prior_cov)), + fill(no_constraint(), size(prior_cov, 1)), + "linlinexp_prior", + ) + + n_ensemble = 50 + initial_ensemble = construct_initial_ensemble(rng, prior_obj, n_ensemble) + ekp = EnsembleKalmanProcess( + initial_ensemble, + y, + obs_noise_cov, + TransformInversion(); + rng, + ) + + n_iters = 0 + for i in 1:50 + n_iters += 1 + G_ens = hcat([forward_map(param, model) for param in eachcol(get_ϕ_final(prior_obj, ekp))]...) + terminate = update_ensemble!(ekp, G_ens) + if !isnothing(terminate) + break + end + end + @info "EKP iterations: $n_iters" + @info "Loss over iterations: $(get_error(ekp))" + @info "Timesteps: $(ekp.Δt)" + @info "Checkpoints: $(get_algorithm_time(ekp))" + αs = vec([0 get_algorithm_time(ekp)[1:end]...]) + ekp_samples = Dict(α => (get_u(ekp, i), get_g(ekp, i)) for (i,α) in enumerate(αs[1:end-1])) + + # evaluate at final time + G_ens = hcat([forward_map(param, model) for param in eachcol(get_ϕ_final(prior_obj, ekp))]...) + ekp_samples[αs[end]] = (get_u(ekp,length(αs)), G_ens) + + #! format: off + save( + joinpath(datadir,"ekp_linlinexp_$(trial).jld2"), + "ekpobj", ekp, + "ekp_samples", ekp_samples, + "prior_obj", prior_obj, + "y", y, + "obs_noise_cov", obs_noise_cov, + "model", model, + "true_parameter", true_parameter, + "alphas", αs, + ) + #! format: on +end diff --git a/examples/DimensionReduction/emulate_sample_linlinexp.jl b/examples/DimensionReduction/emulate_sample_linlinexp.jl new file mode 100644 index 000000000..cafd8609c --- /dev/null +++ b/examples/DimensionReduction/emulate_sample_linlinexp.jl @@ -0,0 +1,140 @@ +using Distributions +using EnsembleKalmanProcesses +using JLD2 +using LinearAlgebra +using Random +using MCMCChains +using AdvancedMH + +# CES +using CalibrateEmulateSample.Emulators +using CalibrateEmulateSample.MarkovChainMonteCarlo +using CalibrateEmulateSample.Utilities + + +include("./models.jl") + +rng = Random.MersenneTwister(41) +input_dim = 100 +output_dim = 100 + +num_trials = 1 +for trial in 1:num_trials + loaded = load("datafiles/ekp_linlinexp_$(trial).jld2") + ekpobj = loaded["ekpobj"] + ekp_samples = loaded["ekp_samples"] + prior = loaded["prior_obj"] + obs_noise_cov = loaded["obs_noise_cov"] + y = loaded["y"] + model = loaded["model"] + true_parameter = loaded["true_parameter"] + αs = loaded["alphas"] + + min_iter = 1 + max_iter = min(10, length(αs)) # number of EKP iterations to use data from is at most this + training_points = [ekp_samples[α] for α in αs[min_iter:max_iter]] + + encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] + + rvs = collect(0.975:0.0125:1.0) + rkls = collect(0.999:0.0005:1.0) + all_errs = zeros(length(rvs), 1 + length(αs)) + + # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor + final_samples_out = ekp_samples[αs[end]][2] + encoder_kwargs = encoder_kwargs_from(ekpobj, prior; final_samples_out=final_samples_out) + + flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final=final_samples_out) + + names = ["reference", "decorrelate, PCA-in", ["decorrelate, LI-in 1:$(i)" for i in 1:length(αs)]...] + + ni_scaling = 0.01 # noise injection into null space scaling (def. 1) + + for (idx, (rv, rkl)) in enumerate(zip(rvs, rkls)) + encoder_schedule_decorrelate = [ + (decorrelate_structure_mat(retain_var = rv), "in"), + (decorrelate_structure_mat(), "out"), + ] + encoder_schedules_li = [ + [ + (decorrelate_structure_mat(), "in_and_out"), + (likelihood_informed(retain_kl=rkl, iters=1:i), "in"), + ] for i in 1:length(αs) + ] + + em_ref = forward_map_wrapper( + param -> forward_map(param, model), + prior, + flat_io_pairs; + encoder_schedule = encoder_schedule_ref, + encoder_kwargs = deepcopy(encoder_kwargs), + noise_injector_scaling=ni_scaling, # shouldnt be needed + ) + + em_decorrelate = forward_map_wrapper( + param -> forward_map(param, model), + prior, + flat_io_pairs; + encoder_schedule = encoder_schedule_decorrelate, + encoder_kwargs = deepcopy(encoder_kwargs), + noise_injector_scaling=ni_scaling, + ) + + ems_li = [ + forward_map_wrapper( + param -> forward_map(param, model), + prior, + flat_io_pairs; + encoder_schedule = encoder_schedule, + encoder_kwargs = deepcopy(encoder_kwargs), + noise_injector_scaling=ni_scaling, + ) for encoder_schedule in encoder_schedules_li + ] + + post_means = reshape(true_parameter, input_dim, 1) + post_covs = [] + + for (nn, em) in zip(names,vcat(em_ref, em_decorrelate, ems_li...)) + println(" ") + @info "Encoding name: $(nn)" + E,_ = get_encoder_from_schedule(get_encoder_schedule(em), "in") + if isnothing(E) + @info "No truncation" + else + + @info "Truncation criteria (var>$(rv), or kl > $(rkl))" + @info "input dim reduced to: $(size(E,1))" + + end + println(" ") + u0 = rand(MvNormal(mean(prior), cov(prior))) + mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) + new_step = optimize_stepsize(mcmc; init_stepsize = 0.05, N = 2000, discard_initial = 0) + + println("Begin MCMC - with step size ", new_step) + mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) + chain = MarkovChainMonteCarlo.sample( + mcmc, + 40_000; + stepsize = new_step, + discard_initial = 5_000, + ) + posterior = MarkovChainMonteCarlo.get_posterior(mcmc, chain) + + post_mean = mean(posterior) + post_cov = cov(posterior) + + post_means = hcat(post_means, reshape(post_mean, input_dim, 1)) + push!(post_covs, post_cov) + end + + # post_means[:,1] = true parameter + # post_means[:,2] = ref + # post_means[:,3] = decor, LI etc. + # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) + all_errs[idx, :] = + [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' + end + @info "error of posterior mean to whitened \"reference\" solution. for $(names[2:end])" + display(all_errs) +end diff --git a/examples/DimensionReduction/models.jl b/examples/DimensionReduction/models.jl new file mode 100644 index 000000000..e083faeac --- /dev/null +++ b/examples/DimensionReduction/models.jl @@ -0,0 +1,50 @@ +using Distributions +using LinearAlgebra +using Statistics + +using EnsembleKalmanProcesses +using EnsembleKalmanProcesses.ParameterDistributions + +abstract type ForwardMapType end + +## Linear-times-exponential model +function linlinexp(input_dim, output_dim, rng) + # prior + γ0 = 4.0 + β_γ = -2 + Γ = Diagonal([γ0 * (1.0 * j)^β_γ for j in 1:input_dim]) + + U = qr(randn(rng, (output_dim, output_dim))).Q + V = qr(randn(rng, (input_dim, input_dim))).Q + λ0 = 100.0 + β_λ = -1 + Λ = Diagonal([λ0 * (1.0 * j)^β_λ for j in 1:output_dim]) + A = U * Λ * V[1:output_dim, :] # output x input + model = LinLinExp(input_dim, output_dim, A) + + # generate data sample + obs_noise_cov = Diagonal([Float64(j)^(-1 / 2) for j in 1:output_dim]) + noise = rand(rng, MvNormal(zeros(output_dim), obs_noise_cov)) + # true_parameter = reshape(ones(input_dim), :, 1) + true_parameter = rand(rng, MvNormal(zeros(input_dim), Γ)) + y = vec(forward_map(true_parameter, model) + noise) + return Γ, y, obs_noise_cov, model, true_parameter +end + +struct LinLinExp{AM <: AbstractMatrix} <: ForwardMapType + input_dim::Int + output_dim::Int + G::AM +end + +function forward_map(X::AVorM, model::LinLinExp) where {AVorM <: AbstractVecOrMat} + return model.G * (X .* exp.(0.05X)) +end + +function jac_forward_map(X::AbstractVector, model::LinLinExp) + return model.G * Diagonal(exp.(0.05X) .* (1 .+ 0.05X)) +end + +function jac_forward_map(X::AbstractMatrix, model::LinLinExp) + return [jac_forward_map(x, model) for x in eachcol(X)] +end diff --git a/src/Emulator.jl b/src/Emulator.jl index a4507f078..ed63726c2 100644 --- a/src/Emulator.jl +++ b/src/Emulator.jl @@ -41,17 +41,17 @@ include(joinpath("MachineLearningTools", "RandomFeature.jl")) # Random Freatures # etc. # defaults in error, all MachineLearningTools require these functions. -function throw_define_mlt() - throw(ErrorException("Unknown MachineLearningTool defined, please use a known implementation")) +function throw_define_mlt(mlt) + throw(ErrorException("Unknown MachineLearningTool defined, please use a known implementation. Please check all methods are defined for the MLT received: \n $mlt")) end function build_models!(mlt, iopairs, input_structure_mats, output_structure_mats, mlt_kwargs...) - throw_define_mlt() + throw_define_mlt(mlt) end function optimize_hyperparameters!(mlt) - throw_define_mlt() + throw_define_mlt(mlt) end function predict(mlt, new_inputs; mlt_kwargs...) - throw_define_mlt() + throw_define_mlt(mlt) end # We will define the different emulator types after the general statements @@ -502,8 +502,6 @@ function forward_map_wrapper( else push!(encoder_schedule, (decorrelate_sample_cov(), "out")) end - else - @warn "Please note that only the output encoder is used in this implementation. \nThe input encoder will be initialized if provided, but not used during sampling, which is completed in the full parameter space." end encoder_schedule = create_encoder_schedule(encoder_schedule) diff --git a/src/Utilities.jl b/src/Utilities.jl index 86fb34a0f..0de4dafab 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -35,7 +35,8 @@ export create_encoder_schedule, get_decoder_from_schedule, NoiseInjector, decode_and_add_noise, - create_noise_injector + create_noise_injector, + get_encoded_dim const StructureMatrix = Union{UniformScaling, AbstractMatrix, AbstractVector, LinearMap} # The vector appears due to possible block-structured matrices (build=false) @@ -50,10 +51,12 @@ Extract the training points needed to train the Gaussian process regression. during the Ensemble Kalman (EK) process. - `train_iterations` - Number (or indices) EK layers/iterations to train on. +- `g_final[=nothing]` - EKP will typically store one extra input data iteration. If desired, the user can add output data for this final iteration directly with `g_final`. It should be of type `<: AbstractMatrix`, sized consistently as with return values from `get_g(ekp,1)`. """ function get_training_points( ekp::EKP.EnsembleKalmanProcess{FT, IT, P}, - train_iterations::Union{IT, AbstractVector{IT}}, + train_iterations::Union{IT, AbstractVector{IT}}; + g_final=nothing, ) where {FT, IT, P} if !isa(train_iterations, AbstractVector) @@ -65,12 +68,24 @@ function get_training_points( u_tp = [] g_tp = [] - for i in iter_range - push!(u_tp, get_u(ekp, i)) #N_parameters x N_ens - push!(g_tp, get_g(ekp, i)) #N_data x N_ens + + g_len=length(get_g(ekp)) + g_full = [get_g(ekp, i) for i in iter_range[iter_range .<= g_len]] + if !isnothing(g_final) + if (isa(g_final, AbstractMatrix)) # add the matrix + @assert(size(g_full[1]) == size(g_final)) + push!(g_full, g_final) + else + throw(ArgumentError, "Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final))") + end end - u_tp = hcat(u_tp...) # N_parameters x (N_ek_it x N_ensemble)] - g_tp = hcat(g_tp...) # N_data x (N_ek_it x N_ensemble) + + for (idx, ir) in enumerate(iter_range) + push!(u_tp, get_u(ekp, ir)) #N_parameters x N_ens + push!(g_tp, g_full[idx]) #N_data x N_ens + end + u_tp = reduce(hcat,u_tp) # N_parameters x (N_ek_it x N_ensemble)] + g_tp = reduce(hcat,g_tp) # N_data x (N_ek_it x N_ensemble) training_points = PairedDataContainer(u_tp, g_tp, data_are_columns = true) @@ -85,6 +100,8 @@ $(TYPEDSIGNATURES) Extracts the relevant encoder kwargs from the observation as a NamedTuple. Contains, - `:obs_noise_cov` as (unbuilt) noise covariance - `:observation` as obs vector + +Commonly called from `encoder_kwargs_from(ekp, prior)` """ function encoder_kwargs_from(obs::OB) where {OB <: Observation} return (; obs_noise_cov = get_obs_noise_cov(obs, build = false), observation = get_obs(obs)) @@ -96,6 +113,8 @@ $(TYPEDSIGNATURES) Extracts the relevant encoder kwargs from the ObservationSeries as a NamedTuple. Assumes the same noise covariance for all observation vectors. Contains, - `:obs_noise_cov` as (unbuilt) noise covariance of FIRST observation - `:observation` as obs vector from all observations + +Commonly called from `encoder_kwargs_from(ekp, prior)` """ function encoder_kwargs_from(os::OS) where {OS <: ObservationSeries} observations = get_observations(os) @@ -115,11 +134,85 @@ $(TYPEDSIGNATURES) Extracts the relevant encoder kwargs from the ParameterDistribution prior. Contains, - `:prior_cov` as prior covariance + +Commonly called from `encoder_kwargs_from(ekp, prior)` """ function encoder_kwargs_from(prior::PD) where {PD <: ParameterDistribution} return (; prior_cov = cov(prior)) end +""" +$(TYPEDSIGNATURES) + +Extracts the relevant encoder kwargs from a vector triple (samples_in, samples_out, dt). Samples describe an ordered sequence of distributions in input and output space, each indexed with a temperature, or algorithm time, `dt`. + +Contains +- `:input_structure_vecs`: Dict with fields `:dt` (Vec{Float}), `:samples_in` (Vec{Matrix}) +- `:output_structure_vecs`: Dict with fields `:dt` (Vec{Float}), `:samples_out` (Vec{Matrix}) + +Commonly called from `encoder_kwargs_from(ekp, prior)` +""" +function encoder_kwargs_from(samples_in::VV2, samples_out::VV1, dt::VV3) where {VV1 <: AbstractVector, VV2 <: AbstractVector, VV3 <: AbstractVector} + if !(minimum(abs.(dt[1])) < eps()) # if 0 is not the first element of the algorithm time. + dt = [0, dt...] + end + if length(samples_out)< min(length(samples_in),length(dt)) + @info """Detected fewer `samples_out` ($(length(samples_out))) than `samples_in` ($(length(samples_in))) and `dt` ($(length(dt))). Input-output structure vectors will be created from $(length(samples_out)) samples. +This commonly occurs when samples are built from `get_u(ekp), get_g(ekp)`. +The final interation of output samples, (e.g., from evaluating `g=forward_map_ensemble(get_ϕ_final(ekp)`) can be provided by `encoder_kwargs_from(ekp, prior; final_samples_out=g)` + +""" + end + len = minimum([length(samples_out), length(samples_in), length(dt)]) + # usually u is stored to one later value than g + samples_in = samples_in[1:len] + dt = dt[1:len] + samples_out = samples_out[1:len] + return( + ; + input_structure_vecs = Dict(:dt => dt, :samples_in => samples_in), + output_structure_vecs = Dict(:dt => dt, :samples_out => samples_out), + ) +end + +""" +$(TYPEDSIGNATURES) + +Extracts the relevant encoder kwargs from the `ekp` object, `prior` distribution. returned as a tuple that is passed to an `Emulator` or `ForwardMapWrapper` in the keyword argument `encoder_kwargs`. One can overload constructed kwargs by providing kwargs. + +kwargs: +- Common overloaded kwarg: `final_samples_out`. As `ekp` stores one more input than output, by default we truncate to the penultimate `ekp` iteration (where input output pairs exist). However, one can provide an additional final output paired with `g=forward_map_ensemble(get_ϕ_final(ekp))` with `final_samples_out=g` + +- Other overloading kwargs: `observation_series`,`samples_in`,`samples_out`,`dt` +""" +function encoder_kwargs_from(ekp::EKP, prior::PD; observation_series=nothing, samples_in=nothing, samples_out=nothing, dt=nothing, final_samples_out=nothing) where {PD <: ParameterDistribution, EKP <: EnsembleKalmanProcess} + observation_series = isnothing(observation_series) ? get_observation_series(ekp) : observation_series + samples_in = isnothing(samples_in) ? get_u(ekp) : samples_in + samples_out = isnothing(samples_out) ? get_g(ekp) : samples_out + dt = isnothing(dt) ? get_algorithm_time(ekp) : dt + # a common setting is you have one-less samples_out than (samples_in, dt) so we extend g + if !isnothing(final_samples_out) + if (isa(final_samples_out, AbstractMatrix)) # add one matrix + if length(samples_out)>0 + @assert(size(samples_out[1]) == size(final_samples_out)) + end + push!(samples_out, final_samples_out) + else # add a vector of matrices + if length(samples_out)>0 + @assert(size(samples_out[1]) == size(final_samples_out[1])) + end + samples_out = reduce(vcat, [samples_out,final_samples_out]) + end + end + + prior_kwargs = encoder_kwargs_from(prior) + obs_kwargs = encoder_kwargs_from(observation_series) + io_kwargs = encoder_kwargs_from(samples_in, samples_out, dt) + return merge(prior_kwargs, obs_kwargs, io_kwargs) + +end + + ## multiplication with observation covariance objects without building """ $(TYPEDSIGNATURES) @@ -379,6 +472,15 @@ function get_structure_mat(structure_mats, name = nothing) end end +function encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} + if eltype(data) <: Real # one vec + return encode_data(proc, reshape(data,:,1)) # reshape to column + else # vec of vec + return [encode_data(proc, vec_or_mat) for vec_or_mat in data] + end +end + + function _encode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString} input_data, output_data = get_data(data) if apply_to == "in" @@ -390,6 +492,14 @@ function _encode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS end end +function decode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} + if eltype(data) <: Real # one vec + return decode_data(proc, reshape(data,:,1)) # reshape to column + else # vec of vec + return [decode_data(proc, data[vec]) for vec in data] + end +end + function _decode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString} input_data, output_data = get_data(data) @@ -500,8 +610,8 @@ function initialize_and_encode_with_schedule!( prior_cov::Union{Nothing, StructureMatrix} = nothing, obs_noise_cov::Union{Nothing, StructureMatrix} = nothing, observation::Union{Nothing, StructureVector} = nothing, - prior_samples_in::Union{Nothing, StructureVector} = nothing, - prior_samples_out::Union{Nothing, StructureVector} = nothing, + samples_in::Union{Nothing, StructureVector} = nothing, + samples_out::Union{Nothing, StructureVector} = nothing, ) where {VV <: AbstractVector, PDC <: PairedDataContainer} processed_io_pairs = deepcopy(io_pairs) @@ -533,18 +643,18 @@ function initialize_and_encode_with_schedule!( end input_structure_vecs = deepcopy(input_structure_vecs) - if !isnothing(prior_samples_in) - (input_structure_vecs[:prior_samples_in] = prior_samples_in) + if !isnothing(samples_in) + (input_structure_vecs[:samples_in] = samples_in) end output_structure_vecs = deepcopy(output_structure_vecs) if !isnothing(observation) (output_structure_vecs[:observation] = observation) end - if !isnothing(prior_samples_out) - (output_structure_vecs[:prior_samples_out] = prior_samples_out) + if !isnothing(samples_out) + (output_structure_vecs[:samples_out] = samples_out) end - + # apply_to is the string "in", "out" etc. for (processor, apply_to) in encoder_schedule @info "Initialize encoding of data: \"$(apply_to)\" with $(processor)" @@ -557,21 +667,22 @@ function initialize_and_encode_with_schedule!( apply_to, ) + non_encode_list = [:dt] # non-data fields if apply_to == "in" input_structure_mats = Dict{Symbol, StructureMatrix}( - name => encode_structure_matrix(processor, mat) for (name, mat) in input_structure_mats - ) + name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) + for (name, mat) in input_structure_mats) input_structure_vecs = Dict{Symbol, StructureVector}( - name => encode_data(processor, vec) for (name, vec) in input_structure_vecs - ) + name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) + for (name, vec) in input_structure_vecs) processed_io_pairs = PairedDataContainer(processed, get_outputs(processed_io_pairs)) elseif apply_to == "out" output_structure_mats = Dict{Symbol, StructureMatrix}( - name => encode_structure_matrix(processor, mat) for (name, mat) in output_structure_mats - ) + name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) + for (name, mat) in output_structure_mats) output_structure_vecs = Dict{Symbol, StructureVector}( - name => encode_data(processor, vec) for (name, vec) in output_structure_vecs - ) + name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) + for (name, vec) in output_structure_vecs) processed_io_pairs = PairedDataContainer(get_inputs(processed_io_pairs), processed) end end @@ -765,8 +876,9 @@ function get_encoder_from_schedule( if length(encoder_mats) == 0 return nothing, nothing else - # Note, the action of encoders (E_1,E_2,E_3) is the product x -> (E_3*E_2*E_1)*x so must be reversed. `prod` unsafe here - linear_part = reduce(*, reverse(encoder_mats)) + # Note, the action of encoders (E_1,E_2,E_3) is the product x -> (E_3*E_2*E_1)*x so must be reversed + linear_part = reduce(*,reverse(encoder_mats)) + # rather than extracting the shifts etc. we can get this by just applying it to zero constant_part = encode_data(encoder_schedule, zeros(size(linear_part, 2), 1), in_or_out) @@ -785,7 +897,43 @@ function get_encoder_from_schedule(encoder_schedule::VV) where {VV <: AbstractVe "in" => get_encoder_from_schedule(encoder_schedule, "in"), "out" => get_encoder_from_schedule(encoder_schedule, "out"), ) +end + +""" +$(TYPEDSIGNATURES) + +gets the dimension of the encoded space, for input (providing "in"), or output (providing "out"), provides nothing if encoder schedule is empty or uninitialized +""" +function get_encoded_dim(encoder_schedule::VV, in_or_out::AS) where {VV <: AbstractVector, AS <: AbstractString} + if length(encoder_schedule) == 0 + return nothing + else + if in_or_out ∉ ["in", "out"] + bad_in_or_out(in_or_out) + end + + encoder_mat_sizes = + [size(get_encoder_mat(processor)[1]) for (processor, apply_to) in encoder_schedule if apply_to == in_or_out] + + if length(encoder_mat_sizes) == 0 + return nothing + else + # (E_1, E_2, E_3) applied as E_3(E_2(E_1(x))) size(E_3,1) matters + return encoder_mat_sizes[end][1] + end + end +end + +""" +$(TYPEDSIGNATURES) +gets the dimension of the encoded space, returned as a Dict with keys "in","out". Provides nothing values if encoder schedule is empty or uninitialized +""" +function get_encoded_dim(encoder_schedule::VV) where {VV <: AbstractVector} + return Dict( + "in" => get_encoded_dim(encoder_schedule, "in"), + "out" => get_encoded_dim(encoder_schedule, "out"), + ) end """ @@ -841,6 +989,11 @@ function get_decoder_from_schedule(encoder_schedule::VV) where {VV <: AbstractVe ) end + +get_encoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_encoder_from_schedule([single_encoder], args...; kwargs...) +get_decoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_decoder_from_schedule([single_encoder], args...; kwargs...) +get_encoded_dim(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_encoded_dim([single_encoder], args...; kwargs...) + ## Decoding and add noise: """ $(TYPEDEF) @@ -977,5 +1130,6 @@ end include("Utilities/canonical_correlation.jl") include("Utilities/decorrelator.jl") include("Utilities/elementwise_scaler.jl") +include("Utilities/likelihood_informed.jl") end # module diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl new file mode 100644 index 000000000..79f500f78 --- /dev/null +++ b/src/Utilities/likelihood_informed.jl @@ -0,0 +1,372 @@ +# included in Utilities.jl + +using Manifolds, Manopt + +export LikelihoodInformed, likelihood_informed + +""" +$(TYPEDEF) + +Uses both input and output data to learn a subspace that allows for a reduced posterior which is close to the full posterior. + +Preferred construction is with the [`likelihood_informed`](@ref) method. + +# Fields +$(TYPEDFIELDS) +""" +mutable struct LikelihoodInformed{VV1<:AbstractVector, VV2<:AbstractVector, VV3<:AbstractVector, VV4<:AbstractVector, FT <: Real} <: PairedDataContainerProcessor + encoder_mat::VV1 + decoder_mat::VV2 + data_mean::VV3 + retain_kl::FT + apply_to::Union{Nothing, AbstractString} + iters::VV4 + grad_type::Symbol + use_data_as_samples::Bool +end + +""" +$(TYPEDSIGNATURES) + +Constructs the `LikelihoodInformed` struct. Keywords: +- `retain_kl`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - retain_kl). Choose `retain_kl` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. +- `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution ∝ π_prior(x) π_likelihood(y | x)^α with α ∈ [0, 1]. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. +- `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). +- `use_data_as_samples`[=false]: if this parameter is `true`, then the data being processed (the training data for the emulator) will be used as the samples mentioned earlier. This means that they must be from the correct distribution corresponding to the chosen `alpha`. If this parameter is `false`, then the method expects `:samples_in` and `:samples_out` structure vectors that contain the samples instead. +""" +function likelihood_informed(; retain_kl = 1, iters=1, grad_type = :linreg, use_data_as_samples = false) + if grad_type ∉ [:linreg, :localsl] + @error "Unknown grad_type=$grad_type" + end + if !isa(iters, AbstractVector) + iters=[iters] + end + if !(eltype(iters) <: Integer) + throw(ArgumentError, "Iterations must be passed as an Int or Vec{Int}. This corresponds to which of the structure-vectors are used to construct the subspace") + end + + LikelihoodInformed([], [], [], retain_kl, nothing, iters, grad_type, use_data_as_samples) +end + +get_encoder_mat(li::LikelihoodInformed) = li.encoder_mat +get_decoder_mat(li::LikelihoodInformed) = li.decoder_mat +get_data_mean(li::LikelihoodInformed) = li.data_mean +get_retain_kl(li::LikelihoodInformed) = li.retain_kl +get_iters(li::LikelihoodInformed) = li.iters +get_grad_type(li::LikelihoodInformed) = li.grad_type + +function Base.show(io::IO, li::LikelihoodInformed) + out = "LikelihoodInformed" + out *= ": iters=$(get_iters(li)), grad_type=$(get_grad_type(li))" + if get_retain_kl(li) < 1.0 + out *= ", retain_kl=$(get_retain_kl(li))" + end + print(io, out) +end + +function initialize_processor!( + li::LikelihoodInformed, + in_data::MM, + out_data::MM, + ::Dict{Symbol, SM1}, + output_structure_matrices::Dict{Symbol, SM2}, + input_structure_vectors::Dict{Symbol, SV1}, + output_structure_vectors::Dict{Symbol, SV2}, + apply_to::AS, +) where {MM <: AbstractMatrix, SM1 <:StructureMatrix, SM2 <: StructureMatrix, SV1 <: StructureVector, SV2 <: StructureVector, AS <: AbstractString} + input_dim = size(in_data, 1) + output_dim = size(out_data, 1) + + + if length(get_encoder_mat(li))==0 + iters = get_iters(li) + alphas = get_structure_vec(input_structure_vectors, :dt) + @info "Constructing a likelihood-informed subspace using, \n iterations:$(get_iters(li)), \n α: $(alphas[iters]) " + diagnostic_mats = Dict{Int64, AbstractMatrix}() + samples_means = Dict{Int64, AbstractMatrix}() + diagnostic_fs = [] + diagnostic_egrads = [] + + obs_noise_cov = Matrix(get_structure_mat(output_structure_matrices, :obs_noise_cov)) + # We convert this to a matrix here to avoid dealing with LinearMaps.jl + obs_whitened = if obs_noise_cov ≈ I + obs_noise_cov = I(output_dim) + true + else + @warn "Consider using decorrelate_structure_mat to gain obs_noise_cov = I before calling likelihood_informed" + false + end + noise_cov_inv = inv(obs_noise_cov) + + li.apply_to = apply_to + + for (it, α) in zip(iters, alphas[iters]) # take the iterations from alpha + #(NB! "it" may not be 1:end) + + # construct the diagnostic matrix, for which we take the eigendecomposition to find encoder/decoder matrices + y = if α ≈ 0.0 + # For α=0, it doesn't matter what this value is, so we avoid requiring its presence + zeros(size(out_data, 1)) + else + vec(get_structure_vec(output_structure_vectors, :observation)[1]) + end + + # take samples from the appropriate distribution as prescribed by alpha + samples_in, samples_out = if li.use_data_as_samples + (in_data, out_data) + else + ( + get_structure_vec(input_structure_vectors, :samples_in)[it], + get_structure_vec(output_structure_vectors, :samples_out)[it], + ) + end + samples_in_mean = mean(samples_in,dims=2) + samples_out_mean = mean(samples_out,dims=2) + + grads = if get_grad_type(li) == :linreg + grad = (samples_out .- samples_out_mean) / (samples_in .- samples_in_mean) + fill(grad, size(samples_in, 2)) + else + @assert get_grad_type(li) == :localsl + + map(eachcol(samples_in)) do u + # TODO: It might be interesting to introduce a parameter to weight this distance with. + # This can be a scalar or a matrix; in the latter case, we can even use the covariance + # of the samples (or the prior covariance). + weights = exp.(-1 / 2 * norm.(eachcol(u .- samples_in)) .^ 2) + weights ./= sum(weights) + D = Diagonal(sqrt.(weights)) + uw = (samples_in .- sum(samples_in * Diagonal(weights); dims = 2)) * D + gw = (samples_out .- sum(samples_out * Diagonal(weights); dims = 2)) * D + gw / uw + end + end + + # get the mean shift + samples_means[it] = if apply_to == "in" + samples_in_mean + else + samples_out_mean + end + + + # get the diagnostics: + # either we get the mats to be truncated, + # or we find the functions & gradients when matrix-free + # if apply_to == "in" || (α ≈ 0 && obs_whitened) #if we keep this branch then we have to possibly combine diagnostic mats and f's + if apply_to == "in" + diagnostic_mats[it] = hermitianpart( + mean( + grad' * + noise_cov_inv * + ((1 - α)*obs_noise_cov + α^2 * (y - g) * (y - g)') * + noise_cov_inv * + grad for (g, grad) in zip(eachcol(samples_out), grads) + ), + ) + #elseif apply_to == "out" && (α ≈ 0 && obs_whitened) + # if we keep this branch then we get an annoying cross-problem where we have to combine both diagnostic mats and diagnostic f's. So we can make them both "f's" for now + # diagnostic_mats[it] = hermitianpart(mean(grad * grad' for grad in grads)) + else + # @assert apply_to == "out" && !(α ≈ 0 && obs_whitened) + @assert apply_to == "out" + # Need to represent the "f" and "egrad" functions for this α + f = + (_, Vs) -> begin + prec = noise_cov_inv - Vs * inv(Vs' * obs_noise_cov * Vs) * Vs' + tr( + mean( + grad' * prec * ((1 - α)obs_noise_cov + α^2 * (y - g) * (y - g)') * prec * grad + for (g, grad) in zip(eachcol(out_data), grads) + ), + ) + end + egrad = + (_, Vs) -> begin + B = Vs * inv(Vs' * obs_noise_cov * Vs) * Vs' + prec = noise_cov_inv - B + + -2obs_noise_cov * prec * mean( + begin + A = ((1 - α)obs_noise_cov + α^2 * (y - g) * (y - g)') + S = grad * grad' + (S * prec * A + A * prec * S) + end for (g, grad) in zip(eachcol(out_data), grads) + ) * + B * + Vs + end + push!(diagnostic_fs, f) + push!(diagnostic_egrads, egrad) + end + + end + + # summarize path of diagnostic matrices, if we have more than one + encoder_mat=nothing + if length(keys(diagnostic_mats))>0 # using diagnostic_mats + if length(iters)>1 + # trap rule + alpha_weight = zeros(length(iters)) + Δa=diff(alphas[iters]) + alpha_weight[1:end-1] .+= Δa ./ 2 + alpha_weight[2:end] .+= Δa ./ 2 + alpha_weight ./= sum(alpha_weight) + diagnostic_mat = sum(alpha_weight[i]*diagnostic_mats[iter] for (i,iter) in enumerate(iters[2:end])) + samples_mean = sum(alpha_weight[i]*samples_means[iter] for (i,iter) in enumerate(iters[2:end])) + else + diagnostic_mat = diagnostic_mats[iters[1]] + samples_mean = samples_means[iters[1]] + end + + # then get the eigen-decomposition + decomp = eigen(diagnostic_mat, sortby = (-)) + sv_cumsum = cumsum(decomp.values) / sum(decomp.values) + retain_kl = get_retain_kl(li) + if retain_kl >= 1.0 + trunc_val = apply_to == "in" ? input_dim : output_dim + + else + trunc_val = findfirst(x -> (x ≥ retain_kl), sv_cumsum) + trunc_val = isnothing(trunc_val) ? (apply_to == "in" ? input_dim : output_dim) : trunc_val + @info " truncating at $trunc_val/$(length(sv_cumsum)) retaining $(100.0*sv_cumsum[trunc_val])% of the KL divergence reduction" + end + encoder_mat = decomp.vectors[:, 1:trunc_val]' + else # using diagnostic_f's and diagnostic_egrads + @assert length(diagnostic_fs)>0 && length(diagnostic_egrads)>0 + @assert apply_to == "out" + + diagnostic_f, diagnostic_egrad, samples_mean = + if length(iters)>1 + method="trap_rule" + if method == "trap_rule" + + alpha_weight = zeros(length(iters)) + Δa=diff(alphas[iters]) + alpha_weight[1:end-1] .+= Δa ./ 2 + alpha_weight[2:end] .+= Δa ./ 2 + alpha_weight ./= sum(alpha_weight) + diagnostic_f = (x,Vs) -> sum(w * f(x,Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) + diagnostic_egrad = (x,Vs) -> sum(w * egrad(x,Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) + samples_mean = sum(alpha_weight[i]*samples_means[iter] for (i,iter) in enumerate(iters[2:end])) + + diagnostic_f, diagnostic_egrad, samples_mean + elseif method == "final" + diagnostic_f = diagnostic_fs[end] + diagnostic_egrad = diagnostic_egrads[end] + samples_mean = samples_means[iters[end]] + + diagnostic_f, diagnostic_egrad, samples_mean + end + else + diagnostic_f = diagnostic_fs[1] + diagnostic_egrad = diagnostic_egrads[1] + samples_mean = samples_means[iters[1]] + + diagnostic_f, diagnostic_egrad, samples_mean + end + + @warn "Using LikelihoodInformed on output data with α≠0 or with obs_noise_cov≠I triggers a manifold optimization process that may take some time. If α=0, consider using decorrelate_structure_mat to gain obs_noise_cov = I before calling likelihood_informed" + + k = 1 + Vs = nothing + retain_kl = get_retain_kl(li) + while true + M = Grassmann(output_dim, k) + + diagnostic_rgrad = (M, Vs) -> begin + (I - Vs * Vs') * diagnostic_egrad(M, Vs) + end + + Vs = Matrix(qr(randn(output_dim, k)).Q) + quasi_Newton!(M, diagnostic_f, diagnostic_rgrad, Vs; stopping_criterion = StopWhenCostChangeLess(0.1)) + + + ref = diagnostic_f(M, zeros(output_dim, 0)) + val = diagnostic_f(M, Vs) + if val / ref ≤ 1 - retain_kl + @info " truncating at $k/$output_dim retaining $(100.0*(1-val/ref))% of the KL divergence reduction" + break # TODO: Start bisecting? + else + newk = min(2k, output_dim) + @info " increasing k from $k to $newk" + k = newk + end + + end + + encoder_mat = Vs' # setting encoder mat + + end + decoder_mat = encoder_mat' + + # creat the linear maps: + # we explicitly make the encoder/decoder maps + encoder_map = LinearMap( + x -> encoder_mat * x, # Ax + x -> encoder_mat' * x, # A'x + size(encoder_mat, 1), # size(A,1) + size(encoder_mat, 2), # size(A,2) + ) + + decoder_map = LinearMap( + x -> decoder_mat * x, # Ax + x -> decoder_mat' * x, # A'x + size(decoder_mat, 1), # size(A,1) + size(decoder_mat, 2), # size(A,2) + ) + + push!(get_encoder_mat(li), encoder_map) + push!(get_decoder_mat(li), decoder_map) + + push!(get_data_mean(li), vec(samples_mean)) + + end + +end + +""" +$(TYPEDSIGNATURES) + +Apply the `LikelihoodInformed` encoder, on a columns-are-data matrix +""" +function encode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} + data_mean = get_data_mean(li)[1] + encoder_mat = get_encoder_mat(li)[1] + out = zeros(size(encoder_mat, 1), size(data, 2)) + mul!(out, encoder_mat, data .- data_mean) + return out +end + +""" +$(TYPEDSIGNATURES) + +Apply the `LikelihoodInformed` decoder, on a columns-are-data matrix +""" +function decode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} + data_mean = get_data_mean(li)[1] + decoder_mat = get_decoder_mat(li)[1] + out = zeros(size(decoder_mat, 1), size(data, 2)) + mul!(out, decoder_mat, data) # must use this form to get matrix output of dec*out + return out .+ data_mean +end + +""" +$(TYPEDSIGNATURES) + +Apply the `LikelihoodInformed` encoder to a provided structure matrix +""" +function encode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} + encoder_mat = get_encoder_mat(li)[1] + return encoder_mat * structure_matrix * encoder_mat' +end + +""" +$(TYPEDSIGNATURES) + +Apply the `LikelihoodInformed` decoder to a provided structure matrix +""" +function decode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} + decoder_mat = get_decoder_mat(li)[1] + return decoder_mat * structure_matrix * decoder_mat' +end From 5108db95d55ae2f13135adb7dac49334142f8b30 Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 8 Apr 2026 10:57:07 -0700 Subject: [PATCH 02/36] rm linlinexp --- .../{calibrate_linlinexp.jl => calibrate.jl} | 16 ++++++-- ..._sample_linlinexp.jl => emulate_sample.jl} | 38 ++++++++++++------ examples/DimensionReduction/models.jl | 40 +++++++++++-------- 3 files changed, 61 insertions(+), 33 deletions(-) rename examples/DimensionReduction/{calibrate_linlinexp.jl => calibrate.jl} (82%) rename examples/DimensionReduction/{emulate_sample_linlinexp.jl => emulate_sample.jl} (82%) diff --git a/examples/DimensionReduction/calibrate_linlinexp.jl b/examples/DimensionReduction/calibrate.jl similarity index 82% rename from examples/DimensionReduction/calibrate_linlinexp.jl rename to examples/DimensionReduction/calibrate.jl index ac68b9b00..77326a58e 100644 --- a/examples/DimensionReduction/calibrate_linlinexp.jl +++ b/examples/DimensionReduction/calibrate.jl @@ -5,6 +5,10 @@ using LinearAlgebra using Random include("./models.jl") +# select the forward map +mod_types=["linear"] +mod_type = mod_types[1] +@info "Executing model type $(mod_type)" datadir = joinpath(@__DIR__,"datafiles") if !isdir(datadir) @@ -18,12 +22,16 @@ output_dim = 100 num_trials = 5 for trial in 1:num_trials @info "Trial $trial" - - prior_cov, y, obs_noise_cov, model, true_parameter = linlinexp(input_dim, output_dim, rng) + if mod_type == "linear" + prior_cov, y, obs_noise_cov, model, true_parameter = lin(input_dim, output_dim, rng) + else + bad_model(mod_type, mod_types) + end + prior_obj = ParameterDistribution( Parameterized(MvNormal(zeros(size(prior_cov, 1)), prior_cov)), fill(no_constraint(), size(prior_cov, 1)), - "linlinexp_prior", + "$(mod_type)_prior", ) n_ensemble = 50 @@ -58,7 +66,7 @@ for trial in 1:num_trials #! format: off save( - joinpath(datadir,"ekp_linlinexp_$(trial).jld2"), + joinpath(datadir,"ekp_$(mod_type)_$(trial).jld2"), "ekpobj", ekp, "ekp_samples", ekp_samples, "prior_obj", prior_obj, diff --git a/examples/DimensionReduction/emulate_sample_linlinexp.jl b/examples/DimensionReduction/emulate_sample.jl similarity index 82% rename from examples/DimensionReduction/emulate_sample_linlinexp.jl rename to examples/DimensionReduction/emulate_sample.jl index cafd8609c..f817fdea1 100644 --- a/examples/DimensionReduction/emulate_sample_linlinexp.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -13,6 +13,10 @@ using CalibrateEmulateSample.Utilities include("./models.jl") +# select the forward map +mod_types=["linear"] +mod_type = mod_types[1] +@info "Executing model type $(mod_type)" rng = Random.MersenneTwister(41) input_dim = 100 @@ -20,7 +24,7 @@ output_dim = 100 num_trials = 1 for trial in 1:num_trials - loaded = load("datafiles/ekp_linlinexp_$(trial).jld2") + loaded = load("datafiles/ekp_$(mod_type)_$(trial).jld2") ekpobj = loaded["ekpobj"] ekp_samples = loaded["ekp_samples"] prior = loaded["prior_obj"] @@ -36,8 +40,8 @@ for trial in 1:num_trials encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] - rvs = collect(0.975:0.0125:1.0) - rkls = collect(0.999:0.0005:1.0) + rvs = [0.9, 0.94, 0.98, 0.99, 0.995, 0.999] + rkls = rvs all_errs = zeros(length(rvs), 1 + length(αs)) # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor @@ -48,7 +52,13 @@ for trial in 1:num_trials names = ["reference", "decorrelate, PCA-in", ["decorrelate, LI-in 1:$(i)" for i in 1:length(αs)]...] - ni_scaling = 0.01 # noise injection into null space scaling (def. 1) + if mod_type=="linear" + ni_scaling = 0.01 # noise injection into null space scaling (def. 1) + else + bad_model(mod_type, mod_types) + end + + reduced_dims = zeros(Int, length(rvs), length(αs)+2) # store reduced dims for final table for (idx, (rv, rkl)) in enumerate(zip(rvs, rkls)) encoder_schedule_decorrelate = [ @@ -58,10 +68,10 @@ for trial in 1:num_trials encoder_schedules_li = [ [ (decorrelate_structure_mat(), "in_and_out"), - (likelihood_informed(retain_kl=rkl, iters=1:i), "in"), + (likelihood_informed(retain_info=rkl, iters=1:i), "in"), ] for i in 1:length(αs) ] - + em_ref = forward_map_wrapper( param -> forward_map(param, model), prior, @@ -90,20 +100,21 @@ for trial in 1:num_trials noise_injector_scaling=ni_scaling, ) for encoder_schedule in encoder_schedules_li ] - post_means = reshape(true_parameter, input_dim, 1) post_covs = [] - - for (nn, em) in zip(names,vcat(em_ref, em_decorrelate, ems_li...)) + for (iidx, nn, em) in zip(1:length(names), names,vcat(em_ref, em_decorrelate, ems_li...)) + + reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em),"in") println(" ") @info "Encoding name: $(nn)" E,_ = get_encoder_from_schedule(get_encoder_schedule(em), "in") + if isnothing(E) @info "No truncation" else - + ed = get_encoded_dim(get_encoder_schedule(em),"in") @info "Truncation criteria (var>$(rv), or kl > $(rkl))" - @info "input dim reduced to: $(size(E,1))" + @info "input dim reduced to: $(ed)" end println(" ") @@ -134,7 +145,10 @@ for trial in 1:num_trials # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) all_errs[idx, :] = [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' - end + end @info "error of posterior mean to whitened \"reference\" solution. for $(names[2:end])" display(all_errs) + @info "... and their reduced dimensions" + display(reduced_dims[:,2:end]) + end diff --git a/examples/DimensionReduction/models.jl b/examples/DimensionReduction/models.jl index e083faeac..074eec0d7 100644 --- a/examples/DimensionReduction/models.jl +++ b/examples/DimensionReduction/models.jl @@ -7,12 +7,22 @@ using EnsembleKalmanProcesses.ParameterDistributions abstract type ForwardMapType end -## Linear-times-exponential model -function linlinexp(input_dim, output_dim, rng) +function bad_model_type(mod_type, mod_types) + throw(ArgumentError("Unknown model type provided: $(mod_type), please choose from $(mod_types)")) +end + +## Linear +struct Lin{AM <: AbstractMatrix} <: ForwardMapType + input_dim::Int + output_dim::Int + G::AM +end + +function lin(input_dim, output_dim, rng) # prior γ0 = 4.0 β_γ = -2 - Γ = Diagonal([γ0 * (1.0 * j)^β_γ for j in 1:input_dim]) + prior_cov = Diagonal([γ0 * (1.0 * j)^β_γ for j in 1:input_dim]) U = qr(randn(rng, (output_dim, output_dim))).Q V = qr(randn(rng, (input_dim, input_dim))).Q @@ -20,31 +30,27 @@ function linlinexp(input_dim, output_dim, rng) β_λ = -1 Λ = Diagonal([λ0 * (1.0 * j)^β_λ for j in 1:output_dim]) A = U * Λ * V[1:output_dim, :] # output x input - model = LinLinExp(input_dim, output_dim, A) + model = Lin(input_dim, output_dim, A) # generate data sample obs_noise_cov = Diagonal([Float64(j)^(-1 / 2) for j in 1:output_dim]) noise = rand(rng, MvNormal(zeros(output_dim), obs_noise_cov)) # true_parameter = reshape(ones(input_dim), :, 1) - true_parameter = rand(rng, MvNormal(zeros(input_dim), Γ)) + true_parameter = rand(rng, MvNormal(zeros(input_dim), prior_cov)) y = vec(forward_map(true_parameter, model) + noise) - return Γ, y, obs_noise_cov, model, true_parameter + return prior_cov, y, obs_noise_cov, model, true_parameter end -struct LinLinExp{AM <: AbstractMatrix} <: ForwardMapType - input_dim::Int - output_dim::Int - G::AM +function forward_map(X::AVorM, model::Lin) where {AVorM <: AbstractVecOrMat} + return model.G * X end -function forward_map(X::AVorM, model::LinLinExp) where {AVorM <: AbstractVecOrMat} - return model.G * (X .* exp.(0.05X)) +function jac_forward_map(X::AbstractVector, model::Lin) + return model.G end -function jac_forward_map(X::AbstractVector, model::LinLinExp) - return model.G * Diagonal(exp.(0.05X) .* (1 .+ 0.05X)) -end - -function jac_forward_map(X::AbstractMatrix, model::LinLinExp) +function jac_forward_map(X::AbstractMatrix, model::Lin) return [jac_forward_map(x, model) for x in eachcol(X)] end + + From 8103bef9db3a526c47f9bb350573ba6e8b593ad0 Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 8 Apr 2026 10:59:10 -0700 Subject: [PATCH 03/36] truncate based on relative log^2(1+li) not li itself --- src/Utilities/likelihood_informed.jl | 47 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index 79f500f78..d13adbd80 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -18,7 +18,7 @@ mutable struct LikelihoodInformed{VV1<:AbstractVector, VV2<:AbstractVector, VV3< encoder_mat::VV1 decoder_mat::VV2 data_mean::VV3 - retain_kl::FT + retain_info::FT apply_to::Union{Nothing, AbstractString} iters::VV4 grad_type::Symbol @@ -29,12 +29,12 @@ end $(TYPEDSIGNATURES) Constructs the `LikelihoodInformed` struct. Keywords: -- `retain_kl`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - retain_kl). Choose `retain_kl` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. +- `retain_info`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - retain_info). Choose `retain_info` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. - `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution ∝ π_prior(x) π_likelihood(y | x)^α with α ∈ [0, 1]. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. - `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). - `use_data_as_samples`[=false]: if this parameter is `true`, then the data being processed (the training data for the emulator) will be used as the samples mentioned earlier. This means that they must be from the correct distribution corresponding to the chosen `alpha`. If this parameter is `false`, then the method expects `:samples_in` and `:samples_out` structure vectors that contain the samples instead. """ -function likelihood_informed(; retain_kl = 1, iters=1, grad_type = :linreg, use_data_as_samples = false) +function likelihood_informed(; retain_info = 1, iters=1, grad_type = :linreg, use_data_as_samples = false) if grad_type ∉ [:linreg, :localsl] @error "Unknown grad_type=$grad_type" end @@ -45,21 +45,21 @@ function likelihood_informed(; retain_kl = 1, iters=1, grad_type = :linreg, use_ throw(ArgumentError, "Iterations must be passed as an Int or Vec{Int}. This corresponds to which of the structure-vectors are used to construct the subspace") end - LikelihoodInformed([], [], [], retain_kl, nothing, iters, grad_type, use_data_as_samples) + LikelihoodInformed([], [], [], retain_info, nothing, iters, grad_type, use_data_as_samples) end get_encoder_mat(li::LikelihoodInformed) = li.encoder_mat get_decoder_mat(li::LikelihoodInformed) = li.decoder_mat get_data_mean(li::LikelihoodInformed) = li.data_mean -get_retain_kl(li::LikelihoodInformed) = li.retain_kl +get_retain_info(li::LikelihoodInformed) = li.retain_info get_iters(li::LikelihoodInformed) = li.iters get_grad_type(li::LikelihoodInformed) = li.grad_type function Base.show(io::IO, li::LikelihoodInformed) out = "LikelihoodInformed" out *= ": iters=$(get_iters(li)), grad_type=$(get_grad_type(li))" - if get_retain_kl(li) < 1.0 - out *= ", retain_kl=$(get_retain_kl(li))" + if get_retain_info(li) < 1.0 + out *= ", retain_info=$(get_retain_info(li))" end print(io, out) end @@ -164,12 +164,11 @@ function initialize_processor!( grad for (g, grad) in zip(eachcol(samples_out), grads) ), ) - #elseif apply_to == "out" && (α ≈ 0 && obs_whitened) - # if we keep this branch then we get an annoying cross-problem where we have to combine both diagnostic mats and diagnostic f's. So we can make them both "f's" for now - # diagnostic_mats[it] = hermitianpart(mean(grad * grad' for grad in grads)) + elseif apply_to == "out" && (α ≈ 0 && obs_whitened) && (length(alphas[iters]) == 1) # special case for output space (whitened and prior-only distribution) + diagnostic_mats[it] = hermitianpart(mean(grad * grad' for grad in grads)) else - # @assert apply_to == "out" && !(α ≈ 0 && obs_whitened) - @assert apply_to == "out" + # @assert apply_to == "out" && ( !(α ≈ 0 && obs_whitened) || length(alphas[iters]) > 1 ) + @assert apply_to == "out" # Need to represent the "f" and "egrad" functions for this α f = (_, Vs) -> begin @@ -196,15 +195,17 @@ function initialize_processor!( B * Vs end + push!(diagnostic_fs, f) - push!(diagnostic_egrads, egrad) + push!(diagnostic_egrads, egrad) + end end # summarize path of diagnostic matrices, if we have more than one encoder_mat=nothing - if length(keys(diagnostic_mats))>0 # using diagnostic_mats + if length(keys(diagnostic_mats))>0 # using diagnostic_mats if length(iters)>1 # trap rule alpha_weight = zeros(length(iters)) @@ -221,15 +222,15 @@ function initialize_processor!( # then get the eigen-decomposition decomp = eigen(diagnostic_mat, sortby = (-)) - sv_cumsum = cumsum(decomp.values) / sum(decomp.values) - retain_kl = get_retain_kl(li) - if retain_kl >= 1.0 + sv_cumsum = cumsum(log.(decomp.values .+ 1).^2)/sum(log.(decomp.values .+ 1).^2) # frac Forstner distance-based cutoff + trunc_val=nothing + retain_info = get_retain_info(li) + if retain_info >= 1.0 trunc_val = apply_to == "in" ? input_dim : output_dim - - else - trunc_val = findfirst(x -> (x ≥ retain_kl), sv_cumsum) + else + trunc_val = findfirst(x -> (x ≥ retain_info), sv_cumsum) trunc_val = isnothing(trunc_val) ? (apply_to == "in" ? input_dim : output_dim) : trunc_val - @info " truncating at $trunc_val/$(length(sv_cumsum)) retaining $(100.0*sv_cumsum[trunc_val])% of the KL divergence reduction" + @info " truncating at $trunc_val/$(length(sv_cumsum)) retaining $(100.0*sv_cumsum[trunc_val])% of the information" end encoder_mat = decomp.vectors[:, 1:trunc_val]' else # using diagnostic_f's and diagnostic_egrads @@ -270,7 +271,7 @@ function initialize_processor!( k = 1 Vs = nothing - retain_kl = get_retain_kl(li) + retain_info = get_retain_info(li) while true M = Grassmann(output_dim, k) @@ -284,7 +285,7 @@ function initialize_processor!( ref = diagnostic_f(M, zeros(output_dim, 0)) val = diagnostic_f(M, Vs) - if val / ref ≤ 1 - retain_kl + if val / ref ≤ 1 - retain_info @info " truncating at $k/$output_dim retaining $(100.0*(1-val/ref))% of the KL divergence reduction" break # TODO: Start bisecting? else From 9374aadc7d1c83205abc2c475abc94f2f86453ba Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 8 Apr 2026 11:22:53 -0700 Subject: [PATCH 04/36] add docs manifest --- docs/Manifest.toml | 719 +++++++++++++++++++++++++++++++-------------- 1 file changed, 499 insertions(+), 220 deletions(-) diff --git a/docs/Manifest.toml b/docs/Manifest.toml index 188bad891..d68467ce5 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -1,13 +1,13 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.11.5" +julia_version = "1.12.0" manifest_format = "2.0" -project_hash = "e4d965798d55f5903483b71f545533e62ea32fdf" +project_hash = "5255fc92659f2799f0f4c5144942145e13d951ed" [[deps.ADTypes]] -git-tree-sha1 = "8be2ae325471fc20b11c27bb34b518541d07dd3a" +git-tree-sha1 = "f7304359109c768cf32dc5fa2d371565bb63b68a" uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -version = "1.19.0" +version = "1.21.0" [deps.ADTypes.extensions] ADTypesChainRulesCoreExt = "ChainRulesCore" @@ -48,21 +48,53 @@ uuid = "99985d1d-32ba-4be9-9821-2ec096f28918" version = "0.5.24" [[deps.AbstractMCMC]] -deps = ["BangBang", "ConsoleProgressMonitor", "Distributed", "LogDensityProblems", "Logging", "LoggingExtras", "ProgressLogging", "Random", "StatsBase", "TerminalLoggers", "Transducers"] -git-tree-sha1 = "87e63dcb990029346b091b170252f3c416568afc" +deps = ["BangBang", "ConsoleProgressMonitor", "Dates", "Distributed", "FillArrays", "LogDensityProblems", "Logging", "LoggingExtras", "ProgressLogging", "Random", "StatsBase", "TerminalLoggers", "Transducers", "UUIDs"] +git-tree-sha1 = "511d0d8cbf38045be05188ae26880afb57342a88" uuid = "80f14c24-f653-4e6a-9b94-39d6b0f70001" -version = "4.4.2" +version = "5.14.0" + + [deps.AbstractMCMC.extensions] + AbstractMCMCOnlineStatsExt = "OnlineStats" + AbstractMCMCTensorBoardLoggerExt = "TensorBoardLogger" + + [deps.AbstractMCMC.weakdeps] + OnlineStats = "a15396b6-48d5-5d58-9928-6d29437db91e" + TensorBoardLogger = "899adc3e-224a-11e9-021f-63837185c80f" [[deps.AbstractTrees]] git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" version = "0.4.5" +[[deps.Accessors]] +deps = ["CompositionsBase", "ConstructionBase", "Dates", "InverseFunctions", "MacroTools"] +git-tree-sha1 = "2eeb2c9bef11013efc6f8f97f32ee59b146b09fb" +uuid = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +version = "0.1.44" + + [deps.Accessors.extensions] + AxisKeysExt = "AxisKeys" + IntervalSetsExt = "IntervalSets" + LinearAlgebraExt = "LinearAlgebra" + StaticArraysExt = "StaticArrays" + StructArraysExt = "StructArrays" + TestExt = "Test" + UnitfulExt = "Unitful" + + [deps.Accessors.weakdeps] + AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5" + IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + [[deps.Adapt]] deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "7e35fca2bdfba44d797c53dfe63a51fabf39bfc0" +git-tree-sha1 = "35ea197a51ce46fcd01c4a44befce0578a1aaeca" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.4.0" +version = "4.5.0" weakdeps = ["SparseArrays", "StaticArrays"] [deps.Adapt.extensions] @@ -70,10 +102,10 @@ weakdeps = ["SparseArrays", "StaticArrays"] AdaptStaticArraysExt = "StaticArrays" [[deps.AdvancedMH]] -deps = ["AbstractMCMC", "Distributions", "FillArrays", "LinearAlgebra", "LogDensityProblems", "Random", "Requires"] -git-tree-sha1 = "b2a1602952739e589cf5e2daff1274a49f22c9a4" +deps = ["AbstractMCMC", "Distributions", "DocStringExtensions", "FillArrays", "LinearAlgebra", "LogDensityProblems", "Random", "Requires"] +git-tree-sha1 = "62ddbccf0ce5c26f8ef3cebe4bedef6b1599d616" uuid = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170" -version = "0.7.5" +version = "0.8.10" [deps.AdvancedMH.extensions] AdvancedMHForwardDiffExt = ["DiffResults", "ForwardDiff"] @@ -101,6 +133,12 @@ version = "2.5.0" uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" version = "1.1.2" +[[deps.ArnoldiMethod]] +deps = ["LinearAlgebra", "Random", "StaticArrays"] +git-tree-sha1 = "d57bd3762d308bded22c3b82d033bff85f6195c6" +uuid = "ec485272-7323-5ecc-a04f-4719b315124d" +version = "0.4.0" + [[deps.Arpack]] deps = ["Arpack_jll", "Libdl", "LinearAlgebra", "Logging"] git-tree-sha1 = "9b9b347613394885fd1c8c7729bfc60528faa436" @@ -108,18 +146,19 @@ uuid = "7d9fca2a-8960-54d3-9f78-7d1dccf2cb97" version = "0.5.4" [[deps.Arpack_jll]] -deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "OpenBLAS_jll", "Pkg"] -git-tree-sha1 = "5ba6c757e8feccf03a1554dfaf3e26b3cfc7fd5e" +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "libblastrampoline_jll"] +git-tree-sha1 = "7f54761502ff149a9d492e4acefe9805898e29b3" uuid = "68821587-b530-5797-8361-c406ea357684" -version = "3.5.1+1" +version = "3.5.2+0" [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "d81ae5489e13bc03567d4fbbb06c546a5e53c857" +git-tree-sha1 = "78b3a7a536b4b0a747a0f296ea77091ca0a9f9a3" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.22.0" +version = "7.23.0" [deps.ArrayInterface.extensions] + ArrayInterfaceAMDGPUExt = "AMDGPU" ArrayInterfaceBandedMatricesExt = "BandedMatrices" ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" ArrayInterfaceCUDAExt = "CUDA" @@ -134,6 +173,7 @@ version = "7.22.0" ArrayInterfaceTrackerExt = "Tracker" [deps.ArrayInterface.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" BandedMatrices = "aae01518-5342-5314-be14-df237901396f" BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" @@ -164,16 +204,17 @@ uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9" version = "0.4.8" [[deps.BangBang]] -deps = ["Compat", "ConstructionBase", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables"] -git-tree-sha1 = "7aa7ad1682f3d5754e3491bb59b8103cae28e3a3" +deps = ["Accessors", "ConstructionBase", "InitialValues", "LinearAlgebra"] +git-tree-sha1 = "cceb62468025be98d42a5dc581b163c20896b040" uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" -version = "0.3.40" +version = "0.4.9" [deps.BangBang.extensions] BangBangChainRulesCoreExt = "ChainRulesCore" BangBangDataFramesExt = "DataFrames" BangBangStaticArraysExt = "StaticArrays" BangBangStructArraysExt = "StructArrays" + BangBangTablesExt = "Tables" BangBangTypedTablesExt = "TypedTables" [deps.BangBang.weakdeps] @@ -181,6 +222,7 @@ version = "0.3.40" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" + Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" [[deps.Base64]] @@ -194,9 +236,9 @@ version = "0.1.1" [[deps.BenchmarkTools]] deps = ["Compat", "JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] -git-tree-sha1 = "7fecfb1123b8d0232218e2da0c213004ff15358d" +git-tree-sha1 = "6876e30dc02dc69f0613cb6ece242144f2ca9e56" uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -version = "1.6.3" +version = "1.7.0" [[deps.BitTwiddlingConvenienceFunctions]] deps = ["Static"] @@ -218,15 +260,15 @@ version = "0.2.7" [[deps.Cairo_jll]] deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "fde3bf89aead2e723284a8ff9cdf5b551ed700e8" +git-tree-sha1 = "a21c5464519504e41e0cbc91f0188e8ca23d7440" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.18.5+0" +version = "1.18.5+1" [[deps.CalibrateEmulateSample]] -deps = ["AbstractGPs", "AbstractMCMC", "AdvancedMH", "ChunkSplitters", "Conda", "Distributions", "DocStringExtensions", "EnsembleKalmanProcesses", "ForwardDiff", "GaussianProcesses", "KernelFunctions", "LinearAlgebra", "LinearMaps", "LowRankApprox", "MCMCChains", "Pkg", "Printf", "ProgressBars", "PyCall", "Random", "RandomFeatures", "ReverseDiff", "ScikitLearn", "StableRNGs", "Statistics", "StatsBase", "TSVD"] +deps = ["AbstractGPs", "AbstractMCMC", "AdvancedMH", "ChunkSplitters", "Conda", "Distributions", "DocStringExtensions", "EnsembleKalmanProcesses", "ForwardDiff", "GaussianProcesses", "KernelFunctions", "LinearAlgebra", "LinearMaps", "LowRankApprox", "MCMCChains", "Manifolds", "Manopt", "Pkg", "Printf", "ProgressBars", "PyCall", "Random", "RandomFeatures", "ReverseDiff", "ScikitLearn", "StableRNGs", "Statistics", "StatsBase", "TSVD"] path = ".." uuid = "95e48a1f-0bec-4818-9538-3db4340308e3" -version = "0.7.0" +version = "1.0.0" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] @@ -239,9 +281,9 @@ weakdeps = ["SparseArrays"] ChainRulesCoreSparseArraysExt = "SparseArrays" [[deps.ChunkSplitters]] -git-tree-sha1 = "63a3903063d035260f0f6eab00f517471c5dc784" +git-tree-sha1 = "1c52c8e2673edc030191177ff1aee42d25149acb" uuid = "ae650224-84b6-46f8-82ea-d812ca08434e" -version = "3.1.2" +version = "3.2.0" [[deps.CloseOpenIntervals]] deps = ["Static", "StaticArrayInterface"] @@ -261,6 +303,38 @@ git-tree-sha1 = "962834c22b66e32aa10f7611c08c8ca4e20749a9" uuid = "944b1d66-785c-5afd-91f1-9de20f533193" version = "0.7.8" +[[deps.ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] +git-tree-sha1 = "b0fd3f56fa442f81e0a47815c92245acfaaa4e34" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.31.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "67e11ee83a43eb71ddc950302c53bf33f0690dfe" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.12.1" +weakdeps = ["StyledStrings"] + + [deps.ColorTypes.extensions] + StyledStringsExt = "StyledStrings" + +[[deps.ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] +git-tree-sha1 = "8b3b6f87ce8f65a2b4f857528fd8d70086cd72b1" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.11.0" +weakdeps = ["SpecialFunctions"] + + [deps.ColorVectorSpace.extensions] + SpecialFunctionsExt = "SpecialFunctions" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "37ea44092930b1811e666c3bc38065d7d87fcc74" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.13.1" + [[deps.CommonSubexpressions]] deps = ["MacroTools"] git-tree-sha1 = "cda2cfaebb4be89c9084adaca7dd7333369715c5" @@ -285,7 +359,7 @@ weakdeps = ["Dates", "LinearAlgebra"] [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.1.1+0" +version = "1.3.0+1" [[deps.CompositionsBase]] git-tree-sha1 = "802bb88cd69dfd1509f6670416bd4434015693ad" @@ -321,9 +395,9 @@ weakdeps = ["IntervalSets", "LinearAlgebra", "StaticArrays"] [[deps.Convex]] deps = ["AbstractTrees", "BenchmarkTools", "LDLFactorizations", "LinearAlgebra", "MathOptInterface", "OrderedCollections", "SparseArrays", "Test"] -git-tree-sha1 = "dec769959be3af9ba94970b1f14b31c196b0fb9e" +git-tree-sha1 = "b42f0670988b3ee7bfcf0d9ff0f9243a2736963f" uuid = "f65535da-76fb-5f13-bab9-19810c17039a" -version = "0.16.4" +version = "0.16.5" [[deps.CpuId]] deps = ["Markdown"] @@ -382,9 +456,9 @@ version = "1.15.1" [[deps.DifferentiationInterface]] deps = ["ADTypes", "LinearAlgebra"] -git-tree-sha1 = "80bd15222b3e8d0bc70d921d2201aa0084810ce5" +git-tree-sha1 = "7ae99144ea44715402c6c882bfef2adbeadbc4ce" uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" -version = "0.7.12" +version = "0.7.16" [deps.DifferentiationInterface.extensions] DifferentiationInterfaceChainRulesCoreExt = "ChainRulesCore" @@ -448,9 +522,9 @@ version = "1.11.0" [[deps.Distributions]] deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] -git-tree-sha1 = "3bc002af51045ca3b47d2e1787d6ce02e68b943a" +git-tree-sha1 = "fbcc7610f6d8348428f722ecbe0e6cfe22e672c6" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.122" +version = "0.25.123" [deps.Distributions.extensions] DistributionsChainRulesCoreExt = "ChainRulesCore" @@ -491,10 +565,10 @@ uuid = "2904ab23-551e-5aed-883f-487f97af5226" version = "0.2.4" [[deps.EnsembleKalmanProcesses]] -deps = ["Convex", "Distributions", "DocStringExtensions", "FFMPEG", "GaussianRandomFields", "Interpolations", "LinearAlgebra", "MathOptInterface", "Optim", "QuadGK", "Random", "RecipesBase", "SCS", "SparseArrays", "Statistics", "StatsBase", "TOML", "TSVD"] -git-tree-sha1 = "52faab1c57dac15c161f60f0c1d94ebb110ea3c8" +deps = ["Convex", "Distributions", "DocStringExtensions", "FFMPEG", "GaussianRandomFields", "Interpolations", "LinearAlgebra", "MathOptInterface", "Optim", "QuadGK", "Random", "RecipesBase", "SCS", "SparseArrays", "Statistics", "StatsBase", "TOML"] +git-tree-sha1 = "bb39ccc7bd5f7e8f078a987820044d85d61df72b" uuid = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" -version = "2.6.0" +version = "2.7.0" [deps.EnsembleKalmanProcesses.extensions] EnsembleKalmanProcessesMakieExt = "Makie" @@ -503,9 +577,9 @@ version = "2.6.0" Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" [[deps.EnumX]] -git-tree-sha1 = "bddad79635af6aec424f53ed8aad5d7555dc6f00" +git-tree-sha1 = "c49898e8438c828577f04b92fc9368c388ac783c" uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" -version = "1.0.5" +version = "1.0.7" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -520,10 +594,16 @@ uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" version = "0.4.5" [[deps.FFMPEG_jll]] -deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "ccc81ba5e42497f4e76553a5545665eed577a663" +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libva_jll", "libvorbis_jll", "x264_jll", "x265_jll"] +git-tree-sha1 = "66381d7059b5f3f6162f28831854008040a4e905" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "8.0.0+0" +version = "8.0.1+1" + +[[deps.FFTA]] +deps = ["AbstractFFTs", "DocStringExtensions", "LinearAlgebra", "MuladdMacro", "Primes", "Random", "Reexport"] +git-tree-sha1 = "65e55303b72f4a567a51b174dd2c47496efeb95a" +uuid = "b86e33f2-c0db-4aa1-a6e0-ab43e668529e" +version = "0.3.1" [[deps.FFTW]] deps = ["AbstractFFTs", "FFTW_jll", "Libdl", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] @@ -539,9 +619,9 @@ version = "3.3.11+0" [[deps.FastGaussQuadrature]] deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] -git-tree-sha1 = "58d83dd5a78a36205bdfddb82b1bb67682e64487" +git-tree-sha1 = "0044e9f5e49a57e88205e8f30ab73928b05fe5b6" uuid = "442a2c76-b920-505d-bb47-c5924d526838" -version = "0.4.9" +version = "1.1.0" [[deps.FileWatching]] uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" @@ -549,14 +629,15 @@ version = "1.11.0" [[deps.FillArrays]] deps = ["LinearAlgebra"] -git-tree-sha1 = "5bfcd42851cf2f1b303f51525a54dc5e98d408a3" +git-tree-sha1 = "2f979084d1e13948a3352cf64a25df6bd3b4dca3" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" -version = "1.15.0" -weakdeps = ["PDMats", "SparseArrays", "Statistics"] +version = "1.16.0" +weakdeps = ["PDMats", "SparseArrays", "StaticArrays", "Statistics"] [deps.FillArrays.extensions] FillArraysPDMatsExt = "PDMats" FillArraysSparseArraysExt = "SparseArrays" + FillArraysStaticArraysExt = "StaticArrays" FillArraysStatisticsExt = "Statistics" [[deps.FiniteDiff]] @@ -577,23 +658,23 @@ version = "2.29.0" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +[[deps.FixedPointNumbers]] +deps = ["Statistics"] +git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" +uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +version = "0.8.5" + [[deps.Fontconfig_jll]] deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Zlib_jll"] git-tree-sha1 = "f85dac9a96a01087df6e3a749840015a0ca3817d" uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" version = "2.17.1+0" -[[deps.Formatting]] -deps = ["Logging", "Printf"] -git-tree-sha1 = "fb409abab2caf118986fc597ba84b50cbaf00b87" -uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" -version = "0.4.3" - [[deps.ForwardDiff]] deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] -git-tree-sha1 = "afb7c51ac63e40708a3071f80f5e84a752299d4f" +git-tree-sha1 = "cddeab6487248a39dae1a960fff0ac17b2a28888" uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.39" +version = "1.3.3" weakdeps = ["StaticArrays"] [deps.ForwardDiff.extensions] @@ -601,9 +682,9 @@ weakdeps = ["StaticArrays"] [[deps.FreeType2_jll]] deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "2c5512e11c791d1baed2049c5652441b28fc6a31" +git-tree-sha1 = "70329abc09b886fd2c5d94ad2d9527639c421e3e" uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" -version = "2.13.4+0" +version = "2.14.3+1" [[deps.FriBidi_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -629,9 +710,9 @@ version = "1.11.0" [[deps.GaussianProcesses]] deps = ["Distances", "Distributions", "ElasticArrays", "ElasticPDMats", "FastGaussQuadrature", "ForwardDiff", "LinearAlgebra", "Optim", "PDMats", "Printf", "ProgressMeter", "Random", "RecipesBase", "ScikitLearnBase", "SpecialFunctions", "StaticArrays", "Statistics", "StatsFuns"] -git-tree-sha1 = "31749ff6868caf6dd50902eec652a724071dbed3" +git-tree-sha1 = "d983b4e1ff0257ed7c51686e6a63926551884373" uuid = "891a1506-143c-57d2-908e-e1f8e92e6de9" -version = "0.12.5" +version = "0.12.6" [[deps.GaussianRandomFields]] deps = ["Arpack", "FFTW", "FastGaussQuadrature", "LinearAlgebra", "Random", "RecipesBase", "SpecialFunctions", "Statistics", "StatsBase"] @@ -659,15 +740,20 @@ version = "3.7.0+0" [[deps.Git_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "b6a684587ebe896d9f68ae777f648205940f0f70" +git-tree-sha1 = "dc34a3e3d96b4ed305b641e626dc14c12b7824b8" uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" -version = "2.51.3+0" +version = "2.53.0+0" [[deps.Glib_jll]] deps = ["Artifacts", "GettextRuntime_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "50c11ffab2a3d50192a228c313f05b5b5dc5acb2" +git-tree-sha1 = "24f6def62397474a297bfcec22384101609142ed" uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" -version = "2.86.0+0" +version = "2.86.3+0" + +[[deps.Glossaries]] +git-tree-sha1 = "60a11a815b6113e7024157c31a77a75619d97a23" +uuid = "8f48dd54-e453-4cdc-9500-53b96149560b" +version = "0.1.1" [[deps.Graphite2_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -675,6 +761,12 @@ git-tree-sha1 = "8a6dbda1fd736d60cc477d99f2e7a042acfa46e8" uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" version = "1.3.15+0" +[[deps.Graphs]] +deps = ["ArnoldiMethod", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] +git-tree-sha1 = "7a98c6502f4632dbe9fb1973a4244eaa3324e84d" +uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" +version = "1.13.1" + [[deps.HarfBuzz_jll]] deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll"] git-tree-sha1 = "f923f9a774fcf3f5cb761bfa43aeadd689714813" @@ -682,10 +774,16 @@ uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" version = "8.5.1+0" [[deps.HostCPUFeatures]] -deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] -git-tree-sha1 = "8e070b599339d622e9a081d17230d74a5c473293" +deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Preferences", "Static"] +git-tree-sha1 = "af9ab7d1f70739a47f03be78771ebda38c3c71bf" uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" -version = "0.1.17" +version = "0.1.18" + +[[deps.HypergeometricFunctions]] +deps = ["LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] +git-tree-sha1 = "68c173f4f449de5b438ee67ed0c9c748dc31a2ec" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.28" [[deps.IOCapture]] deps = ["Logging", "Random"] @@ -698,6 +796,11 @@ git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" version = "0.1.1" +[[deps.Inflate]] +git-tree-sha1 = "d1b1b796e47d94588b3757fe84fbf65a5ec4a80d" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.5" + [[deps.InitialValues]] git-tree-sha1 = "4da0f88e9a39111c2fa3add390ab15f3a44f3ca3" uuid = "22cec73e-a1b8-11e9-2c92-598750a2cf9c" @@ -716,6 +819,11 @@ version = "1.4.5" ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +[[deps.IntegerMathUtils]] +git-tree-sha1 = "4c1acff2dc6b6967e7e750633c50bc3b8d83e617" +uuid = "18e54dd8-cb9d-406c-a71d-865a43cbb235" +version = "0.1.3" + [[deps.IntelOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] git-tree-sha1 = "ec1debd61c300961f98064cfb21287613ad7f303" @@ -728,25 +836,26 @@ uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" version = "1.11.0" [[deps.Interpolations]] -deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] -git-tree-sha1 = "88a101217d7cb38a7b481ccd50d21876e1d1b0e0" +deps = ["Adapt", "AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] +git-tree-sha1 = "65d505fa4c0d7072990d659ef3fc086eb6da8208" uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" -version = "0.15.1" +version = "0.16.2" [deps.Interpolations.extensions] + InterpolationsForwardDiffExt = "ForwardDiff" InterpolationsUnitfulExt = "Unitful" [deps.Interpolations.weakdeps] + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" [[deps.IntervalSets]] -git-tree-sha1 = "03b4f40b4987baa6a653a21f6f33f902af6255f3" +git-tree-sha1 = "d966f85b3b7a8e49d034d27a189e9a4874b4391a" uuid = "8197267c-284f-5f27-9208-e0e47529a953" -version = "0.7.12" -weakdeps = ["Printf", "Random", "RecipesBase", "Statistics"] +version = "0.7.13" +weakdeps = ["Random", "RecipesBase", "Statistics"] [deps.IntervalSets.extensions] - IntervalSetsPrintfExt = "Printf" IntervalSetsRandomExt = "Random" IntervalSetsRecipesBaseExt = "RecipesBase" IntervalSetsStatisticsExt = "Statistics" @@ -767,9 +876,9 @@ uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" version = "1.3.1" [[deps.IrrationalConstants]] -git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151" +git-tree-sha1 = "b2d91fe939cae05960e760110b328288867b5758" uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" -version = "0.1.1" +version = "0.2.6" [[deps.IterTools]] git-tree-sha1 = "42d5f897009e7ff2cf88db414a389e5ed1bdd023" @@ -789,9 +898,9 @@ version = "1.7.1" [[deps.JSON]] deps = ["Dates", "Logging", "Parsers", "PrecompileTools", "StructUtils", "UUIDs", "Unicode"] -git-tree-sha1 = "5b6bb73f555bc753a6153deec3717b8904f5551c" +git-tree-sha1 = "b3ad4a0255688dcb895a52fafbaae3023b588a90" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "1.3.0" +version = "1.4.0" [deps.JSON.extensions] JSONArrowExt = ["ArrowTypes"] @@ -799,29 +908,28 @@ version = "1.3.0" [deps.JSON.weakdeps] ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" -[[deps.JSON3]] -deps = ["Dates", "Mmap", "Parsers", "PrecompileTools", "StructTypes", "UUIDs"] -git-tree-sha1 = "411eccfe8aba0814ffa0fdf4860913ed09c34975" -uuid = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" -version = "1.14.3" - - [deps.JSON3.extensions] - JSON3ArrowExt = ["ArrowTypes"] - - [deps.JSON3.weakdeps] - ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" +[[deps.JuliaSyntaxHighlighting]] +deps = ["StyledStrings"] +uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" +version = "1.12.0" [[deps.KernelDensity]] -deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] -git-tree-sha1 = "ba51324b894edaf1df3ab16e2cc6bc3280a2f1a7" +deps = ["Distributions", "DocStringExtensions", "FFTA", "Interpolations", "StatsBase"] +git-tree-sha1 = "4260cfc991b8885bf747801fb60dd4503250e478" uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" -version = "0.6.10" +version = "0.6.11" [[deps.KernelFunctions]] deps = ["ChainRulesCore", "Compat", "CompositionsBase", "Distances", "FillArrays", "Functors", "IrrationalConstants", "LinearAlgebra", "LogExpFunctions", "Random", "Requires", "SpecialFunctions", "Statistics", "StatsBase", "TensorCore", "Test", "ZygoteRules"] -git-tree-sha1 = "0b75b447ee242254ff037402461e5593a84f9ac7" +git-tree-sha1 = "9db545feadff48ec2da8216f589857e7a619df84" uuid = "ec8451be-7e33-11e9-00cf-bbf324bd1392" -version = "0.10.66" +version = "0.10.67" + +[[deps.Kronecker]] +deps = ["LinearAlgebra", "NamedDims", "SparseArrays", "StatsBase"] +git-tree-sha1 = "9253429e28cceae6e823bec9ffde12460d79bb38" +uuid = "2c470bb0-bcc8-11e8-3dad-c9649493f05e" +version = "0.5.5" [[deps.LAME_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -831,9 +939,9 @@ version = "3.100.3+0" [[deps.LDLFactorizations]] deps = ["AMD", "LinearAlgebra", "SparseArrays", "Test"] -git-tree-sha1 = "70f582b446a1c3ad82cf87e62b878668beef9d13" +git-tree-sha1 = "d75c5cb8d6ac9c359ae9eb8e87e446ba9f221dd4" uuid = "40e66cde-538c-5869-a4ad-c39174c6795b" -version = "0.10.1" +version = "0.10.2" [[deps.LLVMOpenMP_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -880,24 +988,24 @@ uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.4" [[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.6.0+0" +version = "8.11.1+1" [[deps.LibGit2]] -deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" version = "1.11.0" [[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.7.2+0" +version = "1.9.0+0" [[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +deps = ["Artifacts", "Libdl", "OpenSSL_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.0+1" +version = "1.11.3+1" [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" @@ -917,26 +1025,26 @@ version = "1.18.0+0" [[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "3acf07f130a76f87c041cfb2ff7d7284ca67b072" +git-tree-sha1 = "97bbca976196f2a1eb9607131cb108c69ec3f8a6" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.41.2+0" +version = "2.41.3+0" [[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "2a7a12fc0a4e7fb773450d17975322aa77142106" +git-tree-sha1 = "d0205286d9eceadc518742860bf23f703779a3d6" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.41.2+0" +version = "2.41.3+0" [[deps.LineSearches]] -deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] -git-tree-sha1 = "4adee99b7262ad2a1a4bbbc59d993d24e55ea96f" +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Printf"] +git-tree-sha1 = "9ea3422d03222c6de679934d1c08f0a99405aa03" uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" -version = "7.4.0" +version = "7.5.1" [[deps.LinearAlgebra]] deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -version = "1.11.0" +version = "1.12.0" [[deps.LinearMaps]] deps = ["LinearAlgebra"] @@ -1016,16 +1124,16 @@ weakdeps = ["FillArrays"] LowRankMatricesFillArraysExt = "FillArrays" [[deps.MCMCChains]] -deps = ["AbstractMCMC", "AxisArrays", "Dates", "Distributions", "Formatting", "IteratorInterfaceExtensions", "KernelDensity", "LinearAlgebra", "MCMCDiagnosticTools", "MLJModelInterface", "NaturalSort", "OrderedCollections", "PrettyTables", "Random", "RecipesBase", "Serialization", "Statistics", "StatsBase", "StatsFuns", "TableTraits", "Tables"] -git-tree-sha1 = "c659f7508035a7bdd5102aef2de028ab035f289a" +deps = ["AbstractMCMC", "AxisArrays", "DataAPI", "Dates", "Distributions", "IteratorInterfaceExtensions", "KernelDensity", "LinearAlgebra", "MCMCDiagnosticTools", "MLJModelInterface", "NaturalSort", "OrderedCollections", "PrettyTables", "Random", "RecipesBase", "Statistics", "StatsBase", "StatsFuns", "TableTraits", "Tables"] +git-tree-sha1 = "060d6bc7cf60e621dfd056ed2c1a2db1e68db0fe" uuid = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" -version = "5.7.1" +version = "7.7.0" [[deps.MCMCDiagnosticTools]] -deps = ["AbstractFFTs", "DataAPI", "DataStructures", "Distributions", "LinearAlgebra", "MLJModelInterface", "Random", "SpecialFunctions", "Statistics", "StatsBase", "Tables"] -git-tree-sha1 = "d1737c39191aa26f42a64e320de313f1d1fd74b1" +deps = ["AbstractFFTs", "DataAPI", "DataStructures", "Distributions", "LinearAlgebra", "MLJModelInterface", "Random", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Tables"] +git-tree-sha1 = "526c98cd41028da22c01cb8a203246799ad853a8" uuid = "be115224-59cd-429b-ad48-344e309966f0" -version = "0.2.1" +version = "0.3.15" [[deps.MKL_jll]] deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] @@ -1035,47 +1143,132 @@ version = "2025.2.0+0" [[deps.MLJModelInterface]] deps = ["InteractiveUtils", "REPL", "Random", "ScientificTypesBase", "StatisticalTraits"] -git-tree-sha1 = "ccaa3f7938890ee8042cc970ba275115428bd592" +git-tree-sha1 = "c275fae2e693206b4527dd9d2382aa15359ef3ed" uuid = "e80e1ace-859a-464e-9ed9-23947d8ae3ea" -version = "1.12.0" +version = "1.12.1" [[deps.MacroTools]] git-tree-sha1 = "1e0228a030642014fe5cfe68c2c0a818f9e3f522" uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" version = "0.5.16" +[[deps.ManifoldDiff]] +deps = ["ADTypes", "DifferentiationInterface", "LinearAlgebra", "ManifoldsBase", "Markdown", "Random", "Requires"] +git-tree-sha1 = "28c69b401c75dd3f3b34a39bb7cb7948a2aeb61d" +uuid = "af67fdf4-a580-4b9f-bbec-742ef357defd" +version = "0.4.5" + + [deps.ManifoldDiff.weakdeps] + FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" + FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.Manifolds]] +deps = ["ADTypes", "DifferentiationInterface", "Graphs", "Kronecker", "LinearAlgebra", "ManifoldDiff", "ManifoldsBase", "Markdown", "MatrixEquations", "Quaternions", "Random", "SimpleWeightedGraphs", "SpecialFunctions", "StaticArrays", "Statistics", "StatsBase", "Tullio"] +git-tree-sha1 = "b4ad952229f66fa7c1fe37efb15b20ce59290e44" +uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" +version = "0.11.20" + + [deps.Manifolds.extensions] + ManifoldsBoundaryValueDiffEqExt = "BoundaryValueDiffEq" + ManifoldsDistributionsExt = ["Distributions", "RecursiveArrayTools"] + ManifoldsHybridArraysExt = "HybridArrays" + ManifoldsNLsolveExt = "NLsolve" + ManifoldsOrdinaryDiffEqDiffEqCallbacksExt = ["DiffEqCallbacks", "OrdinaryDiffEq", "RecursiveArrayTools"] + ManifoldsOrdinaryDiffEqExt = "OrdinaryDiffEq" + ManifoldsRecipesBaseExt = ["Colors", "RecipesBase"] + ManifoldsRecursiveArrayToolsExt = "RecursiveArrayTools" + ManifoldsTestExt = "Test" + + [deps.Manifolds.weakdeps] + BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d" + Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" + DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" + Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" + HybridArrays = "1baab800-613f-4b0a-84e4-9cd3431bfbb9" + NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" + OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" + RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" + RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.ManifoldsBase]] +deps = ["LinearAlgebra", "Markdown", "Printf", "Random"] +git-tree-sha1 = "c96ad9c0d0d5b182c6a6398486f04c13b8fe7d25" +uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" +version = "2.3.4" + + [deps.ManifoldsBase.extensions] + ManifoldsBasePlotsExt = "Plots" + ManifoldsBaseQuaternionsExt = "Quaternions" + ManifoldsBaseRecursiveArrayToolsExt = "RecursiveArrayTools" + ManifoldsBaseStatisticsExt = "Statistics" + + [deps.ManifoldsBase.weakdeps] + Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" + Quaternions = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0" + RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" + Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" + +[[deps.Manopt]] +deps = ["ColorSchemes", "ColorTypes", "Colors", "DataStructures", "Dates", "Glossaries", "LinearAlgebra", "ManifoldDiff", "ManifoldsBase", "Markdown", "Preferences", "Printf", "Random", "SparseArrays", "Statistics"] +git-tree-sha1 = "c3a8ad10124613c0325c0f9c46fe66e575bfc974" +uuid = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5" +version = "0.5.34" + + [deps.Manopt.extensions] + ManoptJuMPExt = "JuMP" + ManoptLRUCacheExt = "LRUCache" + ManoptLineSearchesExt = "LineSearches" + ManoptManifoldsExt = "Manifolds" + ManoptRecursiveArrayToolsExt = "RecursiveArrayTools" + ManoptRipQPQuadraticModelsExt = ["RipQP", "QuadraticModels"] + + [deps.Manopt.weakdeps] + JuMP = "4076af6c-e467-56ae-b986-b466b2749572" + LRUCache = "8ac3fa9e-de4c-5943-b1dc-09c6b5f20637" + LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" + Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" + Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" + QuadraticModels = "f468eda6-eac5-11e8-05a5-ff9e497bcd19" + RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" + RipQP = "1e40b3f8-35eb-4cd8-8edd-3e515bb9de08" + [[deps.ManualMemory]] git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" version = "0.1.8" [[deps.Markdown]] -deps = ["Base64"] +deps = ["Base64", "JuliaSyntaxHighlighting", "StyledStrings"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" version = "1.11.0" [[deps.MarkdownAST]] deps = ["AbstractTrees", "Markdown"] -git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" +git-tree-sha1 = "93c718d892e73931841089cdc0e982d6dd9cc87b" uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" -version = "0.1.2" +version = "0.1.3" [[deps.MathOptInterface]] -deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON3", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] -git-tree-sha1 = "a2cbab4256690aee457d136752c404e001f27768" +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] +git-tree-sha1 = "ce739e3d8a21313ea418772edfc3b7b15a1dfc16" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" -version = "1.46.0" +version = "1.50.1" -[[deps.MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" -version = "2.28.6+0" +[[deps.MatrixEquations]] +deps = ["LinearAlgebra", "LinearMaps"] +git-tree-sha1 = "51f3fade0b4ff2cf90b36b3312425460631abb56" +uuid = "99c1a7ee-ab34-5fd5-8076-27c950a045f4" +version = "2.5.6" [[deps.MicroCollections]] -deps = ["BangBang", "InitialValues", "Setfield"] -git-tree-sha1 = "629afd7d10dbc6935ec59b32daeb33bc4460a42e" +deps = ["Accessors", "BangBang", "InitialValues"] +git-tree-sha1 = "44d32db644e84c75dab479f1bc15ee76a1a3618f" uuid = "128add7d-3638-4c79-886c-908ea0c25c34" -version = "0.1.4" +version = "0.2.0" [[deps.Missings]] deps = ["DataAPI"] @@ -1089,13 +1282,18 @@ version = "1.11.0" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2023.12.12" +version = "2025.5.20" + +[[deps.MuladdMacro]] +git-tree-sha1 = "cac9cc5499c25554cba55cd3c30543cff5ca4fab" +uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +version = "0.2.4" [[deps.MutableArithmetics]] deps = ["LinearAlgebra", "SparseArrays", "Test"] -git-tree-sha1 = "22df8573f8e7c593ac205455ca088989d0a2c7a0" +git-tree-sha1 = "7c25249fc13a070f5ba433c50e21e22bb33c6fb0" uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" -version = "1.6.7" +version = "1.7.1" [[deps.NLSolversBase]] deps = ["ADTypes", "DifferentiationInterface", "Distributed", "FiniteDiff", "ForwardDiff"] @@ -1109,6 +1307,25 @@ git-tree-sha1 = "9b8215b1ee9e78a293f99797cd31375471b2bcae" uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" version = "1.1.3" +[[deps.NamedDims]] +deps = ["LinearAlgebra", "Statistics"] +git-tree-sha1 = "f9e4a49ecd1ea2eccfb749a506fa882c094152b4" +uuid = "356022a1-0364-5f58-8944-0da4b18d706f" +version = "1.2.3" + + [deps.NamedDims.extensions] + AbstractFFTsExt = "AbstractFFTs" + ChainRulesCoreExt = "ChainRulesCore" + CovarianceEstimationExt = "CovarianceEstimation" + TrackerExt = "Tracker" + + [deps.NamedDims.weakdeps] + AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + CovarianceEstimation = "587fd27a-f159-11e8-2dae-1979310e6154" + Requires = "ae029012-a4dd-5104-9daa-d747884805df" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + [[deps.NaturalSort]] git-tree-sha1 = "eda490d06b9f7c00752ee81cfa451efe55521e21" uuid = "c020b1a1-e9b0-503a-9c33-f039bfc54a85" @@ -1116,7 +1333,7 @@ version = "1.0.0" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.2.0" +version = "1.3.0" [[deps.Nullables]] git-tree-sha1 = "8f87854cc8f3685a60689d8edecaa29d2251979b" @@ -1140,19 +1357,19 @@ version = "1.3.6+0" [[deps.OpenBLAS32_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "ece4587683695fe4c5f20e990da0ed7e83c351e7" +git-tree-sha1 = "46cce8b42186882811da4ce1f4c7208b02deb716" uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.29+0" +version = "0.3.30+0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.27+1" +version = "0.3.29+0" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.5+0" +version = "0.8.7+0" [[deps.OpenSSH_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll", "Zlib_jll"] @@ -1161,10 +1378,9 @@ uuid = "9bd350c2-7e96-507f-8002-3f2e150b4e1b" version = "10.2.1+0" [[deps.OpenSSL_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "f19301ae653233bc88b1810ae908194f07f8db9d" +deps = ["Artifacts", "Libdl"] uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.5.4+0" +version = "3.5.1+0" [[deps.OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] @@ -1174,9 +1390,9 @@ version = "0.5.6+0" [[deps.Optim]] deps = ["Compat", "EnumX", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] -git-tree-sha1 = "61942645c38dd2b5b78e2082c9b51ab315315d10" +git-tree-sha1 = "48968edaf014f67e58fe4c8a4ce72d392aed3294" uuid = "429524aa-4258-5aef-a3af-852621145aeb" -version = "1.13.2" +version = "1.13.3" weakdeps = ["MathOptInterface"] [deps.Optim.extensions] @@ -1184,9 +1400,9 @@ weakdeps = ["MathOptInterface"] [[deps.Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "c392fc5dd032381919e3b22dd32d6443760ce7ea" +git-tree-sha1 = "e2bb57a313a74b8104064b7efd01406c0a50d2ff" uuid = "91d4177d-7536-5919-b921-800302f37372" -version = "1.5.2+0" +version = "1.6.1+0" [[deps.OrderedCollections]] git-tree-sha1 = "05868e21324cede2207c6f0f466b4bfef6d5e7ee" @@ -1196,7 +1412,7 @@ version = "1.8.1" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.42.0+1" +version = "10.44.0+1" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -1225,7 +1441,7 @@ version = "0.44.2+0" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -version = "1.11.0" +version = "1.12.0" weakdeps = ["REPL"] [deps.Pkg.extensions] @@ -1251,21 +1467,33 @@ version = "0.2.4" [[deps.PrecompileTools]] deps = ["Preferences"] -git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +git-tree-sha1 = "07a921781cab75691315adc645096ed5e370cb77" uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" -version = "1.2.1" +version = "1.3.3" [[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "0f27480397253da18fe2c12a4ba4eb9eb208bf3d" +git-tree-sha1 = "8b770b60760d4451834fe79dd483e318eee709c4" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.5.0" +version = "1.5.2" [[deps.PrettyTables]] -deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] -git-tree-sha1 = "1101cd475833706e4d0e7b122218257178f48f34" +deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "REPL", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "624de6279ab7d94fc9f672f0068107eb6619732c" uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" -version = "2.4.0" +version = "3.3.2" + + [deps.PrettyTables.extensions] + PrettyTablesTypstryExt = "Typstry" + + [deps.PrettyTables.weakdeps] + Typstry = "f0ed7684-a786-439e-b1e3-3b82803b501e" + +[[deps.Primes]] +deps = ["IntegerMathUtils"] +git-tree-sha1 = "25cdd1d20cd005b52fc12cb6be3f75faaf59bb9b" +uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae" +version = "0.5.7" [[deps.Printf]] deps = ["Unicode"] @@ -1273,6 +1501,7 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" version = "1.11.0" [[deps.Profile]] +deps = ["StyledStrings"] uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" version = "1.11.0" @@ -1284,9 +1513,9 @@ version = "1.5.1" [[deps.ProgressLogging]] deps = ["Logging", "SHA", "UUIDs"] -git-tree-sha1 = "d95ed0324b0799843ac6f7a6a85e65fe4e5173f0" +git-tree-sha1 = "f0803bc1171e455a04124affa9c21bba5ac4db32" uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" -version = "0.1.5" +version = "0.1.6" [[deps.ProgressMeter]] deps = ["Distributed", "Printf"] @@ -1295,9 +1524,9 @@ uuid = "92933f4c-e287-5a05-a399-4b506db050ca" version = "1.11.0" [[deps.PtrArrays]] -git-tree-sha1 = "1d36ef11a9aaf1e8b74dacc6a731dd1de8fd493d" +git-tree-sha1 = "4fbbafbc6251b883f4d2705356f3641f3652a7fe" uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" -version = "1.3.0" +version = "1.4.0" [[deps.PyCall]] deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] @@ -1317,8 +1546,14 @@ version = "2.11.2" [deps.QuadGK.weakdeps] Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" +[[deps.Quaternions]] +deps = ["LinearAlgebra", "Random", "RealDot"] +git-tree-sha1 = "4d8c1b7c3329c1885b857abb50d08fa3f4d9e3c8" +uuid = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0" +version = "0.7.7" + [[deps.REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "StyledStrings", "Unicode"] +deps = ["InteractiveUtils", "JuliaSyntaxHighlighting", "Markdown", "Sockets", "StyledStrings", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" version = "1.11.0" @@ -1343,12 +1578,16 @@ deps = ["Requires"] git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b" uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" version = "0.4.5" +weakdeps = ["FixedPointNumbers"] [deps.Ratios.extensions] RatiosFixedPointNumbersExt = "FixedPointNumbers" - [deps.Ratios.weakdeps] - FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +[[deps.RealDot]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "9f0a1b71baaf7650f4fa8a1d168c7fb6ee41f0c9" +uuid = "c1ae055f-0cd5-4b69-90a6-9a35b1a98df9" +version = "0.1.0" [[deps.RecipesBase]] deps = ["PrecompileTools"] @@ -1375,27 +1614,27 @@ version = "1.3.1" [[deps.ReverseDiff]] deps = ["ChainRulesCore", "DiffResults", "DiffRules", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NaNMath", "Random", "SpecialFunctions", "StaticArrays", "Statistics"] -git-tree-sha1 = "3ab8eee3620451b09f0272c271875b4bc02146d9" +git-tree-sha1 = "f1b07322a8cdc0d46812473b37fb72f69ec07b22" uuid = "37e2e3b7-166d-5795-8a7a-e32c996b4267" -version = "1.16.1" +version = "1.16.2" [[deps.Rmath]] deps = ["Random", "Rmath_jll"] -git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b" +git-tree-sha1 = "5b3d50eb374cea306873b371d3f8d3915a018f0b" uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" -version = "0.7.1" +version = "0.9.0" [[deps.Rmath_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "e60724fd3beea548353984dc61c943ecddb0e29a" +git-tree-sha1 = "58cdd8fb2201a6267e1db87ff148dd6c1dbd8ad8" uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" -version = "0.4.3+0" +version = "0.5.1+0" [[deps.SCS]] deps = ["LinearAlgebra", "MathOptInterface", "OpenBLAS32_jll", "PrecompileTools", "SCS_jll", "SparseArrays"] -git-tree-sha1 = "48ec3c39787bc7b278789b9af17c157ea8774dae" +git-tree-sha1 = "cd27f0cfefd06c7b2bd0343e08edbd9a3d2e1869" uuid = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" -version = "2.4.0" +version = "2.6.3" [deps.SCS.extensions] SCSSCS_GPU_jllExt = ["SCS_GPU_jll"] @@ -1407,9 +1646,9 @@ version = "2.4.0" [[deps.SCS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl", "libblastrampoline_jll"] -git-tree-sha1 = "05d6e31efa3debae6618dabee35dbd53cf4539d8" +git-tree-sha1 = "f7864fb125fc5eb61fa2f2c5738623be0b986edd" uuid = "f4f2fc5b-1d94-523c-97ea-2ab488bedf4b" -version = "300.200.900+0" +version = "300.200.1100+0" [[deps.SHA]] uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" @@ -1427,14 +1666,15 @@ uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" version = "0.6.43" [[deps.SciMLPublic]] -git-tree-sha1 = "ed647f161e8b3f2973f24979ec074e8d084f1bee" +git-tree-sha1 = "0ba076dbdce87ba230fff48ca9bca62e1f345c9b" uuid = "431bcebd-1456-4ced-9d72-93c2757fff0b" -version = "1.0.0" +version = "1.0.1" [[deps.ScientificTypesBase]] -git-tree-sha1 = "a8e18eb383b5ecf1b5e6fc237eb39255044fd92b" +deps = ["InteractiveUtils"] +git-tree-sha1 = "e785eaa35a0f5518a388f9010e66fda64ea95ede" uuid = "30f210dd-8aff-4c5f-94ba-8e64358c1161" -version = "3.0.0" +version = "3.1.0" [[deps.ScikitLearn]] deps = ["Compat", "Conda", "DataFrames", "Distributed", "IterTools", "LinearAlgebra", "MacroTools", "Parameters", "Printf", "PyCall", "Random", "ScikitLearnBase", "SparseArrays", "StatsBase", "VersionParsing"] @@ -1450,9 +1690,9 @@ version = "0.5.0" [[deps.SentinelArrays]] deps = ["Dates", "Random"] -git-tree-sha1 = "712fb0231ee6f9120e005ccd56297abbc053e7e0" +git-tree-sha1 = "ebe7e59b37c400f694f52b58c93d26201387da70" uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" -version = "1.4.8" +version = "1.4.9" [[deps.Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" @@ -1469,6 +1709,18 @@ deps = ["Distributed", "Mmap", "Random", "Serialization"] uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" version = "1.11.0" +[[deps.SimpleTraits]] +deps = ["InteractiveUtils", "MacroTools"] +git-tree-sha1 = "be8eeac05ec97d379347584fa9fe2f5f76795bcb" +uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" +version = "0.9.5" + +[[deps.SimpleWeightedGraphs]] +deps = ["Graphs", "LinearAlgebra", "Markdown", "SparseArrays"] +git-tree-sha1 = "749a2b719ec7f34f280c0d97ac3dab5c89818631" +uuid = "47aef6b3-ad0c-573a-a1e2-d07658019622" +version = "1.5.1" + [[deps.Sockets]] uuid = "6462fe0b-24de-5631-8697-dd941f90decc" version = "1.11.0" @@ -1482,13 +1734,13 @@ version = "1.2.2" [[deps.SparseArrays]] deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -version = "1.11.0" +version = "1.12.0" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] -git-tree-sha1 = "f2685b435df2613e25fc10ad8c26dddb8640f547" +git-tree-sha1 = "2700b235561b0335d5bef7097a111dc513b8655e" uuid = "276daf66-3868-5448-9aa4-cd146d93841b" -version = "2.6.1" +version = "2.7.2" weakdeps = ["ChainRulesCore"] [deps.SpecialFunctions.extensions] @@ -1513,10 +1765,10 @@ uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" version = "1.3.1" [[deps.StaticArrayInterface]] -deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "Static"] -git-tree-sha1 = "96381d50f1ce85f2663584c8e886a6ca97e60554" +deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "SciMLPublic", "Static"] +git-tree-sha1 = "aa1ea41b3d45ac449d10477f65e2b40e3197a0d2" uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718" -version = "1.8.0" +version = "1.9.0" weakdeps = ["OffsetArrays", "StaticArrays"] [deps.StaticArrayInterface.extensions] @@ -1525,9 +1777,9 @@ weakdeps = ["OffsetArrays", "StaticArrays"] [[deps.StaticArrays]] deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] -git-tree-sha1 = "b8693004b385c842357406e3af647701fe783f98" +git-tree-sha1 = "246a8bb2e6667f832eea063c3a56aef96429a3db" uuid = "90137ffa-7385-5640-81b9-e52037218182" -version = "1.9.15" +version = "1.9.18" weakdeps = ["ChainRulesCore", "Statistics"] [deps.StaticArrays.extensions] @@ -1557,9 +1809,9 @@ weakdeps = ["SparseArrays"] [[deps.StatsAPI]] deps = ["LinearAlgebra"] -git-tree-sha1 = "9d72a13a3f4dd3795a195ac5a44d7d6ff5f552ff" +git-tree-sha1 = "178ed29fd5b2a2cfc3bd31c13375ae925623ff36" uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" -version = "1.7.1" +version = "1.8.0" [[deps.StatsBase]] deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] @@ -1568,35 +1820,36 @@ uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" version = "0.33.21" [[deps.StatsFuns]] -deps = ["ChainRulesCore", "InverseFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] -git-tree-sha1 = "5950925ff997ed6fb3e985dcce8eb1ba42a0bbe7" +deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "91f091a8716a6bb38417a6e6f274602a19aaa685" uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" -version = "0.9.18" +version = "1.5.2" +weakdeps = ["ChainRulesCore", "InverseFunctions"] + + [deps.StatsFuns.extensions] + StatsFunsChainRulesCoreExt = "ChainRulesCore" + StatsFunsInverseFunctionsExt = "InverseFunctions" [[deps.StringManipulation]] deps = ["PrecompileTools"] -git-tree-sha1 = "725421ae8e530ec29bcbdddbe91ff8053421d023" +git-tree-sha1 = "d05693d339e37d6ab134c5ab53c29fce5ee5d7d5" uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" -version = "0.4.1" - -[[deps.StructTypes]] -deps = ["Dates", "UUIDs"] -git-tree-sha1 = "159331b30e94d7b11379037feeb9b690950cace8" -uuid = "856f2bd8-1eba-4b0a-8007-ebc267875bd4" -version = "1.11.0" +version = "0.4.4" [[deps.StructUtils]] deps = ["Dates", "UUIDs"] -git-tree-sha1 = "79529b493a44927dd5b13dde1c7ce957c2d049e4" +git-tree-sha1 = "fa95b3b097bcef5845c142ea2e085f1b2591e92c" uuid = "ec057cc2-7a8d-4b58-b3b3-92acb9f63b42" -version = "2.6.0" +version = "2.7.1" [deps.StructUtils.extensions] StructUtilsMeasurementsExt = ["Measurements"] + StructUtilsStaticArraysCoreExt = ["StaticArraysCore"] StructUtilsTablesExt = ["Tables"] [deps.StructUtils.weakdeps] Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" + StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" [[deps.StyledStrings]] @@ -1610,7 +1863,7 @@ uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.7.0+0" +version = "7.8.3+2" [[deps.TOML]] deps = ["Dates"] @@ -1669,12 +1922,13 @@ uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.11.3" [[deps.Transducers]] -deps = ["Adapt", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "ConstructionBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "Requires", "Setfield", "SplittablesBase", "Tables"] -git-tree-sha1 = "3064e780dbb8a9296ebb3af8f440f787bb5332af" +deps = ["Accessors", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "ConstructionBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "SplittablesBase", "Tables"] +git-tree-sha1 = "4aa1fdf6c1da74661f6f5d3edfd96648321dade9" uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999" -version = "0.4.80" +version = "0.4.85" [deps.Transducers.extensions] + TransducersAdaptExt = "Adapt" TransducersBlockArraysExt = "BlockArrays" TransducersDataFramesExt = "DataFrames" TransducersLazyArraysExt = "LazyArrays" @@ -1682,6 +1936,7 @@ version = "0.4.80" TransducersReferenceablesExt = "Referenceables" [deps.Transducers.weakdeps] + Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02" @@ -1690,9 +1945,9 @@ version = "0.4.80" [[deps.Tullio]] deps = ["DiffRules", "LinearAlgebra", "Requires"] -git-tree-sha1 = "972698b132b9df8791ae74aa547268e977b55f68" +git-tree-sha1 = "de0febfe1243e89f352abd4ca0e9de6c8e6190c5" uuid = "bc48ee85-29a4-5162-ae0b-a64e1601d4bc" -version = "0.3.8" +version = "0.3.9" [deps.Tullio.extensions] TullioCUDAExt = "CUDA" @@ -1733,15 +1988,15 @@ version = "1.3.0" [[deps.WoodburyMatrices]] deps = ["LinearAlgebra", "SparseArrays"] -git-tree-sha1 = "c1a7aa6219628fcd757dede0ca95e245c5cd9511" +git-tree-sha1 = "248a7031b3da79a127f14e5dc5f417e26f9f6db7" uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" -version = "1.0.0" +version = "1.1.0" [[deps.Xorg_libX11_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] -git-tree-sha1 = "b5899b25d17bf1889d25906fb9deed5da0c15b3b" +git-tree-sha1 = "808090ede1d41644447dd5cbafced4731c56bd2f" uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" -version = "1.8.12+0" +version = "1.8.13+0" [[deps.Xorg_libXau_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1757,9 +2012,15 @@ version = "1.1.6+0" [[deps.Xorg_libXext_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] -git-tree-sha1 = "a4c0ee07ad36bf8bbce1c3bb52d21fb1e0b987fb" +git-tree-sha1 = "1a4a26870bf1e5d26cd585e38038d399d7e65706" uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" -version = "1.3.7+0" +version = "1.3.8+0" + +[[deps.Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] +git-tree-sha1 = "75e00946e43621e09d431d9b95818ee751e6b2ef" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "6.0.2+0" [[deps.Xorg_libXrender_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] @@ -1767,6 +2028,12 @@ git-tree-sha1 = "7ed9347888fac59a618302ee38216dd0379c480d" uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" version = "0.9.12+0" +[[deps.Xorg_libpciaccess_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "4909eb8f1cbf6bd4b1c30dd18b2ead9019ef2fad" +uuid = "a65dc6b1-eb27-53a1-bb3e-dea574b5389e" +version = "0.18.1+0" + [[deps.Xorg_libxcb_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXau_jll", "Xorg_libXdmcp_jll"] git-tree-sha1 = "bfcaf7ec088eaba362093393fe11aa141fa15422" @@ -1782,7 +2049,7 @@ version = "1.6.0+0" [[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.2.13+1" +version = "1.3.1+2" [[deps.ZygoteRules]] deps = ["ChainRulesCore", "MacroTools"] @@ -1805,7 +2072,13 @@ version = "0.17.4+0" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.11.0+0" +version = "5.13.1+1" + +[[deps.libdrm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libpciaccess_jll"] +git-tree-sha1 = "63aac0bcb0b582e11bad965cef4a689905456c03" +uuid = "8e53e030-5e6c-5a89-a30b-be5b7263a166" +version = "2.4.125+1" [[deps.libfdk_aac_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] @@ -1815,9 +2088,15 @@ version = "2.0.4+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "07b6a107d926093898e82b3b1db657ebe33134ec" +git-tree-sha1 = "e2a7072fc0cdd7949528c1455a3e5da4122e1153" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.50+0" +version = "1.6.56+0" + +[[deps.libva_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll", "Xorg_libXext_jll", "Xorg_libXfixes_jll", "libdrm_jll"] +git-tree-sha1 = "7dbf96baae3310fe2fa0df0ccbb3c6288d5816c9" +uuid = "9a156e7d-b971-5f62-b2c9-67348b8fb97c" +version = "2.23.0+0" [[deps.libvorbis_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll"] @@ -1828,7 +2107,7 @@ version = "1.3.8+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.59.0+0" +version = "1.64.0+1" [[deps.oneTBB_jll]] deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] @@ -1839,7 +2118,7 @@ version = "2022.0.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.4.0+2" +version = "17.5.0+2" [[deps.x264_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] From 4f4d51b889358e9633066556d725ee7eeda2d743 Mon Sep 17 00:00:00 2001 From: odunbar Date: Tue, 21 Apr 2026 17:14:15 -0700 Subject: [PATCH 05/36] remove data-as-samples (make default behaviour), first tests --- src/Utilities/likelihood_informed.jl | 31 ++++++++++++++++---------- test/Utilities/runtests.jl | 33 +++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index d13adbd80..acd2537c9 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -2,7 +2,7 @@ using Manifolds, Manopt -export LikelihoodInformed, likelihood_informed +export LikelihoodInformed, likelihood_informed, get_retain_info, get_iters, get_grad_type """ $(TYPEDEF) @@ -22,7 +22,6 @@ mutable struct LikelihoodInformed{VV1<:AbstractVector, VV2<:AbstractVector, VV3< apply_to::Union{Nothing, AbstractString} iters::VV4 grad_type::Symbol - use_data_as_samples::Bool end """ @@ -32,11 +31,11 @@ Constructs the `LikelihoodInformed` struct. Keywords: - `retain_info`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - retain_info). Choose `retain_info` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. - `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution ∝ π_prior(x) π_likelihood(y | x)^α with α ∈ [0, 1]. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. - `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). -- `use_data_as_samples`[=false]: if this parameter is `true`, then the data being processed (the training data for the emulator) will be used as the samples mentioned earlier. This means that they must be from the correct distribution corresponding to the chosen `alpha`. If this parameter is `false`, then the method expects `:samples_in` and `:samples_out` structure vectors that contain the samples instead. """ -function likelihood_informed(; retain_info = 1, iters=1, grad_type = :linreg, use_data_as_samples = false) - if grad_type ∉ [:linreg, :localsl] - @error "Unknown grad_type=$grad_type" +function likelihood_informed(; retain_info = 1, iters=1, grad_type = :linreg) + grad_types = [:linreg, :localsl] + if grad_type ∉ grad_types + throw(ArgumentError("Unknown grad_type=$grad_type, please select from $(grad_types)")) end if !isa(iters, AbstractVector) iters=[iters] @@ -45,7 +44,7 @@ function likelihood_informed(; retain_info = 1, iters=1, grad_type = :linreg, us throw(ArgumentError, "Iterations must be passed as an Int or Vec{Int}. This corresponds to which of the structure-vectors are used to construct the subspace") end - LikelihoodInformed([], [], [], retain_info, nothing, iters, grad_type, use_data_as_samples) + LikelihoodInformed([], [], [], retain_info, nothing, iters, grad_type) end get_encoder_mat(li::LikelihoodInformed) = li.encoder_mat @@ -79,8 +78,15 @@ function initialize_processor!( if length(get_encoder_mat(li))==0 - iters = get_iters(li) - alphas = get_structure_vec(input_structure_vectors, :dt) + iters = get_iters(li) + + if :dt in keys(input_structure_vectors) + alphas = get_structure_vec(input_structure_vectors, :dt) + else + @warn "Structure vectors do not contain key `:dt`. \n Continuing, assuming all vectors come from the prior `:dt=>0`." + iters = [1] + alphas = [0] + end @info "Constructing a likelihood-informed subspace using, \n iterations:$(get_iters(li)), \n α: $(alphas[iters]) " diagnostic_mats = Dict{Int64, AbstractMatrix}() samples_means = Dict{Int64, AbstractMatrix}() @@ -112,13 +118,14 @@ function initialize_processor!( end # take samples from the appropriate distribution as prescribed by alpha - samples_in, samples_out = if li.use_data_as_samples - (in_data, out_data) - else + samples_in, samples_out = if issubset([:samples_in, :samples_out], keys(input_structure_vectors)) ( get_structure_vec(input_structure_vectors, :samples_in)[it], get_structure_vec(output_structure_vectors, :samples_out)[it], ) + else + @info "Structure vectors either not provided, else do not contain keys `:samples_in, :samples_out`. \n Continuing using input-output pairs as structure vectors" + (in_data, out_data) end samples_in_mean = mean(samples_in,dims=2) samples_out_mean = mean(samples_out,dims=2) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 7acda147c..c926455a3 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -158,6 +158,8 @@ end @test Utilities.get_structure_mat(structure_mats, "c") == [1 2; 3 4] # quick build tests and test getters + + # elementwise zs = zscore_scale() mm = minmax_scale() qq = quartile_scale() @@ -174,6 +176,7 @@ end @test get_data_decoder_mat(QQ) == [4] @test get_struct_encoder_mat(QQ) == [5] @test get_struct_decoder_mat(QQ) == [6] + # decorrelator dd = decorrelate() @test get_retain_var(dd) == 1.0 @test get_decorrelate_with(dd) == "combined" @@ -191,7 +194,7 @@ end @test get_max_rank(DD) == 5 @test get_psvd_kwargs(DD) == (; test = 6) - + # canonical correlation cc = canonical_correlation() @test get_retain_var(cc) == 1.0 cc2 = canonical_correlation(retain_var = 0.7) @@ -202,15 +205,37 @@ end @test get_decoder_mat(cc3) == [3] @test get_apply_to(cc3) == "test" + # likelihood informed + ll = likelihood_informed() + @test get_retain_info(ll) == 1.0 + @test get_iters(ll) == [1] + @test get_grad_type(ll) == :linreg + ll2 = likelihood_informed(retain_info=0.99, iters=3:5, grad_type=:localsl) + @test get_retain_info(ll2) == 0.99 + @test get_iters(ll2) == 3:5 + @test get_grad_type(ll2) == :localsl + ll3 = LikelihoodInformed([2],[3],[4], 0.99, nothing, [3:5], :localsl) + @test get_encoder_mat(ll3) == [2] + @test get_decoder_mat(ll3) == [3] + @test get_data_mean(ll3) == [4] + @test_throws ArgumentError likelihood_informed(grad_type = :bad_type) + @test_throws ArgumentError likelihood_informed(iters = 1.3) # test equalities cc = canonical_correlation() cc_copy = canonical_correlation() dd = decorrelate() dd_copy = decorrelate() + zs = zscore_scale() + zs_copy = zscore_scale() + ll = likelihood_informed() + ll_copy = likelihood_informed() + @test cc == cc_copy @test dd == dd_copy - + @test zs == zs_copy + @test ll == ll_copy + # get some data as IO pairs for functional tests in_dim = 10 @@ -234,6 +259,7 @@ end "canonical-correlation", "decorrelate-structure-mat-retain-0.95-var", "canonical-correlation-0.95-var", + "likelihood_informed-0.99-info" ] # Test encodings-decodings individually @@ -247,9 +273,10 @@ end (canonical_correlation(), "in_and_out"), (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), (canonical_correlation(retain_var = 0.95), "in_and_out"), + (likelihood_informed(retain_info = 0.99), "in_and_out"), ] - lossless = [fill(true, 6); fill(false, 4)] # are these lossless approximations? + lossless = [fill(true, 6); fill(false, 5)] # are these lossless approximations? # functional test pipeline tol = 1e-12 From 96f5e6b75dadbf303d7b596d61cdff8e976929ae Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 22 Apr 2026 09:53:08 -0700 Subject: [PATCH 06/36] format --- examples/DimensionReduction/calibrate.jl | 20 +- examples/DimensionReduction/emulate_sample.jl | 75 +++---- examples/DimensionReduction/models.jl | 4 +- src/Emulator.jl | 6 +- src/Utilities.jl | 104 +++++---- src/Utilities/likelihood_informed.jl | 201 ++++++++++-------- test/Utilities/runtests.jl | 10 +- 7 files changed, 221 insertions(+), 199 deletions(-) diff --git a/examples/DimensionReduction/calibrate.jl b/examples/DimensionReduction/calibrate.jl index 77326a58e..e0dcb469e 100644 --- a/examples/DimensionReduction/calibrate.jl +++ b/examples/DimensionReduction/calibrate.jl @@ -6,11 +6,11 @@ using Random include("./models.jl") # select the forward map -mod_types=["linear"] +mod_types = ["linear"] mod_type = mod_types[1] @info "Executing model type $(mod_type)" -datadir = joinpath(@__DIR__,"datafiles") +datadir = joinpath(@__DIR__, "datafiles") if !isdir(datadir) mkpath(datadir) end @@ -27,7 +27,7 @@ for trial in 1:num_trials else bad_model(mod_type, mod_types) end - + prior_obj = ParameterDistribution( Parameterized(MvNormal(zeros(size(prior_cov, 1)), prior_cov)), fill(no_constraint(), size(prior_cov, 1)), @@ -36,13 +36,7 @@ for trial in 1:num_trials n_ensemble = 50 initial_ensemble = construct_initial_ensemble(rng, prior_obj, n_ensemble) - ekp = EnsembleKalmanProcess( - initial_ensemble, - y, - obs_noise_cov, - TransformInversion(); - rng, - ) + ekp = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, TransformInversion(); rng) n_iters = 0 for i in 1:50 @@ -58,12 +52,12 @@ for trial in 1:num_trials @info "Timesteps: $(ekp.Δt)" @info "Checkpoints: $(get_algorithm_time(ekp))" αs = vec([0 get_algorithm_time(ekp)[1:end]...]) - ekp_samples = Dict(α => (get_u(ekp, i), get_g(ekp, i)) for (i,α) in enumerate(αs[1:end-1])) + ekp_samples = Dict(α => (get_u(ekp, i), get_g(ekp, i)) for (i, α) in enumerate(αs[1:(end - 1)])) # evaluate at final time G_ens = hcat([forward_map(param, model) for param in eachcol(get_ϕ_final(prior_obj, ekp))]...) - ekp_samples[αs[end]] = (get_u(ekp,length(αs)), G_ens) - + ekp_samples[αs[end]] = (get_u(ekp, length(αs)), G_ens) + #! format: off save( joinpath(datadir,"ekp_$(mod_type)_$(trial).jld2"), diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index f817fdea1..1a48347bc 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -14,7 +14,7 @@ using CalibrateEmulateSample.Utilities include("./models.jl") # select the forward map -mod_types=["linear"] +mod_types = ["linear"] mod_type = mod_types[1] @info "Executing model type $(mod_type)" @@ -39,46 +39,41 @@ for trial in 1:num_trials training_points = [ekp_samples[α] for α in αs[min_iter:max_iter]] encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] - - rvs = [0.9, 0.94, 0.98, 0.99, 0.995, 0.999] + + rvs = [0.9, 0.94, 0.98, 0.99, 0.995, 0.999] rkls = rvs all_errs = zeros(length(rvs), 1 + length(αs)) # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor final_samples_out = ekp_samples[αs[end]][2] - encoder_kwargs = encoder_kwargs_from(ekpobj, prior; final_samples_out=final_samples_out) + encoder_kwargs = encoder_kwargs_from(ekpobj, prior; final_samples_out = final_samples_out) + + flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final = final_samples_out) - flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final=final_samples_out) - names = ["reference", "decorrelate, PCA-in", ["decorrelate, LI-in 1:$(i)" for i in 1:length(αs)]...] - if mod_type=="linear" + if mod_type == "linear" ni_scaling = 0.01 # noise injection into null space scaling (def. 1) else bad_model(mod_type, mod_types) end - - reduced_dims = zeros(Int, length(rvs), length(αs)+2) # store reduced dims for final table - + + reduced_dims = zeros(Int, length(rvs), length(αs) + 2) # store reduced dims for final table + for (idx, (rv, rkl)) in enumerate(zip(rvs, rkls)) - encoder_schedule_decorrelate = [ - (decorrelate_structure_mat(retain_var = rv), "in"), - (decorrelate_structure_mat(), "out"), - ] + encoder_schedule_decorrelate = + [(decorrelate_structure_mat(retain_var = rv), "in"), (decorrelate_structure_mat(), "out")] encoder_schedules_li = [ - [ - (decorrelate_structure_mat(), "in_and_out"), - (likelihood_informed(retain_info=rkl, iters=1:i), "in"), - ] for i in 1:length(αs) + [(decorrelate_structure_mat(), "in_and_out"), (likelihood_informed(retain_info = rkl, iters = 1:i), "in")] for i in 1:length(αs) ] - + em_ref = forward_map_wrapper( param -> forward_map(param, model), prior, flat_io_pairs; encoder_schedule = encoder_schedule_ref, encoder_kwargs = deepcopy(encoder_kwargs), - noise_injector_scaling=ni_scaling, # shouldnt be needed + noise_injector_scaling = ni_scaling, # shouldnt be needed ) em_decorrelate = forward_map_wrapper( @@ -87,36 +82,36 @@ for trial in 1:num_trials flat_io_pairs; encoder_schedule = encoder_schedule_decorrelate, encoder_kwargs = deepcopy(encoder_kwargs), - noise_injector_scaling=ni_scaling, + noise_injector_scaling = ni_scaling, ) ems_li = [ forward_map_wrapper( param -> forward_map(param, model), - prior, + prior, flat_io_pairs; encoder_schedule = encoder_schedule, encoder_kwargs = deepcopy(encoder_kwargs), - noise_injector_scaling=ni_scaling, + noise_injector_scaling = ni_scaling, ) for encoder_schedule in encoder_schedules_li ] post_means = reshape(true_parameter, input_dim, 1) post_covs = [] - for (iidx, nn, em) in zip(1:length(names), names,vcat(em_ref, em_decorrelate, ems_li...)) + for (iidx, nn, em) in zip(1:length(names), names, vcat(em_ref, em_decorrelate, ems_li...)) - reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em),"in") + reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em), "in") println(" ") - @info "Encoding name: $(nn)" - E,_ = get_encoder_from_schedule(get_encoder_schedule(em), "in") - + @info "Encoding name: $(nn)" + E, _ = get_encoder_from_schedule(get_encoder_schedule(em), "in") + if isnothing(E) - @info "No truncation" + @info "No truncation" else - ed = get_encoded_dim(get_encoder_schedule(em),"in") + ed = get_encoded_dim(get_encoder_schedule(em), "in") @info "Truncation criteria (var>$(rv), or kl > $(rkl))" @info "input dim reduced to: $(ed)" - - end + + end println(" ") u0 = rand(MvNormal(mean(prior), cov(prior))) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) @@ -124,12 +119,7 @@ for trial in 1:num_trials println("Begin MCMC - with step size ", new_step) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) - chain = MarkovChainMonteCarlo.sample( - mcmc, - 40_000; - stepsize = new_step, - discard_initial = 5_000, - ) + chain = MarkovChainMonteCarlo.sample(mcmc, 40_000; stepsize = new_step, discard_initial = 5_000) posterior = MarkovChainMonteCarlo.get_posterior(mcmc, chain) post_mean = mean(posterior) @@ -138,17 +128,16 @@ for trial in 1:num_trials post_means = hcat(post_means, reshape(post_mean, input_dim, 1)) push!(post_covs, post_cov) end - + # post_means[:,1] = true parameter # post_means[:,2] = ref # post_means[:,3] = decor, LI etc. # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) - all_errs[idx, :] = - [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' - end + all_errs[idx, :] = [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' + end @info "error of posterior mean to whitened \"reference\" solution. for $(names[2:end])" display(all_errs) @info "... and their reduced dimensions" - display(reduced_dims[:,2:end]) + display(reduced_dims[:, 2:end]) end diff --git a/examples/DimensionReduction/models.jl b/examples/DimensionReduction/models.jl index 074eec0d7..b39346e7f 100644 --- a/examples/DimensionReduction/models.jl +++ b/examples/DimensionReduction/models.jl @@ -46,11 +46,9 @@ function forward_map(X::AVorM, model::Lin) where {AVorM <: AbstractVecOrMat} end function jac_forward_map(X::AbstractVector, model::Lin) - return model.G + return model.G end function jac_forward_map(X::AbstractMatrix, model::Lin) return [jac_forward_map(x, model) for x in eachcol(X)] end - - diff --git a/src/Emulator.jl b/src/Emulator.jl index ed63726c2..9a16b16b6 100644 --- a/src/Emulator.jl +++ b/src/Emulator.jl @@ -42,7 +42,11 @@ include(joinpath("MachineLearningTools", "RandomFeature.jl")) # Random Freatures # defaults in error, all MachineLearningTools require these functions. function throw_define_mlt(mlt) - throw(ErrorException("Unknown MachineLearningTool defined, please use a known implementation. Please check all methods are defined for the MLT received: \n $mlt")) + throw( + ErrorException( + "Unknown MachineLearningTool defined, please use a known implementation. Please check all methods are defined for the MLT received: \n $mlt", + ), + ) end function build_models!(mlt, iopairs, input_structure_mats, output_structure_mats, mlt_kwargs...) throw_define_mlt(mlt) diff --git a/src/Utilities.jl b/src/Utilities.jl index 0de4dafab..48fe78f56 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -56,7 +56,7 @@ Extract the training points needed to train the Gaussian process regression. function get_training_points( ekp::EKP.EnsembleKalmanProcess{FT, IT, P}, train_iterations::Union{IT, AbstractVector{IT}}; - g_final=nothing, + g_final = nothing, ) where {FT, IT, P} if !isa(train_iterations, AbstractVector) @@ -69,23 +69,26 @@ function get_training_points( u_tp = [] g_tp = [] - g_len=length(get_g(ekp)) + g_len = length(get_g(ekp)) g_full = [get_g(ekp, i) for i in iter_range[iter_range .<= g_len]] if !isnothing(g_final) if (isa(g_final, AbstractMatrix)) # add the matrix @assert(size(g_full[1]) == size(g_final)) push!(g_full, g_final) else - throw(ArgumentError, "Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final))") + throw( + ArgumentError, + "Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final))", + ) end end - + for (idx, ir) in enumerate(iter_range) push!(u_tp, get_u(ekp, ir)) #N_parameters x N_ens push!(g_tp, g_full[idx]) #N_data x N_ens end - u_tp = reduce(hcat,u_tp) # N_parameters x (N_ek_it x N_ensemble)] - g_tp = reduce(hcat,g_tp) # N_data x (N_ek_it x N_ensemble) + u_tp = reduce(hcat, u_tp) # N_parameters x (N_ek_it x N_ensemble)] + g_tp = reduce(hcat, g_tp) # N_data x (N_ek_it x N_ensemble) training_points = PairedDataContainer(u_tp, g_tp, data_are_columns = true) @@ -152,11 +155,15 @@ Contains Commonly called from `encoder_kwargs_from(ekp, prior)` """ -function encoder_kwargs_from(samples_in::VV2, samples_out::VV1, dt::VV3) where {VV1 <: AbstractVector, VV2 <: AbstractVector, VV3 <: AbstractVector} +function encoder_kwargs_from( + samples_in::VV2, + samples_out::VV1, + dt::VV3, +) where {VV1 <: AbstractVector, VV2 <: AbstractVector, VV3 <: AbstractVector} if !(minimum(abs.(dt[1])) < eps()) # if 0 is not the first element of the algorithm time. - dt = [0, dt...] + dt = [0, dt...] end - if length(samples_out)< min(length(samples_in),length(dt)) + if length(samples_out) < min(length(samples_in), length(dt)) @info """Detected fewer `samples_out` ($(length(samples_out))) than `samples_in` ($(length(samples_in))) and `dt` ($(length(dt))). Input-output structure vectors will be created from $(length(samples_out)) samples. This commonly occurs when samples are built from `get_u(ekp), get_g(ekp)`. The final interation of output samples, (e.g., from evaluating `g=forward_map_ensemble(get_ϕ_final(ekp)`) can be provided by `encoder_kwargs_from(ekp, prior; final_samples_out=g)` @@ -168,8 +175,7 @@ The final interation of output samples, (e.g., from evaluating `g=forward_map_en samples_in = samples_in[1:len] dt = dt[1:len] samples_out = samples_out[1:len] - return( - ; + return (; input_structure_vecs = Dict(:dt => dt, :samples_in => samples_in), output_structure_vecs = Dict(:dt => dt, :samples_out => samples_out), ) @@ -185,31 +191,39 @@ kwargs: - Other overloading kwargs: `observation_series`,`samples_in`,`samples_out`,`dt` """ -function encoder_kwargs_from(ekp::EKP, prior::PD; observation_series=nothing, samples_in=nothing, samples_out=nothing, dt=nothing, final_samples_out=nothing) where {PD <: ParameterDistribution, EKP <: EnsembleKalmanProcess} +function encoder_kwargs_from( + ekp::EKP, + prior::PD; + observation_series = nothing, + samples_in = nothing, + samples_out = nothing, + dt = nothing, + final_samples_out = nothing, +) where {PD <: ParameterDistribution, EKP <: EnsembleKalmanProcess} observation_series = isnothing(observation_series) ? get_observation_series(ekp) : observation_series samples_in = isnothing(samples_in) ? get_u(ekp) : samples_in - samples_out = isnothing(samples_out) ? get_g(ekp) : samples_out + samples_out = isnothing(samples_out) ? get_g(ekp) : samples_out dt = isnothing(dt) ? get_algorithm_time(ekp) : dt # a common setting is you have one-less samples_out than (samples_in, dt) so we extend g if !isnothing(final_samples_out) if (isa(final_samples_out, AbstractMatrix)) # add one matrix - if length(samples_out)>0 + if length(samples_out) > 0 @assert(size(samples_out[1]) == size(final_samples_out)) end push!(samples_out, final_samples_out) else # add a vector of matrices - if length(samples_out)>0 + if length(samples_out) > 0 @assert(size(samples_out[1]) == size(final_samples_out[1])) end - samples_out = reduce(vcat, [samples_out,final_samples_out]) + samples_out = reduce(vcat, [samples_out, final_samples_out]) end end - + prior_kwargs = encoder_kwargs_from(prior) obs_kwargs = encoder_kwargs_from(observation_series) io_kwargs = encoder_kwargs_from(samples_in, samples_out, dt) return merge(prior_kwargs, obs_kwargs, io_kwargs) - + end @@ -472,12 +486,12 @@ function get_structure_mat(structure_mats, name = nothing) end end -function encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} +function encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} if eltype(data) <: Real # one vec - return encode_data(proc, reshape(data,:,1)) # reshape to column + return encode_data(proc, reshape(data, :, 1)) # reshape to column else # vec of vec return [encode_data(proc, vec_or_mat) for vec_or_mat in data] - end + end end @@ -494,10 +508,10 @@ end function decode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} if eltype(data) <: Real # one vec - return decode_data(proc, reshape(data,:,1)) # reshape to column + return decode_data(proc, reshape(data, :, 1)) # reshape to column else # vec of vec return [decode_data(proc, data[vec]) for vec in data] - end + end end function _decode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString} @@ -654,7 +668,7 @@ function initialize_and_encode_with_schedule!( if !isnothing(samples_out) (output_structure_vecs[:samples_out] = samples_out) end - + # apply_to is the string "in", "out" etc. for (processor, apply_to) in encoder_schedule @info "Initialize encoding of data: \"$(apply_to)\" with $(processor)" @@ -670,19 +684,23 @@ function initialize_and_encode_with_schedule!( non_encode_list = [:dt] # non-data fields if apply_to == "in" input_structure_mats = Dict{Symbol, StructureMatrix}( - name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) - for (name, mat) in input_structure_mats) + name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) for + (name, mat) in input_structure_mats + ) input_structure_vecs = Dict{Symbol, StructureVector}( - name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) - for (name, vec) in input_structure_vecs) + name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) for + (name, vec) in input_structure_vecs + ) processed_io_pairs = PairedDataContainer(processed, get_outputs(processed_io_pairs)) elseif apply_to == "out" output_structure_mats = Dict{Symbol, StructureMatrix}( - name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) - for (name, mat) in output_structure_mats) + name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) for + (name, mat) in output_structure_mats + ) output_structure_vecs = Dict{Symbol, StructureVector}( - name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) - for (name, vec) in output_structure_vecs) + name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) for + (name, vec) in output_structure_vecs + ) processed_io_pairs = PairedDataContainer(get_inputs(processed_io_pairs), processed) end end @@ -877,7 +895,7 @@ function get_encoder_from_schedule( return nothing, nothing else # Note, the action of encoders (E_1,E_2,E_3) is the product x -> (E_3*E_2*E_1)*x so must be reversed - linear_part = reduce(*,reverse(encoder_mats)) + linear_part = reduce(*, reverse(encoder_mats)) # rather than extracting the shifts etc. we can get this by just applying it to zero constant_part = encode_data(encoder_schedule, zeros(size(linear_part, 2), 1), in_or_out) @@ -911,10 +929,10 @@ function get_encoded_dim(encoder_schedule::VV, in_or_out::AS) where {VV <: Abstr if in_or_out ∉ ["in", "out"] bad_in_or_out(in_or_out) end - + encoder_mat_sizes = [size(get_encoder_mat(processor)[1]) for (processor, apply_to) in encoder_schedule if apply_to == in_or_out] - + if length(encoder_mat_sizes) == 0 return nothing else @@ -930,10 +948,7 @@ $(TYPEDSIGNATURES) gets the dimension of the encoded space, returned as a Dict with keys "in","out". Provides nothing values if encoder schedule is empty or uninitialized """ function get_encoded_dim(encoder_schedule::VV) where {VV <: AbstractVector} - return Dict( - "in" => get_encoded_dim(encoder_schedule, "in"), - "out" => get_encoded_dim(encoder_schedule, "out"), - ) + return Dict("in" => get_encoded_dim(encoder_schedule, "in"), "out" => get_encoded_dim(encoder_schedule, "out")) end """ @@ -989,10 +1004,13 @@ function get_decoder_from_schedule(encoder_schedule::VV) where {VV <: AbstractVe ) end - -get_encoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_encoder_from_schedule([single_encoder], args...; kwargs...) -get_decoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_decoder_from_schedule([single_encoder], args...; kwargs...) -get_encoded_dim(single_encoder::T, args...; kwargs...) where {T <: Tuple} = get_encoded_dim([single_encoder], args...; kwargs...) + +get_encoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = + get_encoder_from_schedule([single_encoder], args...; kwargs...) +get_decoder_from_schedule(single_encoder::T, args...; kwargs...) where {T <: Tuple} = + get_decoder_from_schedule([single_encoder], args...; kwargs...) +get_encoded_dim(single_encoder::T, args...; kwargs...) where {T <: Tuple} = + get_encoded_dim([single_encoder], args...; kwargs...) ## Decoding and add noise: """ diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index acd2537c9..b20c7b370 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -14,7 +14,13 @@ Preferred construction is with the [`likelihood_informed`](@ref) method. # Fields $(TYPEDFIELDS) """ -mutable struct LikelihoodInformed{VV1<:AbstractVector, VV2<:AbstractVector, VV3<:AbstractVector, VV4<:AbstractVector, FT <: Real} <: PairedDataContainerProcessor +mutable struct LikelihoodInformed{ + VV1 <: AbstractVector, + VV2 <: AbstractVector, + VV3 <: AbstractVector, + VV4 <: AbstractVector, + FT <: Real, +} <: PairedDataContainerProcessor encoder_mat::VV1 decoder_mat::VV2 data_mean::VV3 @@ -32,18 +38,21 @@ Constructs the `LikelihoodInformed` struct. Keywords: - `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution ∝ π_prior(x) π_likelihood(y | x)^α with α ∈ [0, 1]. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. - `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). """ -function likelihood_informed(; retain_info = 1, iters=1, grad_type = :linreg) +function likelihood_informed(; retain_info = 1, iters = 1, grad_type = :linreg) grad_types = [:linreg, :localsl] if grad_type ∉ grad_types throw(ArgumentError("Unknown grad_type=$grad_type, please select from $(grad_types)")) end if !isa(iters, AbstractVector) - iters=[iters] + iters = [iters] end if !(eltype(iters) <: Integer) - throw(ArgumentError, "Iterations must be passed as an Int or Vec{Int}. This corresponds to which of the structure-vectors are used to construct the subspace") + throw( + ArgumentError, + "Iterations must be passed as an Int or Vec{Int}. This corresponds to which of the structure-vectors are used to construct the subspace", + ) end - + LikelihoodInformed([], [], [], retain_info, nothing, iters, grad_type) end @@ -72,12 +81,19 @@ function initialize_processor!( input_structure_vectors::Dict{Symbol, SV1}, output_structure_vectors::Dict{Symbol, SV2}, apply_to::AS, -) where {MM <: AbstractMatrix, SM1 <:StructureMatrix, SM2 <: StructureMatrix, SV1 <: StructureVector, SV2 <: StructureVector, AS <: AbstractString} +) where { + MM <: AbstractMatrix, + SM1 <: StructureMatrix, + SM2 <: StructureMatrix, + SV1 <: StructureVector, + SV2 <: StructureVector, + AS <: AbstractString, +} input_dim = size(in_data, 1) output_dim = size(out_data, 1) - - if length(get_encoder_mat(li))==0 + + if length(get_encoder_mat(li)) == 0 iters = get_iters(li) if :dt in keys(input_structure_vectors) @@ -87,7 +103,7 @@ function initialize_processor!( iters = [1] alphas = [0] end - @info "Constructing a likelihood-informed subspace using, \n iterations:$(get_iters(li)), \n α: $(alphas[iters]) " + @info "Constructing a likelihood-informed subspace using, \n iterations:$(get_iters(li)), \n α: $(alphas[iters]) " diagnostic_mats = Dict{Int64, AbstractMatrix}() samples_means = Dict{Int64, AbstractMatrix}() diagnostic_fs = [] @@ -103,9 +119,9 @@ function initialize_processor!( false end noise_cov_inv = inv(obs_noise_cov) - + li.apply_to = apply_to - + for (it, α) in zip(iters, alphas[iters]) # take the iterations from alpha #(NB! "it" may not be 1:end) @@ -116,7 +132,7 @@ function initialize_processor!( else vec(get_structure_vec(output_structure_vectors, :observation)[1]) end - + # take samples from the appropriate distribution as prescribed by alpha samples_in, samples_out = if issubset([:samples_in, :samples_out], keys(input_structure_vectors)) ( @@ -127,15 +143,15 @@ function initialize_processor!( @info "Structure vectors either not provided, else do not contain keys `:samples_in, :samples_out`. \n Continuing using input-output pairs as structure vectors" (in_data, out_data) end - samples_in_mean = mean(samples_in,dims=2) - samples_out_mean = mean(samples_out,dims=2) - + samples_in_mean = mean(samples_in, dims = 2) + samples_out_mean = mean(samples_out, dims = 2) + grads = if get_grad_type(li) == :linreg grad = (samples_out .- samples_out_mean) / (samples_in .- samples_in_mean) fill(grad, size(samples_in, 2)) else @assert get_grad_type(li) == :localsl - + map(eachcol(samples_in)) do u # TODO: It might be interesting to introduce a parameter to weight this distance with. # This can be a scalar or a matrix; in the latter case, we can even use the covariance @@ -150,7 +166,7 @@ function initialize_processor!( end # get the mean shift - samples_means[it] = if apply_to == "in" + samples_means[it] = if apply_to == "in" samples_in_mean else samples_out_mean @@ -161,15 +177,15 @@ function initialize_processor!( # either we get the mats to be truncated, # or we find the functions & gradients when matrix-free # if apply_to == "in" || (α ≈ 0 && obs_whitened) #if we keep this branch then we have to possibly combine diagnostic mats and f's - if apply_to == "in" - diagnostic_mats[it] = hermitianpart( + if apply_to == "in" + diagnostic_mats[it] = hermitianpart( mean( grad' * - noise_cov_inv * - ((1 - α)*obs_noise_cov + α^2 * (y - g) * (y - g)') * - noise_cov_inv * - grad for (g, grad) in zip(eachcol(samples_out), grads) - ), + noise_cov_inv * + ((1 - α) * obs_noise_cov + α^2 * (y - g) * (y - g)') * + noise_cov_inv * + grad for (g, grad) in zip(eachcol(samples_out), grads) + ), ) elseif apply_to == "out" && (α ≈ 0 && obs_whitened) && (length(alphas[iters]) == 1) # special case for output space (whitened and prior-only distribution) diagnostic_mats[it] = hermitianpart(mean(grad * grad' for grad in grads)) @@ -182,114 +198,117 @@ function initialize_processor!( prec = noise_cov_inv - Vs * inv(Vs' * obs_noise_cov * Vs) * Vs' tr( mean( - grad' * prec * ((1 - α)obs_noise_cov + α^2 * (y - g) * (y - g)') * prec * grad - for (g, grad) in zip(eachcol(out_data), grads) - ), + grad' * prec * ((1 - α)obs_noise_cov + α^2 * (y - g) * (y - g)') * prec * grad for + (g, grad) in zip(eachcol(out_data), grads) + ), ) end egrad = (_, Vs) -> begin B = Vs * inv(Vs' * obs_noise_cov * Vs) * Vs' prec = noise_cov_inv - B - - -2obs_noise_cov * prec * mean( + + -2obs_noise_cov * + prec * + mean( begin A = ((1 - α)obs_noise_cov + α^2 * (y - g) * (y - g)') S = grad * grad' (S * prec * A + A * prec * S) end for (g, grad) in zip(eachcol(out_data), grads) - ) * - B * - Vs + ) * + B * + Vs end push!(diagnostic_fs, f) push!(diagnostic_egrads, egrad) - + end - + end - + # summarize path of diagnostic matrices, if we have more than one - encoder_mat=nothing - if length(keys(diagnostic_mats))>0 # using diagnostic_mats - if length(iters)>1 + encoder_mat = nothing + if length(keys(diagnostic_mats)) > 0 # using diagnostic_mats + if length(iters) > 1 # trap rule alpha_weight = zeros(length(iters)) - Δa=diff(alphas[iters]) - alpha_weight[1:end-1] .+= Δa ./ 2 - alpha_weight[2:end] .+= Δa ./ 2 + Δa = diff(alphas[iters]) + alpha_weight[1:(end - 1)] .+= Δa ./ 2 + alpha_weight[2:end] .+= Δa ./ 2 alpha_weight ./= sum(alpha_weight) - diagnostic_mat = sum(alpha_weight[i]*diagnostic_mats[iter] for (i,iter) in enumerate(iters[2:end])) - samples_mean = sum(alpha_weight[i]*samples_means[iter] for (i,iter) in enumerate(iters[2:end])) + diagnostic_mat = sum(alpha_weight[i] * diagnostic_mats[iter] for (i, iter) in enumerate(iters[2:end])) + samples_mean = sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) else diagnostic_mat = diagnostic_mats[iters[1]] samples_mean = samples_means[iters[1]] end - + # then get the eigen-decomposition decomp = eigen(diagnostic_mat, sortby = (-)) - sv_cumsum = cumsum(log.(decomp.values .+ 1).^2)/sum(log.(decomp.values .+ 1).^2) # frac Forstner distance-based cutoff - trunc_val=nothing + sv_cumsum = cumsum(log.(decomp.values .+ 1) .^ 2) / sum(log.(decomp.values .+ 1) .^ 2) # frac Forstner distance-based cutoff + trunc_val = nothing retain_info = get_retain_info(li) if retain_info >= 1.0 trunc_val = apply_to == "in" ? input_dim : output_dim - else + else trunc_val = findfirst(x -> (x ≥ retain_info), sv_cumsum) trunc_val = isnothing(trunc_val) ? (apply_to == "in" ? input_dim : output_dim) : trunc_val @info " truncating at $trunc_val/$(length(sv_cumsum)) retaining $(100.0*sv_cumsum[trunc_val])% of the information" end - encoder_mat = decomp.vectors[:, 1:trunc_val]' + encoder_mat = decomp.vectors[:, 1:trunc_val]' else # using diagnostic_f's and diagnostic_egrads - @assert length(diagnostic_fs)>0 && length(diagnostic_egrads)>0 + @assert length(diagnostic_fs) > 0 && length(diagnostic_egrads) > 0 @assert apply_to == "out" - - diagnostic_f, diagnostic_egrad, samples_mean = - if length(iters)>1 - method="trap_rule" - if method == "trap_rule" - - alpha_weight = zeros(length(iters)) - Δa=diff(alphas[iters]) - alpha_weight[1:end-1] .+= Δa ./ 2 - alpha_weight[2:end] .+= Δa ./ 2 - alpha_weight ./= sum(alpha_weight) - diagnostic_f = (x,Vs) -> sum(w * f(x,Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) - diagnostic_egrad = (x,Vs) -> sum(w * egrad(x,Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) - samples_mean = sum(alpha_weight[i]*samples_means[iter] for (i,iter) in enumerate(iters[2:end])) - - diagnostic_f, diagnostic_egrad, samples_mean - elseif method == "final" - diagnostic_f = diagnostic_fs[end] - diagnostic_egrad = diagnostic_egrads[end] - samples_mean = samples_means[iters[end]] - - diagnostic_f, diagnostic_egrad, samples_mean - end - else - diagnostic_f = diagnostic_fs[1] - diagnostic_egrad = diagnostic_egrads[1] - samples_mean = samples_means[iters[1]] - + + diagnostic_f, diagnostic_egrad, samples_mean = if length(iters) > 1 + method = "trap_rule" + if method == "trap_rule" + + alpha_weight = zeros(length(iters)) + Δa = diff(alphas[iters]) + alpha_weight[1:(end - 1)] .+= Δa ./ 2 + alpha_weight[2:end] .+= Δa ./ 2 + alpha_weight ./= sum(alpha_weight) + diagnostic_f = (x, Vs) -> sum(w * f(x, Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) + diagnostic_egrad = + (x, Vs) -> sum(w * egrad(x, Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) + samples_mean = + sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) + + diagnostic_f, diagnostic_egrad, samples_mean + elseif method == "final" + diagnostic_f = diagnostic_fs[end] + diagnostic_egrad = diagnostic_egrads[end] + samples_mean = samples_means[iters[end]] + diagnostic_f, diagnostic_egrad, samples_mean end - + else + diagnostic_f = diagnostic_fs[1] + diagnostic_egrad = diagnostic_egrads[1] + samples_mean = samples_means[iters[1]] + + diagnostic_f, diagnostic_egrad, samples_mean + end + @warn "Using LikelihoodInformed on output data with α≠0 or with obs_noise_cov≠I triggers a manifold optimization process that may take some time. If α=0, consider using decorrelate_structure_mat to gain obs_noise_cov = I before calling likelihood_informed" - + k = 1 Vs = nothing retain_info = get_retain_info(li) while true M = Grassmann(output_dim, k) - + diagnostic_rgrad = (M, Vs) -> begin (I - Vs * Vs') * diagnostic_egrad(M, Vs) end - + Vs = Matrix(qr(randn(output_dim, k)).Q) quasi_Newton!(M, diagnostic_f, diagnostic_rgrad, Vs; stopping_criterion = StopWhenCostChangeLess(0.1)) - - + + ref = diagnostic_f(M, zeros(output_dim, 0)) val = diagnostic_f(M, Vs) if val / ref ≤ 1 - retain_info @@ -300,12 +319,12 @@ function initialize_processor!( @info " increasing k from $k to $newk" k = newk end - + end - + encoder_mat = Vs' # setting encoder mat - - end + + end decoder_mat = encoder_mat' # creat the linear maps: @@ -328,9 +347,9 @@ function initialize_processor!( push!(get_decoder_mat(li), decoder_map) push!(get_data_mean(li), vec(samples_mean)) - + end - + end """ @@ -342,7 +361,7 @@ function encode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatr data_mean = get_data_mean(li)[1] encoder_mat = get_encoder_mat(li)[1] out = zeros(size(encoder_mat, 1), size(data, 2)) - mul!(out, encoder_mat, data .- data_mean) + mul!(out, encoder_mat, data .- data_mean) return out end @@ -354,7 +373,7 @@ Apply the `LikelihoodInformed` decoder, on a columns-are-data matrix function decode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(li)[1] decoder_mat = get_decoder_mat(li)[1] - out = zeros(size(decoder_mat, 1), size(data, 2)) + out = zeros(size(decoder_mat, 1), size(data, 2)) mul!(out, decoder_mat, data) # must use this form to get matrix output of dec*out return out .+ data_mean end diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index c926455a3..e4b3c9c5d 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -210,11 +210,11 @@ end @test get_retain_info(ll) == 1.0 @test get_iters(ll) == [1] @test get_grad_type(ll) == :linreg - ll2 = likelihood_informed(retain_info=0.99, iters=3:5, grad_type=:localsl) + ll2 = likelihood_informed(retain_info = 0.99, iters = 3:5, grad_type = :localsl) @test get_retain_info(ll2) == 0.99 @test get_iters(ll2) == 3:5 @test get_grad_type(ll2) == :localsl - ll3 = LikelihoodInformed([2],[3],[4], 0.99, nothing, [3:5], :localsl) + ll3 = LikelihoodInformed([2], [3], [4], 0.99, nothing, [3:5], :localsl) @test get_encoder_mat(ll3) == [2] @test get_decoder_mat(ll3) == [3] @test get_data_mean(ll3) == [4] @@ -235,7 +235,7 @@ end @test dd == dd_copy @test zs == zs_copy @test ll == ll_copy - + # get some data as IO pairs for functional tests in_dim = 10 @@ -259,7 +259,7 @@ end "canonical-correlation", "decorrelate-structure-mat-retain-0.95-var", "canonical-correlation-0.95-var", - "likelihood_informed-0.99-info" + "likelihood_informed-0.99-info", ] # Test encodings-decodings individually @@ -273,7 +273,7 @@ end (canonical_correlation(), "in_and_out"), (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), (canonical_correlation(retain_var = 0.95), "in_and_out"), - (likelihood_informed(retain_info = 0.99), "in_and_out"), + (likelihood_informed(retain_info = 0.99), "in_and_out"), ] lossless = [fill(true, 6); fill(false, 5)] # are these lossless approximations? From e56b69e6aea57f46e6dca7ddc25d9f91b019493b Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 22 Apr 2026 12:38:47 -0700 Subject: [PATCH 07/36] add encoder_kwargs_from test --- test/GaussianProcess/runtests.jl | 2 ++ test/Utilities/runtests.jl | 37 +++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/test/GaussianProcess/runtests.jl b/test/GaussianProcess/runtests.jl index 3d7a6080c..69994b6f6 100644 --- a/test/GaussianProcess/runtests.jl +++ b/test/GaussianProcess/runtests.jl @@ -74,6 +74,8 @@ using CalibrateEmulateSample.Utilities Emulators.optimize_hyperparameters!(em1) + @test_throws ErrorException Emulators.optimize_hyperparameters(10) # not an mlt + μ1, σ1² = Emulators.predict(em1, new_inputs) @test vec(μ1) ≈ [0.0, 1.0, 0.0, -1.0, 0.0] atol = 0.3 diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index e4b3c9c5d..2efb0f79e 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -19,7 +19,8 @@ using CalibrateEmulateSample.ParameterDistributions n_ens = 10 dim_obs = 3 dim_par = 2 - initial_ensemble = randn(rng, dim_par, n_ens)#params are cols + prior = constrained_gaussian("test", 1.0, 2.0, repeats=dim_par) + initial_ensemble = construct_initial_ensemble(rng, prior, n_ens) # params are cols y_obs = randn(rng, dim_obs) Γy = Matrix{Float64}(I, dim_obs, dim_obs) ekp = EnsembleKalmanProcesses.EnsembleKalmanProcess(initial_ensemble, y_obs, Γy, Inversion(), rng = rng) @@ -42,6 +43,40 @@ using CalibrateEmulateSample.ParameterDistributions @test isposdef(pdmat2) @test minimum(eigvals(pdmat2)) >= (1 - 1e-4) * tol + # get encoder kwargs from ekp and prior + g_ens_final = randn(rng, dim_obs, n_ens) # add a final set out outputs. + encoder_kwargs = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) + + prior_kwargs = (; prior_cov=cov(prior)) + obs_kwargs = (; obs_noise_cov = [Γy], observation=[y_obs]) + io_kwargs = (; + input_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...], + :samples_in => get_u(ekp), + ), + output_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...], + :samples_out => [get_g(ekp)..., g_ens_final], + ), + ) + test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) + + @test all(encoder_kwargs[key] == test_kwargs[key] for key in keys(encoder_kwargs)) + # remove final g + encoder_reduced_kwargs = encoder_kwargs_from(ekp, prior) + io_reduced_kwargs = (; + input_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...][1:end-1], + :samples_in => get_u(ekp)[1:end-1], + ), + output_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...][1:end-1], + :samples_out => [get_g(ekp)...], + ), + ) + test_reduced_kwargs = merge(prior_kwargs, obs_kwargs, io_reduced_kwargs) + @test all(encoder_reduced_kwargs[key] == test_reduced_kwargs[key] for key in keys(encoder_kwargs)) + end From 8b7215a920a6856bd9d0dc42b1f506bb7a91fecc Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 22 Apr 2026 13:19:44 -0700 Subject: [PATCH 08/36] typo --- test/Utilities/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 2efb0f79e..e44da3e7b 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -19,7 +19,7 @@ using CalibrateEmulateSample.ParameterDistributions n_ens = 10 dim_obs = 3 dim_par = 2 - prior = constrained_gaussian("test", 1.0, 2.0, repeats=dim_par) + prior = constrained_gaussian("test", 1.0, 2.0, 0.0, Inf, repeats=dim_par) initial_ensemble = construct_initial_ensemble(rng, prior, n_ens) # params are cols y_obs = randn(rng, dim_obs) Γy = Matrix{Float64}(I, dim_obs, dim_obs) From 22fbfc86f1da06c4304e52efa33db7b1811df336 Mon Sep 17 00:00:00 2001 From: odunbar Date: Wed, 22 Apr 2026 16:03:48 -0700 Subject: [PATCH 09/36] typo --- test/GaussianProcess/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/GaussianProcess/runtests.jl b/test/GaussianProcess/runtests.jl index 69994b6f6..bfd41041e 100644 --- a/test/GaussianProcess/runtests.jl +++ b/test/GaussianProcess/runtests.jl @@ -74,7 +74,7 @@ using CalibrateEmulateSample.Utilities Emulators.optimize_hyperparameters!(em1) - @test_throws ErrorException Emulators.optimize_hyperparameters(10) # not an mlt + @test_throws ErrorException Emulators.optimize_hyperparameters!(10) # not an mlt μ1, σ1² = Emulators.predict(em1, new_inputs) From 8edceea2372d88e0591d73b2f9f307f14bd2ec94 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 24 Apr 2026 15:35:28 -0700 Subject: [PATCH 10/36] logic typo --- src/Utilities/likelihood_informed.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index b20c7b370..bd8218956 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -134,7 +134,7 @@ function initialize_processor!( end # take samples from the appropriate distribution as prescribed by alpha - samples_in, samples_out = if issubset([:samples_in, :samples_out], keys(input_structure_vectors)) + samples_in, samples_out = if (:samples_in ∈ keys(input_structure_vectors)) && (:samples_out ∈ keys(output_structure_vectors)) ( get_structure_vec(input_structure_vectors, :samples_in)[it], get_structure_vec(output_structure_vectors, :samples_out)[it], From bb59a3f7f082ef9271fad9963e20bedcf2deb43d Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 24 Apr 2026 15:36:18 -0700 Subject: [PATCH 11/36] increase shaky tol --- test/Emulator/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Emulator/runtests.jl b/test/Emulator/runtests.jl index 128962414..82b721fb5 100644 --- a/test/Emulator/runtests.jl +++ b/test/Emulator/runtests.jl @@ -147,7 +147,7 @@ end # with out enc. fmw = forward_map_wrapper(G, prior, io_pairs, encoder_kwargs = (; obs_noise_cov = Σ)) y_pred, y_cov = EM.predict(fmw, x_test, add_obs_noise_cov = true) - @test all(isapprox(norm(yc - Σ), 0; atol = d * tol) for yc in y_cov) + @test all(isapprox(norm(yc - Σ), 0; atol = d * tol ) for yc in y_cov) # try pass encoder for input new_schedule = (decorrelate_sample_cov(), "in") # for these i fmw = forward_map_wrapper(G, prior, io_pairs, encoder_schedule = new_schedule) From 921369c31d3b51aa1e74ea027570b444b1444ffc Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 15:58:19 -0700 Subject: [PATCH 12/36] refactor private/public encode/decode functions --- src/Emulator.jl | 74 +-------------- src/Utilities.jl | 119 ++++++++++++++++++++----- src/Utilities/canonical_correlation.jl | 28 +----- src/Utilities/decorrelator.jl | 28 +----- src/Utilities/elementwise_scaler.jl | 28 +----- src/Utilities/likelihood_informed.jl | 28 +----- 6 files changed, 116 insertions(+), 189 deletions(-) diff --git a/src/Emulator.jl b/src/Emulator.jl index 9a16b16b6..0a4b0326e 100644 --- a/src/Emulator.jl +++ b/src/Emulator.jl @@ -2,14 +2,12 @@ module Emulators using ..DataContainers using ..Utilities -import ..Utilities.encode_with_schedule -import ..Utilities.decode_with_schedule +# to API for encoding import ..Utilities.encode_data -import ..Utilities.decode_data import ..Utilities.encode_structure_matrix +import ..Utilities.decode_data import ..Utilities.decode_structure_matrix - using DocStringExtensions using Statistics using Distributions @@ -251,49 +249,17 @@ function optimize_hyperparameters!(emulator::Emulator{FT}, args...; kwargs...) w optimize_hyperparameters!(emulator.machine_learning_tool, args...; kwargs...) end -""" -$(TYPEDSIGNATURES) - -Encode the new data (a `DataContainer`, or matrix where data are columns) representing inputs (`"in"`) or outputs (`"out"`). with the stored and initialized encoder schedule. -""" -function encode_data( - encoder_schedule::VV, - data::MorDC, - in_or_out::AS, -) where {AS <: AbstractString, MorDC <: Union{AbstractMatrix, DataContainer}, VV <: AbstractVector} - if isa(data, AbstractMatrix) - return get_data(encode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) - else - return encode_with_schedule(encoder_schedule, data, in_or_out) - end -end - function encode_data( em_or_fmw::EorFMW, - data::MorDC, + data, in_or_out::AS, ) where { AS <: AbstractString, - MorDC <: Union{AbstractMatrix, DataContainer}, EorFMW <: Union{Emulator, ForwardMapWrapper}, } return encode_data(get_encoder_schedule(em_or_fmw), data, in_or_out) end - -""" -$(TYPEDSIGNATURES) - -Encode a new structure matrix in the input space (`"in"`) or output space (`"out"`). with the stored and initialized encoder schedule. -""" -function encode_structure_matrix( - encoder_schedule::VV, - structure_mat, - in_or_out::AS, -) where {AS <: AbstractString, VV <: AbstractVector} - return encode_with_schedule(encoder_schedule, structure_mat, in_or_out) -end - function encode_structure_matrix( em_or_fmw::EorFMW, structure_mat, @@ -302,49 +268,17 @@ function encode_structure_matrix( return encode_structure_matrix(get_encoder_schedule(em_or_fmw), structure_mat, in_or_out) end - -""" -$(TYPEDSIGNATURES) - -Decode the new data (a `DataContainer`, or matrix where data are columns) representing inputs (`"in"`) or outputs (`"out"`). with the stored and initialized encoder schedule. -""" -function decode_data( - encoder_schedule::VV, - data::MorDC, - in_or_out::AS, -) where {AS <: AbstractString, MorDC <: Union{AbstractMatrix, DataContainer}, VV <: AbstractVector} - if isa(data, AbstractMatrix) - return get_data(decode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) - else - return decode_with_schedule(encoder_schedule, data, in_or_out) - end -end - function decode_data( em_or_fmw::EorFMW, - data::MorDC, + data, in_or_out::AS, ) where { AS <: AbstractString, - MorDC <: Union{AbstractMatrix, DataContainer}, EorFMW <: Union{Emulator, ForwardMapWrapper}, } return decode_data(get_encoder_schedule(em_or_fmw), data, in_or_out) end -""" -$(TYPEDSIGNATURES) - -Decode a new structure matrix in the input space (`"in"`) or output space (`"out"`). with the stored and initialized encoder schedule. -""" -function decode_structure_matrix( - encoder_schedule::VV, - structure_mat, - in_or_out::AS, -) where {AS <: AbstractString, VV <: AbstractVector} - return decode_with_schedule(encoder_schedule, structure_mat, in_or_out) -end - function decode_structure_matrix( em_or_fmw::EorFMW, structure_mat, diff --git a/src/Utilities.jl b/src/Utilities.jl index 48fe78f56..2e5b108b5 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -22,9 +22,9 @@ export PairedDataContainerProcessor, DataContainerProcessor export create_encoder_schedule, initialize_and_encode_with_schedule!, encode_with_schedule, - decode_with_schedule, encode_data, encode_structure_matrix, + decode_with_schedule, decode_data, decode_structure_matrix, norm, @@ -486,41 +486,45 @@ function get_structure_mat(structure_mats, name = nothing) end end -function encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} +# just for reshaping into matrix +function _encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} + data_vec = isa(data, DataContainer) ? get_data(data) : data if eltype(data) <: Real # one vec - return encode_data(proc, reshape(data, :, 1)) # reshape to column + return _encode_data(proc, reshape(data, :, 1)) # reshape to column else # vec of vec - return [encode_data(proc, vec_or_mat) for vec_or_mat in data] + return [_encode_data(proc, vec_or_mat) for vec_or_mat in data] end end -function _encode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString} +function _encode_data(proc::P, data::PDC, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} input_data, output_data = get_data(data) if apply_to == "in" - return encode_data(proc, input_data) + return _encode_data(proc, input_data) elseif apply_to == "out" - return encode_data(proc, output_data) + return _encode_data(proc, output_data) else bad_apply_to(apply_to) end end -function decode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} +# just for reshaping +function _decode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: AbstractVector} if eltype(data) <: Real # one vec - return decode_data(proc, reshape(data, :, 1)) # reshape to column + return _decode_data(proc, reshape(data, :, 1)) # reshape to column else # vec of vec - return [decode_data(proc, data[vec]) for vec in data] + return [_decode_data(proc, data[vec]) for vec in data] end end -function _decode_data(proc::P, data, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString} + +function _decode_data(proc::P, data::PDC, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} input_data, output_data = get_data(data) if apply_to == "in" - return decode_data(proc, input_data) + return _decode_data(proc, input_data) elseif apply_to == "out" - return decode_data(proc, output_data) + return _decode_data(proc, output_data) else bad_apply_to(apply_to) end @@ -684,21 +688,21 @@ function initialize_and_encode_with_schedule!( non_encode_list = [:dt] # non-data fields if apply_to == "in" input_structure_mats = Dict{Symbol, StructureMatrix}( - name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) for + name => (name ∉ non_encode_list ? _encode_structure_matrix(processor, mat) : mat) for (name, mat) in input_structure_mats ) input_structure_vecs = Dict{Symbol, StructureVector}( - name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) for + name => (name ∉ non_encode_list ? _encode_data(processor, vec) : vec) for (name, vec) in input_structure_vecs ) processed_io_pairs = PairedDataContainer(processed, get_outputs(processed_io_pairs)) elseif apply_to == "out" output_structure_mats = Dict{Symbol, StructureMatrix}( - name => (name ∉ non_encode_list ? encode_structure_matrix(processor, mat) : mat) for + name => (name ∉ non_encode_list ? _encode_structure_matrix(processor, mat) : mat) for (name, mat) in output_structure_mats ) output_structure_vecs = Dict{Symbol, StructureVector}( - name => (name ∉ non_encode_list ? encode_data(processor, vec) : vec) for + name => (name ∉ non_encode_list ? _encode_data(processor, vec) : vec) for (name, vec) in output_structure_vecs ) processed_io_pairs = PairedDataContainer(get_inputs(processed_io_pairs), processed) @@ -728,7 +732,7 @@ function encode_with_schedule( # apply_to is the string "in", "out" etc. for (processor, apply_to) in encoder_schedule if apply_to == in_or_out - processed = encode_data(processor, get_data(processed_container)) + processed = _encode_data(processor, get_data(processed_container)) processed_container = DataContainer(processed) end end @@ -754,13 +758,48 @@ function encode_with_schedule( # apply_to is the string "in", "out" etc. for (processor, apply_to) in encoder_schedule if apply_to == in_or_out - processed_structure_matrix = encode_structure_matrix(processor, processed_structure_matrix) + processed_structure_matrix = _encode_structure_matrix(processor, processed_structure_matrix) end end return processed_structure_matrix end +""" +$(TYPEDSIGNATURES) + +Encode the new data (a `DataContainer`, or matrix where data are columns, or vector viewed as one column) representing inputs (`"in"`) or outputs (`"out"`), with the stored and initialized encoder schedule. +Always internally calls `CES.Utilities.encode_with_schedule` +""" +function encode_data( + encoder_schedule::VV, + data::VorMorDC, + in_or_out::AS, +) where {AS <: AbstractString, VorMorDC <: Union{AbstractVector, AbstractMatrix, DataContainer}, VV <: AbstractVector} + if isa(data, AbstractVector) + return vec(get_data(encode_with_schedule(encoder_schedule, DataContainer(reshape(data,:,1)), in_or_out))) + elseif isa(data, AbstractMatrix) + return get_data(encode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) + else + return encode_with_schedule(encoder_schedule, data, in_or_out) + end +end + +""" +$(TYPEDSIGNATURES) + +Encode a new structure matrix in the input space (`"in"`) or output space (`"out"`). with the stored and initialized encoder schedule. +Always internally calls `CES.Utilities.encode_with_schedule`. If the structure matrix is a `LinearMap`, then the encoded structure matrix remains a `LinearMap` +""" +function encode_structure_matrix( + encoder_schedule::VV, + structure_mat, + in_or_out::AS, +) where {AS <: AbstractString, VV <: AbstractVector} + return encode_with_schedule(encoder_schedule, structure_mat, in_or_out) +end + + """ $TYPEDSIGNATURES @@ -782,10 +821,10 @@ function decode_with_schedule( processed = _decode_data(processor, processed_io_pairs, apply_to) if apply_to == "in" - processed_input_structure_mat = decode_structure_matrix(processor, processed_input_structure_mat) + processed_input_structure_mat = _decode_structure_matrix(processor, processed_input_structure_mat) processed_io_pairs = PairedDataContainer(processed, get_outputs(processed_io_pairs)) elseif apply_to == "out" - processed_output_structure_mat = decode_structure_matrix(processor, processed_output_structure_mat) + processed_output_structure_mat = _decode_structure_matrix(processor, processed_output_structure_mat) processed_io_pairs = PairedDataContainer(get_inputs(processed_io_pairs), processed) else bad_apply_to(apply_to) @@ -814,7 +853,7 @@ function decode_with_schedule( for idx in reverse(eachindex(encoder_schedule)) (processor, apply_to) = encoder_schedule[idx] if apply_to == in_or_out - processed = decode_data(processor, get_data(processed_container)) + processed = _decode_data(processor, get_data(processed_container)) processed_container = DataContainer(processed) end end @@ -841,7 +880,7 @@ function decode_with_schedule( for idx in reverse(eachindex(encoder_schedule)) (processor, apply_to) = encoder_schedule[idx] if apply_to == in_or_out - processed_structure_matrix = decode_structure_matrix(processor, processed_structure_matrix) + processed_structure_matrix = _decode_structure_matrix(processor, processed_structure_matrix) end end @@ -849,6 +888,40 @@ function decode_with_schedule( end +""" +$(TYPEDSIGNATURES) + +Decode the new data (a `DataContainer`, or matrix where data are columns, or vector viewed as one column) representing inputs (`"in"`) or outputs (`"out"`), with the stored and initialized encoder schedule. +Always internally calls `CES.Utilities.decode_with_schedule` +""" +function decode_data( + encoder_schedule::VV, + data::VorMorDC, + in_or_out::AS, +) where {AS <: AbstractString, VorMorDC <: Union{AbstractVector, AbstractMatrix, DataContainer}, VV <: AbstractVector} + if isa(data, AbstractVector) + return vec(get_data(decode_with_schedule(encoder_schedule, DataContainer(reshape(data,:,1)), in_or_out))) + elseif isa(data, AbstractMatrix) + return get_data(decode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) + else + return decode_with_schedule(encoder_schedule, data, in_or_out) + end +end + +""" +$(TYPEDSIGNATURES) + +Decode a new structure matrix in the input space (`"in"`) or output space (`"out"`). with the stored and initialized encoder schedule. +Always internally calls `CES.Utilities.decode_with_schedule`. If the structure matrix is a `LinearMap`, then the decoded structure matrix remains a `LinearMap` +""" +function decode_structure_matrix( + encoder_schedule::VV, + structure_mat, + in_or_out::AS, +) where {AS <: AbstractString, VV <: AbstractVector} + return decode_with_schedule(encoder_schedule, structure_mat, in_or_out) +end + # Errors function bad_apply_to(apply_to::AS) where {AS <: AbstractString} diff --git a/src/Utilities/canonical_correlation.jl b/src/Utilities/canonical_correlation.jl index 9e52cc1fd..0020ad79b 100644 --- a/src/Utilities/canonical_correlation.jl +++ b/src/Utilities/canonical_correlation.jl @@ -178,12 +178,7 @@ initialize_processor!( ) where {MM <: AbstractMatrix, AS <: AbstractString} = initialize_processor!(cc, in_data, out_data, apply_to) -""" -$(TYPEDSIGNATURES) - -Apply the `CanonicalCorrelation` encoder, on a columns-are-data matrix -""" -function encode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMatrix} +function _encode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(cc)[1] encoder_mat = get_encoder_mat(cc)[1] out = zeros(size(encoder_mat, 1), size(data, 2)) @@ -191,12 +186,7 @@ function encode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMa return out end -""" -$(TYPEDSIGNATURES) - -Apply the `CanonicalCorrelation` decoder, on a columns-are-data matrix -""" -function decode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMatrix} +function _decode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(cc)[1] decoder_mat = get_decoder_mat(cc)[1] out = zeros(size(decoder_mat, 1), size(data, 2)) @@ -204,22 +194,12 @@ function decode_data(cc::CanonicalCorrelation, data::MM) where {MM <: AbstractMa return out .+ data_mean end -""" -$(TYPEDSIGNATURES) - -Apply the `CanonicalCorrelation` encoder to a provided structure matrix -""" -function encode_structure_matrix(cc::CanonicalCorrelation, structure_matrix::SM) where {SM <: StructureMatrix} +function _encode_structure_matrix(cc::CanonicalCorrelation, structure_matrix::SM) where {SM <: StructureMatrix} encoder_mat = get_encoder_mat(cc)[1] return encoder_mat * structure_matrix * encoder_mat' end -""" -$(TYPEDSIGNATURES) - -Apply the `CanonicalCorrelation` decoder to a provided structure matrix -""" -function decode_structure_matrix(cc::CanonicalCorrelation, enc_structure_matrix::SM) where {SM <: StructureMatrix} +function _decode_structure_matrix(cc::CanonicalCorrelation, enc_structure_matrix::SM) where {SM <: StructureMatrix} decoder_mat = get_decoder_mat(cc)[1] return decoder_mat * enc_structure_matrix * decoder_mat' end diff --git a/src/Utilities/decorrelator.jl b/src/Utilities/decorrelator.jl index 6c5ec24c6..c6a37cdae 100644 --- a/src/Utilities/decorrelator.jl +++ b/src/Utilities/decorrelator.jl @@ -359,12 +359,7 @@ function initialize_processor!( end -""" -$(TYPEDSIGNATURES) - -Apply the `Decorrelator` encoder, on a columns-are-data matrix -""" -function encode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} +function _encode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(dd)[1] encoder_mat = get_encoder_mat(dd)[1] out = zeros(size(encoder_mat, 1), size(data, 2)) @@ -372,12 +367,7 @@ function encode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} return out end -""" -$(TYPEDSIGNATURES) - -Apply the `Decorrelator` decoder, on a columns-are-data matrix -""" -function decode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} +function _decode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(dd)[1] decoder_mat = get_decoder_mat(dd)[1] out = zeros(size(decoder_mat, 1), size(data, 2)) @@ -385,22 +375,12 @@ function decode_data(dd::Decorrelator, data::MM) where {MM <: AbstractMatrix} return out .+ data_mean end -""" -$(TYPEDSIGNATURES) - -Apply the `Decorrelator` encoder to a provided structure matrix. If the structure matrix is a LinearMap, then the encoded structure matrix remains a LinearMap. -""" -function encode_structure_matrix(dd::Decorrelator, structure_matrix::SM) where {SM <: StructureMatrix} +function _encode_structure_matrix(dd::Decorrelator, structure_matrix::SM) where {SM <: StructureMatrix} encoder_mat = get_encoder_mat(dd)[1] return encoder_mat * structure_matrix * encoder_mat' end -""" -$(TYPEDSIGNATURES) - -Apply the `Decorrelator` decoder to a provided structure matrix. If the structure matrix is a LinearMap, then the encoded structure matrix remains a LinearMap. -""" -function decode_structure_matrix(dd::Decorrelator, enc_structure_matrix::SM) where {SM <: StructureMatrix} +function _decode_structure_matrix(dd::Decorrelator, enc_structure_matrix::SM) where {SM <: StructureMatrix} decoder_mat = get_decoder_mat(dd)[1] return decoder_mat * enc_structure_matrix * decoder_mat' end diff --git a/src/Utilities/elementwise_scaler.jl b/src/Utilities/elementwise_scaler.jl index be3987ad2..ec6449f1b 100644 --- a/src/Utilities/elementwise_scaler.jl +++ b/src/Utilities/elementwise_scaler.jl @@ -218,24 +218,14 @@ function initialize_processor!(es::ElementwiseScaler, data::MM) where {MM <: Abs end end -""" -$(TYPEDSIGNATURES) - -Apply the `ElementwiseScaler` encoder, on a columns-are-data matrix -""" -function encode_data(es::ElementwiseScaler, data::MM) where {MM <: AbstractMatrix} +function _encode_data(es::ElementwiseScaler, data::MM) where {MM <: AbstractMatrix} out = zeros(size(data)) enc = get_data_encoder_mat(es)[1] mul!(out, enc, data) # must use this form to get matrix output of enc*out return out end -""" -$(TYPEDSIGNATURES) - -Apply the `ElementwiseScaler` decoder, on a columns-are-data matrix -""" -function decode_data(es::ElementwiseScaler, data::MM) where {MM <: AbstractMatrix} +function _decode_data(es::ElementwiseScaler, data::MM) where {MM <: AbstractMatrix} out = zeros(size(data)) dec = get_data_decoder_mat(es)[1] mul!(out, dec, data) # must use this form to get matrix output of dec*out @@ -255,22 +245,12 @@ initialize_processor!( ) where {MM <: AbstractMatrix} = initialize_processor!(es, data) -""" -$(TYPEDSIGNATURES) - -Apply the `ElementwiseScaler` encoder to a provided structure matrix. If the structure matrix is a LinearMap, then the encoded structure matrix remains a LinearMap. -""" -function encode_structure_matrix(es::ElementwiseScaler, structure_matrix::SM) where {SM <: StructureMatrix} +function _encode_structure_matrix(es::ElementwiseScaler, structure_matrix::SM) where {SM <: StructureMatrix} encoder_mat = get_struct_encoder_mat(es)[1] return encoder_mat * structure_matrix * encoder_mat' end -""" -$(TYPEDSIGNATURES) - -Apply the `ElementwiseScaler` decoder to a provided structure matrix. If the structure matrix is a LinearMap, then the encoded structure matrix remains a LinearMap. -""" -function decode_structure_matrix(es::ElementwiseScaler, enc_structure_matrix::SM) where {SM <: StructureMatrix} +function _decode_structure_matrix(es::ElementwiseScaler, enc_structure_matrix::SM) where {SM <: StructureMatrix} decoder_mat = get_struct_decoder_mat(es)[1] return decoder_mat * enc_structure_matrix * decoder_mat' end diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index bd8218956..fdffbbfeb 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -352,12 +352,7 @@ function initialize_processor!( end -""" -$(TYPEDSIGNATURES) - -Apply the `LikelihoodInformed` encoder, on a columns-are-data matrix -""" -function encode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} +function _encode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(li)[1] encoder_mat = get_encoder_mat(li)[1] out = zeros(size(encoder_mat, 1), size(data, 2)) @@ -365,12 +360,7 @@ function encode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatr return out end -""" -$(TYPEDSIGNATURES) - -Apply the `LikelihoodInformed` decoder, on a columns-are-data matrix -""" -function decode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} +function _decode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatrix} data_mean = get_data_mean(li)[1] decoder_mat = get_decoder_mat(li)[1] out = zeros(size(decoder_mat, 1), size(data, 2)) @@ -378,22 +368,12 @@ function decode_data(li::LikelihoodInformed, data::MM) where {MM <: AbstractMatr return out .+ data_mean end -""" -$(TYPEDSIGNATURES) - -Apply the `LikelihoodInformed` encoder to a provided structure matrix -""" -function encode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} +function _encode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} encoder_mat = get_encoder_mat(li)[1] return encoder_mat * structure_matrix * encoder_mat' end -""" -$(TYPEDSIGNATURES) - -Apply the `LikelihoodInformed` decoder to a provided structure matrix -""" -function decode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} +function _decode_structure_matrix(li::LikelihoodInformed, structure_matrix::SM) where {SM <: StructureMatrix} decoder_mat = get_decoder_mat(li)[1] return decoder_mat * structure_matrix * decoder_mat' end From b5525d6b07d13314809454c2dcdbbb8113d0d870 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 16:09:10 -0700 Subject: [PATCH 13/36] format --- src/Emulator.jl | 10 ++---- src/Utilities.jl | 16 ++++++--- src/Utilities/likelihood_informed.jl | 19 ++++++----- test/Emulator/runtests.jl | 2 +- test/GaussianProcess/runtests.jl | 2 +- test/Utilities/runtests.jl | 49 +++++++++++++++------------- 6 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/Emulator.jl b/src/Emulator.jl index 0a4b0326e..d03d6827a 100644 --- a/src/Emulator.jl +++ b/src/Emulator.jl @@ -253,10 +253,7 @@ function encode_data( em_or_fmw::EorFMW, data, in_or_out::AS, -) where { - AS <: AbstractString, - EorFMW <: Union{Emulator, ForwardMapWrapper}, -} +) where {AS <: AbstractString, EorFMW <: Union{Emulator, ForwardMapWrapper}} return encode_data(get_encoder_schedule(em_or_fmw), data, in_or_out) end @@ -272,10 +269,7 @@ function decode_data( em_or_fmw::EorFMW, data, in_or_out::AS, -) where { - AS <: AbstractString, - EorFMW <: Union{Emulator, ForwardMapWrapper}, -} +) where {AS <: AbstractString, EorFMW <: Union{Emulator, ForwardMapWrapper}} return decode_data(get_encoder_schedule(em_or_fmw), data, in_or_out) end diff --git a/src/Utilities.jl b/src/Utilities.jl index 2e5b108b5..49d6c5f2b 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -497,7 +497,11 @@ function _encode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: Abstra end -function _encode_data(proc::P, data::PDC, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} +function _encode_data( + proc::P, + data::PDC, + apply_to::AS, +) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} input_data, output_data = get_data(data) if apply_to == "in" return _encode_data(proc, input_data) @@ -518,7 +522,11 @@ function _decode_data(proc::P, data::VV) where {P <: DataProcessor, VV <: Abstra end -function _decode_data(proc::P, data::PDC, apply_to::AS) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} +function _decode_data( + proc::P, + data::PDC, + apply_to::AS, +) where {P <: DataProcessor, AS <: AbstractString, PDC <: PairedDataContainer} input_data, output_data = get_data(data) if apply_to == "in" @@ -777,7 +785,7 @@ function encode_data( in_or_out::AS, ) where {AS <: AbstractString, VorMorDC <: Union{AbstractVector, AbstractMatrix, DataContainer}, VV <: AbstractVector} if isa(data, AbstractVector) - return vec(get_data(encode_with_schedule(encoder_schedule, DataContainer(reshape(data,:,1)), in_or_out))) + return vec(get_data(encode_with_schedule(encoder_schedule, DataContainer(reshape(data, :, 1)), in_or_out))) elseif isa(data, AbstractMatrix) return get_data(encode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) else @@ -900,7 +908,7 @@ function decode_data( in_or_out::AS, ) where {AS <: AbstractString, VorMorDC <: Union{AbstractVector, AbstractMatrix, DataContainer}, VV <: AbstractVector} if isa(data, AbstractVector) - return vec(get_data(decode_with_schedule(encoder_schedule, DataContainer(reshape(data,:,1)), in_or_out))) + return vec(get_data(decode_with_schedule(encoder_schedule, DataContainer(reshape(data, :, 1)), in_or_out))) elseif isa(data, AbstractMatrix) return get_data(decode_with_schedule(encoder_schedule, DataContainer(data), in_or_out)) else diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index fdffbbfeb..c8d6f9272 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -134,15 +134,16 @@ function initialize_processor!( end # take samples from the appropriate distribution as prescribed by alpha - samples_in, samples_out = if (:samples_in ∈ keys(input_structure_vectors)) && (:samples_out ∈ keys(output_structure_vectors)) - ( - get_structure_vec(input_structure_vectors, :samples_in)[it], - get_structure_vec(output_structure_vectors, :samples_out)[it], - ) - else - @info "Structure vectors either not provided, else do not contain keys `:samples_in, :samples_out`. \n Continuing using input-output pairs as structure vectors" - (in_data, out_data) - end + samples_in, samples_out = + if (:samples_in ∈ keys(input_structure_vectors)) && (:samples_out ∈ keys(output_structure_vectors)) + ( + get_structure_vec(input_structure_vectors, :samples_in)[it], + get_structure_vec(output_structure_vectors, :samples_out)[it], + ) + else + @info "Structure vectors either not provided, else do not contain keys `:samples_in, :samples_out`. \n Continuing using input-output pairs as structure vectors" + (in_data, out_data) + end samples_in_mean = mean(samples_in, dims = 2) samples_out_mean = mean(samples_out, dims = 2) diff --git a/test/Emulator/runtests.jl b/test/Emulator/runtests.jl index 82b721fb5..128962414 100644 --- a/test/Emulator/runtests.jl +++ b/test/Emulator/runtests.jl @@ -147,7 +147,7 @@ end # with out enc. fmw = forward_map_wrapper(G, prior, io_pairs, encoder_kwargs = (; obs_noise_cov = Σ)) y_pred, y_cov = EM.predict(fmw, x_test, add_obs_noise_cov = true) - @test all(isapprox(norm(yc - Σ), 0; atol = d * tol ) for yc in y_cov) + @test all(isapprox(norm(yc - Σ), 0; atol = d * tol) for yc in y_cov) # try pass encoder for input new_schedule = (decorrelate_sample_cov(), "in") # for these i fmw = forward_map_wrapper(G, prior, io_pairs, encoder_schedule = new_schedule) diff --git a/test/GaussianProcess/runtests.jl b/test/GaussianProcess/runtests.jl index bfd41041e..1b566221e 100644 --- a/test/GaussianProcess/runtests.jl +++ b/test/GaussianProcess/runtests.jl @@ -75,7 +75,7 @@ using CalibrateEmulateSample.Utilities Emulators.optimize_hyperparameters!(em1) @test_throws ErrorException Emulators.optimize_hyperparameters!(10) # not an mlt - + μ1, σ1² = Emulators.predict(em1, new_inputs) @test vec(μ1) ≈ [0.0, 1.0, 0.0, -1.0, 0.0] atol = 0.3 diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index e44da3e7b..5eb22d3d8 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -19,7 +19,7 @@ using CalibrateEmulateSample.ParameterDistributions n_ens = 10 dim_obs = 3 dim_par = 2 - prior = constrained_gaussian("test", 1.0, 2.0, 0.0, Inf, repeats=dim_par) + prior = constrained_gaussian("test", 1.0, 2.0, 0.0, Inf, repeats = dim_par) initial_ensemble = construct_initial_ensemble(rng, prior, n_ens) # params are cols y_obs = randn(rng, dim_obs) Γy = Matrix{Float64}(I, dim_obs, dim_obs) @@ -47,33 +47,30 @@ using CalibrateEmulateSample.ParameterDistributions g_ens_final = randn(rng, dim_obs, n_ens) # add a final set out outputs. encoder_kwargs = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) - prior_kwargs = (; prior_cov=cov(prior)) - obs_kwargs = (; obs_noise_cov = [Γy], observation=[y_obs]) + prior_kwargs = (; prior_cov = cov(prior)) + obs_kwargs = (; obs_noise_cov = [Γy], observation = [y_obs]) io_kwargs = (; - input_structure_vecs = Dict( - :dt => [0, get_algorithm_time(ekp)...], - :samples_in => get_u(ekp), - ), - output_structure_vecs = Dict( - :dt => [0, get_algorithm_time(ekp)...], - :samples_out => [get_g(ekp)..., g_ens_final], - ), - ) + input_structure_vecs = Dict(:dt => [0, get_algorithm_time(ekp)...], :samples_in => get_u(ekp)), + output_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...], + :samples_out => [get_g(ekp)..., g_ens_final], + ), + ) test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) - + @test all(encoder_kwargs[key] == test_kwargs[key] for key in keys(encoder_kwargs)) # remove final g encoder_reduced_kwargs = encoder_kwargs_from(ekp, prior) io_reduced_kwargs = (; - input_structure_vecs = Dict( - :dt => [0, get_algorithm_time(ekp)...][1:end-1], - :samples_in => get_u(ekp)[1:end-1], - ), - output_structure_vecs = Dict( - :dt => [0, get_algorithm_time(ekp)...][1:end-1], - :samples_out => [get_g(ekp)...], - ), - ) + input_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...][1:(end - 1)], + :samples_in => get_u(ekp)[1:(end - 1)], + ), + output_structure_vecs = Dict( + :dt => [0, get_algorithm_time(ekp)...][1:(end - 1)], + :samples_out => [get_g(ekp)...], + ), + ) test_reduced_kwargs = merge(prior_kwargs, obs_kwargs, io_reduced_kwargs) @test all(encoder_reduced_kwargs[key] == test_reduced_kwargs[key] for key in keys(encoder_kwargs)) @@ -490,6 +487,7 @@ end in_mat = in_dat * in_dat' out_mat = out_dat * out_dat' for (i_o, dat, mat) in (("in", in_dat, in_mat), ("out", out_dat, out_mat)) + enc_dat = encode_data(encoder_schedule, dat, i_o) dec_dat = decode_data(encoder_schedule, enc_dat, i_o) enc_mat = Matrix(encode_structure_matrix(encoder_schedule, mat, i_o)) @@ -504,6 +502,13 @@ end @test isapprox(norm((D * enc_dat + b) - dec_dat), 0; atol = tol * size(D, 1)) @test isapprox(norm(E * mat * E' - enc_mat), 0; atol = tol * size(E, 1)^2) @test isapprox(norm(D * enc_mat * D' - dec_mat), 0; atol = tol * size(D, 1)^2) + + # test vec input + enc_dat_vec = encode_data(encoder_schedule, vec(dat), i_o) + dec_dat_vec = decode_data(encoder_schedule, enc_dat_vec, i_o) + @test isapprox(norm(enc_dat_vec - vec(enc_dat)), 0; atol = tol) + @test isapprox(norm(dec_dat_vec - vec(dec_dat)), 0; atol = tol) + end end From 9afc8b4530b1ebb75743a7f2e517bae23458939e Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 16:47:55 -0700 Subject: [PATCH 14/36] new docs manifest --- docs/Manifest.toml | 205 ++++++++++++++++++--------------------------- 1 file changed, 82 insertions(+), 123 deletions(-) diff --git a/docs/Manifest.toml b/docs/Manifest.toml index d68467ce5..d94662389 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -5,9 +5,9 @@ manifest_format = "2.0" project_hash = "5255fc92659f2799f0f4c5144942145e13d951ed" [[deps.ADTypes]] -git-tree-sha1 = "f7304359109c768cf32dc5fa2d371565bb63b68a" +git-tree-sha1 = "bbc22a9a08a0ef6460041086d8a7b27940ed4ffd" uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" -version = "1.21.0" +version = "1.22.0" [deps.ADTypes.extensions] ADTypesChainRulesCoreExt = "ChainRulesCore" @@ -48,10 +48,10 @@ uuid = "99985d1d-32ba-4be9-9821-2ec096f28918" version = "0.5.24" [[deps.AbstractMCMC]] -deps = ["BangBang", "ConsoleProgressMonitor", "Dates", "Distributed", "FillArrays", "LogDensityProblems", "Logging", "LoggingExtras", "ProgressLogging", "Random", "StatsBase", "TerminalLoggers", "Transducers", "UUIDs"] -git-tree-sha1 = "511d0d8cbf38045be05188ae26880afb57342a88" +deps = ["BangBang", "ConsoleProgressMonitor", "Dates", "Distributed", "LogDensityProblems", "Logging", "LoggingExtras", "ProgressLogging", "Random", "StatsBase", "TerminalLoggers", "UUIDs"] +git-tree-sha1 = "8ac6182431567907e0d5170bcac6dd48fa541f78" uuid = "80f14c24-f653-4e6a-9b94-39d6b0f70001" -version = "5.14.0" +version = "5.15.1" [deps.AbstractMCMC.extensions] AbstractMCMCOnlineStatsExt = "OnlineStats" @@ -92,9 +92,9 @@ version = "0.1.44" [[deps.Adapt]] deps = ["LinearAlgebra", "Requires"] -git-tree-sha1 = "35ea197a51ce46fcd01c4a44befce0578a1aaeca" +git-tree-sha1 = "0761717147821d696c9470a7a86364b2fbd22fd8" uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" -version = "4.5.0" +version = "4.5.2" weakdeps = ["SparseArrays", "StaticArrays"] [deps.Adapt.extensions] @@ -153,9 +153,9 @@ version = "3.5.2+0" [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "78b3a7a536b4b0a747a0f296ea77091ca0a9f9a3" +git-tree-sha1 = "54f895554d05c83e3dd59f6a396671dae8999573" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.23.0" +version = "7.24.0" [deps.ArrayInterface.extensions] ArrayInterfaceAMDGPUExt = "AMDGPU" @@ -229,16 +229,11 @@ version = "0.4.9" uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" version = "1.11.0" -[[deps.Baselet]] -git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e" -uuid = "9718e550-a3fa-408a-8086-8db961cd8217" -version = "0.1.1" - [[deps.BenchmarkTools]] -deps = ["Compat", "JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] -git-tree-sha1 = "6876e30dc02dc69f0613cb6ece242144f2ca9e56" +deps = ["Compat", "JSON", "Logging", "PrecompileTools", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "9670d3febc2b6da60a0ae57846ba74670290653f" uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -version = "1.7.0" +version = "1.8.0" [[deps.BitTwiddlingConvenienceFunctions]] deps = ["Static"] @@ -259,10 +254,10 @@ uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" version = "0.2.7" [[deps.Cairo_jll]] -deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] -git-tree-sha1 = "a21c5464519504e41e0cbc91f0188e8ca23d7440" +deps = ["Artifacts", "Bzip2_jll", "CompilerSupportLibraries_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "Libdl", "Pixman_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "d0efe2c6fdcdaa1c161d206aa8b933788397ec71" uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" -version = "1.18.5+1" +version = "1.18.6+0" [[deps.CalibrateEmulateSample]] deps = ["AbstractGPs", "AbstractMCMC", "AdvancedMH", "ChunkSplitters", "Conda", "Distributions", "DocStringExtensions", "EnsembleKalmanProcesses", "ForwardDiff", "GaussianProcesses", "KernelFunctions", "LinearAlgebra", "LinearMaps", "LowRankApprox", "MCMCChains", "Manifolds", "Manopt", "Pkg", "Printf", "ProgressBars", "PyCall", "Random", "RandomFeatures", "ReverseDiff", "ScikitLearn", "StableRNGs", "Statistics", "StatsBase", "TSVD"] @@ -272,9 +267,9 @@ version = "1.0.0" [[deps.ChainRulesCore]] deps = ["Compat", "LinearAlgebra"] -git-tree-sha1 = "e4c6a16e77171a5f5e25e9646617ab1c276c5607" +git-tree-sha1 = "12177ad6b3cad7fd50c8b3825ce24a99ad61c18f" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.26.0" +version = "1.26.1" weakdeps = ["SparseArrays"] [deps.ChainRulesCore.extensions] @@ -417,9 +412,9 @@ version = "1.16.0" [[deps.DataFrames]] deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] -git-tree-sha1 = "d8928e9169ff76c6281f39a659f9bca3a573f24c" +git-tree-sha1 = "5fab31e2e01e70ad66e3e24c968c264d1cf166d6" uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -version = "1.8.1" +version = "1.8.2" [[deps.DataStructures]] deps = ["Compat", "InteractiveUtils", "OrderedCollections"] @@ -437,11 +432,6 @@ deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" version = "1.11.0" -[[deps.DefineSingletons]] -git-tree-sha1 = "0fba8b706d0178b4dc7fd44a96a92382c9065c2c" -uuid = "244e2a9f-e319-4986-a169-4d1fe445cd52" -version = "0.1.2" - [[deps.DiffResults]] deps = ["StaticArraysCore"] git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" @@ -456,9 +446,9 @@ version = "1.15.1" [[deps.DifferentiationInterface]] deps = ["ADTypes", "LinearAlgebra"] -git-tree-sha1 = "7ae99144ea44715402c6c882bfef2adbeadbc4ce" +git-tree-sha1 = "d0250552e42bf7cc36479fd38a6e30004c9e8c2b" uuid = "a0c0ee7d-e4b9-4e03-894e-1c5f64a51d63" -version = "0.7.16" +version = "0.7.17" [deps.DifferentiationInterface.extensions] DifferentiationInterfaceChainRulesCoreExt = "ChainRulesCore" @@ -468,7 +458,7 @@ version = "0.7.16" DifferentiationInterfaceFiniteDiffExt = "FiniteDiff" DifferentiationInterfaceFiniteDifferencesExt = "FiniteDifferences" DifferentiationInterfaceForwardDiffExt = ["ForwardDiff", "DiffResults"] - DifferentiationInterfaceGPUArraysCoreExt = "GPUArraysCore" + DifferentiationInterfaceGPUArraysCoreExt = ["GPUArraysCore", "Adapt"] DifferentiationInterfaceGTPSAExt = "GTPSA" DifferentiationInterfaceMooncakeExt = "Mooncake" DifferentiationInterfacePolyesterForwardDiffExt = ["PolyesterForwardDiff", "ForwardDiff", "DiffResults"] @@ -482,6 +472,7 @@ version = "0.7.16" DifferentiationInterfaceZygoteExt = ["Zygote", "ForwardDiff"] [deps.DifferentiationInterface.weakdeps] + Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" Diffractor = "9f5e2b26-1114-432f-b630-d3fe2085c51c" @@ -522,9 +513,9 @@ version = "1.11.0" [[deps.Distributions]] deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] -git-tree-sha1 = "fbcc7610f6d8348428f722ecbe0e6cfe22e672c6" +git-tree-sha1 = "e421c1938fafab0165b04dc1a9dbe2a26272952c" uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" -version = "0.25.123" +version = "0.25.125" [deps.Distributions.extensions] DistributionsChainRulesCoreExt = "ChainRulesCore" @@ -543,9 +534,9 @@ version = "0.9.5" [[deps.Documenter]] deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] -git-tree-sha1 = "70c521ca3a23c576e12655d15963977c9766c26b" +git-tree-sha1 = "56e9c37b5e7c3b4f080ab1da18d72d5c290e184a" uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "1.16.0" +version = "1.17.0" [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] @@ -583,9 +574,9 @@ version = "1.0.7" [[deps.Expat_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "27af30de8b5445644e8ffe3bcb0d72049c089cf1" +git-tree-sha1 = "8f05e9a2e7c2e3eb524102bb2926c5743c07fbe1" uuid = "2e619515-83b5-522b-bb60-26c02a35a201" -version = "2.7.3+0" +version = "2.8.0+0" [[deps.FFMPEG]] deps = ["FFMPEG_jll"] @@ -595,9 +586,9 @@ version = "0.4.5" [[deps.FFMPEG_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "PCRE2_jll", "Zlib_jll", "libaom_jll", "libass_jll", "libfdk_aac_jll", "libva_jll", "libvorbis_jll", "x264_jll", "x265_jll"] -git-tree-sha1 = "66381d7059b5f3f6162f28831854008040a4e905" +git-tree-sha1 = "cac41ca6b2d399adfc95e51240566f8a60a80806" uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" -version = "8.0.1+1" +version = "8.1.0+0" [[deps.FFTA]] deps = ["AbstractFFTs", "DocStringExtensions", "LinearAlgebra", "MuladdMacro", "Primes", "Random", "Reexport"] @@ -613,9 +604,9 @@ version = "1.10.0" [[deps.FFTW_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "6d6219a004b8cf1e0b4dbe27a2860b8e04eba0be" +git-tree-sha1 = "6866aec60ef98e3164cd8d6855225684207e9dff" uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" -version = "3.3.11+0" +version = "3.3.12+0" [[deps.FastGaussQuadrature]] deps = ["LinearAlgebra", "SpecialFunctions", "StaticArrays"] @@ -642,9 +633,9 @@ weakdeps = ["PDMats", "SparseArrays", "StaticArrays", "Statistics"] [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Setfield"] -git-tree-sha1 = "9340ca07ca27093ff68418b7558ca37b05f8aeb1" +git-tree-sha1 = "f7017a4f337f8df189fcce98e32b67a1298a2115" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.29.0" +version = "2.31.0" [deps.FiniteDiff.extensions] FiniteDiffBandedMatricesExt = "BandedMatrices" @@ -740,9 +731,9 @@ version = "3.7.0+0" [[deps.Git_jll]] deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] -git-tree-sha1 = "dc34a3e3d96b4ed305b641e626dc14c12b7824b8" +git-tree-sha1 = "0dd4cfb426924210c8f42742751cbde74b27bfa3" uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" -version = "2.53.0+0" +version = "2.54.0+0" [[deps.Glib_jll]] deps = ["Artifacts", "GettextRuntime_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] @@ -850,9 +841,9 @@ version = "0.16.2" Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" [[deps.IntervalSets]] -git-tree-sha1 = "d966f85b3b7a8e49d034d27a189e9a4874b4391a" +git-tree-sha1 = "79d6bd28c8d9bccc2229784f1bd637689b256377" uuid = "8197267c-284f-5f27-9208-e0e47529a953" -version = "0.7.13" +version = "0.7.14" weakdeps = ["Random", "RecipesBase", "Statistics"] [deps.IntervalSets.extensions] @@ -898,9 +889,9 @@ version = "1.7.1" [[deps.JSON]] deps = ["Dates", "Logging", "Parsers", "PrecompileTools", "StructUtils", "UUIDs", "Unicode"] -git-tree-sha1 = "b3ad4a0255688dcb895a52fafbaae3023b588a90" +git-tree-sha1 = "fe23330af47b8ab4e135b2ff65f7398c3a2bfc65" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" -version = "1.4.0" +version = "1.5.2" [deps.JSON.extensions] JSONArrowExt = ["ArrowTypes"] @@ -949,12 +940,6 @@ git-tree-sha1 = "eb62a3deb62fc6d8822c0c4bef73e4412419c5d8" uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" version = "18.1.8+0" -[[deps.LZO_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "1c602b1127f4751facb671441ca72715cc95938a" -uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" -version = "2.10.3+0" - [[deps.LaTeXStrings]] git-tree-sha1 = "dda21b8cbd6a6c40d9d02a73230f9d70fed6918c" uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" @@ -1025,15 +1010,15 @@ version = "1.18.0+0" [[deps.Libmount_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "97bbca976196f2a1eb9607131cb108c69ec3f8a6" +git-tree-sha1 = "cc3ad4faf30015a3e8094c9b5b7f19e85bdf2386" uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" -version = "2.41.3+0" +version = "2.42.0+0" [[deps.Libuuid_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "d0205286d9eceadc518742860bf23f703779a3d6" +git-tree-sha1 = "d620582b1f0cbe2c72dd1d5bd195a9ce73370ab1" uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" -version = "2.41.3+0" +version = "2.42.0+0" [[deps.LineSearches]] deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Printf"] @@ -1167,9 +1152,9 @@ version = "0.4.5" [[deps.Manifolds]] deps = ["ADTypes", "DifferentiationInterface", "Graphs", "Kronecker", "LinearAlgebra", "ManifoldDiff", "ManifoldsBase", "Markdown", "MatrixEquations", "Quaternions", "Random", "SimpleWeightedGraphs", "SpecialFunctions", "StaticArrays", "Statistics", "StatsBase", "Tullio"] -git-tree-sha1 = "b4ad952229f66fa7c1fe37efb15b20ce59290e44" +git-tree-sha1 = "709b90386258b79674859d61fc5dd397bd9c941d" uuid = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" -version = "0.11.20" +version = "0.11.22" [deps.Manifolds.extensions] ManifoldsBoundaryValueDiffEqExt = "BoundaryValueDiffEq" @@ -1196,9 +1181,9 @@ version = "0.11.20" [[deps.ManifoldsBase]] deps = ["LinearAlgebra", "Markdown", "Printf", "Random"] -git-tree-sha1 = "c96ad9c0d0d5b182c6a6398486f04c13b8fe7d25" +git-tree-sha1 = "9329a9b772e3e50409b5b5cbbace1351139c6cf3" uuid = "3362f125-f0bb-47a3-aa74-596ffd7ef2fb" -version = "2.3.4" +version = "2.3.5" [deps.ManifoldsBase.extensions] ManifoldsBasePlotsExt = "Plots" @@ -1214,9 +1199,9 @@ version = "2.3.4" [[deps.Manopt]] deps = ["ColorSchemes", "ColorTypes", "Colors", "DataStructures", "Dates", "Glossaries", "LinearAlgebra", "ManifoldDiff", "ManifoldsBase", "Markdown", "Preferences", "Printf", "Random", "SparseArrays", "Statistics"] -git-tree-sha1 = "c3a8ad10124613c0325c0f9c46fe66e575bfc974" +git-tree-sha1 = "656cfa06ad863c778799c6b116e6f8310844a470" uuid = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5" -version = "0.5.34" +version = "0.5.36" [deps.Manopt.extensions] ManoptJuMPExt = "JuMP" @@ -1253,10 +1238,18 @@ uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" version = "0.1.3" [[deps.MathOptInterface]] -deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] -git-tree-sha1 = "ce739e3d8a21313ea418772edfc3b7b15a1dfc16" +deps = ["CodecBzip2", "CodecZlib", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test"] +git-tree-sha1 = "73939c06e863f8d68322106fdc2464f3443b5e1a" uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" -version = "1.50.1" +version = "1.51.0" + + [deps.MathOptInterface.extensions] + MathOptInterfaceBenchmarkToolsExt = "BenchmarkTools" + MathOptInterfaceCliqueTreesExt = "CliqueTrees" + + [deps.MathOptInterface.weakdeps] + BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" + CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8" [[deps.MatrixEquations]] deps = ["LinearAlgebra", "LinearMaps"] @@ -1264,12 +1257,6 @@ git-tree-sha1 = "51f3fade0b4ff2cf90b36b3312425460631abb56" uuid = "99c1a7ee-ab34-5fd5-8076-27c950a045f4" version = "2.5.6" -[[deps.MicroCollections]] -deps = ["Accessors", "BangBang", "InitialValues"] -git-tree-sha1 = "44d32db644e84c75dab479f1bc15ee76a1a3618f" -uuid = "128add7d-3638-4c79-886c-908ea0c25c34" -version = "0.2.0" - [[deps.Missings]] deps = ["DataAPI"] git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" @@ -1357,9 +1344,9 @@ version = "1.3.6+0" [[deps.OpenBLAS32_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] -git-tree-sha1 = "46cce8b42186882811da4ce1f4c7208b02deb716" +git-tree-sha1 = "dd0d9979377e43918a80486a562ddedcc6d9bdf3" uuid = "656ef2d0-ae68-5445-9ca0-591084a874a2" -version = "0.3.30+0" +version = "0.3.33+0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] @@ -1373,9 +1360,9 @@ version = "0.8.7+0" [[deps.OpenSSH_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll", "Zlib_jll"] -git-tree-sha1 = "301412a644646fdc0ad67d0a87487466b491e53d" +git-tree-sha1 = "57baa4b81a24c2910afbb6d853aa0685e4312bf7" uuid = "9bd350c2-7e96-507f-8002-3f2e150b4e1b" -version = "10.2.1+0" +version = "10.3.1+0" [[deps.OpenSSL_jll]] deps = ["Artifacts", "Libdl"] @@ -1428,9 +1415,9 @@ version = "0.12.3" [[deps.Parsers]] deps = ["Dates", "PrecompileTools", "UUIDs"] -git-tree-sha1 = "7d2f8f21da5db6a806faf7b9b292296da42b2810" +git-tree-sha1 = "5d5e0a78e971354b1c7bff0655d11fdc1b0e12c8" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" -version = "2.8.3" +version = "2.8.4" [[deps.Pixman_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] @@ -1536,9 +1523,9 @@ version = "1.96.4" [[deps.QuadGK]] deps = ["DataStructures", "LinearAlgebra"] -git-tree-sha1 = "9da16da70037ba9d701192e27befedefb91ec284" +git-tree-sha1 = "5e8e8b0ab68215d7a2b14b9921a946fee794749e" uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" -version = "2.11.2" +version = "2.11.3" [deps.QuadGK.extensions] QuadGKEnzymeExt = "Enzyme" @@ -1746,12 +1733,6 @@ weakdeps = ["ChainRulesCore"] [deps.SpecialFunctions.extensions] SpecialFunctionsChainRulesCoreExt = "ChainRulesCore" -[[deps.SplittablesBase]] -deps = ["Setfield", "Test"] -git-tree-sha1 = "e08a62abc517eb79667d0a29dc08a3b589516bb5" -uuid = "171d559e-b47b-412a-8079-5efa626c420e" -version = "0.1.15" - [[deps.StableRNGs]] deps = ["Random"] git-tree-sha1 = "4f96c596b8c8258cc7d3b19797854d368f243ddc" @@ -1760,15 +1741,15 @@ version = "1.0.4" [[deps.Static]] deps = ["CommonWorldInvalidations", "IfElse", "PrecompileTools", "SciMLPublic"] -git-tree-sha1 = "49440414711eddc7227724ae6e570c7d5559a086" +git-tree-sha1 = "bb072715f158b59ad8819ff80da5ffa90cce6ceb" uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" -version = "1.3.1" +version = "1.4.0" [[deps.StaticArrayInterface]] deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "SciMLPublic", "Static"] -git-tree-sha1 = "aa1ea41b3d45ac449d10477f65e2b40e3197a0d2" +git-tree-sha1 = "2a635e15d5035c53b345077c947f31ff91744078" uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718" -version = "1.9.0" +version = "1.10.0" weakdeps = ["OffsetArrays", "StaticArrays"] [deps.StaticArrayInterface.extensions] @@ -1838,9 +1819,9 @@ version = "0.4.4" [[deps.StructUtils]] deps = ["Dates", "UUIDs"] -git-tree-sha1 = "fa95b3b097bcef5845c142ea2e085f1b2591e92c" +git-tree-sha1 = "dd974aefe288ef2898733aecf40858dc86742d74" uuid = "ec057cc2-7a8d-4b58-b3b3-92acb9f63b42" -version = "2.7.1" +version = "2.8.1" [deps.StructUtils.extensions] StructUtilsMeasurementsExt = ["Measurements"] @@ -1921,28 +1902,6 @@ git-tree-sha1 = "0c45878dcfdcfa8480052b6ab162cdd138781742" uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" version = "0.11.3" -[[deps.Transducers]] -deps = ["Accessors", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "ConstructionBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "SplittablesBase", "Tables"] -git-tree-sha1 = "4aa1fdf6c1da74661f6f5d3edfd96648321dade9" -uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999" -version = "0.4.85" - - [deps.Transducers.extensions] - TransducersAdaptExt = "Adapt" - TransducersBlockArraysExt = "BlockArrays" - TransducersDataFramesExt = "DataFrames" - TransducersLazyArraysExt = "LazyArrays" - TransducersOnlineStatsBaseExt = "OnlineStatsBase" - TransducersReferenceablesExt = "Referenceables" - - [deps.Transducers.weakdeps] - Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" - BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" - DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" - LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02" - OnlineStatsBase = "925886fa-5bf2-5e8e-b522-a9147a512338" - Referenceables = "42d2dcc6-99eb-4e98-b66c-637b7d73030e" - [[deps.Tullio]] deps = ["DiffRules", "LinearAlgebra", "Requires"] git-tree-sha1 = "de0febfe1243e89f352abd4ca0e9de6c8e6190c5" @@ -2030,9 +1989,9 @@ version = "0.9.12+0" [[deps.Xorg_libpciaccess_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "4909eb8f1cbf6bd4b1c30dd18b2ead9019ef2fad" +git-tree-sha1 = "58972370b81423fc546c56a60ed1a009450177c3" uuid = "a65dc6b1-eb27-53a1-bb3e-dea574b5389e" -version = "0.18.1+0" +version = "0.19.0+0" [[deps.Xorg_libxcb_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libXau_jll", "Xorg_libXdmcp_jll"] @@ -2059,9 +2018,9 @@ version = "0.2.7" [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "371cc681c00a3ccc3fbc5c0fb91f58ba9bec1ecf" +git-tree-sha1 = "850b06095ee71f0135d644ffd8a52850699581ed" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" -version = "3.13.1+0" +version = "3.13.3+0" [[deps.libass_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Zlib_jll"] @@ -2088,9 +2047,9 @@ version = "2.0.4+0" [[deps.libpng_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] -git-tree-sha1 = "e2a7072fc0cdd7949528c1455a3e5da4122e1153" +git-tree-sha1 = "e51150d5ab85cee6fc36726850f0e627ad2e4aba" uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" -version = "1.6.56+0" +version = "1.6.58+0" [[deps.libva_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll", "Xorg_libXext_jll", "Xorg_libXfixes_jll", "libdrm_jll"] From f294c759261604354f9a7fa3f0417dea73c840d1 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 17:04:31 -0700 Subject: [PATCH 15/36] more coverage --- test/Utilities/runtests.jl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 5eb22d3d8..fc0f23087 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -324,6 +324,12 @@ end encoded_input_structure_mats[:prior_cov], encoded_output_structure_mats[:obs_noise_cov], ) + enc_in_dim = get_encoded_dim(encoded_schedule,"in") + enc_out_dim = get_encoded_dim(encoded_schedule,"out") + @test enc_in_dim == size(get_inputs(encoded_io_pairs),1) + @test enc_out_dim == size(get_outputs(encoded_io_pairs),1) + @test isnothing(get_encoded_dim([],"in")) + @test_throws ArgumentError get_encoded_dim(encoder_schedule, "bad_in") for (enc_dat, dec_dat, test_dat, enc_covv, dec_covv, test_covv, dim) in zip( (get_inputs(encoded_io_pairs), get_outputs(encoded_io_pairs)), (get_inputs(decoded_io_pairs), get_outputs(decoded_io_pairs)), @@ -333,6 +339,7 @@ end (prior_cov, obs_noise_cov), (in_dim, out_dim), ) + # univariate "rescaling" tests if name == "zscore" stat_vec = [[mean(dd), std(dd)] for dd in eachrow(enc_dat)] From 9152c2d6c1ac0168c64a2fa5a62bc7dd5cf48d17 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 17:11:01 -0700 Subject: [PATCH 16/36] more coverage --- test/Utilities/runtests.jl | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index fc0f23087..9ff867d9e 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -324,8 +324,11 @@ end encoded_input_structure_mats[:prior_cov], encoded_output_structure_mats[:obs_noise_cov], ) - enc_in_dim = get_encoded_dim(encoded_schedule,"in") - enc_out_dim = get_encoded_dim(encoded_schedule,"out") + enc_in_dim = get_encoded_dim(encoder_schedule,"in") + enc_out_dim = get_encoded_dim(encoder_schedule,"out") + enc_dims = get_encoded_dim(encoder_schedule) + @test enc_in_dim == enc_dims["in"] + @test enc_out_dim == enc_dims["out"] @test enc_in_dim == size(get_inputs(encoded_io_pairs),1) @test enc_out_dim == size(get_outputs(encoded_io_pairs),1) @test isnothing(get_encoded_dim([],"in")) From 13a8ddf3c00e1509c2485b0e818ec85e81fc3f63 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 17:22:04 -0700 Subject: [PATCH 17/36] add cases --- test/Utilities/runtests.jl | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 9ff867d9e..4ff47db05 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -279,19 +279,20 @@ end in_data = rand(rng, MvNormal(zeros(in_dim), prior_cov), samples) obs_noise_cov = [max(5.0 - abs(i - j), 0.0) for i in 1:out_dim, j in 1:out_dim] # [5 4 3 2 1 0 0 ...] off diagonal out_data = rand(rng, MvNormal(-10 * ones(out_dim), obs_noise_cov), samples) - + io_pairs = PairedDataContainer(in_data, out_data) test_names = [ # order as in schedules below - "zscore", - "quartile", - "minmax", - "decorrelate-sample-cov", - "decorrelate-structure-mat", - "decorrelate-combined", - "canonical-correlation", - "decorrelate-structure-mat-retain-0.95-var", - "canonical-correlation-0.95-var", - "likelihood_informed-0.99-info", + "zscore", + "quartile", + "minmax", + "decorrelate-sample-cov", + "decorrelate-structure-mat", + "decorrelate-combined", + "canonical-correlation", + "decorrelate-structure-mat-retain-0.95-var", + "canonical-correlation-0.95-var", + "likelihood_informed-0.99-info", + "likelihood_informed-0.99-info-acc", ] # Test encodings-decodings individually @@ -306,9 +307,10 @@ end (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), (canonical_correlation(retain_var = 0.95), "in_and_out"), (likelihood_informed(retain_info = 0.99), "in_and_out"), + (likelihood_informed(retain_info = 0.99, iters=1:2, grad_type=:localsl), "in_and_out"), ] - lossless = [fill(true, 6); fill(false, 5)] # are these lossless approximations? + lossless = [fill(true, 6); fill(false, length(schedules)-6)] # are these lossless approximations? # functional test pipeline tol = 1e-12 From 6321755f7506b89753b8bd36c1cc07de35cccde1 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 17:22:24 -0700 Subject: [PATCH 18/36] rm trap rule switch for now --- src/Utilities/likelihood_informed.jl | 38 +++++++++++----------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index c8d6f9272..cce69d1a9 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -264,33 +264,25 @@ function initialize_processor!( @assert apply_to == "out" diagnostic_f, diagnostic_egrad, samples_mean = if length(iters) > 1 - method = "trap_rule" - if method == "trap_rule" - - alpha_weight = zeros(length(iters)) - Δa = diff(alphas[iters]) - alpha_weight[1:(end - 1)] .+= Δa ./ 2 - alpha_weight[2:end] .+= Δa ./ 2 - alpha_weight ./= sum(alpha_weight) - diagnostic_f = (x, Vs) -> sum(w * f(x, Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) - diagnostic_egrad = - (x, Vs) -> sum(w * egrad(x, Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) - samples_mean = - sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) - - diagnostic_f, diagnostic_egrad, samples_mean - elseif method == "final" - diagnostic_f = diagnostic_fs[end] - diagnostic_egrad = diagnostic_egrads[end] - samples_mean = samples_means[iters[end]] - - diagnostic_f, diagnostic_egrad, samples_mean - end + alpha_weight = zeros(length(iters)) + Δa = diff(alphas[iters]) + alpha_weight[1:(end - 1)] .+= Δa ./ 2 + alpha_weight[2:end] .+= Δa ./ 2 + alpha_weight ./= sum(alpha_weight) + diagnostic_f = (x, Vs) -> sum(w * f(x, Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) + diagnostic_egrad = + (x, Vs) -> sum(w * egrad(x, Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) + samples_mean = + sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) + + # return: + diagnostic_f, diagnostic_egrad, samples_mean else diagnostic_f = diagnostic_fs[1] diagnostic_egrad = diagnostic_egrads[1] samples_mean = samples_means[iters[1]] - + + # return: diagnostic_f, diagnostic_egrad, samples_mean end From 24da32c8dc8e1e915acab9b98ae06a53c2f58a92 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 30 Apr 2026 17:27:56 -0700 Subject: [PATCH 19/36] format --- src/Utilities/likelihood_informed.jl | 7 +++-- test/Utilities/runtests.jl | 40 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index cce69d1a9..78873058b 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -272,16 +272,15 @@ function initialize_processor!( diagnostic_f = (x, Vs) -> sum(w * f(x, Vs) for (f, w) in zip(diagnostic_fs, alpha_weight)) diagnostic_egrad = (x, Vs) -> sum(w * egrad(x, Vs) for (egrad, w) in zip(diagnostic_egrads, alpha_weight)) - samples_mean = - sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) - + samples_mean = sum(alpha_weight[i] * samples_means[iter] for (i, iter) in enumerate(iters[2:end])) + # return: diagnostic_f, diagnostic_egrad, samples_mean else diagnostic_f = diagnostic_fs[1] diagnostic_egrad = diagnostic_egrads[1] samples_mean = samples_means[iters[1]] - + # return: diagnostic_f, diagnostic_egrad, samples_mean end diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 4ff47db05..8b516b3d4 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -279,20 +279,20 @@ end in_data = rand(rng, MvNormal(zeros(in_dim), prior_cov), samples) obs_noise_cov = [max(5.0 - abs(i - j), 0.0) for i in 1:out_dim, j in 1:out_dim] # [5 4 3 2 1 0 0 ...] off diagonal out_data = rand(rng, MvNormal(-10 * ones(out_dim), obs_noise_cov), samples) - + io_pairs = PairedDataContainer(in_data, out_data) test_names = [ # order as in schedules below - "zscore", - "quartile", - "minmax", - "decorrelate-sample-cov", - "decorrelate-structure-mat", - "decorrelate-combined", - "canonical-correlation", - "decorrelate-structure-mat-retain-0.95-var", - "canonical-correlation-0.95-var", - "likelihood_informed-0.99-info", - "likelihood_informed-0.99-info-acc", + "zscore", + "quartile", + "minmax", + "decorrelate-sample-cov", + "decorrelate-structure-mat", + "decorrelate-combined", + "canonical-correlation", + "decorrelate-structure-mat-retain-0.95-var", + "canonical-correlation-0.95-var", + "likelihood_informed-0.99-info", + "likelihood_informed-0.99-info-acc", ] # Test encodings-decodings individually @@ -307,10 +307,10 @@ end (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), (canonical_correlation(retain_var = 0.95), "in_and_out"), (likelihood_informed(retain_info = 0.99), "in_and_out"), - (likelihood_informed(retain_info = 0.99, iters=1:2, grad_type=:localsl), "in_and_out"), + (likelihood_informed(retain_info = 0.99, iters = 1:2, grad_type = :localsl), "in_and_out"), ] - lossless = [fill(true, 6); fill(false, length(schedules)-6)] # are these lossless approximations? + lossless = [fill(true, 6); fill(false, length(schedules) - 6)] # are these lossless approximations? # functional test pipeline tol = 1e-12 @@ -326,14 +326,14 @@ end encoded_input_structure_mats[:prior_cov], encoded_output_structure_mats[:obs_noise_cov], ) - enc_in_dim = get_encoded_dim(encoder_schedule,"in") - enc_out_dim = get_encoded_dim(encoder_schedule,"out") + enc_in_dim = get_encoded_dim(encoder_schedule, "in") + enc_out_dim = get_encoded_dim(encoder_schedule, "out") enc_dims = get_encoded_dim(encoder_schedule) @test enc_in_dim == enc_dims["in"] @test enc_out_dim == enc_dims["out"] - @test enc_in_dim == size(get_inputs(encoded_io_pairs),1) - @test enc_out_dim == size(get_outputs(encoded_io_pairs),1) - @test isnothing(get_encoded_dim([],"in")) + @test enc_in_dim == size(get_inputs(encoded_io_pairs), 1) + @test enc_out_dim == size(get_outputs(encoded_io_pairs), 1) + @test isnothing(get_encoded_dim([], "in")) @test_throws ArgumentError get_encoded_dim(encoder_schedule, "bad_in") for (enc_dat, dec_dat, test_dat, enc_covv, dec_covv, test_covv, dim) in zip( (get_inputs(encoded_io_pairs), get_outputs(encoded_io_pairs)), @@ -344,7 +344,7 @@ end (prior_cov, obs_noise_cov), (in_dim, out_dim), ) - + # univariate "rescaling" tests if name == "zscore" stat_vec = [[mean(dd), std(dd)] for dd in eachrow(enc_dat)] From f3fce97402770f029f9c3752dfa3468c118c1e6a Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 11:58:20 -0700 Subject: [PATCH 20/36] test pipeline gets better kwargs --- test/Utilities/runtests.jl | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 8b516b3d4..461331691 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -24,7 +24,14 @@ using CalibrateEmulateSample.ParameterDistributions y_obs = randn(rng, dim_obs) Γy = Matrix{Float64}(I, dim_obs, dim_obs) ekp = EnsembleKalmanProcesses.EnsembleKalmanProcess(initial_ensemble, y_obs, Γy, Inversion(), rng = rng) - g_ens = randn(rng, dim_obs, n_ens) # data are cols + function G(rng, x::MM, Γy) where {MM <: AbstractMatrix} + d_in, d_ens = size(x) + d_out = size(Γy, 1) + A = randn(rng, d_out, d_in) + b = abs.(randn(rng, d_out, 1)) + return A * x .+ b .+ rand(MvNormal(zeros(d_out), Γy), d_ens) + end + g_ens = G(rng, initial_ensemble, Γy) # data are cols EnsembleKalmanProcesses.update_ensemble!(ekp, g_ens) training_points = get_training_points(ekp, 1) @test get_inputs(training_points) ≈ initial_ensemble @@ -44,7 +51,7 @@ using CalibrateEmulateSample.ParameterDistributions @test minimum(eigvals(pdmat2)) >= (1 - 1e-4) * tol # get encoder kwargs from ekp and prior - g_ens_final = randn(rng, dim_obs, n_ens) # add a final set out outputs. + g_ens_final = G(rng, get_ϕ_final(prior, ekp), Γy) encoder_kwargs = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) prior_kwargs = (; prior_cov = cov(prior)) @@ -74,6 +81,8 @@ using CalibrateEmulateSample.ParameterDistributions test_reduced_kwargs = merge(prior_kwargs, obs_kwargs, io_reduced_kwargs) @test all(encoder_reduced_kwargs[key] == test_reduced_kwargs[key] for key in keys(encoder_kwargs)) + # for the following experiments + encoder_kwargs_for_exps = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) end @@ -312,13 +321,23 @@ end lossless = [fill(true, 6); fill(false, length(schedules) - 6)] # are these lossless approximations? + # kwargs - can usually get from EKP + prior_kwargs = (; prior_cov = prior_cov) + obs_kwargs = (; obs_noise_cov = [obs_noise_cov], observation = [vec(out_data[:, 1])]) + io_kwargs = (; + input_structure_vecs = Dict(:dt => [0, 0.5], :samples_in => [in_data, in_data .+ 1]), + output_structure_vecs = Dict(:dt => [0, 0.5], :samples_out => [out_data, out_data .+ 1]), + ) + test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) + + # functional test pipeline tol = 1e-12 for (name, sch, ll_flag) in zip(test_names, schedules, lossless) encoder_schedule = create_encoder_schedule(sch) (encoded_io_pairs, encoded_input_structure_mats, encoded_output_structure_mats, _, _) = - initialize_and_encode_with_schedule!(encoder_schedule, io_pairs; prior_cov, obs_noise_cov) + initialize_and_encode_with_schedule!(encoder_schedule, io_pairs; test_kwargs...) (decoded_io_pairs, decoded_input_structure_mat, decoded_output_structure_mat) = decode_with_schedule( encoder_schedule, From 0e251a573c74d70bead635bd6b4e91c36a9a3e98 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 13:02:00 -0700 Subject: [PATCH 21/36] recreate manifest for docs and julia 1.11.9 --- docs/Manifest.toml | 70 +++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/Manifest.toml b/docs/Manifest.toml index d94662389..101b149f2 100644 --- a/docs/Manifest.toml +++ b/docs/Manifest.toml @@ -1,8 +1,8 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.12.0" +julia_version = "1.11.9" manifest_format = "2.0" -project_hash = "5255fc92659f2799f0f4c5144942145e13d951ed" +project_hash = "e4d965798d55f5903483b71f545533e62ea32fdf" [[deps.ADTypes]] git-tree-sha1 = "bbc22a9a08a0ef6460041086d8a7b27940ed4ffd" @@ -354,7 +354,7 @@ weakdeps = ["Dates", "LinearAlgebra"] [[deps.CompilerSupportLibraries_jll]] deps = ["Artifacts", "Libdl"] uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "1.3.0+1" +version = "1.1.1+0" [[deps.CompositionsBase]] git-tree-sha1 = "802bb88cd69dfd1509f6670416bd4434015693ad" @@ -899,11 +899,6 @@ version = "1.5.2" [deps.JSON.weakdeps] ArrowTypes = "31f734f8-188a-4ce0-8406-c8a06bd891cd" -[[deps.JuliaSyntaxHighlighting]] -deps = ["StyledStrings"] -uuid = "ac6e5ff7-fb65-4e79-a425-ec3bc9c03011" -version = "1.12.0" - [[deps.KernelDensity]] deps = ["Distributions", "DocStringExtensions", "FFTA", "Interpolations", "StatsBase"] git-tree-sha1 = "4260cfc991b8885bf747801fb60dd4503250e478" @@ -973,24 +968,24 @@ uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" version = "0.6.4" [[deps.LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll", "Zlib_jll", "nghttp2_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" -version = "8.11.1+1" +version = "8.6.0+0" [[deps.LibGit2]] -deps = ["LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" version = "1.11.0" [[deps.LibGit2_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "OpenSSL_jll"] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" -version = "1.9.0+0" +version = "1.7.2+0" [[deps.LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "OpenSSL_jll"] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" -version = "1.11.3+1" +version = "1.11.0+1" [[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" @@ -1029,7 +1024,7 @@ version = "7.5.1" [[deps.LinearAlgebra]] deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -version = "1.12.0" +version = "1.11.0" [[deps.LinearMaps]] deps = ["LinearAlgebra"] @@ -1227,7 +1222,7 @@ uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" version = "0.1.8" [[deps.Markdown]] -deps = ["Base64", "JuliaSyntaxHighlighting", "StyledStrings"] +deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" version = "1.11.0" @@ -1257,6 +1252,11 @@ git-tree-sha1 = "51f3fade0b4ff2cf90b36b3312425460631abb56" uuid = "99c1a7ee-ab34-5fd5-8076-27c950a045f4" version = "2.5.6" +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.6+0" + [[deps.Missings]] deps = ["DataAPI"] git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" @@ -1269,7 +1269,7 @@ version = "1.11.0" [[deps.MozillaCACerts_jll]] uuid = "14a3606d-f60d-562e-9121-12d972cd8159" -version = "2025.5.20" +version = "2023.12.12" [[deps.MuladdMacro]] git-tree-sha1 = "cac9cc5499c25554cba55cd3c30543cff5ca4fab" @@ -1320,7 +1320,7 @@ version = "1.0.0" [[deps.NetworkOptions]] uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" -version = "1.3.0" +version = "1.2.0" [[deps.Nullables]] git-tree-sha1 = "8f87854cc8f3685a60689d8edecaa29d2251979b" @@ -1351,12 +1351,12 @@ version = "0.3.33+0" [[deps.OpenBLAS_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.29+0" +version = "0.3.27+1" [[deps.OpenLibm_jll]] deps = ["Artifacts", "Libdl"] uuid = "05823500-19ac-5b8b-9628-191a04bc5112" -version = "0.8.7+0" +version = "0.8.5+0" [[deps.OpenSSH_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "OpenSSL_jll", "Zlib_jll"] @@ -1365,9 +1365,10 @@ uuid = "9bd350c2-7e96-507f-8002-3f2e150b4e1b" version = "10.3.1+0" [[deps.OpenSSL_jll]] -deps = ["Artifacts", "Libdl"] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "2ac022577e5eac7da040de17776d51bb770cd895" uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" -version = "3.5.1+0" +version = "3.5.6+0" [[deps.OpenSpecFun_jll]] deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl"] @@ -1399,7 +1400,7 @@ version = "1.8.1" [[deps.PCRE2_jll]] deps = ["Artifacts", "Libdl"] uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" -version = "10.44.0+1" +version = "10.42.0+1" [[deps.PDMats]] deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] @@ -1428,7 +1429,7 @@ version = "0.44.2+0" [[deps.Pkg]] deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "Random", "SHA", "TOML", "Tar", "UUIDs", "p7zip_jll"] uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" -version = "1.12.0" +version = "1.11.0" weakdeps = ["REPL"] [deps.Pkg.extensions] @@ -1454,9 +1455,9 @@ version = "0.2.4" [[deps.PrecompileTools]] deps = ["Preferences"] -git-tree-sha1 = "07a921781cab75691315adc645096ed5e370cb77" +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" -version = "1.3.3" +version = "1.2.1" [[deps.Preferences]] deps = ["TOML"] @@ -1488,7 +1489,6 @@ uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" version = "1.11.0" [[deps.Profile]] -deps = ["StyledStrings"] uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" version = "1.11.0" @@ -1540,7 +1540,7 @@ uuid = "94ee1d12-ae83-5a48-8b1c-48b8ff168ae0" version = "0.7.7" [[deps.REPL]] -deps = ["InteractiveUtils", "JuliaSyntaxHighlighting", "Markdown", "Sockets", "StyledStrings", "Unicode"] +deps = ["InteractiveUtils", "Markdown", "Sockets", "StyledStrings", "Unicode"] uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" version = "1.11.0" @@ -1721,7 +1721,7 @@ version = "1.2.2" [[deps.SparseArrays]] deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -version = "1.12.0" +version = "1.11.0" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] @@ -1844,7 +1844,7 @@ uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" [[deps.SuiteSparse_jll]] deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "7.8.3+2" +version = "7.7.0+0" [[deps.TOML]] deps = ["Dates"] @@ -2008,7 +2008,7 @@ version = "1.6.0+0" [[deps.Zlib_jll]] deps = ["Libdl"] uuid = "83775a58-1f1d-513f-b197-d71354ab007a" -version = "1.3.1+2" +version = "1.2.13+1" [[deps.ZygoteRules]] deps = ["ChainRulesCore", "MacroTools"] @@ -2031,7 +2031,7 @@ version = "0.17.4+0" [[deps.libblastrampoline_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "5.13.1+1" +version = "5.11.0+0" [[deps.libdrm_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libpciaccess_jll"] @@ -2066,7 +2066,7 @@ version = "1.3.8+0" [[deps.nghttp2_jll]] deps = ["Artifacts", "Libdl"] uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" -version = "1.64.0+1" +version = "1.59.0+0" [[deps.oneTBB_jll]] deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl"] @@ -2077,7 +2077,7 @@ version = "2022.0.0+1" [[deps.p7zip_jll]] deps = ["Artifacts", "Libdl"] uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" -version = "17.5.0+2" +version = "17.4.0+2" [[deps.x264_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] From 528930f18163aff8c32d891e3d8492dd5a5d03c3 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 13:39:12 -0700 Subject: [PATCH 22/36] add coverage --- test/Utilities/runtests.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 461331691..0e9c07791 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -330,6 +330,10 @@ end ) test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) + # quick test without struct. vec, + test_kwargs_no_svs = merge(prior_kwargs, obs_kwargs) + sch_test = (likelihood_informed(retain_info = 0.99), "in_and_out") + initialize_and_encode_with_schedule!(sch_test, io_pairs; test_kwargs_no_svs...) # functional test pipeline tol = 1e-12 @@ -354,6 +358,9 @@ end @test enc_out_dim == size(get_outputs(encoded_io_pairs), 1) @test isnothing(get_encoded_dim([], "in")) @test_throws ArgumentError get_encoded_dim(encoder_schedule, "bad_in") + + + for (enc_dat, dec_dat, test_dat, enc_covv, dec_covv, test_covv, dim) in zip( (get_inputs(encoded_io_pairs), get_outputs(encoded_io_pairs)), (get_inputs(decoded_io_pairs), get_outputs(decoded_io_pairs)), @@ -498,7 +505,7 @@ end # test for some schedules tol = 1e-12 schedules = [ - (zscore_scale(), "in_and_out"), + (zscore_scale(), "in_and out"), (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), [(canonical_correlation(), "in_and_out"), (zscore_scale(), "in_and_out")], [ From ed09626c5684dd1ebd2e478ef4ddd88c1a7ec2e9 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 14:02:46 -0700 Subject: [PATCH 23/36] add apply_to for paired_data_container --- src/Utilities.jl | 6 +++++- test/Utilities/runtests.jl | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Utilities.jl b/src/Utilities.jl index 49d6c5f2b..4473a1ad9 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -546,7 +546,11 @@ function _initialize_and_encode_data!( apply_to::AS, ) where {AS <: AbstractString} initialize_processor!(proc, get_data(data)..., structure_mats..., structure_vecs..., apply_to) - return _encode_data(proc, data, apply_to) + if apply_to ∈ ["in", "out"] + return _encode_data(proc, data, apply_to) + else + bad_apply_to(apply_to) + end end function _initialize_and_encode_data!( diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 0e9c07791..09404221e 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -332,7 +332,7 @@ end # quick test without struct. vec, test_kwargs_no_svs = merge(prior_kwargs, obs_kwargs) - sch_test = (likelihood_informed(retain_info = 0.99), "in_and_out") + sch_test = create_encoder_schedule((likelihood_informed(retain_info = 0.85), "in_and_out")) initialize_and_encode_with_schedule!(sch_test, io_pairs; test_kwargs_no_svs...) # functional test pipeline From 4bfc315968c4eede1248a899061f2d072895db42 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 14:12:37 -0700 Subject: [PATCH 24/36] typo --- test/Utilities/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 09404221e..5117fde4d 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -505,7 +505,7 @@ end # test for some schedules tol = 1e-12 schedules = [ - (zscore_scale(), "in_and out"), + (zscore_scale(), "in_and_out"), (decorrelate_structure_mat(retain_var = 0.95), "in_and_out"), [(canonical_correlation(), "in_and_out"), (zscore_scale(), "in_and_out")], [ From 7134a070d60859160fcf56edddff9cb666333b74 Mon Sep 17 00:00:00 2001 From: odunbar Date: Fri, 1 May 2026 15:11:09 -0700 Subject: [PATCH 25/36] format --- test/Utilities/runtests.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 5117fde4d..cd14d3486 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -358,9 +358,9 @@ end @test enc_out_dim == size(get_outputs(encoded_io_pairs), 1) @test isnothing(get_encoded_dim([], "in")) @test_throws ArgumentError get_encoded_dim(encoder_schedule, "bad_in") - - - + + + for (enc_dat, dec_dat, test_dat, enc_covv, dec_covv, test_covv, dim) in zip( (get_inputs(encoded_io_pairs), get_outputs(encoded_io_pairs)), (get_inputs(decoded_io_pairs), get_outputs(decoded_io_pairs)), From d2fca838196c36b93501139c4e0c1698e5ff8e76 Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 11:53:06 -0700 Subject: [PATCH 26/36] nicer table, and bugfix ref with deepcopy --- examples/DimensionReduction/Project.toml | 3 +- examples/DimensionReduction/calibrate.jl | 29 ++--- examples/DimensionReduction/emulate_sample.jl | 106 ++++++++++-------- examples/DimensionReduction/models.jl | 16 +++ 4 files changed, 89 insertions(+), 65 deletions(-) diff --git a/examples/DimensionReduction/Project.toml b/examples/DimensionReduction/Project.toml index a1b195d9d..04a347cf2 100644 --- a/examples/DimensionReduction/Project.toml +++ b/examples/DimensionReduction/Project.toml @@ -2,6 +2,7 @@ AdvancedMH = "5b7e9947-ddc0-4b3f-9b55-0d8042f74170" CalibrateEmulateSample = "95e48a1f-0bec-4818-9538-3db4340308e3" ChunkSplitters = "ae650224-84b6-46f8-82ea-d812ca08434e" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" EnsembleKalmanProcesses = "aa8a2aa5-91d8-4396-bcef-d4f2ec43552d" @@ -14,4 +15,4 @@ Manifolds = "1cead3c2-87b3-11e9-0ccd-23c62b72b94e" Manopt = "0fc0a36d-df90-57f3-8f93-d78a9fc72bb5" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" \ No newline at end of file +StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" diff --git a/examples/DimensionReduction/calibrate.jl b/examples/DimensionReduction/calibrate.jl index e0dcb469e..f873e13fc 100644 --- a/examples/DimensionReduction/calibrate.jl +++ b/examples/DimensionReduction/calibrate.jl @@ -4,30 +4,18 @@ using JLD2 using LinearAlgebra using Random -include("./models.jl") + +include("./models.jl") # defines dims, files, mod_type # select the forward map -mod_types = ["linear"] -mod_type = mod_types[1] @info "Executing model type $(mod_type)" -datadir = joinpath(@__DIR__, "datafiles") -if !isdir(datadir) - mkpath(datadir) -end - -rng = Random.MersenneTwister(41) -input_dim = 100 -output_dim = 100 - -num_trials = 5 -for trial in 1:num_trials - @info "Trial $trial" +function main() if mod_type == "linear" prior_cov, y, obs_noise_cov, model, true_parameter = lin(input_dim, output_dim, rng) else bad_model(mod_type, mod_types) end - + prior_obj = ParameterDistribution( Parameterized(MvNormal(zeros(size(prior_cov, 1)), prior_cov)), fill(no_constraint(), size(prior_cov, 1)), @@ -37,9 +25,10 @@ for trial in 1:num_trials n_ensemble = 50 initial_ensemble = construct_initial_ensemble(rng, prior_obj, n_ensemble) ekp = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, TransformInversion(); rng) - + + max_iter = 20 n_iters = 0 - for i in 1:50 + for i in 1:max_iter n_iters += 1 G_ens = hcat([forward_map(param, model) for param in eachcol(get_ϕ_final(prior_obj, ekp))]...) terminate = update_ensemble!(ekp, G_ens) @@ -60,7 +49,7 @@ for trial in 1:num_trials #! format: off save( - joinpath(datadir,"ekp_$(mod_type)_$(trial).jld2"), + joinpath(datadir,"ekp_$(mod_type).jld2"), "ekpobj", ekp, "ekp_samples", ekp_samples, "prior_obj", prior_obj, @@ -71,4 +60,6 @@ for trial in 1:num_trials "alphas", αs, ) #! format: on + end +main() diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index 1a48347bc..507bb4640 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -5,7 +5,7 @@ using LinearAlgebra using Random using MCMCChains using AdvancedMH - +using DataFrames # table print at end # CES using CalibrateEmulateSample.Emulators using CalibrateEmulateSample.MarkovChainMonteCarlo @@ -18,13 +18,8 @@ mod_types = ["linear"] mod_type = mod_types[1] @info "Executing model type $(mod_type)" -rng = Random.MersenneTwister(41) -input_dim = 100 -output_dim = 100 - -num_trials = 1 -for trial in 1:num_trials - loaded = load("datafiles/ekp_$(mod_type)_$(trial).jld2") +function main() + loaded = load("datafiles/ekp_$(mod_type).jld2") ekpobj = loaded["ekpobj"] ekp_samples = loaded["ekp_samples"] prior = loaded["prior_obj"] @@ -33,111 +28,132 @@ for trial in 1:num_trials model = loaded["model"] true_parameter = loaded["true_parameter"] αs = loaded["alphas"] - + mask=[1,length(αs)] # don't do all cases + αs = αs[mask] + min_iter = 1 max_iter = min(10, length(αs)) # number of EKP iterations to use data from is at most this training_points = [ekp_samples[α] for α in αs[min_iter:max_iter]] - + encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] - - rvs = [0.9, 0.94, 0.98, 0.99, 0.995, 0.999] - rkls = rvs - all_errs = zeros(length(rvs), 1 + length(αs)) - + + # chosen some truncations with similar dimension + rvs_rinfos = [ + (0.995, 0.999999), + (0.99, 0.9999), + (0.98, 0.999), + (0.94, 0.94), + (0.9, 0.88), + ] + all_errs = zeros(length(rvs_rinfos), 1 + length(αs)) + # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor final_samples_out = ekp_samples[αs[end]][2] encoder_kwargs = encoder_kwargs_from(ekpobj, prior; final_samples_out = final_samples_out) - + flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final = final_samples_out) + + names = ["reference", "PCA-in", ["LI-in 1:$(i)" for i in mask]...] - names = ["reference", "decorrelate, PCA-in", ["decorrelate, LI-in 1:$(i)" for i in 1:length(αs)]...] - + if mod_type == "linear" - ni_scaling = 0.01 # noise injection into null space scaling (def. 1) + ni_scaling = 0.0 # noise injection into null space scaling (def. 1) else bad_model(mod_type, mod_types) end - - reduced_dims = zeros(Int, length(rvs), length(αs) + 2) # store reduced dims for final table - - for (idx, (rv, rkl)) in enumerate(zip(rvs, rkls)) + + reduced_dims = zeros(Int, length(rvs_rinfos), length(αs) + 2) # store reduced dims for final table + + for (idx, rv_rinfo) in enumerate(rvs_rinfos) + rv, rinfo = rv_rinfo encoder_schedule_decorrelate = [(decorrelate_structure_mat(retain_var = rv), "in"), (decorrelate_structure_mat(), "out")] encoder_schedules_li = [ - [(decorrelate_structure_mat(), "in_and_out"), (likelihood_informed(retain_info = rkl, iters = 1:i), "in")] for i in 1:length(αs) - ] - + [(decorrelate_structure_mat(), "in_and_out"), (likelihood_informed(retain_info = rinfo, iters = 1:i), "in")] for i in mask + ] + em_ref = forward_map_wrapper( param -> forward_map(param, model), prior, flat_io_pairs; - encoder_schedule = encoder_schedule_ref, + encoder_schedule = deepcopy(encoder_schedule_ref), encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, # shouldnt be needed ) - + em_decorrelate = forward_map_wrapper( param -> forward_map(param, model), prior, flat_io_pairs; - encoder_schedule = encoder_schedule_decorrelate, + encoder_schedule = deepcopy(encoder_schedule_decorrelate), encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, ) - + ems_li = [ forward_map_wrapper( param -> forward_map(param, model), prior, flat_io_pairs; - encoder_schedule = encoder_schedule, + encoder_schedule = deepcopy(encoder_schedule), encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, ) for encoder_schedule in encoder_schedules_li - ] + ] post_means = reshape(true_parameter, input_dim, 1) post_covs = [] for (iidx, nn, em) in zip(1:length(names), names, vcat(em_ref, em_decorrelate, ems_li...)) - + reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em), "in") println(" ") @info "Encoding name: $(nn)" E, _ = get_encoder_from_schedule(get_encoder_schedule(em), "in") - + if isnothing(E) @info "No truncation" else ed = get_encoded_dim(get_encoder_schedule(em), "in") - @info "Truncation criteria (var>$(rv), or kl > $(rkl))" + @info "Truncation criteria (var>$(rv), or information > $(rinfo))" @info "input dim reduced to: $(ed)" - + end println(" ") u0 = rand(MvNormal(mean(prior), cov(prior))) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) new_step = optimize_stepsize(mcmc; init_stepsize = 0.05, N = 2000, discard_initial = 0) - + println("Begin MCMC - with step size ", new_step) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) chain = MarkovChainMonteCarlo.sample(mcmc, 40_000; stepsize = new_step, discard_initial = 5_000) posterior = MarkovChainMonteCarlo.get_posterior(mcmc, chain) - + post_mean = mean(posterior) post_cov = cov(posterior) - + post_means = hcat(post_means, reshape(post_mean, input_dim, 1)) push!(post_covs, post_cov) end - + # post_means[:,1] = true parameter # post_means[:,2] = ref # post_means[:,3] = decor, LI etc. # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) all_errs[idx, :] = [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' end - @info "error of posterior mean to whitened \"reference\" solution. for $(names[2:end])" - display(all_errs) - @info "... and their reduced dimensions" - display(reduced_dims[:, 2:end]) - + + df = DataFrame(all_errs, [Symbol(n) for n in names[2:end]]) + + # build dataframe + pairs =[(reduced_dims[i, j+1], all_errs[i, j]) + for i in axes(all_errs, 1), j in axes(all_errs, 2)] + + df = DataFrame(pairs, Symbol.(names[2:end])) # columns = names + df.truncation = rvs_rinfos # add row labels + return df, all_errs, reduced_dims[:, 2:end] end + +df, all_errs, red_dims = main() + +@info "(reduced_dim, error) of posterior mean to whitened \"reference\" solution,\n when using the truncation ({for PCA}, {for LI})" +select!(df, :truncation, :) + diff --git a/examples/DimensionReduction/models.jl b/examples/DimensionReduction/models.jl index b39346e7f..34e5fd9a7 100644 --- a/examples/DimensionReduction/models.jl +++ b/examples/DimensionReduction/models.jl @@ -11,6 +11,22 @@ function bad_model_type(mod_type, mod_types) throw(ArgumentError("Unknown model type provided: $(mod_type), please choose from $(mod_types)")) end +# setup parameters +input_dim = 100 +output_dim = 100 + +datadir = joinpath(@__DIR__, "datafiles") +if !isdir(datadir) + mkpath(datadir) +end + +rng = Random.MersenneTwister(41) + +mod_types = ["linear"] +mod_type = mod_types[1] + + + ## Linear struct Lin{AM <: AbstractMatrix} <: ForwardMapType input_dim::Int From 7dd956009900ff04a1806f91c9f4ed00b1dedbe8 Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 12:16:24 -0700 Subject: [PATCH 27/36] format --- examples/DimensionReduction/calibrate.jl | 8 +-- examples/DimensionReduction/emulate_sample.jl | 67 +++++++++---------- 2 files changed, 35 insertions(+), 40 deletions(-) diff --git a/examples/DimensionReduction/calibrate.jl b/examples/DimensionReduction/calibrate.jl index f873e13fc..a12218d7b 100644 --- a/examples/DimensionReduction/calibrate.jl +++ b/examples/DimensionReduction/calibrate.jl @@ -15,20 +15,20 @@ function main() else bad_model(mod_type, mod_types) end - + prior_obj = ParameterDistribution( Parameterized(MvNormal(zeros(size(prior_cov, 1)), prior_cov)), fill(no_constraint(), size(prior_cov, 1)), "$(mod_type)_prior", ) - n_ensemble = 50 + n_ensemble = 80 initial_ensemble = construct_initial_ensemble(rng, prior_obj, n_ensemble) ekp = EnsembleKalmanProcess(initial_ensemble, y, obs_noise_cov, TransformInversion(); rng) - + max_iter = 20 n_iters = 0 - for i in 1:max_iter + for i in 1:max_iter n_iters += 1 G_ens = hcat([forward_map(param, model) for param in eachcol(get_ϕ_final(prior_obj, ekp))]...) terminate = update_ensemble!(ekp, G_ens) diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index 507bb4640..35337dd57 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -28,50 +28,47 @@ function main() model = loaded["model"] true_parameter = loaded["true_parameter"] αs = loaded["alphas"] - mask=[1,length(αs)] # don't do all cases + mask = [1, length(αs)] # don't do all cases αs = αs[mask] - + min_iter = 1 max_iter = min(10, length(αs)) # number of EKP iterations to use data from is at most this training_points = [ekp_samples[α] for α in αs[min_iter:max_iter]] - + encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] - + # chosen some truncations with similar dimension - rvs_rinfos = [ - (0.995, 0.999999), - (0.99, 0.9999), - (0.98, 0.999), - (0.94, 0.94), - (0.9, 0.88), - ] + rvs_rinfos = [(0.995, 0.999999), (0.99, 0.9999), (0.98, 0.999), (0.94, 0.94), (0.9, 0.88)] all_errs = zeros(length(rvs_rinfos), 1 + length(αs)) - + # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor final_samples_out = ekp_samples[αs[end]][2] encoder_kwargs = encoder_kwargs_from(ekpobj, prior; final_samples_out = final_samples_out) - + flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final = final_samples_out) - + names = ["reference", "PCA-in", ["LI-in 1:$(i)" for i in mask]...] - + if mod_type == "linear" ni_scaling = 0.0 # noise injection into null space scaling (def. 1) else bad_model(mod_type, mod_types) end - + reduced_dims = zeros(Int, length(rvs_rinfos), length(αs) + 2) # store reduced dims for final table - + for (idx, rv_rinfo) in enumerate(rvs_rinfos) rv, rinfo = rv_rinfo encoder_schedule_decorrelate = [(decorrelate_structure_mat(retain_var = rv), "in"), (decorrelate_structure_mat(), "out")] encoder_schedules_li = [ - [(decorrelate_structure_mat(), "in_and_out"), (likelihood_informed(retain_info = rinfo, iters = 1:i), "in")] for i in mask - ] - + [ + (decorrelate_structure_mat(), "in_and_out"), + (likelihood_informed(retain_info = rinfo, iters = 1:i), "in"), + ] for i in mask + ] + em_ref = forward_map_wrapper( param -> forward_map(param, model), prior, @@ -80,7 +77,7 @@ function main() encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, # shouldnt be needed ) - + em_decorrelate = forward_map_wrapper( param -> forward_map(param, model), prior, @@ -89,7 +86,7 @@ function main() encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, ) - + ems_li = [ forward_map_wrapper( param -> forward_map(param, model), @@ -99,54 +96,53 @@ function main() encoder_kwargs = deepcopy(encoder_kwargs), noise_injector_scaling = ni_scaling, ) for encoder_schedule in encoder_schedules_li - ] + ] post_means = reshape(true_parameter, input_dim, 1) post_covs = [] for (iidx, nn, em) in zip(1:length(names), names, vcat(em_ref, em_decorrelate, ems_li...)) - + reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em), "in") println(" ") @info "Encoding name: $(nn)" E, _ = get_encoder_from_schedule(get_encoder_schedule(em), "in") - + if isnothing(E) @info "No truncation" else ed = get_encoded_dim(get_encoder_schedule(em), "in") @info "Truncation criteria (var>$(rv), or information > $(rinfo))" @info "input dim reduced to: $(ed)" - + end println(" ") u0 = rand(MvNormal(mean(prior), cov(prior))) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) new_step = optimize_stepsize(mcmc; init_stepsize = 0.05, N = 2000, discard_initial = 0) - + println("Begin MCMC - with step size ", new_step) mcmc = MCMCWrapper(RWMHSampling(), y, prior, em; init_params = u0) chain = MarkovChainMonteCarlo.sample(mcmc, 40_000; stepsize = new_step, discard_initial = 5_000) posterior = MarkovChainMonteCarlo.get_posterior(mcmc, chain) - + post_mean = mean(posterior) post_cov = cov(posterior) - + post_means = hcat(post_means, reshape(post_mean, input_dim, 1)) push!(post_covs, post_cov) end - + # post_means[:,1] = true parameter # post_means[:,2] = ref # post_means[:,3] = decor, LI etc. # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) all_errs[idx, :] = [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' end - + df = DataFrame(all_errs, [Symbol(n) for n in names[2:end]]) - + # build dataframe - pairs =[(reduced_dims[i, j+1], all_errs[i, j]) - for i in axes(all_errs, 1), j in axes(all_errs, 2)] - + pairs = [(reduced_dims[i, j + 1], all_errs[i, j]) for i in axes(all_errs, 1), j in axes(all_errs, 2)] + df = DataFrame(pairs, Symbol.(names[2:end])) # columns = names df.truncation = rvs_rinfos # add row labels return df, all_errs, reduced_dims[:, 2:end] @@ -156,4 +152,3 @@ df, all_errs, red_dims = main() @info "(reduced_dim, error) of posterior mean to whitened \"reference\" solution,\n when using the truncation ({for PCA}, {for LI})" select!(df, :truncation, :) - From c1405a267077eae5e85b1121fd66fbd8c84bc5f9 Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 13:04:51 -0700 Subject: [PATCH 28/36] docs update --- docs/src/data_processing.md | 68 +++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/docs/src/data_processing.md b/docs/src/data_processing.md index 662bcad95..9225d7c30 100644 --- a/docs/src/data_processing.md +++ b/docs/src/data_processing.md @@ -12,37 +12,72 @@ The framework works as follows An external API is also available using the `encode_data`, and `encode_structure_matrix` methods if needed to encode new data, or new covariance-type matrices. ## Defaults and recommendations -### Default schedule (no explicit dimension reduction) -When no schedule is provided, i.e. + +### Recommended schedule: ("latest and greatest") + +Given `ekp` and `prior` from an ensemble kalman process run (e.g., the "Calibrate" stage). Assume we have chosen our machine learning tool and obtained training data. Our recommendeded family to balance efficiency and reduce dimension is to use the `retain_var` and `retain_info`. + ```julia -emulator = Emulator(machine_learning_tool, input_output_pairs) +retain_var = 0.999 # reduce dimension retaining 99.9% of variance (for PCA) +retain_info = 0.999 # reduce dimension retaining 99.9% of information (for likelihood-informed) +ekp_it = 5 # number of eki iteration (for likelihood-informed) + +encoder_schedule = [ + (decorrelate_sample_cov(retain_var = retain_var), "in"), + (decorrelate_structure_mat(retain_var = retain_var), "out"), + (likelihood_informed(retain_info=retain_info, iters = 1:ekp_it), "in"), + (likelihood_informed(retain_info=retain_info, iters = 1:1), "out"), +] ``` -The default schedule under-the-hood, is given by +The motivation is that PCA is an efficient, but blunt, tool for reducing dimension from ((>100s) -> (100s)) dimension, then use likelihood-informed tools to hone down ((100s) -> (10s)) dimensions. `iters=1:X` is more performant in input than output dimension for `X>1` so we only do this here. This schedule is added to the emulator as follows +``` +emulator = Emulator( + machine_learning_tool, + input_output_pairs; + encoder_schedule = encoder_schedule, + encoder_kwargs = encoder_kwargs_from(ekp, prior), # kwargs from "Calibrate" objects +) +``` + +## Recommended: get `encoder_kwargs` from and `EnsembleKalmanProcess` and `Prior` + +To transition more smoothly from the `EnsembleKalmanProcesses` infrastructure, one can get the kwargs in the `EnsembleKalmanProcesses.jl` package. This will provide a superset of kwargs that work for any of the data-processors. + ```julia -schedule = (decorrelate_sample_cov(), "in_and_out") +# `prior::ParameterDistribution` +# `ekp::EnsembleKalmanProcess` +encoder_kwargs = encoder_kwargs_from(ekp, prior) ``` -If the user only provides the observational noise covariance, + +### Default schedule (whiten with no dimension reduction) +When the user provides no `encoder_schedule`, the following is created ```julia emulator = Emulator( machine_learning_tool, input_output_pairs; - encoder_kwargs = (; obs_noise_cov = obs_noise_cov), + encoder_kwargs = encoder_kwargs, ) ``` The default schedule under-the-hood, is given by ```julia schedule = [ (decorrelate_sample_cov(), "in"), - (decorrelate_structure_mat(), "out"), # uses obs_noise_cov + (decorrelate_structure_mat(), "out"), # uses obs_noise_cov kwarg +] +``` +With no kwargs also provided, the following schedule under-the-hood, is given by +```julia +schedule = [ + (decorrelate_sample_cov(), "in_and_out"), ] ``` !!! note "Switch encoding off" To ensure that no encoding is happening, the user must pass in an empty schedule `encoder_schedule = []` -### Recommended: schedule for PCA dimension reduction +## Other typical schedule: PCA dimension reduction -Our recommendeded family to balance efficiency and reduce dimension is to use the `retain_var` kwargs. +Robust and blunt dimension reduction can be done with only PCA ```julia retain_var_in = 0.99 # reduce dimension retaining 99% of input variance retain_var_out = 0.95 # reduce dimension retaining 95% of output variance @@ -59,22 +94,21 @@ emulator = Emulator( encoder_kwargs = encoder_kwargs, ) ``` -## Recommended: Get `encoder_kwargs` from `ObservationSeries` etc. +## kwargs from other objects: -To transition more smoothly from the `EnsembleKalmanProcesses` infrastructure, one can also get the kwargs in the desired format from any [`Observation` and `ObservationSeries`](https://clima.github.io/EnsembleKalmanProcesses.jl/dev/observations/) objects, as well as [`ParameterDistribution`](https://clima.github.io/EnsembleKalmanProcesses.jl/dev/parameter_distributions/) objects used in the `EnsembleKalmanProcesses.jl` package. +One can also obtain individual kwarg sets from other objects, and can merge these as follows ```julia # `prior::ParameterDistribution` -input_kwargs = get_kwargs_from(prior) - # `observation_series::ObservationSeries` +input_kwargs = get_kwargs_from(prior) output_kwargs = get_kwargs_from(observation_series) - encoder_kwargs = merge(input_kwargs, output_kwargs) ``` + +Though not recommended, you can also build your own keyword arguments. !!! note "Observational noise notes" 1. The `obs_noise_cov` object does not need to be a constructed `AbstractMatrix`, rather it can be any type of compactly stored matrix compatible with `EnsembleKalmanProcesses` (e.g., [here](https://clima.github.io/EnsembleKalmanProcesses.jl/dev/observations/)). - 2. When `ObservationSeries` contains multiple observations, it is assumed that the covariance of the noise of all observations are the same. (If they are not, only the first will be taken by default in `get_kwargs_from(...)` - + 2. When `ObservationSeries` contains multiple observations, it is assumed that the covariance of the noise of all observations are the same. (If they are not, only the first will be taken by default in `get_kwargs_from(...)` ## Building and interpreting encoder schedules From a2323d8083c36acbffe9fb27491b4bee0f45ab7b Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 15:28:33 -0700 Subject: [PATCH 29/36] refine example setup for LI 1:5 in 1:1 out --- examples/DimensionReduction/emulate_sample.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index 35337dd57..cc905a394 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -35,10 +35,10 @@ function main() max_iter = min(10, length(αs)) # number of EKP iterations to use data from is at most this training_points = [ekp_samples[α] for α in αs[min_iter:max_iter]] - encoder_schedule_ref = [(decorrelate_structure_mat(; retain_var = 1.0), "in_and_out")] + encoder_schedule_ref = [(decorrelate_structure_mat(), "in_and_out")] # chosen some truncations with similar dimension - rvs_rinfos = [(0.995, 0.999999), (0.99, 0.9999), (0.98, 0.999), (0.94, 0.94), (0.9, 0.88)] + rvs_rinfos = [(0.995, 0.99999), (0.99, 0.9999), (0.98, 0.999), (0.95, 0.99), (0.9, 0.95)] all_errs = zeros(length(rvs_rinfos), 1 + length(αs)) # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor @@ -47,11 +47,11 @@ function main() flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final = final_samples_out) - names = ["reference", "PCA-in", ["LI-in 1:$(i)" for i in mask]...] + names = ["reference", "PCA-in-out", ["LI-in(1:$(i))-out(1:1)" for i in mask]...] if mod_type == "linear" - ni_scaling = 0.0 # noise injection into null space scaling (def. 1) + ni_scaling = 0.0 # noise injection when eval forward map (def. 1) else bad_model(mod_type, mod_types) end @@ -60,12 +60,12 @@ function main() for (idx, rv_rinfo) in enumerate(rvs_rinfos) rv, rinfo = rv_rinfo - encoder_schedule_decorrelate = - [(decorrelate_structure_mat(retain_var = rv), "in"), (decorrelate_structure_mat(), "out")] + encoder_schedule_decorrelate = [(decorrelate_structure_mat(retain_var = rv), "in_and_out")] encoder_schedules_li = [ [ (decorrelate_structure_mat(), "in_and_out"), (likelihood_informed(retain_info = rinfo, iters = 1:i), "in"), + (likelihood_informed(retain_info = rinfo, iters = 1:1), "out"), ] for i in mask ] From 02b4fcc11a99cdbde3443fea7ba4030e2b50269e Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 19:03:54 -0700 Subject: [PATCH 30/36] add ref in as comparison to true parameters in example --- examples/DimensionReduction/emulate_sample.jl | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index cc905a394..8b03de090 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -38,8 +38,7 @@ function main() encoder_schedule_ref = [(decorrelate_structure_mat(), "in_and_out")] # chosen some truncations with similar dimension - rvs_rinfos = [(0.995, 0.99999), (0.99, 0.9999), (0.98, 0.999), (0.95, 0.99), (0.9, 0.95)] - all_errs = zeros(length(rvs_rinfos), 1 + length(αs)) + rvs_rinfos = [(0.995, 0.99995), (0.99, 0.9995), (0.98, 0.995), (0.95, 0.97), (0.9, 0.9)] # as we have more input samples than out stored in ekp. we provide the extended set of outputs to be used in the likelihood informed processor final_samples_out = ekp_samples[αs[end]][2] @@ -47,7 +46,7 @@ function main() flat_io_pairs = get_training_points(ekpobj, min_iter:max_iter, g_final = final_samples_out) - names = ["reference", "PCA-in-out", ["LI-in(1:$(i))-out(1:1)" for i in mask]...] + names = ["reference", "PCA-in-out", "PCA(mat)-in-out", ["LI-in(1:$(i))-out(1:1)" for i in mask]...] if mod_type == "linear" @@ -56,10 +55,12 @@ function main() bad_model(mod_type, mod_types) end - reduced_dims = zeros(Int, length(rvs_rinfos), length(αs) + 2) # store reduced dims for final table + all_errs = zeros(length(rvs_rinfos), length(names)) + reduced_dims = zeros(Int, length(rvs_rinfos), length(names)) # store reduced dims for final table for (idx, rv_rinfo) in enumerate(rvs_rinfos) rv, rinfo = rv_rinfo + encoder_schedule_decorrelate_samp = [(decorrelate_sample_cov(retain_var = rv), "in_and_out")] encoder_schedule_decorrelate = [(decorrelate_structure_mat(retain_var = rv), "in_and_out")] encoder_schedules_li = [ [ @@ -78,6 +79,15 @@ function main() noise_injector_scaling = ni_scaling, # shouldnt be needed ) + em_decorrelate_samp = forward_map_wrapper( + param -> forward_map(param, model), + prior, + flat_io_pairs; + encoder_schedule = deepcopy(encoder_schedule_decorrelate_samp), + encoder_kwargs = deepcopy(encoder_kwargs), + noise_injector_scaling = ni_scaling, + ) + em_decorrelate = forward_map_wrapper( param -> forward_map(param, model), prior, @@ -87,6 +97,7 @@ function main() noise_injector_scaling = ni_scaling, ) + ems_li = [ forward_map_wrapper( param -> forward_map(param, model), @@ -99,7 +110,7 @@ function main() ] post_means = reshape(true_parameter, input_dim, 1) post_covs = [] - for (iidx, nn, em) in zip(1:length(names), names, vcat(em_ref, em_decorrelate, ems_li...)) + for (iidx, nn, em) in zip(1:length(names), names, vcat(em_ref, em_decorrelate_samp, em_decorrelate, ems_li...)) reduced_dims[idx, iidx] = get_encoded_dim(get_encoder_schedule(em), "in") println(" ") @@ -135,20 +146,21 @@ function main() # post_means[:,2] = ref # post_means[:,3] = decor, LI etc. # so err cols are normalized diff to ref of (decor, LI etc.) (lower is better) - all_errs[idx, :] = [norm(post_means[:, 2] - v) / norm(post_means[:, 2]) for v in eachcol(post_means[:, 3:end])]' + all_errs[idx, :] = [norm(post_means[:, 1] - v) / norm(post_means[:, 1]) for v in eachcol(post_means[:, 2:end])]' end - df = DataFrame(all_errs, [Symbol(n) for n in names[2:end]]) + df = DataFrame(all_errs, [Symbol(n) for n in names[1:end]]) # build dataframe - pairs = [(reduced_dims[i, j + 1], all_errs[i, j]) for i in axes(all_errs, 1), j in axes(all_errs, 2)] + @info size(reduced_dims), size(all_errs) + pairs = [(reduced_dims[i, j], all_errs[i, j]) for i in axes(all_errs, 1), j in axes(all_errs, 2)] - df = DataFrame(pairs, Symbol.(names[2:end])) # columns = names + df = DataFrame(pairs, Symbol.(names[1:end])) # columns = names df.truncation = rvs_rinfos # add row labels - return df, all_errs, reduced_dims[:, 2:end] + return df, all_errs, reduced_dims[:, 1:end] end df, all_errs, red_dims = main() @info "(reduced_dim, error) of posterior mean to whitened \"reference\" solution,\n when using the truncation ({for PCA}, {for LI})" -select!(df, :truncation, :) +select!(df, :reference, :) From 9474c1f16e79d80717c92cbe57de74e2fcea9e2f Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 19:21:25 -0700 Subject: [PATCH 31/36] remove extra message --- examples/DimensionReduction/emulate_sample.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/DimensionReduction/emulate_sample.jl b/examples/DimensionReduction/emulate_sample.jl index 8b03de090..10efcb5ea 100644 --- a/examples/DimensionReduction/emulate_sample.jl +++ b/examples/DimensionReduction/emulate_sample.jl @@ -152,7 +152,6 @@ function main() df = DataFrame(all_errs, [Symbol(n) for n in names[1:end]]) # build dataframe - @info size(reduced_dims), size(all_errs) pairs = [(reduced_dims[i, j], all_errs[i, j]) for i in axes(all_errs, 1), j in axes(all_errs, 2)] df = DataFrame(pairs, Symbol.(names[1:end])) # columns = names From 8a294b341eabade61e74c7f330a60a2f9fa27a79 Mon Sep 17 00:00:00 2001 From: odunbar Date: Mon, 4 May 2026 19:28:16 -0700 Subject: [PATCH 32/36] docs improvement --- docs/src/data_processing.md | 2 +- src/Utilities/likelihood_informed.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/data_processing.md b/docs/src/data_processing.md index 9225d7c30..4f6c1a21d 100644 --- a/docs/src/data_processing.md +++ b/docs/src/data_processing.md @@ -179,7 +179,7 @@ The `DataContainerProcessor` encodes "input" data agnostic of the "output" data, The `PairedDataContainerProcessor` encodes inputs (or outputs) using information of the both inputs and outputs in pairs - `CanonicalCorrelation` - constructed with `canonical_correlation()`, which performs [canonical correlation analysis](https://en.wikipedia.org/wiki/Canonical_correlation) to process the pairs. In effect this performs PCA on the cross-correlation from input and output samples. -- [Coming soon] `LikelihoodInformed` - this will use the data or likelihood from the inverse problem at hand to build diagnostic matrices that are used to find informative directions for dimension reduction. In particular we build generalizations of current frameworks (e.g., [Cui, Zahm 2021](http://doi.org/10.1088/1361-6420/abeafb), [Baptista, Marzouk, Zahm 2022](https://arxiv.org/abs/2207.08670)) to use the latest EKP iterations. +- `LikelihoodInformed`- constructed with `likelihood_informed()`- we use the data or likelihood from the inverse problem at hand to build diagnostic matrices that are used to find informative directions for dimension reduction. In particular we build generalizations of current frameworks (e.g., [Cui, Zahm 2021](http://doi.org/10.1088/1361-6420/abeafb), [Baptista, Marzouk, Zahm 2022](https://arxiv.org/abs/2207.08670)) to use the latest EKP iterations. We in fact generalize this framework here [Preprint Coming soon] for use in partially-informed distributions (e.g. EKI iterations) This is an extensible framework, and so new data processors can be added to this library. diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index 78873058b..3e66b0390 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -34,8 +34,8 @@ end $(TYPEDSIGNATURES) Constructs the `LikelihoodInformed` struct. Keywords: -- `retain_info`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - retain_info). Choose `retain_info` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. -- `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution ∝ π_prior(x) π_likelihood(y | x)^α with α ∈ [0, 1]. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. +- `retain_info`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - `retain_info`). Choose `retain_info` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. +- `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution `∝ π_prior(x) π_likelihood(y | x)^α` with `α ∈ [0, 1]`. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. - `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). """ function likelihood_informed(; retain_info = 1, iters = 1, grad_type = :linreg) From 9804ba20abb3c774fcb03a52c5581061f9c9e5b6 Mon Sep 17 00:00:00 2001 From: odunbar Date: Tue, 5 May 2026 11:00:09 -0700 Subject: [PATCH 33/36] codecov --- src/Utilities.jl | 2 +- test/Utilities/runtests.jl | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Utilities.jl b/src/Utilities.jl index 4473a1ad9..978763d95 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -213,7 +213,7 @@ function encoder_kwargs_from( push!(samples_out, final_samples_out) else # add a vector of matrices if length(samples_out) > 0 - @assert(size(samples_out[1]) == size(final_samples_out[1])) + @assert all(size(samples_out[1]) == size(so) for so in final_samples_out) end samples_out = reduce(vcat, [samples_out, final_samples_out]) end diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index cd14d3486..3405e6bd5 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -73,14 +73,25 @@ using CalibrateEmulateSample.ParameterDistributions :dt => [0, get_algorithm_time(ekp)...][1:(end - 1)], :samples_in => get_u(ekp)[1:(end - 1)], ), - output_structure_vecs = Dict( - :dt => [0, get_algorithm_time(ekp)...][1:(end - 1)], - :samples_out => [get_g(ekp)...], - ), + output_structure_vecs = Dict(:dt => [0, get_algorithm_time(ekp)...][1:(end - 1)], :samples_out => get_g(ekp)), ) test_reduced_kwargs = merge(prior_kwargs, obs_kwargs, io_reduced_kwargs) @test all(encoder_reduced_kwargs[key] == test_reduced_kwargs[key] for key in keys(encoder_kwargs)) + # replace samples: + encoder_reduced_kwargs_2 = encoder_kwargs_from( + ekp, + prior; + dt = [0, 0, get_algorithm_time(ekp)...], + samples_in = [get_u(ekp)[1], get_u(ekp)[1], get_u(ekp)[1]], + samples_out = [get_g(ekp)[1]], # 2-short + final_samples_out = [get_g(ekp)[1], g_ens_final], # extend by 2 + ) + + @test encoder_reduced_kwargs_2[:output_structure_vecs] == + Dict(:dt => [0, 0, get_algorithm_time(ekp)...], :samples_out => [get_g(ekp)[1], get_g(ekp)[1], g_ens_final]) + + # for the following experiments encoder_kwargs_for_exps = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) end From 3ed768740bc7d3db1113bb614458c78ada76f3df Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 7 May 2026 15:11:54 -0700 Subject: [PATCH 34/36] updates from review --- docs/src/data_processing.md | 6 +++--- src/Utilities/likelihood_informed.jl | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/data_processing.md b/docs/src/data_processing.md index 4f6c1a21d..c4b48efef 100644 --- a/docs/src/data_processing.md +++ b/docs/src/data_processing.md @@ -39,9 +39,9 @@ emulator = Emulator( ) ``` -## Recommended: get `encoder_kwargs` from and `EnsembleKalmanProcess` and `Prior` +## Recommended `encoder_kwargs` -To transition more smoothly from the `EnsembleKalmanProcesses` infrastructure, one can get the kwargs in the `EnsembleKalmanProcesses.jl` package. This will provide a superset of kwargs that work for any of the data-processors. +The `EnsembleKalmanProcesses` infrastructure naturally provides information to build the data processors. We provide some utilities to extract these into `kwargs` of the correct format, the recommended (but not only) option is: ```julia # `prior::ParameterDistribution` @@ -49,7 +49,7 @@ To transition more smoothly from the `EnsembleKalmanProcesses` infrastructure, o encoder_kwargs = encoder_kwargs_from(ekp, prior) ``` -### Default schedule (whiten with no dimension reduction) +### Default schedule (to whiten with no dimension reduction) When the user provides no `encoder_schedule`, the following is created ```julia emulator = Emulator( diff --git a/src/Utilities/likelihood_informed.jl b/src/Utilities/likelihood_informed.jl index 3e66b0390..75156c701 100644 --- a/src/Utilities/likelihood_informed.jl +++ b/src/Utilities/likelihood_informed.jl @@ -35,8 +35,8 @@ $(TYPEDSIGNATURES) Constructs the `LikelihoodInformed` struct. Keywords: - `retain_info`: the method will attempt to limit the KL divergence of the true posterior from the reduced posterior to a value proportional to (1 - `retain_info`). Choose `retain_info` close to 1 to get a good approximation in a large subspace, and reduce it to get a worse approximation in a smaller subspace. -- `iters`[=[1]]: the likelihood-informed data processor requires samples from the distribution `∝ π_prior(x) π_likelihood(y | x)^α` with `α ∈ [0, 1]`. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. -- `grad_type`[=:localsl]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). +- `iters`[`= [1]`]: the likelihood-informed data processor requires samples from the distribution `∝ π_prior(x) π_likelihood(y | x)^α` with `α ∈ [0, 1]`. Here, `iter` indicates the structure vector iterations to use, as sampled from these distributions. For how to pass in these samples, see the `use_data_as_samples` parameter. +- `grad_type`[`= :linreg`]: how the gradient of the forward model at the samples will be approximated. Choose from `:linreg` (global linear regression) and `:localsl` (localized statistical linearization; see [Wacker, 2025]). """ function likelihood_informed(; retain_info = 1, iters = 1, grad_type = :linreg) grad_types = [:linreg, :localsl] @@ -123,7 +123,7 @@ function initialize_processor!( li.apply_to = apply_to for (it, α) in zip(iters, alphas[iters]) # take the iterations from alpha - #(NB! "it" may not be 1:end) + #(NB! "iters" may not be 1:end) # construct the diagnostic matrix, for which we take the eigendecomposition to find encoder/decoder matrices y = if α ≈ 0.0 From 7e6bd5b070f2016094f5a01a52787984ef1cf749 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 7 May 2026 16:03:37 -0700 Subject: [PATCH 35/36] codecov, and a bugfix for get_training_points --- src/Utilities.jl | 28 ++++++++++++++++++---------- test/Utilities/runtests.jl | 13 +++++++++++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/Utilities.jl b/src/Utilities.jl index 978763d95..7fbf968e9 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -45,12 +45,11 @@ const StructureVector = Union{AbstractVector, AbstractMatrix} # In case of a mat """ $(DocStringExtensions.TYPEDSIGNATURES) -Extract the training points needed to train the Gaussian process regression. +Extract and flatten the training points needed to train an Emulator. returned as a `PairedDataContainer` - `ekp` - EnsembleKalmanProcess holding the parameters and the data that were produced during the Ensemble Kalman (EK) process. -- `train_iterations` - Number (or indices) EK layers/iterations to train on. - +- `train_iterations` - Number (e.g. 1:train_iterations), or indices train_iterations=`3:2:9`, for EKP iterations to extract. - `g_final[=nothing]` - EKP will typically store one extra input data iteration. If desired, the user can add output data for this final iteration directly with `g_final`. It should be of type `<: AbstractMatrix`, sized consistently as with return values from `get_g(ekp,1)`. """ function get_training_points( @@ -60,12 +59,18 @@ function get_training_points( ) where {FT, IT, P} if !isa(train_iterations, AbstractVector) - # Note u[end] does not have an equivalent g - iter_range = (get_N_iterations(ekp) - train_iterations + 1):get_N_iterations(ekp) + iter_range = 1:min(train_iterations, length(get_u(ekp))) else - iter_range = train_iterations + min_it = max(1,minimum(train_iterations)) + max_it = min(length(get_u(ekp)),maximum(train_iterations)) + iter_range = [i for i in train_iterations if (min_it <= i <= max_it) ] end - + + @info "extracting iterations $(iter_range) from EnsembleKalmanProcess" + if (maximum(iter_range) > length(get_g(ekp))) && isnothing(g_final) + throw(ArgumentError("Require outputs associated to parameters `get_u(ekp,$(maximum(iter_range)))`. \n the user can provide this with the `g_final` keyword. Received `g_final=$(g_final)`")) + end + u_tp = [] g_tp = [] @@ -73,12 +78,15 @@ function get_training_points( g_full = [get_g(ekp, i) for i in iter_range[iter_range .<= g_len]] if !isnothing(g_final) if (isa(g_final, AbstractMatrix)) # add the matrix - @assert(size(g_full[1]) == size(g_final)) + if !(size(g_full[1]) == size(g_final)) + throw( + ArgumentError("Expected `g_final` size: $(size(g_full[1])), received $(size(g_final)).") + ) + end push!(g_full, g_final) else throw( - ArgumentError, - "Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final))", + ArgumentError("Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final)).") ) end end diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 3405e6bd5..32152071f 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -37,6 +37,14 @@ using CalibrateEmulateSample.ParameterDistributions @test get_inputs(training_points) ≈ initial_ensemble @test get_outputs(training_points) ≈ g_ens + g_ens_final = G(rng, get_ϕ_final(prior, ekp), Γy) + training_points = get_training_points(ekp, 1:2, g_final=g_ens_final) + @test get_inputs(training_points) ≈ reduce(hcat, get_u(ekp)) + @test get_outputs(training_points) ≈ reduce(hcat, [g_ens, g_ens_final]) + @test_throws ArgumentError get_training_points(ekp, 1:2) + @test_throws ArgumentError get_training_points(ekp, 1:2, g_final=[1]) + @test_throws ArgumentError get_training_points(ekp, 1:2, g_final=g_ens_final') + #positive definiteness mat = reshape(collect(-3:(-3 + 10^2 - 1)), 10, 10) tol = 1e12 * eps() @@ -51,9 +59,8 @@ using CalibrateEmulateSample.ParameterDistributions @test minimum(eigvals(pdmat2)) >= (1 - 1e-4) * tol # get encoder kwargs from ekp and prior - g_ens_final = G(rng, get_ϕ_final(prior, ekp), Γy) encoder_kwargs = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) - + prior_kwargs = (; prior_cov = cov(prior)) obs_kwargs = (; obs_noise_cov = [Γy], observation = [y_obs]) io_kwargs = (; @@ -66,6 +73,8 @@ using CalibrateEmulateSample.ParameterDistributions test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) @test all(encoder_kwargs[key] == test_kwargs[key] for key in keys(encoder_kwargs)) + + # remove final g encoder_reduced_kwargs = encoder_kwargs_from(ekp, prior) io_reduced_kwargs = (; From 697e3bc2dd1b0bdaaf6d36d752e20aaf6aabde72 Mon Sep 17 00:00:00 2001 From: odunbar Date: Thu, 7 May 2026 16:04:11 -0700 Subject: [PATCH 36/36] format --- src/Utilities.jl | 24 ++++++++++++++---------- test/Utilities/runtests.jl | 14 +++++++------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Utilities.jl b/src/Utilities.jl index 7fbf968e9..01b8d02bf 100644 --- a/src/Utilities.jl +++ b/src/Utilities.jl @@ -61,16 +61,20 @@ function get_training_points( if !isa(train_iterations, AbstractVector) iter_range = 1:min(train_iterations, length(get_u(ekp))) else - min_it = max(1,minimum(train_iterations)) - max_it = min(length(get_u(ekp)),maximum(train_iterations)) - iter_range = [i for i in train_iterations if (min_it <= i <= max_it) ] + min_it = max(1, minimum(train_iterations)) + max_it = min(length(get_u(ekp)), maximum(train_iterations)) + iter_range = [i for i in train_iterations if (min_it <= i <= max_it)] end - + @info "extracting iterations $(iter_range) from EnsembleKalmanProcess" if (maximum(iter_range) > length(get_g(ekp))) && isnothing(g_final) - throw(ArgumentError("Require outputs associated to parameters `get_u(ekp,$(maximum(iter_range)))`. \n the user can provide this with the `g_final` keyword. Received `g_final=$(g_final)`")) + throw( + ArgumentError( + "Require outputs associated to parameters `get_u(ekp,$(maximum(iter_range)))`. \n the user can provide this with the `g_final` keyword. Received `g_final=$(g_final)`", + ), + ) end - + u_tp = [] g_tp = [] @@ -79,14 +83,14 @@ function get_training_points( if !isnothing(g_final) if (isa(g_final, AbstractMatrix)) # add the matrix if !(size(g_full[1]) == size(g_final)) - throw( - ArgumentError("Expected `g_final` size: $(size(g_full[1])), received $(size(g_final)).") - ) + throw(ArgumentError("Expected `g_final` size: $(size(g_full[1])), received $(size(g_final)).")) end push!(g_full, g_final) else throw( - ArgumentError("Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final)).") + ArgumentError( + "Expected `g_final` to be type `<:AbstractMatrix`, of size: $(size(g_full[1])), received $(typeof(g_final)).", + ), ) end end diff --git a/test/Utilities/runtests.jl b/test/Utilities/runtests.jl index 32152071f..8703e6cd3 100644 --- a/test/Utilities/runtests.jl +++ b/test/Utilities/runtests.jl @@ -38,13 +38,13 @@ using CalibrateEmulateSample.ParameterDistributions @test get_outputs(training_points) ≈ g_ens g_ens_final = G(rng, get_ϕ_final(prior, ekp), Γy) - training_points = get_training_points(ekp, 1:2, g_final=g_ens_final) + training_points = get_training_points(ekp, 1:2, g_final = g_ens_final) @test get_inputs(training_points) ≈ reduce(hcat, get_u(ekp)) @test get_outputs(training_points) ≈ reduce(hcat, [g_ens, g_ens_final]) @test_throws ArgumentError get_training_points(ekp, 1:2) - @test_throws ArgumentError get_training_points(ekp, 1:2, g_final=[1]) - @test_throws ArgumentError get_training_points(ekp, 1:2, g_final=g_ens_final') - + @test_throws ArgumentError get_training_points(ekp, 1:2, g_final = [1]) + @test_throws ArgumentError get_training_points(ekp, 1:2, g_final = g_ens_final') + #positive definiteness mat = reshape(collect(-3:(-3 + 10^2 - 1)), 10, 10) tol = 1e12 * eps() @@ -60,7 +60,7 @@ using CalibrateEmulateSample.ParameterDistributions # get encoder kwargs from ekp and prior encoder_kwargs = encoder_kwargs_from(ekp, prior, final_samples_out = g_ens_final) - + prior_kwargs = (; prior_cov = cov(prior)) obs_kwargs = (; obs_noise_cov = [Γy], observation = [y_obs]) io_kwargs = (; @@ -73,8 +73,8 @@ using CalibrateEmulateSample.ParameterDistributions test_kwargs = merge(prior_kwargs, obs_kwargs, io_kwargs) @test all(encoder_kwargs[key] == test_kwargs[key] for key in keys(encoder_kwargs)) - - + + # remove final g encoder_reduced_kwargs = encoder_kwargs_from(ekp, prior) io_reduced_kwargs = (;