From 8c1721235c002d5d987d93d097a59983b0a5154e Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Mon, 30 Oct 2023 12:51:28 -0400 Subject: [PATCH 1/9] Relax type of alg in ensemble solve for optimization --- src/ensemble/basic_ensemble_solve.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ensemble/basic_ensemble_solve.jl b/src/ensemble/basic_ensemble_solve.jl index e4dd54fac..245b3cf1e 100644 --- a/src/ensemble/basic_ensemble_solve.jl +++ b/src/ensemble/basic_ensemble_solve.jl @@ -57,10 +57,10 @@ function __solve(prob::EnsembleProblem{<:AbstractVector{<:AbstractSciMLProblem}} end function __solve(prob::AbstractEnsembleProblem, - alg::Union{AbstractDEAlgorithm, Nothing}, + alg::A, ensemblealg::BasicEnsembleAlgorithm; trajectories, batch_size = trajectories, - pmap_batch_size = batch_size ÷ 100 > 0 ? batch_size ÷ 100 : 1, kwargs...) + pmap_batch_size = batch_size ÷ 100 > 0 ? batch_size ÷ 100 : 1, kwargs...) where {A} num_batches = trajectories ÷ batch_size num_batches < 1 && error("trajectories ÷ batch_size cannot be less than 1, got $num_batches") From 23754a83a99bac3eeea49d8779520bbc7be2c072 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Wed, 1 Nov 2023 11:16:52 -0400 Subject: [PATCH 2/9] Add more methods for EnsembleProblem and add more tests --- src/ensemble/ensemble_problems.jl | 20 ++++++++++++++++++++ test/downstream/Project.toml | 1 + test/downstream/ensemble_diffeq.jl | 8 ++++++++ test/downstream/ensemble_nondes.jl | 26 ++++++++++++++++++++++++++ test/runtests.jl | 6 ++++++ 5 files changed, 61 insertions(+) create mode 100644 test/downstream/ensemble_diffeq.jl create mode 100644 test/downstream/ensemble_nondes.jl diff --git a/src/ensemble/ensemble_problems.jl b/src/ensemble/ensemble_problems.jl index 4e493c380..49ee18a9b 100644 --- a/src/ensemble/ensemble_problems.jl +++ b/src/ensemble/ensemble_problems.jl @@ -44,6 +44,26 @@ function EnsembleProblem(; prob, EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) end +function EnsembleProblem(; prob, + u0s::Union{Nothing, Vector{uType}} = nothing, + prob_func = (prob, i, repeat) -> remake(prob, u0 = u0s[i]), + output_func = DEFAULT_OUTPUT_FUNC, + reduction = DEFAULT_REDUCTION, + u_init = nothing, p = nothing, + safetycopy = prob_func !== DEFAULT_PROB_FUNC) where {uType} + EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) +end + +function EnsembleProblem(; prob, + trajectories::Int, + prob_func, + output_func = DEFAULT_OUTPUT_FUNC, + reduction = DEFAULT_REDUCTION, + u_init = nothing, p = nothing, + safetycopy = prob_func !== DEFAULT_PROB_FUNC) + EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) +end + struct WeightedEnsembleProblem{T1 <: AbstractEnsembleProblem, T2 <: AbstractVector} <: AbstractEnsembleProblem ensembleprob::T1 diff --git a/test/downstream/Project.toml b/test/downstream/Project.toml index db1a40a1c..9c4b9014a 100644 --- a/test/downstream/Project.toml +++ b/test/downstream/Project.toml @@ -1,5 +1,6 @@ [deps] BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d" +DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e" diff --git a/test/downstream/ensemble_diffeq.jl b/test/downstream/ensemble_diffeq.jl new file mode 100644 index 000000000..f64f9b15e --- /dev/null +++ b/test/downstream/ensemble_diffeq.jl @@ -0,0 +1,8 @@ +using DifferentialEquations + +f(u, p, t) = 1.01 * u +u0 = 1 / 2 +tspan = (0.0, 1.0) +prob = ODEProblem(f, u0, tspan) +ensemble_prob = EnsembleProblem(prob, prob_func = (prob, i, repeat) -> remake(prob, u0 = rand())) +sim = solve(ensemble_prob, EnsembleThreads(), trajectories = 10, dt = 0.1) \ No newline at end of file diff --git a/test/downstream/ensemble_nondes.jl b/test/downstream/ensemble_nondes.jl new file mode 100644 index 000000000..c1274ba1d --- /dev/null +++ b/test/downstream/ensemble_nondes.jl @@ -0,0 +1,26 @@ +using Optimization, OptimizationOptimJL, ForwardDiff, Test + +x0 = zeros(2) +rosenbrock(x, p = nothing) = (1 - x[1])^2 + 100 * (x[2] - x[1]^2)^2 +l1 = rosenbrock(x0) + +optf = OptimizationFunction(rosenbrock, Optimization.AutoForwardDiff()) +prob = OptimizationProblem(optf, x0) +sol1 = Optimization.solve(prob, OptimizationOptimJL.BFGS(), maxiters = 5) + +ensembleprob = Optimization.EnsembleProblem(prob, [x0, x0 .+ rand(2), x0 .+ rand(2), x0 .+ rand(2)]) + +sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleThreads(), trajectories = 4, maxiters = 5) +@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective + +sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleDistributed(), trajectories = 4, maxiters = 5) +@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective + +prob = OptimizationProblem(optf, x0, lb = [-0.5, -0.5], ub = [0.5, 0.5]) +ensembleprob = Optimization.EnsembleProblem(prob, 5, prob_func = (prob, i, repeat) -> remake(prob, u0 = rand(-0.5:0.001:0.5, 2))) + +sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleThreads(), trajectories = 5, maxiters = 5) +@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective + +sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleDistributed(), trajectories = 5, maxiters = 5) +@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index ead9e0d72..0c58fb841 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -78,6 +78,12 @@ end @time @safetestset "Ensemble solution statistics" begin include("downstream/ensemble_stats.jl") end + @time @safetestset "Ensemble Optimization and Nonlinear problems" begin + include("downstream/ensemble_nondes.jl") + end + @time @safetestset "Ensemble with DifferentialEquations automatic algorithm selection" begin + include("downstream/ensemble_diffeq.jl") + end @time @safetestset "Symbol and integer based indexing of interpolated solutions" begin include("downstream/symbol_indexing.jl") end From 94317714eb43e0c0abc4fba8dffe2bb8dba7aee0 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Fri, 3 Nov 2023 10:35:11 -0400 Subject: [PATCH 3/9] revert new dispatches to check if tests pass with the relaxed type signature: --- src/ensemble/ensemble_problems.jl | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/ensemble/ensemble_problems.jl b/src/ensemble/ensemble_problems.jl index 49ee18a9b..4e493c380 100644 --- a/src/ensemble/ensemble_problems.jl +++ b/src/ensemble/ensemble_problems.jl @@ -44,26 +44,6 @@ function EnsembleProblem(; prob, EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) end -function EnsembleProblem(; prob, - u0s::Union{Nothing, Vector{uType}} = nothing, - prob_func = (prob, i, repeat) -> remake(prob, u0 = u0s[i]), - output_func = DEFAULT_OUTPUT_FUNC, - reduction = DEFAULT_REDUCTION, - u_init = nothing, p = nothing, - safetycopy = prob_func !== DEFAULT_PROB_FUNC) where {uType} - EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) -end - -function EnsembleProblem(; prob, - trajectories::Int, - prob_func, - output_func = DEFAULT_OUTPUT_FUNC, - reduction = DEFAULT_REDUCTION, - u_init = nothing, p = nothing, - safetycopy = prob_func !== DEFAULT_PROB_FUNC) - EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) -end - struct WeightedEnsembleProblem{T1 <: AbstractEnsembleProblem, T2 <: AbstractVector} <: AbstractEnsembleProblem ensembleprob::T1 From 275cfe1e8a39fa121b4875a21688a4e165bcd674 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Fri, 3 Nov 2023 16:50:25 -0400 Subject: [PATCH 4/9] add diffeq to project.toml --- test/downstream/Project.toml | 1 + test/downstream/ensemble_diffeq.jl | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/test/downstream/Project.toml b/test/downstream/Project.toml index 9c4b9014a..2ebdfda5b 100644 --- a/test/downstream/Project.toml +++ b/test/downstream/Project.toml @@ -1,6 +1,7 @@ [deps] BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e" diff --git a/test/downstream/ensemble_diffeq.jl b/test/downstream/ensemble_diffeq.jl index f64f9b15e..e82545de6 100644 --- a/test/downstream/ensemble_diffeq.jl +++ b/test/downstream/ensemble_diffeq.jl @@ -1,8 +1,9 @@ using DifferentialEquations -f(u, p, t) = 1.01 * u -u0 = 1 / 2 -tspan = (0.0, 1.0) -prob = ODEProblem(f, u0, tspan) -ensemble_prob = EnsembleProblem(prob, prob_func = (prob, i, repeat) -> remake(prob, u0 = rand())) -sim = solve(ensemble_prob, EnsembleThreads(), trajectories = 10, dt = 0.1) \ No newline at end of file +prob = ODEProblem((u, p, t) -> 1.01u, 0.5, (0.0, 1.0)) +function prob_func(prob, i, repeat) + remake(prob, u0 = rand() * prob.u0) +end +ensemble_prob = EnsembleProblem(prob, prob_func = prob_func) +sim = solve(ensemble_prob, Tsit5(), EnsembleThreads(), trajectories = 10) +@test sim isa EnsembleSolution \ No newline at end of file From 7e7367b17fa4a9bbf85894b87eb5acad8cf5d1f8 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Fri, 3 Nov 2023 17:24:14 -0400 Subject: [PATCH 5/9] comment out optimization tests for now try ci --- test/runtests.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 0c58fb841..b2406b9e8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -78,9 +78,9 @@ end @time @safetestset "Ensemble solution statistics" begin include("downstream/ensemble_stats.jl") end - @time @safetestset "Ensemble Optimization and Nonlinear problems" begin - include("downstream/ensemble_nondes.jl") - end + # @time @safetestset "Ensemble Optimization and Nonlinear problems" begin + # include("downstream/ensemble_nondes.jl") + # end @time @safetestset "Ensemble with DifferentialEquations automatic algorithm selection" begin include("downstream/ensemble_diffeq.jl") end From dea66d13638555fb43176d564c0ce896b59ec9e3 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Tue, 7 Nov 2023 14:01:54 -0500 Subject: [PATCH 6/9] Run optimization tests and add constructors for it --- Project.toml | 1 + src/SciMLBase.jl | 2 +- src/ensemble/ensemble_problems.jl | 17 +++++++++++++++++ test/downstream/ensemble_nondes.jl | 14 +++++++++++++- test/runtests.jl | 6 +++--- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 3019705b3..6b2d27999 100644 --- a/Project.toml +++ b/Project.toml @@ -21,6 +21,7 @@ Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Preferences = "21216c6a-2e73-6563-6e65-726566657250" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +QuasiMonteCarlo = "8a4e6c94-4038-4cdc-81c3-7e6ffdb2a71b" RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" Reexport = "189a3867-3050-52da-a836-e630ba90ab69" diff --git a/src/SciMLBase.jl b/src/SciMLBase.jl index 72c887d77..485995dd8 100644 --- a/src/SciMLBase.jl +++ b/src/SciMLBase.jl @@ -25,7 +25,7 @@ import ADTypes: AbstractADType import ChainRulesCore import ZygoteRules: @adjoint import FillArrays - +import QuasiMonteCarlo using Reexport using SciMLOperators using SciMLOperators: diff --git a/src/ensemble/ensemble_problems.jl b/src/ensemble/ensemble_problems.jl index 4e493c380..4ad493495 100644 --- a/src/ensemble/ensemble_problems.jl +++ b/src/ensemble/ensemble_problems.jl @@ -44,6 +44,23 @@ function EnsembleProblem(; prob, EnsembleProblem(prob; prob_func, output_func, reduction, u_init, safetycopy) end +#since NonlinearProblem might want to use this dispatch as well +function SciMLBase.EnsembleProblem(prob::AbstractSciMLProblem, u0s::Vector{Vector{T}}; kwargs...) where {T} + prob_func = (prob, i, repeat = nothing) -> remake(prob, u0 = u0s[i]) + return SciMLBase.EnsembleProblem(prob; prob_func, kwargs...) +end + +#only makes sense for OptimizationProblem, might make sense for IntervalNonlinearProblem +function SciMLBase.EnsembleProblem(prob::OptimizationProblem, trajectories::Int; kwargs...) + if prob.lb !== nothing && prob.ub !== nothing + u0s = QuasiMonteCarlo.sample(trajectories, prob.lb, prob.ub, QuasiMonteCarlo.LatinHypercubeSample()) + prob_func = (prob, i, repeat = nothing) -> remake(prob, u0 = u0s[:, i]) + else + error("EnsembleProblem with `trajectories` as second argument requires lower and upper bounds to be defined in the `OptimizationProblem`.") + end + return SciMLBase.EnsembleProblem(prob; prob_func, kwargs...) +end + struct WeightedEnsembleProblem{T1 <: AbstractEnsembleProblem, T2 <: AbstractVector} <: AbstractEnsembleProblem ensembleprob::T1 diff --git a/test/downstream/ensemble_nondes.jl b/test/downstream/ensemble_nondes.jl index c1274ba1d..789bdb4fc 100644 --- a/test/downstream/ensemble_nondes.jl +++ b/test/downstream/ensemble_nondes.jl @@ -23,4 +23,16 @@ sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleThrea @test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective sol = Optimization.solve(ensembleprob, OptimizationOptimJL.BFGS(), EnsembleDistributed(), trajectories = 5, maxiters = 5) -@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective \ No newline at end of file +@test findmin(i -> sol[i].objective, 1:4)[1] < sol1.objective + +using NonlinearSolve + +f(u, p) = u .* u .- p +u0 = [1.0, 1.0] +p = 2.0 +prob = NonlinearProblem(f, u0, p) +ensembleprob = EnsembleProblem(prob, [u0, u0 .+ rand(2), u0 .+ rand(2), u0 .+ rand(2)]) + +sol = solve(ensembleprob, EnsembleThreads(), trajectories = 4, maxiters = 100) + +sol = solve(ensembleprob, EnsembleDistributed(), trajectories = 4, maxiters = 100) \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index b2406b9e8..0c58fb841 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -78,9 +78,9 @@ end @time @safetestset "Ensemble solution statistics" begin include("downstream/ensemble_stats.jl") end - # @time @safetestset "Ensemble Optimization and Nonlinear problems" begin - # include("downstream/ensemble_nondes.jl") - # end + @time @safetestset "Ensemble Optimization and Nonlinear problems" begin + include("downstream/ensemble_nondes.jl") + end @time @safetestset "Ensemble with DifferentialEquations automatic algorithm selection" begin include("downstream/ensemble_diffeq.jl") end From 1d87d19fce551d7d23093db7709eb5215a0090ce Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Tue, 7 Nov 2023 14:34:09 -0500 Subject: [PATCH 7/9] Add compat --- Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Project.toml b/Project.toml index 6b2d27999..36452cc3e 100644 --- a/Project.toml +++ b/Project.toml @@ -74,6 +74,7 @@ Statistics = "1" SymbolicIndexingInterface = "0.2" Tables = "1" TruncatedStacktraces = "1" +QuasiMonteCarlo = "0.3" ZygoteRules = "0.2" julia = "1.6" From 145f4952be438f17204d3e766f70af14855f4639 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Tue, 7 Nov 2023 17:01:37 -0500 Subject: [PATCH 8/9] Add solve --- src/solve.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/solve.jl b/src/solve.jl index 35c833901..f9c98c32f 100644 --- a/src/solve.jl +++ b/src/solve.jl @@ -98,6 +98,10 @@ function solve(prob::OptimizationProblem, alg, args...; end end +function SciMLBase.solve(prob::EnsembleProblem{T}, args...; kwargs...) where {T <: OptimizationProblem} + return SciMLBase.__solve(prob, args...; kwargs...) +end + function _check_opt_alg(prob::OptimizationProblem, alg; kwargs...) !allowsbounds(alg) && (!isnothing(prob.lb) || !isnothing(prob.ub)) && throw(IncompatibleOptimizerError("The algorithm $(typeof(alg)) does not support box constraints. Either remove the `lb` or `ub` bounds passed to `OptimizationProblem` or use a different algorithm.")) From ebcbae334c884938d710ae3bf27391277c204d27 Mon Sep 17 00:00:00 2001 From: Vaibhav Dixit Date: Tue, 7 Nov 2023 17:49:28 -0500 Subject: [PATCH 9/9] add nonlinearsolve --- test/downstream/Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/downstream/Project.toml b/test/downstream/Project.toml index 2ebdfda5b..ed8b088ef 100644 --- a/test/downstream/Project.toml +++ b/test/downstream/Project.toml @@ -3,6 +3,7 @@ BoundaryValueDiffEq = "764a87c0-6b3e-53db-9096-fe964310641d" DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e" OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"