From 6d92f78abcf93da042691ab4a5aaef4a7ebec0b1 Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Sun, 26 May 2024 04:29:46 +0000 Subject: [PATCH] build based on d660156 --- stable | 2 +- v1 | 2 +- v1.5 | 1 + v1.5.0/.documenter-siteinfo.json | 1 + v1.5.0/assets/Manifest.toml | 3552 +++++++++++++++++ v1.5.0/assets/Project.toml | 96 + v1.5.0/assets/documenter.js | 1057 +++++ v1.5.0/assets/favicon.ico | Bin 0 -> 1394 bytes v1.5.0/assets/logo.png | Bin 0 -> 26575 bytes v1.5.0/assets/themes/documenter-dark.css | 7 + v1.5.0/assets/themes/documenter-light.css | 9 + v1.5.0/assets/themeswap.js | 84 + v1.5.0/assets/warner.js | 52 + v1.5.0/comparisons/cppfortran/index.html | 2 + v1.5.0/comparisons/matlab/index.html | 2 + v1.5.0/comparisons/python/index.html | 2 + v1.5.0/comparisons/r/index.html | 2 + v1.5.0/getting_started/find_root/index.html | 69 + .../first_optimization/index.html | 32 + .../first_simulation/6b2ae665.svg | 46 + .../first_simulation/778780f6.svg | 54 + .../first_simulation/8da7844b.svg | 86 + .../first_simulation/a7a12805.svg | 86 + .../first_simulation/index.html | 198 + .../fit_simulation/2321e184.svg | 76 + .../fit_simulation/5207edff.svg | 70 + .../getting_started/fit_simulation/index.html | 147 + .../getting_started/index.html | 2 + .../getting_started/installation/index.html | 3 + v1.5.0/highlevels/array_libraries/index.html | 25 + .../developer_documentation/index.html | 3 + v1.5.0/highlevels/equation_solvers/index.html | 2 + .../function_approximation/index.html | 2 + v1.5.0/highlevels/implicit_layers/index.html | 2 + v1.5.0/highlevels/interfaces/index.html | 2 + v1.5.0/highlevels/inverse_problems/index.html | 2 + .../highlevels/learning_resources/index.html | 2 + .../model_libraries_and_importers/index.html | 2 + .../highlevels/modeling_languages/index.html | 2 + .../highlevels/numerical_utilities/index.html | 2 + .../highlevels/parameter_analysis/index.html | 2 + .../index.html | 2 + .../highlevels/plots_visualization/index.html | 2 + .../highlevels/symbolic_learning/index.html | 2 + v1.5.0/highlevels/symbolic_tools/index.html | 2 + .../uncertainty_quantification/index.html | 2 + v1.5.0/index.html | 574 +++ v1.5.0/objects.inv | Bin 0 -> 11954 bytes v1.5.0/overview/index.html | 2 + v1.5.0/search_index.js | 3 + .../showcase/bayesian_neural_ode/2117136c.svg | 169 + .../showcase/bayesian_neural_ode/9b2a29b1.svg | 338 ++ .../showcase/bayesian_neural_ode/f47df3bc.svg | 731 ++++ .../showcase/bayesian_neural_ode/faab785d.svg | 389 ++ .../showcase/bayesian_neural_ode/index.html | 79 + v1.5.0/showcase/blackhole/17feb703.svg | 50 + v1.5.0/showcase/blackhole/7db8c76f.svg | 48 + v1.5.0/showcase/blackhole/991a7a22.svg | 54 + v1.5.0/showcase/blackhole/be18b50e.svg | 301 ++ v1.5.0/showcase/blackhole/f6eae0f3.svg | 50 + v1.5.0/showcase/blackhole/index.html | 470 +++ v1.5.0/showcase/brusselator/index.html | 381 ++ v1.5.0/showcase/gpu_spde/3adc1997.svg | 615 +++ v1.5.0/showcase/gpu_spde/56d2d928.svg | 1399 +++++++ v1.5.0/showcase/gpu_spde/efaa6f6c.svg | 812 ++++ v1.5.0/showcase/gpu_spde/index.html | 431 ++ .../massively_parallel_gpu/index.html | 26 + v1.5.0/showcase/missing_physics/186dcc63.svg | 157 + v1.5.0/showcase/missing_physics/31abc02c.svg | 92 + v1.5.0/showcase/missing_physics/4bc5ce80.svg | 36 + v1.5.0/showcase/missing_physics/7257452b.svg | 92 + v1.5.0/showcase/missing_physics/c9af9d34.svg | 54 + v1.5.0/showcase/missing_physics/db29de04.svg | 231 ++ v1.5.0/showcase/missing_physics/e79dc32d.svg | 50 + v1.5.0/showcase/missing_physics/f34dda71.svg | 52 + v1.5.0/showcase/missing_physics/fc0b0254.svg | 54 + v1.5.0/showcase/missing_physics/index.html | 362 ++ v1.5.0/showcase/ode_types/40dab875.svg | 136 + v1.5.0/showcase/ode_types/58302a4e.svg | 460 +++ v1.5.0/showcase/ode_types/9b60f1eb.svg | 251 ++ v1.5.0/showcase/ode_types/ad46406c.svg | 374 ++ v1.5.0/showcase/ode_types/f36ad9a8.svg | 50 + v1.5.0/showcase/ode_types/index.html | 308 ++ .../0cea76ad.svg | 551 +++ .../67d2dd6c.svg | 50 + .../79ee2585.svg | 47 + .../7da7676f.svg | 150 + .../ab0e7f3e.svg | 551 +++ .../c967a9a6.svg | 45 + .../e73b93f0.svg | 46 + .../f3625363.svg | 150 + .../optimization_under_uncertainty/index.html | 174 + v1.5.0/showcase/pinngpu/index.html | 99 + v1.5.0/showcase/showcase/index.html | 2 + .../showcase/symbolic_analysis/17b5286a.svg | 54 + .../showcase/symbolic_analysis/85954770.svg | 54 + .../showcase/symbolic_analysis/cca78dd2.svg | 54 + v1.5.0/showcase/symbolic_analysis/index.html | 178 + v1.5.0/siteinfo.js | 1 + versions.js | 3 +- 100 files changed, 17685 insertions(+), 3 deletions(-) create mode 120000 v1.5 create mode 100644 v1.5.0/.documenter-siteinfo.json create mode 100644 v1.5.0/assets/Manifest.toml create mode 100644 v1.5.0/assets/Project.toml create mode 100644 v1.5.0/assets/documenter.js create mode 100644 v1.5.0/assets/favicon.ico create mode 100644 v1.5.0/assets/logo.png create mode 100644 v1.5.0/assets/themes/documenter-dark.css create mode 100644 v1.5.0/assets/themes/documenter-light.css create mode 100644 v1.5.0/assets/themeswap.js create mode 100644 v1.5.0/assets/warner.js create mode 100644 v1.5.0/comparisons/cppfortran/index.html create mode 100644 v1.5.0/comparisons/matlab/index.html create mode 100644 v1.5.0/comparisons/python/index.html create mode 100644 v1.5.0/comparisons/r/index.html create mode 100644 v1.5.0/getting_started/find_root/index.html create mode 100644 v1.5.0/getting_started/first_optimization/index.html create mode 100644 v1.5.0/getting_started/first_simulation/6b2ae665.svg create mode 100644 v1.5.0/getting_started/first_simulation/778780f6.svg create mode 100644 v1.5.0/getting_started/first_simulation/8da7844b.svg create mode 100644 v1.5.0/getting_started/first_simulation/a7a12805.svg create mode 100644 v1.5.0/getting_started/first_simulation/index.html create mode 100644 v1.5.0/getting_started/fit_simulation/2321e184.svg create mode 100644 v1.5.0/getting_started/fit_simulation/5207edff.svg create mode 100644 v1.5.0/getting_started/fit_simulation/index.html create mode 100644 v1.5.0/getting_started/getting_started/index.html create mode 100644 v1.5.0/getting_started/installation/index.html create mode 100644 v1.5.0/highlevels/array_libraries/index.html create mode 100644 v1.5.0/highlevels/developer_documentation/index.html create mode 100644 v1.5.0/highlevels/equation_solvers/index.html create mode 100644 v1.5.0/highlevels/function_approximation/index.html create mode 100644 v1.5.0/highlevels/implicit_layers/index.html create mode 100644 v1.5.0/highlevels/interfaces/index.html create mode 100644 v1.5.0/highlevels/inverse_problems/index.html create mode 100644 v1.5.0/highlevels/learning_resources/index.html create mode 100644 v1.5.0/highlevels/model_libraries_and_importers/index.html create mode 100644 v1.5.0/highlevels/modeling_languages/index.html create mode 100644 v1.5.0/highlevels/numerical_utilities/index.html create mode 100644 v1.5.0/highlevels/parameter_analysis/index.html create mode 100644 v1.5.0/highlevels/partial_differential_equation_solvers/index.html create mode 100644 v1.5.0/highlevels/plots_visualization/index.html create mode 100644 v1.5.0/highlevels/symbolic_learning/index.html create mode 100644 v1.5.0/highlevels/symbolic_tools/index.html create mode 100644 v1.5.0/highlevels/uncertainty_quantification/index.html create mode 100644 v1.5.0/index.html create mode 100644 v1.5.0/objects.inv create mode 100644 v1.5.0/overview/index.html create mode 100644 v1.5.0/search_index.js create mode 100644 v1.5.0/showcase/bayesian_neural_ode/2117136c.svg create mode 100644 v1.5.0/showcase/bayesian_neural_ode/9b2a29b1.svg create mode 100644 v1.5.0/showcase/bayesian_neural_ode/f47df3bc.svg create mode 100644 v1.5.0/showcase/bayesian_neural_ode/faab785d.svg create mode 100644 v1.5.0/showcase/bayesian_neural_ode/index.html create mode 100644 v1.5.0/showcase/blackhole/17feb703.svg create mode 100644 v1.5.0/showcase/blackhole/7db8c76f.svg create mode 100644 v1.5.0/showcase/blackhole/991a7a22.svg create mode 100644 v1.5.0/showcase/blackhole/be18b50e.svg create mode 100644 v1.5.0/showcase/blackhole/f6eae0f3.svg create mode 100644 v1.5.0/showcase/blackhole/index.html create mode 100644 v1.5.0/showcase/brusselator/index.html create mode 100644 v1.5.0/showcase/gpu_spde/3adc1997.svg create mode 100644 v1.5.0/showcase/gpu_spde/56d2d928.svg create mode 100644 v1.5.0/showcase/gpu_spde/efaa6f6c.svg create mode 100644 v1.5.0/showcase/gpu_spde/index.html create mode 100644 v1.5.0/showcase/massively_parallel_gpu/index.html create mode 100644 v1.5.0/showcase/missing_physics/186dcc63.svg create mode 100644 v1.5.0/showcase/missing_physics/31abc02c.svg create mode 100644 v1.5.0/showcase/missing_physics/4bc5ce80.svg create mode 100644 v1.5.0/showcase/missing_physics/7257452b.svg create mode 100644 v1.5.0/showcase/missing_physics/c9af9d34.svg create mode 100644 v1.5.0/showcase/missing_physics/db29de04.svg create mode 100644 v1.5.0/showcase/missing_physics/e79dc32d.svg create mode 100644 v1.5.0/showcase/missing_physics/f34dda71.svg create mode 100644 v1.5.0/showcase/missing_physics/fc0b0254.svg create mode 100644 v1.5.0/showcase/missing_physics/index.html create mode 100644 v1.5.0/showcase/ode_types/40dab875.svg create mode 100644 v1.5.0/showcase/ode_types/58302a4e.svg create mode 100644 v1.5.0/showcase/ode_types/9b60f1eb.svg create mode 100644 v1.5.0/showcase/ode_types/ad46406c.svg create mode 100644 v1.5.0/showcase/ode_types/f36ad9a8.svg create mode 100644 v1.5.0/showcase/ode_types/index.html create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/0cea76ad.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/67d2dd6c.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/79ee2585.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/7da7676f.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/ab0e7f3e.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/c967a9a6.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/e73b93f0.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/f3625363.svg create mode 100644 v1.5.0/showcase/optimization_under_uncertainty/index.html create mode 100644 v1.5.0/showcase/pinngpu/index.html create mode 100644 v1.5.0/showcase/showcase/index.html create mode 100644 v1.5.0/showcase/symbolic_analysis/17b5286a.svg create mode 100644 v1.5.0/showcase/symbolic_analysis/85954770.svg create mode 100644 v1.5.0/showcase/symbolic_analysis/cca78dd2.svg create mode 100644 v1.5.0/showcase/symbolic_analysis/index.html create mode 100644 v1.5.0/siteinfo.js diff --git a/stable b/stable index ec7b9678297..76864c1c20c 120000 --- a/stable +++ b/stable @@ -1 +1 @@ -v1.4.0 \ No newline at end of file +v1.5.0 \ No newline at end of file diff --git a/v1 b/v1 index ec7b9678297..76864c1c20c 120000 --- a/v1 +++ b/v1 @@ -1 +1 @@ -v1.4.0 \ No newline at end of file +v1.5.0 \ No newline at end of file diff --git a/v1.5 b/v1.5 new file mode 120000 index 00000000000..76864c1c20c --- /dev/null +++ b/v1.5 @@ -0,0 +1 @@ +v1.5.0 \ No newline at end of file diff --git a/v1.5.0/.documenter-siteinfo.json b/v1.5.0/.documenter-siteinfo.json new file mode 100644 index 00000000000..52c937b421b --- /dev/null +++ b/v1.5.0/.documenter-siteinfo.json @@ -0,0 +1 @@ +{"documenter":{"julia_version":"1.10.3","generation_timestamp":"2024-05-26T04:26:33","documenter_version":"1.4.1"}} \ No newline at end of file diff --git a/v1.5.0/assets/Manifest.toml b/v1.5.0/assets/Manifest.toml new file mode 100644 index 00000000000..d336ef1ecdb --- /dev/null +++ b/v1.5.0/assets/Manifest.toml @@ -0,0 +1,3552 @@ +# This file is machine-generated - editing it directly is not advised + +julia_version = "1.10.3" +manifest_format = "2.0" +project_hash = "8b6e5a92c2dcb98c5400709cffa816a8e161e4ba" + +[[deps.ADTypes]] +git-tree-sha1 = "016833eb52ba2d6bea9fcb50ca295980e728ee24" +uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" +version = "0.2.7" + +[[deps.ANSIColoredPrinters]] +git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" +uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" +version = "0.0.1" + +[[deps.AbstractFFTs]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "d92ad398961a3ed262d8bf04a1a2b8340f915fef" +uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" +version = "1.5.0" +weakdeps = ["ChainRulesCore", "Test"] + + [deps.AbstractFFTs.extensions] + AbstractFFTsChainRulesCoreExt = "ChainRulesCore" + AbstractFFTsTestExt = "Test" + +[[deps.AbstractMCMC]] +deps = ["BangBang", "ConsoleProgressMonitor", "Distributed", "FillArrays", "LogDensityProblems", "Logging", "LoggingExtras", "ProgressLogging", "Random", "StatsBase", "TerminalLoggers", "Transducers"] +git-tree-sha1 = "b0489adc45a7c8cf0d8e2ddf764f89c1c3decebd" +uuid = "80f14c24-f653-4e6a-9b94-39d6b0f70001" +version = "5.2.0" + +[[deps.AbstractTrees]] +git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" +uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" +version = "0.4.5" + +[[deps.Accessors]] +deps = ["CompositionsBase", "ConstructionBase", "Dates", "InverseFunctions", "LinearAlgebra", "MacroTools", "Markdown", "Test"] +git-tree-sha1 = "c0d491ef0b135fd7d63cbc6404286bc633329425" +uuid = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" +version = "0.1.36" + + [deps.Accessors.extensions] + AccessorsAxisKeysExt = "AxisKeys" + AccessorsIntervalSetsExt = "IntervalSets" + AccessorsStaticArraysExt = "StaticArrays" + AccessorsStructArraysExt = "StructArrays" + AccessorsUnitfulExt = "Unitful" + + [deps.Accessors.weakdeps] + AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5" + IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953" + Requires = "ae029012-a4dd-5104-9daa-d747884805df" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.Adapt]] +deps = ["LinearAlgebra", "Requires"] +git-tree-sha1 = "6a55b747d1812e699320963ffde36f1ebdda4099" +uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" +version = "4.0.4" +weakdeps = ["StaticArrays"] + + [deps.Adapt.extensions] + AdaptStaticArraysExt = "StaticArrays" + +[[deps.AdvancedHMC]] +deps = ["AbstractMCMC", "ArgCheck", "DocStringExtensions", "InplaceOps", "LinearAlgebra", "LogDensityProblems", "LogDensityProblemsAD", "ProgressMeter", "Random", "Requires", "Setfield", "SimpleUnPack", "Statistics", "StatsBase", "StatsFuns"] +git-tree-sha1 = "dfa0e3508fc3df81d28624b328f3b937c1df8bc2" +uuid = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" +version = "0.6.1" +weakdeps = ["CUDA", "MCMCChains", "OrdinaryDiffEq"] + + [deps.AdvancedHMC.extensions] + AdvancedHMCCUDAExt = "CUDA" + AdvancedHMCMCMCChainsExt = "MCMCChains" + AdvancedHMCOrdinaryDiffEqExt = "OrdinaryDiffEq" + +[[deps.AliasTables]] +deps = ["PtrArrays", "Random"] +git-tree-sha1 = "9876e1e164b144ca45e9e3198d0b689cadfed9ff" +uuid = "66dad0bd-aa9a-41b7-9441-69ab47430ed8" +version = "1.1.3" + +[[deps.ArgCheck]] +git-tree-sha1 = "a3a402a35a2f7e0b87828ccabbd5ebfbebe356b4" +uuid = "dce04be8-c92d-5529-be00-80e4d2c0e197" +version = "2.3.0" + +[[deps.ArgTools]] +uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +version = "1.1.1" + +[[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" +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" +uuid = "68821587-b530-5797-8361-c406ea357684" +version = "3.5.1+1" + +[[deps.ArrayInterface]] +deps = ["Adapt", "LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "133a240faec6e074e07c31ee75619c90544179cf" +uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" +version = "7.10.0" + + [deps.ArrayInterface.extensions] + ArrayInterfaceBandedMatricesExt = "BandedMatrices" + ArrayInterfaceBlockBandedMatricesExt = "BlockBandedMatrices" + ArrayInterfaceCUDAExt = "CUDA" + ArrayInterfaceCUDSSExt = "CUDSS" + ArrayInterfaceChainRulesExt = "ChainRules" + ArrayInterfaceGPUArraysCoreExt = "GPUArraysCore" + ArrayInterfaceReverseDiffExt = "ReverseDiff" + ArrayInterfaceStaticArraysCoreExt = "StaticArraysCore" + ArrayInterfaceTrackerExt = "Tracker" + + [deps.ArrayInterface.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" + ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" + GPUArraysCore = "46192b85-c4d5-4398-a991-12ede77f4527" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + +[[deps.ArrayLayouts]] +deps = ["FillArrays", "LinearAlgebra"] +git-tree-sha1 = "29649b61e0313db0a7ad5ecf41210e4e85aea234" +uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" +version = "1.9.3" +weakdeps = ["SparseArrays"] + + [deps.ArrayLayouts.extensions] + ArrayLayoutsSparseArraysExt = "SparseArrays" + +[[deps.Artifacts]] +uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" + +[[deps.Atomix]] +deps = ["UnsafeAtomics"] +git-tree-sha1 = "c06a868224ecba914baa6942988e2f2aade419be" +uuid = "a9b6321e-bd34-4604-b9c9-b65b8de01458" +version = "0.1.0" + +[[deps.AxisAlgorithms]] +deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] +git-tree-sha1 = "66771c8d21c8ff5e3a93379480a2307ac36863f7" +uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" +version = "1.0.1" + +[[deps.AxisArrays]] +deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"] +git-tree-sha1 = "16351be62963a67ac4083f748fdb3cca58bfd52f" +uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9" +version = "0.4.7" + +[[deps.BFloat16s]] +deps = ["LinearAlgebra", "Printf", "Random", "Test"] +git-tree-sha1 = "2c7cc21e8678eff479978a0a2ef5ce2f51b63dff" +uuid = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" +version = "0.5.0" + +[[deps.BandedMatrices]] +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "PrecompileTools"] +git-tree-sha1 = "30b7ea34abc4fe816eb1a5f434a43da804836163" +uuid = "aae01518-5342-5314-be14-df237901396f" +version = "1.7.0" +weakdeps = ["SparseArrays"] + + [deps.BandedMatrices.extensions] + BandedMatricesSparseArraysExt = "SparseArrays" + +[[deps.BangBang]] +deps = ["Compat", "ConstructionBase", "InitialValues", "LinearAlgebra", "Requires", "Setfield", "Tables"] +git-tree-sha1 = "7aa7ad1682f3d5754e3491bb59b8103cae28e3a3" +uuid = "198e06fe-97b7-11e9-32a5-e1d131e6ad66" +version = "0.3.40" + + [deps.BangBang.extensions] + BangBangChainRulesCoreExt = "ChainRulesCore" + BangBangDataFramesExt = "DataFrames" + BangBangStaticArraysExt = "StaticArrays" + BangBangStructArraysExt = "StructArrays" + BangBangTypedTablesExt = "TypedTables" + + [deps.BangBang.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + StructArrays = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" + TypedTables = "9d95f2ec-7b3d-5a63-8d20-e2491e220bb9" + +[[deps.Base64]] +uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" + +[[deps.Baselet]] +git-tree-sha1 = "aebf55e6d7795e02ca500a689d326ac979aaf89e" +uuid = "9718e550-a3fa-408a-8086-8db961cd8217" +version = "0.1.1" + +[[deps.BenchmarkTools]] +deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"] +git-tree-sha1 = "f1dff6729bc61f4d49e140da1af55dcd1ac97b2f" +uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +version = "1.5.0" + +[[deps.Bijections]] +git-tree-sha1 = "c9b163bd832e023571e86d0b90d9de92a9879088" +uuid = "e2ed5e7c-b2de-5872-ae92-c73ca462fb04" +version = "0.1.6" + +[[deps.BitFlags]] +git-tree-sha1 = "2dc09997850d68179b69dafb58ae806167a32b1b" +uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" +version = "0.1.8" + +[[deps.BitTwiddlingConvenienceFunctions]] +deps = ["Static"] +git-tree-sha1 = "0c5f81f47bbbcf4aea7b2959135713459170798b" +uuid = "62783981-4cbd-42fc-bca8-16325de8dc4b" +version = "0.1.5" + +[[deps.BoundaryValueDiffEq]] +deps = ["ADTypes", "Adapt", "ArrayInterface", "BandedMatrices", "ConcreteStructs", "DiffEqBase", "FastAlmostBandedMatrices", "FastClosures", "ForwardDiff", "LinearAlgebra", "LinearSolve", "Logging", "NonlinearSolve", "OrdinaryDiffEq", "PreallocationTools", "PrecompileTools", "Preferences", "RecursiveArrayTools", "Reexport", "SciMLBase", "Setfield", "SparseArrays", "SparseDiffTools"] +git-tree-sha1 = "005b55fa2eebaa4d7bf3cfb8097807f47116175f" +uuid = "764a87c0-6b3e-53db-9096-fe964310641d" +version = "5.7.1" + + [deps.BoundaryValueDiffEq.extensions] + BoundaryValueDiffEqODEInterfaceExt = "ODEInterface" + + [deps.BoundaryValueDiffEq.weakdeps] + ODEInterface = "54ca160b-1b9f-5127-a996-1867f4bc2a2c" + +[[deps.Bzip2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9e2a6b69137e6969bab0152632dcb3bc108c8bdd" +uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" +version = "1.0.8+1" + +[[deps.CEnum]] +git-tree-sha1 = "389ad5c84de1ae7cf0e28e381131c98ea87d54fc" +uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" +version = "0.5.0" + +[[deps.CPUSummary]] +deps = ["CpuId", "IfElse", "PrecompileTools", "Static"] +git-tree-sha1 = "585a387a490f1c4bd88be67eea15b93da5e85db7" +uuid = "2a0fbf3d-bb9c-48f3-b0a9-814d99fd7ab9" +version = "0.2.5" + +[[deps.CSTParser]] +deps = ["Tokenize"] +git-tree-sha1 = "0157e592151e39fa570645e2b2debcdfb8a0f112" +uuid = "00ebfdb7-1f24-5e51-bd34-a7502290713f" +version = "3.4.3" + +[[deps.CSV]] +deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] +git-tree-sha1 = "6c834533dc1fabd820c1db03c839bf97e45a3fab" +uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +version = "0.10.14" + +[[deps.CUDA]] +deps = ["AbstractFFTs", "Adapt", "BFloat16s", "CEnum", "CUDA_Driver_jll", "CUDA_Runtime_Discovery", "CUDA_Runtime_jll", "Crayons", "DataFrames", "ExprTools", "GPUArrays", "GPUCompiler", "KernelAbstractions", "LLVM", "LLVMLoopInfo", "LazyArtifacts", "Libdl", "LinearAlgebra", "Logging", "NVTX", "Preferences", "PrettyTables", "Printf", "Random", "Random123", "RandomNumbers", "Reexport", "Requires", "SparseArrays", "StaticArrays", "Statistics"] +git-tree-sha1 = "4e33522a036b39fc6f5cb7447ae3b28eb8fbe99b" +uuid = "052768ef-5323-5732-b1bb-66c8b64840ba" +version = "5.3.3" +weakdeps = ["ChainRulesCore", "SpecialFunctions"] + + [deps.CUDA.extensions] + ChainRulesCoreExt = "ChainRulesCore" + SpecialFunctionsExt = "SpecialFunctions" + +[[deps.CUDA_Driver_jll]] +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] +git-tree-sha1 = "dc172b558adbf17952001e15cf0d6364e6d78c2f" +uuid = "4ee394cb-3365-5eb0-8335-949819d2adfc" +version = "0.8.1+0" + +[[deps.CUDA_Runtime_Discovery]] +deps = ["Libdl"] +git-tree-sha1 = "38f830504358e9972d2a0c3e5d51cb865e0733df" +uuid = "1af6417a-86b4-443c-805f-a4643ffb695f" +version = "0.2.4" + +[[deps.CUDA_Runtime_jll]] +deps = ["Artifacts", "CUDA_Driver_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "4ca7d6d92075906c2ce871ea8bba971fff20d00c" +uuid = "76a88914-d11a-5bdc-97e0-2f5a05c973a2" +version = "0.12.1+0" + +[[deps.CUDNN_jll]] +deps = ["Artifacts", "CUDA_Runtime_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "cbf7d75f8c58b147bdf6acea2e5bc96cececa6d4" +uuid = "62b44479-cb7b-5706-934f-f13b2eb2e645" +version = "9.0.0+1" + +[[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 = "a2f1c8c668c8e3cb4cca4e57a8efdb09067bb3fd" +uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" +version = "1.18.0+2" + +[[deps.Calculus]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad" +uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9" +version = "0.5.1" + +[[deps.Cassette]] +git-tree-sha1 = "0970356c3bb9113309c74c27c87083cf9c73880a" +uuid = "7057c7e9-c182-5462-911a-8362d720325c" +version = "0.3.13" + +[[deps.ChainRules]] +deps = ["Adapt", "ChainRulesCore", "Compat", "Distributed", "GPUArraysCore", "IrrationalConstants", "LinearAlgebra", "Random", "RealDot", "SparseArrays", "SparseInverseSubset", "Statistics", "StructArrays", "SuiteSparse"] +git-tree-sha1 = "291821c1251486504f6bae435227907d734e94d2" +uuid = "082447d4-558c-5d27-93f4-14fc19e9eca2" +version = "1.66.0" + +[[deps.ChainRulesCore]] +deps = ["Compat", "LinearAlgebra"] +git-tree-sha1 = "575cd02e080939a33b6df6c5853d14924c08e35b" +uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" +version = "1.23.0" +weakdeps = ["SparseArrays"] + + [deps.ChainRulesCore.extensions] + ChainRulesCoreSparseArraysExt = "SparseArrays" + +[[deps.ChunkSplitters]] +deps = ["Compat", "TestItems"] +git-tree-sha1 = "c7962ce1b964bde2867808235d1c521781df191e" +uuid = "ae650224-84b6-46f8-82ea-d812ca08434e" +version = "2.4.2" + +[[deps.CloseOpenIntervals]] +deps = ["Static", "StaticArrayInterface"] +git-tree-sha1 = "70232f82ffaab9dc52585e0dd043b5e0c6b714f1" +uuid = "fb6a15b2-703c-40df-9091-08a04967cfa9" +version = "0.1.12" + +[[deps.Clustering]] +deps = ["Distances", "LinearAlgebra", "NearestNeighbors", "Printf", "Random", "SparseArrays", "Statistics", "StatsBase"] +git-tree-sha1 = "9ebb045901e9bbf58767a9f34ff89831ed711aae" +uuid = "aaaa29a8-35af-508c-8bc3-b662a17a0fe5" +version = "0.15.7" + +[[deps.CodecBzip2]] +deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"] +git-tree-sha1 = "9b1ca1aa6ce3f71b3d1840c538a8210a043625eb" +uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd" +version = "0.8.2" + +[[deps.CodecZlib]] +deps = ["TranscodingStreams", "Zlib_jll"] +git-tree-sha1 = "59939d8a997469ee05c4b4944560a820f9ba0d73" +uuid = "944b1d66-785c-5afd-91f1-9de20f533193" +version = "0.7.4" + +[[deps.ColorSchemes]] +deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] +git-tree-sha1 = "4b270d6465eb21ae89b732182c20dc165f8bf9f2" +uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" +version = "3.25.0" + +[[deps.ColorTypes]] +deps = ["FixedPointNumbers", "Random"] +git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d" +uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" +version = "0.11.5" + +[[deps.ColorVectorSpace]] +deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] +git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249" +uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" +version = "0.10.0" +weakdeps = ["SpecialFunctions"] + + [deps.ColorVectorSpace.extensions] + SpecialFunctionsExt = "SpecialFunctions" + +[[deps.Colors]] +deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] +git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" +uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" +version = "0.12.11" + +[[deps.Combinatorics]] +git-tree-sha1 = "08c8b6831dc00bfea825826be0bc8336fc369860" +uuid = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" +version = "1.0.2" + +[[deps.CommonMark]] +deps = ["Crayons", "JSON", "PrecompileTools", "URIs"] +git-tree-sha1 = "532c4185d3c9037c0237546d817858b23cf9e071" +uuid = "a80b9123-70ca-4bc0-993e-6e3bcb318db6" +version = "0.8.12" + +[[deps.CommonSolve]] +git-tree-sha1 = "0eee5eb66b1cf62cd6ad1b460238e60e4b09400c" +uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" +version = "0.2.4" + +[[deps.CommonSubexpressions]] +deps = ["MacroTools", "Test"] +git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" +uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" +version = "0.3.0" + +[[deps.Compat]] +deps = ["TOML", "UUIDs"] +git-tree-sha1 = "b1c55339b7c6c350ee89f2c1604299660525b248" +uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" +version = "4.15.0" +weakdeps = ["Dates", "LinearAlgebra"] + + [deps.Compat.extensions] + CompatLinearAlgebraExt = "LinearAlgebra" + +[[deps.CompilerSupportLibraries_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" +version = "1.1.1+0" + +[[deps.ComponentArrays]] +deps = ["ArrayInterface", "ChainRulesCore", "ForwardDiff", "Functors", "LinearAlgebra", "PackageExtensionCompat", "StaticArrayInterface", "StaticArraysCore"] +git-tree-sha1 = "85d7d0c192e8eec909799737fe590f7d7ff0a6eb" +uuid = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +version = "0.15.13" +weakdeps = ["Adapt", "ConstructionBase", "GPUArrays", "Optimisers", "RecursiveArrayTools", "ReverseDiff", "SciMLBase", "Tracker", "TruncatedStacktraces", "Zygote"] + + [deps.ComponentArrays.extensions] + ComponentArraysAdaptExt = "Adapt" + ComponentArraysConstructionBaseExt = "ConstructionBase" + ComponentArraysGPUArraysExt = "GPUArrays" + ComponentArraysOptimisersExt = "Optimisers" + ComponentArraysRecursiveArrayToolsExt = "RecursiveArrayTools" + ComponentArraysReverseDiffExt = "ReverseDiff" + ComponentArraysSciMLBaseExt = "SciMLBase" + ComponentArraysTrackerExt = "Tracker" + ComponentArraysTruncatedStacktracesExt = "TruncatedStacktraces" + ComponentArraysZygoteExt = "Zygote" + +[[deps.CompositeTypes]] +git-tree-sha1 = "bce26c3dab336582805503bed209faab1c279768" +uuid = "b152e2b5-7a66-4b01-a709-34e65c35f657" +version = "0.1.4" + +[[deps.CompositionsBase]] +git-tree-sha1 = "802bb88cd69dfd1509f6670416bd4434015693ad" +uuid = "a33af91c-f02d-484b-be07-31d278c5ca2b" +version = "0.1.2" +weakdeps = ["InverseFunctions"] + + [deps.CompositionsBase.extensions] + CompositionsBaseInverseFunctionsExt = "InverseFunctions" + +[[deps.ConcreteStructs]] +git-tree-sha1 = "f749037478283d372048690eb3b5f92a79432b34" +uuid = "2569d6c7-a4a2-43d3-a901-331e8e4be471" +version = "0.2.3" + +[[deps.ConcurrentUtilities]] +deps = ["Serialization", "Sockets"] +git-tree-sha1 = "6cbbd4d241d7e6579ab354737f4dd95ca43946e1" +uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" +version = "2.4.1" + +[[deps.ConsoleProgressMonitor]] +deps = ["Logging", "ProgressMeter"] +git-tree-sha1 = "3ab7b2136722890b9af903859afcf457fa3059e8" +uuid = "88cd18e8-d9cc-4ea6-8889-5259c0d15c8b" +version = "0.1.2" + +[[deps.ConstructionBase]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "260fd2400ed2dab602a7c15cf10c1933c59930a2" +uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" +version = "1.5.5" +weakdeps = ["IntervalSets", "StaticArrays"] + + [deps.ConstructionBase.extensions] + ConstructionBaseIntervalSetsExt = "IntervalSets" + ConstructionBaseStaticArraysExt = "StaticArrays" + +[[deps.ContextVariablesX]] +deps = ["Compat", "Logging", "UUIDs"] +git-tree-sha1 = "25cc3803f1030ab855e383129dcd3dc294e322cc" +uuid = "6add18c4-b38d-439d-96f6-d6bc489c04c5" +version = "0.1.3" + +[[deps.Contour]] +git-tree-sha1 = "439e35b0b36e2e5881738abc8857bd92ad6ff9a8" +uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" +version = "0.6.3" + +[[deps.CpuId]] +deps = ["Markdown"] +git-tree-sha1 = "fcbb72b032692610bfbdb15018ac16a36cf2e406" +uuid = "adafc99b-e345-5852-983c-f28acb93d879" +version = "0.3.1" + +[[deps.Crayons]] +git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" +uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" +version = "4.1.1" + +[[deps.Cubature]] +deps = ["Cubature_jll"] +git-tree-sha1 = "c3f4b3b38abd7b5c3ccf59adab2568212e7530d3" +uuid = "667455a9-e2ce-5579-9412-b964f529a492" +version = "1.5.1" + +[[deps.Cubature_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0fe9efb84e3eb7b14f885a95aaa0ed50c7e839c8" +uuid = "7bc98958-0e37-5d67-a6ac-a3a19030071a" +version = "1.0.5+0" + +[[deps.DataAPI]] +git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" +uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" +version = "1.16.0" + +[[deps.DataDrivenDiffEq]] +deps = ["CommonSolve", "DataInterpolations", "DiffEqBase", "DocStringExtensions", "LinearAlgebra", "MLUtils", "ModelingToolkit", "Parameters", "ProgressMeter", "QuadGK", "Random", "RecipesBase", "Reexport", "Setfield", "Statistics", "StatsBase", "SymbolicUtils", "Symbolics"] +git-tree-sha1 = "24aef32b3eab9f7db146e00220be50dd60ded125" +uuid = "2445eb08-9709-466a-b3fc-47e12bd697a2" +version = "1.4.1" + +[[deps.DataDrivenSparse]] +deps = ["DataDrivenDiffEq", "LinearAlgebra", "Printf", "Reexport"] +git-tree-sha1 = "62c1877475c7fbad13a3df008e919960bcecb842" +uuid = "5b588203-7d8b-4fab-a537-c31a7f73f46b" +version = "0.1.2" + +[[deps.DataFrames]] +deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] +git-tree-sha1 = "04c738083f29f86e62c8afc341f0967d8717bdb8" +uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +version = "1.6.1" + +[[deps.DataInterpolations]] +deps = ["FindFirstFunctions", "ForwardDiff", "LinearAlgebra", "PrettyTables", "RecipesBase", "Reexport"] +git-tree-sha1 = "b580ef00ec248aeb137b4ef3a4f751a567d35556" +uuid = "82cc6244-b520-54b8-b5a6-8a565e85f1d0" +version = "5.0.0" + + [deps.DataInterpolations.extensions] + DataInterpolationsChainRulesCoreExt = "ChainRulesCore" + DataInterpolationsOptimExt = "Optim" + DataInterpolationsRegularizationToolsExt = "RegularizationTools" + DataInterpolationsSymbolicsExt = "Symbolics" + + [deps.DataInterpolations.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Optim = "429524aa-4258-5aef-a3af-852621145aeb" + RegularizationTools = "29dad682-9a27-4bc3-9c72-016788665182" + Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" + +[[deps.DataStructures]] +deps = ["Compat", "InteractiveUtils", "OrderedCollections"] +git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.18.20" + +[[deps.DataValueInterfaces]] +git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" +uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" +version = "1.0.0" + +[[deps.Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[deps.DefineSingletons]] +git-tree-sha1 = "0fba8b706d0178b4dc7fd44a96a92382c9065c2c" +uuid = "244e2a9f-e319-4986-a169-4d1fe445cd52" +version = "0.1.2" + +[[deps.DelayDiffEq]] +deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "LinearAlgebra", "Logging", "OrdinaryDiffEq", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SimpleNonlinearSolve", "SimpleUnPack"] +git-tree-sha1 = "5959ae76ebd198f70e9af81153644543da0cfaf2" +uuid = "bcd4f6db-9728-5f36-b5f7-82caef46ccdb" +version = "5.47.3" + +[[deps.DelimitedFiles]] +deps = ["Mmap"] +git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" +uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" +version = "1.9.1" + +[[deps.DiffEqBase]] +deps = ["ArrayInterface", "ConcreteStructs", "DataStructures", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "ForwardDiff", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "Parameters", "PreallocationTools", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "Setfield", "SparseArrays", "Static", "StaticArraysCore", "Statistics", "Tricks", "TruncatedStacktraces"] +git-tree-sha1 = "03b9555f4c3a7c2f530bb1ae13e85719c632f74e" +uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" +version = "6.151.1" + + [deps.DiffEqBase.extensions] + DiffEqBaseCUDAExt = "CUDA" + DiffEqBaseChainRulesCoreExt = "ChainRulesCore" + DiffEqBaseDistributionsExt = "Distributions" + DiffEqBaseEnzymeExt = ["ChainRulesCore", "Enzyme"] + DiffEqBaseGeneralizedGeneratedExt = "GeneralizedGenerated" + DiffEqBaseMPIExt = "MPI" + DiffEqBaseMeasurementsExt = "Measurements" + DiffEqBaseMonteCarloMeasurementsExt = "MonteCarloMeasurements" + DiffEqBaseReverseDiffExt = "ReverseDiff" + DiffEqBaseTrackerExt = "Tracker" + DiffEqBaseUnitfulExt = "Unitful" + + [deps.DiffEqBase.weakdeps] + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + GeneralizedGenerated = "6b9d7cbe-bcb9-11e9-073f-15a7a543e2eb" + MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" + Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" + MonteCarloMeasurements = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.DiffEqCallbacks]] +deps = ["DataStructures", "DiffEqBase", "ForwardDiff", "Functors", "LinearAlgebra", "Markdown", "NonlinearSolve", "Parameters", "RecipesBase", "RecursiveArrayTools", "SciMLBase", "StaticArraysCore"] +git-tree-sha1 = "c959cfd2657d16beada157a74d52269e8556500e" +uuid = "459566f4-90b8-5000-8ac3-15dfb0a30def" +version = "3.6.2" +weakdeps = ["OrdinaryDiffEq", "Sundials"] + +[[deps.DiffEqGPU]] +deps = ["Adapt", "ChainRulesCore", "DiffEqBase", "Distributed", "DocStringExtensions", "ForwardDiff", "KernelAbstractions", "LinearAlgebra", "LinearSolve", "MuladdMacro", "Parameters", "Random", "RecursiveArrayTools", "Requires", "SciMLBase", "Setfield", "SimpleDiffEq", "StaticArrays", "TOML", "ZygoteRules"] +git-tree-sha1 = "7a714b856fe00d6194774bc38e387375f06963fe" +uuid = "071ae1c0-96b5-11e9-1965-c90190d839ea" +version = "3.4.1" + + [deps.DiffEqGPU.extensions] + AMDGPUExt = ["AMDGPU"] + CUDAExt = ["CUDA"] + MetalExt = ["Metal"] + oneAPIExt = ["oneAPI"] + + [deps.DiffEqGPU.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" + oneAPI = "8f75cd03-7ff8-4ecb-9b8f-daf728133b1b" + +[[deps.DiffEqNoiseProcess]] +deps = ["DiffEqBase", "Distributions", "GPUArraysCore", "LinearAlgebra", "Markdown", "Optim", "PoissonRandom", "QuadGK", "Random", "Random123", "RandomNumbers", "RecipesBase", "RecursiveArrayTools", "Requires", "ResettableStacks", "SciMLBase", "StaticArraysCore", "Statistics"] +git-tree-sha1 = "65cbbe1450ced323b4b17228ccd96349d96795a7" +uuid = "77a26b50-5914-5dd7-bc55-306e6241c503" +version = "5.21.0" +weakdeps = ["ReverseDiff"] + + [deps.DiffEqNoiseProcess.extensions] + DiffEqNoiseProcessReverseDiffExt = "ReverseDiff" + +[[deps.DiffResults]] +deps = ["StaticArraysCore"] +git-tree-sha1 = "782dd5f4561f5d267313f23853baaaa4c52ea621" +uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" +version = "1.1.0" + +[[deps.DiffRules]] +deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"] +git-tree-sha1 = "23163d55f885173722d1e4cf0f6110cdbaf7e272" +uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" +version = "1.15.1" + +[[deps.DifferentialEquations]] +deps = ["BoundaryValueDiffEq", "DelayDiffEq", "DiffEqBase", "DiffEqCallbacks", "DiffEqNoiseProcess", "JumpProcesses", "LinearAlgebra", "LinearSolve", "NonlinearSolve", "OrdinaryDiffEq", "Random", "RecursiveArrayTools", "Reexport", "SciMLBase", "SteadyStateDiffEq", "StochasticDiffEq", "Sundials"] +git-tree-sha1 = "81042254a307980b8ab5b67033aca26c2e157ebb" +uuid = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +version = "7.13.0" + +[[deps.Distances]] +deps = ["LinearAlgebra", "Statistics", "StatsAPI"] +git-tree-sha1 = "66c4c81f259586e8f002eacebc177e1fb06363b0" +uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" +version = "0.10.11" +weakdeps = ["ChainRulesCore", "SparseArrays"] + + [deps.Distances.extensions] + DistancesChainRulesCoreExt = "ChainRulesCore" + DistancesSparseArraysExt = "SparseArrays" + +[[deps.Distributed]] +deps = ["Random", "Serialization", "Sockets"] +uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" + +[[deps.Distributions]] +deps = ["AliasTables", "FillArrays", "LinearAlgebra", "PDMats", "Printf", "QuadGK", "Random", "SpecialFunctions", "Statistics", "StatsAPI", "StatsBase", "StatsFuns"] +git-tree-sha1 = "22c595ca4146c07b16bcf9c8bea86f731f7109d2" +uuid = "31c24e10-a181-5473-b8eb-7969acd0382f" +version = "0.25.108" + + [deps.Distributions.extensions] + DistributionsChainRulesCoreExt = "ChainRulesCore" + DistributionsDensityInterfaceExt = "DensityInterface" + DistributionsTestExt = "Test" + + [deps.Distributions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + DensityInterface = "b429d917-457f-4dbc-8f4c-0cc954292b1d" + Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.DocStringExtensions]] +deps = ["LibGit2"] +git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" +uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" +version = "0.9.3" + +[[deps.Documenter]] +deps = ["ANSIColoredPrinters", "AbstractTrees", "Base64", "CodecZlib", "Dates", "DocStringExtensions", "Downloads", "Git", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "MarkdownAST", "Pkg", "PrecompileTools", "REPL", "RegistryInstances", "SHA", "TOML", "Test", "Unicode"] +git-tree-sha1 = "5461b2a67beb9089980e2f8f25145186b6d34f91" +uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +version = "1.4.1" + +[[deps.DomainSets]] +deps = ["CompositeTypes", "IntervalSets", "LinearAlgebra", "Random", "StaticArrays", "Statistics"] +git-tree-sha1 = "51b4b84d33ec5e0955b55ff4b748b99ce2c3faa9" +uuid = "5b8099bc-c8ec-5219-889f-1d9e522a28bf" +version = "0.6.7" + +[[deps.Downloads]] +deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] +uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" +version = "1.6.0" + +[[deps.DualNumbers]] +deps = ["Calculus", "NaNMath", "SpecialFunctions"] +git-tree-sha1 = "5837a837389fccf076445fce071c8ddaea35a566" +uuid = "fa6b7ba4-c1ee-5f82-b5fc-ecf0adba8f74" +version = "0.6.8" + +[[deps.DynamicPolynomials]] +deps = ["Future", "LinearAlgebra", "MultivariatePolynomials", "MutableArithmetics", "Pkg", "Reexport", "Test"] +git-tree-sha1 = "30a1848c4f4fc35d1d4bbbd125650f6a11b5bc6c" +uuid = "7c1d4256-1411-5781-91ec-d7bc3513ac07" +version = "0.5.7" + +[[deps.DynamicQuantities]] +deps = ["Compat", "PackageExtensionCompat", "Tricks"] +git-tree-sha1 = "412b25c7d99ec6b06967d315c7b29bb8e484f092" +uuid = "06fc5a27-2a28-4c7c-a15d-362465fb6821" +version = "0.13.2" + + [deps.DynamicQuantities.extensions] + DynamicQuantitiesLinearAlgebraExt = "LinearAlgebra" + DynamicQuantitiesMeasurementsExt = "Measurements" + DynamicQuantitiesScientificTypesExt = "ScientificTypes" + DynamicQuantitiesUnitfulExt = "Unitful" + + [deps.DynamicQuantities.weakdeps] + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" + ScientificTypes = "321657f4-b219-11e9-178b-2701a2544e81" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.EllipsisNotation]] +deps = ["StaticArrayInterface"] +git-tree-sha1 = "3507300d4343e8e4ad080ad24e335274c2e297a9" +uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949" +version = "1.8.0" + +[[deps.EnumX]] +git-tree-sha1 = "bdb1942cd4c45e3c678fd11569d5cccd80976237" +uuid = "4e289a0a-7415-4d19-859d-a7e5c4648b56" +version = "1.0.4" + +[[deps.Enzyme]] +deps = ["CEnum", "EnzymeCore", "Enzyme_jll", "GPUCompiler", "LLVM", "Libdl", "LinearAlgebra", "ObjectFile", "Preferences", "Printf", "Random"] +git-tree-sha1 = "3fb48f9c18de1993c477457265b85130756746ae" +uuid = "7da242da-08ed-463a-9acd-ee780be4f1d9" +version = "0.11.20" +weakdeps = ["SpecialFunctions"] + + [deps.Enzyme.extensions] + EnzymeSpecialFunctionsExt = "SpecialFunctions" + +[[deps.EnzymeCore]] +git-tree-sha1 = "1bc328eec34ffd80357f84a84bb30e4374e9bd60" +uuid = "f151be2c-9106-41f4-ab19-57ee4f262869" +version = "0.6.6" +weakdeps = ["Adapt"] + + [deps.EnzymeCore.extensions] + AdaptExt = "Adapt" + +[[deps.Enzyme_jll]] +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "32d418c804279c60dd38ac7868126696f3205a4f" +uuid = "7cc45869-7501-5eee-bdea-0790c847d4ef" +version = "0.0.102+0" + +[[deps.EpollShim_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "8e9441ee83492030ace98f9789a654a6d0b1f643" +uuid = "2702e6a9-849d-5ed8-8c21-79e8b8f9ee43" +version = "0.0.20230411+0" + +[[deps.ExceptionUnwrapping]] +deps = ["Test"] +git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a" +uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" +version = "0.1.10" + +[[deps.Expat_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1c6317308b9dc757616f0b5cb379db10494443a7" +uuid = "2e619515-83b5-522b-bb60-26c02a35a201" +version = "2.6.2+0" + +[[deps.ExponentialUtilities]] +deps = ["Adapt", "ArrayInterface", "GPUArraysCore", "GenericSchur", "LinearAlgebra", "PrecompileTools", "Printf", "SparseArrays", "libblastrampoline_jll"] +git-tree-sha1 = "8e18940a5ba7f4ddb41fe2b79b6acaac50880a86" +uuid = "d4d017d3-3776-5f7e-afef-a10c40355c18" +version = "1.26.1" + +[[deps.ExprTools]] +git-tree-sha1 = "27415f162e6028e81c72b82ef756bf321213b6ec" +uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" +version = "0.1.10" + +[[deps.FFMPEG]] +deps = ["FFMPEG_jll"] +git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" +uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" +version = "0.4.1" + +[[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 = "466d45dc38e15794ec7d5d63ec03d776a9aff36e" +uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" +version = "4.4.4+1" + +[[deps.FFTW]] +deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] +git-tree-sha1 = "4820348781ae578893311153d69049a93d05f39d" +uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +version = "1.8.0" + +[[deps.FFTW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea" +uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" +version = "3.3.10+0" + +[[deps.FLoops]] +deps = ["BangBang", "Compat", "FLoopsBase", "InitialValues", "JuliaVariables", "MLStyle", "Serialization", "Setfield", "Transducers"] +git-tree-sha1 = "ffb97765602e3cbe59a0589d237bf07f245a8576" +uuid = "cc61a311-1640-44b5-9fba-1b764f453329" +version = "0.2.1" + +[[deps.FLoopsBase]] +deps = ["ContextVariablesX"] +git-tree-sha1 = "656f7a6859be8673bf1f35da5670246b923964f7" +uuid = "b9860ae5-e623-471e-878b-f6a53c775ea6" +version = "0.1.1" + +[[deps.FastAlmostBandedMatrices]] +deps = ["ArrayInterface", "ArrayLayouts", "BandedMatrices", "ConcreteStructs", "LazyArrays", "LinearAlgebra", "MatrixFactorizations", "PrecompileTools", "Reexport"] +git-tree-sha1 = "aee47d984d8eddc4ef5fd6b637e7285a16b1283f" +uuid = "9d29842c-ecb8-4973-b1e9-a27b1157504e" +version = "0.1.2" + +[[deps.FastBroadcast]] +deps = ["ArrayInterface", "LinearAlgebra", "Polyester", "Static", "StaticArrayInterface", "StrideArraysCore"] +git-tree-sha1 = "a6e756a880fc419c8b41592010aebe6a5ce09136" +uuid = "7034ab61-46d4-4ed7-9d0f-46aef9175898" +version = "0.2.8" + +[[deps.FastClosures]] +git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef" +uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a" +version = "0.3.2" + +[[deps.FastLapackInterface]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "cbf5edddb61a43669710cbc2241bc08b36d9e660" +uuid = "29a986be-02c6-4525-aec4-84b980013641" +version = "2.0.4" + +[[deps.FilePathsBase]] +deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] +git-tree-sha1 = "9f00e42f8d99fdde64d40c8ea5d14269a2e2c1aa" +uuid = "48062228-2e41-5def-b9a4-89aafe57970f" +version = "0.9.21" + +[[deps.FileWatching]] +uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" + +[[deps.FillArrays]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "0653c0a2396a6da5bc4766c43041ef5fd3efbe57" +uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" +version = "1.11.0" +weakdeps = ["PDMats", "SparseArrays", "Statistics"] + + [deps.FillArrays.extensions] + FillArraysPDMatsExt = "PDMats" + FillArraysSparseArraysExt = "SparseArrays" + FillArraysStatisticsExt = "Statistics" + +[[deps.FindFirstFunctions]] +git-tree-sha1 = "e90fef90f7d75e6a5b435b0fd65609759f99717a" +uuid = "64ca27bc-2ba2-4a57-88aa-44e436879224" +version = "1.2.0" + +[[deps.FiniteDiff]] +deps = ["ArrayInterface", "LinearAlgebra", "Requires", "Setfield", "SparseArrays"] +git-tree-sha1 = "2de436b72c3422940cbe1367611d137008af7ec3" +uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" +version = "2.23.1" + + [deps.FiniteDiff.extensions] + FiniteDiffBandedMatricesExt = "BandedMatrices" + FiniteDiffBlockBandedMatricesExt = "BlockBandedMatrices" + FiniteDiffStaticArraysExt = "StaticArrays" + + [deps.FiniteDiff.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockBandedMatrices = "ffab5731-97b5-5995-9138-79e8c1846df0" + 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.Flux]] +deps = ["Adapt", "ChainRulesCore", "Compat", "Functors", "LinearAlgebra", "MLUtils", "MacroTools", "NNlib", "OneHotArrays", "Optimisers", "Preferences", "ProgressLogging", "Random", "Reexport", "SparseArrays", "SpecialFunctions", "Statistics", "Zygote"] +git-tree-sha1 = "a5475163b611812d073171583982c42ea48d22b0" +uuid = "587475ba-b771-5e3f-ad9e-33799f191a9c" +version = "0.14.15" + + [deps.Flux.extensions] + FluxAMDGPUExt = "AMDGPU" + FluxCUDAExt = "CUDA" + FluxCUDAcuDNNExt = ["CUDA", "cuDNN"] + FluxMetalExt = "Metal" + + [deps.Flux.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" + cuDNN = "02a925ec-e4fe-4b08-9a7e-0d78e3d38ccd" + +[[deps.Fontconfig_jll]] +deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Zlib_jll"] +git-tree-sha1 = "db16beca600632c95fc8aca29890d83788dd8b23" +uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" +version = "2.13.96+0" + +[[deps.Format]] +git-tree-sha1 = "9c68794ef81b08086aeb32eeaf33531668d5f5fc" +uuid = "1fa38f19-a742-5d3f-a2b9-30dd87b9d5f8" +version = "1.3.7" + +[[deps.ForwardDiff]] +deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions"] +git-tree-sha1 = "cf0fe81336da9fb90944683b8c41984b08793dad" +uuid = "f6369f11-7733-5829-9624-2563aa707210" +version = "0.10.36" +weakdeps = ["StaticArrays"] + + [deps.ForwardDiff.extensions] + ForwardDiffStaticArraysExt = "StaticArrays" + +[[deps.FreeType2_jll]] +deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "5c1d8ae0efc6c2e7b1fc502cbe25def8f661b7bc" +uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" +version = "2.13.2+0" + +[[deps.FriBidi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1ed150b39aebcc805c26b93a8d0122c940f64ce2" +uuid = "559328eb-81f9-559d-9380-de523a88c83c" +version = "1.0.14+0" + +[[deps.FunctionProperties]] +deps = ["Cassette", "DiffRules"] +git-tree-sha1 = "bf7c740307eb0ee80e05d8aafbd0c5a901578398" +uuid = "f62d2435-5019-4c03-9749-2d4c77af0cbc" +version = "0.1.2" + +[[deps.FunctionWrappers]] +git-tree-sha1 = "d62485945ce5ae9c0c48f124a84998d755bae00e" +uuid = "069b7b12-0de2-55c6-9aab-29f3d0a68a2e" +version = "1.1.3" + +[[deps.FunctionWrappersWrappers]] +deps = ["FunctionWrappers"] +git-tree-sha1 = "b104d487b34566608f8b4e1c39fb0b10aa279ff8" +uuid = "77dc65aa-8811-40c2-897b-53d922fa7daf" +version = "0.1.3" + +[[deps.Functors]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "d3e63d9fa13f8eaa2f06f64949e2afc593ff52c2" +uuid = "d9f16b24-f501-4c13-a1f2-28368ffc5196" +version = "0.4.10" + +[[deps.Future]] +deps = ["Random"] +uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" + +[[deps.GLFW_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] +git-tree-sha1 = "ff38ba61beff76b8f4acad8ab0c97ef73bb670cb" +uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" +version = "3.3.9+0" + +[[deps.GPUArrays]] +deps = ["Adapt", "GPUArraysCore", "LLVM", "LinearAlgebra", "Printf", "Random", "Reexport", "Serialization", "Statistics"] +git-tree-sha1 = "38cb19b8a3e600e509dc36a6396ac74266d108c1" +uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" +version = "10.1.1" + +[[deps.GPUArraysCore]] +deps = ["Adapt"] +git-tree-sha1 = "ec632f177c0d990e64d955ccc1b8c04c485a0950" +uuid = "46192b85-c4d5-4398-a991-12ede77f4527" +version = "0.1.6" + +[[deps.GPUCompiler]] +deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "Scratch", "TimerOutputs", "UUIDs"] +git-tree-sha1 = "a846f297ce9d09ccba02ead0cae70690e072a119" +uuid = "61eb1bfa-7361-4325-ad38-22787b887f55" +version = "0.25.0" + +[[deps.GR]] +deps = ["Artifacts", "Base64", "DelimitedFiles", "Downloads", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Preferences", "Printf", "Random", "Serialization", "Sockets", "TOML", "Tar", "Test", "p7zip_jll"] +git-tree-sha1 = "ddda044ca260ee324c5fc07edb6d7cf3f0b9c350" +uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" +version = "0.73.5" + +[[deps.GR_jll]] +deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "FreeType2_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Qt6Base_jll", "Zlib_jll", "libpng_jll"] +git-tree-sha1 = "278e5e0f820178e8a26df3184fcb2280717c79b1" +uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" +version = "0.73.5+0" + +[[deps.GenericSchur]] +deps = ["LinearAlgebra", "Printf"] +git-tree-sha1 = "af49a0851f8113fcfae2ef5027c6d49d0acec39b" +uuid = "c145ed77-6b09-5dd9-b285-bf645a82121e" +version = "0.5.4" + +[[deps.Gettext_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" +uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" +version = "0.21.0+0" + +[[deps.Git]] +deps = ["Git_jll"] +git-tree-sha1 = "04eff47b1354d702c3a85e8ab23d539bb7d5957e" +uuid = "d7ba0133-e1db-5d97-8f8c-041e4b3a1eb2" +version = "1.3.1" + +[[deps.Git_jll]] +deps = ["Artifacts", "Expat_jll", "JLLWrappers", "LibCURL_jll", "Libdl", "Libiconv_jll", "OpenSSL_jll", "PCRE2_jll", "Zlib_jll"] +git-tree-sha1 = "d18fb8a1f3609361ebda9bf029b60fd0f120c809" +uuid = "f8c6e375-362e-5223-8a59-34ff63f689eb" +version = "2.44.0+2" + +[[deps.Glib_jll]] +deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE2_jll", "Zlib_jll"] +git-tree-sha1 = "7c82e6a6cd34e9d935e9aa4051b66c6ff3af59ba" +uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" +version = "2.80.2+0" + +[[deps.Glob]] +git-tree-sha1 = "97285bbd5230dd766e9ef6749b80fc617126d496" +uuid = "c27321d9-0574-5035-807b-f59d2c89b15c" +version = "1.3.1" + +[[deps.Graphite2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011" +uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472" +version = "1.3.14+0" + +[[deps.Graphs]] +deps = ["ArnoldiMethod", "Compat", "DataStructures", "Distributed", "Inflate", "LinearAlgebra", "Random", "SharedArrays", "SimpleTraits", "SparseArrays", "Statistics"] +git-tree-sha1 = "4f2b57488ac7ee16124396de4f2bbdd51b2602ad" +uuid = "86223c79-3864-5bf0-83f7-82e725a168b6" +version = "1.11.0" + +[[deps.Grisu]] +git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" +uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" +version = "1.0.2" + +[[deps.Gumbo]] +deps = ["AbstractTrees", "Gumbo_jll", "Libdl"] +git-tree-sha1 = "a1a138dfbf9df5bace489c7a9d5196d6afdfa140" +uuid = "708ec375-b3d6-5a57-a7ce-8257bf98657a" +version = "0.8.2" + +[[deps.Gumbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "29070dee9df18d9565276d68a596854b1764aa38" +uuid = "528830af-5a63-567c-a44a-034ed33b8444" +version = "0.10.2+0" + +[[deps.HCubature]] +deps = ["Combinatorics", "DataStructures", "LinearAlgebra", "QuadGK", "StaticArrays"] +git-tree-sha1 = "10f37537bbd83e52c63abf6393f209dbd641fedc" +uuid = "19dc6840-f33b-545b-b366-655c7e3ffd49" +version = "1.6.0" + +[[deps.HTTP]] +deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] +git-tree-sha1 = "d1d712be3164d61d1fb98e7ce9bcbc6cc06b45ed" +uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" +version = "1.10.8" + +[[deps.HarfBuzz_jll]] +deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"] +git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3" +uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566" +version = "2.8.1+1" + +[[deps.HostCPUFeatures]] +deps = ["BitTwiddlingConvenienceFunctions", "IfElse", "Libdl", "Static"] +git-tree-sha1 = "eb8fed28f4994600e29beef49744639d985a04b2" +uuid = "3e5b6fbb-0976-4d2c-9146-d79de83f2fb0" +version = "0.1.16" + +[[deps.HypergeometricFunctions]] +deps = ["DualNumbers", "LinearAlgebra", "OpenLibm_jll", "SpecialFunctions"] +git-tree-sha1 = "f218fe3736ddf977e0e772bc9a586b2383da2685" +uuid = "34004b35-14d8-5ef3-9330-4cdb6864b03a" +version = "0.3.23" + +[[deps.HypertextLiteral]] +deps = ["Tricks"] +git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" +uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" +version = "0.9.5" + +[[deps.IOCapture]] +deps = ["Logging", "Random"] +git-tree-sha1 = "8b72179abc660bfab5e28472e019392b97d0985c" +uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" +version = "0.2.4" + +[[deps.IRTools]] +deps = ["InteractiveUtils", "MacroTools"] +git-tree-sha1 = "950c3717af761bc3ff906c2e8e52bd83390b6ec2" +uuid = "7869d1d1-7146-5819-86e3-90919afe41df" +version = "0.4.14" + +[[deps.IfElse]] +git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" +uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" +version = "0.1.1" + +[[deps.IncompleteLU]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "6c676e79f98abb6d33fa28122cad099f1e464afe" +uuid = "40713840-3770-5561-ab4c-a76e7d0d7895" +version = "0.2.1" + +[[deps.Inflate]] +git-tree-sha1 = "ea8031dea4aff6bd41f1df8f2fdfb25b33626381" +uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9" +version = "0.1.4" + +[[deps.InitialValues]] +git-tree-sha1 = "4da0f88e9a39111c2fa3add390ab15f3a44f3ca3" +uuid = "22cec73e-a1b8-11e9-2c92-598750a2cf9c" +version = "0.3.1" + +[[deps.InlineStrings]] +deps = ["Parsers"] +git-tree-sha1 = "9cc2baf75c6d09f9da536ddf58eb2f29dedaf461" +uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" +version = "1.4.0" + +[[deps.InplaceOps]] +deps = ["LinearAlgebra", "Test"] +git-tree-sha1 = "50b41d59e7164ab6fda65e71049fee9d890731ff" +uuid = "505f98c9-085e-5b2c-8e89-488be7bf1f34" +version = "0.3.0" + +[[deps.IntegerMathUtils]] +git-tree-sha1 = "b8ffb903da9f7b8cf695a8bead8e01814aa24b30" +uuid = "18e54dd8-cb9d-406c-a71d-865a43cbb235" +version = "0.1.2" + +[[deps.Integrals]] +deps = ["CommonSolve", "HCubature", "LinearAlgebra", "MonteCarloIntegration", "QuadGK", "Reexport", "SciMLBase"] +git-tree-sha1 = "ebf5737d823873add85809f2b52e20e3eae71997" +uuid = "de52edbc-65ea-441a-8357-d3a637375a31" +version = "4.4.1" + + [deps.Integrals.extensions] + IntegralsArblibExt = "Arblib" + IntegralsCubaExt = "Cuba" + IntegralsCubatureExt = "Cubature" + IntegralsFastGaussQuadratureExt = "FastGaussQuadrature" + IntegralsForwardDiffExt = "ForwardDiff" + IntegralsMCIntegrationExt = "MCIntegration" + IntegralsZygoteExt = ["Zygote", "ChainRulesCore"] + + [deps.Integrals.weakdeps] + Arblib = "fb37089c-8514-4489-9461-98f9c8763369" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Cuba = "8a292aeb-7a57-582c-b821-06e4c11590b1" + Cubature = "667455a9-e2ce-5579-9412-b964f529a492" + FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + MCIntegration = "ea1e2de9-7db7-4b42-91ee-0cd1bf6df167" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.IntelOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "be50fe8df3acbffa0274a744f1a99d29c45a57f4" +uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" +version = "2024.1.0+0" + +[[deps.InteractiveUtils]] +deps = ["Markdown"] +uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" + +[[deps.Interpolations]] +deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] +git-tree-sha1 = "00a19d6ab0cbdea2978fc23c5a6482e02c192501" +uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" +version = "0.14.0" + +[[deps.IntervalSets]] +git-tree-sha1 = "dba9ddf07f77f60450fe5d2e2beb9854d9a49bd0" +uuid = "8197267c-284f-5f27-9208-e0e47529a953" +version = "0.7.10" +weakdeps = ["Random", "RecipesBase", "Statistics"] + + [deps.IntervalSets.extensions] + IntervalSetsRandomExt = "Random" + IntervalSetsRecipesBaseExt = "RecipesBase" + IntervalSetsStatisticsExt = "Statistics" + +[[deps.InverseFunctions]] +deps = ["Test"] +git-tree-sha1 = "e7cbed5032c4c397a6ac23d1493f3289e01231c4" +uuid = "3587e190-3f89-42d0-90ee-14403ec27112" +version = "0.1.14" +weakdeps = ["Dates"] + + [deps.InverseFunctions.extensions] + DatesExt = "Dates" + +[[deps.InvertedIndices]] +git-tree-sha1 = "0dc7b50b8d436461be01300fd8cd45aa0274b038" +uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" +version = "1.3.0" + +[[deps.IrrationalConstants]] +git-tree-sha1 = "630b497eafcc20001bba38a4651b327dcfc491d2" +uuid = "92d709cd-6900-40b7-9082-c6be49f344b6" +version = "0.2.2" + +[[deps.IterTools]] +git-tree-sha1 = "42d5f897009e7ff2cf88db414a389e5ed1bdd023" +uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" +version = "1.10.0" + +[[deps.IteratorInterfaceExtensions]] +git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" +uuid = "82899510-4779-5014-852e-03e436cf321d" +version = "1.0.0" + +[[deps.JLFzf]] +deps = ["Pipe", "REPL", "Random", "fzf_jll"] +git-tree-sha1 = "a53ebe394b71470c7f97c2e7e170d51df21b17af" +uuid = "1019f520-868f-41f5-a6de-eb00f4b6a39c" +version = "0.1.7" + +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" +uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" +version = "1.5.0" + +[[deps.JSON]] +deps = ["Dates", "Mmap", "Parsers", "Unicode"] +git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" +uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +version = "0.21.4" + +[[deps.JpegTurbo_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "c84a835e1a09b289ffcd2271bf2a337bbdda6637" +uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" +version = "3.0.3+0" + +[[deps.JuliaFormatter]] +deps = ["CSTParser", "CommonMark", "DataStructures", "Glob", "Pkg", "PrecompileTools", "Tokenize"] +git-tree-sha1 = "1c4880cb70a5c6c87ea36deccc3d7f9e7969c18c" +uuid = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +version = "1.0.56" + +[[deps.JuliaNVTXCallbacks_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "af433a10f3942e882d3c671aacb203e006a5808f" +uuid = "9c1d0b0a-7046-5b2e-a33f-ea22f176ac7e" +version = "0.2.1+0" + +[[deps.JuliaVariables]] +deps = ["MLStyle", "NameResolution"] +git-tree-sha1 = "49fb3cb53362ddadb4415e9b73926d6b40709e70" +uuid = "b14d175d-62b4-44ba-8fb7-3064adc8c3ec" +version = "0.2.4" + +[[deps.JumpProcesses]] +deps = ["ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "FunctionWrappers", "Graphs", "LinearAlgebra", "Markdown", "PoissonRandom", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "StaticArrays", "SymbolicIndexingInterface", "UnPack"] +git-tree-sha1 = "ed08d89318be7d625613f3c435d1f6678fba4850" +uuid = "ccbc3e58-028d-4f4c-8cd5-9ae44345cda5" +version = "9.11.1" +weakdeps = ["FastBroadcast"] + + [deps.JumpProcesses.extensions] + JumpProcessFastBroadcastExt = "FastBroadcast" + +[[deps.KLU]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse_jll"] +git-tree-sha1 = "07649c499349dad9f08dde4243a4c597064663e9" +uuid = "ef3ab10e-7fda-4108-b977-705223b18434" +version = "0.6.0" + +[[deps.KernelAbstractions]] +deps = ["Adapt", "Atomix", "InteractiveUtils", "LinearAlgebra", "MacroTools", "PrecompileTools", "Requires", "SparseArrays", "StaticArrays", "UUIDs", "UnsafeAtomics", "UnsafeAtomicsLLVM"] +git-tree-sha1 = "ed7167240f40e62d97c1f5f7735dea6de3cc5c49" +uuid = "63c18a36-062a-441e-b654-da1e3ab1ce7c" +version = "0.9.18" +weakdeps = ["EnzymeCore"] + + [deps.KernelAbstractions.extensions] + EnzymeExt = "EnzymeCore" + +[[deps.KernelDensity]] +deps = ["Distributions", "DocStringExtensions", "FFTW", "Interpolations", "StatsBase"] +git-tree-sha1 = "7d703202e65efa1369de1279c162b915e245eed1" +uuid = "5ab0869b-81aa-558d-bb23-cbf5423bbe9b" +version = "0.6.9" + +[[deps.Krylov]] +deps = ["LinearAlgebra", "Printf", "SparseArrays"] +git-tree-sha1 = "267dad6b4b7b5d529c76d40ff48d33f7e94cb834" +uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7" +version = "0.9.6" + +[[deps.LAME_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "170b660facf5df5de098d866564877e119141cbd" +uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" +version = "3.100.2+0" + +[[deps.LERC_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "bf36f528eec6634efc60d7ec062008f171071434" +uuid = "88015f11-f218-50d7-93a8-a6af411a945d" +version = "3.0.0+1" + +[[deps.LLVM]] +deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Preferences", "Printf", "Requires", "Unicode"] +git-tree-sha1 = "839c82932db86740ae729779e610f07a1640be9a" +uuid = "929cbde3-209d-540e-8aea-75f648917ca0" +version = "6.6.3" +weakdeps = ["BFloat16s"] + + [deps.LLVM.extensions] + BFloat16sExt = "BFloat16s" + +[[deps.LLVMExtra_jll]] +deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "TOML"] +git-tree-sha1 = "88b916503aac4fb7f701bb625cd84ca5dd1677bc" +uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab" +version = "0.0.29+0" + +[[deps.LLVMLoopInfo]] +git-tree-sha1 = "2e5c102cfc41f48ae4740c7eca7743cc7e7b75ea" +uuid = "8b046642-f1f6-4319-8d3c-209ddc03c586" +version = "1.0.0" + +[[deps.LLVMOpenMP_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "d986ce2d884d49126836ea94ed5bfb0f12679713" +uuid = "1d63c593-3942-5779-bab2-d838dc0a180e" +version = "15.0.7+0" + +[[deps.LZO_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "70c5da094887fd2cae843b8db33920bac4b6f07d" +uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" +version = "2.10.2+0" + +[[deps.LaTeXStrings]] +git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" +uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" +version = "1.3.1" + +[[deps.LabelledArrays]] +deps = ["ArrayInterface", "ChainRulesCore", "ForwardDiff", "LinearAlgebra", "MacroTools", "PreallocationTools", "RecursiveArrayTools", "StaticArrays"] +git-tree-sha1 = "e459fda6b68ea8684b3fcd513d2fd1e5130c4402" +uuid = "2ee39098-c373-598a-b85f-a56591580800" +version = "1.16.0" + +[[deps.LambertW]] +git-tree-sha1 = "c5ffc834de5d61d00d2b0e18c96267cffc21f648" +uuid = "984bce1d-4616-540c-a9ee-88d1112d94c9" +version = "0.4.6" + +[[deps.Latexify]] +deps = ["Format", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "OrderedCollections", "Requires"] +git-tree-sha1 = "e0b5cd21dc1b44ec6e64f351976f961e6f31d6c4" +uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" +version = "0.16.3" + + [deps.Latexify.extensions] + DataFramesExt = "DataFrames" + SymEngineExt = "SymEngine" + + [deps.Latexify.weakdeps] + DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" + SymEngine = "123dc426-2d89-5057-bbad-38513e3affd8" + +[[deps.LatticeRules]] +deps = ["Random"] +git-tree-sha1 = "7f5b02258a3ca0221a6a9710b0a0a2e8fb4957fe" +uuid = "73f95e8e-ec14-4e6a-8b18-0d2e271c4e55" +version = "0.0.1" + +[[deps.LayoutPointers]] +deps = ["ArrayInterface", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface"] +git-tree-sha1 = "62edfee3211981241b57ff1cedf4d74d79519277" +uuid = "10f19ff3-798f-405d-979b-55457f8fc047" +version = "0.1.15" + +[[deps.LazilyInitializedFields]] +git-tree-sha1 = "8f7f3cabab0fd1800699663533b6d5cb3fc0e612" +uuid = "0e77f7df-68c5-4e49-93ce-4cd80f5598bf" +version = "1.2.2" + +[[deps.LazyArrays]] +deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra", "MacroTools", "MatrixFactorizations", "SparseArrays"] +git-tree-sha1 = "35079a6a869eecace778bcda8641f9a54ca3a828" +uuid = "5078a376-72f3-5289-bfd5-ec5146d43c02" +version = "1.10.0" +weakdeps = ["StaticArrays"] + + [deps.LazyArrays.extensions] + LazyArraysStaticArraysExt = "StaticArrays" + +[[deps.LazyArtifacts]] +deps = ["Artifacts", "Pkg"] +uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" + +[[deps.LeftChildRightSiblingTrees]] +deps = ["AbstractTrees"] +git-tree-sha1 = "fb6803dafae4a5d62ea5cab204b1e657d9737e7f" +uuid = "1d6d02ad-be62-4b6b-8a6d-2f90e265016e" +version = "0.2.0" + +[[deps.LevyArea]] +deps = ["LinearAlgebra", "Random", "SpecialFunctions"] +git-tree-sha1 = "56513a09b8e0ae6485f34401ea9e2f31357958ec" +uuid = "2d8b4e74-eb68-11e8-0fb9-d5eb67b50637" +version = "1.0.0" + +[[deps.LibCURL]] +deps = ["LibCURL_jll", "MozillaCACerts_jll"] +uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" +version = "0.6.4" + +[[deps.LibCURL_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] +uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" +version = "8.4.0+0" + +[[deps.LibGit2]] +deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] +uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" + +[[deps.LibGit2_jll]] +deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] +uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" +version = "1.6.4+0" + +[[deps.LibSSH2_jll]] +deps = ["Artifacts", "Libdl", "MbedTLS_jll"] +uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" +version = "1.11.0+1" + +[[deps.Libdl]] +uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" + +[[deps.Libffi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290" +uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" +version = "3.2.2+1" + +[[deps.Libgcrypt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll"] +git-tree-sha1 = "9fd170c4bbfd8b935fdc5f8b7aa33532c991a673" +uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" +version = "1.8.11+0" + +[[deps.Libglvnd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] +git-tree-sha1 = "6f73d1dd803986947b2c750138528a999a6c7733" +uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" +version = "1.6.0+0" + +[[deps.Libgpg_error_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "fbb1f2bef882392312feb1ede3615ddc1e9b99ed" +uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" +version = "1.49.0+0" + +[[deps.Libiconv_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175" +uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" +version = "1.17.0+0" + +[[deps.Libmount_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "0c4f9c4f1a50d8f35048fa0532dabbadf702f81e" +uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" +version = "2.40.1+0" + +[[deps.Libtiff_jll]] +deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "LERC_jll", "Libdl", "XZ_jll", "Zlib_jll", "Zstd_jll"] +git-tree-sha1 = "2da088d113af58221c52828a80378e16be7d037a" +uuid = "89763e89-9b03-5906-acba-b20f662cd828" +version = "4.5.1+1" + +[[deps.Libuuid_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "5ee6203157c120d79034c748a2acba45b82b8807" +uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" +version = "2.40.1+0" + +[[deps.LineSearches]] +deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] +git-tree-sha1 = "7bbea35cec17305fc70a0e5b4641477dc0789d9d" +uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +version = "7.2.0" + +[[deps.LinearAlgebra]] +deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] +uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" + +[[deps.LinearSolve]] +deps = ["ArrayInterface", "ChainRulesCore", "ConcreteStructs", "DocStringExtensions", "EnumX", "FastLapackInterface", "GPUArraysCore", "InteractiveUtils", "KLU", "Krylov", "LazyArrays", "Libdl", "LinearAlgebra", "MKL_jll", "Markdown", "PrecompileTools", "Preferences", "RecursiveFactorization", "Reexport", "SciMLBase", "SciMLOperators", "Setfield", "SparseArrays", "Sparspak", "StaticArraysCore", "UnPack"] +git-tree-sha1 = "7648cc20100504f4b453917aacc8520e9c0ecfb3" +uuid = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +version = "2.30.1" + + [deps.LinearSolve.extensions] + LinearSolveBandedMatricesExt = "BandedMatrices" + LinearSolveBlockDiagonalsExt = "BlockDiagonals" + LinearSolveCUDAExt = "CUDA" + LinearSolveCUDSSExt = "CUDSS" + LinearSolveEnzymeExt = ["Enzyme", "EnzymeCore"] + LinearSolveFastAlmostBandedMatricesExt = ["FastAlmostBandedMatrices"] + LinearSolveHYPREExt = "HYPRE" + LinearSolveIterativeSolversExt = "IterativeSolvers" + LinearSolveKernelAbstractionsExt = "KernelAbstractions" + LinearSolveKrylovKitExt = "KrylovKit" + LinearSolveMetalExt = "Metal" + LinearSolvePardisoExt = "Pardiso" + LinearSolveRecursiveArrayToolsExt = "RecursiveArrayTools" + + [deps.LinearSolve.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + BlockDiagonals = "0a1fb500-61f7-11e9-3c65-f5ef3456f9f0" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + CUDSS = "45b445bb-4962-46a0-9369-b4df9d0f772e" + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + FastAlmostBandedMatrices = "9d29842c-ecb8-4973-b1e9-a27b1157504e" + HYPRE = "b5ffcf37-a2bd-41ab-a3da-4bd9bc8ad771" + IterativeSolvers = "42fd0dbc-a981-5370-80f2-aaf504508153" + KernelAbstractions = "63c18a36-062a-441e-b654-da1e3ab1ce7c" + KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" + Pardiso = "46dd5b70-b6fb-5a00-ae2d-e8fea33afaf2" + RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" + +[[deps.LogDensityProblems]] +deps = ["ArgCheck", "DocStringExtensions", "Random"] +git-tree-sha1 = "f9a11237204bc137617194d79d813069838fcf61" +uuid = "6fdf6af0-433a-55f7-b3ed-c6c6e0b8df7c" +version = "2.1.1" + +[[deps.LogDensityProblemsAD]] +deps = ["DocStringExtensions", "LogDensityProblems", "Requires", "SimpleUnPack"] +git-tree-sha1 = "98cad2db1c46f2fff70a5e305fb42c97a251422a" +uuid = "996a588d-648d-4e1f-a8f0-a84b347e47b1" +version = "1.9.0" + + [deps.LogDensityProblemsAD.extensions] + LogDensityProblemsADADTypesExt = "ADTypes" + LogDensityProblemsADEnzymeExt = "Enzyme" + LogDensityProblemsADFiniteDifferencesExt = "FiniteDifferences" + LogDensityProblemsADForwardDiffBenchmarkToolsExt = ["BenchmarkTools", "ForwardDiff"] + LogDensityProblemsADForwardDiffExt = "ForwardDiff" + LogDensityProblemsADReverseDiffExt = "ReverseDiff" + LogDensityProblemsADTrackerExt = "Tracker" + LogDensityProblemsADZygoteExt = "Zygote" + + [deps.LogDensityProblemsAD.weakdeps] + ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" + BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.LogExpFunctions]] +deps = ["DocStringExtensions", "IrrationalConstants", "LinearAlgebra"] +git-tree-sha1 = "18144f3e9cbe9b15b070288eef858f71b291ce37" +uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" +version = "0.3.27" + + [deps.LogExpFunctions.extensions] + LogExpFunctionsChainRulesCoreExt = "ChainRulesCore" + LogExpFunctionsChangesOfVariablesExt = "ChangesOfVariables" + LogExpFunctionsInverseFunctionsExt = "InverseFunctions" + + [deps.LogExpFunctions.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + ChangesOfVariables = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0" + InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112" + +[[deps.Logging]] +uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" + +[[deps.LoggingExtras]] +deps = ["Dates", "Logging"] +git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" +uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" +version = "1.0.3" + +[[deps.LoopVectorization]] +deps = ["ArrayInterface", "CPUSummary", "CloseOpenIntervals", "DocStringExtensions", "HostCPUFeatures", "IfElse", "LayoutPointers", "LinearAlgebra", "OffsetArrays", "PolyesterWeave", "PrecompileTools", "SIMDTypes", "SLEEFPirates", "Static", "StaticArrayInterface", "ThreadingUtilities", "UnPack", "VectorizationBase"] +git-tree-sha1 = "8f6786d8b2b3248d79db3ad359ce95382d5a6df8" +uuid = "bdcacae8-1622-11e9-2a5c-532679323890" +version = "0.12.170" +weakdeps = ["ChainRulesCore", "ForwardDiff", "SpecialFunctions"] + + [deps.LoopVectorization.extensions] + ForwardDiffExt = ["ChainRulesCore", "ForwardDiff"] + SpecialFunctionsExt = "SpecialFunctions" + +[[deps.Lux]] +deps = ["ADTypes", "Adapt", "ArrayInterface", "ChainRulesCore", "ConcreteStructs", "ConstructionBase", "FastClosures", "Functors", "GPUArraysCore", "LinearAlgebra", "LuxCore", "LuxDeviceUtils", "LuxLib", "MacroTools", "Markdown", "OhMyThreads", "PrecompileTools", "Preferences", "Random", "Reexport", "Setfield", "WeightInitializers"] +git-tree-sha1 = "c3fb0095a627c6333e6a910a5a5000e57bd02032" +uuid = "b2108857-7c20-44ae-9111-449ecde12c47" +version = "0.5.47" + + [deps.Lux.extensions] + LuxComponentArraysExt = "ComponentArrays" + LuxDynamicExpressionsExt = "DynamicExpressions" + LuxDynamicExpressionsForwardDiffExt = ["DynamicExpressions", "ForwardDiff"] + LuxFluxExt = "Flux" + LuxForwardDiffExt = "ForwardDiff" + LuxLuxAMDGPUExt = "LuxAMDGPU" + LuxMLUtilsExt = "MLUtils" + LuxMPIExt = "MPI" + LuxMPINCCLExt = ["CUDA", "MPI", "NCCL"] + LuxOptimisersExt = "Optimisers" + LuxReverseDiffExt = "ReverseDiff" + LuxSimpleChainsExt = "SimpleChains" + LuxTrackerExt = "Tracker" + LuxZygoteExt = "Zygote" + + [deps.Lux.weakdeps] + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" + DynamicExpressions = "a40a106e-89c9-4ca8-8020-a735e8728b6b" + Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + LuxAMDGPU = "83120cb1-ca15-4f04-bf3b-6967d2e6b60b" + MLUtils = "f1d291b0-491e-4a28-83b9-f70985020b54" + MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" + NCCL = "3fe64909-d7a1-4096-9b7d-7a0f12cf0f6b" + Optimisers = "3bd65402-5787-11e9-1adc-39752487f4e2" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + SimpleChains = "de6bee2f-e2f4-4ec7-b6ed-219cc6f6e9e5" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.LuxCUDA]] +deps = ["CUDA", "Reexport", "cuDNN"] +git-tree-sha1 = "7cf839d5eecb41e50dd430a9dcf9398727b71e8a" +uuid = "d0bbae9a-e099-4d5b-a835-1c6931763bda" +version = "0.3.2" + +[[deps.LuxCore]] +deps = ["Functors", "Random", "Setfield"] +git-tree-sha1 = "c96985555a9fe41d7ec2bd5625d6c2077e05e33e" +uuid = "bb33d45b-7691-41d6-9220-0943567d0623" +version = "0.1.15" + +[[deps.LuxDeviceUtils]] +deps = ["Adapt", "ChainRulesCore", "FastClosures", "Functors", "LuxCore", "PrecompileTools", "Preferences", "Random"] +git-tree-sha1 = "bbcf12d598b8ef6d2b12e506b1d18125552c3b27" +uuid = "34f89e08-e1d5-43b4-8944-0b49ac560553" +version = "0.1.20" + + [deps.LuxDeviceUtils.extensions] + LuxDeviceUtilsAMDGPUExt = "AMDGPU" + LuxDeviceUtilsCUDAExt = "CUDA" + LuxDeviceUtilsFillArraysExt = "FillArrays" + LuxDeviceUtilsGPUArraysExt = "GPUArrays" + LuxDeviceUtilsLuxAMDGPUExt = "LuxAMDGPU" + LuxDeviceUtilsLuxCUDAExt = "LuxCUDA" + LuxDeviceUtilsMetalGPUArraysExt = ["GPUArrays", "Metal"] + LuxDeviceUtilsRecursiveArrayToolsExt = "RecursiveArrayTools" + LuxDeviceUtilsSparseArraysExt = "SparseArrays" + LuxDeviceUtilsZygoteExt = "Zygote" + + [deps.LuxDeviceUtils.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b" + GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" + LuxAMDGPU = "83120cb1-ca15-4f04-bf3b-6967d2e6b60b" + LuxCUDA = "d0bbae9a-e099-4d5b-a835-1c6931763bda" + Metal = "dde4c033-4e86-420c-a63e-0dd931031962" + RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd" + SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.LuxLib]] +deps = ["ArrayInterface", "ChainRulesCore", "FastBroadcast", "FastClosures", "GPUArraysCore", "KernelAbstractions", "LinearAlgebra", "LuxCore", "Markdown", "NNlib", "PrecompileTools", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "f65d3c5632d5290cc36930cc024d1fb40a6b41f9" +uuid = "82251201-b29d-42c6-8e01-566dec8acb11" +version = "0.3.22" + + [deps.LuxLib.extensions] + LuxLibAMDGPUExt = "AMDGPU" + LuxLibCUDAExt = "CUDA" + LuxLibForwardDiffExt = "ForwardDiff" + LuxLibReverseDiffExt = "ReverseDiff" + LuxLibTrackerAMDGPUExt = ["AMDGPU", "Tracker"] + LuxLibTrackerExt = "Tracker" + LuxLibTrackercuDNNExt = ["CUDA", "Tracker", "cuDNN"] + LuxLibcuDNNExt = ["CUDA", "cuDNN"] + + [deps.LuxLib.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + cuDNN = "02a925ec-e4fe-4b08-9a7e-0d78e3d38ccd" + +[[deps.MCMCChains]] +deps = ["AbstractMCMC", "AxisArrays", "Dates", "Distributions", "IteratorInterfaceExtensions", "KernelDensity", "LinearAlgebra", "MCMCDiagnosticTools", "MLJModelInterface", "NaturalSort", "OrderedCollections", "PrettyTables", "Random", "RecipesBase", "Statistics", "StatsBase", "StatsFuns", "TableTraits", "Tables"] +git-tree-sha1 = "d28056379864318172ff4b7958710cfddd709339" +uuid = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" +version = "6.0.6" + +[[deps.MCMCDiagnosticTools]] +deps = ["AbstractFFTs", "DataAPI", "DataStructures", "Distributions", "LinearAlgebra", "MLJModelInterface", "Random", "SpecialFunctions", "Statistics", "StatsBase", "StatsFuns", "Tables"] +git-tree-sha1 = "8ba8b1840d3ab5b38e7c71c23c3193bb5cbc02b5" +uuid = "be115224-59cd-429b-ad48-344e309966f0" +version = "0.3.10" + +[[deps.MKL_jll]] +deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "oneTBB_jll"] +git-tree-sha1 = "80b2833b56d466b3858d565adcd16a4a05f2089b" +uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" +version = "2024.1.0+0" + +[[deps.MLJModelInterface]] +deps = ["Random", "ScientificTypesBase", "StatisticalTraits"] +git-tree-sha1 = "d2a45e1b5998ba3fdfb6cfe0c81096d4c7fb40e7" +uuid = "e80e1ace-859a-464e-9ed9-23947d8ae3ea" +version = "1.9.6" + +[[deps.MLStyle]] +git-tree-sha1 = "bc38dff0548128765760c79eb7388a4b37fae2c8" +uuid = "d8e11817-5142-5d16-987a-aa16d5891078" +version = "0.4.17" + +[[deps.MLUtils]] +deps = ["ChainRulesCore", "Compat", "DataAPI", "DelimitedFiles", "FLoops", "NNlib", "Random", "ShowCases", "SimpleTraits", "Statistics", "StatsBase", "Tables", "Transducers"] +git-tree-sha1 = "b45738c2e3d0d402dffa32b2c1654759a2ac35a4" +uuid = "f1d291b0-491e-4a28-83b9-f70985020b54" +version = "0.4.4" + +[[deps.MacroTools]] +deps = ["Markdown", "Random"] +git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" +uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" +version = "0.5.13" + +[[deps.ManualMemory]] +git-tree-sha1 = "bcaef4fc7a0cfe2cba636d84cda54b5e4e4ca3cd" +uuid = "d125e4d3-2237-4719-b19c-fa641b8a4667" +version = "0.1.8" + +[[deps.Markdown]] +deps = ["Base64"] +uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" + +[[deps.MarkdownAST]] +deps = ["AbstractTrees", "Markdown"] +git-tree-sha1 = "465a70f0fc7d443a00dcdc3267a497397b8a3899" +uuid = "d0879d2d-cac2-40c8-9cee-1863dc0c7391" +version = "0.1.2" + +[[deps.MathOptInterface]] +deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MutableArithmetics", "NaNMath", "OrderedCollections", "PrecompileTools", "Printf", "SparseArrays", "SpecialFunctions", "Test", "Unicode"] +git-tree-sha1 = "fffbbdbc10ba66885b7b4c06f4bd2c0efc5813d6" +uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" +version = "1.30.0" + +[[deps.MatrixFactorizations]] +deps = ["ArrayLayouts", "LinearAlgebra", "Printf", "Random"] +git-tree-sha1 = "6731e0574fa5ee21c02733e397beb133df90de35" +uuid = "a3b82374-2e81-5b9e-98ce-41277c0e4c87" +version = "2.2.0" + +[[deps.MaybeInplace]] +deps = ["ArrayInterface", "LinearAlgebra", "MacroTools", "SparseArrays"] +git-tree-sha1 = "1b9e613f2ca3b6cdcbfe36381e17ca2b66d4b3a1" +uuid = "bb5d69b7-63fc-4a16-80bd-7e42200c7bdb" +version = "0.1.3" + +[[deps.MbedTLS]] +deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] +git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf" +uuid = "739be429-bea8-5141-9913-cc70e7f3736d" +version = "1.1.9" + +[[deps.MbedTLS_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +version = "2.28.2+1" + +[[deps.Measurements]] +deps = ["Calculus", "LinearAlgebra", "Printf", "Requires"] +git-tree-sha1 = "bdcde8ec04ca84aef5b124a17684bf3b302de00e" +uuid = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" +version = "2.11.0" + + [deps.Measurements.extensions] + MeasurementsBaseTypeExt = "BaseType" + MeasurementsJunoExt = "Juno" + MeasurementsRecipesBaseExt = "RecipesBase" + MeasurementsSpecialFunctionsExt = "SpecialFunctions" + MeasurementsUnitfulExt = "Unitful" + + [deps.Measurements.weakdeps] + BaseType = "7fbed51b-1ef5-4d67-9085-a4a9b26f478c" + Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" + RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" + SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.Measures]] +git-tree-sha1 = "c13304c81eec1ed3af7fc20e75fb6b26092a1102" +uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" +version = "0.3.2" + +[[deps.MethodOfLines]] +deps = ["Combinatorics", "DiffEqBase", "DomainSets", "IfElse", "Interpolations", "Latexify", "LinearAlgebra", "ModelingToolkit", "OrdinaryDiffEq", "PDEBase", "PrecompileTools", "RuntimeGeneratedFunctions", "SciMLBase", "StaticArrays", "SymbolicIndexingInterface", "SymbolicUtils", "Symbolics", "TermInterface"] +git-tree-sha1 = "b91b01ee55d92cc11b6916c074808149aec2f823" +uuid = "94925ecb-adb7-4558-8ed8-f975c56a0bf4" +version = "0.11.0" + +[[deps.MicroCollections]] +deps = ["BangBang", "InitialValues", "Setfield"] +git-tree-sha1 = "629afd7d10dbc6935ec59b32daeb33bc4460a42e" +uuid = "128add7d-3638-4c79-886c-908ea0c25c34" +version = "0.1.4" + +[[deps.Missings]] +deps = ["DataAPI"] +git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "1.2.0" + +[[deps.Mmap]] +uuid = "a63ad114-7e13-5084-954f-fe012c677804" + +[[deps.ModelingToolkit]] +deps = ["AbstractTrees", "ArrayInterface", "Combinatorics", "Compat", "ConstructionBase", "DataStructures", "DiffEqBase", "DiffEqCallbacks", "DiffRules", "Distributed", "Distributions", "DocStringExtensions", "DomainSets", "DynamicQuantities", "ExprTools", "FindFirstFunctions", "ForwardDiff", "FunctionWrappersWrappers", "Graphs", "InteractiveUtils", "JuliaFormatter", "JumpProcesses", "LabelledArrays", "Latexify", "Libdl", "LinearAlgebra", "MLStyle", "NaNMath", "OrderedCollections", "OrdinaryDiffEq", "PrecompileTools", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLBase", "SciMLStructures", "Serialization", "Setfield", "SimpleNonlinearSolve", "SparseArrays", "SpecialFunctions", "StaticArrays", "SymbolicIndexingInterface", "SymbolicUtils", "Symbolics", "URIs", "UnPack", "Unitful"] +git-tree-sha1 = "81ffc7d059a10669a809a4dad2576998b196a43b" +uuid = "961ee093-0014-501f-94e3-6117800e7a78" +version = "9.15.0" + + [deps.ModelingToolkit.extensions] + MTKBifurcationKitExt = "BifurcationKit" + MTKDeepDiffsExt = "DeepDiffs" + + [deps.ModelingToolkit.weakdeps] + BifurcationKit = "0f109fa4-8a5d-4b75-95aa-f515264e7665" + DeepDiffs = "ab62b9b5-e342-54a8-a765-a90f495de1a6" + +[[deps.MonteCarloIntegration]] +deps = ["Distributions", "QuasiMonteCarlo", "Random"] +git-tree-sha1 = "722ad522068d31954b4a976b66a26aeccbf509ed" +uuid = "4886b29c-78c9-11e9-0a6e-41e1f4161f7b" +version = "0.2.0" + +[[deps.MonteCarloMeasurements]] +deps = ["Distributed", "Distributions", "ForwardDiff", "GenericSchur", "LinearAlgebra", "MacroTools", "Random", "RecipesBase", "Requires", "SLEEFPirates", "StaticArrays", "Statistics", "StatsBase", "Test"] +git-tree-sha1 = "19d4a73e20ca54f0f0e8a4ed349ee0dfd6e997b7" +uuid = "0987c9cc-fe09-11e8-30f0-b96dd679fdca" +version = "1.1.6" + +[[deps.MozillaCACerts_jll]] +uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +version = "2023.1.10" + +[[deps.MuladdMacro]] +git-tree-sha1 = "cac9cc5499c25554cba55cd3c30543cff5ca4fab" +uuid = "46d2c3a1-f734-5fdb-9937-b9b9aeba4221" +version = "0.2.4" + +[[deps.MultiDocumenter]] +deps = ["AbstractTrees", "Git", "Gumbo", "HypertextLiteral", "JSON", "NodeJS", "Pkg"] +git-tree-sha1 = "d6513c60e177cd7f31f3f023e0f997956bd45c31" +uuid = "87ed4bf0-c935-4a67-83c3-2a03bee4197c" +version = "0.7.0" + +[[deps.MultivariatePolynomials]] +deps = ["ChainRulesCore", "DataStructures", "LinearAlgebra", "MutableArithmetics"] +git-tree-sha1 = "dad7be0c92b688bf8f24af170825ccedc104b116" +uuid = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3" +version = "0.5.5" + +[[deps.MultivariateStats]] +deps = ["Arpack", "LinearAlgebra", "SparseArrays", "Statistics", "StatsAPI", "StatsBase"] +git-tree-sha1 = "68bf5103e002c44adfd71fea6bd770b3f0586843" +uuid = "6f286f6a-111f-5878-ab1e-185364afe411" +version = "0.10.2" + +[[deps.MutableArithmetics]] +deps = ["LinearAlgebra", "SparseArrays", "Test"] +git-tree-sha1 = "a3589efe0005fc4718775d8641b2de9060d23f73" +uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" +version = "1.4.4" + +[[deps.NLSolversBase]] +deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] +git-tree-sha1 = "a0b464d183da839699f4c79e7606d9d186ec172c" +uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" +version = "7.8.3" + +[[deps.NLopt]] +deps = ["NLopt_jll"] +git-tree-sha1 = "3b887e2ef56be3309e68d2546c6178e2d2fa9a60" +uuid = "76087f3c-5699-56af-9a33-bf431cd00edd" +version = "1.0.2" +weakdeps = ["MathOptInterface"] + + [deps.NLopt.extensions] + NLoptMathOptInterfaceExt = ["MathOptInterface"] + +[[deps.NLopt_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "9b1f15a08f9d00cdb2761dcfa6f453f5d0d6f973" +uuid = "079eb43e-fd8e-5478-9966-2cf3e3edb778" +version = "2.7.1+0" + +[[deps.NLsolve]] +deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] +git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" +uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" +version = "4.5.1" + +[[deps.NNlib]] +deps = ["Adapt", "Atomix", "ChainRulesCore", "GPUArraysCore", "KernelAbstractions", "LinearAlgebra", "Pkg", "Random", "Requires", "Statistics"] +git-tree-sha1 = "3d4617f943afe6410206a5294a95948c8d1b35bd" +uuid = "872c559c-99b0-510c-b3b7-b6c96a88d5cd" +version = "0.9.17" + + [deps.NNlib.extensions] + NNlibAMDGPUExt = "AMDGPU" + NNlibCUDACUDNNExt = ["CUDA", "cuDNN"] + NNlibCUDAExt = "CUDA" + NNlibEnzymeCoreExt = "EnzymeCore" + + [deps.NNlib.weakdeps] + AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" + CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" + EnzymeCore = "f151be2c-9106-41f4-ab19-57ee4f262869" + cuDNN = "02a925ec-e4fe-4b08-9a7e-0d78e3d38ccd" + +[[deps.NVTX]] +deps = ["Colors", "JuliaNVTXCallbacks_jll", "Libdl", "NVTX_jll"] +git-tree-sha1 = "53046f0483375e3ed78e49190f1154fa0a4083a1" +uuid = "5da4648a-3479-48b8-97b9-01cb529c0a1f" +version = "0.3.4" + +[[deps.NVTX_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ce3269ed42816bf18d500c9f63418d4b0d9f5a3b" +uuid = "e98f9f5b-d649-5603-91fd-7774390e6439" +version = "3.1.0+2" + +[[deps.NaNMath]] +deps = ["OpenLibm_jll"] +git-tree-sha1 = "0877504529a3e5c3343c6f8b4c0381e57e4387e4" +uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" +version = "1.0.2" + +[[deps.NameResolution]] +deps = ["PrettyPrint"] +git-tree-sha1 = "1a0fa0e9613f46c9b8c11eee38ebb4f590013c5e" +uuid = "71a1bf82-56d0-4bbc-8a3c-48b961074391" +version = "0.1.5" + +[[deps.NaturalSort]] +git-tree-sha1 = "eda490d06b9f7c00752ee81cfa451efe55521e21" +uuid = "c020b1a1-e9b0-503a-9c33-f039bfc54a85" +version = "1.0.0" + +[[deps.NearestNeighbors]] +deps = ["Distances", "StaticArrays"] +git-tree-sha1 = "ded64ff6d4fdd1cb68dfcbb818c69e144a5b2e4c" +uuid = "b8a86587-4115-5ab1-83bc-aa920d37bbce" +version = "0.4.16" + +[[deps.NetworkOptions]] +uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" +version = "1.2.0" + +[[deps.NeuralPDE]] +deps = ["Adapt", "AdvancedHMC", "ArrayInterface", "ChainRulesCore", "ComponentArrays", "Cubature", "DiffEqNoiseProcess", "Distributions", "DocStringExtensions", "DomainSets", "ForwardDiff", "Functors", "Integrals", "LinearAlgebra", "LogDensityProblems", "Lux", "MCMCChains", "ModelingToolkit", "MonteCarloMeasurements", "Optim", "Optimization", "OptimizationOptimisers", "QuasiMonteCarlo", "Random", "Reexport", "RuntimeGeneratedFunctions", "SciMLBase", "Statistics", "SymbolicUtils", "Symbolics", "UnPack", "Zygote"] +git-tree-sha1 = "dac06389c92a6d6040cf05f8822cc7668fb8a00c" +uuid = "315f7962-48a3-4962-8226-d0f33b1235f0" +version = "5.16.0" + +[[deps.NodeJS]] +deps = ["Pkg"] +git-tree-sha1 = "bf1f49fd62754064bc42490a8ddc2aa3694a8e7a" +uuid = "2bd173c7-0d6d-553b-b6af-13a54713934c" +version = "2.0.0" + +[[deps.NonlinearSolve]] +deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "FastBroadcast", "FastClosures", "FiniteDiff", "ForwardDiff", "LazyArrays", "LineSearches", "LinearAlgebra", "LinearSolve", "MaybeInplace", "PrecompileTools", "Preferences", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SimpleNonlinearSolve", "SparseArrays", "SparseDiffTools", "StaticArraysCore", "SymbolicIndexingInterface", "TimerOutputs"] +git-tree-sha1 = "dc0d78eeed89323526203b8a11a4fa6cdbe25cd6" +uuid = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" +version = "3.11.0" + + [deps.NonlinearSolve.extensions] + NonlinearSolveBandedMatricesExt = "BandedMatrices" + NonlinearSolveFastLevenbergMarquardtExt = "FastLevenbergMarquardt" + NonlinearSolveFixedPointAccelerationExt = "FixedPointAcceleration" + NonlinearSolveLeastSquaresOptimExt = "LeastSquaresOptim" + NonlinearSolveMINPACKExt = "MINPACK" + NonlinearSolveNLSolversExt = "NLSolvers" + NonlinearSolveNLsolveExt = "NLsolve" + NonlinearSolveSIAMFANLEquationsExt = "SIAMFANLEquations" + NonlinearSolveSpeedMappingExt = "SpeedMapping" + NonlinearSolveSymbolicsExt = "Symbolics" + NonlinearSolveZygoteExt = "Zygote" + + [deps.NonlinearSolve.weakdeps] + BandedMatrices = "aae01518-5342-5314-be14-df237901396f" + FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce" + FixedPointAcceleration = "817d07cb-a79a-5c30-9a31-890123675176" + LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891" + MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9" + NLSolvers = "337daf1e-9722-11e9-073e-8b9effe078ba" + NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" + SIAMFANLEquations = "084e46ad-d928-497d-ad5e-07fa361a48c4" + SpeedMapping = "f1835b91-879b-4a3f-a438-e4baacf14412" + Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.ObjectFile]] +deps = ["Reexport", "StructIO"] +git-tree-sha1 = "195e0a19842f678dd3473ceafbe9d82dfacc583c" +uuid = "d8793406-e978-5875-9003-1fc021f44a92" +version = "0.4.1" + +[[deps.Observables]] +git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225" +uuid = "510215fc-4207-5dde-b226-833fc4488ee2" +version = "0.5.5" + +[[deps.OffsetArrays]] +git-tree-sha1 = "e64b4f5ea6b7389f6f046d13d4896a8f9c1ba71e" +uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" +version = "1.14.0" +weakdeps = ["Adapt"] + + [deps.OffsetArrays.extensions] + OffsetArraysAdaptExt = "Adapt" + +[[deps.Ogg_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f" +uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" +version = "1.3.5+1" + +[[deps.OhMyThreads]] +deps = ["BangBang", "ChunkSplitters", "StableTasks", "TaskLocalValues"] +git-tree-sha1 = "4b43015960c9e1b660cfae4c1b19c7ed9c86b92c" +uuid = "67456a42-1dca-4109-a031-0a68de7e3ad5" +version = "0.5.2" + +[[deps.OneHotArrays]] +deps = ["Adapt", "ChainRulesCore", "Compat", "GPUArraysCore", "LinearAlgebra", "NNlib"] +git-tree-sha1 = "963a3f28a2e65bb87a68033ea4a616002406037d" +uuid = "0b1bfda6-eb8a-41d2-88d8-f5af5cad476f" +version = "0.2.5" + +[[deps.OpenBLAS_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] +uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" +version = "0.3.23+4" + +[[deps.OpenLibm_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "05823500-19ac-5b8b-9628-191a04bc5112" +version = "0.8.1+2" + +[[deps.OpenSSL]] +deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] +git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4" +uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" +version = "1.4.3" + +[[deps.OpenSSL_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "3da7367955dcc5c54c1ba4d402ccdc09a1a3e046" +uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" +version = "3.0.13+1" + +[[deps.OpenSpecFun_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" +uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" +version = "0.5.5+0" + +[[deps.Optim]] +deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] +git-tree-sha1 = "d9b79c4eed437421ac4285148fcadf42e0700e89" +uuid = "429524aa-4258-5aef-a3af-852621145aeb" +version = "1.9.4" +weakdeps = ["MathOptInterface"] + + [deps.Optim.extensions] + OptimMOIExt = "MathOptInterface" + +[[deps.Optimisers]] +deps = ["ChainRulesCore", "Functors", "LinearAlgebra", "Random", "Statistics"] +git-tree-sha1 = "6572fe0c5b74431aaeb0b18a4aa5ef03c84678be" +uuid = "3bd65402-5787-11e9-1adc-39752487f4e2" +version = "0.3.3" + +[[deps.Optimization]] +deps = ["ADTypes", "ArrayInterface", "ConsoleProgressMonitor", "DocStringExtensions", "LinearAlgebra", "Logging", "LoggingExtras", "OptimizationBase", "Pkg", "Printf", "ProgressLogging", "Reexport", "SciMLBase", "SparseArrays", "TerminalLoggers"] +git-tree-sha1 = "bc659730e7efff07c95218f24ed4c6f472054938" +uuid = "7f7a1694-90dd-40f0-9382-eb1efda571ba" +version = "3.24.3" + +[[deps.OptimizationBase]] +deps = ["ADTypes", "ArrayInterface", "DocStringExtensions", "LinearAlgebra", "Reexport", "Requires", "SciMLBase", "SparseArrays"] +git-tree-sha1 = "6266f3365980f0a6a39426316595bc1254df239c" +uuid = "bca83a33-5cc9-4baa-983d-23429ab6bcbb" +version = "0.0.5" +weakdeps = ["Enzyme", "FiniteDiff", "ForwardDiff", "ModelingToolkit", "ReverseDiff", "SparseDiffTools", "Symbolics", "Tracker", "Zygote"] + + [deps.OptimizationBase.extensions] + OptimizationEnzymeExt = "Enzyme" + OptimizationFiniteDiffExt = "FiniteDiff" + OptimizationForwardDiffExt = "ForwardDiff" + OptimizationMTKExt = "ModelingToolkit" + OptimizationReverseDiffExt = "ReverseDiff" + OptimizationSparseDiffExt = ["SparseDiffTools", "Symbolics", "ReverseDiff"] + OptimizationTrackerExt = "Tracker" + OptimizationZygoteExt = "Zygote" + +[[deps.OptimizationMOI]] +deps = ["MathOptInterface", "ModelingToolkit", "Optimization", "Reexport", "SciMLStructures", "SparseArrays", "SymbolicIndexingInterface", "Symbolics"] +git-tree-sha1 = "065ed47c8bb8012e8fefc0d723f4b8e1511ad768" +uuid = "fd9f6733-72f4-499f-8506-86b2bdd0dea1" +version = "0.4.2" + +[[deps.OptimizationNLopt]] +deps = ["NLopt", "Optimization", "Reexport"] +git-tree-sha1 = "745df99f24c30787886b7b941553e513ffeccc8e" +uuid = "4e6fcdb7-1186-4e1f-a706-475e75c168bb" +version = "0.2.0" + +[[deps.OptimizationOptimJL]] +deps = ["Optim", "Optimization", "Reexport", "SparseArrays"] +git-tree-sha1 = "d405cc3190e039da584da43c55ed4490d79a242f" +uuid = "36348300-93cb-4f02-beb5-3c3902f8871e" +version = "0.3.1" + +[[deps.OptimizationOptimisers]] +deps = ["Optimisers", "Optimization", "Printf", "ProgressLogging", "Reexport"] +git-tree-sha1 = "6c12ab297301d706b542d8876e55bfadfe773b00" +uuid = "42dfb2eb-d2b4-4451-abcd-913932933ac1" +version = "0.2.1" + +[[deps.OptimizationPolyalgorithms]] +deps = ["Optimization", "OptimizationOptimJL", "OptimizationOptimisers", "Reexport"] +git-tree-sha1 = "396fc0bfac20e32956b66a273bb97202766fdeb0" +uuid = "500b13db-7e66-49ce-bda4-eed966be6282" +version = "0.2.1" + +[[deps.Opus_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" +uuid = "91d4177d-7536-5919-b921-800302f37372" +version = "1.3.2+0" + +[[deps.OrderedCollections]] +git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.6.3" + +[[deps.OrdinaryDiffEq]] +deps = ["ADTypes", "Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DocStringExtensions", "EnumX", "ExponentialUtilities", "FastBroadcast", "FastClosures", "FillArrays", "FiniteDiff", "ForwardDiff", "FunctionWrappersWrappers", "IfElse", "InteractiveUtils", "LineSearches", "LinearAlgebra", "LinearSolve", "Logging", "MacroTools", "MuladdMacro", "NonlinearSolve", "Polyester", "PreallocationTools", "PrecompileTools", "Preferences", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SciMLStructures", "SimpleNonlinearSolve", "SimpleUnPack", "SparseArrays", "SparseDiffTools", "StaticArrayInterface", "StaticArrays", "TruncatedStacktraces"] +git-tree-sha1 = "a4af6d00e3f0682b21d734fccf934566f60be767" +uuid = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +version = "6.80.0" + +[[deps.PCRE2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15" +version = "10.42.0+1" + +[[deps.PDEBase]] +deps = ["DomainSets", "ModelingToolkit", "SciMLBase", "SymbolicUtils", "Symbolics"] +git-tree-sha1 = "9b2df8a3e0dfc8dec2edeb361dffd03ccf3fc63f" +uuid = "a7812802-0625-4b9e-961c-d332478797e5" +version = "0.1.10" + +[[deps.PDMats]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "949347156c25054de2db3b166c52ac4728cbad65" +uuid = "90014a1f-27ba-587c-ab20-58faa44d9150" +version = "0.11.31" + +[[deps.PackageExtensionCompat]] +git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518" +uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930" +version = "1.0.2" +weakdeps = ["Requires", "TOML"] + +[[deps.Parameters]] +deps = ["OrderedCollections", "UnPack"] +git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" +uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" +version = "0.12.3" + +[[deps.Parsers]] +deps = ["Dates", "PrecompileTools", "UUIDs"] +git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" +uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" +version = "2.8.1" + +[[deps.PartialFunctions]] +deps = ["MacroTools"] +git-tree-sha1 = "47b49a4dbc23b76682205c646252c0f9e1eb75af" +uuid = "570af359-4316-4cb7-8c74-252c00c2016b" +version = "1.2.0" + +[[deps.Pipe]] +git-tree-sha1 = "6842804e7867b115ca9de748a0cf6b364523c16d" +uuid = "b98c9c47-44ae-5843-9183-064241ee97a0" +version = "1.3.0" + +[[deps.Pixman_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "LLVMOpenMP_jll", "Libdl"] +git-tree-sha1 = "35621f10a7531bc8fa58f74610b1bfb70a3cfc6b" +uuid = "30392449-352a-5448-841d-b1acce4e97dc" +version = "0.43.4+0" + +[[deps.Pkg]] +deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] +uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +version = "1.10.0" + +[[deps.PlotThemes]] +deps = ["PlotUtils", "Statistics"] +git-tree-sha1 = "1f03a2d339f42dca4a4da149c7e15e9b896ad899" +uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" +version = "3.1.0" + +[[deps.PlotUtils]] +deps = ["ColorSchemes", "Colors", "Dates", "PrecompileTools", "Printf", "Random", "Reexport", "Statistics"] +git-tree-sha1 = "7b1a9df27f072ac4c9c7cbe5efb198489258d1f5" +uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" +version = "1.4.1" + +[[deps.Plots]] +deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "JLFzf", "JSON", "LaTeXStrings", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "Pkg", "PlotThemes", "PlotUtils", "PrecompileTools", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "RelocatableFolders", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "UnitfulLatexify", "Unzip"] +git-tree-sha1 = "442e1e7ac27dd5ff8825c3fa62fbd1e86397974b" +uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +version = "1.40.4" + + [deps.Plots.extensions] + FileIOExt = "FileIO" + GeometryBasicsExt = "GeometryBasics" + IJuliaExt = "IJulia" + ImageInTerminalExt = "ImageInTerminal" + UnitfulExt = "Unitful" + + [deps.Plots.weakdeps] + FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" + GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" + IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" + ImageInTerminal = "d8c32880-2388-543b-8c61-d9f865259254" + Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" + +[[deps.PoissonRandom]] +deps = ["Random"] +git-tree-sha1 = "a0f1159c33f846aa77c3f30ebbc69795e5327152" +uuid = "e409e4f3-bfea-5376-8464-e040bb5c01ab" +version = "0.4.4" + +[[deps.Polyester]] +deps = ["ArrayInterface", "BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "ManualMemory", "PolyesterWeave", "Requires", "Static", "StaticArrayInterface", "StrideArraysCore", "ThreadingUtilities"] +git-tree-sha1 = "b3e2bae88cf07baf0a051fe09666b8ef97aefe93" +uuid = "f517fe37-dbe3-4b94-8317-1923a5111588" +version = "0.7.14" + +[[deps.PolyesterWeave]] +deps = ["BitTwiddlingConvenienceFunctions", "CPUSummary", "IfElse", "Static", "ThreadingUtilities"] +git-tree-sha1 = "240d7170f5ffdb285f9427b92333c3463bf65bf6" +uuid = "1d0040c9-8b98-4ee7-8388-3f51789ca0ad" +version = "0.2.1" + +[[deps.PooledArrays]] +deps = ["DataAPI", "Future"] +git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" +uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" +version = "1.4.3" + +[[deps.PositiveFactorizations]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" +uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" +version = "0.2.4" + +[[deps.PreallocationTools]] +deps = ["Adapt", "ArrayInterface", "ForwardDiff"] +git-tree-sha1 = "a660e9daab5db07adf3dedfe09b435cc530d855e" +uuid = "d236fae5-4411-538c-8e31-a6e3d9e00b46" +version = "0.4.21" +weakdeps = ["ReverseDiff"] + + [deps.PreallocationTools.extensions] + PreallocationToolsReverseDiffExt = "ReverseDiff" + +[[deps.PrecompileTools]] +deps = ["Preferences"] +git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" +uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +version = "1.2.1" + +[[deps.Preferences]] +deps = ["TOML"] +git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" +uuid = "21216c6a-2e73-6563-6e65-726566657250" +version = "1.4.3" + +[[deps.PrettyPrint]] +git-tree-sha1 = "632eb4abab3449ab30c5e1afaa874f0b98b586e4" +uuid = "8162dcfd-2161-5ef2-ae6c-7681170c5f98" +version = "0.2.0" + +[[deps.PrettyTables]] +deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] +git-tree-sha1 = "88b895d13d53b5577fd53379d913b9ab9ac82660" +uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" +version = "2.3.1" + +[[deps.Primes]] +deps = ["IntegerMathUtils"] +git-tree-sha1 = "cb420f77dc474d23ee47ca8d14c90810cafe69e7" +uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae" +version = "0.5.6" + +[[deps.Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[deps.Profile]] +deps = ["Printf"] +uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" + +[[deps.ProgressLogging]] +deps = ["Logging", "SHA", "UUIDs"] +git-tree-sha1 = "80d919dee55b9c50e8d9e2da5eeafff3fe58b539" +uuid = "33c8b6b6-d38a-422a-b730-caa89a2f386c" +version = "0.1.4" + +[[deps.ProgressMeter]] +deps = ["Distributed", "Printf"] +git-tree-sha1 = "763a8ceb07833dd51bb9e3bbca372de32c0605ad" +uuid = "92933f4c-e287-5a05-a399-4b506db050ca" +version = "1.10.0" + +[[deps.PtrArrays]] +git-tree-sha1 = "f011fbb92c4d401059b2212c05c0601b70f8b759" +uuid = "43287f4e-b6f4-7ad1-bb20-aadabca52c3d" +version = "1.2.0" + +[[deps.Qt6Base_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Vulkan_Loader_jll", "Xorg_libSM_jll", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_cursor_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "libinput_jll", "xkbcommon_jll"] +git-tree-sha1 = "37b7bb7aabf9a085e0044307e1717436117f2b3b" +uuid = "c0090381-4147-56d7-9ebc-da0b1113ec56" +version = "6.5.3+1" + +[[deps.QuadGK]] +deps = ["DataStructures", "LinearAlgebra"] +git-tree-sha1 = "9b23c31e76e333e6fb4c1595ae6afa74966a729e" +uuid = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" +version = "2.9.4" + +[[deps.QuasiMonteCarlo]] +deps = ["Accessors", "ConcreteStructs", "LatticeRules", "LinearAlgebra", "Primes", "Random", "Requires", "Sobol", "StatsBase"] +git-tree-sha1 = "cc086f8485bce77b6187141e1413c3b55f9a4341" +uuid = "8a4e6c94-4038-4cdc-81c3-7e6ffdb2a71b" +version = "0.3.3" +weakdeps = ["Distributions"] + + [deps.QuasiMonteCarlo.extensions] + QuasiMonteCarloDistributionsExt = "Distributions" + +[[deps.REPL]] +deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] +uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" + +[[deps.Random]] +deps = ["SHA"] +uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" + +[[deps.Random123]] +deps = ["Random", "RandomNumbers"] +git-tree-sha1 = "4743b43e5a9c4a2ede372de7061eed81795b12e7" +uuid = "74087812-796a-5b5d-8853-05524746bad3" +version = "1.7.0" + +[[deps.RandomNumbers]] +deps = ["Random", "Requires"] +git-tree-sha1 = "043da614cc7e95c703498a491e2c21f58a2b8111" +uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143" +version = "1.5.3" + +[[deps.RangeArrays]] +git-tree-sha1 = "b9039e93773ddcfc828f12aadf7115b4b4d225f5" +uuid = "b3c3ace0-ae52-54e7-9d0b-2c1406fd6b9d" +version = "0.3.2" + +[[deps.Ratios]] +deps = ["Requires"] +git-tree-sha1 = "1342a47bf3260ee108163042310d26f2be5ec90b" +uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" +version = "0.4.5" +weakdeps = ["FixedPointNumbers"] + + [deps.Ratios.extensions] + RatiosFixedPointNumbersExt = "FixedPointNumbers" + +[[deps.RealDot]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "9f0a1b71baaf7650f4fa8a1d168c7fb6ee41f0c9" +uuid = "c1ae055f-0cd5-4b69-90a6-9a35b1a98df9" +version = "0.1.0" + +[[deps.RecipesBase]] +deps = ["PrecompileTools"] +git-tree-sha1 = "5c3d09cc4f31f5fc6af001c250bf1278733100ff" +uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" +version = "1.3.4" + +[[deps.RecipesPipeline]] +deps = ["Dates", "NaNMath", "PlotUtils", "PrecompileTools", "RecipesBase"] +git-tree-sha1 = "45cf9fd0ca5839d06ef333c8201714e888486342" +uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" +version = "0.6.12" + +[[deps.RecursiveArrayTools]] +deps = ["Adapt", "ArrayInterface", "DocStringExtensions", "GPUArraysCore", "IteratorInterfaceExtensions", "LinearAlgebra", "RecipesBase", "SparseArrays", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables"] +git-tree-sha1 = "758bc86b90e9fee2edc4af2a750b0d3f2d5c02c5" +uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" +version = "3.19.0" +weakdeps = ["FastBroadcast", "ForwardDiff", "Measurements", "MonteCarloMeasurements", "ReverseDiff", "Tracker", "Zygote"] + + [deps.RecursiveArrayTools.extensions] + RecursiveArrayToolsFastBroadcastExt = "FastBroadcast" + RecursiveArrayToolsForwardDiffExt = "ForwardDiff" + RecursiveArrayToolsMeasurementsExt = "Measurements" + RecursiveArrayToolsMonteCarloMeasurementsExt = "MonteCarloMeasurements" + RecursiveArrayToolsReverseDiffExt = ["ReverseDiff", "Zygote"] + RecursiveArrayToolsTrackerExt = "Tracker" + RecursiveArrayToolsZygoteExt = "Zygote" + +[[deps.RecursiveFactorization]] +deps = ["LinearAlgebra", "LoopVectorization", "Polyester", "PrecompileTools", "StrideArraysCore", "TriangularSolve"] +git-tree-sha1 = "6db1a75507051bc18bfa131fbc7c3f169cc4b2f6" +uuid = "f2c3362d-daeb-58d1-803e-2bc74f2840b4" +version = "0.2.23" + +[[deps.Reexport]] +git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" +uuid = "189a3867-3050-52da-a836-e630ba90ab69" +version = "1.2.2" + +[[deps.RegistryInstances]] +deps = ["LazilyInitializedFields", "Pkg", "TOML", "Tar"] +git-tree-sha1 = "ffd19052caf598b8653b99404058fce14828be51" +uuid = "2792f1a3-b283-48e8-9a74-f99dce5104f3" +version = "0.1.0" + +[[deps.RelocatableFolders]] +deps = ["SHA", "Scratch"] +git-tree-sha1 = "ffdaf70d81cf6ff22c2b6e733c900c3321cab864" +uuid = "05181044-ff0b-4ac5-8273-598c1e38db00" +version = "1.0.1" + +[[deps.Requires]] +deps = ["UUIDs"] +git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" +uuid = "ae029012-a4dd-5104-9daa-d747884805df" +version = "1.3.0" + +[[deps.ResettableStacks]] +deps = ["StaticArrays"] +git-tree-sha1 = "256eeeec186fa7f26f2801732774ccf277f05db9" +uuid = "ae5879a3-cd67-5da8-be7f-38c6eb64a37b" +version = "1.1.1" + +[[deps.ReverseDiff]] +deps = ["ChainRulesCore", "DiffResults", "DiffRules", "ForwardDiff", "FunctionWrappers", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NaNMath", "Random", "SpecialFunctions", "StaticArrays", "Statistics"] +git-tree-sha1 = "cc6cd622481ea366bb9067859446a8b01d92b468" +uuid = "37e2e3b7-166d-5795-8a7a-e32c996b4267" +version = "1.15.3" + +[[deps.Rmath]] +deps = ["Random", "Rmath_jll"] +git-tree-sha1 = "f65dcb5fa46aee0cf9ed6274ccbd597adc49aa7b" +uuid = "79098fc4-a85e-5d69-aa6a-4863f24498fa" +version = "0.7.1" + +[[deps.Rmath_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "d483cd324ce5cf5d61b77930f0bbd6cb61927d21" +uuid = "f50d1b31-88e8-58de-be2c-1cc44531875f" +version = "0.4.2+0" + +[[deps.RuntimeGeneratedFunctions]] +deps = ["ExprTools", "SHA", "Serialization"] +git-tree-sha1 = "04c968137612c4a5629fa531334bb81ad5680f00" +uuid = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" +version = "0.5.13" + +[[deps.SHA]] +uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" +version = "0.7.0" + +[[deps.SIMDTypes]] +git-tree-sha1 = "330289636fb8107c5f32088d2741e9fd7a061a5c" +uuid = "94e857df-77ce-4151-89e5-788b33177be4" +version = "0.1.0" + +[[deps.SLEEFPirates]] +deps = ["IfElse", "Static", "VectorizationBase"] +git-tree-sha1 = "3aac6d68c5e57449f5b9b865c9ba50ac2970c4cf" +uuid = "476501e8-09a2-5ece-8869-fb82de89a1fa" +version = "0.6.42" + +[[deps.SciMLBase]] +deps = ["ADTypes", "ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "PrecompileTools", "Preferences", "Printf", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "SciMLStructures", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables"] +git-tree-sha1 = "9f59654e2a85017ee27b0f59c7fac5a57aa10ced" +uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" +version = "2.39.0" + + [deps.SciMLBase.extensions] + SciMLBaseChainRulesCoreExt = "ChainRulesCore" + SciMLBaseMakieExt = "Makie" + SciMLBasePartialFunctionsExt = "PartialFunctions" + SciMLBasePyCallExt = "PyCall" + SciMLBasePythonCallExt = "PythonCall" + SciMLBaseRCallExt = "RCall" + SciMLBaseZygoteExt = "Zygote" + + [deps.SciMLBase.weakdeps] + ChainRules = "082447d4-558c-5d27-93f4-14fc19e9eca2" + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + Makie = "ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" + PartialFunctions = "570af359-4316-4cb7-8c74-252c00c2016b" + PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" + PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d" + RCall = "6f49c342-dc21-5d91-9882-a32aef131414" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.SciMLExpectations]] +deps = ["DiffEqBase", "DiffEqNoiseProcess", "Distributions", "Integrals", "KernelDensity", "LinearAlgebra", "Parameters", "Random", "RecursiveArrayTools", "Reexport", "SciMLBase", "StaticArrays", "Statistics", "Zygote"] +git-tree-sha1 = "6332835c431ed3da99dcc391e84e11a65fe31c50" +uuid = "afe9f18d-7609-4d0e-b7b7-af0cb72b8ea8" +version = "2.2.0" + +[[deps.SciMLOperators]] +deps = ["ArrayInterface", "DocStringExtensions", "LinearAlgebra", "MacroTools", "Setfield", "SparseArrays", "StaticArraysCore"] +git-tree-sha1 = "10499f619ef6e890f3f4a38914481cc868689cd5" +uuid = "c0aeaf25-5076-4817-a8d5-81caf7dfa961" +version = "0.3.8" + +[[deps.SciMLSensitivity]] +deps = ["ADTypes", "Adapt", "ArrayInterface", "ChainRulesCore", "DiffEqBase", "DiffEqCallbacks", "DiffEqNoiseProcess", "Distributions", "EllipsisNotation", "Enzyme", "FiniteDiff", "ForwardDiff", "FunctionProperties", "FunctionWrappersWrappers", "Functors", "GPUArraysCore", "LinearAlgebra", "LinearSolve", "Markdown", "OrdinaryDiffEq", "Parameters", "PreallocationTools", "QuadGK", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "ReverseDiff", "SciMLBase", "SciMLOperators", "SparseDiffTools", "StaticArrays", "StaticArraysCore", "Statistics", "StochasticDiffEq", "Tracker", "TruncatedStacktraces", "Zygote"] +git-tree-sha1 = "a7f777fff9cc15920e1e6c040c1e25b769760a8e" +uuid = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +version = "7.56.2" + +[[deps.SciMLStructures]] +git-tree-sha1 = "d778a74df2f64059c38453b34abad1953b2b8722" +uuid = "53ae85a6-f571-4167-b2af-e1d143709226" +version = "1.2.0" + +[[deps.ScientificTypesBase]] +git-tree-sha1 = "a8e18eb383b5ecf1b5e6fc237eb39255044fd92b" +uuid = "30f210dd-8aff-4c5f-94ba-8e64358c1161" +version = "3.0.0" + +[[deps.Scratch]] +deps = ["Dates"] +git-tree-sha1 = "3bac05bc7e74a75fd9cba4295cde4045d9fe2386" +uuid = "6c6a2e73-6563-6170-7368-637461726353" +version = "1.2.1" + +[[deps.SentinelArrays]] +deps = ["Dates", "Random"] +git-tree-sha1 = "90b4f68892337554d31cdcdbe19e48989f26c7e6" +uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" +version = "1.4.3" + +[[deps.Serialization]] +uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" + +[[deps.Setfield]] +deps = ["ConstructionBase", "Future", "MacroTools", "StaticArraysCore"] +git-tree-sha1 = "e2cc6d8c88613c05e1defb55170bf5ff211fbeac" +uuid = "efcf1570-3423-57d1-acb7-fd33fddbac46" +version = "1.1.1" + +[[deps.SharedArrays]] +deps = ["Distributed", "Mmap", "Random", "Serialization"] +uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" + +[[deps.ShowCases]] +git-tree-sha1 = "7f534ad62ab2bd48591bdeac81994ea8c445e4a5" +uuid = "605ecd9f-84a6-4c9e-81e2-4798472b76a3" +version = "0.1.0" + +[[deps.Showoff]] +deps = ["Dates", "Grisu"] +git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" +uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" +version = "1.0.3" + +[[deps.SimpleBufferStream]] +git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" +uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" +version = "1.1.0" + +[[deps.SimpleDiffEq]] +deps = ["DiffEqBase", "LinearAlgebra", "MuladdMacro", "Parameters", "RecursiveArrayTools", "Reexport", "StaticArrays"] +git-tree-sha1 = "afd610e15259e1c42e6b578d306a1c0cdf386533" +uuid = "05bca326-078c-5bf0-a5bf-ce7c7982d7fd" +version = "1.11.1" + +[[deps.SimpleNonlinearSolve]] +deps = ["ADTypes", "ArrayInterface", "ConcreteStructs", "DiffEqBase", "DiffResults", "FastClosures", "FiniteDiff", "ForwardDiff", "LinearAlgebra", "MaybeInplace", "PrecompileTools", "Reexport", "SciMLBase", "StaticArraysCore"] +git-tree-sha1 = "c020028bb22a2f23cbd88cb92cf47cbb8c98513f" +uuid = "727e6d20-b764-4bd8-a329-72de5adea6c7" +version = "1.8.0" + + [deps.SimpleNonlinearSolve.extensions] + SimpleNonlinearSolveChainRulesCoreExt = "ChainRulesCore" + SimpleNonlinearSolvePolyesterForwardDiffExt = "PolyesterForwardDiff" + SimpleNonlinearSolveReverseDiffExt = "ReverseDiff" + SimpleNonlinearSolveStaticArraysExt = "StaticArrays" + SimpleNonlinearSolveTrackerExt = "Tracker" + SimpleNonlinearSolveZygoteExt = "Zygote" + + [deps.SimpleNonlinearSolve.weakdeps] + ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" + PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b" + ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267" + StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" + Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.SimpleTraits]] +deps = ["InteractiveUtils", "MacroTools"] +git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231" +uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d" +version = "0.9.4" + +[[deps.SimpleUnPack]] +git-tree-sha1 = "58e6353e72cde29b90a69527e56df1b5c3d8c437" +uuid = "ce78b400-467f-4804-87d8-8f486da07d0a" +version = "1.1.0" + +[[deps.Sobol]] +deps = ["DelimitedFiles", "Random"] +git-tree-sha1 = "5a74ac22a9daef23705f010f72c81d6925b19df8" +uuid = "ed01d8cd-4d21-5b2a-85b4-cc3bdc58bad4" +version = "1.5.0" + +[[deps.Sockets]] +uuid = "6462fe0b-24de-5631-8697-dd941f90decc" + +[[deps.SortingAlgorithms]] +deps = ["DataStructures"] +git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" +uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" +version = "1.2.1" + +[[deps.SparseArrays]] +deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] +uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" +version = "1.10.0" + +[[deps.SparseDiffTools]] +deps = ["ADTypes", "Adapt", "ArrayInterface", "Compat", "DataStructures", "FiniteDiff", "ForwardDiff", "Graphs", "LinearAlgebra", "PackageExtensionCompat", "Random", "Reexport", "SciMLOperators", "Setfield", "SparseArrays", "StaticArrayInterface", "StaticArrays", "Tricks", "UnPack", "VertexSafeGraphs"] +git-tree-sha1 = "cce98ad7c896e52bb0eded174f02fc2a29c38477" +uuid = "47a9eef4-7e08-11e9-0b38-333d64bd3804" +version = "2.18.0" + + [deps.SparseDiffTools.extensions] + SparseDiffToolsEnzymeExt = "Enzyme" + SparseDiffToolsPolyesterExt = "Polyester" + SparseDiffToolsPolyesterForwardDiffExt = "PolyesterForwardDiff" + SparseDiffToolsSymbolicsExt = "Symbolics" + SparseDiffToolsZygoteExt = "Zygote" + + [deps.SparseDiffTools.weakdeps] + Enzyme = "7da242da-08ed-463a-9acd-ee780be4f1d9" + Polyester = "f517fe37-dbe3-4b94-8317-1923a5111588" + PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b" + Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7" + Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[[deps.SparseInverseSubset]] +deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"] +git-tree-sha1 = "52962839426b75b3021296f7df242e40ecfc0852" +uuid = "dc90abb0-5640-4711-901d-7e5b23a2fada" +version = "0.1.2" + +[[deps.Sparspak]] +deps = ["Libdl", "LinearAlgebra", "Logging", "OffsetArrays", "Printf", "SparseArrays", "Test"] +git-tree-sha1 = "342cf4b449c299d8d1ceaf00b7a49f4fbc7940e7" +uuid = "e56a9233-b9d6-4f03-8d0f-1825330902ac" +version = "0.3.9" + +[[deps.SpecialFunctions]] +deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] +git-tree-sha1 = "2f5d4697f21388cbe1ff299430dd169ef97d7e14" +uuid = "276daf66-3868-5448-9aa4-cd146d93841b" +version = "2.4.0" +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 = "83e6cce8324d49dfaf9ef059227f91ed4441a8e5" +uuid = "860ef19b-820b-49d6-a774-d7a799459cd3" +version = "1.0.2" + +[[deps.StableTasks]] +git-tree-sha1 = "073d5c20d44129b20fe954720b97069579fa403b" +uuid = "91464d47-22a1-43fe-8b7f-2d57ee82463f" +version = "0.1.5" + +[[deps.Static]] +deps = ["IfElse"] +git-tree-sha1 = "d2fdac9ff3906e27f7a618d47b676941baa6c80c" +uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" +version = "0.8.10" + +[[deps.StaticArrayInterface]] +deps = ["ArrayInterface", "Compat", "IfElse", "LinearAlgebra", "PrecompileTools", "Requires", "SparseArrays", "Static", "SuiteSparse"] +git-tree-sha1 = "5d66818a39bb04bf328e92bc933ec5b4ee88e436" +uuid = "0d7ed370-da01-4f52-bd93-41d350b8b718" +version = "1.5.0" +weakdeps = ["OffsetArrays", "StaticArrays"] + + [deps.StaticArrayInterface.extensions] + StaticArrayInterfaceOffsetArraysExt = "OffsetArrays" + StaticArrayInterfaceStaticArraysExt = "StaticArrays" + +[[deps.StaticArrays]] +deps = ["LinearAlgebra", "PrecompileTools", "Random", "StaticArraysCore"] +git-tree-sha1 = "9ae599cd7529cfce7fea36cf00a62cfc56f0f37c" +uuid = "90137ffa-7385-5640-81b9-e52037218182" +version = "1.9.4" +weakdeps = ["ChainRulesCore", "Statistics"] + + [deps.StaticArrays.extensions] + StaticArraysChainRulesCoreExt = "ChainRulesCore" + StaticArraysStatisticsExt = "Statistics" + +[[deps.StaticArraysCore]] +git-tree-sha1 = "36b3d696ce6366023a0ea192b4cd442268995a0d" +uuid = "1e83bf80-4336-4d27-bf5d-d5a4f845583c" +version = "1.4.2" + +[[deps.StatisticalTraits]] +deps = ["ScientificTypesBase"] +git-tree-sha1 = "30b9236691858e13f167ce829490a68e1a597782" +uuid = "64bff920-2084-43da-a3e6-9bb72801c0c9" +version = "3.2.0" + +[[deps.Statistics]] +deps = ["LinearAlgebra", "SparseArrays"] +uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +version = "1.10.0" + +[[deps.StatsAPI]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1ff449ad350c9c4cbc756624d6f8a8c3ef56d3ed" +uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" +version = "1.7.0" + +[[deps.StatsBase]] +deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] +git-tree-sha1 = "5cf7606d6cef84b543b483848d4ae08ad9832b21" +uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" +version = "0.34.3" + +[[deps.StatsFuns]] +deps = ["HypergeometricFunctions", "IrrationalConstants", "LogExpFunctions", "Reexport", "Rmath", "SpecialFunctions"] +git-tree-sha1 = "cef0472124fab0695b58ca35a77c6fb942fdab8a" +uuid = "4c63d2b9-4356-54db-8cca-17b64c39e42c" +version = "1.3.1" +weakdeps = ["ChainRulesCore", "InverseFunctions"] + + [deps.StatsFuns.extensions] + StatsFunsChainRulesCoreExt = "ChainRulesCore" + StatsFunsInverseFunctionsExt = "InverseFunctions" + +[[deps.StatsPlots]] +deps = ["AbstractFFTs", "Clustering", "DataStructures", "Distributions", "Interpolations", "KernelDensity", "LinearAlgebra", "MultivariateStats", "NaNMath", "Observables", "Plots", "RecipesBase", "RecipesPipeline", "Reexport", "StatsBase", "TableOperations", "Tables", "Widgets"] +git-tree-sha1 = "3b1dcbf62e469a67f6733ae493401e53d92ff543" +uuid = "f3b207a7-027a-5e70-b257-86293d7955fd" +version = "0.15.7" + +[[deps.SteadyStateDiffEq]] +deps = ["ConcreteStructs", "DiffEqBase", "DiffEqCallbacks", "LinearAlgebra", "Reexport", "SciMLBase"] +git-tree-sha1 = "1158cfdf0da5b0eacdfcfba7c16b174a37bdf6c7" +uuid = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f" +version = "2.2.0" + +[[deps.StochasticDiffEq]] +deps = ["Adapt", "ArrayInterface", "DataStructures", "DiffEqBase", "DiffEqNoiseProcess", "DocStringExtensions", "FiniteDiff", "ForwardDiff", "JumpProcesses", "LevyArea", "LinearAlgebra", "Logging", "MuladdMacro", "NLsolve", "OrdinaryDiffEq", "Random", "RandomNumbers", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SparseArrays", "SparseDiffTools", "StaticArrays", "UnPack"] +git-tree-sha1 = "97e5d0b7e5ec2e68eec6626af97c59e9f6b6c3d0" +uuid = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0" +version = "6.65.1" + +[[deps.StrideArraysCore]] +deps = ["ArrayInterface", "CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "ManualMemory", "SIMDTypes", "Static", "StaticArrayInterface", "ThreadingUtilities"] +git-tree-sha1 = "25349bf8f63aa36acbff5e3550a86e9f5b0ef682" +uuid = "7792a7ef-975c-4747-a70f-980b88e8d1da" +version = "0.5.6" + +[[deps.StringManipulation]] +deps = ["PrecompileTools"] +git-tree-sha1 = "a04cabe79c5f01f4d723cc6704070ada0b9d46d5" +uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" +version = "0.3.4" + +[[deps.StructArrays]] +deps = ["ConstructionBase", "DataAPI", "Tables"] +git-tree-sha1 = "f4dc295e983502292c4c3f951dbb4e985e35b3be" +uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" +version = "0.6.18" +weakdeps = ["Adapt", "GPUArraysCore", "SparseArrays", "StaticArrays"] + + [deps.StructArrays.extensions] + StructArraysAdaptExt = "Adapt" + StructArraysGPUArraysCoreExt = "GPUArraysCore" + StructArraysSparseArraysExt = "SparseArrays" + StructArraysStaticArraysExt = "StaticArrays" + +[[deps.StructIO]] +deps = ["Test"] +git-tree-sha1 = "010dc73c7146869c042b49adcdb6bf528c12e859" +uuid = "53d494c1-5632-5724-8f4c-31dff12d585f" +version = "0.3.0" + +[[deps.SuiteSparse]] +deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"] +uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" + +[[deps.SuiteSparse_jll]] +deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] +uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" +version = "7.2.1+1" + +[[deps.Sundials]] +deps = ["CEnum", "DataStructures", "DiffEqBase", "Libdl", "LinearAlgebra", "Logging", "PrecompileTools", "Reexport", "SciMLBase", "SparseArrays", "Sundials_jll"] +git-tree-sha1 = "e15f5a73f0d14b9079b807a9d1dac13e4302e997" +uuid = "c3572dad-4567-51f8-b174-8c6c989267f4" +version = "4.24.0" + +[[deps.Sundials_jll]] +deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "SuiteSparse_jll", "libblastrampoline_jll"] +git-tree-sha1 = "ba4d38faeb62de7ef47155ed321dce40a549c305" +uuid = "fb77eaff-e24c-56d4-86b1-d163f2edb164" +version = "5.2.2+0" + +[[deps.SymbolicIndexingInterface]] +deps = ["Accessors", "ArrayInterface", "RuntimeGeneratedFunctions", "StaticArraysCore"] +git-tree-sha1 = "b479c7a16803f08779ac5b7f9844a42621baeeda" +uuid = "2efcf032-c050-4f8e-a9bb-153293bab1f5" +version = "0.3.21" + +[[deps.SymbolicLimits]] +deps = ["SymbolicUtils"] +git-tree-sha1 = "89aa6b25a75418c8fffc42073b2e7dce69847394" +uuid = "19f23fe9-fdab-4a78-91af-e7b7767979c3" +version = "0.2.0" + +[[deps.SymbolicUtils]] +deps = ["AbstractTrees", "Bijections", "ChainRulesCore", "Combinatorics", "ConstructionBase", "DataStructures", "DocStringExtensions", "DynamicPolynomials", "IfElse", "LabelledArrays", "LinearAlgebra", "MultivariatePolynomials", "NaNMath", "Setfield", "SparseArrays", "SpecialFunctions", "StaticArrays", "SymbolicIndexingInterface", "TimerOutputs", "Unityper"] +git-tree-sha1 = "669e43e90df46fcee4aa859b587da7a7948272ac" +uuid = "d1185830-fcd6-423d-90d6-eec64667417b" +version = "1.5.1" + +[[deps.Symbolics]] +deps = ["ArrayInterface", "Bijections", "ConstructionBase", "DataStructures", "DiffRules", "Distributions", "DocStringExtensions", "DomainSets", "DynamicPolynomials", "ForwardDiff", "IfElse", "LaTeXStrings", "LambertW", "Latexify", "Libdl", "LinearAlgebra", "LogExpFunctions", "MacroTools", "Markdown", "NaNMath", "PrecompileTools", "RecipesBase", "Reexport", "Requires", "RuntimeGeneratedFunctions", "SciMLBase", "Setfield", "SparseArrays", "SpecialFunctions", "StaticArrays", "SymbolicIndexingInterface", "SymbolicLimits", "SymbolicUtils"] +git-tree-sha1 = "4104548fff14d7370b278ee767651d6ec61eb195" +uuid = "0c5d862f-8b57-4792-8d23-62f2024744c7" +version = "5.28.0" + + [deps.Symbolics.extensions] + SymbolicsGroebnerExt = "Groebner" + SymbolicsLuxCoreExt = "LuxCore" + SymbolicsPreallocationToolsExt = "PreallocationTools" + SymbolicsSymPyExt = "SymPy" + + [deps.Symbolics.weakdeps] + Groebner = "0b43b601-686d-58a3-8a1c-6623616c7cd4" + LuxCore = "bb33d45b-7691-41d6-9220-0943567d0623" + PreallocationTools = "d236fae5-4411-538c-8e31-a6e3d9e00b46" + SymPy = "24249f21-da20-56a4-8eb1-6a02cf4ae2e6" + +[[deps.TOML]] +deps = ["Dates"] +uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" + +[[deps.TableOperations]] +deps = ["SentinelArrays", "Tables", "Test"] +git-tree-sha1 = "e383c87cf2a1dc41fa30c093b2a19877c83e1bc1" +uuid = "ab02a1b2-a7df-11e8-156e-fb1833f50b87" +version = "1.2.0" + +[[deps.TableTraits]] +deps = ["IteratorInterfaceExtensions"] +git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" +uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" +version = "1.0.1" + +[[deps.Tables]] +deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"] +git-tree-sha1 = "cb76cf677714c095e535e3501ac7954732aeea2d" +uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" +version = "1.11.1" + +[[deps.Tar]] +deps = ["ArgTools", "SHA"] +uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" +version = "1.10.0" + +[[deps.TaskLocalValues]] +git-tree-sha1 = "eb0b8d147eb907a9ad3fd952da7c6a053b29ae28" +uuid = "ed4db957-447d-4319-bfb6-7fa9ae7ecf34" +version = "0.1.1" + +[[deps.TensorCore]] +deps = ["LinearAlgebra"] +git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" +uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" +version = "0.1.1" + +[[deps.TermInterface]] +git-tree-sha1 = "3939db0ce564b5fda6e9f9edcb4dabe0a1a0cc5f" +uuid = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" +version = "0.3.3" + +[[deps.TerminalLoggers]] +deps = ["LeftChildRightSiblingTrees", "Logging", "Markdown", "Printf", "ProgressLogging", "UUIDs"] +git-tree-sha1 = "f133fab380933d042f6796eda4e130272ba520ca" +uuid = "5d786b92-1e48-4d6f-9151-6b4477ca9bed" +version = "0.1.7" + +[[deps.Test]] +deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] +uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[[deps.TestItems]] +git-tree-sha1 = "8621ba2637b49748e2dc43ba3d84340be2938022" +uuid = "1c621080-faea-4a02-84b6-bbd5e436b8fe" +version = "0.1.1" + +[[deps.ThreadingUtilities]] +deps = ["ManualMemory"] +git-tree-sha1 = "eda08f7e9818eb53661b3deb74e3159460dfbc27" +uuid = "8290d209-cae3-49c0-8002-c8c24d57dab5" +version = "0.5.2" + +[[deps.TimerOutputs]] +deps = ["ExprTools", "Printf"] +git-tree-sha1 = "5a13ae8a41237cff5ecf34f73eb1b8f42fff6531" +uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" +version = "0.5.24" + +[[deps.Tokenize]] +git-tree-sha1 = "468b4685af4abe0e9fd4d7bf495a6554a6276e75" +uuid = "0796e94c-ce3b-5d07-9a54-7f471281c624" +version = "0.5.29" + +[[deps.Tracker]] +deps = ["Adapt", "ChainRulesCore", "DiffRules", "ForwardDiff", "Functors", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NNlib", "NaNMath", "Optimisers", "Printf", "Random", "Requires", "SpecialFunctions", "Statistics"] +git-tree-sha1 = "5158100ed55411867674576788e710a815a0af02" +uuid = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c" +version = "0.2.34" +weakdeps = ["PDMats"] + + [deps.Tracker.extensions] + TrackerPDMatsExt = "PDMats" + +[[deps.TranscodingStreams]] +git-tree-sha1 = "5d54d076465da49d6746c647022f3b3674e64156" +uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" +version = "0.10.8" +weakdeps = ["Random", "Test"] + + [deps.TranscodingStreams.extensions] + TestExt = ["Test", "Random"] + +[[deps.Transducers]] +deps = ["Adapt", "ArgCheck", "BangBang", "Baselet", "CompositionsBase", "ConstructionBase", "DefineSingletons", "Distributed", "InitialValues", "Logging", "Markdown", "MicroCollections", "Requires", "Setfield", "SplittablesBase", "Tables"] +git-tree-sha1 = "3064e780dbb8a9296ebb3af8f440f787bb5332af" +uuid = "28d57a85-8fef-5791-bfe6-a80928e7c999" +version = "0.4.80" + + [deps.Transducers.extensions] + TransducersBlockArraysExt = "BlockArrays" + TransducersDataFramesExt = "DataFrames" + TransducersLazyArraysExt = "LazyArrays" + TransducersOnlineStatsBaseExt = "OnlineStatsBase" + TransducersReferenceablesExt = "Referenceables" + + [deps.Transducers.weakdeps] + 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.TriangularSolve]] +deps = ["CloseOpenIntervals", "IfElse", "LayoutPointers", "LinearAlgebra", "LoopVectorization", "Polyester", "Static", "VectorizationBase"] +git-tree-sha1 = "66c68a20907800c0b7c04ff8a6164115e8747de2" +uuid = "d5829a12-d9aa-46ab-831f-fb7c9ab06edf" +version = "0.2.0" + +[[deps.Tricks]] +git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f" +uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" +version = "0.1.8" + +[[deps.TruncatedStacktraces]] +deps = ["InteractiveUtils", "MacroTools", "Preferences"] +git-tree-sha1 = "ea3e54c2bdde39062abf5a9758a23735558705e1" +uuid = "781d530d-4396-4725-bb49-402e4bee1e77" +version = "1.4.0" + +[[deps.URIs]] +git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" +uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" +version = "1.5.1" + +[[deps.UUIDs]] +deps = ["Random", "SHA"] +uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" + +[[deps.UnPack]] +git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" +uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" +version = "1.0.2" + +[[deps.Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" + +[[deps.UnicodeFun]] +deps = ["REPL"] +git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf" +uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1" +version = "0.4.1" + +[[deps.Unitful]] +deps = ["Dates", "LinearAlgebra", "Random"] +git-tree-sha1 = "dd260903fdabea27d9b6021689b3cd5401a57748" +uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" +version = "1.20.0" +weakdeps = ["ConstructionBase", "InverseFunctions"] + + [deps.Unitful.extensions] + ConstructionBaseUnitfulExt = "ConstructionBase" + InverseFunctionsUnitfulExt = "InverseFunctions" + +[[deps.UnitfulLatexify]] +deps = ["LaTeXStrings", "Latexify", "Unitful"] +git-tree-sha1 = "e2d817cc500e960fdbafcf988ac8436ba3208bfd" +uuid = "45397f5d-5981-4c77-b2b3-fc36d6e9b728" +version = "1.6.3" + +[[deps.Unityper]] +deps = ["ConstructionBase"] +git-tree-sha1 = "25008b734a03736c41e2a7dc314ecb95bd6bbdb0" +uuid = "a7c27f48-0311-42f6-a7f8-2c11e75eb415" +version = "0.1.6" + +[[deps.UnsafeAtomics]] +git-tree-sha1 = "6331ac3440856ea1988316b46045303bef658278" +uuid = "013be700-e6cd-48c3-b4a1-df204f14c38f" +version = "0.2.1" + +[[deps.UnsafeAtomicsLLVM]] +deps = ["LLVM", "UnsafeAtomics"] +git-tree-sha1 = "d9f5962fecd5ccece07db1ff006fb0b5271bdfdd" +uuid = "d80eeb9a-aca5-4d75-85e5-170c8b632249" +version = "0.1.4" + +[[deps.Unzip]] +git-tree-sha1 = "ca0969166a028236229f63514992fc073799bb78" +uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d" +version = "0.2.0" + +[[deps.VectorizationBase]] +deps = ["ArrayInterface", "CPUSummary", "HostCPUFeatures", "IfElse", "LayoutPointers", "Libdl", "LinearAlgebra", "SIMDTypes", "Static", "StaticArrayInterface"] +git-tree-sha1 = "6129a4faf6242e7c3581116fbe3270f3ab17c90d" +uuid = "3d5dd08c-fd9d-11e8-17fa-ed2836048c2f" +version = "0.21.67" + +[[deps.VertexSafeGraphs]] +deps = ["Graphs"] +git-tree-sha1 = "8351f8d73d7e880bfc042a8b6922684ebeafb35c" +uuid = "19fa3120-7c27-5ec5-8db8-b0b0aa330d6f" +version = "0.2.0" + +[[deps.Vulkan_Loader_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Wayland_jll", "Xorg_libX11_jll", "Xorg_libXrandr_jll", "xkbcommon_jll"] +git-tree-sha1 = "2f0486047a07670caad3a81a075d2e518acc5c59" +uuid = "a44049a8-05dd-5a78-86c9-5fde0876e88c" +version = "1.3.243+0" + +[[deps.Wayland_jll]] +deps = ["Artifacts", "EpollShim_jll", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] +git-tree-sha1 = "7558e29847e99bc3f04d6569e82d0f5c54460703" +uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" +version = "1.21.0+1" + +[[deps.Wayland_protocols_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "93f43ab61b16ddfb2fd3bb13b3ce241cafb0e6c9" +uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" +version = "1.31.0+0" + +[[deps.WeakRefStrings]] +deps = ["DataAPI", "InlineStrings", "Parsers"] +git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" +uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" +version = "1.4.2" + +[[deps.WeightInitializers]] +deps = ["ChainRulesCore", "LinearAlgebra", "PartialFunctions", "PrecompileTools", "Random", "SpecialFunctions", "Statistics"] +git-tree-sha1 = "f0e6760ef9d22f043710289ddf29e4a4048c4822" +uuid = "d49dbf32-c5c2-4618-8acc-27bb2598ef2d" +version = "0.1.7" +weakdeps = ["CUDA"] + + [deps.WeightInitializers.extensions] + WeightInitializersCUDAExt = "CUDA" + +[[deps.Widgets]] +deps = ["Colors", "Dates", "Observables", "OrderedCollections"] +git-tree-sha1 = "fcdae142c1cfc7d89de2d11e08721d0f2f86c98a" +uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62" +version = "0.6.6" + +[[deps.WoodburyMatrices]] +deps = ["LinearAlgebra", "SparseArrays"] +git-tree-sha1 = "5f24e158cf4cee437052371455fe361f526da062" +uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" +version = "0.5.6" + +[[deps.WorkerUtilities]] +git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7" +uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" +version = "1.6.1" + +[[deps.XML2_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] +git-tree-sha1 = "52ff2af32e591541550bd753c0da8b9bc92bb9d9" +uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" +version = "2.12.7+0" + +[[deps.XSLT_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] +git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" +uuid = "aed1982a-8fda-507f-9586-7b0439959a61" +version = "1.1.34+0" + +[[deps.XZ_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "ac88fb95ae6447c8dda6a5503f3bafd496ae8632" +uuid = "ffd25f8a-64ca-5728-b0f7-c24cf3aae800" +version = "5.4.6+0" + +[[deps.Xorg_libICE_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "326b4fea307b0b39892b3e85fa451692eda8d46c" +uuid = "f67eecfb-183a-506d-b269-f58e52b52d7c" +version = "1.1.1+0" + +[[deps.Xorg_libSM_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libICE_jll"] +git-tree-sha1 = "3796722887072218eabafb494a13c963209754ce" +uuid = "c834827a-8449-5923-a945-d239c165b7dd" +version = "1.2.4+0" + +[[deps.Xorg_libX11_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] +git-tree-sha1 = "afead5aba5aa507ad5a3bf01f58f82c8d1403495" +uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" +version = "1.8.6+0" + +[[deps.Xorg_libXau_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "6035850dcc70518ca32f012e46015b9beeda49d8" +uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" +version = "1.0.11+0" + +[[deps.Xorg_libXcursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" +uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" +version = "1.2.0+4" + +[[deps.Xorg_libXdmcp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "34d526d318358a859d7de23da945578e8e8727b7" +uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" +version = "1.1.4+0" + +[[deps.Xorg_libXext_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] +git-tree-sha1 = "d2d1a5c49fae4ba39983f63de6afcbea47194e85" +uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" +version = "1.3.6+0" + +[[deps.Xorg_libXfixes_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] +git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" +uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" +version = "5.0.3+4" + +[[deps.Xorg_libXi_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] +git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" +uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" +version = "1.7.10+4" + +[[deps.Xorg_libXinerama_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] +git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" +uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" +version = "1.1.4+4" + +[[deps.Xorg_libXrandr_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] +git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" +uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" +version = "1.5.2+4" + +[[deps.Xorg_libXrender_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] +git-tree-sha1 = "47e45cd78224c53109495b3e324df0c37bb61fbe" +uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" +version = "0.9.11+0" + +[[deps.Xorg_libpthread_stubs_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "8fdda4c692503d44d04a0603d9ac0982054635f9" +uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" +version = "0.1.1+0" + +[[deps.Xorg_libxcb_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] +git-tree-sha1 = "b4bfde5d5b652e22b9c790ad00af08b6d042b97d" +uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" +version = "1.15.0+0" + +[[deps.Xorg_libxkbfile_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libX11_jll"] +git-tree-sha1 = "730eeca102434283c50ccf7d1ecdadf521a765a4" +uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" +version = "1.1.2+0" + +[[deps.Xorg_xcb_util_cursor_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_jll", "Xorg_xcb_util_renderutil_jll"] +git-tree-sha1 = "04341cb870f29dcd5e39055f895c39d016e18ccd" +uuid = "e920d4aa-a673-5f3a-b3d7-f755a4d47c43" +version = "0.1.4+0" + +[[deps.Xorg_xcb_util_image_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" +uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] +git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" +uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_keysyms_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" +uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" +version = "0.4.0+1" + +[[deps.Xorg_xcb_util_renderutil_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" +uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" +version = "0.3.9+1" + +[[deps.Xorg_xcb_util_wm_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] +git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" +uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" +version = "0.4.1+1" + +[[deps.Xorg_xkbcomp_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_libxkbfile_jll"] +git-tree-sha1 = "330f955bc41bb8f5270a369c473fc4a5a4e4d3cb" +uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" +version = "1.4.6+0" + +[[deps.Xorg_xkeyboard_config_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Xorg_xkbcomp_jll"] +git-tree-sha1 = "691634e5453ad362044e2ad653e79f3ee3bb98c3" +uuid = "33bec58e-1273-512f-9401-5d533626f822" +version = "2.39.0+0" + +[[deps.Xorg_xtrans_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e92a1a012a10506618f10b7047e478403a046c77" +uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" +version = "1.5.0+0" + +[[deps.Zlib_jll]] +deps = ["Libdl"] +uuid = "83775a58-1f1d-513f-b197-d71354ab007a" +version = "1.2.13+1" + +[[deps.Zstd_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "e678132f07ddb5bfa46857f0d7620fb9be675d3b" +uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" +version = "1.5.6+0" + +[[deps.Zygote]] +deps = ["AbstractFFTs", "ChainRules", "ChainRulesCore", "DiffRules", "Distributed", "FillArrays", "ForwardDiff", "GPUArrays", "GPUArraysCore", "IRTools", "InteractiveUtils", "LinearAlgebra", "LogExpFunctions", "MacroTools", "NaNMath", "PrecompileTools", "Random", "Requires", "SparseArrays", "SpecialFunctions", "Statistics", "ZygoteRules"] +git-tree-sha1 = "19c586905e78a26f7e4e97f81716057bd6b1bc54" +uuid = "e88e6eb3-aa80-5325-afca-941959d7151f" +version = "0.6.70" +weakdeps = ["Colors", "Distances", "Tracker"] + + [deps.Zygote.extensions] + ZygoteColorsExt = "Colors" + ZygoteDistancesExt = "Distances" + ZygoteTrackerExt = "Tracker" + +[[deps.ZygoteRules]] +deps = ["ChainRulesCore", "MacroTools"] +git-tree-sha1 = "27798139afc0a2afa7b1824c206d5e87ea587a00" +uuid = "700de1a5-db45-46bc-99cf-38207098b444" +version = "0.2.5" + +[[deps.cuDNN]] +deps = ["CEnum", "CUDA", "CUDA_Runtime_Discovery", "CUDNN_jll"] +git-tree-sha1 = "1f6a185a8da9bbbc20134b7b935981f70c9b26ad" +uuid = "02a925ec-e4fe-4b08-9a7e-0d78e3d38ccd" +version = "1.3.1" + +[[deps.eudev_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "gperf_jll"] +git-tree-sha1 = "431b678a28ebb559d224c0b6b6d01afce87c51ba" +uuid = "35ca27e7-8b34-5b7f-bca9-bdc33f59eb06" +version = "3.2.9+0" + +[[deps.fzf_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "a68c9655fbe6dfcab3d972808f1aafec151ce3f8" +uuid = "214eeab7-80f7-51ab-84ad-2988db7cef09" +version = "0.43.0+0" + +[[deps.gperf_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "3516a5630f741c9eecb3720b1ec9d8edc3ecc033" +uuid = "1a1c6b14-54f6-533d-8383-74cd7377aa70" +version = "3.1.1+0" + +[[deps.libaom_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "1827acba325fdcdf1d2647fc8d5301dd9ba43a9d" +uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" +version = "3.9.0+0" + +[[deps.libass_jll]] +deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] +git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47" +uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" +version = "0.15.1+0" + +[[deps.libblastrampoline_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" +version = "5.8.0+1" + +[[deps.libevdev_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "141fe65dc3efabb0b1d5ba74e91f6ad26f84cc22" +uuid = "2db6ffa8-e38f-5e21-84af-90c45d0032cc" +version = "1.11.0+0" + +[[deps.libfdk_aac_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55" +uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" +version = "2.0.2+0" + +[[deps.libinput_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "eudev_jll", "libevdev_jll", "mtdev_jll"] +git-tree-sha1 = "ad50e5b90f222cfe78aa3d5183a20a12de1322ce" +uuid = "36db933b-70db-51c0-b978-0f229ee0e533" +version = "1.18.0+0" + +[[deps.libpng_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Zlib_jll"] +git-tree-sha1 = "d7015d2e18a5fd9a4f47de711837e980519781a4" +uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" +version = "1.6.43+1" + +[[deps.libvorbis_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] +git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c" +uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" +version = "1.3.7+1" + +[[deps.mtdev_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "814e154bdb7be91d78b6802843f76b6ece642f11" +uuid = "009596ad-96f7-51b1-9f1b-5ce2d5e8a71e" +version = "1.1.6+0" + +[[deps.nghttp2_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" +version = "1.52.0+1" + +[[deps.oneTBB_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "7d0ea0f4895ef2f5cb83645fa689e52cb55cf493" +uuid = "1317d2d5-d96f-522e-a858-c73665f53c3e" +version = "2021.12.0+0" + +[[deps.p7zip_jll]] +deps = ["Artifacts", "Libdl"] +uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "17.4.0+2" + +[[deps.x264_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2" +uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" +version = "2021.5.5+0" + +[[deps.x265_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] +git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9" +uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" +version = "3.5.0+0" + +[[deps.xkbcommon_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] +git-tree-sha1 = "9c304562909ab2bab0262639bd4f444d7bc2be37" +uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" +version = "1.4.1+1" diff --git a/v1.5.0/assets/Project.toml b/v1.5.0/assets/Project.toml new file mode 100644 index 00000000000..044a380b599 --- /dev/null +++ b/v1.5.0/assets/Project.toml @@ -0,0 +1,96 @@ +[deps] +AdvancedHMC = "0bf59076-c3b1-5ca4-86bd-e02cd72cde3d" +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" +CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +ComponentArrays = "b0b7db55-cfe3-40fc-9ded-d10e2dbeff66" +DataDrivenDiffEq = "2445eb08-9709-466a-b3fc-47e12bd697a2" +DataDrivenSparse = "5b588203-7d8b-4fab-a537-c31a7f73f46b" +DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +DiffEqGPU = "071ae1c0-96b5-11e9-1965-c90190d839ea" +DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" +Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf" +Flux = "587475ba-b771-5e3f-ad9e-33799f191a9c" +ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" +IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895" +Integrals = "de52edbc-65ea-441a-8357-d3a637375a31" +LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433" +LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" +LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae" +Lux = "b2108857-7c20-44ae-9111-449ecde12c47" +LuxCUDA = "d0bbae9a-e099-4d5b-a835-1c6931763bda" +MCMCChains = "c7f686f2-ff18-58e9-bc7b-31028e88f75d" +Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7" +MethodOfLines = "94925ecb-adb7-4558-8ed8-f975c56a0bf4" +ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" +MultiDocumenter = "87ed4bf0-c935-4a67-83c3-2a03bee4197c" +NeuralPDE = "315f7962-48a3-4962-8226-d0f33b1235f0" +NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec" +Optimization = "7f7a1694-90dd-40f0-9382-eb1efda571ba" +OptimizationMOI = "fd9f6733-72f4-499f-8506-86b2bdd0dea1" +OptimizationNLopt = "4e6fcdb7-1186-4e1f-a706-475e75c168bb" +OptimizationOptimJL = "36348300-93cb-4f02-beb5-3c3902f8871e" +OptimizationOptimisers = "42dfb2eb-d2b4-4451-abcd-913932933ac1" +OptimizationPolyalgorithms = "500b13db-7e66-49ce-bda4-eed966be6282" +OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" +SciMLExpectations = "afe9f18d-7609-4d0e-b7b7-af0cb72b8ea8" +SciMLSensitivity = "1ed8b502-d754-442c-8d5d-10ac956f44a1" +StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3" +StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +StatsPlots = "f3b207a7-027a-5e70-b257-86293d7955fd" +Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" +Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" + +[compat] +AdvancedHMC = "0.6" +BenchmarkTools = "1" +CSV = "0.10" +CUDA = "5" +ComponentArrays = "0.15" +DataDrivenDiffEq = "1.4" +DataDrivenSparse = "0.1" +DataFrames = "1" +DiffEqGPU = "3" +DifferentialEquations = "7" +Distributions = "0.25" +Documenter = "1" +DomainSets = "0.6, 0.7" +Flux = "0.13, 0.14" +ForwardDiff = "0.10" +IncompleteLU = "0.2" +Integrals = "4" +LineSearches = "7" +LinearSolve = "2" +Lux = "0.5" +LuxCUDA = "0.3" +MCMCChains = "6" +Measurements = "2" +MethodOfLines = "0.11" +ModelingToolkit = "9.9" +MultiDocumenter = "0.7" +NeuralPDE = "5.15" +NonlinearSolve = "3" +Optimization = "3" +OptimizationMOI = "0.4" +OptimizationNLopt = "0.2" +OptimizationOptimJL = "0.2, 0.3" +OptimizationOptimisers = "0.2" +OptimizationPolyalgorithms = "0.2" +OrdinaryDiffEq = "6" +Plots = "1" +SciMLExpectations = "2" +SciMLSensitivity = "7" +StableRNGs = "1" +StaticArrays = "1" +Statistics = "1" +StatsPlots = "0.15" +Unitful = "1" +Zygote = "0.6" diff --git a/v1.5.0/assets/documenter.js b/v1.5.0/assets/documenter.js new file mode 100644 index 00000000000..75719b2a965 --- /dev/null +++ b/v1.5.0/assets/documenter.js @@ -0,0 +1,1057 @@ +// Generated by Documenter.jl +requirejs.config({ + paths: { + 'highlight-julia': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/julia.min', + 'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/headroom.min', + 'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min', + 'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.min', + 'headroom-jquery': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.12.0/jQuery.headroom.min', + 'highlight': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min', + 'highlight-julia-repl': 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/languages/julia-repl.min', + }, + shim: { + "highlight-julia": { + "deps": [ + "highlight" + ] + }, + "headroom-jquery": { + "deps": [ + "jquery", + "headroom" + ] + }, + "highlight-julia-repl": { + "deps": [ + "highlight" + ] + } +} +}); +//////////////////////////////////////////////////////////////////////////////// +require([], function() { +window.MathJax = { + "tex": { + "packages": [ + "base", + "ams", + "autoload", + "mathtools", + "require" + ], + "inlineMath": [ + [ + "$", + "$" + ], + [ + "\\(", + "\\)" + ] + ] + }, + "loader": { + "load": [ + "[tex]/require", + "[tex]/mathtools" + ] + }, + "options": { + "ignoreHtmlClass": "tex2jax_ignore", + "processHtmlClass": "tex2jax_process" + } +} +; + +(function () { + var script = document.createElement('script'); + script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-svg.js'; + script.async = true; + document.head.appendChild(script); +})(); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'highlight', 'highlight-julia', 'highlight-julia-repl'], function($) { +$(document).ready(function() { + hljs.highlightAll(); +}) + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +let timer = 0; +var isExpanded = true; + +$(document).on("click", ".docstring header", function () { + let articleToggleTitle = "Expand docstring"; + + debounce(() => { + if ($(this).siblings("section").is(":visible")) { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + } else { + $(this) + .find(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + articleToggleTitle = "Collapse docstring"; + } + + $(this) + .find(".docstring-article-toggle-button") + .prop("title", articleToggleTitle); + $(this).siblings("section").slideToggle(); + }); +}); + +$(document).on("click", ".docs-article-toggle-button", function (event) { + let articleToggleTitle = "Expand docstring"; + let navArticleToggleTitle = "Expand all docstrings"; + let animationSpeed = event.noToggleAnimation ? 0 : 400; + + debounce(() => { + if (isExpanded) { + $(this).removeClass("fa-chevron-up").addClass("fa-chevron-down"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-down") + .addClass("fa-chevron-right"); + + isExpanded = false; + + $(".docstring section").slideUp(animationSpeed); + } else { + $(this).removeClass("fa-chevron-down").addClass("fa-chevron-up"); + $(".docstring-article-toggle-button") + .removeClass("fa-chevron-right") + .addClass("fa-chevron-down"); + + isExpanded = true; + articleToggleTitle = "Collapse docstring"; + navArticleToggleTitle = "Collapse all docstrings"; + + $(".docstring section").slideDown(animationSpeed); + } + + $(this).prop("title", navArticleToggleTitle); + $(".docstring-article-toggle-button").prop("title", articleToggleTitle); + }); +}); + +function debounce(callback, timeout = 300) { + if (Date.now() - timer > timeout) { + callback(); + } + + clearTimeout(timer); + + timer = Date.now(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require([], function() { +function addCopyButtonCallbacks() { + for (const el of document.getElementsByTagName("pre")) { + const button = document.createElement("button"); + button.classList.add("copy-button", "fa-solid", "fa-copy"); + button.setAttribute("aria-label", "Copy this code block"); + button.setAttribute("title", "Copy"); + + el.appendChild(button); + + const success = function () { + button.classList.add("success", "fa-check"); + button.classList.remove("fa-copy"); + }; + + const failure = function () { + button.classList.add("error", "fa-xmark"); + button.classList.remove("fa-copy"); + }; + + button.addEventListener("click", function () { + copyToClipboard(el.innerText).then(success, failure); + + setTimeout(function () { + button.classList.add("fa-copy"); + button.classList.remove("success", "fa-check", "fa-xmark"); + }, 5000); + }); + } +} + +function copyToClipboard(text) { + // clipboard API is only available in secure contexts + if (window.navigator && window.navigator.clipboard) { + return window.navigator.clipboard.writeText(text); + } else { + return new Promise(function (resolve, reject) { + try { + const el = document.createElement("textarea"); + el.textContent = text; + el.style.position = "fixed"; + el.style.opacity = 0; + document.body.appendChild(el); + el.select(); + document.execCommand("copy"); + + resolve(); + } catch (err) { + reject(err); + } finally { + document.body.removeChild(el); + } + }); + } +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", addCopyButtonCallbacks); +} else { + addCopyButtonCallbacks(); +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery', 'headroom', 'headroom-jquery'], function($, Headroom) { + +// Manages the top navigation bar (hides it when the user starts scrolling down on the +// mobile). +window.Headroom = Headroom; // work around buggy module loading? +$(document).ready(function () { + $("#documenter .docs-navbar").headroom({ + tolerance: { up: 10, down: 10 }, + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +$(document).ready(function () { + let meta = $("div[data-docstringscollapsed]").data(); + + if (meta?.docstringscollapsed) { + $("#documenter-article-toggle-button").trigger({ + type: "click", + noToggleAnimation: true, + }); + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +/* +To get an in-depth about the thought process you can refer: https://hetarth02.hashnode.dev/series/gsoc + +PSEUDOCODE: + +Searching happens automatically as the user types or adjusts the selected filters. +To preserve responsiveness, as much as possible of the slow parts of the search are done +in a web worker. Searching and result generation are done in the worker, and filtering and +DOM updates are done in the main thread. The filters are in the main thread as they should +be very quick to apply. This lets filters be changed without re-searching with minisearch +(which is possible even if filtering is on the worker thread) and also lets filters be +changed _while_ the worker is searching and without message passing (neither of which are +possible if filtering is on the worker thread) + +SEARCH WORKER: + +Import minisearch + +Build index + +On message from main thread + run search + find the first 200 unique results from each category, and compute their divs for display + note that this is necessary and sufficient information for the main thread to find the + first 200 unique results from any given filter set + post results to main thread + +MAIN: + +Launch worker + +Declare nonconstant globals (worker_is_running, last_search_text, unfiltered_results) + +On text update + if worker is not running, launch_search() + +launch_search + set worker_is_running to true, set last_search_text to the search text + post the search query to worker + +on message from worker + if last_search_text is not the same as the text in the search field, + the latest search result is not reflective of the latest search query, so update again + launch_search() + otherwise + set worker_is_running to false + + regardless, display the new search results to the user + save the unfiltered_results as a global + update_search() + +on filter click + adjust the filter selection + update_search() + +update_search + apply search filters by looping through the unfiltered_results and finding the first 200 + unique results that match the filters + + Update the DOM +*/ + +/////// SEARCH WORKER /////// + +function worker_function(documenterSearchIndex, documenterBaseURL, filters) { + importScripts( + "https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js" + ); + + let data = documenterSearchIndex.map((x, key) => { + x["id"] = key; // minisearch requires a unique for each object + return x; + }); + + // list below is the lunr 2.1.3 list minus the intersect with names(Base) + // (all, any, get, in, is, only, which) and (do, else, for, let, where, while, with) + // ideally we'd just filter the original list but it's not available as a variable + const stopWords = new Set([ + "a", + "able", + "about", + "across", + "after", + "almost", + "also", + "am", + "among", + "an", + "and", + "are", + "as", + "at", + "be", + "because", + "been", + "but", + "by", + "can", + "cannot", + "could", + "dear", + "did", + "does", + "either", + "ever", + "every", + "from", + "got", + "had", + "has", + "have", + "he", + "her", + "hers", + "him", + "his", + "how", + "however", + "i", + "if", + "into", + "it", + "its", + "just", + "least", + "like", + "likely", + "may", + "me", + "might", + "most", + "must", + "my", + "neither", + "no", + "nor", + "not", + "of", + "off", + "often", + "on", + "or", + "other", + "our", + "own", + "rather", + "said", + "say", + "says", + "she", + "should", + "since", + "so", + "some", + "than", + "that", + "the", + "their", + "them", + "then", + "there", + "these", + "they", + "this", + "tis", + "to", + "too", + "twas", + "us", + "wants", + "was", + "we", + "were", + "what", + "when", + "who", + "whom", + "why", + "will", + "would", + "yet", + "you", + "your", + ]); + + let index = new MiniSearch({ + fields: ["title", "text"], // fields to index for full-text search + storeFields: ["location", "title", "text", "category", "page"], // fields to return with results + processTerm: (term) => { + let word = stopWords.has(term) ? null : term; + if (word) { + // custom trimmer that doesn't strip @ and !, which are used in julia macro and function names + word = word + .replace(/^[^a-zA-Z0-9@!]+/, "") + .replace(/[^a-zA-Z0-9@!]+$/, ""); + + word = word.toLowerCase(); + } + + return word ?? null; + }, + // add . as a separator, because otherwise "title": "Documenter.Anchors.add!", would not + // find anything if searching for "add!", only for the entire qualification + tokenize: (string) => string.split(/[\s\-\.]+/), + // options which will be applied during the search + searchOptions: { + prefix: true, + boost: { title: 100 }, + fuzzy: 2, + }, + }); + + index.addAll(data); + + /** + * Used to map characters to HTML entities. + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + const htmlEscapes = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + }; + + /** + * Used to match HTML entities and HTML characters. + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + const reUnescapedHtml = /[&<>"']/g; + const reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** + * Escape function from lodash + * Refer: https://github.com/lodash/lodash/blob/main/src/escape.ts + */ + function escape(string) { + return string && reHasUnescapedHtml.test(string) + ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr]) + : string || ""; + } + + /** + * Make the result component given a minisearch result data object and the value + * of the search input as queryString. To view the result object structure, refer: + * https://lucaong.github.io/minisearch/modules/_minisearch_.html#searchresult + * + * @param {object} result + * @param {string} querystring + * @returns string + */ + function make_search_result(result, querystring) { + let search_divider = `
`; + let display_link = + result.location.slice(Math.max(0), Math.min(50, result.location.length)) + + (result.location.length > 30 ? "..." : ""); // To cut-off the link because it messes with the overflow of the whole div + + if (result.page !== "") { + display_link += ` (${result.page})`; + } + + let textindex = new RegExp(`${querystring}`, "i").exec(result.text); + let text = + textindex !== null + ? result.text.slice( + Math.max(textindex.index - 100, 0), + Math.min( + textindex.index + querystring.length + 100, + result.text.length + ) + ) + : ""; // cut-off text before and after from the match + + text = text.length ? escape(text) : ""; + + let display_result = text.length + ? "..." + + text.replace( + new RegExp(`${escape(querystring)}`, "i"), // For first occurrence + '$&' + ) + + "..." + : ""; // highlights the match + + let in_code = false; + if (!["page", "section"].includes(result.category.toLowerCase())) { + in_code = true; + } + + // We encode the full url to escape some special characters which can lead to broken links + let result_div = ` + +
+
${escape(result.title)}
+
${result.category}
+
+

+ ${display_result} +

+
+ ${display_link} +
+
+ ${search_divider} + `; + + return result_div; + } + + self.onmessage = function (e) { + let query = e.data; + let results = index.search(query, { + filter: (result) => { + // Only return relevant results + return result.score >= 1; + }, + }); + + // Pre-filter to deduplicate and limit to 200 per category to the extent + // possible without knowing what the filters are. + let filtered_results = []; + let counts = {}; + for (let filter of filters) { + counts[filter] = 0; + } + let present = {}; + + for (let result of results) { + cat = result.category; + cnt = counts[cat]; + if (cnt < 200) { + id = cat + "---" + result.location; + if (present[id]) { + continue; + } + present[id] = true; + filtered_results.push({ + location: result.location, + category: cat, + div: make_search_result(result, query), + }); + } + } + + postMessage(filtered_results); + }; +} + +// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript! +const filters = [ + ...new Set(documenterSearchIndex["docs"].map((x) => x.category)), +]; +const worker_str = + "(" + + worker_function.toString() + + ")(" + + JSON.stringify(documenterSearchIndex["docs"]) + + "," + + JSON.stringify(documenterBaseURL) + + "," + + JSON.stringify(filters) + + ")"; +const worker_blob = new Blob([worker_str], { type: "text/javascript" }); +const worker = new Worker(URL.createObjectURL(worker_blob)); + +/////// SEARCH MAIN /////// + +// Whether the worker is currently handling a search. This is a boolean +// as the worker only ever handles 1 or 0 searches at a time. +var worker_is_running = false; + +// The last search text that was sent to the worker. This is used to determine +// if the worker should be launched again when it reports back results. +var last_search_text = ""; + +// The results of the last search. This, in combination with the state of the filters +// in the DOM, is used compute the results to display on calls to update_search. +var unfiltered_results = []; + +// Which filter is currently selected +var selected_filter = ""; + +$(document).on("input", ".documenter-search-input", function (event) { + if (!worker_is_running) { + launch_search(); + } +}); + +function launch_search() { + worker_is_running = true; + last_search_text = $(".documenter-search-input").val(); + worker.postMessage(last_search_text); +} + +worker.onmessage = function (e) { + if (last_search_text !== $(".documenter-search-input").val()) { + launch_search(); + } else { + worker_is_running = false; + } + + unfiltered_results = e.data; + update_search(); +}; + +$(document).on("click", ".search-filter", function () { + if ($(this).hasClass("search-filter-selected")) { + selected_filter = ""; + } else { + selected_filter = $(this).text().toLowerCase(); + } + + // This updates search results and toggles classes for UI: + update_search(); +}); + +/** + * Make/Update the search component + */ +function update_search() { + let querystring = $(".documenter-search-input").val(); + + if (querystring.trim()) { + if (selected_filter == "") { + results = unfiltered_results; + } else { + results = unfiltered_results.filter((result) => { + return selected_filter == result.category.toLowerCase(); + }); + } + + let search_result_container = ``; + let modal_filters = make_modal_body_filters(); + let search_divider = `
`; + + if (results.length) { + let links = []; + let count = 0; + let search_results = ""; + + for (var i = 0, n = results.length; i < n && count < 200; ++i) { + let result = results[i]; + if (result.location && !links.includes(result.location)) { + search_results += result.div; + count++; + links.push(result.location); + } + } + + if (count == 1) { + count_str = "1 result"; + } else if (count == 200) { + count_str = "200+ results"; + } else { + count_str = count + " results"; + } + let result_count = `
${count_str}
`; + + search_result_container = ` +
+ ${modal_filters} + ${search_divider} + ${result_count} +
+ ${search_results} +
+
+ `; + } else { + search_result_container = ` +
+ ${modal_filters} + ${search_divider} +
0 result(s)
+
+
No result found!
+ `; + } + + if ($(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").removeClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(search_result_container); + } else { + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".search-modal-card-body").html(` +
Type something to get started!
+ `); + } +} + +/** + * Make the modal filter html + * + * @returns string + */ +function make_modal_body_filters() { + let str = filters + .map((val) => { + if (selected_filter == val.toLowerCase()) { + return `${val}`; + } else { + return `${val}`; + } + }) + .join(""); + + return ` +
+ Filters: + ${str} +
`; +} + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Modal settings dialog +$(document).ready(function () { + var settings = $("#documenter-settings"); + $("#documenter-settings-button").click(function () { + settings.toggleClass("is-active"); + }); + // Close the dialog if X is clicked + $("#documenter-settings button.delete").click(function () { + settings.removeClass("is-active"); + }); + // Close dialog if ESC is pressed + $(document).keyup(function (e) { + if (e.keyCode == 27) settings.removeClass("is-active"); + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +$(document).ready(function () { + let search_modal_header = ` + + `; + + let initial_search_body = ` +
Type something to get started!
+ `; + + let search_modal_footer = ` + + `; + + $(document.body).append( + ` + + ` + ); + + document.querySelector(".docs-search-query").addEventListener("click", () => { + openModal(); + }); + + document + .querySelector(".close-search-modal") + .addEventListener("click", () => { + closeModal(); + }); + + $(document).on("click", ".search-result-link", function () { + closeModal(); + }); + + document.addEventListener("keydown", (event) => { + if ((event.ctrlKey || event.metaKey) && event.key === "/") { + openModal(); + } else if (event.key === "Escape") { + closeModal(); + } + + return false; + }); + + // Functions to open and close a modal + function openModal() { + let searchModal = document.querySelector("#search-modal"); + + searchModal.classList.add("is-active"); + document.querySelector(".documenter-search-input").focus(); + } + + function closeModal() { + let searchModal = document.querySelector("#search-modal"); + let initial_search_body = ` +
Type something to get started!
+ `; + + searchModal.classList.remove("is-active"); + document.querySelector(".documenter-search-input").blur(); + + if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) { + $(".search-modal-card-body").addClass("is-justify-content-center"); + } + + $(".documenter-search-input").val(""); + $(".search-modal-card-body").html(initial_search_body); + } + + document + .querySelector("#search-modal .modal-background") + .addEventListener("click", () => { + closeModal(); + }); +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Manages the showing and hiding of the sidebar. +$(document).ready(function () { + var sidebar = $("#documenter > .docs-sidebar"); + var sidebar_button = $("#documenter-sidebar-button"); + sidebar_button.click(function (ev) { + ev.preventDefault(); + sidebar.toggleClass("visible"); + if (sidebar.hasClass("visible")) { + // Makes sure that the current menu item is visible in the sidebar. + $("#documenter .docs-menu a.is-active").focus(); + } + }); + $("#documenter > .docs-main").bind("click", function (ev) { + if ($(ev.target).is(sidebar_button)) { + return; + } + if (sidebar.hasClass("visible")) { + sidebar.removeClass("visible"); + } + }); +}); + +// Resizes the package name / sitename in the sidebar if it is too wide. +// Inspired by: https://github.com/davatron5000/FitText.js +$(document).ready(function () { + e = $("#documenter .docs-autofit"); + function resize() { + var L = parseInt(e.css("max-width"), 10); + var L0 = e.width(); + if (L0 > L) { + var h0 = parseInt(e.css("font-size"), 10); + e.css("font-size", (L * h0) / L0); + // TODO: make sure it survives resizes? + } + } + // call once and then register events + resize(); + $(window).resize(resize); + $(window).on("orientationchange", resize); +}); + +// Scroll the navigation bar to the currently selected menu item +$(document).ready(function () { + var sidebar = $("#documenter .docs-menu").get(0); + var active = $("#documenter .docs-menu .is-active").get(0); + if (typeof active !== "undefined") { + sidebar.scrollTop = active.offsetTop - sidebar.offsetTop - 15; + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// Theme picker setup +$(document).ready(function () { + // onchange callback + $("#documenter-themepicker").change(function themepick_callback(ev) { + var themename = $("#documenter-themepicker option:selected").attr("value"); + if (themename === "auto") { + // set_theme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + window.localStorage.removeItem("documenter-theme"); + } else { + // set_theme(themename); + window.localStorage.setItem("documenter-theme", themename); + } + // We re-use the global function from themeswap.js to actually do the swapping. + set_theme_from_local_storage(); + }); + + // Make sure that the themepicker displays the correct theme when the theme is retrieved + // from localStorage + if (typeof window.localStorage !== "undefined") { + var theme = window.localStorage.getItem("documenter-theme"); + if (theme !== null) { + $("#documenter-themepicker option").each(function (i, e) { + e.selected = e.value === theme; + }); + } + } +}); + +}) +//////////////////////////////////////////////////////////////////////////////// +require(['jquery'], function($) { + +// update the version selector with info from the siteinfo.js and ../versions.js files +$(document).ready(function () { + // If the version selector is disabled with DOCUMENTER_VERSION_SELECTOR_DISABLED in the + // siteinfo.js file, we just return immediately and not display the version selector. + if ( + typeof DOCUMENTER_VERSION_SELECTOR_DISABLED === "boolean" && + DOCUMENTER_VERSION_SELECTOR_DISABLED + ) { + return; + } + + var version_selector = $("#documenter .docs-version-selector"); + var version_selector_select = $("#documenter .docs-version-selector select"); + + version_selector_select.change(function (x) { + target_href = version_selector_select + .children("option:selected") + .get(0).value; + window.location.href = target_href; + }); + + // add the current version to the selector based on siteinfo.js, but only if the selector is empty + if ( + typeof DOCUMENTER_CURRENT_VERSION !== "undefined" && + $("#version-selector > option").length == 0 + ) { + var option = $( + "" + ); + version_selector_select.append(option); + } + + if (typeof DOC_VERSIONS !== "undefined") { + var existing_versions = version_selector_select.children("option"); + var existing_versions_texts = existing_versions.map(function (i, x) { + return x.text; + }); + DOC_VERSIONS.forEach(function (each) { + var version_url = documenterBaseURL + "/../" + each + "/"; + var existing_id = $.inArray(each, existing_versions_texts); + // if not already in the version selector, add it as a new option, + // otherwise update the old option with the URL and enable it + if (existing_id == -1) { + var option = $( + "" + ); + version_selector_select.append(option); + } else { + var option = existing_versions[existing_id]; + option.value = version_url; + option.disabled = false; + } + }); + } + + // only show the version selector if the selector has been populated + if (version_selector_select.children("option").length > 0) { + version_selector.toggleClass("visible"); + } +}); + +}) diff --git a/v1.5.0/assets/favicon.ico b/v1.5.0/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3c6bd470373d2cccea2154d70907b0e02ab202c8 GIT binary patch literal 1394 zcmV-&1&#WNP))4@f zESiZxsDh$SK?orzI4h7)!K_)tSt22l`~sH^AU4hd#4^dEVwrY<#7l}16euf4MM5oA zGelH`G_7yy*q(SiW6qh(1ShdOcHJW#kLRKLefQk&oO>=u2C%E=UZQZxflq;Jo}-n( z%iv2d{`gCIkTJOdz!7)>97z~|jM=0q5(D35D!i7ia-C%6`X$2k368*daJKw>ll^?E zO-B?;1x|3^?^reB)au6T*CcZ8x=1~eNMe3y0suY>mtsBCHaJ0jD-0r8u3Dx-b+raANS7iZ{06M)(0d0EyR%Ub;A zS!;YWoa$TINCG0IWAq-H0L;Dsj(;(fT2zV*l3fG|k0{AJL}7Md0+@1QG^*M4Is+kL zTCqmUB!gNea-4)kr3fUlgGOLVh^VA(+a>S*!<*Y{Z0-KKtMtQur*YR!Ma+aw!!(_U zkK=W@mmb6}v)6b<$#J|J{#E?B^4=;Il_U(JZ#VCE8_2JUXF@_K3(G}O2e@o*cEmCi z$S=eD$v^^FYNbSiIJ>4_)%MLJ5@;CmduC+{$mEZ!kGY}*O=RKu1sLN(&=O1`fnf|l zO5oE?yE(C5{d*pk4+x}D4+S8R>q!8@uZyvm&I#~%Zwa&^i5TE>ppVJxm75HU80cXE zNNBwxus?f2k%uPG84C}`)ua4U|52hZQD-IkL1xb>8H8yLoY~t zA(B*jeq*;B=%^bwAp;4NtMWxN zZ%I!uXh4FZ5R?&^awxu@A3z--*HgdwW&Q`wV_uP4jGVrEk;cczh`SkeF)U0ke7C~& zn0XNtpT}J9Wv!-7HaG9E%g@c@5-=#w6F$=1u1M)$(N{@*eVsrfI!L)CufrAMQI`%$FO@90ysb)o z46b>vu%qB=6_adP|FV_SOJql>xThwV{rr)Wkxv5E37eBa>o=HcZThWQ2^&;YIo1Ub zSsqf2VvX+<90EG1@<#)l8+t_EMzw~*qTVq> zW?K#dF)uPM==&FQEzE*5vB%pFZFm=*0!tSmGvOw7HU`z^%o+_7?2l$Cn#xp2^maG=s& zxNiNlXisOiBt+KvSs{<(DDq^bV?O-NIA;cH=)9lcgk2OBm(zn3*3SwR2`cGd?KXr1 zUxep=sy97J&h+}r$tuE01O|WnZ`JX5=7Z5-!s1mG>O<-G{f!I7q%LKT=H~D4ayP{O zwNNey+_aJ9kG17Fdr5OSbvoL!ig&Z<^7~l%#;D_nwC&38i+p6vx+^T?bIekhd)L|) z8mCR>_hP_mgI6tnPBx`cI4g};iLZYr zdj;PP)p$Sdr!9&SzG{D%;Tu5ehuT|Ff?#0p#_;k0HT>M?FXzkw3shB@ zk!>l&x%}q7+MTH-yOip6yLe0v$jdN72+_!t6qx1zptG${M(XzC7qFHRbmty1<5yXo zuuv=oDIS;#BJI=c3_9O|Y?MTZ(qpxU(*G?>4|e=Sp0zXnNW}hdsr}<~hTD;LvMtok z8>c_oR|dLaA{r&d<7V_QH zSnA(f1$MbMUG=)tbgAt_|HQ_UpF*wVKYTYcWNN>Em-O0S--Y`iyC8+@pLsGialu)G z-zG^6PevS8D`&fImc34GJ{_sx5W-j&PNN^(EaNXv?ju?;N#OrYNl@II@^MBcK{`f(`SXT%APoqu$_!m|1Yv@?#WJm9dzZyw5@$bH<)ecm9{QjU zX-aLpPvw5sh$uVX1Oi$Dh_uPklU#-`lrmHltr?Woa7-bmAV{q>c-2vBO;v2&Z-|Is z!bcNL{B*H;3g+LTvUcr0FMk{c)l+*Ub&wN?fQ2dkzK>s8{Z(31lY?EpymHQrAJTCB zd)E3DXVi&Wgk94wwjXl4k$aDi)M1^4ib2Y+d*t#uzSwzzy7NtIlg^!zFmL9AJU~Xm zZ15Jz>mfeZii}$aN{X2cGH!U^>AjgZIccK905)&@Q}%i&jLBI(mmzMKEKbeK`GHjX z0Nh<#io^WObeYHx@ebdj%#2THi7qP@9}}?lDh1jkuQ`#h ze7?<>hXa(>qv3XkRSU|E@@)lOdlt$LboGsNQfgeOB-s7rR3Z7>ksRB{dPA*nm&QNi zC0rlG-JWwdFF-G3?aRalHFNd#ZyLw?4u-je_;fzr1^E!H`-z`5_2&x%60zxON98v> zlQ5=HbRct1NYB9tqk9{STl(JSE{3~Doi#zQA1SM(3T!#$G;%Ed zEG$DnBUZ$KMY`MPmb4gc2gp_Bbr?{j<)jWiePIrVp-wUi3tg%+6Zj!-kOEKs77~#V zRy@E?@O^L17lymtP7EsM=2YAIWYSNI{-rjA>rg>KAO!OP5v%Fx{rtM`u!Z!Qs;v|Z z%!(k_mVEC_DmsNjA`xINlGJ#MDx<+U&z8w&0t3$vvr&0Fo}8O%nfXA@tH%*&TC_UBpH zLg^a?N9K`k*f*goch6<@oXYdFDn66mb6Nj096u#|fF?RrNxiqeHdcJ8E(#N{>Kqd> zIKSu$QJjrwI2m3Reo=~m6it?q?m|2tdhwvLzQf)UHwTD?{h2K4x#n~6KqhKj z>*bXXdKMDH+CuW*A40+72Q@P^iCyn2c*~n(gC?o;H&1hU_LkyXn{Z~kJXdGHs7C5n zjN*T3bEE{m?JIv{1^6amg`FQ%rFyxmoWhn^`OG*B=q|ZSG(GcO6Cq>Vx zn8w_B>Ba7}MY*8}cL7mtTk{btc|NU~bL|YLZrKlLY~U&X3hi$4mJAME{dhOjp0@Gy z>k1S0GF{ugoKl(-nGcdimC+MBltTZS$Cdl26M79!d@cHRl4ypx{=j??5xCz&uU)Yo z)vb6?asR!f=Yjl~2DdX{2Ms5F<9CeTx__FORM2B{@f-j83JN2G=|eqLB83vS#*<5?d!#vLVSzRdoEBmdLw*24)bIrPId&q9iQ3b=7ykwk8+ z+-wp`3w3<>NL^{H3tSIHszVvE~>mUuIuXN~6!$wQ}b1O9$3S__3S+61^9X8z@K)bMtcT4bJ}S zPwA`p)Z6y4DyEy|AiP4-&SthDQv$z2F4}hukM}8%o8t{4nz-cY;+|n90_&LsrZ;jt zWok=Vr@IY2;#eFXFt%&r5?1X84J<<@SsLB=RBV(FMJ^cF-mSYQ`mO;ctU)(HBlsS{_A4kyUQb6|6;4O(fA8W`1Hu)8^2KPc0x|-ToD}_}`#7e{?=uI|Dw#;gC0}|~pExX0v(131Zp_V|aLqEh zTkSWrqe|VyMH~?Zz5CIOP3*(!V}NBhm4-UTJx1H{YaH!Mv@r|L-Aglx-f68-L~gJt zay<^z>nSh_|H%Z8wTUBXW3U+?DmN&wQ!YZk z{j^}RKR`FobU|2}#RuUI%mrr)i3*HcL&W$X!P zkR3nO1GszB+_Wc^>oe{0o~6M9x5mGOy`wbc2i!`phqCO;gV#~Q^zFHbi}lZPHa`|l zKUJr%O^;&iWquEKoL)*)+yhdL1%>NDte@T5KM6 ztfNxpcn(@Se^-g%zKP$eOm;}SQk4S2D=s(%C<`PTmsXuLgGANThiDQ)s@a5Ggj}Ed zRQCG$pVF-KyRMy1$xoRH(o0txASbwPfq%}jJrX||%)DK7(Rcqvu&|`tE6V#CeNxOw zQX>f>(eVPdJ)=V01=3jXxFWSqEPXByyb0dJYIvp8r@NF?j zq05cu^cLP3?5HT^@~IUWASt(f(O>z1VF>OD7yqL8?%SHuRml*;l%n8!iv!|tQzZq)K zHg1fHRW=w}TYeY!tGmI}3_ZIxXO_NiDhfXwkv!C)7oQ;|btueBS^f>d&=n2oRQzdC zxf*G_Ahs@idZkRtOsC=v!soZ)r$0jgwKzX?{j+4n*3QuCWFnczfZgW1xpGYQJuVeV zRX8O-VM^%A6z)kkSD5ntYSKz;aHH)-4cOs~>^RuH9ZmCAo`T-ftKzWQv5jhJh?kh` z7-#Fhdx@s1Y#&EN3LBnq?`4?j;2GV(8au^L{)RQp3)1lWT^vTSHLe(Ri>2GWd_AXbyUjr(N{mxJ%uDX&nrsl5LLE7UJ?rrRW+G=^m@&3p~n$=$4m)MdsMQQ zms7&w!p@ytLRyi=hPArNq>o?8f*3@q9=bXoKdN>68ZI2Sx;kR$0KMuqa2=K#+8t7) ze}_+Ab5~{M`iQ(im7fEG?2brbm6E5jA;k>yO<_bk!1$=?R&N^*TcwK~JodZ0V+Eg# zS7bQ;lSb<<8fi<4Hzzl0-kyopLz^`5=Qf*MZ6MISVdA4?JR5Jf4;MT70V)1suZMba z(5+$CH*)+OM)OMu4NT?@eYmJx#wKy_QUu>N*`U4#Ka-@}-_I##f!~5sSi3*Pk9#ZO z%N){IOUK)A_P;d)lSx#%?3;X^VTg+^mRJ7&WQB!+MUjnK&JHX?-qkB4)QX zxqb;&T+K0EpUKYQ1rCv6QyE=cp-Y|1LQ{eTVsm`*#fX3aMJJIdUihCic0%Bgu#vl* ze;Z$ao@~2nR6Y2_XeQEeH=#%v5~zPLJM(hSJi+PNoh@rvKG$9iB?sqiRt#p}jv6*o zW%|Sz1a*Zie)*Y5YG+HkgdBrv(c4&gJyz78imi}R2e|S%cekSDBe+I}xaZ_T!ckg? zq7yZC+tV@E!D&vwsyKs)F#I+Rm^2<2PMrr2n~kIkb8bg7HBY6Pt+d!TtyYrMrKuOg zHVvk*BkykwEkZ85@*h4g*)g(B_;KIIUrjOl0V#aM&=|&+iI|rE(uD`YK>ba{8}OoA zovK`R=90^mGAD&0I6$1Ssld7(l;8~Z`aShBfi3XM2E}lPK_d^dg#Sq)Woi@;cO^3H zP@{s)#}aYe!ER|$=0m!O_i^x~4{4&ZcKV;B-VbCnqYKSd1qxI?r=1zW(2<;HxFK9N zvp6yw5;Vd&*6u;9^Efhw{|prej4*AQ727_@xnX!>)A_v4oq1c32jL}yFETUyJ~~7a zmhgIN$CC|U{6`K7OTq(_Ll5dwP?y!KRWpQ9tv}E;Vx{@qxqfM?w+GTCFGKu=X6e2> z-vwfT&yq?^!u19xGB(8Zk|#|3<8s{N-2*MZY-&!8Kb=vZqU-3y;6}6LWGByN2V<6>vB zWFAMKlTEXdF>B8h{R8cwVor}9sUTo-JRB)y{SdsUm?L%4Uv)mj!`@F$0OjwY|8CXl z5k*~r*c)N6%;1}U6+4ciCnT}8lH%vExHH>i#uhHVf{)YsITW`NV*6)LXy0IOM9$tw zm@zQ{C(@{=4Nm5>lgb9rK91{7?p%%^Tr| z8%-Xn1Im$XO^X-JZ$LQWRw()>&s4%hk6zu5{0=#~{NA-#=T73pX~!lrpc=_0Tp#j; z>V%%f=Ffut9VJd=DT_yx?v4`4(P?h0=nfgR^d0o%c!X46`pGhI!(rZtYRM5J`Y82$ z3BC7yQ_a}JXK;r2KOJw?(CcMJT6LPj(Pr~DRz(y+G;>b&&VAj8SxpY##$yXb%2bjc z)J#NmlrCg2#Heb9v)3N+KP=D)FU|E4Z{m-4^{X}NDh!q@HVfA)trQg2q^1V=)f4_1 zkJG~s?k$c1F4k&?_j5O}btDaHQL29rC?>wt^o}&jR{k>`t;f#HGnCPNozIoALvb>Q zrVbHs6xc%=8q{y69LGv^Vj9|%e3u*7i_dX~ig-}mhO>SKz*OI`T$OGpJEii!(UJY+70eIMHdaKJ=b1uQA-Os8-?BTJFvc=9@{`Z z{AV_Ggjd5|?%+zakFVk1hGc^kh*Q_+6#Xw~9e>qOx`SI!I(Oc2+CG+X*(nxxKaBeA!4f zWm2{-eA`hPvo=g{os5+HTW`^fsf0M9<{7tQJt`XCeRsl%BcY zb;u`cx*VnJ4bRu(;6F{X^|M}o z@fAV0n_oCp@_r~)R(>G4;mZ`HUJ|%`*jByR6A_d#D=KyjWBVW4h8|ITYLm+uS&z6A zgq?O^F_3>gk{@y^B$L*5$jpb`0Z#2=SQuNRVw~&eTYXu&MV1^`x4i=$R^Dv~Ikp@B zz4ZFgg-H`l1BT__iQ61e%X0O4dh1Nx!T#5W6`UVR^$Fo}jfTh(--xCQ)RBj_9n+v5 zM0(=Bq6?7R4KfFuO94AhX5>9HXm2~jUAsQdF!A#QiO6NdoCry}%~%Y8m3!?O#R)`q z4@dqysX`H1X@0NY8I!wOOs2T-v|q%#zSt8qB7)`jc?-}Od>eUjFWE0hJ~~hpZiZ06 z9r1xcZB{orUFvxDWozntQBE1P$O-&@b~4vc_x3%kzl`Sru&W%HJfbDvbOyX}9YRNLx4Lhh5j9?mme;@VP{2EL+3RJb9@i(FSqa z00H@?Z^WGk=vsJJn4t)^nev|xmgD3uuaf6yCr@XXt@O9OKb%tBpB*v1ai>YXo~-e< z!&g!m09>)l51Jt#6KM42+rV>L65mDnqQWvGh=;F?MtObu$0j|y8FSyS@Zw4qv%iB|CWj{+k28S-*>!##bcoWfOjpk-9UUmpz%`L58-^dei{r z9+-ZB-Qm=>Ex771G=Q)5UudFADdSky8mBi@H?$m`B{Kqza6O_TmY}CL`rmQg1!tZ( zT3CmMtikswhubb{hId+0K#Bn+Rc3n`d5%h1zpfwzP_9o45@h{O^{%5GBNxG&zC`x$ zZ|=L=hFQ^-*w!7)w7=xl%5OpREcgT#WBxgN^nLXIOjshK%=xBnfRZEC#feq+RJr9VmzG z?O^dsy#W2Mny3*?ac~bjL%tPzsqV(p1X)&b!p45%dvtBt;kI%&%nY6aut+O|? zghKH)7LhdkT;idh!B5%Ebt5haqF0?BZGnG3-FDOG$BS!qt$aqaTeyq@;v{=+TpW#~_Wdh|k52Sma3pvgZqSN7Cxg z9h}ZKve1ia_x+~F{hykxvg*n`CU9O`<=;~$7Ry?s-MWX}l`Q`e;>CUMTL%WK`di$1 zlU$i8c32vk96Htay8D#-$A}^un#dR&qPTqew6gJw-P^C=lqP_g&>>Ub{akX zD}67k2x)%kx4!AO4Q?*b&zg|881o*>}%Sq=rVvS z1C3~Ih$EGKy^b;uyDIPk+hS%nXhXea2(fZk&A&>2ER7*ZnL>qS5hk7!*d?{1>>b6i ztcCEA?yQl}!RepqJ;FNlAm2>s`s*>mnx`}P5HfT$=kI*VQ24I+>KHr$kP0 z@zv9h5W!4R274p_^!O}meH?4>h1e|Y9)Uutscc^U(8ioKDF$#L(pmjtT5uvOYh1Ja zEqiTE{9sO!t>x%AW4=G2i5x4#F@F2Lr%H4JqrGbFhbJC0eqJBN@x)1KQTRe9){)roSraC*+E#`H^Cl9tQemHLeJr2A6-Syn}* zzi076uMC(PB=Zhzwr#`fPE)_Ec}Y4+il_az$w<0?VGRj(edx;k3A?auy&J{2yKrjinazj42 zYZKfo#?z!{{zHhHO+()k8GgS8`JZ|?{Api3E;KRCZ>ulce`C2QRb288s>q5oc!^;= zNax3XU%r_}UbZMbyj$00_cr~k)3R`dwvxNod~jC3;e~Yxu6b>&D|(DQPQva|owN{M z1Xdq7ymC1y7P&xq?X*8RSn~suoxB<)>;Jq;Gk_2fTiLj-Z7%ThxriV16VdCc_k6&G z)FnIdt`}sVU2we(a{Um*VA7f@5)~4FKg#;TQDiZZ)=q!P+t2vog`J?`svlgkF$BfF z?MjinrswT2S9i2FGR@nM6Z@b?i>9hV4#wEN@>K|{+~^%iQB_m==R&{ZGNh~VNsMIW+=wbK!Y-)0O0Hpf#j_dXs(I{LPvaeMUzcW%YzRR`K{^gyh zG%9Hm9wG|nMgI1cA#8Em`BnSb8@RiDK19GL^3Rb~hMc<^?cJQ@0~0T@Zn8X$V>r~N zf91)~7>B>qWE5z{ws#QgjAwhNvmt2dn20Eg2&r;omZ_`LGbx(jS8qlU;Rn%SFX z?sGE6UpmLnd?I}T$H1x2)ZXLbVn1dvtZR46iqr=8WWrf!S-TK7*i6zML zxwG!o?9H4+?L&}=b_1;Mfdu867i<%htF#;$82h7&Z>qY-Y0&_ed(lc?_{A=gM-fBw{UBjkFw31|}nv{-P@MjtG8cs`U zJ5ve-P}3J>+Vk?!A{cuPnE9L4H8RINrpbXBp|ft=mGN3!Niw-cbW4=?m+Y<*Ld@h& z;D#@&5MHDR!N)$tat>gbm*LEtBab1{8m5odybfx*szz0(T(r^u@?cUoed!-2J0{7~ z9m(E36014Gm3Mqcx<`_R#1AqiBS5rKKV`-=@kfDs$h}Wm@kPGws3Hzh8I*fIukaHZ)o z^vetJ;XFBorXF9Mnzo=U!VXEk(gz{zCeaM#G?Hqss#na1`DyN8cN;t{)W^*7^jr15 zjE?QOf#wfkF$dvT)8EHc?kN$9R}8S4ql)X?YwYe#FzptJ_jHM~--TTYDRVw;C^TN1 z3P+r`q#pVNMx`;A9K_V<)`;G>adey$Eo|kc7(=ytl94F&KkmER_@D3cR*4{lm3d;Zx1Ev(=vS8X+Fu>qu+0apqfy9}mx)fnEvX+e>wMie?|?9qcU`_nY?IN5Kxlqo zM$|n}nnQOjb10<=cIUJqLX1%i;PYqE73k}ZJ@|o< z1UeIV4Vx&W|8k&sT1QEojg|L~nCYW^(Kp!M_WX=RiXiN+pGjXU9(=mgZJZ6a>I_Bl z|8wKCndBMTJ5x!T;4?|DvAXxU=xP2niQYhFmWbfVOttOe{$6ilmO>l23}2Xr6R@051+P0p#S7)+Of-k6yMKPjru7b9@gZs zX3QSc7wa==5d)-h)CjxTxt|R12`q3qI;R#uBIa)A@(g7k^T8PceKd2!lM%U%GgV}! zwqo*o=%qM*#mRrM-2^J+aN9`kqtV1n2{W@ zg~cP^Z)kJDgc&fMF^GklX22**)z(XA=y-0gZdgEG!P>CdnlBRzmjmJmz~WNTxNt1_M$>39igj>4dpc-Lm*17jtrXfK!L;GT`;9$#fij2G+Fm5 zNO8b6KL9GWWq)C~w}M`q8E0ZN+?iPK{NrKRd8K_%J&SL@sVJMty!dv>?!3y7LyPI< z{Dw4VV^Wf<M zF54yOgys@(yq;6zLy*xBT+q$!C6Z}Sn;6gVSX5x0_KWG{UtMmav{;U4Os|(CHA}zJ z1r(1aZnbEPJ=AZdkbe8@fUs>zWN+Hv=Rz}uJnI3cnT&8+jK*P+<{0K|1miIrfAZ22PtdSPp<|BcL(Xq8#E_cH2C>l{MaW; zenxc?7{8@e!HRZ6rQ<7u{($%F5pSr&T&tcVBK0xi-(LPAOQw@!T9*zPxwXm!*8!)! z_ezL&odW!2&Ny&QjaW_rK7s zYgmRX*HUZU5)2vZ-ZP0MxSG1Wy@<`!7b*wI)}g?Ex;&R{aF9jxZoY!Vy3(#wG@f+6 z$lxmYpB|oW`y+X}!<(;|?i&qAbQk;}5vM6LiheIk!ydm50(ViMlfs3+J-lzU9)4jI zx8#*vL~R4Wk#eK^z1$4(to#RDr_21`9ox?jH2(F3*lstln}UbsYfz z0OL6CkAOXEBU*3PrG8*mg}QM_u5fY0jVu2d^4Z>_-aWCT)BcOex!fp?`aOjY7qym| zfC=7?%>xc3twDME@Ng=GWpB;z0@8$@9NZpro!$HJpY$nJnrLAlEur0_*xX2>nl8XryC z51#HhhrkmoLX}eKq5tRB;CU*yWUZ<>HAzXg5w}pKpukM=TZfje2JdN4QlGY7K^nlk zR3}8SJ6aWi`9kjDtgubFsd05w^`Pqpk()F9y2hvym%c7Nlvl6SUFJXOL`7#n9~#AKruf(0}#;wj8lJ5y6XWvc1I( zxMtS5T3MUOvX^M^6VvNrx#a!G>$Iyv01Z#5oqon30?t3l1s-ezid7Lk1y)s&Wql+F zC{7{}X7c7o5tOqaupH&-lU-N!33tcSHn$@WA;{VtnozIpZ^Kl&V}#>-9~#F#HV8>8 z!k^xnfk5haAuu}Ri4je8m~<}9`6NKVu3ff zAB_5CkxjKR1gRX$%X0V7H;PeYVGG)^z~6>y{Ysygpa>WT^pqi1D-M<8G}4 z!^py+c%WuU&-49{$-FB{H$HO~c5;*_o%PTy2@x=ip27`=sCWy=j4?L8n!)gMno+vP z&|M6jbb_Gc`mF?*ap0vqraJT@*QL)VB%5@=$Ai<%mZT=KOo61;ns0kD)&6vWu>LcU z0yA^lvMKs}M)hg+V;>+yn#H4obSm#irDi;F^XtI}KcRGck?B0(v$BNPJ5Lcyta>Ot z_N2_HYvH(L*T8RNpz%}!8f5G!t$;5TXQ2Od4|tJV5 zGS#fe&qmM#ZWyoBTPPIV6e_U7?@~tth(4km(xKcMS;iS?RIF7Yo<~^idm_@l42z)% z7wJSL7mRw>pNrX%FGd_s?sUHquusnPmP)RL_DDb&F{8w+8@aypA`oc>T{#AUsh%yn zN9z;Mju9r0=^$Lw)^>7E$gG5pj1Uebt%z&#_8DN+2od%gp0`;Z{-?>AsYfINlj^^c zzBN4!%%-WHwslmuBGdtRo6603TNIgiPQp*~Dox!Qequlf=Uie0nPlpTEiQ`-pIM&#&+EJm!3bWv(;*+Ha1A&mFvk;m1|h+4*Q zzS3xOHevN*5rMNaf&R}|XKw7UcT-(M7^R7w);VYis$IxnWLx7Gb>j&R0hF|R4V_*G zJv`SnPemR5Ema1AbBY@hWQ6H(n_kb6Hk}Y9Rav|pyJ^4iP^3tz9Cb);T2Kxu6bkIY zmqEdRZr>@IM44^xhJHI;ZnMG2Y&=sxrGDw|f&m9f<~^X*4dndLt??vjQ`iZK*qdY+ zoZI{I@Z@!$t=>@DKy}OO1?57Z&c$OPsiv+Z_WObl-n^5XP?=tqrWBGwXeiS7K|v}c z1+TqL-SJJuzW8977f!FDY8gJg7Cpoi4)&MNOE7}b z4jb>s4a@ak`7rT5h#;uQ@_;Cql1QPJ?mOzX$(D2-;!foqwLmS7-?9H9m!4=F-MEfY z*xQNoe)n4p`BOWflCSX0-Ej|NotTW1>}T`WJY~yotRPEWviy?mym@%ls$&PQB;O~F zPQ06bsm>==BV-YSgJ>%f)%!W)6#<6jo6JGtj>YSeFQ2@m8Vl9$uoaV|b^RTG)~a+= zWSlIv(-F~Sro|!8F$Gi){ewOzY|VQOvGHLEQ-`gw`zD<|CT@WdDF{Y6A-W9S46-=n zmH1i5)fL{M*v6}O9mf?PO+L>~U&Q7YcNH`MPjU0Rh|c}a4xT#F_7>!+>(@fJ>gmt# zuSVN49d%n0+*qVyyAHic3~O})vibhh%YgoP8dumR@5=ndYeEM*h}A#3^oboa65TFZ zsrUWw`SMCylhdld%p<=-s2G)xlEep+uMWZ6V?pti*|@U^{$|6c$ZC|w5QGDE1}_q< zrE4!Tgy?B9h#EG};#&qNh3s0-OSEa%(3%)RyLMVm-ga^@N;|}h3;kw(zO;PhN5y8ND=Fsf zpX{3>PTqKNz7Pa&GMTgi@xoW4_MT^+(QpIa56R1A^Fs%+DhnG|Z?_+`%3~U&i0s&z z@f(I>08PzV*gHjgZu2?7R)O+i;Pn{DlZ&^ycXX(z>xzxTo{kvb5h#dxjNkNYWl1s-< ziu#KXW1~pl=yFey-EvbBJM?IoToOxjV!VY}bIi3>7ZueSHHzahP%&!E+I%#dUZ z7iHWC`$p}ygA-OePc$$mk~S=qP&vKfgM2$gxf02>{fSe6^VYOXF#ONASx&Zx-hs~H z(wuqXjM&4$jgPRKAzJc7)}P%4$6fpT+U0KYXkv({#_!bDoD4 zC9emIK#5#SZT|N-emyb4z@t3Lq!o6=#YbjJ9!tKWhTApT3)u@nw5^Wj>+*OG?UT)g zt!q;24o_uEy%sVp~af zQjz@6IpAl)pvV(Il6OWd5OPfGc6QlFH##R#^8%@oEtLM)Fn}>zD);Pe7@e{j;gOr)F0@qS&?pX82l9CC3{x60bj{tE#)4hFU6O!W1%TH;xe4pN%NIiKw z06%RQ!q(g0i8|&5rYiBPvB-)R=MZ%rvV=%HeDjpMWFG_q=eMBf*~@lW^7)slwAFhv zp^;bE;AMwOx7~N2_Mg9MJo)rXv>Nf{3em&s8zYmY-T!s@V0Vnx!Gp?8H$M;{EcmfO zxEGcA9P8x~l!#5yC7_t^sZ>p>72PQ5rGCmE-ptM!?J-F#l+n?TKftx}dG@UYs=OIk zASpca;C%~|iBC?!&V&X2_KyV6MqX9dWjjhpj%^q|a<5SQI{Q=ntth-6QQqE~f77io zSGzeM(H9IX1aaufhs{@b_W*=1pN-*0Zf@!Zq6+IMZ_8db!u_I6o&vL048oBDl` z@kRV;V^h67cDu#AAtX>jF2oO+9{E0>x3wehjRMzFlMp%YZc@3T>6;pYRGLVGs{yoJ zRW#!vy`W}BQc|UEYmrf)gWE*!FL`PH6}^?DmZ~ID=YUUAEeZ#HJse`DFe;-V!c>qI zrHK=8dNG-lQ&lsqv3YTy-@m@;!m^4A?Ll)`p#P*7u(4-pyE#e1&y1jE-|O}W{4lMi z2Zq#5DK|SS*LoZ3todV9ugJ@pOd=K2LUklJ=^LD;B8&s z8|mWMZ%sTLW-unnSaWBhsS-OFvGb4)-yfm-z8dBf6j{`ToEA1*dkNaN^B8&?J(HgY zvoC}i{LPej`+khvg+}BAZDl;#fW5pSPNR`pr|CMp&ua>x40c>MAJXVEiJ$9NUmg41*FBKAqTIMFB)LOQ zr23IHf6CNoK(^5jx;1v(>flWDrQaD3+e}C|{31WlsKM(4Wg8hP3qzBRFMJjTS*HKTj4AUsX02}7#>~R8vV=0>p9L~23%tAxFL&>$ zJ1Wq_-8_FyWfRgvMaxA=CB-nKa*@MB3XCHFlbw6)5I+fRd?-v_zT-Py7O}*fj1sG~ zaDhx*sQ3UF3+qcY(9Be|5_#N}Yz`(zjv>f{5xZmfTsfkAHY^5`F?To*SZ3+Rq(-1j z4EOclCAZxenPZW}z_g<&YWh&a)NHIXk_tk88!Asd+OoMD`0i4yu@{yWh#O6Ea1^NR z?oPO=!0U?T4KFrBKQUe9mSsoiwV~|1C{KbDg{rQX!uVgMg7b+?qp+BrxE&$LyJs`4 z&Zh4doGfFMZbA+TdkV&7glukN%0POI9W_NxTNNA!YHB}}|jfcy0)i}w1~ zT4OyAQq|gD_TNvAR5Gsh&EeQr!`v+PN%Xc*xWOjpPZLCx%|P)UA}rF6sg^x@sEYi75+36?9VMvKJZ4`@6w6Z=9)<%^A0&6ok zh9clEKttB9M*>QWA-No{o_nD!)Eb9Qke~M{GWYRG8S!{RossqB48C)sGwPhEqd-u% z^NoTfxr(L?OM0ciV?(G|GVkL#3Xzi(V#}w{0xM&YLV+dYqqd~WHH*cEZ)V$t`N>Bx z?0;wzpY&G2zQ)+WU6(}D>Z5zLxG2{&Ja&1WJemu%^DqfY%>;Ywf5^mdBJ3?>bU_9j z*N`?uyWT9(6jPB|w$%J@YOF$)GS4C}gZFNZQiED#+P>X?8+P6}B;rY;q&QcPFr%$T zl`oSj$>YpCmfxorCJ`o=Uqlig0a!7sioY|fCGCANf}BELEWIxt+nGD)kYht9nVeqy_9f=>r-k~Jv&<#$-p zbYdj3P)`A2xMjL%I6nN8QKXvf33lhZ5-~hKM;Uk<@Bi`o)>_Lz3*_ENk=l4h5pqH@ zoE6Ew8I|7%@Rh>i8Q8-l*n4m~BZLry%ChPyxYcuwWen>@J6 zJ(Oc{`;_m3md-}7{dDmQbi5vRmMPzvh}}cs1RSwT)00a$so4S z&mL-`iqz#__+W_v$onE1k*=22m zk6=ACgc{0!u&b?XHkmQ;po!;pLF$xv&Pg`7d)RTt>n4u?Hj3Lx+U(%gRC+gNp&lJv zDnp86xcsqjn+-`)dvW#0uhM|WPzOM%aLG%i%GleTDEdc7WU{gcO?M#glB99fWo5|9 z+}xvzT&i32&)s)`rN(~uJx7q*KWjFJE1}0EFaMf0o|PgKvrnJC>jZKhpD3YnVqoU0 zTMa2u21^wg7B>BXJsNt%mh``h;ld}eRi5NfRI?==;Hu9d{4{Esu8&xx4GiGfK0K;H zw7oIjD%?oM%B;O#G1zw>fo)~Bf+-S8I#O$tc?!JEF1v-)3!6W_9&D?(eDx&G8`%}` z#12L@oUu{3RQpOikrlE->xTU99h6#s7*FnAp|$x~M?Fw^;O%7`2;Q{b1Oc{PAI;DY z`r)2bQoxC<#uc!(g10|&N3wDeh=f!V{pqv-Hnna(_IkptnJ22oBo&m}G=eL@n~Dn5 zJAvzr1vpW|1?UH!i``nT9w98+Nvt@=F;OBPjfT)5nuD0eGrYYgq0|>H6_t1TJH8A8 zI83EzAMYjhjsFV>&G%u!-9s#Bc$%BNL`T|mRnt_sT1 zTh?|!x8E0wI&zw%F1$c^Wg0+vqOy-#mdU4c^R8^!aePl6;ni$T-3A<)cQ?b@T!pyy z3)2<o4jI;?_odUV<(RpGmDmaUcU+(>4lXBmw{Zh2vaxBDCVUXYJrlCbV5{t)-8fuPr>LVpjvpxZe0)QO@yZ18zp3vLEz_W`^|5%`t6?e`+pw^^O75DiOy z`M%ToP2rUMU(f5-LGbYLzXo%ot%-%%f_9AEG2UoHsGGYMgnzOip2AfHDzo#VjvjQO zBNE8lCRyZ3^aH(Te01>JrXQ{(>7|kWXN2)69|rtp=TMt%REmXuaH=}G62j9Q*j8u4 z)0lCuZD=t25j|~*g23|r1RWh%n8ua+qhpu>6Si(=hw+hrq|K`bhB1#kl8ag!BQsJS zMr#!)aXh(a$_rl}zm3Q*klhjlh8YR;|2dZ1b6f|z3%>F!pqeb0MNTLxE(w>rj!#L! z7E(dUd{0^X`PyE2G?*Xl0>{QhF5hcWEpp&le+T!VfK@SyHzUTEzv7vR1ztL%Xy+EG ze2{Hf15g}%AI?zOr@01t{V0cBvevlx0*VI*=9stbUde4&7oW?_#c!#~ zLMUI3nM$eUg&d-0s4G&^Kfe)>PF^Mgo*d+(sKzq*6pp-|wmT!Os< zCzXdSmHIQKOa#zaLy?a)v>Gq?X*`0u4D2oIcH$8Xu`+69ol4xuxFHEcxYWSvgvIg1 z?u24&x4{xIN$d!4MECrS91D4de5gBlzo-(spJ8akFKo7cvN%z+w64yIBeg_~I^#+z z-lFYiya1R@R1_k$Kbu&bt$)=~c51KK*Qz;ICOL)rB?3qsK#T4aM$=ck4PPDUL97C$ zph>&C20_Sj)b&OeA76OxOyC;#pt@882|kEYX!+&MpN@u=ir>#UUu`TYacohz7CAUg z9!zI?yVw87>pPTSZ@8&*k?~gAU|cH48ytiyN?|GE74(Q4FwWKi>}}4xA9g>f6YV>z@Se z>n3D2M#itF8j(Je82Wr0cj*fB*y>|q*WTEyF}@Mv`E7MN2xFxCLl0s zbg85WvQg6AE!{n8FjC*g-{<{v`)v2_`_z4Q&bhAVb-@l+sY|Q$z)MagKn0xSxh~-3?VmW;wHTerqihI_yq} zjYiig#{pYA7)G59#VIkuXBGH&hRZr8xd{`t5aV(LKy1^L28v%`_3W!+#W)2q zg2x)|uecB|1n&KFk{O17GKDCVK$eDQM{c||!UKE?_#Sj0&o3U-UXfyaG}79}Yi?xW zK#`t}JmMLv6a+&=33vnT-W@dzC&f=`^ojm~uiwfwN-1QaHmEQTY3`|r4(GsFhj`G}oH*u%yTOwgc zCSVhK5l!Pq?h4`cydXDpMb2*B``I%BGUonq2;<$oT}v4gq^>AoeM>^t>(-Ljb~|2O z-7gcA)b9Fe8TCI;38rHG!S(H)#x%q+K3x4yjR$+<2f-j0?VZtG=r-4_e_mW5WPSux zXo*-!Jp~C&?*PZ-WwG|NF1mUsD2NI*i{2d#`{zhedLqEiMW^dJr{$4$b>zE42fxWK z6ZiQ!MRZfQ`D$Ynv;mv|k=pjOikXE;J=3>BYHmTh4~3`00b{9POV=+w+h5lP zo32u$ob2Va) zxOcZ%euKg2B~p;R!ar{HRn#zQF%iS#8=9YL?)57*_@O_`r@PWGA zd4bFOFEoMZolqlYR1P$*$Fn1Bz(G9(z;L(TXalY)?mVQD{0imo6jWy2nx13ldQsoJ z2=S!BrR-b%k|Pidw!ZV`{39^7bXA*(i!atH*7{_j1RPYcf4SFPBfHDZW1T4dUiJKL z@uaGQa#HBz)PHz-DDqil>*L`q;wHB%E(z#l0V6U>9tGS0K;?E&1rSmBTtgtAW@~5N zcu?8(VP6a-clQ{zu1WnW*VYRpqO#tj;tQJ-QOv|Z^gf+nf$>ywY^GU~%+_z^4FS&}wGy6?2LhoQR{TUI9QhmJ$j zWVOFy`_4wwj&w0mlI7$_!wi5cD*93FV`iL0xr8cDe*ez>`H$KI`1{0~hBcXqWoJO+ zwur6h%kr{h)|1tcZm%Iy+k`fPSxS(A&HKP5abGz-40|231^w4Qn*IS%4sSEDTYW*i z<7uTZb#;5vbj$f$22cu!SAQ`!Q_LedXg0n)3gk$~WCeg6AEK}<0UMOtC;IM#K_^}( zE1zoWuyeqCR*h)UWUb1`hmQt((VrMaN{K@dYZBI*bz8S8brAuL)%mqqUP36rn>eja z129G{!0=Lr3rF^oT%+YfaM}eI0?X3L`339IH@}fxPlDmKrVQ9_73ysGqA?{11f%vc z246(J*89~_NufrZ4dO(o-2d0j+vwAc!mhRj^y!VG7qk_~Kxv_kw@s5uy()>h=OWVm zJh#Y+|}3AUQiXtW{h0oIVDh7NNgfwegKvPMMMf$wgmG!+>Y zLaVmkciUrY^6Jcm*xUs^zq$k6E@U`yw`jj^&n|lRpN5OypJgPYC#Bg#Yiz?k0k)J& zp9nf~j4s02w8GcYMH4@=i9^0<`0yI|<<-$ulv>$K8@Hlj$>icHIu?yt6nIYX%_-k# zn@)I0yf;^daxin1DA)C~!d-k*ifKLpXg$qcS2?a$?gWZW zzO9(ryUMZ{rzc>J2fmKdCdaD7di`I);JgU|{AdjShR*u1I*Fnn3x~?qATj!cnY2k| z*G}T00y3qtOm;Rt_~XWDQ|h~0G#DthkTC@eW_X2?RY2;B_&o?SL$TPy9vtltR#j>r zvz>(DNRzq#k{HQ*?4%|O(ws(Wx$|2~n>aL#6{?*lsg>#5U@e^Gyf5$H<(MI+9F~EG z(V@MU|G>->DK;N(`Rn>?c`fnS3pR@7Ze!MZcK^b<*$#+&x7FjlO<5A>V$eNr7?H&T z4c@WqPHS;T=8I<|)i>#DX3Ag8MzM1fxuF#WWu zU2H~Xf~-sjv)_c?o!+BPsvw12K9qTjCbkBooG>jz-p(@nOJp9+I}Y@k1)RWXDo&yn z77>DEq#UzBHk!{Wxi9a|Q`K_AKAuKUG%_ad?3JF>D0^)Vx}!6dBGHwt;q;lC&CM@n zGo(k0eK05di5=W$1CCvKC5+~ICBKZzvqca&<`IOIoQj(gEpkSXsWeqIAI$rH1)0G^ zBIq{VYND#xQ-}IZqkhj57huZd_{n7YXM#II!pY|}UcXSg$`S^Wdoy3ec3QL&s6b5R z>z9%!A_(5kDv3pZIr>8LFw9NaLMrh{ITyb_@hW_Qyca-*tSwX2Z|e1f)>a-^kx2H9 zb>CtovAFp9m~_wsosVUi%J*UG8lM)asjdh6Y+AKnlzLXHG$pc(N6U=ijD85pQlAoW zr?%e{S|*NxkAMyOGaD>-W81>Z(<#SI8(Ht2+(tPi&($LB=q?BA z{Z{{)qz&sL`q@>aYlYQjAzltyvr)jjMYx$G>FWC6RXa+Ew{Mw0N9qOT`z%*EBmg8^ z33gx)Y2xziHxXcsV)s|eQ`9=XU83VyfwyU?46trz8Trhfq~!FVgve&__z5jh;b`k* zx#sS4A)?fm1pUT8-?rq&A=6I6Jw$N-fNdeNtHVkz@?szHcmI20_`=_|;edqK(~Z8zx7))XAd?@ZQ<{_T0sbmg9Do}(LBer-7Q@YiWi?6X_t4u26h}G58;HeZ@%c2zV>$MYq z%_Y{638l@4X*<%gVCjBx3x#k=aL}JHlvynt@@)AFLB54nH%nW0I2Sx*Gj!}Tli8mKy6flX17a2ga zh3((Ipkt{!@#P_c#9Zdl+GX2j6Od9+$s#L!pb1JvH;HRR!qNavS;ccZ@AxSOw;XxV z;FX%{@SMy2Z0-rZU&ELccFA6h$eHpHO6L7ph>rvkf>U6Q?Z-x-B=t!~(LZz2`J zAjn;}DD&PTc&=Zxzvr(^XrhxybDn#Wt_>oP`AM9$(}Qj94Jr)}E!2SRZ9giWF*ls}Xp#ZSt`0qi?lko-Lk&;|8j8@3p zH%I1WMw97XR%rM_h1NZ~JMaa7Lg*ch_Z$aGy7?AYlgMWjj@G+NSXyFOM%D30OaLh7 zWB=YefjMc$m9h;PorrQ=L3+yms;3vVznY!{h#1qoJzW3hgVxLOk-%{Jbg8=vc{WWs zHhaj3pcy@O@2JTH+7FrE?%M>5{r=yA6|eTvva{uifuVekn=383-}O`~!vk-Xk6+^! zJE9bcc|j=1TFNUm*Ia=TgGI>VlK4Y4lKKvV;mGo^p?VJBJJQxwp%u?PFXXVJxa;i~enDPTU?rzz?`>%Mns5FG9pr~&&rzw56 zlvmS?@dt+Eq*aXGhE@w6L6m`u1}U9u;-i$x?yS50ajCw(wryGHcUoJGY2w( zFiyJ7zeZBEXe6RJ+V98G<4*7GwZ+zO^}9wqpg2|S^Ag9}iYq9oc;IF6gx(O=UUWRG zNXZz(Je0VmY-2NMSLx-K+Uv`KD_3DPxP3%MDqz!gD7{%iN6X+H*j)K{OU9P%HWkRv zJA3w4C0VbtFEwStj#6{^OgO%zY z&3#^Y3EIloofTY0YGK%d*=1e(W~^WG@QefeRx|Q4{5F5qzCgVe@+_xmt`1xvk`!fI zgv&nR(;D&wjQNiRuHA_7SA!|#y7&O_#ugzk!^nuldx?2$ej&dUeyI^C)}fIFJ>Z-| zXS-?M&-CBsB>a24_}76To#F$$W1#C(pr+TUarhy8CrI8skImuN-@ru`?MSs+fTe6G zOu0YQdvPP7`rZiGpLPkl@UwqjUQ;Owb3*!jixu?FH${ulnv>;RQD{Z|y-1f1HRvpS*EuzK?|!9X zcW!`#$6YJfIj3&*eQ*}LAC0&7O?1bc-4E$#^ypw9EVb*bJKmiQNQ^ZGgxD9LoMfM4Ck^2SzR&=U5tA6XwMiBoP+Art|~e_Hpb)}5>iILh2S(iosYbWVH` zHt*+z15=)D?fEr)x&VF$>Tjl#DcSb;oUr9tgz%%I@7Vk5nD@laX5AT{mc%~mV;}h) zBT-NrOcUs{EKlF>co^Nu&G8Q({PBd<(scGCIhguv zTCh;`SrN|=$}pJ}@c~B(X9*F^`FG>Wc*!;g6a^TSCO%0@`EEe5-3j#OQpZ`wlKr0A zG__y%bdFUn%zf+tRyVwpLCX9^jNW{dfjyW-bB4mF26=0-OlR+kud_*tww9Xqp06-C z6tR1$Dp74o(l_oO12cqeU52-dM@w$s=^e4@7m}|O*3;}aaK`d(XqnQU^h-d4yjw^w z6f`!+-YVcxkG?1!P8++o11vO40A7?823R?TzePz%{43au9sVXgP zxJC?y4~MfXPJBZ}^|0C?h%PrhJ6OC2Se*yNgf?K*(BghS_#FdH0+EQ4uI?We zBmA9(f_Vr$eL#Vo(9-1c@8t#Z{a%CUv#o@oZJ$CH&V0IsrS8q3MxOen1YVLa;N=0O z4gaK+rmotnIbzSU7X?oRxXKeOXzw`iB+BI&7(5LW_B~pi+vgy zeJXB~MXoR82T$@ei{Z`n{Is<~1 zmwL^)>5hwh1%0wBV%o)%-j60D&AUCb+doBM-DDXT=V=#l(__;kJOGECr-XM`j}w~i z#DWylln^DhsPJR%j-afADYGuF&@w>IY+Bx!E!|Hd=6ZVi*2juiy#m_uu3!n}Kz{0@ z`P0*azZTn~GeHjy{Cw3t=xXK%QkczPi) zWs_yB&_(pYdU_>D$*>rJR4G*~X9a~zw+C6)pWSf>9U*GivJCHm^thHOby*Y#gO0s! zgG0HN(FZAs1=(xSk(QmgZ?@@-oOWx({ewYV!`kuULPa{-nbj zXKO1Kjy<2C&@5xphr7+RVZQnL*>^^ybwr*usk+HtBLFWX*n-M{Q+QmP%#8sZ=G<^1~?1>^N=58@o zlEAXTCXOTk(%6F#@|I{S3~PAhK_hPPfCP2FT=oHmXf)V54qPuY2VkR+E(q9c^9QwBNhR|nVp4`Y(N(4Us2AFh-AH1 zp=_zNt^rY({Xk5=$mHevV}qlDQ)J;O*wbte&m?v4AlSH# z=eTAIiOe|IH%?Jp0GN5(?#Bc5V#JNte>9HA=23*QUf{42aSJN~kk%@c_CCY?n>>pC zNXE!O$oq|dIWROzblp41Gy9Av-x&9BT?-tou zh=M)hgoiCc$Lw9JXrD;A7dUXzz-4oV7zJB_z5^qdQe#&CA!;0RBeEQa4VdO+qw#i+ zv(77LQKVA9Z}lpDemTDObCk?~jptftE~Zj!JgxOLLG|4rHA-GOP?V*-&nZt!S=QuY zhoYA#^-<3@AKk)MQv}b7S@&j*$g%%TzUwXk06q6z&l&Df(-(5N?Zg0$LM=Cux+$@xqcrK>F3+FUP~UhImgUu zB+iWtW-J9y2nPiDUJsNPs~NksU$1`WYBm_YyEx96)b&_rE*?mLanB#oD6{r>E7d8a zGWf?t`CMV8`4&!dgO;J{tXC_KrL~4!nRCNupAFXkcTRnT(X5OCopl<7gtJ%cVP}#< zN4bF&>le3{N8K+1b>O-QH122ebc2yUZ$=}qjTE`C{U)7r88H;jL-ut*IOue3?ipO_ zx@`U|p1GQIp{c46+9l3`Dk_U@|NcxtqwPS|mOqW+$lh&SPTPuz2SZ~iU-QnrIO{M6U=JPl_~!|ElGARhL)+wF zPnIcVW=u#S=!c+U{^Fb%LR$qG%Y|d+gE{{vo>bzG;42~?Ajj0oY}5Z_V(NlOpSDms zs5X-3JJQ0(J%dff-1MODnL)>I9AKov*sF3)jwuynMxm%-j(IEdbCa8vKC6ih#Lp5g zh$PXx#<=tEGOMEt49_>Tw`dAeR9#`UtA=iqOp9dZxam$Q6Oz;qQQaf9+7wWCRHXUk zR-(qc&{Q>rNh#U|8T*Q{WW(V`Qt2joz=Z8tRHvoGenB%^EdvlcmRdxL+eHqU`gLQz zix9X>l~=XpeUP5;a$I?4NLFg4_>anf#Zb|ip%ITj+#RPmY2_xkcxV5wc&V`ZPXQLX zzk~c}00Z%C&GuZYrmK10ug9kOE)=ZRnz6a6X$(vTzMMWH!lbk_c5@A%I*Z=+>{^fx z7JHJtgyfW9v|R;Tqa=E%`^i2=J=n1Rq3d`=0ab%s>PQ2kf52eXc@eQ z(srTi^tf@A`B*Akx&&i~L`$&ZZGf1-{ViU11${8`{MWaZqt1ix`w@n9c&A-an?or6mTRH~jg+mT>T=d5|4DP0N4KA3v{dd?>vo0kuO4d5Je4HIT*NqanDMv3 zT489j$?Z4vxIHp}9VkGyr`Zb%X#N>o`T^&V>t@^Y z;e#)r!3XNF7N5pgvA#!J7qn+ZzsWluHesHH$_*!Lb6Rd}+>QM&^{;@QE$4ERn$K~% zhE2W)QnAjQ4~!zGqsH-H{xNt-4Z7f@J|_A~L?kPe=SI8vg8$Ji)j1lQvk~dJSY)j4 zLCDx$6$cX5#yo3ptL%hUo#nyQoYi2@iX8TXBH#77hX8Gn(VUKr7TEQOoJj6m!)tMx z%M7hQ=_Opvo9BTvt|N}TbWOG~H6wfc7PNU$n8T<#U3J`46du24L)#`H%oWsvJ#!}$ z4-5E^v&!aK&$0POif(~-OXc3#%PRptf;_h~RMo+t+#3B}>Yii5H;M`OO^fl9%*N=G z;N;UadffM@0Hwx9229wnoceqfBDSlE9G6^AvRd^zF)K1v1-;YDy54>tGXI&d#_|_f z!ga;sUz@KEb-rgieI31US6nX2iK##eg=A*{DNxSm(3ORkN?TOP@TInGV^u_CeU(bz zj*X-%*|V^W5VyAPP4}cK;_6dAL5kuHhc(_?yO%V6|H<>|POgXH@I(gI4>ea6^q6iO zAdfs>LCE@Qn}l>v!IVkDGN=_5hMMcZ^zMYg2(^Nw`*@XQ0DU@4&WZKe|80o+r2T>s zE4|TN{fr?N_~^qw9gV;P5}vX#kcor-(M<~-l61ZQs*;s^v206tsf$~rcT)rii`Cm3 z%NO?Q#osCOPQwA(<457YrZ~&zNv_pc|MJkg{QC&~a~v}_T_D-Bf9q&II`=s5++M|Z yAl@5RlKy*(jQ5;YJ2YupA9!iM{Fm|df4JWKCtVeAHsA?8|7ob`Dwiw14*5SON>w`m literal 0 HcmV?d00001 diff --git a/v1.5.0/assets/themes/documenter-dark.css b/v1.5.0/assets/themes/documenter-dark.css new file mode 100644 index 00000000000..1d71701582f --- /dev/null +++ b/v1.5.0/assets/themes/documenter-dark.css @@ -0,0 +1,7 @@ +html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:.4em;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 1px);position:relative;vertical-align:top}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus,html.theme--documenter-dark .pagination-ellipsis:focus,html.theme--documenter-dark .file-cta:focus,html.theme--documenter-dark .file-name:focus,html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .button:focus,html.theme--documenter-dark .is-focused.pagination-previous,html.theme--documenter-dark .is-focused.pagination-next,html.theme--documenter-dark .is-focused.pagination-link,html.theme--documenter-dark .is-focused.pagination-ellipsis,html.theme--documenter-dark .is-focused.file-cta,html.theme--documenter-dark .is-focused.file-name,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-focused.button,html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active,html.theme--documenter-dark .pagination-ellipsis:active,html.theme--documenter-dark .file-cta:active,html.theme--documenter-dark .file-name:active,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .button:active,html.theme--documenter-dark .is-active.pagination-previous,html.theme--documenter-dark .is-active.pagination-next,html.theme--documenter-dark .is-active.pagination-link,html.theme--documenter-dark .is-active.pagination-ellipsis,html.theme--documenter-dark .is-active.file-cta,html.theme--documenter-dark .is-active.file-name,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .is-active.button{outline:none}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-ellipsis[disabled],html.theme--documenter-dark .file-cta[disabled],html.theme--documenter-dark .file-name[disabled],html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark fieldset[disabled] .pagination-previous,fieldset[disabled] html.theme--documenter-dark .pagination-next,html.theme--documenter-dark fieldset[disabled] .pagination-next,fieldset[disabled] html.theme--documenter-dark .pagination-link,html.theme--documenter-dark fieldset[disabled] .pagination-link,fieldset[disabled] html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark fieldset[disabled] .pagination-ellipsis,fieldset[disabled] html.theme--documenter-dark .file-cta,html.theme--documenter-dark fieldset[disabled] .file-cta,fieldset[disabled] html.theme--documenter-dark .file-name,html.theme--documenter-dark fieldset[disabled] .file-name,fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark fieldset[disabled] .select select,html.theme--documenter-dark .select fieldset[disabled] select,html.theme--documenter-dark fieldset[disabled] .textarea,html.theme--documenter-dark fieldset[disabled] .input,html.theme--documenter-dark fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] html.theme--documenter-dark .button,html.theme--documenter-dark fieldset[disabled] .button{cursor:not-allowed}html.theme--documenter-dark .tabs,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .breadcrumb,html.theme--documenter-dark .file,html.theme--documenter-dark .button,.is-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after,html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}html.theme--documenter-dark .admonition:not(:last-child),html.theme--documenter-dark .tabs:not(:last-child),html.theme--documenter-dark .pagination:not(:last-child),html.theme--documenter-dark .message:not(:last-child),html.theme--documenter-dark .level:not(:last-child),html.theme--documenter-dark .breadcrumb:not(:last-child),html.theme--documenter-dark .block:not(:last-child),html.theme--documenter-dark .title:not(:last-child),html.theme--documenter-dark .subtitle:not(:last-child),html.theme--documenter-dark .table-container:not(:last-child),html.theme--documenter-dark .table:not(:last-child),html.theme--documenter-dark .progress:not(:last-child),html.theme--documenter-dark .notification:not(:last-child),html.theme--documenter-dark .content:not(:last-child),html.theme--documenter-dark .box:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .modal-close,html.theme--documenter-dark .delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before,html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .modal-close::before,html.theme--documenter-dark .delete::before{height:2px;width:50%}html.theme--documenter-dark .modal-close::after,html.theme--documenter-dark .delete::after{height:50%;width:2px}html.theme--documenter-dark .modal-close:hover,html.theme--documenter-dark .delete:hover,html.theme--documenter-dark .modal-close:focus,html.theme--documenter-dark .delete:focus{background-color:rgba(10,10,10,0.3)}html.theme--documenter-dark .modal-close:active,html.theme--documenter-dark .delete:active{background-color:rgba(10,10,10,0.4)}html.theme--documenter-dark .is-small.modal-close,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.modal-close,html.theme--documenter-dark .is-small.delete,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}html.theme--documenter-dark .is-medium.modal-close,html.theme--documenter-dark .is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}html.theme--documenter-dark .is-large.modal-close,html.theme--documenter-dark .is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}html.theme--documenter-dark .control.is-loading::after,html.theme--documenter-dark .select.is-loading::after,html.theme--documenter-dark .loader,html.theme--documenter-dark .button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdee0;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}html.theme--documenter-dark .hero-video,html.theme--documenter-dark .modal-background,html.theme--documenter-dark .modal,html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}html.theme--documenter-dark .navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#ecf0f1 !important}a.has-text-light:hover,a.has-text-light:focus{color:#cfd9db !important}.has-background-light{background-color:#ecf0f1 !important}.has-text-dark{color:#282f2f !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#111414 !important}.has-background-dark{background-color:#282f2f !important}.has-text-primary{color:#375a7f !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#28415b !important}.has-background-primary{background-color:#375a7f !important}.has-text-primary-light{color:#f1f5f9 !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#cddbe9 !important}.has-background-primary-light{background-color:#f1f5f9 !important}.has-text-primary-dark{color:#4d7eb2 !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#7198c1 !important}.has-background-primary-dark{background-color:#4d7eb2 !important}.has-text-link{color:#1abc9c !important}a.has-text-link:hover,a.has-text-link:focus{color:#148f77 !important}.has-background-link{background-color:#1abc9c !important}.has-text-link-light{color:#edfdf9 !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c0f6ec !important}.has-background-link-light{background-color:#edfdf9 !important}.has-text-link-dark{color:#15987e !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#1bc5a4 !important}.has-background-link-dark{background-color:#15987e !important}.has-text-info{color:#024c7d !important}a.has-text-info:hover,a.has-text-info:focus{color:#012d4b !important}.has-background-info{background-color:#024c7d !important}.has-text-info-light{color:#ebf7ff !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#b9e2fe !important}.has-background-info-light{background-color:#ebf7ff !important}.has-text-info-dark{color:#0e9dfb !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#40b1fc !important}.has-background-info-dark{background-color:#0e9dfb !important}.has-text-success{color:#008438 !important}a.has-text-success:hover,a.has-text-success:focus{color:#005122 !important}.has-background-success{background-color:#008438 !important}.has-text-success-light{color:#ebfff3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#b8ffd6 !important}.has-background-success-light{background-color:#ebfff3 !important}.has-text-success-dark{color:#00eb64 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#1fff7e !important}.has-background-success-dark{background-color:#00eb64 !important}.has-text-warning{color:#ad8100 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#7a5b00 !important}.has-background-warning{background-color:#ad8100 !important}.has-text-warning-light{color:#fffaeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#ffedb8 !important}.has-background-warning-light{background-color:#fffaeb !important}.has-text-warning-dark{color:#d19c00 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#ffbf05 !important}.has-background-warning-dark{background-color:#d19c00 !important}.has-text-danger{color:#9e1b0d !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#6f1309 !important}.has-background-danger{background-color:#9e1b0d !important}.has-text-danger-light{color:#fdeeec !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#fac3bd !important}.has-background-danger-light{background-color:#fdeeec !important}.has-text-danger-dark{color:#ec311d !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#f05c4c !important}.has-background-danger-dark{background-color:#ec311d !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#282f2f !important}.has-background-grey-darker{background-color:#282f2f !important}.has-text-grey-dark{color:#343c3d !important}.has-background-grey-dark{background-color:#343c3d !important}.has-text-grey{color:#5e6d6f !important}.has-background-grey{background-color:#5e6d6f !important}.has-text-grey-light{color:#8c9b9d !important}.has-background-grey-light{background-color:#8c9b9d !important}.has-text-grey-lighter{color:#dbdee0 !important}.has-background-grey-lighter{background-color:#dbdee0 !important}.has-text-white-ter{color:#ecf0f1 !important}.has-background-white-ter{background-color:#ecf0f1 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:1rem !important}.is-size-7,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{font-size:.75rem !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:1rem !important}.is-size-7-mobile{font-size:.75rem !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:1rem !important}.is-size-7-tablet{font-size:.75rem !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:1rem !important}.is-size-7-touch{font-size:.75rem !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:1rem !important}.is-size-7-desktop{font-size:.75rem !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:1rem !important}.is-size-7-widescreen{font-size:.75rem !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:1rem !important}.is-size-7-fullhd{font-size:.75rem !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.is-underlined{text-decoration:underline !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}html.theme--documenter-dark{/*! + Theme: a11y-dark + Author: @ericwbailey + Maintainer: @ericwbailey + + Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css +*/}html.theme--documenter-dark html{background-color:#1f2424;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark article,html.theme--documenter-dark aside,html.theme--documenter-dark figure,html.theme--documenter-dark footer,html.theme--documenter-dark header,html.theme--documenter-dark hgroup,html.theme--documenter-dark section{display:block}html.theme--documenter-dark body,html.theme--documenter-dark button,html.theme--documenter-dark input,html.theme--documenter-dark optgroup,html.theme--documenter-dark select,html.theme--documenter-dark textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}html.theme--documenter-dark code,html.theme--documenter-dark pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark body{color:#fff;font-size:1em;font-weight:400;line-height:1.5}html.theme--documenter-dark a{color:#1abc9c;cursor:pointer;text-decoration:none}html.theme--documenter-dark a strong{color:currentColor}html.theme--documenter-dark a:hover{color:#1dd2af}html.theme--documenter-dark code{background-color:rgba(255,255,255,0.05);color:#ececec;font-size:.875em;font-weight:normal;padding:.1em}html.theme--documenter-dark hr{background-color:#282f2f;border:none;display:block;height:2px;margin:1.5rem 0}html.theme--documenter-dark img{height:auto;max-width:100%}html.theme--documenter-dark input[type="checkbox"],html.theme--documenter-dark input[type="radio"]{vertical-align:baseline}html.theme--documenter-dark small{font-size:.875em}html.theme--documenter-dark span{font-style:inherit;font-weight:inherit}html.theme--documenter-dark strong{color:#f2f2f2;font-weight:700}html.theme--documenter-dark fieldset{border:none}html.theme--documenter-dark pre{-webkit-overflow-scrolling:touch;background-color:#282f2f;color:#fff;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}html.theme--documenter-dark pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}html.theme--documenter-dark table td,html.theme--documenter-dark table th{vertical-align:top}html.theme--documenter-dark table td:not([align]),html.theme--documenter-dark table th:not([align]){text-align:inherit}html.theme--documenter-dark table th{color:#f2f2f2}html.theme--documenter-dark .box{background-color:#343c3d;border-radius:8px;box-shadow:none;color:#fff;display:block;padding:1.25rem}html.theme--documenter-dark a.box:hover,html.theme--documenter-dark a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #1abc9c}html.theme--documenter-dark a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #1abc9c}html.theme--documenter-dark .button{background-color:#282f2f;border-color:#4c5759;border-width:1px;color:#375a7f;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}html.theme--documenter-dark .button strong{color:inherit}html.theme--documenter-dark .button .icon,html.theme--documenter-dark .button .icon.is-small,html.theme--documenter-dark .button #documenter .docs-sidebar form.docs-search>input.icon,html.theme--documenter-dark #documenter .docs-sidebar .button form.docs-search>input.icon,html.theme--documenter-dark .button .icon.is-medium,html.theme--documenter-dark .button .icon.is-large{height:1.5em;width:1.5em}html.theme--documenter-dark .button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}html.theme--documenter-dark .button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}html.theme--documenter-dark .button:hover,html.theme--documenter-dark .button.is-hovered{border-color:#8c9b9d;color:#f2f2f2}html.theme--documenter-dark .button:focus,html.theme--documenter-dark .button.is-focused{border-color:#8c9b9d;color:#17a689}html.theme--documenter-dark .button:focus:not(:active),html.theme--documenter-dark .button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button:active,html.theme--documenter-dark .button.is-active{border-color:#343c3d;color:#f2f2f2}html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;color:#fff;text-decoration:underline}html.theme--documenter-dark .button.is-text:hover,html.theme--documenter-dark .button.is-text.is-hovered,html.theme--documenter-dark .button.is-text:focus,html.theme--documenter-dark .button.is-text.is-focused{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .button.is-text:active,html.theme--documenter-dark .button.is-text.is-active{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .button.is-text[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}html.theme--documenter-dark .button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#1abc9c;text-decoration:none}html.theme--documenter-dark .button.is-ghost:hover,html.theme--documenter-dark .button.is-ghost.is-hovered{color:#1abc9c;text-decoration:underline}html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:hover,html.theme--documenter-dark .button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus,html.theme--documenter-dark .button.is-white.is-focused{border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white:focus:not(:active),html.theme--documenter-dark .button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .button.is-white[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-hovered{background-color:#000}html.theme--documenter-dark .button.is-white.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-white.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-white.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:hover,html.theme--documenter-dark .button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus,html.theme--documenter-dark .button.is-black.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black:focus:not(:active),html.theme--documenter-dark .button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-black[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-black.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-black.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}html.theme--documenter-dark .button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:hover,html.theme--documenter-dark .button.is-light.is-hovered{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus,html.theme--documenter-dark .button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light:focus:not(:active),html.theme--documenter-dark .button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light.is-active{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light{background-color:#ecf0f1;border-color:#ecf0f1;box-shadow:none}html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-outlined.is-focused{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}html.theme--documenter-dark .button.is-light.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-outlined{background-color:transparent;border-color:#ecf0f1;box-shadow:none;color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ecf0f1 #ecf0f1 !important}html.theme--documenter-dark .button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .button.is-dark,html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover,html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark:focus:not(:active),html.theme--documenter-dark .content kbd.button:focus:not(:active),html.theme--documenter-dark .button.is-dark.is-focused:not(:active),html.theme--documenter-dark .content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-dark[disabled],html.theme--documenter-dark .content kbd.button[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark,fieldset[disabled] html.theme--documenter-dark .content kbd.button{background-color:#282f2f;border-color:#282f2f;box-shadow:none}html.theme--documenter-dark .button.is-dark.is-inverted,html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted:hover,html.theme--documenter-dark .content kbd.button.is-inverted:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-dark.is-inverted[disabled],html.theme--documenter-dark .content kbd.button.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-loading::after,html.theme--documenter-dark .content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined,html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-outlined.is-focused{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-dark.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-outlined{background-color:transparent;border-color:#282f2f;box-shadow:none;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:hover,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined:focus,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#282f2f}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #282f2f #282f2f !important}html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined[disabled],html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-dark.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary:focus:not(:active),html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus:not(:active),html.theme--documenter-dark .button.is-primary.is-focused:not(:active),html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-primary[disabled],html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;box-shadow:none}html.theme--documenter-dark .button.is-primary.is-inverted,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}html.theme--documenter-dark .button.is-primary.is-inverted[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-primary.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#375a7f;box-shadow:none;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:hover,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined:focus,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#375a7f}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #375a7f #375a7f !important}html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined[disabled],html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-primary.is-inverted.is-outlined,fieldset[disabled] html.theme--documenter-dark .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:hover,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:hover,html.theme--documenter-dark .button.is-primary.is-light.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e8eef5;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-primary.is-light:active,html.theme--documenter-dark .docstring>section>a.button.is-light.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary.is-light.is-active,html.theme--documenter-dark .docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#dfe8f1;border-color:transparent;color:#4d7eb2}html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:hover,html.theme--documenter-dark .button.is-link.is-hovered{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus,html.theme--documenter-dark .button.is-link.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link:focus:not(:active),html.theme--documenter-dark .button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link.is-active{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-link[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link{background-color:#1abc9c;border-color:#1abc9c;box-shadow:none}html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-link.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-outlined.is-focused{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-link.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-outlined{background-color:transparent;border-color:#1abc9c;box-shadow:none;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#1abc9c}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #1abc9c #1abc9c !important}html.theme--documenter-dark .button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:hover,html.theme--documenter-dark .button.is-link.is-light.is-hovered{background-color:#e2fbf6;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-link.is-light:active,html.theme--documenter-dark .button.is-link.is-light.is-active{background-color:#d7f9f3;border-color:transparent;color:#15987e}html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:hover,html.theme--documenter-dark .button.is-info.is-hovered{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus,html.theme--documenter-dark .button.is-info.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info:focus:not(:active),html.theme--documenter-dark .button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info.is-active{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-info[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info{background-color:#024c7d;border-color:#024c7d;box-shadow:none}html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-info.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;color:#024c7d}html.theme--documenter-dark .button.is-info.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-outlined.is-focused{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-info.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-outlined{background-color:transparent;border-color:#024c7d;box-shadow:none;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#024c7d}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #024c7d #024c7d !important}html.theme--documenter-dark .button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:hover,html.theme--documenter-dark .button.is-info.is-light.is-hovered{background-color:#def2fe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-info.is-light:active,html.theme--documenter-dark .button.is-info.is-light.is-active{background-color:#d2edfe;border-color:transparent;color:#0e9dfb}html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:hover,html.theme--documenter-dark .button.is-success.is-hovered{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus,html.theme--documenter-dark .button.is-success.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success:focus:not(:active),html.theme--documenter-dark .button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success.is-active{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-success[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success{background-color:#008438;border-color:#008438;box-shadow:none}html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-success.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;color:#008438}html.theme--documenter-dark .button.is-success.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-outlined.is-focused{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-success.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-outlined{background-color:transparent;border-color:#008438;box-shadow:none;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#008438}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #008438 #008438 !important}html.theme--documenter-dark .button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:hover,html.theme--documenter-dark .button.is-success.is-light.is-hovered{background-color:#deffec;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-success.is-light:active,html.theme--documenter-dark .button.is-success.is-light.is-active{background-color:#d1ffe5;border-color:transparent;color:#00eb64}html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:hover,html.theme--documenter-dark .button.is-warning.is-hovered{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus,html.theme--documenter-dark .button.is-warning.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning:focus:not(:active),html.theme--documenter-dark .button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning.is-active{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-warning[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning{background-color:#ad8100;border-color:#ad8100;box-shadow:none}html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-warning.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-outlined.is-focused{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-warning.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-outlined{background-color:transparent;border-color:#ad8100;box-shadow:none;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-focused{background-color:#fff;color:#ad8100}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ad8100 #ad8100 !important}html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:hover,html.theme--documenter-dark .button.is-warning.is-light.is-hovered{background-color:#fff7de;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-warning.is-light:active,html.theme--documenter-dark .button.is-warning.is-light.is-active{background-color:#fff3d1;border-color:transparent;color:#d19c00}html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:hover,html.theme--documenter-dark .button.is-danger.is-hovered{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus,html.theme--documenter-dark .button.is-danger.is-focused{border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger:focus:not(:active),html.theme--documenter-dark .button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger.is-active{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .button.is-danger[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;box-shadow:none}html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}html.theme--documenter-dark .button.is-danger.is-inverted[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-outlined.is-focused{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}html.theme--documenter-dark .button.is-danger.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-outlined{background-color:transparent;border-color:#9e1b0d;box-shadow:none;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:hover,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-hovered,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined:focus,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#9e1b0d}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:hover::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading:focus::after,html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #9e1b0d #9e1b0d !important}html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] html.theme--documenter-dark .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}html.theme--documenter-dark .button.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:hover,html.theme--documenter-dark .button.is-danger.is-light.is-hovered{background-color:#fce3e0;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-danger.is-light:active,html.theme--documenter-dark .button.is-danger.is-light.is-active{background-color:#fcd8d5;border-color:transparent;color:#ec311d}html.theme--documenter-dark .button.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}html.theme--documenter-dark .button.is-small:not(.is-rounded),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:3px}html.theme--documenter-dark .button.is-normal{font-size:1rem}html.theme--documenter-dark .button.is-medium{font-size:1.25rem}html.theme--documenter-dark .button.is-large{font-size:1.5rem}html.theme--documenter-dark .button[disabled],fieldset[disabled] html.theme--documenter-dark .button{background-color:#8c9b9d;border-color:#5e6d6f;box-shadow:none;opacity:.5}html.theme--documenter-dark .button.is-fullwidth{display:flex;width:100%}html.theme--documenter-dark .button.is-loading{color:transparent !important;pointer-events:none}html.theme--documenter-dark .button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}html.theme--documenter-dark .button.is-static{background-color:#282f2f;border-color:#5e6d6f;color:#dbdee0;box-shadow:none;pointer-events:none}html.theme--documenter-dark .button.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}html.theme--documenter-dark .buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .buttons .button{margin-bottom:0.5rem}html.theme--documenter-dark .buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}html.theme--documenter-dark .buttons:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .buttons:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}html.theme--documenter-dark .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:3px}html.theme--documenter-dark .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}html.theme--documenter-dark .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}html.theme--documenter-dark .buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}html.theme--documenter-dark .buttons.has-addons .button:last-child{margin-right:0}html.theme--documenter-dark .buttons.has-addons .button:hover,html.theme--documenter-dark .buttons.has-addons .button.is-hovered{z-index:2}html.theme--documenter-dark .buttons.has-addons .button:focus,html.theme--documenter-dark .buttons.has-addons .button.is-focused,html.theme--documenter-dark .buttons.has-addons .button:active,html.theme--documenter-dark .buttons.has-addons .button.is-active,html.theme--documenter-dark .buttons.has-addons .button.is-selected{z-index:3}html.theme--documenter-dark .buttons.has-addons .button:focus:hover,html.theme--documenter-dark .buttons.has-addons .button.is-focused:hover,html.theme--documenter-dark .buttons.has-addons .button:active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-active:hover,html.theme--documenter-dark .buttons.has-addons .button.is-selected:hover{z-index:4}html.theme--documenter-dark .buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .buttons.is-centered{justify-content:center}html.theme--documenter-dark .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}html.theme--documenter-dark .buttons.is-right{justify-content:flex-end}html.theme--documenter-dark .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .button.is-responsive.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}html.theme--documenter-dark .button.is-responsive,html.theme--documenter-dark .button.is-responsive.is-normal{font-size:.75rem}html.theme--documenter-dark .button.is-responsive.is-medium{font-size:1rem}html.theme--documenter-dark .button.is-responsive.is-large{font-size:1.25rem}}html.theme--documenter-dark .container{flex-grow:1;margin:0 auto;position:relative;width:auto}html.theme--documenter-dark .container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){html.theme--documenter-dark .container{max-width:992px}}@media screen and (max-width: 1215px){html.theme--documenter-dark .container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){html.theme--documenter-dark .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){html.theme--documenter-dark .container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){html.theme--documenter-dark .container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}html.theme--documenter-dark .content li+li{margin-top:0.25em}html.theme--documenter-dark .content p:not(:last-child),html.theme--documenter-dark .content dl:not(:last-child),html.theme--documenter-dark .content ol:not(:last-child),html.theme--documenter-dark .content ul:not(:last-child),html.theme--documenter-dark .content blockquote:not(:last-child),html.theme--documenter-dark .content pre:not(:last-child),html.theme--documenter-dark .content table:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .content h1,html.theme--documenter-dark .content h2,html.theme--documenter-dark .content h3,html.theme--documenter-dark .content h4,html.theme--documenter-dark .content h5,html.theme--documenter-dark .content h6{color:#f2f2f2;font-weight:600;line-height:1.125}html.theme--documenter-dark .content h1{font-size:2em;margin-bottom:0.5em}html.theme--documenter-dark .content h1:not(:first-child){margin-top:1em}html.theme--documenter-dark .content h2{font-size:1.75em;margin-bottom:0.5714em}html.theme--documenter-dark .content h2:not(:first-child){margin-top:1.1428em}html.theme--documenter-dark .content h3{font-size:1.5em;margin-bottom:0.6666em}html.theme--documenter-dark .content h3:not(:first-child){margin-top:1.3333em}html.theme--documenter-dark .content h4{font-size:1.25em;margin-bottom:0.8em}html.theme--documenter-dark .content h5{font-size:1.125em;margin-bottom:0.8888em}html.theme--documenter-dark .content h6{font-size:1em;margin-bottom:1em}html.theme--documenter-dark .content blockquote{background-color:#282f2f;border-left:5px solid #5e6d6f;padding:1.25em 1.5em}html.theme--documenter-dark .content ol{list-style-position:outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ol:not([type]){list-style-type:decimal}html.theme--documenter-dark .content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}html.theme--documenter-dark .content ol.is-lower-roman:not([type]){list-style-type:lower-roman}html.theme--documenter-dark .content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}html.theme--documenter-dark .content ol.is-upper-roman:not([type]){list-style-type:upper-roman}html.theme--documenter-dark .content ul{list-style:disc outside;margin-left:2em;margin-top:1em}html.theme--documenter-dark .content ul ul{list-style-type:circle;margin-top:0.5em}html.theme--documenter-dark .content ul ul ul{list-style-type:square}html.theme--documenter-dark .content dd{margin-left:2em}html.theme--documenter-dark .content figure{margin-left:2em;margin-right:2em;text-align:center}html.theme--documenter-dark .content figure:not(:first-child){margin-top:2em}html.theme--documenter-dark .content figure:not(:last-child){margin-bottom:2em}html.theme--documenter-dark .content figure img{display:inline-block}html.theme--documenter-dark .content figure figcaption{font-style:italic}html.theme--documenter-dark .content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}html.theme--documenter-dark .content sup,html.theme--documenter-dark .content sub{font-size:75%}html.theme--documenter-dark .content table{width:100%}html.theme--documenter-dark .content table td,html.theme--documenter-dark .content table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .content table th{color:#f2f2f2}html.theme--documenter-dark .content table th:not([align]){text-align:inherit}html.theme--documenter-dark .content table thead td,html.theme--documenter-dark .content table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .content table tfoot td,html.theme--documenter-dark .content table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .content table tbody tr:last-child td,html.theme--documenter-dark .content table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .content .tabs li+li{margin-top:0}html.theme--documenter-dark .content.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}html.theme--documenter-dark .content.is-normal{font-size:1rem}html.theme--documenter-dark .content.is-medium{font-size:1.25rem}html.theme--documenter-dark .content.is-large{font-size:1.5rem}html.theme--documenter-dark .icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}html.theme--documenter-dark .icon.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}html.theme--documenter-dark .icon.is-medium{height:2rem;width:2rem}html.theme--documenter-dark .icon.is-large{height:3rem;width:3rem}html.theme--documenter-dark .icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}html.theme--documenter-dark .icon-text .icon{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .icon-text .icon:not(:last-child){margin-right:.25em}html.theme--documenter-dark .icon-text .icon:not(:first-child){margin-left:.25em}html.theme--documenter-dark div.icon-text{display:flex}html.theme--documenter-dark .image,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{display:block;position:relative}html.theme--documenter-dark .image img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}html.theme--documenter-dark .image img.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}html.theme--documenter-dark .image.is-fullwidth,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}html.theme--documenter-dark .image.is-square img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square img,html.theme--documenter-dark .image.is-square .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,html.theme--documenter-dark .image.is-1by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 img,html.theme--documenter-dark .image.is-1by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,html.theme--documenter-dark .image.is-5by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 img,html.theme--documenter-dark .image.is-5by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,html.theme--documenter-dark .image.is-4by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 img,html.theme--documenter-dark .image.is-4by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,html.theme--documenter-dark .image.is-3by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 img,html.theme--documenter-dark .image.is-3by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,html.theme--documenter-dark .image.is-5by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 img,html.theme--documenter-dark .image.is-5by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,html.theme--documenter-dark .image.is-16by9 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 img,html.theme--documenter-dark .image.is-16by9 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,html.theme--documenter-dark .image.is-2by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 img,html.theme--documenter-dark .image.is-2by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,html.theme--documenter-dark .image.is-3by1 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 img,html.theme--documenter-dark .image.is-3by1 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,html.theme--documenter-dark .image.is-4by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 img,html.theme--documenter-dark .image.is-4by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,html.theme--documenter-dark .image.is-3by4 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 img,html.theme--documenter-dark .image.is-3by4 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,html.theme--documenter-dark .image.is-2by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 img,html.theme--documenter-dark .image.is-2by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,html.theme--documenter-dark .image.is-3by5 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 img,html.theme--documenter-dark .image.is-3by5 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,html.theme--documenter-dark .image.is-9by16 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 img,html.theme--documenter-dark .image.is-9by16 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,html.theme--documenter-dark .image.is-1by2 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 img,html.theme--documenter-dark .image.is-1by2 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,html.theme--documenter-dark .image.is-1by3 img,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 img,html.theme--documenter-dark .image.is-1by3 .has-ratio,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}html.theme--documenter-dark .image.is-square,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-square,html.theme--documenter-dark .image.is-1by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}html.theme--documenter-dark .image.is-5by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}html.theme--documenter-dark .image.is-4by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}html.theme--documenter-dark .image.is-3by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}html.theme--documenter-dark .image.is-5by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}html.theme--documenter-dark .image.is-16by9,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}html.theme--documenter-dark .image.is-2by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}html.theme--documenter-dark .image.is-3by1,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}html.theme--documenter-dark .image.is-4by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}html.theme--documenter-dark .image.is-3by4,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}html.theme--documenter-dark .image.is-2by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}html.theme--documenter-dark .image.is-3by5,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}html.theme--documenter-dark .image.is-9by16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}html.theme--documenter-dark .image.is-1by2,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}html.theme--documenter-dark .image.is-1by3,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}html.theme--documenter-dark .image.is-16x16,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}html.theme--documenter-dark .image.is-24x24,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}html.theme--documenter-dark .image.is-32x32,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}html.theme--documenter-dark .image.is-48x48,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}html.theme--documenter-dark .image.is-64x64,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}html.theme--documenter-dark .image.is-96x96,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}html.theme--documenter-dark .image.is-128x128,html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}html.theme--documenter-dark .notification{background-color:#282f2f;border-radius:.4em;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}html.theme--documenter-dark .notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .notification strong{color:currentColor}html.theme--documenter-dark .notification code,html.theme--documenter-dark .notification pre{background:#fff}html.theme--documenter-dark .notification pre code{background:transparent}html.theme--documenter-dark .notification>.delete{right:.5rem;position:absolute;top:0.5rem}html.theme--documenter-dark .notification .title,html.theme--documenter-dark .notification .subtitle,html.theme--documenter-dark .notification .content{color:currentColor}html.theme--documenter-dark .notification.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .notification.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .notification.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .notification.is-dark,html.theme--documenter-dark .content kbd.notification{background-color:#282f2f;color:#fff}html.theme--documenter-dark .notification.is-primary,html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .notification.is-primary.is-light,html.theme--documenter-dark .docstring>section>a.notification.is-light.docs-sourcelink{background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .notification.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .notification.is-link.is-light{background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .notification.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .notification.is-info.is-light{background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .notification.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .notification.is-success.is-light{background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .notification.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .notification.is-warning.is-light{background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .notification.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .notification.is-danger.is-light{background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}html.theme--documenter-dark .progress::-webkit-progress-bar{background-color:#343c3d}html.theme--documenter-dark .progress::-webkit-progress-value{background-color:#dbdee0}html.theme--documenter-dark .progress::-moz-progress-bar{background-color:#dbdee0}html.theme--documenter-dark .progress::-ms-fill{background-color:#dbdee0;border:none}html.theme--documenter-dark .progress.is-white::-webkit-progress-value{background-color:#fff}html.theme--documenter-dark .progress.is-white::-moz-progress-bar{background-color:#fff}html.theme--documenter-dark .progress.is-white::-ms-fill{background-color:#fff}html.theme--documenter-dark .progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-black::-webkit-progress-value{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-moz-progress-bar{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black::-ms-fill{background-color:#0a0a0a}html.theme--documenter-dark .progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-light::-webkit-progress-value{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-moz-progress-bar{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light::-ms-fill{background-color:#ecf0f1}html.theme--documenter-dark .progress.is-light:indeterminate{background-image:linear-gradient(to right, #ecf0f1 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-dark::-webkit-progress-value,html.theme--documenter-dark .content kbd.progress::-webkit-progress-value{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-moz-progress-bar,html.theme--documenter-dark .content kbd.progress::-moz-progress-bar{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark::-ms-fill,html.theme--documenter-dark .content kbd.progress::-ms-fill{background-color:#282f2f}html.theme--documenter-dark .progress.is-dark:indeterminate,html.theme--documenter-dark .content kbd.progress:indeterminate{background-image:linear-gradient(to right, #282f2f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-primary::-webkit-progress-value,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-moz-progress-bar,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary::-ms-fill,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#375a7f}html.theme--documenter-dark .progress.is-primary:indeterminate,html.theme--documenter-dark .docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #375a7f 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-link::-webkit-progress-value{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-moz-progress-bar{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link::-ms-fill{background-color:#1abc9c}html.theme--documenter-dark .progress.is-link:indeterminate{background-image:linear-gradient(to right, #1abc9c 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-info::-webkit-progress-value{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-moz-progress-bar{background-color:#024c7d}html.theme--documenter-dark .progress.is-info::-ms-fill{background-color:#024c7d}html.theme--documenter-dark .progress.is-info:indeterminate{background-image:linear-gradient(to right, #024c7d 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-success::-webkit-progress-value{background-color:#008438}html.theme--documenter-dark .progress.is-success::-moz-progress-bar{background-color:#008438}html.theme--documenter-dark .progress.is-success::-ms-fill{background-color:#008438}html.theme--documenter-dark .progress.is-success:indeterminate{background-image:linear-gradient(to right, #008438 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-warning::-webkit-progress-value{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-moz-progress-bar{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning::-ms-fill{background-color:#ad8100}html.theme--documenter-dark .progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ad8100 30%, #343c3d 30%)}html.theme--documenter-dark .progress.is-danger::-webkit-progress-value{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-moz-progress-bar{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger::-ms-fill{background-color:#9e1b0d}html.theme--documenter-dark .progress.is-danger:indeterminate{background-image:linear-gradient(to right, #9e1b0d 30%, #343c3d 30%)}html.theme--documenter-dark .progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#343c3d;background-image:linear-gradient(to right, #fff 30%, #343c3d 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}html.theme--documenter-dark .progress:indeterminate::-webkit-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-moz-progress-bar{background-color:transparent}html.theme--documenter-dark .progress:indeterminate::-ms-fill{animation-name:none}html.theme--documenter-dark .progress.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}html.theme--documenter-dark .progress.is-medium{height:1.25rem}html.theme--documenter-dark .progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}html.theme--documenter-dark .table{background-color:#343c3d;color:#fff}html.theme--documenter-dark .table td,html.theme--documenter-dark .table th{border:1px solid #5e6d6f;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}html.theme--documenter-dark .table td.is-white,html.theme--documenter-dark .table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .table td.is-black,html.theme--documenter-dark .table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .table td.is-light,html.theme--documenter-dark .table th.is-light{background-color:#ecf0f1;border-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .table td.is-dark,html.theme--documenter-dark .table th.is-dark{background-color:#282f2f;border-color:#282f2f;color:#fff}html.theme--documenter-dark .table td.is-primary,html.theme--documenter-dark .table th.is-primary{background-color:#375a7f;border-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-link,html.theme--documenter-dark .table th.is-link{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .table td.is-info,html.theme--documenter-dark .table th.is-info{background-color:#024c7d;border-color:#024c7d;color:#fff}html.theme--documenter-dark .table td.is-success,html.theme--documenter-dark .table th.is-success{background-color:#008438;border-color:#008438;color:#fff}html.theme--documenter-dark .table td.is-warning,html.theme--documenter-dark .table th.is-warning{background-color:#ad8100;border-color:#ad8100;color:#fff}html.theme--documenter-dark .table td.is-danger,html.theme--documenter-dark .table th.is-danger{background-color:#9e1b0d;border-color:#9e1b0d;color:#fff}html.theme--documenter-dark .table td.is-narrow,html.theme--documenter-dark .table th.is-narrow{white-space:nowrap;width:1%}html.theme--documenter-dark .table td.is-selected,html.theme--documenter-dark .table th.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table td.is-selected a,html.theme--documenter-dark .table td.is-selected strong,html.theme--documenter-dark .table th.is-selected a,html.theme--documenter-dark .table th.is-selected strong{color:currentColor}html.theme--documenter-dark .table td.is-vcentered,html.theme--documenter-dark .table th.is-vcentered{vertical-align:middle}html.theme--documenter-dark .table th{color:#f2f2f2}html.theme--documenter-dark .table th:not([align]){text-align:left}html.theme--documenter-dark .table tr.is-selected{background-color:#375a7f;color:#fff}html.theme--documenter-dark .table tr.is-selected a,html.theme--documenter-dark .table tr.is-selected strong{color:currentColor}html.theme--documenter-dark .table tr.is-selected td,html.theme--documenter-dark .table tr.is-selected th{border-color:#fff;color:currentColor}html.theme--documenter-dark .table thead{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table thead td,html.theme--documenter-dark .table thead th{border-width:0 0 2px;color:#f2f2f2}html.theme--documenter-dark .table tfoot{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tfoot td,html.theme--documenter-dark .table tfoot th{border-width:2px 0 0;color:#f2f2f2}html.theme--documenter-dark .table tbody{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .table tbody tr:last-child td,html.theme--documenter-dark .table tbody tr:last-child th{border-bottom-width:0}html.theme--documenter-dark .table.is-bordered td,html.theme--documenter-dark .table.is-bordered th{border-width:1px}html.theme--documenter-dark .table.is-bordered tr:last-child td,html.theme--documenter-dark .table.is-bordered tr:last-child th{border-bottom-width:1px}html.theme--documenter-dark .table.is-fullwidth{width:100%}html.theme--documenter-dark .table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#282f2f}html.theme--documenter-dark .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#2d3435}html.theme--documenter-dark .table.is-narrow td,html.theme--documenter-dark .table.is-narrow th{padding:0.25em 0.5em}html.theme--documenter-dark .table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#282f2f}html.theme--documenter-dark .table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}html.theme--documenter-dark .tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .tags .tag,html.theme--documenter-dark .tags .content kbd,html.theme--documenter-dark .content .tags kbd,html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}html.theme--documenter-dark .tags .tag:not(:last-child),html.theme--documenter-dark .tags .content kbd:not(:last-child),html.theme--documenter-dark .content .tags kbd:not(:last-child),html.theme--documenter-dark .tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}html.theme--documenter-dark .tags:last-child{margin-bottom:-0.5rem}html.theme--documenter-dark .tags:not(:last-child){margin-bottom:1rem}html.theme--documenter-dark .tags.are-medium .tag:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .content kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .content .tags.are-medium kbd:not(.is-normal):not(.is-large),html.theme--documenter-dark .tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}html.theme--documenter-dark .tags.are-large .tag:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .content kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .content .tags.are-large kbd:not(.is-normal):not(.is-medium),html.theme--documenter-dark .tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}html.theme--documenter-dark .tags.is-centered{justify-content:center}html.theme--documenter-dark .tags.is-centered .tag,html.theme--documenter-dark .tags.is-centered .content kbd,html.theme--documenter-dark .content .tags.is-centered kbd,html.theme--documenter-dark .tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}html.theme--documenter-dark .tags.is-right{justify-content:flex-end}html.theme--documenter-dark .tags.is-right .tag:not(:first-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:first-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}html.theme--documenter-dark .tags.is-right .tag:not(:last-child),html.theme--documenter-dark .tags.is-right .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.is-right kbd:not(:last-child),html.theme--documenter-dark .tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}html.theme--documenter-dark .tags.has-addons .tag,html.theme--documenter-dark .tags.has-addons .content kbd,html.theme--documenter-dark .content .tags.has-addons kbd,html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}html.theme--documenter-dark .tags.has-addons .tag:not(:first-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:first-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:first-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}html.theme--documenter-dark .tags.has-addons .tag:not(:last-child),html.theme--documenter-dark .tags.has-addons .content kbd:not(:last-child),html.theme--documenter-dark .content .tags.has-addons kbd:not(:last-child),html.theme--documenter-dark .tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}html.theme--documenter-dark .tag:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#282f2f;border-radius:.4em;color:#fff;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}html.theme--documenter-dark .tag:not(body) .delete,html.theme--documenter-dark .content kbd:not(body) .delete,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}html.theme--documenter-dark .tag.is-white:not(body),html.theme--documenter-dark .content kbd.is-white:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .tag.is-black:not(body),html.theme--documenter-dark .content kbd.is-black:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .tag.is-light:not(body),html.theme--documenter-dark .content kbd.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .tag.is-dark:not(body),html.theme--documenter-dark .content kbd:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-dark:not(body),html.theme--documenter-dark .content .docstring>section>kbd:not(body){background-color:#282f2f;color:#fff}html.theme--documenter-dark .tag.is-primary:not(body),html.theme--documenter-dark .content kbd.is-primary:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body){background-color:#375a7f;color:#fff}html.theme--documenter-dark .tag.is-primary.is-light:not(body),html.theme--documenter-dark .content kbd.is-primary.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f1f5f9;color:#4d7eb2}html.theme--documenter-dark .tag.is-link:not(body),html.theme--documenter-dark .content kbd.is-link:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#1abc9c;color:#fff}html.theme--documenter-dark .tag.is-link.is-light:not(body),html.theme--documenter-dark .content kbd.is-link.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#edfdf9;color:#15987e}html.theme--documenter-dark .tag.is-info:not(body),html.theme--documenter-dark .content kbd.is-info:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#024c7d;color:#fff}html.theme--documenter-dark .tag.is-info.is-light:not(body),html.theme--documenter-dark .content kbd.is-info.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ebf7ff;color:#0e9dfb}html.theme--documenter-dark .tag.is-success:not(body),html.theme--documenter-dark .content kbd.is-success:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#008438;color:#fff}html.theme--documenter-dark .tag.is-success.is-light:not(body),html.theme--documenter-dark .content kbd.is-success.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#ebfff3;color:#00eb64}html.theme--documenter-dark .tag.is-warning:not(body),html.theme--documenter-dark .content kbd.is-warning:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ad8100;color:#fff}html.theme--documenter-dark .tag.is-warning.is-light:not(body),html.theme--documenter-dark .content kbd.is-warning.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffaeb;color:#d19c00}html.theme--documenter-dark .tag.is-danger:not(body),html.theme--documenter-dark .content kbd.is-danger:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .tag.is-danger.is-light:not(body),html.theme--documenter-dark .content kbd.is-danger.is-light:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#fdeeec;color:#ec311d}html.theme--documenter-dark .tag.is-normal:not(body),html.theme--documenter-dark .content kbd.is-normal:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}html.theme--documenter-dark .tag.is-medium:not(body),html.theme--documenter-dark .content kbd.is-medium:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}html.theme--documenter-dark .tag.is-large:not(body),html.theme--documenter-dark .content kbd.is-large:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}html.theme--documenter-dark .tag:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .content kbd:not(body) .icon:first-child:not(:last-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}html.theme--documenter-dark .tag:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .content kbd:not(body) .icon:last-child:not(:first-child),html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}html.theme--documenter-dark .tag:not(body) .icon:first-child:last-child,html.theme--documenter-dark .content kbd:not(body) .icon:first-child:last-child,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}html.theme--documenter-dark .tag.is-delete:not(body),html.theme--documenter-dark .content kbd.is-delete:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before,html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}html.theme--documenter-dark .tag.is-delete:not(body)::before,html.theme--documenter-dark .content kbd.is-delete:not(body)::before,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}html.theme--documenter-dark .tag.is-delete:not(body)::after,html.theme--documenter-dark .content kbd.is-delete:not(body)::after,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}html.theme--documenter-dark .tag.is-delete:not(body):hover,html.theme--documenter-dark .content kbd.is-delete:not(body):hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):hover,html.theme--documenter-dark .tag.is-delete:not(body):focus,html.theme--documenter-dark .content kbd.is-delete:not(body):focus,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#1d2122}html.theme--documenter-dark .tag.is-delete:not(body):active,html.theme--documenter-dark .content kbd.is-delete:not(body):active,html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#111414}html.theme--documenter-dark .tag.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:not(body),html.theme--documenter-dark .content kbd.is-rounded:not(body),html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input:not(body),html.theme--documenter-dark .docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}html.theme--documenter-dark a.tag:hover,html.theme--documenter-dark .docstring>section>a.docs-sourcelink:hover{text-decoration:underline}html.theme--documenter-dark .title,html.theme--documenter-dark .subtitle{word-break:break-word}html.theme--documenter-dark .title em,html.theme--documenter-dark .title span,html.theme--documenter-dark .subtitle em,html.theme--documenter-dark .subtitle span{font-weight:inherit}html.theme--documenter-dark .title sub,html.theme--documenter-dark .subtitle sub{font-size:.75em}html.theme--documenter-dark .title sup,html.theme--documenter-dark .subtitle sup{font-size:.75em}html.theme--documenter-dark .title .tag,html.theme--documenter-dark .title .content kbd,html.theme--documenter-dark .content .title kbd,html.theme--documenter-dark .title .docstring>section>a.docs-sourcelink,html.theme--documenter-dark .subtitle .tag,html.theme--documenter-dark .subtitle .content kbd,html.theme--documenter-dark .content .subtitle kbd,html.theme--documenter-dark .subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}html.theme--documenter-dark .title{color:#fff;font-size:2rem;font-weight:500;line-height:1.125}html.theme--documenter-dark .title strong{color:inherit;font-weight:inherit}html.theme--documenter-dark .title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}html.theme--documenter-dark .title.is-1{font-size:3rem}html.theme--documenter-dark .title.is-2{font-size:2.5rem}html.theme--documenter-dark .title.is-3{font-size:2rem}html.theme--documenter-dark .title.is-4{font-size:1.5rem}html.theme--documenter-dark .title.is-5{font-size:1.25rem}html.theme--documenter-dark .title.is-6{font-size:1rem}html.theme--documenter-dark .title.is-7{font-size:.75rem}html.theme--documenter-dark .subtitle{color:#8c9b9d;font-size:1.25rem;font-weight:400;line-height:1.25}html.theme--documenter-dark .subtitle strong{color:#8c9b9d;font-weight:600}html.theme--documenter-dark .subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}html.theme--documenter-dark .subtitle.is-1{font-size:3rem}html.theme--documenter-dark .subtitle.is-2{font-size:2.5rem}html.theme--documenter-dark .subtitle.is-3{font-size:2rem}html.theme--documenter-dark .subtitle.is-4{font-size:1.5rem}html.theme--documenter-dark .subtitle.is-5{font-size:1.25rem}html.theme--documenter-dark .subtitle.is-6{font-size:1rem}html.theme--documenter-dark .subtitle.is-7{font-size:.75rem}html.theme--documenter-dark .heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}html.theme--documenter-dark .number{align-items:center;background-color:#282f2f;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#1f2424;border-color:#5e6d6f;border-radius:.4em;color:#dbdee0}html.theme--documenter-dark .select select::-moz-placeholder,html.theme--documenter-dark .textarea::-moz-placeholder,html.theme--documenter-dark .input::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select::-webkit-input-placeholder,html.theme--documenter-dark .textarea::-webkit-input-placeholder,html.theme--documenter-dark .input::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:-moz-placeholder,html.theme--documenter-dark .textarea:-moz-placeholder,html.theme--documenter-dark .input:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#868c98}html.theme--documenter-dark .select select:-ms-input-placeholder,html.theme--documenter-dark .textarea:-ms-input-placeholder,html.theme--documenter-dark .input:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#868c98}html.theme--documenter-dark .select select:hover,html.theme--documenter-dark .textarea:hover,html.theme--documenter-dark .input:hover,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:hover,html.theme--documenter-dark .select select.is-hovered,html.theme--documenter-dark .is-hovered.textarea,html.theme--documenter-dark .is-hovered.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#8c9b9d}html.theme--documenter-dark .select select:focus,html.theme--documenter-dark .textarea:focus,html.theme--documenter-dark .input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:focus,html.theme--documenter-dark .select select.is-focused,html.theme--documenter-dark .is-focused.textarea,html.theme--documenter-dark .is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .select select:active,html.theme--documenter-dark .textarea:active,html.theme--documenter-dark .input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:active,html.theme--documenter-dark .select select.is-active,html.theme--documenter-dark .is-active.textarea,html.theme--documenter-dark .is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{border-color:#1abc9c;box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select select[disabled],html.theme--documenter-dark .textarea[disabled],html.theme--documenter-dark .input[disabled],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] html.theme--documenter-dark .select select,fieldset[disabled] html.theme--documenter-dark .textarea,fieldset[disabled] html.theme--documenter-dark .input,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{background-color:#8c9b9d;border-color:#282f2f;box-shadow:none;color:#fff}html.theme--documenter-dark .select select[disabled]::-moz-placeholder,html.theme--documenter-dark .textarea[disabled]::-moz-placeholder,html.theme--documenter-dark .input[disabled]::-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .textarea[disabled]::-webkit-input-placeholder,html.theme--documenter-dark .input[disabled]::-webkit-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input::-webkit-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-moz-placeholder,html.theme--documenter-dark .textarea[disabled]:-moz-placeholder,html.theme--documenter-dark .input[disabled]:-moz-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-moz-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .select select[disabled]:-ms-input-placeholder,html.theme--documenter-dark .textarea[disabled]:-ms-input-placeholder,html.theme--documenter-dark .input[disabled]:-ms-input-placeholder,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .select select:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .textarea:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark .input:-ms-input-placeholder,fieldset[disabled] html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:rgba(255,255,255,0.3)}html.theme--documenter-dark .textarea,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}html.theme--documenter-dark .textarea[readonly],html.theme--documenter-dark .input[readonly],html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}html.theme--documenter-dark .is-white.textarea,html.theme--documenter-dark .is-white.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}html.theme--documenter-dark .is-white.textarea:focus,html.theme--documenter-dark .is-white.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:focus,html.theme--documenter-dark .is-white.is-focused.textarea,html.theme--documenter-dark .is-white.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-white.textarea:active,html.theme--documenter-dark .is-white.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-white:active,html.theme--documenter-dark .is-white.is-active.textarea,html.theme--documenter-dark .is-white.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .is-black.textarea,html.theme--documenter-dark .is-black.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}html.theme--documenter-dark .is-black.textarea:focus,html.theme--documenter-dark .is-black.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:focus,html.theme--documenter-dark .is-black.is-focused.textarea,html.theme--documenter-dark .is-black.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-black.textarea:active,html.theme--documenter-dark .is-black.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-black:active,html.theme--documenter-dark .is-black.is-active.textarea,html.theme--documenter-dark .is-black.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .is-light.textarea,html.theme--documenter-dark .is-light.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light{border-color:#ecf0f1}html.theme--documenter-dark .is-light.textarea:focus,html.theme--documenter-dark .is-light.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:focus,html.theme--documenter-dark .is-light.is-focused.textarea,html.theme--documenter-dark .is-light.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-light.textarea:active,html.theme--documenter-dark .is-light.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-light:active,html.theme--documenter-dark .is-light.is-active.textarea,html.theme--documenter-dark .is-light.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .is-dark.textarea,html.theme--documenter-dark .content kbd.textarea,html.theme--documenter-dark .is-dark.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark,html.theme--documenter-dark .content kbd.input{border-color:#282f2f}html.theme--documenter-dark .is-dark.textarea:focus,html.theme--documenter-dark .content kbd.textarea:focus,html.theme--documenter-dark .is-dark.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:focus,html.theme--documenter-dark .content kbd.input:focus,html.theme--documenter-dark .is-dark.is-focused.textarea,html.theme--documenter-dark .content kbd.is-focused.textarea,html.theme--documenter-dark .is-dark.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .content kbd.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-focused,html.theme--documenter-dark .is-dark.textarea:active,html.theme--documenter-dark .content kbd.textarea:active,html.theme--documenter-dark .is-dark.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-dark:active,html.theme--documenter-dark .content kbd.input:active,html.theme--documenter-dark .is-dark.is-active.textarea,html.theme--documenter-dark .content kbd.is-active.textarea,html.theme--documenter-dark .is-dark.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .content kbd.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .is-primary.textarea,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink{border-color:#375a7f}html.theme--documenter-dark .is-primary.textarea:focus,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:focus,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:focus,html.theme--documenter-dark .is-primary.is-focused.textarea,html.theme--documenter-dark .docstring>section>a.is-focused.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .docstring>section>a.is-focused.input.docs-sourcelink,html.theme--documenter-dark .is-primary.textarea:active,html.theme--documenter-dark .docstring>section>a.textarea.docs-sourcelink:active,html.theme--documenter-dark .is-primary.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-primary:active,html.theme--documenter-dark .docstring>section>a.input.docs-sourcelink:active,html.theme--documenter-dark .is-primary.is-active.textarea,html.theme--documenter-dark .docstring>section>a.is-active.textarea.docs-sourcelink,html.theme--documenter-dark .is-primary.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active,html.theme--documenter-dark .docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .is-link.textarea,html.theme--documenter-dark .is-link.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link{border-color:#1abc9c}html.theme--documenter-dark .is-link.textarea:focus,html.theme--documenter-dark .is-link.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:focus,html.theme--documenter-dark .is-link.is-focused.textarea,html.theme--documenter-dark .is-link.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-link.textarea:active,html.theme--documenter-dark .is-link.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-link:active,html.theme--documenter-dark .is-link.is-active.textarea,html.theme--documenter-dark .is-link.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .is-info.textarea,html.theme--documenter-dark .is-info.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info{border-color:#024c7d}html.theme--documenter-dark .is-info.textarea:focus,html.theme--documenter-dark .is-info.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:focus,html.theme--documenter-dark .is-info.is-focused.textarea,html.theme--documenter-dark .is-info.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-info.textarea:active,html.theme--documenter-dark .is-info.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-info:active,html.theme--documenter-dark .is-info.is-active.textarea,html.theme--documenter-dark .is-info.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .is-success.textarea,html.theme--documenter-dark .is-success.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success{border-color:#008438}html.theme--documenter-dark .is-success.textarea:focus,html.theme--documenter-dark .is-success.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:focus,html.theme--documenter-dark .is-success.is-focused.textarea,html.theme--documenter-dark .is-success.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-success.textarea:active,html.theme--documenter-dark .is-success.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-success:active,html.theme--documenter-dark .is-success.is-active.textarea,html.theme--documenter-dark .is-success.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .is-warning.textarea,html.theme--documenter-dark .is-warning.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ad8100}html.theme--documenter-dark .is-warning.textarea:focus,html.theme--documenter-dark .is-warning.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:focus,html.theme--documenter-dark .is-warning.is-focused.textarea,html.theme--documenter-dark .is-warning.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-warning.textarea:active,html.theme--documenter-dark .is-warning.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-warning:active,html.theme--documenter-dark .is-warning.is-active.textarea,html.theme--documenter-dark .is-warning.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .is-danger.textarea,html.theme--documenter-dark .is-danger.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#9e1b0d}html.theme--documenter-dark .is-danger.textarea:focus,html.theme--documenter-dark .is-danger.input:focus,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:focus,html.theme--documenter-dark .is-danger.is-focused.textarea,html.theme--documenter-dark .is-danger.is-focused.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-focused,html.theme--documenter-dark .is-danger.textarea:active,html.theme--documenter-dark .is-danger.input:active,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-danger:active,html.theme--documenter-dark .is-danger.is-active.textarea,html.theme--documenter-dark .is-danger.is-active.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .is-small.textarea,html.theme--documenter-dark .is-small.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .is-medium.textarea,html.theme--documenter-dark .is-medium.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}html.theme--documenter-dark .is-large.textarea,html.theme--documenter-dark .is-large.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}html.theme--documenter-dark .is-fullwidth.textarea,html.theme--documenter-dark .is-fullwidth.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}html.theme--documenter-dark .is-inline.textarea,html.theme--documenter-dark .is-inline.input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}html.theme--documenter-dark .input.is-rounded,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}html.theme--documenter-dark .input.is-static,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}html.theme--documenter-dark .textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}html.theme--documenter-dark .textarea:not([rows]){max-height:40em;min-height:8em}html.theme--documenter-dark .textarea[rows]{height:initial}html.theme--documenter-dark .textarea.has-fixed-size{resize:none}html.theme--documenter-dark .radio,html.theme--documenter-dark .checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}html.theme--documenter-dark .radio input,html.theme--documenter-dark .checkbox input{cursor:pointer}html.theme--documenter-dark .radio:hover,html.theme--documenter-dark .checkbox:hover{color:#8c9b9d}html.theme--documenter-dark .radio[disabled],html.theme--documenter-dark .checkbox[disabled],fieldset[disabled] html.theme--documenter-dark .radio,fieldset[disabled] html.theme--documenter-dark .checkbox,html.theme--documenter-dark .radio input[disabled],html.theme--documenter-dark .checkbox input[disabled]{color:#fff;cursor:not-allowed}html.theme--documenter-dark .radio+.radio{margin-left:.5em}html.theme--documenter-dark .select{display:inline-block;max-width:100%;position:relative;vertical-align:top}html.theme--documenter-dark .select:not(.is-multiple){height:2.5em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading)::after{border-color:#1abc9c;right:1.125em;z-index:4}html.theme--documenter-dark .select.is-rounded select,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}html.theme--documenter-dark .select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}html.theme--documenter-dark .select select::-ms-expand{display:none}html.theme--documenter-dark .select select[disabled]:hover,fieldset[disabled] html.theme--documenter-dark .select select:hover{border-color:#282f2f}html.theme--documenter-dark .select select:not([multiple]){padding-right:2.5em}html.theme--documenter-dark .select select[multiple]{height:auto;padding:0}html.theme--documenter-dark .select select[multiple] option{padding:0.5em 1em}html.theme--documenter-dark .select:not(.is-multiple):not(.is-loading):hover::after{border-color:#8c9b9d}html.theme--documenter-dark .select.is-white:not(:hover)::after{border-color:#fff}html.theme--documenter-dark .select.is-white select{border-color:#fff}html.theme--documenter-dark .select.is-white select:hover,html.theme--documenter-dark .select.is-white select.is-hovered{border-color:#f2f2f2}html.theme--documenter-dark .select.is-white select:focus,html.theme--documenter-dark .select.is-white select.is-focused,html.theme--documenter-dark .select.is-white select:active,html.theme--documenter-dark .select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}html.theme--documenter-dark .select.is-black:not(:hover)::after{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select{border-color:#0a0a0a}html.theme--documenter-dark .select.is-black select:hover,html.theme--documenter-dark .select.is-black select.is-hovered{border-color:#000}html.theme--documenter-dark .select.is-black select:focus,html.theme--documenter-dark .select.is-black select.is-focused,html.theme--documenter-dark .select.is-black select:active,html.theme--documenter-dark .select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}html.theme--documenter-dark .select.is-light:not(:hover)::after{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select{border-color:#ecf0f1}html.theme--documenter-dark .select.is-light select:hover,html.theme--documenter-dark .select.is-light select.is-hovered{border-color:#dde4e6}html.theme--documenter-dark .select.is-light select:focus,html.theme--documenter-dark .select.is-light select.is-focused,html.theme--documenter-dark .select.is-light select:active,html.theme--documenter-dark .select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(236,240,241,0.25)}html.theme--documenter-dark .select.is-dark:not(:hover)::after,html.theme--documenter-dark .content kbd.select:not(:hover)::after{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select,html.theme--documenter-dark .content kbd.select select{border-color:#282f2f}html.theme--documenter-dark .select.is-dark select:hover,html.theme--documenter-dark .content kbd.select select:hover,html.theme--documenter-dark .select.is-dark select.is-hovered,html.theme--documenter-dark .content kbd.select select.is-hovered{border-color:#1d2122}html.theme--documenter-dark .select.is-dark select:focus,html.theme--documenter-dark .content kbd.select select:focus,html.theme--documenter-dark .select.is-dark select.is-focused,html.theme--documenter-dark .content kbd.select select.is-focused,html.theme--documenter-dark .select.is-dark select:active,html.theme--documenter-dark .content kbd.select select:active,html.theme--documenter-dark .select.is-dark select.is-active,html.theme--documenter-dark .content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(40,47,47,0.25)}html.theme--documenter-dark .select.is-primary:not(:hover)::after,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select{border-color:#375a7f}html.theme--documenter-dark .select.is-primary select:hover,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:hover,html.theme--documenter-dark .select.is-primary select.is-hovered,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#2f4d6d}html.theme--documenter-dark .select.is-primary select:focus,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:focus,html.theme--documenter-dark .select.is-primary select.is-focused,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-focused,html.theme--documenter-dark .select.is-primary select:active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select:active,html.theme--documenter-dark .select.is-primary select.is-active,html.theme--documenter-dark .docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(55,90,127,0.25)}html.theme--documenter-dark .select.is-link:not(:hover)::after{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select{border-color:#1abc9c}html.theme--documenter-dark .select.is-link select:hover,html.theme--documenter-dark .select.is-link select.is-hovered{border-color:#17a689}html.theme--documenter-dark .select.is-link select:focus,html.theme--documenter-dark .select.is-link select.is-focused,html.theme--documenter-dark .select.is-link select:active,html.theme--documenter-dark .select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(26,188,156,0.25)}html.theme--documenter-dark .select.is-info:not(:hover)::after{border-color:#024c7d}html.theme--documenter-dark .select.is-info select{border-color:#024c7d}html.theme--documenter-dark .select.is-info select:hover,html.theme--documenter-dark .select.is-info select.is-hovered{border-color:#023d64}html.theme--documenter-dark .select.is-info select:focus,html.theme--documenter-dark .select.is-info select.is-focused,html.theme--documenter-dark .select.is-info select:active,html.theme--documenter-dark .select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(2,76,125,0.25)}html.theme--documenter-dark .select.is-success:not(:hover)::after{border-color:#008438}html.theme--documenter-dark .select.is-success select{border-color:#008438}html.theme--documenter-dark .select.is-success select:hover,html.theme--documenter-dark .select.is-success select.is-hovered{border-color:#006b2d}html.theme--documenter-dark .select.is-success select:focus,html.theme--documenter-dark .select.is-success select.is-focused,html.theme--documenter-dark .select.is-success select:active,html.theme--documenter-dark .select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(0,132,56,0.25)}html.theme--documenter-dark .select.is-warning:not(:hover)::after{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select{border-color:#ad8100}html.theme--documenter-dark .select.is-warning select:hover,html.theme--documenter-dark .select.is-warning select.is-hovered{border-color:#946e00}html.theme--documenter-dark .select.is-warning select:focus,html.theme--documenter-dark .select.is-warning select.is-focused,html.theme--documenter-dark .select.is-warning select:active,html.theme--documenter-dark .select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(173,129,0,0.25)}html.theme--documenter-dark .select.is-danger:not(:hover)::after{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select{border-color:#9e1b0d}html.theme--documenter-dark .select.is-danger select:hover,html.theme--documenter-dark .select.is-danger select.is-hovered{border-color:#86170b}html.theme--documenter-dark .select.is-danger select:focus,html.theme--documenter-dark .select.is-danger select.is-focused,html.theme--documenter-dark .select.is-danger select:active,html.theme--documenter-dark .select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(158,27,13,0.25)}html.theme--documenter-dark .select.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.select{border-radius:3px;font-size:.75rem}html.theme--documenter-dark .select.is-medium{font-size:1.25rem}html.theme--documenter-dark .select.is-large{font-size:1.5rem}html.theme--documenter-dark .select.is-disabled::after{border-color:#fff !important;opacity:0.5}html.theme--documenter-dark .select.is-fullwidth{width:100%}html.theme--documenter-dark .select.is-fullwidth select{width:100%}html.theme--documenter-dark .select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}html.theme--documenter-dark .select.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .select.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .select.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}html.theme--documenter-dark .file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:hover .file-cta,html.theme--documenter-dark .file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-white:focus .file-cta,html.theme--documenter-dark .file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}html.theme--documenter-dark .file.is-white:active .file-cta,html.theme--documenter-dark .file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}html.theme--documenter-dark .file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:hover .file-cta,html.theme--documenter-dark .file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-black:focus .file-cta,html.theme--documenter-dark .file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}html.theme--documenter-dark .file.is-black:active .file-cta,html.theme--documenter-dark .file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-light .file-cta{background-color:#ecf0f1;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:hover .file-cta,html.theme--documenter-dark .file.is-light.is-hovered .file-cta{background-color:#e5eaec;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:focus .file-cta,html.theme--documenter-dark .file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(236,240,241,0.25);color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-light:active .file-cta,html.theme--documenter-dark .file.is-light.is-active .file-cta{background-color:#dde4e6;border-color:transparent;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .file.is-dark .file-cta,html.theme--documenter-dark .content kbd.file .file-cta{background-color:#282f2f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:hover .file-cta,html.theme--documenter-dark .content kbd.file:hover .file-cta,html.theme--documenter-dark .file.is-dark.is-hovered .file-cta,html.theme--documenter-dark .content kbd.file.is-hovered .file-cta{background-color:#232829;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-dark:focus .file-cta,html.theme--documenter-dark .content kbd.file:focus .file-cta,html.theme--documenter-dark .file.is-dark.is-focused .file-cta,html.theme--documenter-dark .content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(40,47,47,0.25);color:#fff}html.theme--documenter-dark .file.is-dark:active .file-cta,html.theme--documenter-dark .content kbd.file:active .file-cta,html.theme--documenter-dark .file.is-dark.is-active .file-cta,html.theme--documenter-dark .content kbd.file.is-active .file-cta{background-color:#1d2122;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink .file-cta{background-color:#375a7f;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:hover .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:hover .file-cta,html.theme--documenter-dark .file.is-primary.is-hovered .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#335476;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-primary:focus .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:focus .file-cta,html.theme--documenter-dark .file.is-primary.is-focused .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(55,90,127,0.25);color:#fff}html.theme--documenter-dark .file.is-primary:active .file-cta,html.theme--documenter-dark .docstring>section>a.file.docs-sourcelink:active .file-cta,html.theme--documenter-dark .file.is-primary.is-active .file-cta,html.theme--documenter-dark .docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#2f4d6d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link .file-cta{background-color:#1abc9c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:hover .file-cta,html.theme--documenter-dark .file.is-link.is-hovered .file-cta{background-color:#18b193;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-link:focus .file-cta,html.theme--documenter-dark .file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(26,188,156,0.25);color:#fff}html.theme--documenter-dark .file.is-link:active .file-cta,html.theme--documenter-dark .file.is-link.is-active .file-cta{background-color:#17a689;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info .file-cta{background-color:#024c7d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:hover .file-cta,html.theme--documenter-dark .file.is-info.is-hovered .file-cta{background-color:#024470;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-info:focus .file-cta,html.theme--documenter-dark .file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(2,76,125,0.25);color:#fff}html.theme--documenter-dark .file.is-info:active .file-cta,html.theme--documenter-dark .file.is-info.is-active .file-cta{background-color:#023d64;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success .file-cta{background-color:#008438;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:hover .file-cta,html.theme--documenter-dark .file.is-success.is-hovered .file-cta{background-color:#073;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-success:focus .file-cta,html.theme--documenter-dark .file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(0,132,56,0.25);color:#fff}html.theme--documenter-dark .file.is-success:active .file-cta,html.theme--documenter-dark .file.is-success.is-active .file-cta{background-color:#006b2d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning .file-cta{background-color:#ad8100;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:hover .file-cta,html.theme--documenter-dark .file.is-warning.is-hovered .file-cta{background-color:#a07700;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-warning:focus .file-cta,html.theme--documenter-dark .file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(173,129,0,0.25);color:#fff}html.theme--documenter-dark .file.is-warning:active .file-cta,html.theme--documenter-dark .file.is-warning.is-active .file-cta{background-color:#946e00;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger .file-cta{background-color:#9e1b0d;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:hover .file-cta,html.theme--documenter-dark .file.is-danger.is-hovered .file-cta{background-color:#92190c;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-danger:focus .file-cta,html.theme--documenter-dark .file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(158,27,13,0.25);color:#fff}html.theme--documenter-dark .file.is-danger:active .file-cta,html.theme--documenter-dark .file.is-danger.is-active .file-cta{background-color:#86170b;border-color:transparent;color:#fff}html.theme--documenter-dark .file.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}html.theme--documenter-dark .file.is-normal{font-size:1rem}html.theme--documenter-dark .file.is-medium{font-size:1.25rem}html.theme--documenter-dark .file.is-medium .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-large{font-size:1.5rem}html.theme--documenter-dark .file.is-large .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .file.has-name.is-empty .file-cta{border-radius:.4em}html.theme--documenter-dark .file.has-name.is-empty .file-name{display:none}html.theme--documenter-dark .file.is-boxed .file-label{flex-direction:column}html.theme--documenter-dark .file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}html.theme--documenter-dark .file.is-boxed .file-name{border-width:0 1px 1px}html.theme--documenter-dark .file.is-boxed .file-icon{height:1.5em;width:1.5em}html.theme--documenter-dark .file.is-boxed .file-icon .fa{font-size:21px}html.theme--documenter-dark .file.is-boxed.is-small .file-icon .fa,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}html.theme--documenter-dark .file.is-boxed.is-medium .file-icon .fa{font-size:28px}html.theme--documenter-dark .file.is-boxed.is-large .file-icon .fa{font-size:35px}html.theme--documenter-dark .file.is-boxed.has-name .file-cta{border-radius:.4em .4em 0 0}html.theme--documenter-dark .file.is-boxed.has-name .file-name{border-radius:0 0 .4em .4em;border-width:0 1px 1px}html.theme--documenter-dark .file.is-centered{justify-content:center}html.theme--documenter-dark .file.is-fullwidth .file-label{width:100%}html.theme--documenter-dark .file.is-fullwidth .file-name{flex-grow:1;max-width:none}html.theme--documenter-dark .file.is-right{justify-content:flex-end}html.theme--documenter-dark .file.is-right .file-cta{border-radius:0 .4em .4em 0}html.theme--documenter-dark .file.is-right .file-name{border-radius:.4em 0 0 .4em;border-width:1px 0 1px 1px;order:-1}html.theme--documenter-dark .file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}html.theme--documenter-dark .file-label:hover .file-cta{background-color:#232829;color:#f2f2f2}html.theme--documenter-dark .file-label:hover .file-name{border-color:#596668}html.theme--documenter-dark .file-label:active .file-cta{background-color:#1d2122;color:#f2f2f2}html.theme--documenter-dark .file-label:active .file-name{border-color:#535f61}html.theme--documenter-dark .file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}html.theme--documenter-dark .file-cta,html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-radius:.4em;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}html.theme--documenter-dark .file-cta{background-color:#282f2f;color:#fff}html.theme--documenter-dark .file-name{border-color:#5e6d6f;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}html.theme--documenter-dark .file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}html.theme--documenter-dark .file-icon .fa{font-size:14px}html.theme--documenter-dark .label{color:#f2f2f2;display:block;font-size:1rem;font-weight:700}html.theme--documenter-dark .label:not(:last-child){margin-bottom:0.5em}html.theme--documenter-dark .label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}html.theme--documenter-dark .label.is-medium{font-size:1.25rem}html.theme--documenter-dark .label.is-large{font-size:1.5rem}html.theme--documenter-dark .help{display:block;font-size:.75rem;margin-top:0.25rem}html.theme--documenter-dark .help.is-white{color:#fff}html.theme--documenter-dark .help.is-black{color:#0a0a0a}html.theme--documenter-dark .help.is-light{color:#ecf0f1}html.theme--documenter-dark .help.is-dark,html.theme--documenter-dark .content kbd.help{color:#282f2f}html.theme--documenter-dark .help.is-primary,html.theme--documenter-dark .docstring>section>a.help.docs-sourcelink{color:#375a7f}html.theme--documenter-dark .help.is-link{color:#1abc9c}html.theme--documenter-dark .help.is-info{color:#024c7d}html.theme--documenter-dark .help.is-success{color:#008438}html.theme--documenter-dark .help.is-warning{color:#ad8100}html.theme--documenter-dark .help.is-danger{color:#9e1b0d}html.theme--documenter-dark .field:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.has-addons{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.has-addons .control:not(:last-child){margin-right:-1px}html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .button,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .button,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,html.theme--documenter-dark .field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]),html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]){z-index:3}html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .button.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .button:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .button.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark #documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):focus:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-focused:not([disabled]):hover,html.theme--documenter-dark .field.has-addons .control .select select:not([disabled]):active:hover,html.theme--documenter-dark .field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}html.theme--documenter-dark .field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.has-addons.has-addons-centered{justify-content:center}html.theme--documenter-dark .field.has-addons.has-addons-right{justify-content:flex-end}html.theme--documenter-dark .field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .field.is-grouped{display:flex;justify-content:flex-start}html.theme--documenter-dark .field.is-grouped>.control{flex-shrink:0}html.theme--documenter-dark .field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .field.is-grouped.is-grouped-centered{justify-content:center}html.theme--documenter-dark .field.is-grouped.is-grouped-right{justify-content:flex-end}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline{flex-wrap:wrap}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:last-child,html.theme--documenter-dark .field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}html.theme--documenter-dark .field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field.is-horizontal{display:flex}}html.theme--documenter-dark .field-label .label{font-size:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}html.theme--documenter-dark .field-label.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-normal{padding-top:0.375em}html.theme--documenter-dark .field-label.is-medium{font-size:1.25rem;padding-top:0.375em}html.theme--documenter-dark .field-label.is-large{font-size:1.5rem;padding-top:0.375em}}html.theme--documenter-dark .field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{html.theme--documenter-dark .field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}html.theme--documenter-dark .field-body .field{margin-bottom:0}html.theme--documenter-dark .field-body>.field{flex-shrink:1}html.theme--documenter-dark .field-body>.field:not(.is-narrow){flex-grow:1}html.theme--documenter-dark .field-body>.field:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}html.theme--documenter-dark .control.has-icons-left .input:focus~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-left .select:focus~.icon,html.theme--documenter-dark .control.has-icons-right .input:focus~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,html.theme--documenter-dark .control.has-icons-right .select:focus~.icon{color:#282f2f}html.theme--documenter-dark .control.has-icons-left .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-small~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-small~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-small~.icon{font-size:.75rem}html.theme--documenter-dark .control.has-icons-left .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}html.theme--documenter-dark .control.has-icons-left .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-left .select.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,html.theme--documenter-dark .control.has-icons-right .select.is-large~.icon{font-size:1.5rem}html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon{color:#5e6d6f;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}html.theme--documenter-dark .control.has-icons-left .input,html.theme--documenter-dark .control.has-icons-left #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-left form.docs-search>input,html.theme--documenter-dark .control.has-icons-left .select select{padding-left:2.5em}html.theme--documenter-dark .control.has-icons-left .icon.is-left{left:0}html.theme--documenter-dark .control.has-icons-right .input,html.theme--documenter-dark .control.has-icons-right #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-icons-right form.docs-search>input,html.theme--documenter-dark .control.has-icons-right .select select{padding-right:2.5em}html.theme--documenter-dark .control.has-icons-right .icon.is-right{right:0}html.theme--documenter-dark .control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}html.theme--documenter-dark .control.is-loading.is-small:after,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}html.theme--documenter-dark .control.is-loading.is-medium:after{font-size:1.25rem}html.theme--documenter-dark .control.is-loading.is-large:after{font-size:1.5rem}html.theme--documenter-dark .breadcrumb{font-size:1rem;white-space:nowrap}html.theme--documenter-dark .breadcrumb a{align-items:center;color:#1abc9c;display:flex;justify-content:center;padding:0 .75em}html.theme--documenter-dark .breadcrumb a:hover{color:#1dd2af}html.theme--documenter-dark .breadcrumb li{align-items:center;display:flex}html.theme--documenter-dark .breadcrumb li:first-child a{padding-left:0}html.theme--documenter-dark .breadcrumb li.is-active a{color:#f2f2f2;cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb li+li::before{color:#8c9b9d;content:"\0002f"}html.theme--documenter-dark .breadcrumb ul,html.theme--documenter-dark .breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}html.theme--documenter-dark .breadcrumb .icon:first-child{margin-right:.5em}html.theme--documenter-dark .breadcrumb .icon:last-child{margin-left:.5em}html.theme--documenter-dark .breadcrumb.is-centered ol,html.theme--documenter-dark .breadcrumb.is-centered ul{justify-content:center}html.theme--documenter-dark .breadcrumb.is-right ol,html.theme--documenter-dark .breadcrumb.is-right ul{justify-content:flex-end}html.theme--documenter-dark .breadcrumb.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}html.theme--documenter-dark .breadcrumb.is-medium{font-size:1.25rem}html.theme--documenter-dark .breadcrumb.is-large{font-size:1.5rem}html.theme--documenter-dark .breadcrumb.has-arrow-separator li+li::before{content:"\02192"}html.theme--documenter-dark .breadcrumb.has-bullet-separator li+li::before{content:"\02022"}html.theme--documenter-dark .breadcrumb.has-dot-separator li+li::before{content:"\000b7"}html.theme--documenter-dark .breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}html.theme--documenter-dark .card{background-color:#fff;border-radius:.25rem;box-shadow:#171717;color:#fff;max-width:100%;position:relative}html.theme--documenter-dark .card-footer:first-child,html.theme--documenter-dark .card-content:first-child,html.theme--documenter-dark .card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-footer:last-child,html.theme--documenter-dark .card-content:last-child,html.theme--documenter-dark .card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}html.theme--documenter-dark .card-header-title{align-items:center;color:#f2f2f2;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}html.theme--documenter-dark .card-header-title.is-centered{justify-content:center}html.theme--documenter-dark .card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}html.theme--documenter-dark .card-image{display:block;position:relative}html.theme--documenter-dark .card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}html.theme--documenter-dark .card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}html.theme--documenter-dark .card-content{background-color:rgba(0,0,0,0);padding:1.5rem}html.theme--documenter-dark .card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}html.theme--documenter-dark .card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}html.theme--documenter-dark .card-footer-item:not(:last-child){border-right:1px solid #ededed}html.theme--documenter-dark .card .media:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .dropdown{display:inline-flex;position:relative;vertical-align:top}html.theme--documenter-dark .dropdown.is-active .dropdown-menu,html.theme--documenter-dark .dropdown.is-hoverable:hover .dropdown-menu{display:block}html.theme--documenter-dark .dropdown.is-right .dropdown-menu{left:auto;right:0}html.theme--documenter-dark .dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}html.theme--documenter-dark .dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .dropdown-content{background-color:#282f2f;border-radius:.4em;box-shadow:#171717;padding-bottom:.5rem;padding-top:.5rem}html.theme--documenter-dark .dropdown-item{color:#fff;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}html.theme--documenter-dark a.dropdown-item,html.theme--documenter-dark button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}html.theme--documenter-dark a.dropdown-item:hover,html.theme--documenter-dark button.dropdown-item:hover{background-color:#282f2f;color:#0a0a0a}html.theme--documenter-dark a.dropdown-item.is-active,html.theme--documenter-dark button.dropdown-item.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}html.theme--documenter-dark .level{align-items:center;justify-content:space-between}html.theme--documenter-dark .level code{border-radius:.4em}html.theme--documenter-dark .level img{display:inline-block;vertical-align:top}html.theme--documenter-dark .level.is-mobile{display:flex}html.theme--documenter-dark .level.is-mobile .level-left,html.theme--documenter-dark .level.is-mobile .level-right{display:flex}html.theme--documenter-dark .level.is-mobile .level-left+.level-right{margin-top:0}html.theme--documenter-dark .level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}html.theme--documenter-dark .level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level{display:flex}html.theme--documenter-dark .level>.level-item:not(.is-narrow){flex-grow:1}}html.theme--documenter-dark .level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}html.theme--documenter-dark .level-item .title,html.theme--documenter-dark .level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){html.theme--documenter-dark .level-item:not(:last-child){margin-bottom:.75rem}}html.theme--documenter-dark .level-left,html.theme--documenter-dark .level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .level-left .level-item.is-flexible,html.theme--documenter-dark .level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left .level-item:not(:last-child),html.theme--documenter-dark .level-right .level-item:not(:last-child){margin-right:.75rem}}html.theme--documenter-dark .level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){html.theme--documenter-dark .level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-left{display:flex}}html.theme--documenter-dark .level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{html.theme--documenter-dark .level-right{display:flex}}html.theme--documenter-dark .media{align-items:flex-start;display:flex;text-align:inherit}html.theme--documenter-dark .media .content:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .media .media{border-top:1px solid rgba(94,109,111,0.5);display:flex;padding-top:.75rem}html.theme--documenter-dark .media .media .content:not(:last-child),html.theme--documenter-dark .media .media .control:not(:last-child){margin-bottom:.5rem}html.theme--documenter-dark .media .media .media{padding-top:.5rem}html.theme--documenter-dark .media .media .media+.media{margin-top:.5rem}html.theme--documenter-dark .media+.media{border-top:1px solid rgba(94,109,111,0.5);margin-top:1rem;padding-top:1rem}html.theme--documenter-dark .media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}html.theme--documenter-dark .media-left,html.theme--documenter-dark .media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}html.theme--documenter-dark .media-left{margin-right:1rem}html.theme--documenter-dark .media-right{margin-left:1rem}html.theme--documenter-dark .media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){html.theme--documenter-dark .media-content{overflow-x:auto}}html.theme--documenter-dark .menu{font-size:1rem}html.theme--documenter-dark .menu.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}html.theme--documenter-dark .menu.is-medium{font-size:1.25rem}html.theme--documenter-dark .menu.is-large{font-size:1.5rem}html.theme--documenter-dark .menu-list{line-height:1.25}html.theme--documenter-dark .menu-list a{border-radius:3px;color:#fff;display:block;padding:0.5em 0.75em}html.theme--documenter-dark .menu-list a:hover{background-color:#282f2f;color:#f2f2f2}html.theme--documenter-dark .menu-list a.is-active{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .menu-list li ul{border-left:1px solid #5e6d6f;margin:.75em;padding-left:.75em}html.theme--documenter-dark .menu-label{color:#fff;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}html.theme--documenter-dark .menu-label:not(:first-child){margin-top:1em}html.theme--documenter-dark .menu-label:not(:last-child){margin-bottom:1em}html.theme--documenter-dark .message{background-color:#282f2f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .message strong{color:currentColor}html.theme--documenter-dark .message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}html.theme--documenter-dark .message.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}html.theme--documenter-dark .message.is-medium{font-size:1.25rem}html.theme--documenter-dark .message.is-large{font-size:1.5rem}html.theme--documenter-dark .message.is-white{background-color:#fff}html.theme--documenter-dark .message.is-white .message-header{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .message.is-white .message-body{border-color:#fff}html.theme--documenter-dark .message.is-black{background-color:#fafafa}html.theme--documenter-dark .message.is-black .message-header{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .message.is-black .message-body{border-color:#0a0a0a}html.theme--documenter-dark .message.is-light{background-color:#f9fafb}html.theme--documenter-dark .message.is-light .message-header{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .message.is-light .message-body{border-color:#ecf0f1}html.theme--documenter-dark .message.is-dark,html.theme--documenter-dark .content kbd.message{background-color:#f9fafa}html.theme--documenter-dark .message.is-dark .message-header,html.theme--documenter-dark .content kbd.message .message-header{background-color:#282f2f;color:#fff}html.theme--documenter-dark .message.is-dark .message-body,html.theme--documenter-dark .content kbd.message .message-body{border-color:#282f2f}html.theme--documenter-dark .message.is-primary,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink{background-color:#f1f5f9}html.theme--documenter-dark .message.is-primary .message-header,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-header{background-color:#375a7f;color:#fff}html.theme--documenter-dark .message.is-primary .message-body,html.theme--documenter-dark .docstring>section>a.message.docs-sourcelink .message-body{border-color:#375a7f;color:#4d7eb2}html.theme--documenter-dark .message.is-link{background-color:#edfdf9}html.theme--documenter-dark .message.is-link .message-header{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .message.is-link .message-body{border-color:#1abc9c;color:#15987e}html.theme--documenter-dark .message.is-info{background-color:#ebf7ff}html.theme--documenter-dark .message.is-info .message-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .message.is-info .message-body{border-color:#024c7d;color:#0e9dfb}html.theme--documenter-dark .message.is-success{background-color:#ebfff3}html.theme--documenter-dark .message.is-success .message-header{background-color:#008438;color:#fff}html.theme--documenter-dark .message.is-success .message-body{border-color:#008438;color:#00eb64}html.theme--documenter-dark .message.is-warning{background-color:#fffaeb}html.theme--documenter-dark .message.is-warning .message-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .message.is-warning .message-body{border-color:#ad8100;color:#d19c00}html.theme--documenter-dark .message.is-danger{background-color:#fdeeec}html.theme--documenter-dark .message.is-danger .message-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .message.is-danger .message-body{border-color:#9e1b0d;color:#ec311d}html.theme--documenter-dark .message-header{align-items:center;background-color:#fff;border-radius:.4em .4em 0 0;color:rgba(0,0,0,0.7);display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}html.theme--documenter-dark .message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}html.theme--documenter-dark .message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}html.theme--documenter-dark .message-body{border-color:#5e6d6f;border-radius:.4em;border-style:solid;border-width:0 0 0 4px;color:#fff;padding:1.25em 1.5em}html.theme--documenter-dark .message-body code,html.theme--documenter-dark .message-body pre{background-color:#fff}html.theme--documenter-dark .message-body pre code{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}html.theme--documenter-dark .modal.is-active{display:flex}html.theme--documenter-dark .modal-background{background-color:rgba(10,10,10,0.86)}html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){html.theme--documenter-dark .modal-content,html.theme--documenter-dark .modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}html.theme--documenter-dark .modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}html.theme--documenter-dark .modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}html.theme--documenter-dark .modal-card-head,html.theme--documenter-dark .modal-card-foot{align-items:center;background-color:#282f2f;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}html.theme--documenter-dark .modal-card-head{border-bottom:1px solid #5e6d6f;border-top-left-radius:8px;border-top-right-radius:8px}html.theme--documenter-dark .modal-card-title{color:#f2f2f2;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}html.theme--documenter-dark .modal-card-foot{border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid #5e6d6f}html.theme--documenter-dark .modal-card-foot .button:not(:last-child){margin-right:.5em}html.theme--documenter-dark .modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}html.theme--documenter-dark .navbar{background-color:#375a7f;min-height:4rem;position:relative;z-index:30}html.theme--documenter-dark .navbar.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-white .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-white .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}html.theme--documenter-dark .navbar.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-black .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-black .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}html.theme--documenter-dark .navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}html.theme--documenter-dark .navbar.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-light .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-light .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}}html.theme--documenter-dark .navbar.is-dark,html.theme--documenter-dark .content kbd.navbar{background-color:#282f2f;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-brand .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-burger,html.theme--documenter-dark .content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-dark .navbar-start>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-end>.navbar-item,html.theme--documenter-dark .content kbd.navbar .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:focus,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link:hover,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-start .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-dark .navbar-end .navbar-link::after,html.theme--documenter-dark .content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1d2122;color:#fff}html.theme--documenter-dark .navbar.is-dark .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#282f2f;color:#fff}}html.theme--documenter-dark .navbar.is-primary,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-brand .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-burger,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-primary .navbar-start>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-end>.navbar-item,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:focus,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-start .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-primary .navbar-end .navbar-link::after,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#375a7f;color:#fff}}html.theme--documenter-dark .navbar.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-link .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-link .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#17a689;color:#fff}html.theme--documenter-dark .navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c;color:#fff}}html.theme--documenter-dark .navbar.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-info .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-info .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#023d64;color:#fff}html.theme--documenter-dark .navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#024c7d;color:#fff}}html.theme--documenter-dark .navbar.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-success .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-success .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#006b2d;color:#fff}html.theme--documenter-dark .navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#008438;color:#fff}}html.theme--documenter-dark .navbar.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-warning .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-warning .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#946e00;color:#fff}html.theme--documenter-dark .navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ad8100;color:#fff}}html.theme--documenter-dark .navbar.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar.is-danger .navbar-start>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-end>.navbar-item,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link{color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end>a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:focus,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link:hover,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-start .navbar-link::after,html.theme--documenter-dark .navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#86170b;color:#fff}html.theme--documenter-dark .navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#9e1b0d;color:#fff}}html.theme--documenter-dark .navbar>.container{align-items:stretch;display:flex;min-height:4rem;width:100%}html.theme--documenter-dark .navbar.has-shadow{box-shadow:0 2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-bottom,html.theme--documenter-dark .navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #282f2f}html.theme--documenter-dark .navbar.is-fixed-top{top:0}html.theme--documenter-dark html.has-navbar-fixed-top,html.theme--documenter-dark body.has-navbar-fixed-top{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom,html.theme--documenter-dark body.has-navbar-fixed-bottom{padding-bottom:4rem}html.theme--documenter-dark .navbar-brand,html.theme--documenter-dark .navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:4rem}html.theme--documenter-dark .navbar-brand a.navbar-item:focus,html.theme--documenter-dark .navbar-brand a.navbar-item:hover{background-color:transparent}html.theme--documenter-dark .navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}html.theme--documenter-dark .navbar-burger{color:#fff;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:4rem;position:relative;width:4rem;margin-left:auto}html.theme--documenter-dark .navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}html.theme--documenter-dark .navbar-burger span:nth-child(1){top:calc(50% - 6px)}html.theme--documenter-dark .navbar-burger span:nth-child(2){top:calc(50% - 1px)}html.theme--documenter-dark .navbar-burger span:nth-child(3){top:calc(50% + 4px)}html.theme--documenter-dark .navbar-burger:hover{background-color:rgba(0,0,0,0.05)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(2){opacity:0}html.theme--documenter-dark .navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}html.theme--documenter-dark .navbar-menu{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{color:#fff;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}html.theme--documenter-dark .navbar-item .icon:only-child,html.theme--documenter-dark .navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}html.theme--documenter-dark a.navbar-item,html.theme--documenter-dark .navbar-link{cursor:pointer}html.theme--documenter-dark a.navbar-item:focus,html.theme--documenter-dark a.navbar-item:focus-within,html.theme--documenter-dark a.navbar-item:hover,html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link:focus,html.theme--documenter-dark .navbar-link:focus-within,html.theme--documenter-dark .navbar-link:hover,html.theme--documenter-dark .navbar-link.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-item{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .navbar-item img{max-height:1.75rem}html.theme--documenter-dark .navbar-item.has-dropdown{padding:0}html.theme--documenter-dark .navbar-item.is-expanded{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-item.is-tab{border-bottom:1px solid transparent;min-height:4rem;padding-bottom:calc(0.5rem - 1px)}html.theme--documenter-dark .navbar-item.is-tab:focus,html.theme--documenter-dark .navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c}html.theme--documenter-dark .navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#1abc9c;border-bottom-style:solid;border-bottom-width:3px;color:#1abc9c;padding-bottom:calc(0.5rem - 3px)}html.theme--documenter-dark .navbar-content{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .navbar-link:not(.is-arrowless){padding-right:2.5em}html.theme--documenter-dark .navbar-link:not(.is-arrowless)::after{border-color:#fff;margin-top:-0.375em;right:1.125em}html.theme--documenter-dark .navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}html.theme--documenter-dark .navbar-divider{background-color:rgba(0,0,0,0.2);border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar>.container{display:block}html.theme--documenter-dark .navbar-brand .navbar-item,html.theme--documenter-dark .navbar-tabs .navbar-item{align-items:center;display:flex}html.theme--documenter-dark .navbar-link::after{display:none}html.theme--documenter-dark .navbar-menu{background-color:#375a7f;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}html.theme--documenter-dark .navbar-menu.is-active{display:block}html.theme--documenter-dark .navbar.is-fixed-bottom-touch,html.theme--documenter-dark .navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-touch{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-touch{top:0}html.theme--documenter-dark .navbar.is-fixed-top .navbar-menu,html.theme--documenter-dark .navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 4rem);overflow:auto}html.theme--documenter-dark html.has-navbar-fixed-top-touch,html.theme--documenter-dark body.has-navbar-fixed-top-touch{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-touch,html.theme--documenter-dark body.has-navbar-fixed-bottom-touch{padding-bottom:4rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .navbar,html.theme--documenter-dark .navbar-menu,html.theme--documenter-dark .navbar-start,html.theme--documenter-dark .navbar-end{align-items:stretch;display:flex}html.theme--documenter-dark .navbar{min-height:4rem}html.theme--documenter-dark .navbar.is-spaced{padding:1rem 2rem}html.theme--documenter-dark .navbar.is-spaced .navbar-start,html.theme--documenter-dark .navbar.is-spaced .navbar-end{align-items:center}html.theme--documenter-dark .navbar.is-spaced a.navbar-item,html.theme--documenter-dark .navbar.is-spaced .navbar-link{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent a.navbar-item:hover,html.theme--documenter-dark .navbar.is-transparent a.navbar-item.is-active,html.theme--documenter-dark .navbar.is-transparent .navbar-link:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-link:hover,html.theme--documenter-dark .navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,html.theme--documenter-dark .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}html.theme--documenter-dark .navbar-burger{display:none}html.theme--documenter-dark .navbar-item,html.theme--documenter-dark .navbar-link{align-items:center;display:flex}html.theme--documenter-dark .navbar-item.has-dropdown{align-items:stretch}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}html.theme--documenter-dark .navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:1px solid rgba(0,0,0,0.2);border-radius:8px 8px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown,html.theme--documenter-dark .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}html.theme--documenter-dark .navbar-menu{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .navbar-start{justify-content:flex-start;margin-right:auto}html.theme--documenter-dark .navbar-end{justify-content:flex-end;margin-left:auto}html.theme--documenter-dark .navbar-dropdown{background-color:#375a7f;border-bottom-left-radius:8px;border-bottom-right-radius:8px;border-top:1px solid rgba(0,0,0,0.2);box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}html.theme--documenter-dark .navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}html.theme--documenter-dark .navbar-dropdown a.navbar-item{padding-right:3rem}html.theme--documenter-dark .navbar-dropdown a.navbar-item:focus,html.theme--documenter-dark .navbar-dropdown a.navbar-item:hover{background-color:rgba(0,0,0,0);color:#dbdee0}html.theme--documenter-dark .navbar-dropdown a.navbar-item.is-active{background-color:rgba(0,0,0,0);color:#1abc9c}.navbar.is-spaced html.theme--documenter-dark .navbar-dropdown,html.theme--documenter-dark .navbar-dropdown.is-boxed{border-radius:8px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}html.theme--documenter-dark .navbar-dropdown.is-right{left:auto;right:0}html.theme--documenter-dark .navbar-divider{display:block}html.theme--documenter-dark .navbar>.container .navbar-brand,html.theme--documenter-dark .container>.navbar .navbar-brand{margin-left:-.75rem}html.theme--documenter-dark .navbar>.container .navbar-menu,html.theme--documenter-dark .container>.navbar .navbar-menu{margin-right:-.75rem}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop,html.theme--documenter-dark .navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop{bottom:0}html.theme--documenter-dark .navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}html.theme--documenter-dark .navbar.is-fixed-top-desktop{top:0}html.theme--documenter-dark html.has-navbar-fixed-top-desktop,html.theme--documenter-dark body.has-navbar-fixed-top-desktop{padding-top:4rem}html.theme--documenter-dark html.has-navbar-fixed-bottom-desktop,html.theme--documenter-dark body.has-navbar-fixed-bottom-desktop{padding-bottom:4rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-top,html.theme--documenter-dark body.has-spaced-navbar-fixed-top{padding-top:6rem}html.theme--documenter-dark html.has-spaced-navbar-fixed-bottom,html.theme--documenter-dark body.has-spaced-navbar-fixed-bottom{padding-bottom:6rem}html.theme--documenter-dark a.navbar-item.is-active,html.theme--documenter-dark .navbar-link.is-active{color:#1abc9c}html.theme--documenter-dark a.navbar-item.is-active:not(:focus):not(:hover),html.theme--documenter-dark .navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}html.theme--documenter-dark .navbar-item.has-dropdown:focus .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown:hover .navbar-link,html.theme--documenter-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:rgba(0,0,0,0)}}html.theme--documenter-dark .hero.is-fullheight-with-navbar{min-height:calc(100vh - 4rem)}html.theme--documenter-dark .pagination{font-size:1rem;margin:-.25rem}html.theme--documenter-dark .pagination.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}html.theme--documenter-dark .pagination.is-medium{font-size:1.25rem}html.theme--documenter-dark .pagination.is-large{font-size:1.5rem}html.theme--documenter-dark .pagination.is-rounded .pagination-previous,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,html.theme--documenter-dark .pagination.is-rounded .pagination-next,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}html.theme--documenter-dark .pagination.is-rounded .pagination-link,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}html.theme--documenter-dark .pagination,html.theme--documenter-dark .pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link{border-color:#5e6d6f;color:#1abc9c;min-width:2.5em}html.theme--documenter-dark .pagination-previous:hover,html.theme--documenter-dark .pagination-next:hover,html.theme--documenter-dark .pagination-link:hover{border-color:#8c9b9d;color:#1dd2af}html.theme--documenter-dark .pagination-previous:focus,html.theme--documenter-dark .pagination-next:focus,html.theme--documenter-dark .pagination-link:focus{border-color:#8c9b9d}html.theme--documenter-dark .pagination-previous:active,html.theme--documenter-dark .pagination-next:active,html.theme--documenter-dark .pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}html.theme--documenter-dark .pagination-previous[disabled],html.theme--documenter-dark .pagination-previous.is-disabled,html.theme--documenter-dark .pagination-next[disabled],html.theme--documenter-dark .pagination-next.is-disabled,html.theme--documenter-dark .pagination-link[disabled],html.theme--documenter-dark .pagination-link.is-disabled{background-color:#5e6d6f;border-color:#5e6d6f;box-shadow:none;color:#fff;opacity:0.5}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}html.theme--documenter-dark .pagination-link.is-current{background-color:#1abc9c;border-color:#1abc9c;color:#fff}html.theme--documenter-dark .pagination-ellipsis{color:#8c9b9d;pointer-events:none}html.theme--documenter-dark .pagination-list{flex-wrap:wrap}html.theme--documenter-dark .pagination-list li{list-style:none}@media screen and (max-width: 768px){html.theme--documenter-dark .pagination{flex-wrap:wrap}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-ellipsis{margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination-previous{order:2}html.theme--documenter-dark .pagination-next{order:3}html.theme--documenter-dark .pagination{justify-content:space-between;margin-bottom:0;margin-top:0}html.theme--documenter-dark .pagination.is-centered .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-centered .pagination-list{justify-content:center;order:2}html.theme--documenter-dark .pagination.is-centered .pagination-next{order:3}html.theme--documenter-dark .pagination.is-right .pagination-previous{order:1}html.theme--documenter-dark .pagination.is-right .pagination-next{order:2}html.theme--documenter-dark .pagination.is-right .pagination-list{justify-content:flex-end;order:3}}html.theme--documenter-dark .panel{border-radius:8px;box-shadow:#171717;font-size:1rem}html.theme--documenter-dark .panel:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}html.theme--documenter-dark .panel.is-white .panel-block.is-active .panel-icon{color:#fff}html.theme--documenter-dark .panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}html.theme--documenter-dark .panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}html.theme--documenter-dark .panel.is-light .panel-heading{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .panel.is-light .panel-tabs a.is-active{border-bottom-color:#ecf0f1}html.theme--documenter-dark .panel.is-light .panel-block.is-active .panel-icon{color:#ecf0f1}html.theme--documenter-dark .panel.is-dark .panel-heading,html.theme--documenter-dark .content kbd.panel .panel-heading{background-color:#282f2f;color:#fff}html.theme--documenter-dark .panel.is-dark .panel-tabs a.is-active,html.theme--documenter-dark .content kbd.panel .panel-tabs a.is-active{border-bottom-color:#282f2f}html.theme--documenter-dark .panel.is-dark .panel-block.is-active .panel-icon,html.theme--documenter-dark .content kbd.panel .panel-block.is-active .panel-icon{color:#282f2f}html.theme--documenter-dark .panel.is-primary .panel-heading,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#375a7f;color:#fff}html.theme--documenter-dark .panel.is-primary .panel-tabs a.is-active,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#375a7f}html.theme--documenter-dark .panel.is-primary .panel-block.is-active .panel-icon,html.theme--documenter-dark .docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#375a7f}html.theme--documenter-dark .panel.is-link .panel-heading{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .panel.is-link .panel-tabs a.is-active{border-bottom-color:#1abc9c}html.theme--documenter-dark .panel.is-link .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel.is-info .panel-heading{background-color:#024c7d;color:#fff}html.theme--documenter-dark .panel.is-info .panel-tabs a.is-active{border-bottom-color:#024c7d}html.theme--documenter-dark .panel.is-info .panel-block.is-active .panel-icon{color:#024c7d}html.theme--documenter-dark .panel.is-success .panel-heading{background-color:#008438;color:#fff}html.theme--documenter-dark .panel.is-success .panel-tabs a.is-active{border-bottom-color:#008438}html.theme--documenter-dark .panel.is-success .panel-block.is-active .panel-icon{color:#008438}html.theme--documenter-dark .panel.is-warning .panel-heading{background-color:#ad8100;color:#fff}html.theme--documenter-dark .panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ad8100}html.theme--documenter-dark .panel.is-warning .panel-block.is-active .panel-icon{color:#ad8100}html.theme--documenter-dark .panel.is-danger .panel-heading{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .panel.is-danger .panel-tabs a.is-active{border-bottom-color:#9e1b0d}html.theme--documenter-dark .panel.is-danger .panel-block.is-active .panel-icon{color:#9e1b0d}html.theme--documenter-dark .panel-tabs:not(:last-child),html.theme--documenter-dark .panel-block:not(:last-child){border-bottom:1px solid #ededed}html.theme--documenter-dark .panel-heading{background-color:#343c3d;border-radius:8px 8px 0 0;color:#f2f2f2;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}html.theme--documenter-dark .panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}html.theme--documenter-dark .panel-tabs a{border-bottom:1px solid #5e6d6f;margin-bottom:-1px;padding:0.5em}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#343c3d;color:#17a689}html.theme--documenter-dark .panel-list a{color:#fff}html.theme--documenter-dark .panel-list a:hover{color:#1abc9c}html.theme--documenter-dark .panel-block{align-items:center;color:#f2f2f2;display:flex;justify-content:flex-start;padding:0.5em 0.75em}html.theme--documenter-dark .panel-block input[type="checkbox"]{margin-right:.75em}html.theme--documenter-dark .panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}html.theme--documenter-dark .panel-block.is-wrapped{flex-wrap:wrap}html.theme--documenter-dark .panel-block.is-active{border-left-color:#1abc9c;color:#17a689}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#1abc9c}html.theme--documenter-dark .panel-block:last-child{border-bottom-left-radius:8px;border-bottom-right-radius:8px}html.theme--documenter-dark a.panel-block,html.theme--documenter-dark label.panel-block{cursor:pointer}html.theme--documenter-dark a.panel-block:hover,html.theme--documenter-dark label.panel-block:hover{background-color:#282f2f}html.theme--documenter-dark .panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#fff;margin-right:.75em}html.theme--documenter-dark .panel-icon .fa{font-size:inherit;line-height:inherit}html.theme--documenter-dark .tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}html.theme--documenter-dark .tabs a{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;color:#fff;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}html.theme--documenter-dark .tabs a:hover{border-bottom-color:#f2f2f2;color:#f2f2f2}html.theme--documenter-dark .tabs li{display:block}html.theme--documenter-dark .tabs li.is-active a{border-bottom-color:#1abc9c;color:#1abc9c}html.theme--documenter-dark .tabs ul{align-items:center;border-bottom-color:#5e6d6f;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}html.theme--documenter-dark .tabs ul.is-left{padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}html.theme--documenter-dark .tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}html.theme--documenter-dark .tabs .icon:first-child{margin-right:.5em}html.theme--documenter-dark .tabs .icon:last-child{margin-left:.5em}html.theme--documenter-dark .tabs.is-centered ul{justify-content:center}html.theme--documenter-dark .tabs.is-right ul{justify-content:flex-end}html.theme--documenter-dark .tabs.is-boxed a{border:1px solid transparent;border-radius:.4em .4em 0 0}html.theme--documenter-dark .tabs.is-boxed a:hover{background-color:#282f2f;border-bottom-color:#5e6d6f}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#fff;border-color:#5e6d6f;border-bottom-color:rgba(0,0,0,0) !important}html.theme--documenter-dark .tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}html.theme--documenter-dark .tabs.is-toggle a{border-color:#5e6d6f;border-style:solid;border-width:1px;margin-bottom:0;position:relative}html.theme--documenter-dark .tabs.is-toggle a:hover{background-color:#282f2f;border-color:#8c9b9d;z-index:2}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .tabs.is-toggle li:first-child a{border-top-left-radius:.4em;border-bottom-left-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li:last-child a{border-top-right-radius:.4em;border-bottom-right-radius:.4em}html.theme--documenter-dark .tabs.is-toggle li.is-active a{background-color:#1abc9c;border-color:#1abc9c;color:#fff;z-index:1}html.theme--documenter-dark .tabs.is-toggle ul{border-bottom:none}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}html.theme--documenter-dark .tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}html.theme--documenter-dark .tabs.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}html.theme--documenter-dark .tabs.is-medium{font-size:1.25rem}html.theme--documenter-dark .tabs.is-large{font-size:1.5rem}html.theme--documenter-dark .column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>html.theme--documenter-dark .column.is-narrow{flex:none;width:unset}.columns.is-mobile>html.theme--documenter-dark .column.is-full{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-half{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-half{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>html.theme--documenter-dark .column.is-0{flex:none;width:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-0{margin-left:0%}.columns.is-mobile>html.theme--documenter-dark .column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-3{flex:none;width:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-3{margin-left:25%}.columns.is-mobile>html.theme--documenter-dark .column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-6{flex:none;width:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-6{margin-left:50%}.columns.is-mobile>html.theme--documenter-dark .column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-9{flex:none;width:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-9{margin-left:75%}.columns.is-mobile>html.theme--documenter-dark .column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>html.theme--documenter-dark .column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>html.theme--documenter-dark .column.is-12{flex:none;width:100%}.columns.is-mobile>html.theme--documenter-dark .column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){html.theme--documenter-dark .column.is-narrow-mobile{flex:none;width:unset}html.theme--documenter-dark .column.is-full-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-mobile{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-mobile{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-mobile{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-mobile{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-mobile{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-mobile{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-mobile{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-mobile{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-mobile{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-mobile{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-mobile{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-mobile{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-mobile{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-mobile{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-mobile{margin-left:80%}html.theme--documenter-dark .column.is-0-mobile{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-mobile{margin-left:0%}html.theme--documenter-dark .column.is-1-mobile{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-mobile{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-mobile{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-mobile{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-mobile{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-mobile{margin-left:25%}html.theme--documenter-dark .column.is-4-mobile{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-mobile{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-mobile{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-mobile{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-mobile{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-mobile{margin-left:50%}html.theme--documenter-dark .column.is-7-mobile{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-mobile{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-mobile{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-mobile{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-mobile{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-mobile{margin-left:75%}html.theme--documenter-dark .column.is-10-mobile{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-mobile{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-mobile{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-mobile{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-mobile{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .column.is-narrow,html.theme--documenter-dark .column.is-narrow-tablet{flex:none;width:unset}html.theme--documenter-dark .column.is-full,html.theme--documenter-dark .column.is-full-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters,html.theme--documenter-dark .column.is-three-quarters-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds,html.theme--documenter-dark .column.is-two-thirds-tablet{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half,html.theme--documenter-dark .column.is-half-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third,html.theme--documenter-dark .column.is-one-third-tablet{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter,html.theme--documenter-dark .column.is-one-quarter-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth,html.theme--documenter-dark .column.is-one-fifth-tablet{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths,html.theme--documenter-dark .column.is-two-fifths-tablet{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths,html.theme--documenter-dark .column.is-three-fifths-tablet{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths,html.theme--documenter-dark .column.is-four-fifths-tablet{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters,html.theme--documenter-dark .column.is-offset-three-quarters-tablet{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds,html.theme--documenter-dark .column.is-offset-two-thirds-tablet{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half,html.theme--documenter-dark .column.is-offset-half-tablet{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third,html.theme--documenter-dark .column.is-offset-one-third-tablet{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter,html.theme--documenter-dark .column.is-offset-one-quarter-tablet{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth,html.theme--documenter-dark .column.is-offset-one-fifth-tablet{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths,html.theme--documenter-dark .column.is-offset-two-fifths-tablet{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths,html.theme--documenter-dark .column.is-offset-three-fifths-tablet{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths,html.theme--documenter-dark .column.is-offset-four-fifths-tablet{margin-left:80%}html.theme--documenter-dark .column.is-0,html.theme--documenter-dark .column.is-0-tablet{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0,html.theme--documenter-dark .column.is-offset-0-tablet{margin-left:0%}html.theme--documenter-dark .column.is-1,html.theme--documenter-dark .column.is-1-tablet{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1,html.theme--documenter-dark .column.is-offset-1-tablet{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2,html.theme--documenter-dark .column.is-2-tablet{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2,html.theme--documenter-dark .column.is-offset-2-tablet{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3,html.theme--documenter-dark .column.is-3-tablet{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3,html.theme--documenter-dark .column.is-offset-3-tablet{margin-left:25%}html.theme--documenter-dark .column.is-4,html.theme--documenter-dark .column.is-4-tablet{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4,html.theme--documenter-dark .column.is-offset-4-tablet{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5,html.theme--documenter-dark .column.is-5-tablet{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5,html.theme--documenter-dark .column.is-offset-5-tablet{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6,html.theme--documenter-dark .column.is-6-tablet{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6,html.theme--documenter-dark .column.is-offset-6-tablet{margin-left:50%}html.theme--documenter-dark .column.is-7,html.theme--documenter-dark .column.is-7-tablet{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7,html.theme--documenter-dark .column.is-offset-7-tablet{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8,html.theme--documenter-dark .column.is-8-tablet{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8,html.theme--documenter-dark .column.is-offset-8-tablet{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9,html.theme--documenter-dark .column.is-9-tablet{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9,html.theme--documenter-dark .column.is-offset-9-tablet{margin-left:75%}html.theme--documenter-dark .column.is-10,html.theme--documenter-dark .column.is-10-tablet{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10,html.theme--documenter-dark .column.is-offset-10-tablet{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11,html.theme--documenter-dark .column.is-11-tablet{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11,html.theme--documenter-dark .column.is-offset-11-tablet{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12,html.theme--documenter-dark .column.is-12-tablet{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12,html.theme--documenter-dark .column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){html.theme--documenter-dark .column.is-narrow-touch{flex:none;width:unset}html.theme--documenter-dark .column.is-full-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-touch{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-touch{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-touch{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-touch{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-touch{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-touch{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-touch{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-touch{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-touch{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-touch{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-touch{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-touch{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-touch{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-touch{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-touch{margin-left:80%}html.theme--documenter-dark .column.is-0-touch{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-touch{margin-left:0%}html.theme--documenter-dark .column.is-1-touch{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-touch{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-touch{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-touch{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-touch{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-touch{margin-left:25%}html.theme--documenter-dark .column.is-4-touch{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-touch{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-touch{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-touch{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-touch{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-touch{margin-left:50%}html.theme--documenter-dark .column.is-7-touch{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-touch{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-touch{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-touch{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-touch{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-touch{margin-left:75%}html.theme--documenter-dark .column.is-10-touch{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-touch{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-touch{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-touch{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-touch{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){html.theme--documenter-dark .column.is-narrow-desktop{flex:none;width:unset}html.theme--documenter-dark .column.is-full-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-desktop{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-desktop{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-desktop{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-desktop{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-desktop{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-desktop{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-desktop{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-desktop{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-desktop{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-desktop{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-desktop{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-desktop{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-desktop{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-desktop{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-desktop{margin-left:80%}html.theme--documenter-dark .column.is-0-desktop{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-desktop{margin-left:0%}html.theme--documenter-dark .column.is-1-desktop{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-desktop{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-desktop{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-desktop{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-desktop{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-desktop{margin-left:25%}html.theme--documenter-dark .column.is-4-desktop{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-desktop{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-desktop{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-desktop{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-desktop{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-desktop{margin-left:50%}html.theme--documenter-dark .column.is-7-desktop{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-desktop{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-desktop{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-desktop{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-desktop{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-desktop{margin-left:75%}html.theme--documenter-dark .column.is-10-desktop{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-desktop{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-desktop{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-desktop{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-desktop{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){html.theme--documenter-dark .column.is-narrow-widescreen{flex:none;width:unset}html.theme--documenter-dark .column.is-full-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-widescreen{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-widescreen{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-widescreen{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-widescreen{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-widescreen{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-widescreen{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-widescreen{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-widescreen{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-widescreen{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-widescreen{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-widescreen{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-widescreen{margin-left:80%}html.theme--documenter-dark .column.is-0-widescreen{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-widescreen{margin-left:0%}html.theme--documenter-dark .column.is-1-widescreen{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-widescreen{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-widescreen{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-widescreen{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-widescreen{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-widescreen{margin-left:25%}html.theme--documenter-dark .column.is-4-widescreen{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-widescreen{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-widescreen{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-widescreen{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-widescreen{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-widescreen{margin-left:50%}html.theme--documenter-dark .column.is-7-widescreen{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-widescreen{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-widescreen{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-widescreen{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-widescreen{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-widescreen{margin-left:75%}html.theme--documenter-dark .column.is-10-widescreen{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-widescreen{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-widescreen{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-widescreen{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-widescreen{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){html.theme--documenter-dark .column.is-narrow-fullhd{flex:none;width:unset}html.theme--documenter-dark .column.is-full-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-three-quarters-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-two-thirds-fullhd{flex:none;width:66.6666%}html.theme--documenter-dark .column.is-half-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-one-third-fullhd{flex:none;width:33.3333%}html.theme--documenter-dark .column.is-one-quarter-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-one-fifth-fullhd{flex:none;width:20%}html.theme--documenter-dark .column.is-two-fifths-fullhd{flex:none;width:40%}html.theme--documenter-dark .column.is-three-fifths-fullhd{flex:none;width:60%}html.theme--documenter-dark .column.is-four-fifths-fullhd{flex:none;width:80%}html.theme--documenter-dark .column.is-offset-three-quarters-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-offset-two-thirds-fullhd{margin-left:66.6666%}html.theme--documenter-dark .column.is-offset-half-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-offset-one-third-fullhd{margin-left:33.3333%}html.theme--documenter-dark .column.is-offset-one-quarter-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-offset-one-fifth-fullhd{margin-left:20%}html.theme--documenter-dark .column.is-offset-two-fifths-fullhd{margin-left:40%}html.theme--documenter-dark .column.is-offset-three-fifths-fullhd{margin-left:60%}html.theme--documenter-dark .column.is-offset-four-fifths-fullhd{margin-left:80%}html.theme--documenter-dark .column.is-0-fullhd{flex:none;width:0%}html.theme--documenter-dark .column.is-offset-0-fullhd{margin-left:0%}html.theme--documenter-dark .column.is-1-fullhd{flex:none;width:8.33333337%}html.theme--documenter-dark .column.is-offset-1-fullhd{margin-left:8.33333337%}html.theme--documenter-dark .column.is-2-fullhd{flex:none;width:16.66666674%}html.theme--documenter-dark .column.is-offset-2-fullhd{margin-left:16.66666674%}html.theme--documenter-dark .column.is-3-fullhd{flex:none;width:25%}html.theme--documenter-dark .column.is-offset-3-fullhd{margin-left:25%}html.theme--documenter-dark .column.is-4-fullhd{flex:none;width:33.33333337%}html.theme--documenter-dark .column.is-offset-4-fullhd{margin-left:33.33333337%}html.theme--documenter-dark .column.is-5-fullhd{flex:none;width:41.66666674%}html.theme--documenter-dark .column.is-offset-5-fullhd{margin-left:41.66666674%}html.theme--documenter-dark .column.is-6-fullhd{flex:none;width:50%}html.theme--documenter-dark .column.is-offset-6-fullhd{margin-left:50%}html.theme--documenter-dark .column.is-7-fullhd{flex:none;width:58.33333337%}html.theme--documenter-dark .column.is-offset-7-fullhd{margin-left:58.33333337%}html.theme--documenter-dark .column.is-8-fullhd{flex:none;width:66.66666674%}html.theme--documenter-dark .column.is-offset-8-fullhd{margin-left:66.66666674%}html.theme--documenter-dark .column.is-9-fullhd{flex:none;width:75%}html.theme--documenter-dark .column.is-offset-9-fullhd{margin-left:75%}html.theme--documenter-dark .column.is-10-fullhd{flex:none;width:83.33333337%}html.theme--documenter-dark .column.is-offset-10-fullhd{margin-left:83.33333337%}html.theme--documenter-dark .column.is-11-fullhd{flex:none;width:91.66666674%}html.theme--documenter-dark .column.is-offset-11-fullhd{margin-left:91.66666674%}html.theme--documenter-dark .column.is-12-fullhd{flex:none;width:100%}html.theme--documenter-dark .column.is-offset-12-fullhd{margin-left:100%}}html.theme--documenter-dark .columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .columns:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}html.theme--documenter-dark .columns.is-centered{justify-content:center}html.theme--documenter-dark .columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}html.theme--documenter-dark .columns.is-gapless>.column{margin:0;padding:0 !important}html.theme--documenter-dark .columns.is-gapless:not(:last-child){margin-bottom:1.5rem}html.theme--documenter-dark .columns.is-gapless:last-child{margin-bottom:0}html.theme--documenter-dark .columns.is-mobile{display:flex}html.theme--documenter-dark .columns.is-multiline{flex-wrap:wrap}html.theme--documenter-dark .columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-desktop{display:flex}}html.theme--documenter-dark .columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}html.theme--documenter-dark .columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}html.theme--documenter-dark .columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-0-fullhd{--columnGap: 0rem}}html.theme--documenter-dark .columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-1-fullhd{--columnGap: .25rem}}html.theme--documenter-dark .columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-2-fullhd{--columnGap: .5rem}}html.theme--documenter-dark .columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-3-fullhd{--columnGap: .75rem}}html.theme--documenter-dark .columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-4-fullhd{--columnGap: 1rem}}html.theme--documenter-dark .columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}html.theme--documenter-dark .columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}html.theme--documenter-dark .columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}html.theme--documenter-dark .columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){html.theme--documenter-dark .columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark .columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){html.theme--documenter-dark .columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){html.theme--documenter-dark .columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){html.theme--documenter-dark .columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){html.theme--documenter-dark .columns.is-variable.is-8-fullhd{--columnGap: 2rem}}html.theme--documenter-dark .tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}html.theme--documenter-dark .tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}html.theme--documenter-dark .tile.is-ancestor:last-child{margin-bottom:-.75rem}html.theme--documenter-dark .tile.is-ancestor:not(:last-child){margin-bottom:.75rem}html.theme--documenter-dark .tile.is-child{margin:0 !important}html.theme--documenter-dark .tile.is-parent{padding:.75rem}html.theme--documenter-dark .tile.is-vertical{flex-direction:column}html.theme--documenter-dark .tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{html.theme--documenter-dark .tile:not(.is-child){display:flex}html.theme--documenter-dark .tile.is-1{flex:none;width:8.33333337%}html.theme--documenter-dark .tile.is-2{flex:none;width:16.66666674%}html.theme--documenter-dark .tile.is-3{flex:none;width:25%}html.theme--documenter-dark .tile.is-4{flex:none;width:33.33333337%}html.theme--documenter-dark .tile.is-5{flex:none;width:41.66666674%}html.theme--documenter-dark .tile.is-6{flex:none;width:50%}html.theme--documenter-dark .tile.is-7{flex:none;width:58.33333337%}html.theme--documenter-dark .tile.is-8{flex:none;width:66.66666674%}html.theme--documenter-dark .tile.is-9{flex:none;width:75%}html.theme--documenter-dark .tile.is-10{flex:none;width:83.33333337%}html.theme--documenter-dark .tile.is-11{flex:none;width:91.66666674%}html.theme--documenter-dark .tile.is-12{flex:none;width:100%}}html.theme--documenter-dark .hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}html.theme--documenter-dark .hero .navbar{background:none}html.theme--documenter-dark .hero .tabs ul{border-bottom:none}html.theme--documenter-dark .hero.is-white{background-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-white strong{color:inherit}html.theme--documenter-dark .hero.is-white .title{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .subtitle{color:rgba(10,10,10,0.9)}html.theme--documenter-dark .hero.is-white .subtitle a:not(.button),html.theme--documenter-dark .hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-white .navbar-menu{background-color:#fff}}html.theme--documenter-dark .hero.is-white .navbar-item,html.theme--documenter-dark .hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}html.theme--documenter-dark .hero.is-white a.navbar-item:hover,html.theme--documenter-dark .hero.is-white a.navbar-item.is-active,html.theme--documenter-dark .hero.is-white .navbar-link:hover,html.theme--documenter-dark .hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}html.theme--documenter-dark .hero.is-white .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a{color:#0a0a0a}html.theme--documenter-dark .hero.is-white .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}html.theme--documenter-dark .hero.is-black{background-color:#0a0a0a;color:#fff}html.theme--documenter-dark .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-black strong{color:inherit}html.theme--documenter-dark .hero.is-black .title{color:#fff}html.theme--documenter-dark .hero.is-black .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-black .subtitle a:not(.button),html.theme--documenter-dark .hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-black .navbar-menu{background-color:#0a0a0a}}html.theme--documenter-dark .hero.is-black .navbar-item,html.theme--documenter-dark .hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-black a.navbar-item:hover,html.theme--documenter-dark .hero.is-black a.navbar-item.is-active,html.theme--documenter-dark .hero.is-black .navbar-link:hover,html.theme--documenter-dark .hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}html.theme--documenter-dark .hero.is-black .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-black .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-black .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}html.theme--documenter-dark .hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}html.theme--documenter-dark .hero.is-light{background-color:#ecf0f1;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-light strong{color:inherit}html.theme--documenter-dark .hero.is-light .title{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .subtitle{color:rgba(0,0,0,0.9)}html.theme--documenter-dark .hero.is-light .subtitle a:not(.button),html.theme--documenter-dark .hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-light .navbar-menu{background-color:#ecf0f1}}html.theme--documenter-dark .hero.is-light .navbar-item,html.theme--documenter-dark .hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light a.navbar-item:hover,html.theme--documenter-dark .hero.is-light a.navbar-item.is-active,html.theme--documenter-dark .hero.is-light .navbar-link:hover,html.theme--documenter-dark .hero.is-light .navbar-link.is-active{background-color:#dde4e6;color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}html.theme--documenter-dark .hero.is-light .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-light .tabs li.is-active a{color:#ecf0f1 !important;opacity:1}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ecf0f1}html.theme--documenter-dark .hero.is-light.is-bold{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #cadfe0 0%, #ecf0f1 71%, #fafbfc 100%)}}html.theme--documenter-dark .hero.is-dark,html.theme--documenter-dark .content kbd.hero{background-color:#282f2f;color:#fff}html.theme--documenter-dark .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-dark strong,html.theme--documenter-dark .content kbd.hero strong{color:inherit}html.theme--documenter-dark .hero.is-dark .title,html.theme--documenter-dark .content kbd.hero .title{color:#fff}html.theme--documenter-dark .hero.is-dark .subtitle,html.theme--documenter-dark .content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-dark .subtitle a:not(.button),html.theme--documenter-dark .content kbd.hero .subtitle a:not(.button),html.theme--documenter-dark .hero.is-dark .subtitle strong,html.theme--documenter-dark .content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-dark .navbar-menu,html.theme--documenter-dark .content kbd.hero .navbar-menu{background-color:#282f2f}}html.theme--documenter-dark .hero.is-dark .navbar-item,html.theme--documenter-dark .content kbd.hero .navbar-item,html.theme--documenter-dark .hero.is-dark .navbar-link,html.theme--documenter-dark .content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-dark a.navbar-item:hover,html.theme--documenter-dark .content kbd.hero a.navbar-item:hover,html.theme--documenter-dark .hero.is-dark a.navbar-item.is-active,html.theme--documenter-dark .content kbd.hero a.navbar-item.is-active,html.theme--documenter-dark .hero.is-dark .navbar-link:hover,html.theme--documenter-dark .content kbd.hero .navbar-link:hover,html.theme--documenter-dark .hero.is-dark .navbar-link.is-active,html.theme--documenter-dark .content kbd.hero .navbar-link.is-active{background-color:#1d2122;color:#fff}html.theme--documenter-dark .hero.is-dark .tabs a,html.theme--documenter-dark .content kbd.hero .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-dark .tabs a:hover,html.theme--documenter-dark .content kbd.hero .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-dark .tabs li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs li.is-active a{color:#282f2f !important;opacity:1}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle a:hover,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a,html.theme--documenter-dark .content kbd.hero .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#282f2f}html.theme--documenter-dark .hero.is-dark.is-bold,html.theme--documenter-dark .content kbd.hero.is-bold{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-dark.is-bold .navbar-menu,html.theme--documenter-dark .content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0f1615 0%, #282f2f 71%, #313c40 100%)}}html.theme--documenter-dark .hero.is-primary,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink{background-color:#375a7f;color:#fff}html.theme--documenter-dark .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-primary strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink strong{color:inherit}html.theme--documenter-dark .hero.is-primary .title,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .title{color:#fff}html.theme--documenter-dark .hero.is-primary .subtitle,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-primary .subtitle a:not(.button),html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),html.theme--documenter-dark .hero.is-primary .subtitle strong,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-primary .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#375a7f}}html.theme--documenter-dark .hero.is-primary .navbar-item,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-item,html.theme--documenter-dark .hero.is-primary .navbar-link,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-primary a.navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,html.theme--documenter-dark .hero.is-primary a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,html.theme--documenter-dark .hero.is-primary .navbar-link:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link:hover,html.theme--documenter-dark .hero.is-primary .navbar-link.is-active,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#2f4d6d;color:#fff}html.theme--documenter-dark .hero.is-primary .tabs a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-primary .tabs a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-primary .tabs li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#375a7f !important;opacity:1}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle a:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#375a7f}html.theme--documenter-dark .hero.is-primary.is-bold,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-primary.is-bold .navbar-menu,html.theme--documenter-dark .docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #214b62 0%, #375a7f 71%, #3a5796 100%)}}html.theme--documenter-dark .hero.is-link{background-color:#1abc9c;color:#fff}html.theme--documenter-dark .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-link strong{color:inherit}html.theme--documenter-dark .hero.is-link .title{color:#fff}html.theme--documenter-dark .hero.is-link .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-link .subtitle a:not(.button),html.theme--documenter-dark .hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-link .navbar-menu{background-color:#1abc9c}}html.theme--documenter-dark .hero.is-link .navbar-item,html.theme--documenter-dark .hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-link a.navbar-item:hover,html.theme--documenter-dark .hero.is-link a.navbar-item.is-active,html.theme--documenter-dark .hero.is-link .navbar-link:hover,html.theme--documenter-dark .hero.is-link .navbar-link.is-active{background-color:#17a689;color:#fff}html.theme--documenter-dark .hero.is-link .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-link .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-link .tabs li.is-active a{color:#1abc9c !important;opacity:1}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-link .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#1abc9c}html.theme--documenter-dark .hero.is-link.is-bold{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #0c9764 0%, #1abc9c 71%, #17d8d2 100%)}}html.theme--documenter-dark .hero.is-info{background-color:#024c7d;color:#fff}html.theme--documenter-dark .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-info strong{color:inherit}html.theme--documenter-dark .hero.is-info .title{color:#fff}html.theme--documenter-dark .hero.is-info .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-info .subtitle a:not(.button),html.theme--documenter-dark .hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-info .navbar-menu{background-color:#024c7d}}html.theme--documenter-dark .hero.is-info .navbar-item,html.theme--documenter-dark .hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-info a.navbar-item:hover,html.theme--documenter-dark .hero.is-info a.navbar-item.is-active,html.theme--documenter-dark .hero.is-info .navbar-link:hover,html.theme--documenter-dark .hero.is-info .navbar-link.is-active{background-color:#023d64;color:#fff}html.theme--documenter-dark .hero.is-info .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-info .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-info .tabs li.is-active a{color:#024c7d !important;opacity:1}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-info .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#024c7d}html.theme--documenter-dark .hero.is-info.is-bold{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #003a4c 0%, #024c7d 71%, #004299 100%)}}html.theme--documenter-dark .hero.is-success{background-color:#008438;color:#fff}html.theme--documenter-dark .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-success strong{color:inherit}html.theme--documenter-dark .hero.is-success .title{color:#fff}html.theme--documenter-dark .hero.is-success .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-success .subtitle a:not(.button),html.theme--documenter-dark .hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-success .navbar-menu{background-color:#008438}}html.theme--documenter-dark .hero.is-success .navbar-item,html.theme--documenter-dark .hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-success a.navbar-item:hover,html.theme--documenter-dark .hero.is-success a.navbar-item.is-active,html.theme--documenter-dark .hero.is-success .navbar-link:hover,html.theme--documenter-dark .hero.is-success .navbar-link.is-active{background-color:#006b2d;color:#fff}html.theme--documenter-dark .hero.is-success .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-success .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-success .tabs li.is-active a{color:#008438 !important;opacity:1}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-success .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#008438}html.theme--documenter-dark .hero.is-success.is-bold{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #005115 0%, #008438 71%, #009e5d 100%)}}html.theme--documenter-dark .hero.is-warning{background-color:#ad8100;color:#fff}html.theme--documenter-dark .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-warning strong{color:inherit}html.theme--documenter-dark .hero.is-warning .title{color:#fff}html.theme--documenter-dark .hero.is-warning .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-warning .subtitle a:not(.button),html.theme--documenter-dark .hero.is-warning .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-warning .navbar-menu{background-color:#ad8100}}html.theme--documenter-dark .hero.is-warning .navbar-item,html.theme--documenter-dark .hero.is-warning .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-warning a.navbar-item:hover,html.theme--documenter-dark .hero.is-warning a.navbar-item.is-active,html.theme--documenter-dark .hero.is-warning .navbar-link:hover,html.theme--documenter-dark .hero.is-warning .navbar-link.is-active{background-color:#946e00;color:#fff}html.theme--documenter-dark .hero.is-warning .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-warning .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-warning .tabs li.is-active a{color:#ad8100 !important;opacity:1}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ad8100}html.theme--documenter-dark .hero.is-warning.is-bold{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #7a4700 0%, #ad8100 71%, #c7b500 100%)}}html.theme--documenter-dark .hero.is-danger{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),html.theme--documenter-dark .hero.is-danger strong{color:inherit}html.theme--documenter-dark .hero.is-danger .title{color:#fff}html.theme--documenter-dark .hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}html.theme--documenter-dark .hero.is-danger .subtitle a:not(.button),html.theme--documenter-dark .hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){html.theme--documenter-dark .hero.is-danger .navbar-menu{background-color:#9e1b0d}}html.theme--documenter-dark .hero.is-danger .navbar-item,html.theme--documenter-dark .hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}html.theme--documenter-dark .hero.is-danger a.navbar-item:hover,html.theme--documenter-dark .hero.is-danger a.navbar-item.is-active,html.theme--documenter-dark .hero.is-danger .navbar-link:hover,html.theme--documenter-dark .hero.is-danger .navbar-link.is-active{background-color:#86170b;color:#fff}html.theme--documenter-dark .hero.is-danger .tabs a{color:#fff;opacity:0.9}html.theme--documenter-dark .hero.is-danger .tabs a:hover{opacity:1}html.theme--documenter-dark .hero.is-danger .tabs li.is-active a{color:#9e1b0d !important;opacity:1}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a{color:#fff}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-boxed li.is-active a:hover,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a,html.theme--documenter-dark .hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#9e1b0d}html.theme--documenter-dark .hero.is-danger.is-bold{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}@media screen and (max-width: 768px){html.theme--documenter-dark .hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #75030b 0%, #9e1b0d 71%, #ba380a 100%)}}html.theme--documenter-dark .hero.is-small .hero-body,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero.is-large .hero-body{padding:18rem 6rem}}html.theme--documenter-dark .hero.is-halfheight .hero-body,html.theme--documenter-dark .hero.is-fullheight .hero-body,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}html.theme--documenter-dark .hero.is-halfheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight .hero-body>.container,html.theme--documenter-dark .hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}html.theme--documenter-dark .hero.is-halfheight{min-height:50vh}html.theme--documenter-dark .hero.is-fullheight{min-height:100vh}html.theme--documenter-dark .hero-video{overflow:hidden}html.theme--documenter-dark .hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}html.theme--documenter-dark .hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-video{display:none}}html.theme--documenter-dark .hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){html.theme--documenter-dark .hero-buttons .button{display:flex}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-buttons{display:flex;justify-content:center}html.theme--documenter-dark .hero-buttons .button:not(:last-child){margin-right:1.5rem}}html.theme--documenter-dark .hero-head,html.theme--documenter-dark .hero-foot{flex-grow:0;flex-shrink:0}html.theme--documenter-dark .hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{html.theme--documenter-dark .hero-body{padding:3rem 3rem}}html.theme--documenter-dark .section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){html.theme--documenter-dark .section{padding:3rem 3rem}html.theme--documenter-dark .section.is-medium{padding:9rem 4.5rem}html.theme--documenter-dark .section.is-large{padding:18rem 6rem}}html.theme--documenter-dark .footer{background-color:#282f2f;padding:3rem 1.5rem 6rem}html.theme--documenter-dark hr{height:1px}html.theme--documenter-dark h6{text-transform:uppercase;letter-spacing:0.5px}html.theme--documenter-dark .hero{background-color:#343c3d}html.theme--documenter-dark a{transition:all 200ms ease}html.theme--documenter-dark .button{transition:all 200ms ease;border-width:1px;color:#fff}html.theme--documenter-dark .button.is-active,html.theme--documenter-dark .button.is-focused,html.theme--documenter-dark .button:active,html.theme--documenter-dark .button:focus{box-shadow:0 0 0 2px rgba(140,155,157,0.5)}html.theme--documenter-dark .button.is-white.is-hovered,html.theme--documenter-dark .button.is-white:hover{background-color:#fff}html.theme--documenter-dark .button.is-white.is-active,html.theme--documenter-dark .button.is-white.is-focused,html.theme--documenter-dark .button.is-white:active,html.theme--documenter-dark .button.is-white:focus{border-color:#fff;box-shadow:0 0 0 2px rgba(255,255,255,0.5)}html.theme--documenter-dark .button.is-black.is-hovered,html.theme--documenter-dark .button.is-black:hover{background-color:#1d1d1d}html.theme--documenter-dark .button.is-black.is-active,html.theme--documenter-dark .button.is-black.is-focused,html.theme--documenter-dark .button.is-black:active,html.theme--documenter-dark .button.is-black:focus{border-color:#0a0a0a;box-shadow:0 0 0 2px rgba(10,10,10,0.5)}html.theme--documenter-dark .button.is-light.is-hovered,html.theme--documenter-dark .button.is-light:hover{background-color:#fff}html.theme--documenter-dark .button.is-light.is-active,html.theme--documenter-dark .button.is-light.is-focused,html.theme--documenter-dark .button.is-light:active,html.theme--documenter-dark .button.is-light:focus{border-color:#ecf0f1;box-shadow:0 0 0 2px rgba(236,240,241,0.5)}html.theme--documenter-dark .button.is-dark.is-hovered,html.theme--documenter-dark .content kbd.button.is-hovered,html.theme--documenter-dark .button.is-dark:hover,html.theme--documenter-dark .content kbd.button:hover{background-color:#3a4344}html.theme--documenter-dark .button.is-dark.is-active,html.theme--documenter-dark .content kbd.button.is-active,html.theme--documenter-dark .button.is-dark.is-focused,html.theme--documenter-dark .content kbd.button.is-focused,html.theme--documenter-dark .button.is-dark:active,html.theme--documenter-dark .content kbd.button:active,html.theme--documenter-dark .button.is-dark:focus,html.theme--documenter-dark .content kbd.button:focus{border-color:#282f2f;box-shadow:0 0 0 2px rgba(40,47,47,0.5)}html.theme--documenter-dark .button.is-primary.is-hovered,html.theme--documenter-dark .docstring>section>a.button.is-hovered.docs-sourcelink,html.theme--documenter-dark .button.is-primary:hover,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:hover{background-color:#436d9a}html.theme--documenter-dark .button.is-primary.is-active,html.theme--documenter-dark .docstring>section>a.button.is-active.docs-sourcelink,html.theme--documenter-dark .button.is-primary.is-focused,html.theme--documenter-dark .docstring>section>a.button.is-focused.docs-sourcelink,html.theme--documenter-dark .button.is-primary:active,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:active,html.theme--documenter-dark .button.is-primary:focus,html.theme--documenter-dark .docstring>section>a.button.docs-sourcelink:focus{border-color:#375a7f;box-shadow:0 0 0 2px rgba(55,90,127,0.5)}html.theme--documenter-dark .button.is-link.is-hovered,html.theme--documenter-dark .button.is-link:hover{background-color:#1fdeb8}html.theme--documenter-dark .button.is-link.is-active,html.theme--documenter-dark .button.is-link.is-focused,html.theme--documenter-dark .button.is-link:active,html.theme--documenter-dark .button.is-link:focus{border-color:#1abc9c;box-shadow:0 0 0 2px rgba(26,188,156,0.5)}html.theme--documenter-dark .button.is-info.is-hovered,html.theme--documenter-dark .button.is-info:hover{background-color:#0363a3}html.theme--documenter-dark .button.is-info.is-active,html.theme--documenter-dark .button.is-info.is-focused,html.theme--documenter-dark .button.is-info:active,html.theme--documenter-dark .button.is-info:focus{border-color:#024c7d;box-shadow:0 0 0 2px rgba(2,76,125,0.5)}html.theme--documenter-dark .button.is-success.is-hovered,html.theme--documenter-dark .button.is-success:hover{background-color:#00aa48}html.theme--documenter-dark .button.is-success.is-active,html.theme--documenter-dark .button.is-success.is-focused,html.theme--documenter-dark .button.is-success:active,html.theme--documenter-dark .button.is-success:focus{border-color:#008438;box-shadow:0 0 0 2px rgba(0,132,56,0.5)}html.theme--documenter-dark .button.is-warning.is-hovered,html.theme--documenter-dark .button.is-warning:hover{background-color:#d39e00}html.theme--documenter-dark .button.is-warning.is-active,html.theme--documenter-dark .button.is-warning.is-focused,html.theme--documenter-dark .button.is-warning:active,html.theme--documenter-dark .button.is-warning:focus{border-color:#ad8100;box-shadow:0 0 0 2px rgba(173,129,0,0.5)}html.theme--documenter-dark .button.is-danger.is-hovered,html.theme--documenter-dark .button.is-danger:hover{background-color:#c12110}html.theme--documenter-dark .button.is-danger.is-active,html.theme--documenter-dark .button.is-danger.is-focused,html.theme--documenter-dark .button.is-danger:active,html.theme--documenter-dark .button.is-danger:focus{border-color:#9e1b0d;box-shadow:0 0 0 2px rgba(158,27,13,0.5)}html.theme--documenter-dark .label{color:#dbdee0}html.theme--documenter-dark .button,html.theme--documenter-dark .control.has-icons-left .icon,html.theme--documenter-dark .control.has-icons-right .icon,html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .pagination-ellipsis,html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous,html.theme--documenter-dark .select,html.theme--documenter-dark .select select,html.theme--documenter-dark .textarea{height:2.5em}html.theme--documenter-dark .input,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark .textarea{transition:all 200ms ease;box-shadow:none;border-width:1px;padding-left:1em;padding-right:1em}html.theme--documenter-dark .select:after,html.theme--documenter-dark .select select{border-width:1px}html.theme--documenter-dark .control.has-addons .button,html.theme--documenter-dark .control.has-addons .input,html.theme--documenter-dark .control.has-addons #documenter .docs-sidebar form.docs-search>input,html.theme--documenter-dark #documenter .docs-sidebar .control.has-addons form.docs-search>input,html.theme--documenter-dark .control.has-addons .select{margin-right:-1px}html.theme--documenter-dark .notification{background-color:#343c3d}html.theme--documenter-dark .card{box-shadow:none;border:1px solid #343c3d;background-color:#282f2f;border-radius:.4em}html.theme--documenter-dark .card .card-image img{border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-header{box-shadow:none;background-color:rgba(18,18,18,0.2);border-radius:.4em .4em 0 0}html.theme--documenter-dark .card .card-footer{background-color:rgba(18,18,18,0.2)}html.theme--documenter-dark .card .card-footer,html.theme--documenter-dark .card .card-footer-item{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .notification.is-white a:not(.button){color:#0a0a0a;text-decoration:underline}html.theme--documenter-dark .notification.is-black a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-light a:not(.button){color:rgba(0,0,0,0.7);text-decoration:underline}html.theme--documenter-dark .notification.is-dark a:not(.button),html.theme--documenter-dark .content kbd.notification a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-primary a:not(.button),html.theme--documenter-dark .docstring>section>a.notification.docs-sourcelink a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-link a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-info a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-success a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-warning a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .notification.is-danger a:not(.button){color:#fff;text-decoration:underline}html.theme--documenter-dark .tag,html.theme--documenter-dark .content kbd,html.theme--documenter-dark .docstring>section>a.docs-sourcelink{border-radius:.4em}html.theme--documenter-dark .menu-list a{transition:all 300ms ease}html.theme--documenter-dark .modal-card-body{background-color:#282f2f}html.theme--documenter-dark .modal-card-foot,html.theme--documenter-dark .modal-card-head{border-color:#343c3d}html.theme--documenter-dark .message-header{font-weight:700;background-color:#343c3d;color:#fff}html.theme--documenter-dark .message-body{border-width:1px;border-color:#343c3d}html.theme--documenter-dark .navbar{border-radius:.4em}html.theme--documenter-dark .navbar.is-transparent{background:none}html.theme--documenter-dark .navbar.is-primary .navbar-dropdown a.navbar-item.is-active,html.theme--documenter-dark .docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#1abc9c}@media screen and (max-width: 1055px){html.theme--documenter-dark .navbar .navbar-menu{background-color:#375a7f;border-radius:0 0 .4em .4em}}html.theme--documenter-dark .hero .navbar,html.theme--documenter-dark body>.navbar{border-radius:0}html.theme--documenter-dark .pagination-link,html.theme--documenter-dark .pagination-next,html.theme--documenter-dark .pagination-previous{border-width:1px}html.theme--documenter-dark .panel-block,html.theme--documenter-dark .panel-heading,html.theme--documenter-dark .panel-tabs{border-width:1px}html.theme--documenter-dark .panel-block:first-child,html.theme--documenter-dark .panel-heading:first-child,html.theme--documenter-dark .panel-tabs:first-child{border-top-width:1px}html.theme--documenter-dark .panel-heading{font-weight:700}html.theme--documenter-dark .panel-tabs a{border-width:1px;margin-bottom:-1px}html.theme--documenter-dark .panel-tabs a.is-active{border-bottom-color:#17a689}html.theme--documenter-dark .panel-block:hover{color:#1dd2af}html.theme--documenter-dark .panel-block:hover .panel-icon{color:#1dd2af}html.theme--documenter-dark .panel-block.is-active .panel-icon{color:#17a689}html.theme--documenter-dark .tabs a{border-bottom-width:1px;margin-bottom:-1px}html.theme--documenter-dark .tabs ul{border-bottom-width:1px}html.theme--documenter-dark .tabs.is-boxed a{border-width:1px}html.theme--documenter-dark .tabs.is-boxed li.is-active a{background-color:#1f2424}html.theme--documenter-dark .tabs.is-toggle li a{border-width:1px;margin-bottom:0}html.theme--documenter-dark .tabs.is-toggle li+li{margin-left:-1px}html.theme--documenter-dark .hero.is-white .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-black .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-light .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-dark .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .content kbd.hero .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-primary .navbar .navbar-dropdown .navbar-item:hover,html.theme--documenter-dark .docstring>section>a.hero.docs-sourcelink .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-link .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-info .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-success .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-warning .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark .hero.is-danger .navbar .navbar-dropdown .navbar-item:hover{background-color:rgba(0,0,0,0)}html.theme--documenter-dark h1 .docs-heading-anchor,html.theme--documenter-dark h1 .docs-heading-anchor:hover,html.theme--documenter-dark h1 .docs-heading-anchor:visited,html.theme--documenter-dark h2 .docs-heading-anchor,html.theme--documenter-dark h2 .docs-heading-anchor:hover,html.theme--documenter-dark h2 .docs-heading-anchor:visited,html.theme--documenter-dark h3 .docs-heading-anchor,html.theme--documenter-dark h3 .docs-heading-anchor:hover,html.theme--documenter-dark h3 .docs-heading-anchor:visited,html.theme--documenter-dark h4 .docs-heading-anchor,html.theme--documenter-dark h4 .docs-heading-anchor:hover,html.theme--documenter-dark h4 .docs-heading-anchor:visited,html.theme--documenter-dark h5 .docs-heading-anchor,html.theme--documenter-dark h5 .docs-heading-anchor:hover,html.theme--documenter-dark h5 .docs-heading-anchor:visited,html.theme--documenter-dark h6 .docs-heading-anchor,html.theme--documenter-dark h6 .docs-heading-anchor:hover,html.theme--documenter-dark h6 .docs-heading-anchor:visited{color:#f2f2f2}html.theme--documenter-dark h1 .docs-heading-anchor-permalink,html.theme--documenter-dark h2 .docs-heading-anchor-permalink,html.theme--documenter-dark h3 .docs-heading-anchor-permalink,html.theme--documenter-dark h4 .docs-heading-anchor-permalink,html.theme--documenter-dark h5 .docs-heading-anchor-permalink,html.theme--documenter-dark h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}html.theme--documenter-dark h1 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h2 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h3 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h4 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h5 .docs-heading-anchor-permalink::before,html.theme--documenter-dark h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}html.theme--documenter-dark h1:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h2:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h3:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h4:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h5:hover .docs-heading-anchor-permalink,html.theme--documenter-dark h6:hover .docs-heading-anchor-permalink{visibility:visible}html.theme--documenter-dark .docs-light-only{display:none !important}html.theme--documenter-dark pre{position:relative;overflow:hidden}html.theme--documenter-dark pre code,html.theme--documenter-dark pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}html.theme--documenter-dark pre code:first-of-type,html.theme--documenter-dark pre code.hljs:first-of-type{padding-top:0.5rem !important}html.theme--documenter-dark pre code:last-of-type,html.theme--documenter-dark pre code.hljs:last-of-type{padding-bottom:0.5rem !important}html.theme--documenter-dark pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#fff;cursor:pointer;text-align:center}html.theme--documenter-dark pre .copy-button:focus,html.theme--documenter-dark pre .copy-button:hover{opacity:1;background:rgba(255,255,255,0.1);color:#1abc9c}html.theme--documenter-dark pre .copy-button.success{color:#259a12;opacity:1}html.theme--documenter-dark pre .copy-button.error{color:#cb3c33;opacity:1}html.theme--documenter-dark pre:hover .copy-button{opacity:1}html.theme--documenter-dark .admonition{background-color:#282f2f;border-style:solid;border-width:1px;border-color:#5e6d6f;border-radius:.4em;font-size:1rem}html.theme--documenter-dark .admonition strong{color:currentColor}html.theme--documenter-dark .admonition.is-small,html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}html.theme--documenter-dark .admonition.is-medium{font-size:1.25rem}html.theme--documenter-dark .admonition.is-large{font-size:1.5rem}html.theme--documenter-dark .admonition.is-default{background-color:#282f2f;border-color:#5e6d6f}html.theme--documenter-dark .admonition.is-default>.admonition-header{background-color:#5e6d6f;color:#fff}html.theme--documenter-dark .admonition.is-default>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-info{background-color:#282f2f;border-color:#024c7d}html.theme--documenter-dark .admonition.is-info>.admonition-header{background-color:#024c7d;color:#fff}html.theme--documenter-dark .admonition.is-info>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-success{background-color:#282f2f;border-color:#008438}html.theme--documenter-dark .admonition.is-success>.admonition-header{background-color:#008438;color:#fff}html.theme--documenter-dark .admonition.is-success>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-warning{background-color:#282f2f;border-color:#ad8100}html.theme--documenter-dark .admonition.is-warning>.admonition-header{background-color:#ad8100;color:#fff}html.theme--documenter-dark .admonition.is-warning>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-danger{background-color:#282f2f;border-color:#9e1b0d}html.theme--documenter-dark .admonition.is-danger>.admonition-header{background-color:#9e1b0d;color:#fff}html.theme--documenter-dark .admonition.is-danger>.admonition-body{color:#fff}html.theme--documenter-dark .admonition.is-compat{background-color:#282f2f;border-color:#137886}html.theme--documenter-dark .admonition.is-compat>.admonition-header{background-color:#137886;color:#fff}html.theme--documenter-dark .admonition.is-compat>.admonition-body{color:#fff}html.theme--documenter-dark .admonition-header{color:#fff;background-color:#5e6d6f;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}html.theme--documenter-dark .admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}html.theme--documenter-dark details.admonition.is-details>.admonition-header{list-style:none}html.theme--documenter-dark details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}html.theme--documenter-dark details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}html.theme--documenter-dark .admonition-body{color:#fff;padding:0.5rem .75rem}html.theme--documenter-dark .admonition-body pre{background-color:#282f2f}html.theme--documenter-dark .admonition-body code{background-color:rgba(255,255,255,0.05)}html.theme--documenter-dark .docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #5e6d6f;box-shadow:none;max-width:100%}html.theme--documenter-dark .docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#282f2f;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #5e6d6f;overflow:auto}html.theme--documenter-dark .docstring>header code{background-color:transparent}html.theme--documenter-dark .docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}html.theme--documenter-dark .docstring>header .docstring-binding{margin-right:0.3em}html.theme--documenter-dark .docstring>header .docstring-category{margin-left:0.3em}html.theme--documenter-dark .docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .docstring>section:last-child{border-bottom:none}html.theme--documenter-dark .docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}html.theme--documenter-dark .docstring>section>a.docs-sourcelink:focus{opacity:1 !important}html.theme--documenter-dark .docstring:hover>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}html.theme--documenter-dark .docstring>section:hover a.docs-sourcelink{opacity:1}html.theme--documenter-dark .documenter-example-output{background-color:#1f2424}html.theme--documenter-dark .outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#282f2f;color:#fff;border-bottom:3px solid #9e1b0d;padding:10px 35px;text-align:center;font-size:15px}html.theme--documenter-dark .outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}html.theme--documenter-dark .outdated-warning-overlay a{color:#1abc9c}html.theme--documenter-dark .outdated-warning-overlay a:hover{color:#1dd2af}html.theme--documenter-dark .content pre{border:1px solid #5e6d6f}html.theme--documenter-dark .content code{font-weight:inherit}html.theme--documenter-dark .content a code{color:#1abc9c}html.theme--documenter-dark .content a:hover code{color:#1dd2af}html.theme--documenter-dark .content h1 code,html.theme--documenter-dark .content h2 code,html.theme--documenter-dark .content h3 code,html.theme--documenter-dark .content h4 code,html.theme--documenter-dark .content h5 code,html.theme--documenter-dark .content h6 code{color:#f2f2f2}html.theme--documenter-dark .content table{display:block;width:initial;max-width:100%;overflow-x:auto}html.theme--documenter-dark .content blockquote>ul:first-child,html.theme--documenter-dark .content blockquote>ol:first-child,html.theme--documenter-dark .content .admonition-body>ul:first-child,html.theme--documenter-dark .content .admonition-body>ol:first-child{margin-top:0}html.theme--documenter-dark pre,html.theme--documenter-dark code{font-variant-ligatures:no-contextual}html.theme--documenter-dark .breadcrumb a.is-disabled{cursor:default;pointer-events:none}html.theme--documenter-dark .breadcrumb a.is-disabled,html.theme--documenter-dark .breadcrumb a.is-disabled:hover{color:#f2f2f2}html.theme--documenter-dark .hljs{background:initial !important}html.theme--documenter-dark .katex .katex-mathml{top:0;right:0}html.theme--documenter-dark .katex-display,html.theme--documenter-dark mjx-container,html.theme--documenter-dark .MathJax_Display{margin:0.5em 0 !important}html.theme--documenter-dark html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}html.theme--documenter-dark li.no-marker{list-style:none}html.theme--documenter-dark #documenter .docs-main>article{overflow-wrap:break-word}html.theme--documenter-dark #documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main{width:100%}html.theme--documenter-dark #documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-main>header,html.theme--documenter-dark #documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar{background-color:#1f2424;border-bottom:1px solid #5e6d6f;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1;overflow-x:hidden}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-icon,html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}html.theme--documenter-dark #documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #171717;transition-duration:0.7s;-webkit-transition-duration:0.7s}html.theme--documenter-dark #documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}html.theme--documenter-dark #documenter .docs-main section.footnotes{border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-main section.footnotes li .tag:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,html.theme--documenter-dark #documenter .docs-main section.footnotes li .content kbd:first-child,html.theme--documenter-dark .content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}html.theme--documenter-dark #documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #5e6d6f;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage,html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}html.theme--documenter-dark #documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}html.theme--documenter-dark #documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}html.theme--documenter-dark #documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}html.theme--documenter-dark #documenter .docs-sidebar{display:flex;flex-direction:column;color:#fff;background-color:#282f2f;border-right:1px solid #5e6d6f;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}html.theme--documenter-dark #documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #171717}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar{left:0;top:0}}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a,html.theme--documenter-dark #documenter .docs-sidebar .docs-package-name a:hover{color:#fff}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector{border-top:1px solid #5e6d6f;display:none;padding:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar .docs-version-selector.visible{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #5e6d6f;padding-bottom:1.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#fff;background:#282f2f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu a.tocitem:hover,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#fff;background-color:#32393a}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #5e6d6f;border-bottom:1px solid #5e6d6f;background-color:#1f2424}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#1f2424;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#32393a;color:#fff}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #5e6d6f}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}html.theme--documenter-dark #documenter .docs-sidebar form.docs-search>input{width:14.4rem}html.theme--documenter-dark #documenter .docs-sidebar #documenter-search-query{color:#868c98;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}@media screen and (max-width: 1055px){html.theme--documenter-dark #documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#3b4445}html.theme--documenter-dark #documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#4e5a5c}}html.theme--documenter-dark kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(245,245,245,0.6);box-shadow:0 2px 0 1px rgba(245,245,245,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}html.theme--documenter-dark .search-min-width-50{min-width:50%}html.theme--documenter-dark .search-min-height-100{min-height:100%}html.theme--documenter-dark .search-modal-card-body{max-height:calc(100vh - 15rem)}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .property-search-result-badge,html.theme--documenter-dark .search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333;background-color:#f1f5f9}html.theme--documenter-dark .search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}html.theme--documenter-dark .search-filter:hover,html.theme--documenter-dark .search-filter:focus{color:#333}html.theme--documenter-dark .search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}html.theme--documenter-dark .search-filter-selected:hover,html.theme--documenter-dark .search-filter-selected:focus{color:#f5f5f5}html.theme--documenter-dark .search-result-highlight{background-color:#ffdd57;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f}html.theme--documenter-dark .search-result-title{width:85%;color:#f5f5f5}html.theme--documenter-dark .search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-thumb,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}html.theme--documenter-dark #search-modal .modal-card-body::-webkit-scrollbar-track,html.theme--documenter-dark #search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem}html.theme--documenter-dark .gap-8{gap:2rem}html.theme--documenter-dark{background-color:#1f2424;font-size:16px;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}html.theme--documenter-dark .ansi span.sgr1{font-weight:bolder}html.theme--documenter-dark .ansi span.sgr2{font-weight:lighter}html.theme--documenter-dark .ansi span.sgr3{font-style:italic}html.theme--documenter-dark .ansi span.sgr4{text-decoration:underline}html.theme--documenter-dark .ansi span.sgr7{color:#1f2424;background-color:#fff}html.theme--documenter-dark .ansi span.sgr8{color:transparent}html.theme--documenter-dark .ansi span.sgr8 span{color:transparent}html.theme--documenter-dark .ansi span.sgr9{text-decoration:line-through}html.theme--documenter-dark .ansi span.sgr30{color:#242424}html.theme--documenter-dark .ansi span.sgr31{color:#f6705f}html.theme--documenter-dark .ansi span.sgr32{color:#4fb43a}html.theme--documenter-dark .ansi span.sgr33{color:#f4c72f}html.theme--documenter-dark .ansi span.sgr34{color:#7587f0}html.theme--documenter-dark .ansi span.sgr35{color:#bc89d3}html.theme--documenter-dark .ansi span.sgr36{color:#49b6ca}html.theme--documenter-dark .ansi span.sgr37{color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr40{background-color:#242424}html.theme--documenter-dark .ansi span.sgr41{background-color:#f6705f}html.theme--documenter-dark .ansi span.sgr42{background-color:#4fb43a}html.theme--documenter-dark .ansi span.sgr43{background-color:#f4c72f}html.theme--documenter-dark .ansi span.sgr44{background-color:#7587f0}html.theme--documenter-dark .ansi span.sgr45{background-color:#bc89d3}html.theme--documenter-dark .ansi span.sgr46{background-color:#49b6ca}html.theme--documenter-dark .ansi span.sgr47{background-color:#b3bdbe}html.theme--documenter-dark .ansi span.sgr90{color:#92a0a2}html.theme--documenter-dark .ansi span.sgr91{color:#ff8674}html.theme--documenter-dark .ansi span.sgr92{color:#79d462}html.theme--documenter-dark .ansi span.sgr93{color:#ffe76b}html.theme--documenter-dark .ansi span.sgr94{color:#8a98ff}html.theme--documenter-dark .ansi span.sgr95{color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr96{color:#6bc8db}html.theme--documenter-dark .ansi span.sgr97{color:#ecf0f1}html.theme--documenter-dark .ansi span.sgr100{background-color:#92a0a2}html.theme--documenter-dark .ansi span.sgr101{background-color:#ff8674}html.theme--documenter-dark .ansi span.sgr102{background-color:#79d462}html.theme--documenter-dark .ansi span.sgr103{background-color:#ffe76b}html.theme--documenter-dark .ansi span.sgr104{background-color:#8a98ff}html.theme--documenter-dark .ansi span.sgr105{background-color:#d2a4e6}html.theme--documenter-dark .ansi span.sgr106{background-color:#6bc8db}html.theme--documenter-dark .ansi span.sgr107{background-color:#ecf0f1}html.theme--documenter-dark code.language-julia-repl>span.hljs-meta{color:#4fb43a;font-weight:bolder}html.theme--documenter-dark .hljs{background:#2b2b2b;color:#f8f8f2}html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-quote{color:#d4d0ab}html.theme--documenter-dark .hljs-variable,html.theme--documenter-dark .hljs-template-variable,html.theme--documenter-dark .hljs-tag,html.theme--documenter-dark .hljs-name,html.theme--documenter-dark .hljs-selector-id,html.theme--documenter-dark .hljs-selector-class,html.theme--documenter-dark .hljs-regexp,html.theme--documenter-dark .hljs-deletion{color:#ffa07a}html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-link{color:#f5ab35}html.theme--documenter-dark .hljs-attribute{color:#ffd700}html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-addition{color:#abe338}html.theme--documenter-dark .hljs-title,html.theme--documenter-dark .hljs-section{color:#00e0e0}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{color:#dcc6e0}html.theme--documenter-dark .hljs-emphasis{font-style:italic}html.theme--documenter-dark .hljs-strong{font-weight:bold}@media screen and (-ms-high-contrast: active){html.theme--documenter-dark .hljs-addition,html.theme--documenter-dark .hljs-attribute,html.theme--documenter-dark .hljs-built_in,html.theme--documenter-dark .hljs-bullet,html.theme--documenter-dark .hljs-comment,html.theme--documenter-dark .hljs-link,html.theme--documenter-dark .hljs-literal,html.theme--documenter-dark .hljs-meta,html.theme--documenter-dark .hljs-number,html.theme--documenter-dark .hljs-params,html.theme--documenter-dark .hljs-string,html.theme--documenter-dark .hljs-symbol,html.theme--documenter-dark .hljs-type,html.theme--documenter-dark .hljs-quote{color:highlight}html.theme--documenter-dark .hljs-keyword,html.theme--documenter-dark .hljs-selector-tag{font-weight:bold}}html.theme--documenter-dark .hljs-subst{color:#f8f8f2}html.theme--documenter-dark .search-result-link{border-radius:0.7em;transition:all 300ms}html.theme--documenter-dark .search-result-link:hover,html.theme--documenter-dark .search-result-link:focus{background-color:rgba(0,128,128,0.1)}html.theme--documenter-dark .search-result-link .property-search-result-badge,html.theme--documenter-dark .search-result-link .search-filter{transition:all 300ms}html.theme--documenter-dark .search-result-link:hover .property-search-result-badge,html.theme--documenter-dark .search-result-link:hover .search-filter,html.theme--documenter-dark .search-result-link:focus .property-search-result-badge,html.theme--documenter-dark .search-result-link:focus .search-filter{color:#333 !important;background-color:#f1f5f9 !important}html.theme--documenter-dark .search-result-title{color:whitesmoke}html.theme--documenter-dark .search-result-highlight{background-color:greenyellow;color:black}html.theme--documenter-dark .search-divider{border-bottom:1px solid #5e6d6f50}html.theme--documenter-dark .w-100{width:100%}html.theme--documenter-dark .gap-2{gap:0.5rem}html.theme--documenter-dark .gap-4{gap:1rem} diff --git a/v1.5.0/assets/themes/documenter-light.css b/v1.5.0/assets/themes/documenter-light.css new file mode 100644 index 00000000000..07f9d088303 --- /dev/null +++ b/v1.5.0/assets/themes/documenter-light.css @@ -0,0 +1,9 @@ +.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.file-cta,.file-name,.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input,.button{-moz-appearance:none;-webkit-appearance:none;align-items:center;border:1px solid transparent;border-radius:4px;box-shadow:none;display:inline-flex;font-size:1rem;height:2.5em;justify-content:flex-start;line-height:1.5;padding-bottom:calc(0.5em - 1px);padding-left:calc(0.75em - 1px);padding-right:calc(0.75em - 1px);padding-top:calc(0.5em - 1px);position:relative;vertical-align:top}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus,.pagination-ellipsis:focus,.file-cta:focus,.file-name:focus,.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.button:focus,.is-focused.pagination-previous,.is-focused.pagination-next,.is-focused.pagination-link,.is-focused.pagination-ellipsis,.is-focused.file-cta,.is-focused.file-name,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-focused.button,.pagination-previous:active,.pagination-next:active,.pagination-link:active,.pagination-ellipsis:active,.file-cta:active,.file-name:active,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.button:active,.is-active.pagination-previous,.is-active.pagination-next,.is-active.pagination-link,.is-active.pagination-ellipsis,.is-active.file-cta,.is-active.file-name,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.is-active.button{outline:none}.pagination-previous[disabled],.pagination-next[disabled],.pagination-link[disabled],.pagination-ellipsis[disabled],.file-cta[disabled],.file-name[disabled],.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],.button[disabled],fieldset[disabled] .pagination-previous,fieldset[disabled] .pagination-next,fieldset[disabled] .pagination-link,fieldset[disabled] .pagination-ellipsis,fieldset[disabled] .file-cta,fieldset[disabled] .file-name,fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input,fieldset[disabled] .button{cursor:not-allowed}.tabs,.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis,.breadcrumb,.file,.button,.is-unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.navbar-link:not(.is-arrowless)::after,.select:not(.is-multiple):not(.is-loading)::after{border:3px solid rgba(0,0,0,0);border-radius:2px;border-right:0;border-top:0;content:" ";display:block;height:0.625em;margin-top:-0.4375em;pointer-events:none;position:absolute;top:50%;transform:rotate(-45deg);transform-origin:center;width:0.625em}.admonition:not(:last-child),.tabs:not(:last-child),.pagination:not(:last-child),.message:not(:last-child),.level:not(:last-child),.breadcrumb:not(:last-child),.block:not(:last-child),.title:not(:last-child),.subtitle:not(:last-child),.table-container:not(:last-child),.table:not(:last-child),.progress:not(:last-child),.notification:not(:last-child),.content:not(:last-child),.box:not(:last-child){margin-bottom:1.5rem}.modal-close,.delete{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-moz-appearance:none;-webkit-appearance:none;background-color:rgba(10,10,10,0.2);border:none;border-radius:9999px;cursor:pointer;pointer-events:auto;display:inline-block;flex-grow:0;flex-shrink:0;font-size:0;height:20px;max-height:20px;max-width:20px;min-height:20px;min-width:20px;outline:none;position:relative;vertical-align:top;width:20px}.modal-close::before,.delete::before,.modal-close::after,.delete::after{background-color:#fff;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.modal-close::before,.delete::before{height:2px;width:50%}.modal-close::after,.delete::after{height:50%;width:2px}.modal-close:hover,.delete:hover,.modal-close:focus,.delete:focus{background-color:rgba(10,10,10,0.3)}.modal-close:active,.delete:active{background-color:rgba(10,10,10,0.4)}.is-small.modal-close,#documenter .docs-sidebar form.docs-search>input.modal-close,.is-small.delete,#documenter .docs-sidebar form.docs-search>input.delete{height:16px;max-height:16px;max-width:16px;min-height:16px;min-width:16px;width:16px}.is-medium.modal-close,.is-medium.delete{height:24px;max-height:24px;max-width:24px;min-height:24px;min-width:24px;width:24px}.is-large.modal-close,.is-large.delete{height:32px;max-height:32px;max-width:32px;min-height:32px;min-width:32px;width:32px}.control.is-loading::after,.select.is-loading::after,.loader,.button.is-loading::after{animation:spinAround 500ms infinite linear;border:2px solid #dbdbdb;border-radius:9999px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.hero-video,.modal-background,.modal,.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio,.is-overlay{bottom:0;left:0;position:absolute;right:0;top:0}.navbar-burger{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0}.has-text-white{color:#fff !important}a.has-text-white:hover,a.has-text-white:focus{color:#e6e6e6 !important}.has-background-white{background-color:#fff !important}.has-text-black{color:#0a0a0a !important}a.has-text-black:hover,a.has-text-black:focus{color:#000 !important}.has-background-black{background-color:#0a0a0a !important}.has-text-light{color:#f5f5f5 !important}a.has-text-light:hover,a.has-text-light:focus{color:#dbdbdb !important}.has-background-light{background-color:#f5f5f5 !important}.has-text-dark{color:#363636 !important}a.has-text-dark:hover,a.has-text-dark:focus{color:#1c1c1c !important}.has-background-dark{background-color:#363636 !important}.has-text-primary{color:#4eb5de !important}a.has-text-primary:hover,a.has-text-primary:focus{color:#27a1d2 !important}.has-background-primary{background-color:#4eb5de !important}.has-text-primary-light{color:#eef8fc !important}a.has-text-primary-light:hover,a.has-text-primary-light:focus{color:#c3e6f4 !important}.has-background-primary-light{background-color:#eef8fc !important}.has-text-primary-dark{color:#1a6d8e !important}a.has-text-primary-dark:hover,a.has-text-primary-dark:focus{color:#228eb9 !important}.has-background-primary-dark{background-color:#1a6d8e !important}.has-text-link{color:#2e63b8 !important}a.has-text-link:hover,a.has-text-link:focus{color:#244d8f !important}.has-background-link{background-color:#2e63b8 !important}.has-text-link-light{color:#eff3fb !important}a.has-text-link-light:hover,a.has-text-link-light:focus{color:#c6d6f1 !important}.has-background-link-light{background-color:#eff3fb !important}.has-text-link-dark{color:#3169c4 !important}a.has-text-link-dark:hover,a.has-text-link-dark:focus{color:#5485d4 !important}.has-background-link-dark{background-color:#3169c4 !important}.has-text-info{color:#209cee !important}a.has-text-info:hover,a.has-text-info:focus{color:#1081cb !important}.has-background-info{background-color:#209cee !important}.has-text-info-light{color:#ecf7fe !important}a.has-text-info-light:hover,a.has-text-info-light:focus{color:#bde2fa !important}.has-background-info-light{background-color:#ecf7fe !important}.has-text-info-dark{color:#0e72b4 !important}a.has-text-info-dark:hover,a.has-text-info-dark:focus{color:#1190e3 !important}.has-background-info-dark{background-color:#0e72b4 !important}.has-text-success{color:#22c35b !important}a.has-text-success:hover,a.has-text-success:focus{color:#1a9847 !important}.has-background-success{background-color:#22c35b !important}.has-text-success-light{color:#eefcf3 !important}a.has-text-success-light:hover,a.has-text-success-light:focus{color:#c2f4d4 !important}.has-background-success-light{background-color:#eefcf3 !important}.has-text-success-dark{color:#198f43 !important}a.has-text-success-dark:hover,a.has-text-success-dark:focus{color:#21bb57 !important}.has-background-success-dark{background-color:#198f43 !important}.has-text-warning{color:#ffdd57 !important}a.has-text-warning:hover,a.has-text-warning:focus{color:#ffd324 !important}.has-background-warning{background-color:#ffdd57 !important}.has-text-warning-light{color:#fffbeb !important}a.has-text-warning-light:hover,a.has-text-warning-light:focus{color:#fff1b8 !important}.has-background-warning-light{background-color:#fffbeb !important}.has-text-warning-dark{color:#947600 !important}a.has-text-warning-dark:hover,a.has-text-warning-dark:focus{color:#c79f00 !important}.has-background-warning-dark{background-color:#947600 !important}.has-text-danger{color:#da0b00 !important}a.has-text-danger:hover,a.has-text-danger:focus{color:#a70800 !important}.has-background-danger{background-color:#da0b00 !important}.has-text-danger-light{color:#ffeceb !important}a.has-text-danger-light:hover,a.has-text-danger-light:focus{color:#ffbbb8 !important}.has-background-danger-light{background-color:#ffeceb !important}.has-text-danger-dark{color:#f50c00 !important}a.has-text-danger-dark:hover,a.has-text-danger-dark:focus{color:#ff3429 !important}.has-background-danger-dark{background-color:#f50c00 !important}.has-text-black-bis{color:#121212 !important}.has-background-black-bis{background-color:#121212 !important}.has-text-black-ter{color:#242424 !important}.has-background-black-ter{background-color:#242424 !important}.has-text-grey-darker{color:#363636 !important}.has-background-grey-darker{background-color:#363636 !important}.has-text-grey-dark{color:#4a4a4a !important}.has-background-grey-dark{background-color:#4a4a4a !important}.has-text-grey{color:#6b6b6b !important}.has-background-grey{background-color:#6b6b6b !important}.has-text-grey-light{color:#b5b5b5 !important}.has-background-grey-light{background-color:#b5b5b5 !important}.has-text-grey-lighter{color:#dbdbdb !important}.has-background-grey-lighter{background-color:#dbdbdb !important}.has-text-white-ter{color:#f5f5f5 !important}.has-background-white-ter{background-color:#f5f5f5 !important}.has-text-white-bis{color:#fafafa !important}.has-background-white-bis{background-color:#fafafa !important}.is-flex-direction-row{flex-direction:row !important}.is-flex-direction-row-reverse{flex-direction:row-reverse !important}.is-flex-direction-column{flex-direction:column !important}.is-flex-direction-column-reverse{flex-direction:column-reverse !important}.is-flex-wrap-nowrap{flex-wrap:nowrap !important}.is-flex-wrap-wrap{flex-wrap:wrap !important}.is-flex-wrap-wrap-reverse{flex-wrap:wrap-reverse !important}.is-justify-content-flex-start{justify-content:flex-start !important}.is-justify-content-flex-end{justify-content:flex-end !important}.is-justify-content-center{justify-content:center !important}.is-justify-content-space-between{justify-content:space-between !important}.is-justify-content-space-around{justify-content:space-around !important}.is-justify-content-space-evenly{justify-content:space-evenly !important}.is-justify-content-start{justify-content:start !important}.is-justify-content-end{justify-content:end !important}.is-justify-content-left{justify-content:left !important}.is-justify-content-right{justify-content:right !important}.is-align-content-flex-start{align-content:flex-start !important}.is-align-content-flex-end{align-content:flex-end !important}.is-align-content-center{align-content:center !important}.is-align-content-space-between{align-content:space-between !important}.is-align-content-space-around{align-content:space-around !important}.is-align-content-space-evenly{align-content:space-evenly !important}.is-align-content-stretch{align-content:stretch !important}.is-align-content-start{align-content:start !important}.is-align-content-end{align-content:end !important}.is-align-content-baseline{align-content:baseline !important}.is-align-items-stretch{align-items:stretch !important}.is-align-items-flex-start{align-items:flex-start !important}.is-align-items-flex-end{align-items:flex-end !important}.is-align-items-center{align-items:center !important}.is-align-items-baseline{align-items:baseline !important}.is-align-items-start{align-items:start !important}.is-align-items-end{align-items:end !important}.is-align-items-self-start{align-items:self-start !important}.is-align-items-self-end{align-items:self-end !important}.is-align-self-auto{align-self:auto !important}.is-align-self-flex-start{align-self:flex-start !important}.is-align-self-flex-end{align-self:flex-end !important}.is-align-self-center{align-self:center !important}.is-align-self-baseline{align-self:baseline !important}.is-align-self-stretch{align-self:stretch !important}.is-flex-grow-0{flex-grow:0 !important}.is-flex-grow-1{flex-grow:1 !important}.is-flex-grow-2{flex-grow:2 !important}.is-flex-grow-3{flex-grow:3 !important}.is-flex-grow-4{flex-grow:4 !important}.is-flex-grow-5{flex-grow:5 !important}.is-flex-shrink-0{flex-shrink:0 !important}.is-flex-shrink-1{flex-shrink:1 !important}.is-flex-shrink-2{flex-shrink:2 !important}.is-flex-shrink-3{flex-shrink:3 !important}.is-flex-shrink-4{flex-shrink:4 !important}.is-flex-shrink-5{flex-shrink:5 !important}.is-clearfix::after{clear:both;content:" ";display:table}.is-pulled-left{float:left !important}.is-pulled-right{float:right !important}.is-radiusless{border-radius:0 !important}.is-shadowless{box-shadow:none !important}.is-clickable{cursor:pointer !important;pointer-events:all !important}.is-clipped{overflow:hidden !important}.is-relative{position:relative !important}.is-marginless{margin:0 !important}.is-paddingless{padding:0 !important}.m-0{margin:0 !important}.mt-0{margin-top:0 !important}.mr-0{margin-right:0 !important}.mb-0{margin-bottom:0 !important}.ml-0{margin-left:0 !important}.mx-0{margin-left:0 !important;margin-right:0 !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.m-1{margin:.25rem !important}.mt-1{margin-top:.25rem !important}.mr-1{margin-right:.25rem !important}.mb-1{margin-bottom:.25rem !important}.ml-1{margin-left:.25rem !important}.mx-1{margin-left:.25rem !important;margin-right:.25rem !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.m-2{margin:.5rem !important}.mt-2{margin-top:.5rem !important}.mr-2{margin-right:.5rem !important}.mb-2{margin-bottom:.5rem !important}.ml-2{margin-left:.5rem !important}.mx-2{margin-left:.5rem !important;margin-right:.5rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.m-3{margin:.75rem !important}.mt-3{margin-top:.75rem !important}.mr-3{margin-right:.75rem !important}.mb-3{margin-bottom:.75rem !important}.ml-3{margin-left:.75rem !important}.mx-3{margin-left:.75rem !important;margin-right:.75rem !important}.my-3{margin-top:.75rem !important;margin-bottom:.75rem !important}.m-4{margin:1rem !important}.mt-4{margin-top:1rem !important}.mr-4{margin-right:1rem !important}.mb-4{margin-bottom:1rem !important}.ml-4{margin-left:1rem !important}.mx-4{margin-left:1rem !important;margin-right:1rem !important}.my-4{margin-top:1rem !important;margin-bottom:1rem !important}.m-5{margin:1.5rem !important}.mt-5{margin-top:1.5rem !important}.mr-5{margin-right:1.5rem !important}.mb-5{margin-bottom:1.5rem !important}.ml-5{margin-left:1.5rem !important}.mx-5{margin-left:1.5rem !important;margin-right:1.5rem !important}.my-5{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.m-6{margin:3rem !important}.mt-6{margin-top:3rem !important}.mr-6{margin-right:3rem !important}.mb-6{margin-bottom:3rem !important}.ml-6{margin-left:3rem !important}.mx-6{margin-left:3rem !important;margin-right:3rem !important}.my-6{margin-top:3rem !important;margin-bottom:3rem !important}.m-auto{margin:auto !important}.mt-auto{margin-top:auto !important}.mr-auto{margin-right:auto !important}.mb-auto{margin-bottom:auto !important}.ml-auto{margin-left:auto !important}.mx-auto{margin-left:auto !important;margin-right:auto !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.p-0{padding:0 !important}.pt-0{padding-top:0 !important}.pr-0{padding-right:0 !important}.pb-0{padding-bottom:0 !important}.pl-0{padding-left:0 !important}.px-0{padding-left:0 !important;padding-right:0 !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.p-1{padding:.25rem !important}.pt-1{padding-top:.25rem !important}.pr-1{padding-right:.25rem !important}.pb-1{padding-bottom:.25rem !important}.pl-1{padding-left:.25rem !important}.px-1{padding-left:.25rem !important;padding-right:.25rem !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.p-2{padding:.5rem !important}.pt-2{padding-top:.5rem !important}.pr-2{padding-right:.5rem !important}.pb-2{padding-bottom:.5rem !important}.pl-2{padding-left:.5rem !important}.px-2{padding-left:.5rem !important;padding-right:.5rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.p-3{padding:.75rem !important}.pt-3{padding-top:.75rem !important}.pr-3{padding-right:.75rem !important}.pb-3{padding-bottom:.75rem !important}.pl-3{padding-left:.75rem !important}.px-3{padding-left:.75rem !important;padding-right:.75rem !important}.py-3{padding-top:.75rem !important;padding-bottom:.75rem !important}.p-4{padding:1rem !important}.pt-4{padding-top:1rem !important}.pr-4{padding-right:1rem !important}.pb-4{padding-bottom:1rem !important}.pl-4{padding-left:1rem !important}.px-4{padding-left:1rem !important;padding-right:1rem !important}.py-4{padding-top:1rem !important;padding-bottom:1rem !important}.p-5{padding:1.5rem !important}.pt-5{padding-top:1.5rem !important}.pr-5{padding-right:1.5rem !important}.pb-5{padding-bottom:1.5rem !important}.pl-5{padding-left:1.5rem !important}.px-5{padding-left:1.5rem !important;padding-right:1.5rem !important}.py-5{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.p-6{padding:3rem !important}.pt-6{padding-top:3rem !important}.pr-6{padding-right:3rem !important}.pb-6{padding-bottom:3rem !important}.pl-6{padding-left:3rem !important}.px-6{padding-left:3rem !important;padding-right:3rem !important}.py-6{padding-top:3rem !important;padding-bottom:3rem !important}.p-auto{padding:auto !important}.pt-auto{padding-top:auto !important}.pr-auto{padding-right:auto !important}.pb-auto{padding-bottom:auto !important}.pl-auto{padding-left:auto !important}.px-auto{padding-left:auto !important;padding-right:auto !important}.py-auto{padding-top:auto !important;padding-bottom:auto !important}.is-size-1{font-size:3rem !important}.is-size-2{font-size:2.5rem !important}.is-size-3{font-size:2rem !important}.is-size-4{font-size:1.5rem !important}.is-size-5{font-size:1.25rem !important}.is-size-6{font-size:1rem !important}.is-size-7,.docstring>section>a.docs-sourcelink{font-size:.75rem !important}@media screen and (max-width: 768px){.is-size-1-mobile{font-size:3rem !important}.is-size-2-mobile{font-size:2.5rem !important}.is-size-3-mobile{font-size:2rem !important}.is-size-4-mobile{font-size:1.5rem !important}.is-size-5-mobile{font-size:1.25rem !important}.is-size-6-mobile{font-size:1rem !important}.is-size-7-mobile{font-size:.75rem !important}}@media screen and (min-width: 769px),print{.is-size-1-tablet{font-size:3rem !important}.is-size-2-tablet{font-size:2.5rem !important}.is-size-3-tablet{font-size:2rem !important}.is-size-4-tablet{font-size:1.5rem !important}.is-size-5-tablet{font-size:1.25rem !important}.is-size-6-tablet{font-size:1rem !important}.is-size-7-tablet{font-size:.75rem !important}}@media screen and (max-width: 1055px){.is-size-1-touch{font-size:3rem !important}.is-size-2-touch{font-size:2.5rem !important}.is-size-3-touch{font-size:2rem !important}.is-size-4-touch{font-size:1.5rem !important}.is-size-5-touch{font-size:1.25rem !important}.is-size-6-touch{font-size:1rem !important}.is-size-7-touch{font-size:.75rem !important}}@media screen and (min-width: 1056px){.is-size-1-desktop{font-size:3rem !important}.is-size-2-desktop{font-size:2.5rem !important}.is-size-3-desktop{font-size:2rem !important}.is-size-4-desktop{font-size:1.5rem !important}.is-size-5-desktop{font-size:1.25rem !important}.is-size-6-desktop{font-size:1rem !important}.is-size-7-desktop{font-size:.75rem !important}}@media screen and (min-width: 1216px){.is-size-1-widescreen{font-size:3rem !important}.is-size-2-widescreen{font-size:2.5rem !important}.is-size-3-widescreen{font-size:2rem !important}.is-size-4-widescreen{font-size:1.5rem !important}.is-size-5-widescreen{font-size:1.25rem !important}.is-size-6-widescreen{font-size:1rem !important}.is-size-7-widescreen{font-size:.75rem !important}}@media screen and (min-width: 1408px){.is-size-1-fullhd{font-size:3rem !important}.is-size-2-fullhd{font-size:2.5rem !important}.is-size-3-fullhd{font-size:2rem !important}.is-size-4-fullhd{font-size:1.5rem !important}.is-size-5-fullhd{font-size:1.25rem !important}.is-size-6-fullhd{font-size:1rem !important}.is-size-7-fullhd{font-size:.75rem !important}}.has-text-centered{text-align:center !important}.has-text-justified{text-align:justify !important}.has-text-left{text-align:left !important}.has-text-right{text-align:right !important}@media screen and (max-width: 768px){.has-text-centered-mobile{text-align:center !important}}@media screen and (min-width: 769px),print{.has-text-centered-tablet{text-align:center !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-centered-tablet-only{text-align:center !important}}@media screen and (max-width: 1055px){.has-text-centered-touch{text-align:center !important}}@media screen and (min-width: 1056px){.has-text-centered-desktop{text-align:center !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-centered-desktop-only{text-align:center !important}}@media screen and (min-width: 1216px){.has-text-centered-widescreen{text-align:center !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-centered-widescreen-only{text-align:center !important}}@media screen and (min-width: 1408px){.has-text-centered-fullhd{text-align:center !important}}@media screen and (max-width: 768px){.has-text-justified-mobile{text-align:justify !important}}@media screen and (min-width: 769px),print{.has-text-justified-tablet{text-align:justify !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-justified-tablet-only{text-align:justify !important}}@media screen and (max-width: 1055px){.has-text-justified-touch{text-align:justify !important}}@media screen and (min-width: 1056px){.has-text-justified-desktop{text-align:justify !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-justified-desktop-only{text-align:justify !important}}@media screen and (min-width: 1216px){.has-text-justified-widescreen{text-align:justify !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-justified-widescreen-only{text-align:justify !important}}@media screen and (min-width: 1408px){.has-text-justified-fullhd{text-align:justify !important}}@media screen and (max-width: 768px){.has-text-left-mobile{text-align:left !important}}@media screen and (min-width: 769px),print{.has-text-left-tablet{text-align:left !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-left-tablet-only{text-align:left !important}}@media screen and (max-width: 1055px){.has-text-left-touch{text-align:left !important}}@media screen and (min-width: 1056px){.has-text-left-desktop{text-align:left !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-left-desktop-only{text-align:left !important}}@media screen and (min-width: 1216px){.has-text-left-widescreen{text-align:left !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-left-widescreen-only{text-align:left !important}}@media screen and (min-width: 1408px){.has-text-left-fullhd{text-align:left !important}}@media screen and (max-width: 768px){.has-text-right-mobile{text-align:right !important}}@media screen and (min-width: 769px),print{.has-text-right-tablet{text-align:right !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.has-text-right-tablet-only{text-align:right !important}}@media screen and (max-width: 1055px){.has-text-right-touch{text-align:right !important}}@media screen and (min-width: 1056px){.has-text-right-desktop{text-align:right !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.has-text-right-desktop-only{text-align:right !important}}@media screen and (min-width: 1216px){.has-text-right-widescreen{text-align:right !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.has-text-right-widescreen-only{text-align:right !important}}@media screen and (min-width: 1408px){.has-text-right-fullhd{text-align:right !important}}.is-capitalized{text-transform:capitalize !important}.is-lowercase{text-transform:lowercase !important}.is-uppercase{text-transform:uppercase !important}.is-italic{font-style:italic !important}.is-underlined{text-decoration:underline !important}.has-text-weight-light{font-weight:300 !important}.has-text-weight-normal{font-weight:400 !important}.has-text-weight-medium{font-weight:500 !important}.has-text-weight-semibold{font-weight:600 !important}.has-text-weight-bold{font-weight:700 !important}.is-family-primary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-secondary{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-sans-serif{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif !important}.is-family-monospace{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-family-code{font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace !important}.is-block{display:block !important}@media screen and (max-width: 768px){.is-block-mobile{display:block !important}}@media screen and (min-width: 769px),print{.is-block-tablet{display:block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-block-tablet-only{display:block !important}}@media screen and (max-width: 1055px){.is-block-touch{display:block !important}}@media screen and (min-width: 1056px){.is-block-desktop{display:block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-block-desktop-only{display:block !important}}@media screen and (min-width: 1216px){.is-block-widescreen{display:block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-block-widescreen-only{display:block !important}}@media screen and (min-width: 1408px){.is-block-fullhd{display:block !important}}.is-flex{display:flex !important}@media screen and (max-width: 768px){.is-flex-mobile{display:flex !important}}@media screen and (min-width: 769px),print{.is-flex-tablet{display:flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-flex-tablet-only{display:flex !important}}@media screen and (max-width: 1055px){.is-flex-touch{display:flex !important}}@media screen and (min-width: 1056px){.is-flex-desktop{display:flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-flex-desktop-only{display:flex !important}}@media screen and (min-width: 1216px){.is-flex-widescreen{display:flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-flex-widescreen-only{display:flex !important}}@media screen and (min-width: 1408px){.is-flex-fullhd{display:flex !important}}.is-inline{display:inline !important}@media screen and (max-width: 768px){.is-inline-mobile{display:inline !important}}@media screen and (min-width: 769px),print{.is-inline-tablet{display:inline !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-tablet-only{display:inline !important}}@media screen and (max-width: 1055px){.is-inline-touch{display:inline !important}}@media screen and (min-width: 1056px){.is-inline-desktop{display:inline !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-desktop-only{display:inline !important}}@media screen and (min-width: 1216px){.is-inline-widescreen{display:inline !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-widescreen-only{display:inline !important}}@media screen and (min-width: 1408px){.is-inline-fullhd{display:inline !important}}.is-inline-block{display:inline-block !important}@media screen and (max-width: 768px){.is-inline-block-mobile{display:inline-block !important}}@media screen and (min-width: 769px),print{.is-inline-block-tablet{display:inline-block !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-block-tablet-only{display:inline-block !important}}@media screen and (max-width: 1055px){.is-inline-block-touch{display:inline-block !important}}@media screen and (min-width: 1056px){.is-inline-block-desktop{display:inline-block !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-block-desktop-only{display:inline-block !important}}@media screen and (min-width: 1216px){.is-inline-block-widescreen{display:inline-block !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-block-widescreen-only{display:inline-block !important}}@media screen and (min-width: 1408px){.is-inline-block-fullhd{display:inline-block !important}}.is-inline-flex{display:inline-flex !important}@media screen and (max-width: 768px){.is-inline-flex-mobile{display:inline-flex !important}}@media screen and (min-width: 769px),print{.is-inline-flex-tablet{display:inline-flex !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-inline-flex-tablet-only{display:inline-flex !important}}@media screen and (max-width: 1055px){.is-inline-flex-touch{display:inline-flex !important}}@media screen and (min-width: 1056px){.is-inline-flex-desktop{display:inline-flex !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-inline-flex-desktop-only{display:inline-flex !important}}@media screen and (min-width: 1216px){.is-inline-flex-widescreen{display:inline-flex !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-inline-flex-widescreen-only{display:inline-flex !important}}@media screen and (min-width: 1408px){.is-inline-flex-fullhd{display:inline-flex !important}}.is-hidden{display:none !important}.is-sr-only{border:none !important;clip:rect(0, 0, 0, 0) !important;height:0.01em !important;overflow:hidden !important;padding:0 !important;position:absolute !important;white-space:nowrap !important;width:0.01em !important}@media screen and (max-width: 768px){.is-hidden-mobile{display:none !important}}@media screen and (min-width: 769px),print{.is-hidden-tablet{display:none !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-hidden-tablet-only{display:none !important}}@media screen and (max-width: 1055px){.is-hidden-touch{display:none !important}}@media screen and (min-width: 1056px){.is-hidden-desktop{display:none !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-hidden-desktop-only{display:none !important}}@media screen and (min-width: 1216px){.is-hidden-widescreen{display:none !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-hidden-widescreen-only{display:none !important}}@media screen and (min-width: 1408px){.is-hidden-fullhd{display:none !important}}.is-invisible{visibility:hidden !important}@media screen and (max-width: 768px){.is-invisible-mobile{visibility:hidden !important}}@media screen and (min-width: 769px),print{.is-invisible-tablet{visibility:hidden !important}}@media screen and (min-width: 769px) and (max-width: 1055px){.is-invisible-tablet-only{visibility:hidden !important}}@media screen and (max-width: 1055px){.is-invisible-touch{visibility:hidden !important}}@media screen and (min-width: 1056px){.is-invisible-desktop{visibility:hidden !important}}@media screen and (min-width: 1056px) and (max-width: 1215px){.is-invisible-desktop-only{visibility:hidden !important}}@media screen and (min-width: 1216px){.is-invisible-widescreen{visibility:hidden !important}}@media screen and (min-width: 1216px) and (max-width: 1407px){.is-invisible-widescreen-only{visibility:hidden !important}}@media screen and (min-width: 1408px){.is-invisible-fullhd{visibility:hidden !important}}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:#fff;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:auto;overflow-y:scroll;text-rendering:optimizeLegibility;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:"Lato Medium",-apple-system,BlinkMacSystemFont,"Segoe UI","Helvetica Neue","Helvetica","Arial",sans-serif}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}body{color:#222;font-size:1em;font-weight:400;line-height:1.5}a{color:#2e63b8;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:rgba(0,0,0,0.05);color:#000;font-size:.875em;font-weight:normal;padding:.1em}hr{background-color:#f5f5f5;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type="checkbox"],input[type="radio"]{vertical-align:baseline}small{font-size:.875em}span{font-style:inherit;font-weight:inherit}strong{color:#222;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:#f5f5f5;color:#222;font-size:.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:#222}@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.box{background-color:#fff;border-radius:6px;box-shadow:#bbb;color:#222;display:block;padding:1.25rem}a.box:hover,a.box:focus{box-shadow:0 0.5em 1em -0.125em rgba(10,10,10,0.1),0 0 0 1px #2e63b8}a.box:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2),0 0 0 1px #2e63b8}.button{background-color:#fff;border-color:#dbdbdb;border-width:1px;color:#222;cursor:pointer;justify-content:center;padding-bottom:calc(0.5em - 1px);padding-left:1em;padding-right:1em;padding-top:calc(0.5em - 1px);text-align:center;white-space:nowrap}.button strong{color:inherit}.button .icon,.button .icon.is-small,.button #documenter .docs-sidebar form.docs-search>input.icon,#documenter .docs-sidebar .button form.docs-search>input.icon,.button .icon.is-medium,.button .icon.is-large{height:1.5em;width:1.5em}.button .icon:first-child:not(:last-child){margin-left:calc(-0.5em - 1px);margin-right:.25em}.button .icon:last-child:not(:first-child){margin-left:.25em;margin-right:calc(-0.5em - 1px)}.button .icon:first-child:last-child{margin-left:calc(-0.5em - 1px);margin-right:calc(-0.5em - 1px)}.button:hover,.button.is-hovered{border-color:#b5b5b5;color:#363636}.button:focus,.button.is-focused{border-color:#3c5dcd;color:#363636}.button:focus:not(:active),.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button:active,.button.is-active{border-color:#4a4a4a;color:#363636}.button.is-text{background-color:transparent;border-color:transparent;color:#222;text-decoration:underline}.button.is-text:hover,.button.is-text.is-hovered,.button.is-text:focus,.button.is-text.is-focused{background-color:#f5f5f5;color:#222}.button.is-text:active,.button.is-text.is-active{background-color:#e8e8e8;color:#222}.button.is-text[disabled],fieldset[disabled] .button.is-text{background-color:transparent;border-color:transparent;box-shadow:none}.button.is-ghost{background:none;border-color:rgba(0,0,0,0);color:#2e63b8;text-decoration:none}.button.is-ghost:hover,.button.is-ghost.is-hovered{color:#2e63b8;text-decoration:underline}.button.is-white{background-color:#fff;border-color:transparent;color:#0a0a0a}.button.is-white:hover,.button.is-white.is-hovered{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.button.is-white:focus,.button.is-white.is-focused{border-color:transparent;color:#0a0a0a}.button.is-white:focus:not(:active),.button.is-white.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.button.is-white:active,.button.is-white.is-active{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.button.is-white[disabled],fieldset[disabled] .button.is-white{background-color:#fff;border-color:#fff;box-shadow:none}.button.is-white.is-inverted{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted:hover,.button.is-white.is-inverted.is-hovered{background-color:#000}.button.is-white.is-inverted[disabled],fieldset[disabled] .button.is-white.is-inverted{background-color:#0a0a0a;border-color:transparent;box-shadow:none;color:#fff}.button.is-white.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-white.is-outlined:hover,.button.is-white.is-outlined.is-hovered,.button.is-white.is-outlined:focus,.button.is-white.is-outlined.is-focused{background-color:#fff;border-color:#fff;color:#0a0a0a}.button.is-white.is-outlined.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-outlined.is-loading:hover::after,.button.is-white.is-outlined.is-loading.is-hovered::after,.button.is-white.is-outlined.is-loading:focus::after,.button.is-white.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-white.is-outlined[disabled],fieldset[disabled] .button.is-white.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-white.is-inverted.is-outlined:hover,.button.is-white.is-inverted.is-outlined.is-hovered,.button.is-white.is-inverted.is-outlined:focus,.button.is-white.is-inverted.is-outlined.is-focused{background-color:#0a0a0a;color:#fff}.button.is-white.is-inverted.is-outlined.is-loading:hover::after,.button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-white.is-inverted.is-outlined.is-loading:focus::after,.button.is-white.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-white.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-white.is-inverted.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black{background-color:#0a0a0a;border-color:transparent;color:#fff}.button.is-black:hover,.button.is-black.is-hovered{background-color:#040404;border-color:transparent;color:#fff}.button.is-black:focus,.button.is-black.is-focused{border-color:transparent;color:#fff}.button.is-black:focus:not(:active),.button.is-black.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.button.is-black:active,.button.is-black.is-active{background-color:#000;border-color:transparent;color:#fff}.button.is-black[disabled],fieldset[disabled] .button.is-black{background-color:#0a0a0a;border-color:#0a0a0a;box-shadow:none}.button.is-black.is-inverted{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted:hover,.button.is-black.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-black.is-inverted[disabled],fieldset[disabled] .button.is-black.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#0a0a0a}.button.is-black.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;color:#0a0a0a}.button.is-black.is-outlined:hover,.button.is-black.is-outlined.is-hovered,.button.is-black.is-outlined:focus,.button.is-black.is-outlined.is-focused{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.button.is-black.is-outlined.is-loading::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-outlined.is-loading:hover::after,.button.is-black.is-outlined.is-loading.is-hovered::after,.button.is-black.is-outlined.is-loading:focus::after,.button.is-black.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-black.is-outlined[disabled],fieldset[disabled] .button.is-black.is-outlined{background-color:transparent;border-color:#0a0a0a;box-shadow:none;color:#0a0a0a}.button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-black.is-inverted.is-outlined:hover,.button.is-black.is-inverted.is-outlined.is-hovered,.button.is-black.is-inverted.is-outlined:focus,.button.is-black.is-inverted.is-outlined.is-focused{background-color:#fff;color:#0a0a0a}.button.is-black.is-inverted.is-outlined.is-loading:hover::after,.button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-black.is-inverted.is-outlined.is-loading:focus::after,.button.is-black.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #0a0a0a #0a0a0a !important}.button.is-black.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-black.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-light{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:hover,.button.is-light.is-hovered{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:focus,.button.is-light.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light:focus:not(:active),.button.is-light.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.button.is-light:active,.button.is-light.is-active{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-light[disabled],fieldset[disabled] .button.is-light{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none}.button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);color:#f5f5f5}.button.is-light.is-inverted:hover,.button.is-light.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-light.is-inverted[disabled],fieldset[disabled] .button.is-light.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#f5f5f5}.button.is-light.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;color:#f5f5f5}.button.is-light.is-outlined:hover,.button.is-light.is-outlined.is-hovered,.button.is-light.is-outlined:focus,.button.is-light.is-outlined.is-focused{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,0.7)}.button.is-light.is-outlined.is-loading::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-outlined.is-loading:hover::after,.button.is-light.is-outlined.is-loading.is-hovered::after,.button.is-light.is-outlined.is-loading:focus::after,.button.is-light.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-light.is-outlined[disabled],fieldset[disabled] .button.is-light.is-outlined{background-color:transparent;border-color:#f5f5f5;box-shadow:none;color:#f5f5f5}.button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.button.is-light.is-inverted.is-outlined:hover,.button.is-light.is-inverted.is-outlined.is-hovered,.button.is-light.is-inverted.is-outlined:focus,.button.is-light.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#f5f5f5}.button.is-light.is-inverted.is-outlined.is-loading:hover::after,.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-light.is-inverted.is-outlined.is-loading:focus::after,.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #f5f5f5 #f5f5f5 !important}.button.is-light.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-light.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-dark,.content kbd.button{background-color:#363636;border-color:transparent;color:#fff}.button.is-dark:hover,.content kbd.button:hover,.button.is-dark.is-hovered,.content kbd.button.is-hovered{background-color:#2f2f2f;border-color:transparent;color:#fff}.button.is-dark:focus,.content kbd.button:focus,.button.is-dark.is-focused,.content kbd.button.is-focused{border-color:transparent;color:#fff}.button.is-dark:focus:not(:active),.content kbd.button:focus:not(:active),.button.is-dark.is-focused:not(:active),.content kbd.button.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.button.is-dark:active,.content kbd.button:active,.button.is-dark.is-active,.content kbd.button.is-active{background-color:#292929;border-color:transparent;color:#fff}.button.is-dark[disabled],.content kbd.button[disabled],fieldset[disabled] .button.is-dark,fieldset[disabled] .content kbd.button,.content fieldset[disabled] kbd.button{background-color:#363636;border-color:#363636;box-shadow:none}.button.is-dark.is-inverted,.content kbd.button.is-inverted{background-color:#fff;color:#363636}.button.is-dark.is-inverted:hover,.content kbd.button.is-inverted:hover,.button.is-dark.is-inverted.is-hovered,.content kbd.button.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-dark.is-inverted[disabled],.content kbd.button.is-inverted[disabled],fieldset[disabled] .button.is-dark.is-inverted,fieldset[disabled] .content kbd.button.is-inverted,.content fieldset[disabled] kbd.button.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#363636}.button.is-dark.is-loading::after,.content kbd.button.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-dark.is-outlined,.content kbd.button.is-outlined{background-color:transparent;border-color:#363636;color:#363636}.button.is-dark.is-outlined:hover,.content kbd.button.is-outlined:hover,.button.is-dark.is-outlined.is-hovered,.content kbd.button.is-outlined.is-hovered,.button.is-dark.is-outlined:focus,.content kbd.button.is-outlined:focus,.button.is-dark.is-outlined.is-focused,.content kbd.button.is-outlined.is-focused{background-color:#363636;border-color:#363636;color:#fff}.button.is-dark.is-outlined.is-loading::after,.content kbd.button.is-outlined.is-loading::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-outlined.is-loading:hover::after,.content kbd.button.is-outlined.is-loading:hover::after,.button.is-dark.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-outlined.is-loading:focus::after,.content kbd.button.is-outlined.is-loading:focus::after,.button.is-dark.is-outlined.is-loading.is-focused::after,.content kbd.button.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-dark.is-outlined[disabled],.content kbd.button.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-outlined,fieldset[disabled] .content kbd.button.is-outlined,.content fieldset[disabled] kbd.button.is-outlined{background-color:transparent;border-color:#363636;box-shadow:none;color:#363636}.button.is-dark.is-inverted.is-outlined,.content kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-dark.is-inverted.is-outlined:hover,.content kbd.button.is-inverted.is-outlined:hover,.button.is-dark.is-inverted.is-outlined.is-hovered,.content kbd.button.is-inverted.is-outlined.is-hovered,.button.is-dark.is-inverted.is-outlined:focus,.content kbd.button.is-inverted.is-outlined:focus,.button.is-dark.is-inverted.is-outlined.is-focused,.content kbd.button.is-inverted.is-outlined.is-focused{background-color:#fff;color:#363636}.button.is-dark.is-inverted.is-outlined.is-loading:hover::after,.content kbd.button.is-inverted.is-outlined.is-loading:hover::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-dark.is-inverted.is-outlined.is-loading:focus::after,.content kbd.button.is-inverted.is-outlined.is-loading:focus::after,.button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after,.content kbd.button.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #363636 #363636 !important}.button.is-dark.is-inverted.is-outlined[disabled],.content kbd.button.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-dark.is-inverted.is-outlined,fieldset[disabled] .content kbd.button.is-inverted.is-outlined,.content fieldset[disabled] kbd.button.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary,.docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:transparent;color:#fff}.button.is-primary:hover,.docstring>section>a.button.docs-sourcelink:hover,.button.is-primary.is-hovered,.docstring>section>a.button.is-hovered.docs-sourcelink{background-color:#43b1dc;border-color:transparent;color:#fff}.button.is-primary:focus,.docstring>section>a.button.docs-sourcelink:focus,.button.is-primary.is-focused,.docstring>section>a.button.is-focused.docs-sourcelink{border-color:transparent;color:#fff}.button.is-primary:focus:not(:active),.docstring>section>a.button.docs-sourcelink:focus:not(:active),.button.is-primary.is-focused:not(:active),.docstring>section>a.button.is-focused.docs-sourcelink:not(:active){box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.button.is-primary:active,.docstring>section>a.button.docs-sourcelink:active,.button.is-primary.is-active,.docstring>section>a.button.is-active.docs-sourcelink{background-color:#39acda;border-color:transparent;color:#fff}.button.is-primary[disabled],.docstring>section>a.button.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary,fieldset[disabled] .docstring>section>a.button.docs-sourcelink{background-color:#4eb5de;border-color:#4eb5de;box-shadow:none}.button.is-primary.is-inverted,.docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted:hover,.docstring>section>a.button.is-inverted.docs-sourcelink:hover,.button.is-primary.is-inverted.is-hovered,.docstring>section>a.button.is-inverted.is-hovered.docs-sourcelink{background-color:#f2f2f2}.button.is-primary.is-inverted[disabled],.docstring>section>a.button.is-inverted.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted,fieldset[disabled] .docstring>section>a.button.is-inverted.docs-sourcelink{background-color:#fff;border-color:transparent;box-shadow:none;color:#4eb5de}.button.is-primary.is-loading::after,.docstring>section>a.button.is-loading.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined,.docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;color:#4eb5de}.button.is-primary.is-outlined:hover,.docstring>section>a.button.is-outlined.docs-sourcelink:hover,.button.is-primary.is-outlined.is-hovered,.docstring>section>a.button.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-outlined:focus,.docstring>section>a.button.is-outlined.docs-sourcelink:focus,.button.is-primary.is-outlined.is-focused,.docstring>section>a.button.is-outlined.is-focused.docs-sourcelink{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.button.is-primary.is-outlined.is-loading::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #fff #fff !important}.button.is-primary.is-outlined[disabled],.docstring>section>a.button.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-outlined,fieldset[disabled] .docstring>section>a.button.is-outlined.docs-sourcelink{background-color:transparent;border-color:#4eb5de;box-shadow:none;color:#4eb5de}.button.is-primary.is-inverted.is-outlined,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;color:#fff}.button.is-primary.is-inverted.is-outlined:hover,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:hover,.button.is-primary.is-inverted.is-outlined.is-hovered,.docstring>section>a.button.is-inverted.is-outlined.is-hovered.docs-sourcelink,.button.is-primary.is-inverted.is-outlined:focus,.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink:focus,.button.is-primary.is-inverted.is-outlined.is-focused,.docstring>section>a.button.is-inverted.is-outlined.is-focused.docs-sourcelink{background-color:#fff;color:#4eb5de}.button.is-primary.is-inverted.is-outlined.is-loading:hover::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:hover::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-hovered.docs-sourcelink::after,.button.is-primary.is-inverted.is-outlined.is-loading:focus::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.docs-sourcelink:focus::after,.button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after,.docstring>section>a.button.is-inverted.is-outlined.is-loading.is-focused.docs-sourcelink::after{border-color:transparent transparent #4eb5de #4eb5de !important}.button.is-primary.is-inverted.is-outlined[disabled],.docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink[disabled],fieldset[disabled] .button.is-primary.is-inverted.is-outlined,fieldset[disabled] .docstring>section>a.button.is-inverted.is-outlined.docs-sourcelink{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-primary.is-light,.docstring>section>a.button.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.button.is-primary.is-light:hover,.docstring>section>a.button.is-light.docs-sourcelink:hover,.button.is-primary.is-light.is-hovered,.docstring>section>a.button.is-light.is-hovered.docs-sourcelink{background-color:#e3f3fa;border-color:transparent;color:#1a6d8e}.button.is-primary.is-light:active,.docstring>section>a.button.is-light.docs-sourcelink:active,.button.is-primary.is-light.is-active,.docstring>section>a.button.is-light.is-active.docs-sourcelink{background-color:#d8eff8;border-color:transparent;color:#1a6d8e}.button.is-link{background-color:#2e63b8;border-color:transparent;color:#fff}.button.is-link:hover,.button.is-link.is-hovered{background-color:#2b5eae;border-color:transparent;color:#fff}.button.is-link:focus,.button.is-link.is-focused{border-color:transparent;color:#fff}.button.is-link:focus:not(:active),.button.is-link.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.button.is-link:active,.button.is-link.is-active{background-color:#2958a4;border-color:transparent;color:#fff}.button.is-link[disabled],fieldset[disabled] .button.is-link{background-color:#2e63b8;border-color:#2e63b8;box-shadow:none}.button.is-link.is-inverted{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted:hover,.button.is-link.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-link.is-inverted[disabled],fieldset[disabled] .button.is-link.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#2e63b8}.button.is-link.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;color:#2e63b8}.button.is-link.is-outlined:hover,.button.is-link.is-outlined.is-hovered,.button.is-link.is-outlined:focus,.button.is-link.is-outlined.is-focused{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.button.is-link.is-outlined.is-loading::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-outlined.is-loading:hover::after,.button.is-link.is-outlined.is-loading.is-hovered::after,.button.is-link.is-outlined.is-loading:focus::after,.button.is-link.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-link.is-outlined[disabled],fieldset[disabled] .button.is-link.is-outlined{background-color:transparent;border-color:#2e63b8;box-shadow:none;color:#2e63b8}.button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-link.is-inverted.is-outlined:hover,.button.is-link.is-inverted.is-outlined.is-hovered,.button.is-link.is-inverted.is-outlined:focus,.button.is-link.is-inverted.is-outlined.is-focused{background-color:#fff;color:#2e63b8}.button.is-link.is-inverted.is-outlined.is-loading:hover::after,.button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-link.is-inverted.is-outlined.is-loading:focus::after,.button.is-link.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #2e63b8 #2e63b8 !important}.button.is-link.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-link.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-link.is-light{background-color:#eff3fb;color:#3169c4}.button.is-link.is-light:hover,.button.is-link.is-light.is-hovered{background-color:#e4ecf8;border-color:transparent;color:#3169c4}.button.is-link.is-light:active,.button.is-link.is-light.is-active{background-color:#dae5f6;border-color:transparent;color:#3169c4}.button.is-info{background-color:#209cee;border-color:transparent;color:#fff}.button.is-info:hover,.button.is-info.is-hovered{background-color:#1497ed;border-color:transparent;color:#fff}.button.is-info:focus,.button.is-info.is-focused{border-color:transparent;color:#fff}.button.is-info:focus:not(:active),.button.is-info.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.button.is-info:active,.button.is-info.is-active{background-color:#1190e3;border-color:transparent;color:#fff}.button.is-info[disabled],fieldset[disabled] .button.is-info{background-color:#209cee;border-color:#209cee;box-shadow:none}.button.is-info.is-inverted{background-color:#fff;color:#209cee}.button.is-info.is-inverted:hover,.button.is-info.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-info.is-inverted[disabled],fieldset[disabled] .button.is-info.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#209cee}.button.is-info.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined{background-color:transparent;border-color:#209cee;color:#209cee}.button.is-info.is-outlined:hover,.button.is-info.is-outlined.is-hovered,.button.is-info.is-outlined:focus,.button.is-info.is-outlined.is-focused{background-color:#209cee;border-color:#209cee;color:#fff}.button.is-info.is-outlined.is-loading::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-outlined.is-loading:hover::after,.button.is-info.is-outlined.is-loading.is-hovered::after,.button.is-info.is-outlined.is-loading:focus::after,.button.is-info.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-info.is-outlined[disabled],fieldset[disabled] .button.is-info.is-outlined{background-color:transparent;border-color:#209cee;box-shadow:none;color:#209cee}.button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-info.is-inverted.is-outlined:hover,.button.is-info.is-inverted.is-outlined.is-hovered,.button.is-info.is-inverted.is-outlined:focus,.button.is-info.is-inverted.is-outlined.is-focused{background-color:#fff;color:#209cee}.button.is-info.is-inverted.is-outlined.is-loading:hover::after,.button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-info.is-inverted.is-outlined.is-loading:focus::after,.button.is-info.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #209cee #209cee !important}.button.is-info.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-info.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-info.is-light{background-color:#ecf7fe;color:#0e72b4}.button.is-info.is-light:hover,.button.is-info.is-light.is-hovered{background-color:#e0f1fd;border-color:transparent;color:#0e72b4}.button.is-info.is-light:active,.button.is-info.is-light.is-active{background-color:#d4ecfc;border-color:transparent;color:#0e72b4}.button.is-success{background-color:#22c35b;border-color:transparent;color:#fff}.button.is-success:hover,.button.is-success.is-hovered{background-color:#20b856;border-color:transparent;color:#fff}.button.is-success:focus,.button.is-success.is-focused{border-color:transparent;color:#fff}.button.is-success:focus:not(:active),.button.is-success.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.button.is-success:active,.button.is-success.is-active{background-color:#1ead51;border-color:transparent;color:#fff}.button.is-success[disabled],fieldset[disabled] .button.is-success{background-color:#22c35b;border-color:#22c35b;box-shadow:none}.button.is-success.is-inverted{background-color:#fff;color:#22c35b}.button.is-success.is-inverted:hover,.button.is-success.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-success.is-inverted[disabled],fieldset[disabled] .button.is-success.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#22c35b}.button.is-success.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;color:#22c35b}.button.is-success.is-outlined:hover,.button.is-success.is-outlined.is-hovered,.button.is-success.is-outlined:focus,.button.is-success.is-outlined.is-focused{background-color:#22c35b;border-color:#22c35b;color:#fff}.button.is-success.is-outlined.is-loading::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-outlined.is-loading:hover::after,.button.is-success.is-outlined.is-loading.is-hovered::after,.button.is-success.is-outlined.is-loading:focus::after,.button.is-success.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-success.is-outlined[disabled],fieldset[disabled] .button.is-success.is-outlined{background-color:transparent;border-color:#22c35b;box-shadow:none;color:#22c35b}.button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-success.is-inverted.is-outlined:hover,.button.is-success.is-inverted.is-outlined.is-hovered,.button.is-success.is-inverted.is-outlined:focus,.button.is-success.is-inverted.is-outlined.is-focused{background-color:#fff;color:#22c35b}.button.is-success.is-inverted.is-outlined.is-loading:hover::after,.button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-success.is-inverted.is-outlined.is-loading:focus::after,.button.is-success.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #22c35b #22c35b !important}.button.is-success.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-success.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-success.is-light{background-color:#eefcf3;color:#198f43}.button.is-success.is-light:hover,.button.is-success.is-light.is-hovered{background-color:#e3faeb;border-color:transparent;color:#198f43}.button.is-success.is-light:active,.button.is-success.is-light.is-active{background-color:#d8f8e3;border-color:transparent;color:#198f43}.button.is-warning{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:hover,.button.is-warning.is-hovered{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus,.button.is-warning.is-focused{border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning:focus:not(:active),.button.is-warning.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.button.is-warning:active,.button.is-warning.is-active{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.button.is-warning[disabled],fieldset[disabled] .button.is-warning{background-color:#ffdd57;border-color:#ffdd57;box-shadow:none}.button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted:hover,.button.is-warning.is-inverted.is-hovered{background-color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted[disabled],fieldset[disabled] .button.is-warning.is-inverted{background-color:rgba(0,0,0,0.7);border-color:transparent;box-shadow:none;color:#ffdd57}.button.is-warning.is-loading::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;color:#ffdd57}.button.is-warning.is-outlined:hover,.button.is-warning.is-outlined.is-hovered,.button.is-warning.is-outlined:focus,.button.is-warning.is-outlined.is-focused{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.button.is-warning.is-outlined.is-loading::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-outlined.is-loading:hover::after,.button.is-warning.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-outlined.is-loading:focus::after,.button.is-warning.is-outlined.is-loading.is-focused::after{border-color:transparent transparent rgba(0,0,0,0.7) rgba(0,0,0,0.7) !important}.button.is-warning.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-outlined{background-color:transparent;border-color:#ffdd57;box-shadow:none;color:#ffdd57}.button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);color:rgba(0,0,0,0.7)}.button.is-warning.is-inverted.is-outlined:hover,.button.is-warning.is-inverted.is-outlined.is-hovered,.button.is-warning.is-inverted.is-outlined:focus,.button.is-warning.is-inverted.is-outlined.is-focused{background-color:rgba(0,0,0,0.7);color:#ffdd57}.button.is-warning.is-inverted.is-outlined.is-loading:hover::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-warning.is-inverted.is-outlined.is-loading:focus::after,.button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #ffdd57 #ffdd57 !important}.button.is-warning.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-warning.is-inverted.is-outlined{background-color:transparent;border-color:rgba(0,0,0,0.7);box-shadow:none;color:rgba(0,0,0,0.7)}.button.is-warning.is-light{background-color:#fffbeb;color:#947600}.button.is-warning.is-light:hover,.button.is-warning.is-light.is-hovered{background-color:#fff8de;border-color:transparent;color:#947600}.button.is-warning.is-light:active,.button.is-warning.is-light.is-active{background-color:#fff6d1;border-color:transparent;color:#947600}.button.is-danger{background-color:#da0b00;border-color:transparent;color:#fff}.button.is-danger:hover,.button.is-danger.is-hovered{background-color:#cd0a00;border-color:transparent;color:#fff}.button.is-danger:focus,.button.is-danger.is-focused{border-color:transparent;color:#fff}.button.is-danger:focus:not(:active),.button.is-danger.is-focused:not(:active){box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.button.is-danger:active,.button.is-danger.is-active{background-color:#c10a00;border-color:transparent;color:#fff}.button.is-danger[disabled],fieldset[disabled] .button.is-danger{background-color:#da0b00;border-color:#da0b00;box-shadow:none}.button.is-danger.is-inverted{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted:hover,.button.is-danger.is-inverted.is-hovered{background-color:#f2f2f2}.button.is-danger.is-inverted[disabled],fieldset[disabled] .button.is-danger.is-inverted{background-color:#fff;border-color:transparent;box-shadow:none;color:#da0b00}.button.is-danger.is-loading::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;color:#da0b00}.button.is-danger.is-outlined:hover,.button.is-danger.is-outlined.is-hovered,.button.is-danger.is-outlined:focus,.button.is-danger.is-outlined.is-focused{background-color:#da0b00;border-color:#da0b00;color:#fff}.button.is-danger.is-outlined.is-loading::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-outlined.is-loading:hover::after,.button.is-danger.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-outlined.is-loading:focus::after,.button.is-danger.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #fff #fff !important}.button.is-danger.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-outlined{background-color:transparent;border-color:#da0b00;box-shadow:none;color:#da0b00}.button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;color:#fff}.button.is-danger.is-inverted.is-outlined:hover,.button.is-danger.is-inverted.is-outlined.is-hovered,.button.is-danger.is-inverted.is-outlined:focus,.button.is-danger.is-inverted.is-outlined.is-focused{background-color:#fff;color:#da0b00}.button.is-danger.is-inverted.is-outlined.is-loading:hover::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after,.button.is-danger.is-inverted.is-outlined.is-loading:focus::after,.button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after{border-color:transparent transparent #da0b00 #da0b00 !important}.button.is-danger.is-inverted.is-outlined[disabled],fieldset[disabled] .button.is-danger.is-inverted.is-outlined{background-color:transparent;border-color:#fff;box-shadow:none;color:#fff}.button.is-danger.is-light{background-color:#ffeceb;color:#f50c00}.button.is-danger.is-light:hover,.button.is-danger.is-light.is-hovered{background-color:#ffe0de;border-color:transparent;color:#f50c00}.button.is-danger.is-light:active,.button.is-danger.is-light.is-active{background-color:#ffd3d1;border-color:transparent;color:#f50c00}.button.is-small,#documenter .docs-sidebar form.docs-search>input.button{font-size:.75rem}.button.is-small:not(.is-rounded),#documenter .docs-sidebar form.docs-search>input.button:not(.is-rounded){border-radius:2px}.button.is-normal{font-size:1rem}.button.is-medium{font-size:1.25rem}.button.is-large{font-size:1.5rem}.button[disabled],fieldset[disabled] .button{background-color:#fff;border-color:#dbdbdb;box-shadow:none;opacity:.5}.button.is-fullwidth{display:flex;width:100%}.button.is-loading{color:transparent !important;pointer-events:none}.button.is-loading::after{position:absolute;left:calc(50% - (1em * 0.5));top:calc(50% - (1em * 0.5));position:absolute !important}.button.is-static{background-color:#f5f5f5;border-color:#dbdbdb;color:#6b6b6b;box-shadow:none;pointer-events:none}.button.is-rounded,#documenter .docs-sidebar form.docs-search>input.button{border-radius:9999px;padding-left:calc(1em + 0.25em);padding-right:calc(1em + 0.25em)}.buttons{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.buttons .button{margin-bottom:0.5rem}.buttons .button:not(:last-child):not(.is-fullwidth){margin-right:.5rem}.buttons:last-child{margin-bottom:-0.5rem}.buttons:not(:last-child){margin-bottom:1rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large){font-size:.75rem}.buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded){border-radius:2px}.buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large){font-size:1.25rem}.buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium){font-size:1.5rem}.buttons.has-addons .button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.buttons.has-addons .button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0;margin-right:-1px}.buttons.has-addons .button:last-child{margin-right:0}.buttons.has-addons .button:hover,.buttons.has-addons .button.is-hovered{z-index:2}.buttons.has-addons .button:focus,.buttons.has-addons .button.is-focused,.buttons.has-addons .button:active,.buttons.has-addons .button.is-active,.buttons.has-addons .button.is-selected{z-index:3}.buttons.has-addons .button:focus:hover,.buttons.has-addons .button.is-focused:hover,.buttons.has-addons .button:active:hover,.buttons.has-addons .button.is-active:hover,.buttons.has-addons .button.is-selected:hover{z-index:4}.buttons.has-addons .button.is-expanded{flex-grow:1;flex-shrink:1}.buttons.is-centered{justify-content:center}.buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}.buttons.is-right{justify-content:flex-end}.buttons.is-right:not(.has-addons) .button:not(.is-fullwidth){margin-left:0.25rem;margin-right:0.25rem}@media screen and (max-width: 768px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.5625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.65625rem}.button.is-responsive.is-medium{font-size:.75rem}.button.is-responsive.is-large{font-size:1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.button.is-responsive.is-small,#documenter .docs-sidebar form.docs-search>input.is-responsive{font-size:.65625rem}.button.is-responsive,.button.is-responsive.is-normal{font-size:.75rem}.button.is-responsive.is-medium{font-size:1rem}.button.is-responsive.is-large{font-size:1.25rem}}.container{flex-grow:1;margin:0 auto;position:relative;width:auto}.container.is-fluid{max-width:none !important;padding-left:32px;padding-right:32px;width:100%}@media screen and (min-width: 1056px){.container{max-width:992px}}@media screen and (max-width: 1215px){.container.is-widescreen:not(.is-max-desktop){max-width:1152px}}@media screen and (max-width: 1407px){.container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}@media screen and (min-width: 1216px){.container:not(.is-max-desktop){max-width:1152px}}@media screen and (min-width: 1408px){.container:not(.is-max-desktop):not(.is-max-widescreen){max-width:1344px}}.content li+li{margin-top:0.25em}.content p:not(:last-child),.content dl:not(:last-child),.content ol:not(:last-child),.content ul:not(:last-child),.content blockquote:not(:last-child),.content pre:not(:last-child),.content table:not(:last-child){margin-bottom:1em}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{color:#222;font-weight:600;line-height:1.125}.content h1{font-size:2em;margin-bottom:0.5em}.content h1:not(:first-child){margin-top:1em}.content h2{font-size:1.75em;margin-bottom:0.5714em}.content h2:not(:first-child){margin-top:1.1428em}.content h3{font-size:1.5em;margin-bottom:0.6666em}.content h3:not(:first-child){margin-top:1.3333em}.content h4{font-size:1.25em;margin-bottom:0.8em}.content h5{font-size:1.125em;margin-bottom:0.8888em}.content h6{font-size:1em;margin-bottom:1em}.content blockquote{background-color:#f5f5f5;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]){list-style-type:decimal}.content ol.is-lower-alpha:not([type]){list-style-type:lower-alpha}.content ol.is-lower-roman:not([type]){list-style-type:lower-roman}.content ol.is-upper-alpha:not([type]){list-style-type:upper-alpha}.content ol.is-upper-roman:not([type]){list-style-type:upper-roman}.content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul{list-style-type:circle;margin-top:0.5em}.content ul ul ul{list-style-type:square}.content dd{margin-left:2em}.content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child){margin-bottom:2em}.content figure img{display:inline-block}.content figure figcaption{font-style:italic}.content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:0;white-space:pre;word-wrap:normal}.content sup,.content sub{font-size:75%}.content table{width:100%}.content table td,.content table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.content table th{color:#222}.content table th:not([align]){text-align:inherit}.content table thead td,.content table thead th{border-width:0 0 2px;color:#222}.content table tfoot td,.content table tfoot th{border-width:2px 0 0;color:#222}.content table tbody tr:last-child td,.content table tbody tr:last-child th{border-bottom-width:0}.content .tabs li+li{margin-top:0}.content.is-small,#documenter .docs-sidebar form.docs-search>input.content{font-size:.75rem}.content.is-normal{font-size:1rem}.content.is-medium{font-size:1.25rem}.content.is-large{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small,#documenter .docs-sidebar form.docs-search>input.icon{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.icon-text{align-items:flex-start;color:inherit;display:inline-flex;flex-wrap:wrap;line-height:1.5rem;vertical-align:top}.icon-text .icon{flex-grow:0;flex-shrink:0}.icon-text .icon:not(:last-child){margin-right:.25em}.icon-text .icon:not(:first-child){margin-left:.25em}div.icon-text{display:flex}.image,#documenter .docs-sidebar .docs-logo>img{display:block;position:relative}.image img,#documenter .docs-sidebar .docs-logo>img img{display:block;height:auto;width:100%}.image img.is-rounded,#documenter .docs-sidebar .docs-logo>img img.is-rounded{border-radius:9999px}.image.is-fullwidth,#documenter .docs-sidebar .docs-logo>img.is-fullwidth{width:100%}.image.is-square img,#documenter .docs-sidebar .docs-logo>img.is-square img,.image.is-square .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-square .has-ratio,.image.is-1by1 img,#documenter .docs-sidebar .docs-logo>img.is-1by1 img,.image.is-1by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by1 .has-ratio,.image.is-5by4 img,#documenter .docs-sidebar .docs-logo>img.is-5by4 img,.image.is-5by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by4 .has-ratio,.image.is-4by3 img,#documenter .docs-sidebar .docs-logo>img.is-4by3 img,.image.is-4by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by3 .has-ratio,.image.is-3by2 img,#documenter .docs-sidebar .docs-logo>img.is-3by2 img,.image.is-3by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by2 .has-ratio,.image.is-5by3 img,#documenter .docs-sidebar .docs-logo>img.is-5by3 img,.image.is-5by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-5by3 .has-ratio,.image.is-16by9 img,#documenter .docs-sidebar .docs-logo>img.is-16by9 img,.image.is-16by9 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-16by9 .has-ratio,.image.is-2by1 img,#documenter .docs-sidebar .docs-logo>img.is-2by1 img,.image.is-2by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by1 .has-ratio,.image.is-3by1 img,#documenter .docs-sidebar .docs-logo>img.is-3by1 img,.image.is-3by1 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by1 .has-ratio,.image.is-4by5 img,#documenter .docs-sidebar .docs-logo>img.is-4by5 img,.image.is-4by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-4by5 .has-ratio,.image.is-3by4 img,#documenter .docs-sidebar .docs-logo>img.is-3by4 img,.image.is-3by4 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by4 .has-ratio,.image.is-2by3 img,#documenter .docs-sidebar .docs-logo>img.is-2by3 img,.image.is-2by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-2by3 .has-ratio,.image.is-3by5 img,#documenter .docs-sidebar .docs-logo>img.is-3by5 img,.image.is-3by5 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-3by5 .has-ratio,.image.is-9by16 img,#documenter .docs-sidebar .docs-logo>img.is-9by16 img,.image.is-9by16 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-9by16 .has-ratio,.image.is-1by2 img,#documenter .docs-sidebar .docs-logo>img.is-1by2 img,.image.is-1by2 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by2 .has-ratio,.image.is-1by3 img,#documenter .docs-sidebar .docs-logo>img.is-1by3 img,.image.is-1by3 .has-ratio,#documenter .docs-sidebar .docs-logo>img.is-1by3 .has-ratio{height:100%;width:100%}.image.is-square,#documenter .docs-sidebar .docs-logo>img.is-square,.image.is-1by1,#documenter .docs-sidebar .docs-logo>img.is-1by1{padding-top:100%}.image.is-5by4,#documenter .docs-sidebar .docs-logo>img.is-5by4{padding-top:80%}.image.is-4by3,#documenter .docs-sidebar .docs-logo>img.is-4by3{padding-top:75%}.image.is-3by2,#documenter .docs-sidebar .docs-logo>img.is-3by2{padding-top:66.6666%}.image.is-5by3,#documenter .docs-sidebar .docs-logo>img.is-5by3{padding-top:60%}.image.is-16by9,#documenter .docs-sidebar .docs-logo>img.is-16by9{padding-top:56.25%}.image.is-2by1,#documenter .docs-sidebar .docs-logo>img.is-2by1{padding-top:50%}.image.is-3by1,#documenter .docs-sidebar .docs-logo>img.is-3by1{padding-top:33.3333%}.image.is-4by5,#documenter .docs-sidebar .docs-logo>img.is-4by5{padding-top:125%}.image.is-3by4,#documenter .docs-sidebar .docs-logo>img.is-3by4{padding-top:133.3333%}.image.is-2by3,#documenter .docs-sidebar .docs-logo>img.is-2by3{padding-top:150%}.image.is-3by5,#documenter .docs-sidebar .docs-logo>img.is-3by5{padding-top:166.6666%}.image.is-9by16,#documenter .docs-sidebar .docs-logo>img.is-9by16{padding-top:177.7777%}.image.is-1by2,#documenter .docs-sidebar .docs-logo>img.is-1by2{padding-top:200%}.image.is-1by3,#documenter .docs-sidebar .docs-logo>img.is-1by3{padding-top:300%}.image.is-16x16,#documenter .docs-sidebar .docs-logo>img.is-16x16{height:16px;width:16px}.image.is-24x24,#documenter .docs-sidebar .docs-logo>img.is-24x24{height:24px;width:24px}.image.is-32x32,#documenter .docs-sidebar .docs-logo>img.is-32x32{height:32px;width:32px}.image.is-48x48,#documenter .docs-sidebar .docs-logo>img.is-48x48{height:48px;width:48px}.image.is-64x64,#documenter .docs-sidebar .docs-logo>img.is-64x64{height:64px;width:64px}.image.is-96x96,#documenter .docs-sidebar .docs-logo>img.is-96x96{height:96px;width:96px}.image.is-128x128,#documenter .docs-sidebar .docs-logo>img.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;position:relative;padding:1.25rem 2.5rem 1.25rem 1.5rem}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:transparent}.notification>.delete{right:.5rem;position:absolute;top:0.5rem}.notification .title,.notification .subtitle,.notification .content{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.notification.is-dark,.content kbd.notification{background-color:#363636;color:#fff}.notification.is-primary,.docstring>section>a.notification.docs-sourcelink{background-color:#4eb5de;color:#fff}.notification.is-primary.is-light,.docstring>section>a.notification.is-light.docs-sourcelink{background-color:#eef8fc;color:#1a6d8e}.notification.is-link{background-color:#2e63b8;color:#fff}.notification.is-link.is-light{background-color:#eff3fb;color:#3169c4}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-info.is-light{background-color:#ecf7fe;color:#0e72b4}.notification.is-success{background-color:#22c35b;color:#fff}.notification.is-success.is-light{background-color:#eefcf3;color:#198f43}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.notification.is-warning.is-light{background-color:#fffbeb;color:#947600}.notification.is-danger{background-color:#da0b00;color:#fff}.notification.is-danger.is-light{background-color:#ffeceb;color:#f50c00}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:9999px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#ededed}.progress::-webkit-progress-value{background-color:#222}.progress::-moz-progress-bar{background-color:#222}.progress::-ms-fill{background-color:#222;border:none}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #ededed 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #ededed 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right, #f5f5f5 30%, #ededed 30%)}.progress.is-dark::-webkit-progress-value,.content kbd.progress::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar,.content kbd.progress::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill,.content kbd.progress::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate,.content kbd.progress:indeterminate{background-image:linear-gradient(to right, #363636 30%, #ededed 30%)}.progress.is-primary::-webkit-progress-value,.docstring>section>a.progress.docs-sourcelink::-webkit-progress-value{background-color:#4eb5de}.progress.is-primary::-moz-progress-bar,.docstring>section>a.progress.docs-sourcelink::-moz-progress-bar{background-color:#4eb5de}.progress.is-primary::-ms-fill,.docstring>section>a.progress.docs-sourcelink::-ms-fill{background-color:#4eb5de}.progress.is-primary:indeterminate,.docstring>section>a.progress.docs-sourcelink:indeterminate{background-image:linear-gradient(to right, #4eb5de 30%, #ededed 30%)}.progress.is-link::-webkit-progress-value{background-color:#2e63b8}.progress.is-link::-moz-progress-bar{background-color:#2e63b8}.progress.is-link::-ms-fill{background-color:#2e63b8}.progress.is-link:indeterminate{background-image:linear-gradient(to right, #2e63b8 30%, #ededed 30%)}.progress.is-info::-webkit-progress-value{background-color:#209cee}.progress.is-info::-moz-progress-bar{background-color:#209cee}.progress.is-info::-ms-fill{background-color:#209cee}.progress.is-info:indeterminate{background-image:linear-gradient(to right, #209cee 30%, #ededed 30%)}.progress.is-success::-webkit-progress-value{background-color:#22c35b}.progress.is-success::-moz-progress-bar{background-color:#22c35b}.progress.is-success::-ms-fill{background-color:#22c35b}.progress.is-success:indeterminate{background-image:linear-gradient(to right, #22c35b 30%, #ededed 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffdd57}.progress.is-warning::-moz-progress-bar{background-color:#ffdd57}.progress.is-warning::-ms-fill{background-color:#ffdd57}.progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ffdd57 30%, #ededed 30%)}.progress.is-danger::-webkit-progress-value{background-color:#da0b00}.progress.is-danger::-moz-progress-bar{background-color:#da0b00}.progress.is-danger::-ms-fill{background-color:#da0b00}.progress.is-danger:indeterminate{background-image:linear-gradient(to right, #da0b00 30%, #ededed 30%)}.progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#ededed;background-image:linear-gradient(to right, #222 30%, #ededed 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress:indeterminate::-ms-fill{animation-name:none}.progress.is-small,#documenter .docs-sidebar form.docs-search>input.progress{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#222}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:rgba(0,0,0,0.7)}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#fff}.table td.is-primary,.table th.is-primary{background-color:#4eb5de;border-color:#4eb5de;color:#fff}.table td.is-link,.table th.is-link{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.table td.is-info,.table th.is-info{background-color:#209cee;border-color:#209cee;color:#fff}.table td.is-success,.table th.is-success{background-color:#22c35b;border-color:#22c35b;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.table td.is-danger,.table th.is-danger{background-color:#da0b00;border-color:#da0b00;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#4eb5de;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table td.is-vcentered,.table th.is-vcentered{vertical-align:middle}.table th{color:#222}.table th:not([align]){text-align:left}.table tr.is-selected{background-color:#4eb5de;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:rgba(0,0,0,0)}.table thead td,.table thead th{border-width:0 0 2px;color:#222}.table tfoot{background-color:rgba(0,0,0,0)}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#222}.table tbody{background-color:rgba(0,0,0,0)}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:0.25em 0.5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag,.tags .content kbd,.content .tags kbd,.tags .docstring>section>a.docs-sourcelink{margin-bottom:0.5rem}.tags .tag:not(:last-child),.tags .content kbd:not(:last-child),.content .tags kbd:not(:last-child),.tags .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:.5rem}.tags:last-child{margin-bottom:-0.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large),.tags.are-medium .content kbd:not(.is-normal):not(.is-large),.content .tags.are-medium kbd:not(.is-normal):not(.is-large),.tags.are-medium .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium),.tags.are-large .content kbd:not(.is-normal):not(.is-medium),.content .tags.are-large kbd:not(.is-normal):not(.is-medium),.tags.are-large .docstring>section>a.docs-sourcelink:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.is-centered{justify-content:center}.tags.is-centered .tag,.tags.is-centered .content kbd,.content .tags.is-centered kbd,.tags.is-centered .docstring>section>a.docs-sourcelink{margin-right:0.25rem;margin-left:0.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child),.tags.is-right .content kbd:not(:first-child),.content .tags.is-right kbd:not(:first-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0.5rem}.tags.is-right .tag:not(:last-child),.tags.is-right .content kbd:not(:last-child),.content .tags.is-right kbd:not(:last-child),.tags.is-right .docstring>section>a.docs-sourcelink:not(:last-child){margin-right:0}.tags.has-addons .tag,.tags.has-addons .content kbd,.content .tags.has-addons kbd,.tags.has-addons .docstring>section>a.docs-sourcelink{margin-right:0}.tags.has-addons .tag:not(:first-child),.tags.has-addons .content kbd:not(:first-child),.content .tags.has-addons kbd:not(:first-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.tags.has-addons .tag:not(:last-child),.tags.has-addons .content kbd:not(:last-child),.content .tags.has-addons kbd:not(:last-child),.tags.has-addons .docstring>section>a.docs-sourcelink:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.tag:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#222;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.tag:not(body) .delete,.content kbd:not(body) .delete,.docstring>section>a.docs-sourcelink:not(body) .delete{margin-left:.25rem;margin-right:-.375rem}.tag.is-white:not(body),.content kbd.is-white:not(body),.docstring>section>a.docs-sourcelink.is-white:not(body){background-color:#fff;color:#0a0a0a}.tag.is-black:not(body),.content kbd.is-black:not(body),.docstring>section>a.docs-sourcelink.is-black:not(body){background-color:#0a0a0a;color:#fff}.tag.is-light:not(body),.content kbd.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.tag.is-dark:not(body),.content kbd:not(body),.docstring>section>a.docs-sourcelink.is-dark:not(body),.content .docstring>section>kbd:not(body){background-color:#363636;color:#fff}.tag.is-primary:not(body),.content kbd.is-primary:not(body),.docstring>section>a.docs-sourcelink:not(body){background-color:#4eb5de;color:#fff}.tag.is-primary.is-light:not(body),.content kbd.is-primary.is-light:not(body),.docstring>section>a.docs-sourcelink.is-light:not(body){background-color:#eef8fc;color:#1a6d8e}.tag.is-link:not(body),.content kbd.is-link:not(body),.docstring>section>a.docs-sourcelink.is-link:not(body){background-color:#2e63b8;color:#fff}.tag.is-link.is-light:not(body),.content kbd.is-link.is-light:not(body),.docstring>section>a.docs-sourcelink.is-link.is-light:not(body){background-color:#eff3fb;color:#3169c4}.tag.is-info:not(body),.content kbd.is-info:not(body),.docstring>section>a.docs-sourcelink.is-info:not(body){background-color:#209cee;color:#fff}.tag.is-info.is-light:not(body),.content kbd.is-info.is-light:not(body),.docstring>section>a.docs-sourcelink.is-info.is-light:not(body){background-color:#ecf7fe;color:#0e72b4}.tag.is-success:not(body),.content kbd.is-success:not(body),.docstring>section>a.docs-sourcelink.is-success:not(body){background-color:#22c35b;color:#fff}.tag.is-success.is-light:not(body),.content kbd.is-success.is-light:not(body),.docstring>section>a.docs-sourcelink.is-success.is-light:not(body){background-color:#eefcf3;color:#198f43}.tag.is-warning:not(body),.content kbd.is-warning:not(body),.docstring>section>a.docs-sourcelink.is-warning:not(body){background-color:#ffdd57;color:rgba(0,0,0,0.7)}.tag.is-warning.is-light:not(body),.content kbd.is-warning.is-light:not(body),.docstring>section>a.docs-sourcelink.is-warning.is-light:not(body){background-color:#fffbeb;color:#947600}.tag.is-danger:not(body),.content kbd.is-danger:not(body),.docstring>section>a.docs-sourcelink.is-danger:not(body){background-color:#da0b00;color:#fff}.tag.is-danger.is-light:not(body),.content kbd.is-danger.is-light:not(body),.docstring>section>a.docs-sourcelink.is-danger.is-light:not(body){background-color:#ffeceb;color:#f50c00}.tag.is-normal:not(body),.content kbd.is-normal:not(body),.docstring>section>a.docs-sourcelink.is-normal:not(body){font-size:.75rem}.tag.is-medium:not(body),.content kbd.is-medium:not(body),.docstring>section>a.docs-sourcelink.is-medium:not(body){font-size:1rem}.tag.is-large:not(body),.content kbd.is-large:not(body),.docstring>section>a.docs-sourcelink.is-large:not(body){font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child),.content kbd:not(body) .icon:first-child:not(:last-child),.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:not(:last-child){margin-left:-.375em;margin-right:.1875em}.tag:not(body) .icon:last-child:not(:first-child),.content kbd:not(body) .icon:last-child:not(:first-child),.docstring>section>a.docs-sourcelink:not(body) .icon:last-child:not(:first-child){margin-left:.1875em;margin-right:-.375em}.tag:not(body) .icon:first-child:last-child,.content kbd:not(body) .icon:first-child:last-child,.docstring>section>a.docs-sourcelink:not(body) .icon:first-child:last-child{margin-left:-.375em;margin-right:-.375em}.tag.is-delete:not(body),.content kbd.is-delete:not(body),.docstring>section>a.docs-sourcelink.is-delete:not(body){margin-left:1px;padding:0;position:relative;width:2em}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before,.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag.is-delete:not(body)::before,.content kbd.is-delete:not(body)::before,.docstring>section>a.docs-sourcelink.is-delete:not(body)::before{height:1px;width:50%}.tag.is-delete:not(body)::after,.content kbd.is-delete:not(body)::after,.docstring>section>a.docs-sourcelink.is-delete:not(body)::after{height:50%;width:1px}.tag.is-delete:not(body):hover,.content kbd.is-delete:not(body):hover,.docstring>section>a.docs-sourcelink.is-delete:not(body):hover,.tag.is-delete:not(body):focus,.content kbd.is-delete:not(body):focus,.docstring>section>a.docs-sourcelink.is-delete:not(body):focus{background-color:#e8e8e8}.tag.is-delete:not(body):active,.content kbd.is-delete:not(body):active,.docstring>section>a.docs-sourcelink.is-delete:not(body):active{background-color:#dbdbdb}.tag.is-rounded:not(body),#documenter .docs-sidebar form.docs-search>input:not(body),.content kbd.is-rounded:not(body),#documenter .docs-sidebar .content form.docs-search>input:not(body),.docstring>section>a.docs-sourcelink.is-rounded:not(body){border-radius:9999px}a.tag:hover,.docstring>section>a.docs-sourcelink:hover{text-decoration:underline}.title,.subtitle{word-break:break-word}.title em,.title span,.subtitle em,.subtitle span{font-weight:inherit}.title sub,.subtitle sub{font-size:.75em}.title sup,.subtitle sup{font-size:.75em}.title .tag,.title .content kbd,.content .title kbd,.title .docstring>section>a.docs-sourcelink,.subtitle .tag,.subtitle .content kbd,.content .subtitle kbd,.subtitle .docstring>section>a.docs-sourcelink{vertical-align:middle}.title{color:#222;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#222;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#222;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.number{align-items:center;background-color:#f5f5f5;border-radius:9999px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}.select select,.textarea,.input,#documenter .docs-sidebar form.docs-search>input{background-color:#fff;border-color:#dbdbdb;border-radius:4px;color:#222}.select select::-moz-placeholder,.textarea::-moz-placeholder,.input::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input::-moz-placeholder{color:#707070}.select select::-webkit-input-placeholder,.textarea::-webkit-input-placeholder,.input::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder{color:#707070}.select select:-moz-placeholder,.textarea:-moz-placeholder,.input:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input:-moz-placeholder{color:#707070}.select select:-ms-input-placeholder,.textarea:-ms-input-placeholder,.input:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder{color:#707070}.select select:hover,.textarea:hover,.input:hover,#documenter .docs-sidebar form.docs-search>input:hover,.select select.is-hovered,.is-hovered.textarea,.is-hovered.input,#documenter .docs-sidebar form.docs-search>input.is-hovered{border-color:#b5b5b5}.select select:focus,.textarea:focus,.input:focus,#documenter .docs-sidebar form.docs-search>input:focus,.select select.is-focused,.is-focused.textarea,.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.select select:active,.textarea:active,.input:active,#documenter .docs-sidebar form.docs-search>input:active,.select select.is-active,.is-active.textarea,.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{border-color:#2e63b8;box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select select[disabled],.textarea[disabled],.input[disabled],#documenter .docs-sidebar form.docs-search>input[disabled],fieldset[disabled] .select select,.select fieldset[disabled] select,fieldset[disabled] .textarea,fieldset[disabled] .input,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input{background-color:#f5f5f5;border-color:#f5f5f5;box-shadow:none;color:#6b6b6b}.select select[disabled]::-moz-placeholder,.textarea[disabled]::-moz-placeholder,.input[disabled]::-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-moz-placeholder,fieldset[disabled] .select select::-moz-placeholder,.select fieldset[disabled] select::-moz-placeholder,fieldset[disabled] .textarea::-moz-placeholder,fieldset[disabled] .input::-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]::-webkit-input-placeholder,.textarea[disabled]::-webkit-input-placeholder,.input[disabled]::-webkit-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]::-webkit-input-placeholder,fieldset[disabled] .select select::-webkit-input-placeholder,.select fieldset[disabled] select::-webkit-input-placeholder,fieldset[disabled] .textarea::-webkit-input-placeholder,fieldset[disabled] .input::-webkit-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input::-webkit-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input::-webkit-input-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-moz-placeholder,.textarea[disabled]:-moz-placeholder,.input[disabled]:-moz-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-moz-placeholder,fieldset[disabled] .select select:-moz-placeholder,.select fieldset[disabled] select:-moz-placeholder,fieldset[disabled] .textarea:-moz-placeholder,fieldset[disabled] .input:-moz-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-moz-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-moz-placeholder{color:rgba(107,107,107,0.3)}.select select[disabled]:-ms-input-placeholder,.textarea[disabled]:-ms-input-placeholder,.input[disabled]:-ms-input-placeholder,#documenter .docs-sidebar form.docs-search>input[disabled]:-ms-input-placeholder,fieldset[disabled] .select select:-ms-input-placeholder,.select fieldset[disabled] select:-ms-input-placeholder,fieldset[disabled] .textarea:-ms-input-placeholder,fieldset[disabled] .input:-ms-input-placeholder,fieldset[disabled] #documenter .docs-sidebar form.docs-search>input:-ms-input-placeholder,#documenter .docs-sidebar fieldset[disabled] form.docs-search>input:-ms-input-placeholder{color:rgba(107,107,107,0.3)}.textarea,.input,#documenter .docs-sidebar form.docs-search>input{box-shadow:inset 0 0.0625em 0.125em rgba(10,10,10,0.05);max-width:100%;width:100%}.textarea[readonly],.input[readonly],#documenter .docs-sidebar form.docs-search>input[readonly]{box-shadow:none}.is-white.textarea,.is-white.input,#documenter .docs-sidebar form.docs-search>input.is-white{border-color:#fff}.is-white.textarea:focus,.is-white.input:focus,#documenter .docs-sidebar form.docs-search>input.is-white:focus,.is-white.is-focused.textarea,.is-white.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-white.textarea:active,.is-white.input:active,#documenter .docs-sidebar form.docs-search>input.is-white:active,.is-white.is-active.textarea,.is-white.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.is-black.textarea,.is-black.input,#documenter .docs-sidebar form.docs-search>input.is-black{border-color:#0a0a0a}.is-black.textarea:focus,.is-black.input:focus,#documenter .docs-sidebar form.docs-search>input.is-black:focus,.is-black.is-focused.textarea,.is-black.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-black.textarea:active,.is-black.input:active,#documenter .docs-sidebar form.docs-search>input.is-black:active,.is-black.is-active.textarea,.is-black.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.is-light.textarea,.is-light.input,#documenter .docs-sidebar form.docs-search>input.is-light{border-color:#f5f5f5}.is-light.textarea:focus,.is-light.input:focus,#documenter .docs-sidebar form.docs-search>input.is-light:focus,.is-light.is-focused.textarea,.is-light.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-light.textarea:active,.is-light.input:active,#documenter .docs-sidebar form.docs-search>input.is-light:active,.is-light.is-active.textarea,.is-light.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.is-dark.textarea,.content kbd.textarea,.is-dark.input,#documenter .docs-sidebar form.docs-search>input.is-dark,.content kbd.input{border-color:#363636}.is-dark.textarea:focus,.content kbd.textarea:focus,.is-dark.input:focus,#documenter .docs-sidebar form.docs-search>input.is-dark:focus,.content kbd.input:focus,.is-dark.is-focused.textarea,.content kbd.is-focused.textarea,.is-dark.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.content kbd.is-focused.input,#documenter .docs-sidebar .content form.docs-search>input.is-focused,.is-dark.textarea:active,.content kbd.textarea:active,.is-dark.input:active,#documenter .docs-sidebar form.docs-search>input.is-dark:active,.content kbd.input:active,.is-dark.is-active.textarea,.content kbd.is-active.textarea,.is-dark.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.content kbd.is-active.input,#documenter .docs-sidebar .content form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.is-primary.textarea,.docstring>section>a.textarea.docs-sourcelink,.is-primary.input,#documenter .docs-sidebar form.docs-search>input.is-primary,.docstring>section>a.input.docs-sourcelink{border-color:#4eb5de}.is-primary.textarea:focus,.docstring>section>a.textarea.docs-sourcelink:focus,.is-primary.input:focus,#documenter .docs-sidebar form.docs-search>input.is-primary:focus,.docstring>section>a.input.docs-sourcelink:focus,.is-primary.is-focused.textarea,.docstring>section>a.is-focused.textarea.docs-sourcelink,.is-primary.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.docstring>section>a.is-focused.input.docs-sourcelink,.is-primary.textarea:active,.docstring>section>a.textarea.docs-sourcelink:active,.is-primary.input:active,#documenter .docs-sidebar form.docs-search>input.is-primary:active,.docstring>section>a.input.docs-sourcelink:active,.is-primary.is-active.textarea,.docstring>section>a.is-active.textarea.docs-sourcelink,.is-primary.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active,.docstring>section>a.is-active.input.docs-sourcelink{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.is-link.textarea,.is-link.input,#documenter .docs-sidebar form.docs-search>input.is-link{border-color:#2e63b8}.is-link.textarea:focus,.is-link.input:focus,#documenter .docs-sidebar form.docs-search>input.is-link:focus,.is-link.is-focused.textarea,.is-link.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-link.textarea:active,.is-link.input:active,#documenter .docs-sidebar form.docs-search>input.is-link:active,.is-link.is-active.textarea,.is-link.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.is-info.textarea,.is-info.input,#documenter .docs-sidebar form.docs-search>input.is-info{border-color:#209cee}.is-info.textarea:focus,.is-info.input:focus,#documenter .docs-sidebar form.docs-search>input.is-info:focus,.is-info.is-focused.textarea,.is-info.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-info.textarea:active,.is-info.input:active,#documenter .docs-sidebar form.docs-search>input.is-info:active,.is-info.is-active.textarea,.is-info.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.is-success.textarea,.is-success.input,#documenter .docs-sidebar form.docs-search>input.is-success{border-color:#22c35b}.is-success.textarea:focus,.is-success.input:focus,#documenter .docs-sidebar form.docs-search>input.is-success:focus,.is-success.is-focused.textarea,.is-success.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-success.textarea:active,.is-success.input:active,#documenter .docs-sidebar form.docs-search>input.is-success:active,.is-success.is-active.textarea,.is-success.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.is-warning.textarea,.is-warning.input,#documenter .docs-sidebar form.docs-search>input.is-warning{border-color:#ffdd57}.is-warning.textarea:focus,.is-warning.input:focus,#documenter .docs-sidebar form.docs-search>input.is-warning:focus,.is-warning.is-focused.textarea,.is-warning.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-warning.textarea:active,.is-warning.input:active,#documenter .docs-sidebar form.docs-search>input.is-warning:active,.is-warning.is-active.textarea,.is-warning.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.is-danger.textarea,.is-danger.input,#documenter .docs-sidebar form.docs-search>input.is-danger{border-color:#da0b00}.is-danger.textarea:focus,.is-danger.input:focus,#documenter .docs-sidebar form.docs-search>input.is-danger:focus,.is-danger.is-focused.textarea,.is-danger.is-focused.input,#documenter .docs-sidebar form.docs-search>input.is-focused,.is-danger.textarea:active,.is-danger.input:active,#documenter .docs-sidebar form.docs-search>input.is-danger:active,.is-danger.is-active.textarea,.is-danger.is-active.input,#documenter .docs-sidebar form.docs-search>input.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.is-small.textarea,.is-small.input,#documenter .docs-sidebar form.docs-search>input{border-radius:2px;font-size:.75rem}.is-medium.textarea,.is-medium.input,#documenter .docs-sidebar form.docs-search>input.is-medium{font-size:1.25rem}.is-large.textarea,.is-large.input,#documenter .docs-sidebar form.docs-search>input.is-large{font-size:1.5rem}.is-fullwidth.textarea,.is-fullwidth.input,#documenter .docs-sidebar form.docs-search>input.is-fullwidth{display:block;width:100%}.is-inline.textarea,.is-inline.input,#documenter .docs-sidebar form.docs-search>input.is-inline{display:inline;width:auto}.input.is-rounded,#documenter .docs-sidebar form.docs-search>input{border-radius:9999px;padding-left:calc(calc(0.75em - 1px) + 0.375em);padding-right:calc(calc(0.75em - 1px) + 0.375em)}.input.is-static,#documenter .docs-sidebar form.docs-search>input.is-static{background-color:transparent;border-color:transparent;box-shadow:none;padding-left:0;padding-right:0}.textarea{display:block;max-width:100%;min-width:100%;padding:calc(0.75em - 1px);resize:vertical}.textarea:not([rows]){max-height:40em;min-height:8em}.textarea[rows]{height:initial}.textarea.has-fixed-size{resize:none}.radio,.checkbox{cursor:pointer;display:inline-block;line-height:1.25;position:relative}.radio input,.checkbox input{cursor:pointer}.radio:hover,.checkbox:hover{color:#222}.radio[disabled],.checkbox[disabled],fieldset[disabled] .radio,fieldset[disabled] .checkbox,.radio input[disabled],.checkbox input[disabled]{color:#6b6b6b;cursor:not-allowed}.radio+.radio{margin-left:.5em}.select{display:inline-block;max-width:100%;position:relative;vertical-align:top}.select:not(.is-multiple){height:2.5em}.select:not(.is-multiple):not(.is-loading)::after{border-color:#2e63b8;right:1.125em;z-index:4}.select.is-rounded select,#documenter .docs-sidebar form.docs-search>input.select select{border-radius:9999px;padding-left:1em}.select select{cursor:pointer;display:block;font-size:1em;max-width:100%;outline:none}.select select::-ms-expand{display:none}.select select[disabled]:hover,fieldset[disabled] .select select:hover{border-color:#f5f5f5}.select select:not([multiple]){padding-right:2.5em}.select select[multiple]{height:auto;padding:0}.select select[multiple] option{padding:0.5em 1em}.select:not(.is-multiple):not(.is-loading):hover::after{border-color:#222}.select.is-white:not(:hover)::after{border-color:#fff}.select.is-white select{border-color:#fff}.select.is-white select:hover,.select.is-white select.is-hovered{border-color:#f2f2f2}.select.is-white select:focus,.select.is-white select.is-focused,.select.is-white select:active,.select.is-white select.is-active{box-shadow:0 0 0 0.125em rgba(255,255,255,0.25)}.select.is-black:not(:hover)::after{border-color:#0a0a0a}.select.is-black select{border-color:#0a0a0a}.select.is-black select:hover,.select.is-black select.is-hovered{border-color:#000}.select.is-black select:focus,.select.is-black select.is-focused,.select.is-black select:active,.select.is-black select.is-active{box-shadow:0 0 0 0.125em rgba(10,10,10,0.25)}.select.is-light:not(:hover)::after{border-color:#f5f5f5}.select.is-light select{border-color:#f5f5f5}.select.is-light select:hover,.select.is-light select.is-hovered{border-color:#e8e8e8}.select.is-light select:focus,.select.is-light select.is-focused,.select.is-light select:active,.select.is-light select.is-active{box-shadow:0 0 0 0.125em rgba(245,245,245,0.25)}.select.is-dark:not(:hover)::after,.content kbd.select:not(:hover)::after{border-color:#363636}.select.is-dark select,.content kbd.select select{border-color:#363636}.select.is-dark select:hover,.content kbd.select select:hover,.select.is-dark select.is-hovered,.content kbd.select select.is-hovered{border-color:#292929}.select.is-dark select:focus,.content kbd.select select:focus,.select.is-dark select.is-focused,.content kbd.select select.is-focused,.select.is-dark select:active,.content kbd.select select:active,.select.is-dark select.is-active,.content kbd.select select.is-active{box-shadow:0 0 0 0.125em rgba(54,54,54,0.25)}.select.is-primary:not(:hover)::after,.docstring>section>a.select.docs-sourcelink:not(:hover)::after{border-color:#4eb5de}.select.is-primary select,.docstring>section>a.select.docs-sourcelink select{border-color:#4eb5de}.select.is-primary select:hover,.docstring>section>a.select.docs-sourcelink select:hover,.select.is-primary select.is-hovered,.docstring>section>a.select.docs-sourcelink select.is-hovered{border-color:#39acda}.select.is-primary select:focus,.docstring>section>a.select.docs-sourcelink select:focus,.select.is-primary select.is-focused,.docstring>section>a.select.docs-sourcelink select.is-focused,.select.is-primary select:active,.docstring>section>a.select.docs-sourcelink select:active,.select.is-primary select.is-active,.docstring>section>a.select.docs-sourcelink select.is-active{box-shadow:0 0 0 0.125em rgba(78,181,222,0.25)}.select.is-link:not(:hover)::after{border-color:#2e63b8}.select.is-link select{border-color:#2e63b8}.select.is-link select:hover,.select.is-link select.is-hovered{border-color:#2958a4}.select.is-link select:focus,.select.is-link select.is-focused,.select.is-link select:active,.select.is-link select.is-active{box-shadow:0 0 0 0.125em rgba(46,99,184,0.25)}.select.is-info:not(:hover)::after{border-color:#209cee}.select.is-info select{border-color:#209cee}.select.is-info select:hover,.select.is-info select.is-hovered{border-color:#1190e3}.select.is-info select:focus,.select.is-info select.is-focused,.select.is-info select:active,.select.is-info select.is-active{box-shadow:0 0 0 0.125em rgba(32,156,238,0.25)}.select.is-success:not(:hover)::after{border-color:#22c35b}.select.is-success select{border-color:#22c35b}.select.is-success select:hover,.select.is-success select.is-hovered{border-color:#1ead51}.select.is-success select:focus,.select.is-success select.is-focused,.select.is-success select:active,.select.is-success select.is-active{box-shadow:0 0 0 0.125em rgba(34,195,91,0.25)}.select.is-warning:not(:hover)::after{border-color:#ffdd57}.select.is-warning select{border-color:#ffdd57}.select.is-warning select:hover,.select.is-warning select.is-hovered{border-color:#ffd83e}.select.is-warning select:focus,.select.is-warning select.is-focused,.select.is-warning select:active,.select.is-warning select.is-active{box-shadow:0 0 0 0.125em rgba(255,221,87,0.25)}.select.is-danger:not(:hover)::after{border-color:#da0b00}.select.is-danger select{border-color:#da0b00}.select.is-danger select:hover,.select.is-danger select.is-hovered{border-color:#c10a00}.select.is-danger select:focus,.select.is-danger select.is-focused,.select.is-danger select:active,.select.is-danger select.is-active{box-shadow:0 0 0 0.125em rgba(218,11,0,0.25)}.select.is-small,#documenter .docs-sidebar form.docs-search>input.select{border-radius:2px;font-size:.75rem}.select.is-medium{font-size:1.25rem}.select.is-large{font-size:1.5rem}.select.is-disabled::after{border-color:#6b6b6b !important;opacity:0.5}.select.is-fullwidth{width:100%}.select.is-fullwidth select{width:100%}.select.is-loading::after{margin-top:0;position:absolute;right:.625em;top:0.625em;transform:none}.select.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.select.is-loading.is-medium:after{font-size:1.25rem}.select.is-loading.is-large:after{font-size:1.5rem}.file{align-items:stretch;display:flex;justify-content:flex-start;position:relative}.file.is-white .file-cta{background-color:#fff;border-color:transparent;color:#0a0a0a}.file.is-white:hover .file-cta,.file.is-white.is-hovered .file-cta{background-color:#f9f9f9;border-color:transparent;color:#0a0a0a}.file.is-white:focus .file-cta,.file.is-white.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,255,255,0.25);color:#0a0a0a}.file.is-white:active .file-cta,.file.is-white.is-active .file-cta{background-color:#f2f2f2;border-color:transparent;color:#0a0a0a}.file.is-black .file-cta{background-color:#0a0a0a;border-color:transparent;color:#fff}.file.is-black:hover .file-cta,.file.is-black.is-hovered .file-cta{background-color:#040404;border-color:transparent;color:#fff}.file.is-black:focus .file-cta,.file.is-black.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(10,10,10,0.25);color:#fff}.file.is-black:active .file-cta,.file.is-black.is-active .file-cta{background-color:#000;border-color:transparent;color:#fff}.file.is-light .file-cta{background-color:#f5f5f5;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-light:hover .file-cta,.file.is-light.is-hovered .file-cta{background-color:#eee;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-light:focus .file-cta,.file.is-light.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(245,245,245,0.25);color:rgba(0,0,0,0.7)}.file.is-light:active .file-cta,.file.is-light.is-active .file-cta{background-color:#e8e8e8;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-dark .file-cta,.content kbd.file .file-cta{background-color:#363636;border-color:transparent;color:#fff}.file.is-dark:hover .file-cta,.content kbd.file:hover .file-cta,.file.is-dark.is-hovered .file-cta,.content kbd.file.is-hovered .file-cta{background-color:#2f2f2f;border-color:transparent;color:#fff}.file.is-dark:focus .file-cta,.content kbd.file:focus .file-cta,.file.is-dark.is-focused .file-cta,.content kbd.file.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(54,54,54,0.25);color:#fff}.file.is-dark:active .file-cta,.content kbd.file:active .file-cta,.file.is-dark.is-active .file-cta,.content kbd.file.is-active .file-cta{background-color:#292929;border-color:transparent;color:#fff}.file.is-primary .file-cta,.docstring>section>a.file.docs-sourcelink .file-cta{background-color:#4eb5de;border-color:transparent;color:#fff}.file.is-primary:hover .file-cta,.docstring>section>a.file.docs-sourcelink:hover .file-cta,.file.is-primary.is-hovered .file-cta,.docstring>section>a.file.is-hovered.docs-sourcelink .file-cta{background-color:#43b1dc;border-color:transparent;color:#fff}.file.is-primary:focus .file-cta,.docstring>section>a.file.docs-sourcelink:focus .file-cta,.file.is-primary.is-focused .file-cta,.docstring>section>a.file.is-focused.docs-sourcelink .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(78,181,222,0.25);color:#fff}.file.is-primary:active .file-cta,.docstring>section>a.file.docs-sourcelink:active .file-cta,.file.is-primary.is-active .file-cta,.docstring>section>a.file.is-active.docs-sourcelink .file-cta{background-color:#39acda;border-color:transparent;color:#fff}.file.is-link .file-cta{background-color:#2e63b8;border-color:transparent;color:#fff}.file.is-link:hover .file-cta,.file.is-link.is-hovered .file-cta{background-color:#2b5eae;border-color:transparent;color:#fff}.file.is-link:focus .file-cta,.file.is-link.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(46,99,184,0.25);color:#fff}.file.is-link:active .file-cta,.file.is-link.is-active .file-cta{background-color:#2958a4;border-color:transparent;color:#fff}.file.is-info .file-cta{background-color:#209cee;border-color:transparent;color:#fff}.file.is-info:hover .file-cta,.file.is-info.is-hovered .file-cta{background-color:#1497ed;border-color:transparent;color:#fff}.file.is-info:focus .file-cta,.file.is-info.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(32,156,238,0.25);color:#fff}.file.is-info:active .file-cta,.file.is-info.is-active .file-cta{background-color:#1190e3;border-color:transparent;color:#fff}.file.is-success .file-cta{background-color:#22c35b;border-color:transparent;color:#fff}.file.is-success:hover .file-cta,.file.is-success.is-hovered .file-cta{background-color:#20b856;border-color:transparent;color:#fff}.file.is-success:focus .file-cta,.file.is-success.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(34,195,91,0.25);color:#fff}.file.is-success:active .file-cta,.file.is-success.is-active .file-cta{background-color:#1ead51;border-color:transparent;color:#fff}.file.is-warning .file-cta{background-color:#ffdd57;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:hover .file-cta,.file.is-warning.is-hovered .file-cta{background-color:#ffda4a;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-warning:focus .file-cta,.file.is-warning.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(255,221,87,0.25);color:rgba(0,0,0,0.7)}.file.is-warning:active .file-cta,.file.is-warning.is-active .file-cta{background-color:#ffd83e;border-color:transparent;color:rgba(0,0,0,0.7)}.file.is-danger .file-cta{background-color:#da0b00;border-color:transparent;color:#fff}.file.is-danger:hover .file-cta,.file.is-danger.is-hovered .file-cta{background-color:#cd0a00;border-color:transparent;color:#fff}.file.is-danger:focus .file-cta,.file.is-danger.is-focused .file-cta{border-color:transparent;box-shadow:0 0 0.5em rgba(218,11,0,0.25);color:#fff}.file.is-danger:active .file-cta,.file.is-danger.is-active .file-cta{background-color:#c10a00;border-color:transparent;color:#fff}.file.is-small,#documenter .docs-sidebar form.docs-search>input.file{font-size:.75rem}.file.is-normal{font-size:1rem}.file.is-medium{font-size:1.25rem}.file.is-medium .file-icon .fa{font-size:21px}.file.is-large{font-size:1.5rem}.file.is-large .file-icon .fa{font-size:28px}.file.has-name .file-cta{border-bottom-right-radius:0;border-top-right-radius:0}.file.has-name .file-name{border-bottom-left-radius:0;border-top-left-radius:0}.file.has-name.is-empty .file-cta{border-radius:4px}.file.has-name.is-empty .file-name{display:none}.file.is-boxed .file-label{flex-direction:column}.file.is-boxed .file-cta{flex-direction:column;height:auto;padding:1em 3em}.file.is-boxed .file-name{border-width:0 1px 1px}.file.is-boxed .file-icon{height:1.5em;width:1.5em}.file.is-boxed .file-icon .fa{font-size:21px}.file.is-boxed.is-small .file-icon .fa,#documenter .docs-sidebar form.docs-search>input.is-boxed .file-icon .fa{font-size:14px}.file.is-boxed.is-medium .file-icon .fa{font-size:28px}.file.is-boxed.is-large .file-icon .fa{font-size:35px}.file.is-boxed.has-name .file-cta{border-radius:4px 4px 0 0}.file.is-boxed.has-name .file-name{border-radius:0 0 4px 4px;border-width:0 1px 1px}.file.is-centered{justify-content:center}.file.is-fullwidth .file-label{width:100%}.file.is-fullwidth .file-name{flex-grow:1;max-width:none}.file.is-right{justify-content:flex-end}.file.is-right .file-cta{border-radius:0 4px 4px 0}.file.is-right .file-name{border-radius:4px 0 0 4px;border-width:1px 0 1px 1px;order:-1}.file-label{align-items:stretch;display:flex;cursor:pointer;justify-content:flex-start;overflow:hidden;position:relative}.file-label:hover .file-cta{background-color:#eee;color:#222}.file-label:hover .file-name{border-color:#d5d5d5}.file-label:active .file-cta{background-color:#e8e8e8;color:#222}.file-label:active .file-name{border-color:#cfcfcf}.file-input{height:100%;left:0;opacity:0;outline:none;position:absolute;top:0;width:100%}.file-cta,.file-name{border-color:#dbdbdb;border-radius:4px;font-size:1em;padding-left:1em;padding-right:1em;white-space:nowrap}.file-cta{background-color:#f5f5f5;color:#222}.file-name{border-color:#dbdbdb;border-style:solid;border-width:1px 1px 1px 0;display:block;max-width:16em;overflow:hidden;text-align:inherit;text-overflow:ellipsis}.file-icon{align-items:center;display:flex;height:1em;justify-content:center;margin-right:.5em;width:1em}.file-icon .fa{font-size:14px}.label{color:#222;display:block;font-size:1rem;font-weight:700}.label:not(:last-child){margin-bottom:0.5em}.label.is-small,#documenter .docs-sidebar form.docs-search>input.label{font-size:.75rem}.label.is-medium{font-size:1.25rem}.label.is-large{font-size:1.5rem}.help{display:block;font-size:.75rem;margin-top:0.25rem}.help.is-white{color:#fff}.help.is-black{color:#0a0a0a}.help.is-light{color:#f5f5f5}.help.is-dark,.content kbd.help{color:#363636}.help.is-primary,.docstring>section>a.help.docs-sourcelink{color:#4eb5de}.help.is-link{color:#2e63b8}.help.is-info{color:#209cee}.help.is-success{color:#22c35b}.help.is-warning{color:#ffdd57}.help.is-danger{color:#da0b00}.field:not(:last-child){margin-bottom:0.75rem}.field.has-addons{display:flex;justify-content:flex-start}.field.has-addons .control:not(:last-child){margin-right:-1px}.field.has-addons .control:not(:first-child):not(:last-child) .button,.field.has-addons .control:not(:first-child):not(:last-child) .input,.field.has-addons .control:not(:first-child):not(:last-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:not(:first-child):not(:last-child) form.docs-search>input,.field.has-addons .control:not(:first-child):not(:last-child) .select select{border-radius:0}.field.has-addons .control:first-child:not(:only-child) .button,.field.has-addons .control:first-child:not(:only-child) .input,.field.has-addons .control:first-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:first-child:not(:only-child) form.docs-search>input,.field.has-addons .control:first-child:not(:only-child) .select select{border-bottom-right-radius:0;border-top-right-radius:0}.field.has-addons .control:last-child:not(:only-child) .button,.field.has-addons .control:last-child:not(:only-child) .input,.field.has-addons .control:last-child:not(:only-child) #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .field.has-addons .control:last-child:not(:only-child) form.docs-search>input,.field.has-addons .control:last-child:not(:only-child) .select select{border-bottom-left-radius:0;border-top-left-radius:0}.field.has-addons .control .button:not([disabled]):hover,.field.has-addons .control .button.is-hovered:not([disabled]),.field.has-addons .control .input:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):hover,.field.has-addons .control .input.is-hovered:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-hovered:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-hovered:not([disabled]),.field.has-addons .control .select select:not([disabled]):hover,.field.has-addons .control .select select.is-hovered:not([disabled]){z-index:2}.field.has-addons .control .button:not([disabled]):focus,.field.has-addons .control .button.is-focused:not([disabled]),.field.has-addons .control .button:not([disabled]):active,.field.has-addons .control .button.is-active:not([disabled]),.field.has-addons .control .input:not([disabled]):focus,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus,.field.has-addons .control .input.is-focused:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]),.field.has-addons .control .input:not([disabled]):active,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active,.field.has-addons .control .input.is-active:not([disabled]),.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]),#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]),.field.has-addons .control .select select:not([disabled]):focus,.field.has-addons .control .select select.is-focused:not([disabled]),.field.has-addons .control .select select:not([disabled]):active,.field.has-addons .control .select select.is-active:not([disabled]){z-index:3}.field.has-addons .control .button:not([disabled]):focus:hover,.field.has-addons .control .button.is-focused:not([disabled]):hover,.field.has-addons .control .button:not([disabled]):active:hover,.field.has-addons .control .button.is-active:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):focus:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):focus:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):focus:hover,.field.has-addons .control .input.is-focused:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-focused:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-focused:not([disabled]):hover,.field.has-addons .control .input:not([disabled]):active:hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input:not([disabled]):active:hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input:not([disabled]):active:hover,.field.has-addons .control .input.is-active:not([disabled]):hover,.field.has-addons .control #documenter .docs-sidebar form.docs-search>input.is-active:not([disabled]):hover,#documenter .docs-sidebar .field.has-addons .control form.docs-search>input.is-active:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):focus:hover,.field.has-addons .control .select select.is-focused:not([disabled]):hover,.field.has-addons .control .select select:not([disabled]):active:hover,.field.has-addons .control .select select.is-active:not([disabled]):hover{z-index:4}.field.has-addons .control.is-expanded{flex-grow:1;flex-shrink:1}.field.has-addons.has-addons-centered{justify-content:center}.field.has-addons.has-addons-right{justify-content:flex-end}.field.has-addons.has-addons-fullwidth .control{flex-grow:1;flex-shrink:0}.field.is-grouped{display:flex;justify-content:flex-start}.field.is-grouped>.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px),print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width: 768px){.field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px),print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small,#documenter .docs-sidebar form.docs-search>input.field-label{font-size:.75rem;padding-top:0.375em}.field-label.is-normal{padding-top:0.375em}.field-label.is-medium{font-size:1.25rem;padding-top:0.375em}.field-label.is-large{font-size:1.5rem;padding-top:0.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px),print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:inherit}.control.has-icons-left .input:focus~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input:focus~.icon,.control.has-icons-left .select:focus~.icon,.control.has-icons-right .input:focus~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input:focus~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input:focus~.icon,.control.has-icons-right .select:focus~.icon{color:#222}.control.has-icons-left .input.is-small~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input~.icon,.control.has-icons-left .select.is-small~.icon,.control.has-icons-right .input.is-small~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input~.icon,.control.has-icons-right .select.is-small~.icon{font-size:.75rem}.control.has-icons-left .input.is-medium~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-medium~.icon,.control.has-icons-left .select.is-medium~.icon,.control.has-icons-right .input.is-medium~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-medium~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-medium~.icon,.control.has-icons-right .select.is-medium~.icon{font-size:1.25rem}.control.has-icons-left .input.is-large~.icon,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input.is-large~.icon,.control.has-icons-left .select.is-large~.icon,.control.has-icons-right .input.is-large~.icon,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input.is-large~.icon,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input.is-large~.icon,.control.has-icons-right .select.is-large~.icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.5em;pointer-events:none;position:absolute;top:0;width:2.5em;z-index:4}.control.has-icons-left .input,.control.has-icons-left #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-left form.docs-search>input,.control.has-icons-left .select select{padding-left:2.5em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right #documenter .docs-sidebar form.docs-search>input,#documenter .docs-sidebar .control.has-icons-right form.docs-search>input,.control.has-icons-right .select select{padding-right:2.5em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute !important;right:.625em;top:0.625em;z-index:4}.control.is-loading.is-small:after,#documenter .docs-sidebar form.docs-search>input.is-loading:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#2e63b8;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#222;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ul,.breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:.5em}.breadcrumb .icon:last-child{margin-left:.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small,#documenter .docs-sidebar form.docs-search>input.breadcrumb{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;border-radius:.25rem;box-shadow:#bbb;color:#222;max-width:100%;position:relative}.card-footer:first-child,.card-content:first-child,.card-header:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-footer:last-child,.card-content:last-child,.card-header:last-child{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);display:flex}.card-header-title{align-items:center;color:#222;display:flex;flex-grow:1;font-weight:700;padding:0.75rem 1rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;color:currentColor;font-family:inherit;font-size:1em;margin:0;padding:0;align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem 1rem}.card-image{display:block;position:relative}.card-image:first-child img{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card-image:last-child img{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.card-content{background-color:rgba(0,0,0,0);padding:1.5rem}.card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #ededed;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:.75rem}.card-footer-item:not(:last-child){border-right:1px solid #ededed}.card .media:not(:last-child){margin-bottom:1.5rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:#bbb;padding-bottom:.5rem;padding-top:.5rem}.dropdown-item{color:#222;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:inherit;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#2e63b8;color:#fff}.dropdown-divider{background-color:#ededed;border:none;display:block;height:1px;margin:0.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px),print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .title,.level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){.level-item:not(:last-child){margin-bottom:.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px),print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px),print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px),print{.level-right{display:flex}}.media{align-items:flex-start;display:flex;text-align:inherit}.media .content:not(:last-child){margin-bottom:.75rem}.media .media{border-top:1px solid rgba(219,219,219,0.5);display:flex;padding-top:.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:.5rem}.media .media .media{padding-top:.5rem}.media .media .media+.media{margin-top:.5rem}.media+.media{border-top:1px solid rgba(219,219,219,0.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:inherit}@media screen and (max-width: 768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small,#documenter .docs-sidebar form.docs-search>input.menu{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#222;display:block;padding:0.5em 0.75em}.menu-list a:hover{background-color:#f5f5f5;color:#222}.menu-list a.is-active{background-color:#2e63b8;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:.75em;padding-left:.75em}.menu-label{color:#6b6b6b;font-size:.75em;letter-spacing:.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small,#documenter .docs-sidebar form.docs-search>input.message{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.message.is-light .message-body{border-color:#f5f5f5}.message.is-dark,.content kbd.message{background-color:#fafafa}.message.is-dark .message-header,.content kbd.message .message-header{background-color:#363636;color:#fff}.message.is-dark .message-body,.content kbd.message .message-body{border-color:#363636}.message.is-primary,.docstring>section>a.message.docs-sourcelink{background-color:#eef8fc}.message.is-primary .message-header,.docstring>section>a.message.docs-sourcelink .message-header{background-color:#4eb5de;color:#fff}.message.is-primary .message-body,.docstring>section>a.message.docs-sourcelink .message-body{border-color:#4eb5de;color:#1a6d8e}.message.is-link{background-color:#eff3fb}.message.is-link .message-header{background-color:#2e63b8;color:#fff}.message.is-link .message-body{border-color:#2e63b8;color:#3169c4}.message.is-info{background-color:#ecf7fe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#0e72b4}.message.is-success{background-color:#eefcf3}.message.is-success .message-header{background-color:#22c35b;color:#fff}.message.is-success .message-body{border-color:#22c35b;color:#198f43}.message.is-warning{background-color:#fffbeb}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#947600}.message.is-danger{background-color:#ffeceb}.message.is-danger .message-header{background-color:#da0b00;color:#fff}.message.is-danger .message-body{border-color:#da0b00;color:#f50c00}.message-header{align-items:center;background-color:#222;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#222;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:rgba(0,0,0,0)}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,0.86)}.modal-content,.modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px){.modal-content,.modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-head,.modal-card-foot{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#222;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:.5em}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand>.navbar-item,.navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-brand>a.navbar-item:focus,.navbar.is-white .navbar-brand>a.navbar-item:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand .navbar-link:focus,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1056px){.navbar.is-white .navbar-start>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-start>a.navbar-item:focus,.navbar.is-white .navbar-start>a.navbar-item:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start .navbar-link:focus,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-end>a.navbar-item:focus,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end .navbar-link:focus,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-start .navbar-link::after,.navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand>.navbar-item,.navbar.is-black .navbar-brand .navbar-link{color:#fff}.navbar.is-black .navbar-brand>a.navbar-item:focus,.navbar.is-black .navbar-brand>a.navbar-item:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand .navbar-link:focus,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-black .navbar-start>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-end .navbar-link{color:#fff}.navbar.is-black .navbar-start>a.navbar-item:focus,.navbar.is-black .navbar-start>a.navbar-item:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start .navbar-link:focus,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-end>a.navbar-item:focus,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end .navbar-link:focus,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-start .navbar-link::after,.navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand>.navbar-item,.navbar.is-light .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand>a.navbar-item:focus,.navbar.is-light .navbar-brand>a.navbar-item:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand .navbar-link:focus,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){.navbar.is-light .navbar-start>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-start>a.navbar-item:focus,.navbar.is-light .navbar-start>a.navbar-item:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start .navbar-link:focus,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-end>a.navbar-item:focus,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end .navbar-link:focus,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-start .navbar-link::after,.navbar.is-light .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}}.navbar.is-dark,.content kbd.navbar{background-color:#363636;color:#fff}.navbar.is-dark .navbar-brand>.navbar-item,.content kbd.navbar .navbar-brand>.navbar-item,.navbar.is-dark .navbar-brand .navbar-link,.content kbd.navbar .navbar-brand .navbar-link{color:#fff}.navbar.is-dark .navbar-brand>a.navbar-item:focus,.content kbd.navbar .navbar-brand>a.navbar-item:focus,.navbar.is-dark .navbar-brand>a.navbar-item:hover,.content kbd.navbar .navbar-brand>a.navbar-item:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.content kbd.navbar .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand .navbar-link:focus,.content kbd.navbar .navbar-brand .navbar-link:focus,.navbar.is-dark .navbar-brand .navbar-link:hover,.content kbd.navbar .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand .navbar-link.is-active,.content kbd.navbar .navbar-brand .navbar-link.is-active{background-color:#292929;color:#fff}.navbar.is-dark .navbar-brand .navbar-link::after,.content kbd.navbar .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-burger,.content kbd.navbar .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-dark .navbar-start>.navbar-item,.content kbd.navbar .navbar-start>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.content kbd.navbar .navbar-start .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.content kbd.navbar .navbar-end>.navbar-item,.navbar.is-dark .navbar-end .navbar-link,.content kbd.navbar .navbar-end .navbar-link{color:#fff}.navbar.is-dark .navbar-start>a.navbar-item:focus,.content kbd.navbar .navbar-start>a.navbar-item:focus,.navbar.is-dark .navbar-start>a.navbar-item:hover,.content kbd.navbar .navbar-start>a.navbar-item:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.content kbd.navbar .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start .navbar-link:focus,.content kbd.navbar .navbar-start .navbar-link:focus,.navbar.is-dark .navbar-start .navbar-link:hover,.content kbd.navbar .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.content kbd.navbar .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-end>a.navbar-item:focus,.content kbd.navbar .navbar-end>a.navbar-item:focus,.navbar.is-dark .navbar-end>a.navbar-item:hover,.content kbd.navbar .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.content kbd.navbar .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end .navbar-link:focus,.content kbd.navbar .navbar-end .navbar-link:focus,.navbar.is-dark .navbar-end .navbar-link:hover,.content kbd.navbar .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end .navbar-link.is-active,.content kbd.navbar .navbar-end .navbar-link.is-active{background-color:#292929;color:#fff}.navbar.is-dark .navbar-start .navbar-link::after,.content kbd.navbar .navbar-start .navbar-link::after,.navbar.is-dark .navbar-end .navbar-link::after,.content kbd.navbar .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,.content kbd.navbar .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link,.content kbd.navbar .navbar-item.has-dropdown.is-active .navbar-link{background-color:#292929;color:#fff}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active,.content kbd.navbar .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#fff}}.navbar.is-primary,.docstring>section>a.navbar.docs-sourcelink{background-color:#4eb5de;color:#fff}.navbar.is-primary .navbar-brand>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>.navbar-item,.navbar.is-primary .navbar-brand .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link{color:#fff}.navbar.is-primary .navbar-brand>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:focus,.navbar.is-primary .navbar-brand>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:focus,.navbar.is-primary .navbar-brand .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger,.docstring>section>a.navbar.docs-sourcelink .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-primary .navbar-start>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-start>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.docstring>section>a.navbar.docs-sourcelink .navbar-end>.navbar-item,.navbar.is-primary .navbar-end .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link{color:#fff}.navbar.is-primary .navbar-start>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:focus,.navbar.is-primary .navbar-start>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:focus,.navbar.is-primary .navbar-start .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-end>a.navbar-item:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:focus,.navbar.is-primary .navbar-end>a.navbar-item:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end .navbar-link:focus,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:focus,.navbar.is-primary .navbar-end .navbar-link:hover,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end .navbar-link.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link.is-active{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-start .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-start .navbar-link::after,.navbar.is-primary .navbar-end .navbar-link::after,.docstring>section>a.navbar.docs-sourcelink .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link,.docstring>section>a.navbar.docs-sourcelink .navbar-item.has-dropdown.is-active .navbar-link{background-color:#39acda;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active,.docstring>section>a.navbar.docs-sourcelink .navbar-dropdown a.navbar-item.is-active{background-color:#4eb5de;color:#fff}}.navbar.is-link{background-color:#2e63b8;color:#fff}.navbar.is-link .navbar-brand>.navbar-item,.navbar.is-link .navbar-brand .navbar-link{color:#fff}.navbar.is-link .navbar-brand>a.navbar-item:focus,.navbar.is-link .navbar-brand>a.navbar-item:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand .navbar-link:focus,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-link .navbar-start>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-end .navbar-link{color:#fff}.navbar.is-link .navbar-start>a.navbar-item:focus,.navbar.is-link .navbar-start>a.navbar-item:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start .navbar-link:focus,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-end>a.navbar-item:focus,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end .navbar-link:focus,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end .navbar-link.is-active{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-start .navbar-link::after,.navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2958a4;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#2e63b8;color:#fff}}.navbar.is-info{background-color:#209cee;color:#fff}.navbar.is-info .navbar-brand>.navbar-item,.navbar.is-info .navbar-brand .navbar-link{color:#fff}.navbar.is-info .navbar-brand>a.navbar-item:focus,.navbar.is-info .navbar-brand>a.navbar-item:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand .navbar-link:focus,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-info .navbar-start>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-end .navbar-link{color:#fff}.navbar.is-info .navbar-start>a.navbar-item:focus,.navbar.is-info .navbar-start>a.navbar-item:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start .navbar-link:focus,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-end>a.navbar-item:focus,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end .navbar-link:focus,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end .navbar-link.is-active{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-start .navbar-link::after,.navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1190e3;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#209cee;color:#fff}}.navbar.is-success{background-color:#22c35b;color:#fff}.navbar.is-success .navbar-brand>.navbar-item,.navbar.is-success .navbar-brand .navbar-link{color:#fff}.navbar.is-success .navbar-brand>a.navbar-item:focus,.navbar.is-success .navbar-brand>a.navbar-item:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand .navbar-link:focus,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-success .navbar-start>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-end .navbar-link{color:#fff}.navbar.is-success .navbar-start>a.navbar-item:focus,.navbar.is-success .navbar-start>a.navbar-item:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start .navbar-link:focus,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-end>a.navbar-item:focus,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end .navbar-link:focus,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end .navbar-link.is-active{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-start .navbar-link::after,.navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#1ead51;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#22c35b;color:#fff}}.navbar.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>.navbar-item,.navbar.is-warning .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>a.navbar-item:focus,.navbar.is-warning .navbar-brand>a.navbar-item:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand .navbar-link:focus,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1056px){.navbar.is-warning .navbar-start>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start>a.navbar-item:focus,.navbar.is-warning .navbar-start>a.navbar-item:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start .navbar-link:focus,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-end>a.navbar-item:focus,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end .navbar-link:focus,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start .navbar-link::after,.navbar.is-warning .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffdd57;color:rgba(0,0,0,0.7)}}.navbar.is-danger{background-color:#da0b00;color:#fff}.navbar.is-danger .navbar-brand>.navbar-item,.navbar.is-danger .navbar-brand .navbar-link{color:#fff}.navbar.is-danger .navbar-brand>a.navbar-item:focus,.navbar.is-danger .navbar-brand>a.navbar-item:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand .navbar-link:focus,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1056px){.navbar.is-danger .navbar-start>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-end .navbar-link{color:#fff}.navbar.is-danger .navbar-start>a.navbar-item:focus,.navbar.is-danger .navbar-start>a.navbar-item:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start .navbar-link:focus,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-end>a.navbar-item:focus,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end .navbar-link:focus,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-start .navbar-link::after,.navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link,.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#c10a00;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#da0b00;color:#fff}}.navbar>.container{align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}html.has-navbar-fixed-top,body.has-navbar-fixed-top{padding-top:3.25rem}html.has-navbar-fixed-bottom,body.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:focus,.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#222;-moz-appearance:none;-webkit-appearance:none;appearance:none;background:none;border:none;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,0.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#222;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}a.navbar-item,.navbar-link{cursor:pointer}a.navbar-item:focus,a.navbar-item:focus-within,a.navbar-item:hover,a.navbar-item.is-active,.navbar-link:focus,.navbar-link:focus-within,.navbar-link:hover,.navbar-link.is-active{background-color:#fafafa;color:#2e63b8}.navbar-item{flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(0.5rem - 1px)}.navbar-item.is-tab:focus,.navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8}.navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#2e63b8;border-bottom-style:solid;border-bottom-width:3px;color:#2e63b8;padding-bottom:calc(0.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#2e63b8;margin-top:-0.375em;right:1.125em}.navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1055px){.navbar>.container{display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}html.has-navbar-fixed-top-touch,body.has-navbar-fixed-top-touch{padding-top:3.25rem}html.has-navbar-fixed-bottom-touch,body.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width: 1056px){.navbar,.navbar-menu,.navbar-start,.navbar-end{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-start,.navbar.is-spaced .navbar-end{align-items:center}.navbar.is-spaced a.navbar-item,.navbar.is-spaced .navbar-link{border-radius:4px}.navbar.is-transparent a.navbar-item:focus,.navbar.is-transparent a.navbar-item:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent .navbar-link:focus,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}.navbar.is-transparent .navbar-dropdown a.navbar-item:focus,.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown,.navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown,.navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:focus,.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#2e63b8}.navbar.is-spaced .navbar-dropdown,.navbar-dropdown.is-boxed{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1), 0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.navbar>.container .navbar-brand,.container>.navbar .navbar-brand{margin-left:-.75rem}.navbar>.container .navbar-menu,.container>.navbar .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-desktop{top:0}html.has-navbar-fixed-top-desktop,body.has-navbar-fixed-top-desktop{padding-top:3.25rem}html.has-navbar-fixed-bottom-desktop,body.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}html.has-spaced-navbar-fixed-top,body.has-spaced-navbar-fixed-top{padding-top:5.25rem}html.has-spaced-navbar-fixed-bottom,body.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}a.navbar-item.is-active,.navbar-link.is-active{color:#0a0a0a}a.navbar-item.is-active:not(:focus):not(:hover),.navbar-link.is-active:not(:focus):not(:hover){background-color:rgba(0,0,0,0)}.navbar-item.has-dropdown:focus .navbar-link,.navbar-item.has-dropdown:hover .navbar-link,.navbar-item.has-dropdown.is-active .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small,#documenter .docs-sidebar form.docs-search>input.pagination{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-previous,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-previous,.pagination.is-rounded .pagination-next,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-next{padding-left:1em;padding-right:1em;border-radius:9999px}.pagination.is-rounded .pagination-link,#documenter .docs-sidebar form.docs-search>input.pagination .pagination-link{border-radius:9999px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{font-size:1em;justify-content:center;margin:.25rem;padding-left:.5em;padding-right:.5em;text-align:center}.pagination-previous,.pagination-next,.pagination-link{border-color:#dbdbdb;color:#222;min-width:2.5em}.pagination-previous:hover,.pagination-next:hover,.pagination-link:hover{border-color:#b5b5b5;color:#363636}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus{border-color:#3c5dcd}.pagination-previous:active,.pagination-next:active,.pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}.pagination-previous[disabled],.pagination-previous.is-disabled,.pagination-next[disabled],.pagination-next.is-disabled,.pagination-link[disabled],.pagination-link.is-disabled{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#6b6b6b;opacity:0.5}.pagination-previous,.pagination-next{padding-left:.75em;padding-right:.75em;white-space:nowrap}.pagination-link.is-current{background-color:#2e63b8;border-color:#2e63b8;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}.pagination-list li{list-style:none}@media screen and (max-width: 768px){.pagination{flex-wrap:wrap}.pagination-previous,.pagination-next{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px),print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{margin-bottom:0;margin-top:0}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between;margin-bottom:0;margin-top:0}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{border-radius:6px;box-shadow:#bbb;font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel.is-white .panel-heading{background-color:#fff;color:#0a0a0a}.panel.is-white .panel-tabs a.is-active{border-bottom-color:#fff}.panel.is-white .panel-block.is-active .panel-icon{color:#fff}.panel.is-black .panel-heading{background-color:#0a0a0a;color:#fff}.panel.is-black .panel-tabs a.is-active{border-bottom-color:#0a0a0a}.panel.is-black .panel-block.is-active .panel-icon{color:#0a0a0a}.panel.is-light .panel-heading{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.panel.is-light .panel-tabs a.is-active{border-bottom-color:#f5f5f5}.panel.is-light .panel-block.is-active .panel-icon{color:#f5f5f5}.panel.is-dark .panel-heading,.content kbd.panel .panel-heading{background-color:#363636;color:#fff}.panel.is-dark .panel-tabs a.is-active,.content kbd.panel .panel-tabs a.is-active{border-bottom-color:#363636}.panel.is-dark .panel-block.is-active .panel-icon,.content kbd.panel .panel-block.is-active .panel-icon{color:#363636}.panel.is-primary .panel-heading,.docstring>section>a.panel.docs-sourcelink .panel-heading{background-color:#4eb5de;color:#fff}.panel.is-primary .panel-tabs a.is-active,.docstring>section>a.panel.docs-sourcelink .panel-tabs a.is-active{border-bottom-color:#4eb5de}.panel.is-primary .panel-block.is-active .panel-icon,.docstring>section>a.panel.docs-sourcelink .panel-block.is-active .panel-icon{color:#4eb5de}.panel.is-link .panel-heading{background-color:#2e63b8;color:#fff}.panel.is-link .panel-tabs a.is-active{border-bottom-color:#2e63b8}.panel.is-link .panel-block.is-active .panel-icon{color:#2e63b8}.panel.is-info .panel-heading{background-color:#209cee;color:#fff}.panel.is-info .panel-tabs a.is-active{border-bottom-color:#209cee}.panel.is-info .panel-block.is-active .panel-icon{color:#209cee}.panel.is-success .panel-heading{background-color:#22c35b;color:#fff}.panel.is-success .panel-tabs a.is-active{border-bottom-color:#22c35b}.panel.is-success .panel-block.is-active .panel-icon{color:#22c35b}.panel.is-warning .panel-heading{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.panel.is-warning .panel-tabs a.is-active{border-bottom-color:#ffdd57}.panel.is-warning .panel-block.is-active .panel-icon{color:#ffdd57}.panel.is-danger .panel-heading{background-color:#da0b00;color:#fff}.panel.is-danger .panel-tabs a.is-active{border-bottom-color:#da0b00}.panel.is-danger .panel-block.is-active .panel-icon{color:#da0b00}.panel-tabs:not(:last-child),.panel-block:not(:last-child){border-bottom:1px solid #ededed}.panel-heading{background-color:#ededed;border-radius:6px 6px 0 0;color:#222;font-size:1.25em;font-weight:700;line-height:1.25;padding:0.75em 1em}.panel-tabs{align-items:flex-end;display:flex;font-size:.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:0.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#222}.panel-list a:hover{color:#2e63b8}.panel-block{align-items:center;color:#222;display:flex;justify-content:flex-start;padding:0.5em 0.75em}.panel-block input[type="checkbox"]{margin-right:.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#2e63b8;color:#363636}.panel-block.is-active .panel-icon{color:#2e63b8}.panel-block:last-child{border-bottom-left-radius:6px;border-bottom-right-radius:6px}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#6b6b6b;margin-right:.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#222;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#222;color:#222}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#2e63b8;color:#2e63b8}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:0.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}.tabs .icon:first-child{margin-right:.5em}.tabs .icon:last-child{margin-left:.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:rgba(0,0,0,0) !important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-top-left-radius:4px;border-bottom-left-radius:4px}.tabs.is-toggle li:last-child a{border-top-right-radius:4px;border-bottom-right-radius:4px}.tabs.is-toggle li.is-active a{background-color:#2e63b8;border-color:#2e63b8;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:9999px;border-top-left-radius:9999px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:9999px;border-top-right-radius:9999px;padding-right:1.25em}.tabs.is-small,#documenter .docs-sidebar form.docs-search>input.tabs{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none;width:unset}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-0{flex:none;width:0%}.columns.is-mobile>.column.is-offset-0{margin-left:0%}.columns.is-mobile>.column.is-1{flex:none;width:8.33333337%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333337%}.columns.is-mobile>.column.is-2{flex:none;width:16.66666674%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66666674%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333337%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333337%}.columns.is-mobile>.column.is-5{flex:none;width:41.66666674%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66666674%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333337%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333337%}.columns.is-mobile>.column.is-8{flex:none;width:66.66666674%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66666674%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333337%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333337%}.columns.is-mobile>.column.is-11{flex:none;width:91.66666674%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66666674%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){.column.is-narrow-mobile{flex:none;width:unset}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-0-mobile{flex:none;width:0%}.column.is-offset-0-mobile{margin-left:0%}.column.is-1-mobile{flex:none;width:8.33333337%}.column.is-offset-1-mobile{margin-left:8.33333337%}.column.is-2-mobile{flex:none;width:16.66666674%}.column.is-offset-2-mobile{margin-left:16.66666674%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333337%}.column.is-offset-4-mobile{margin-left:33.33333337%}.column.is-5-mobile{flex:none;width:41.66666674%}.column.is-offset-5-mobile{margin-left:41.66666674%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333337%}.column.is-offset-7-mobile{margin-left:58.33333337%}.column.is-8-mobile{flex:none;width:66.66666674%}.column.is-offset-8-mobile{margin-left:66.66666674%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333337%}.column.is-offset-10-mobile{margin-left:83.33333337%}.column.is-11-mobile{flex:none;width:91.66666674%}.column.is-offset-11-mobile{margin-left:91.66666674%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px),print{.column.is-narrow,.column.is-narrow-tablet{flex:none;width:unset}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-0,.column.is-0-tablet{flex:none;width:0%}.column.is-offset-0,.column.is-offset-0-tablet{margin-left:0%}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333337%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333337%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66666674%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66666674%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333337%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333337%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66666674%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66666674%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333337%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333337%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66666674%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66666674%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333337%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333337%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66666674%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66666674%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1055px){.column.is-narrow-touch{flex:none;width:unset}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-0-touch{flex:none;width:0%}.column.is-offset-0-touch{margin-left:0%}.column.is-1-touch{flex:none;width:8.33333337%}.column.is-offset-1-touch{margin-left:8.33333337%}.column.is-2-touch{flex:none;width:16.66666674%}.column.is-offset-2-touch{margin-left:16.66666674%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333337%}.column.is-offset-4-touch{margin-left:33.33333337%}.column.is-5-touch{flex:none;width:41.66666674%}.column.is-offset-5-touch{margin-left:41.66666674%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333337%}.column.is-offset-7-touch{margin-left:58.33333337%}.column.is-8-touch{flex:none;width:66.66666674%}.column.is-offset-8-touch{margin-left:66.66666674%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333337%}.column.is-offset-10-touch{margin-left:83.33333337%}.column.is-11-touch{flex:none;width:91.66666674%}.column.is-offset-11-touch{margin-left:91.66666674%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1056px){.column.is-narrow-desktop{flex:none;width:unset}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-0-desktop{flex:none;width:0%}.column.is-offset-0-desktop{margin-left:0%}.column.is-1-desktop{flex:none;width:8.33333337%}.column.is-offset-1-desktop{margin-left:8.33333337%}.column.is-2-desktop{flex:none;width:16.66666674%}.column.is-offset-2-desktop{margin-left:16.66666674%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333337%}.column.is-offset-4-desktop{margin-left:33.33333337%}.column.is-5-desktop{flex:none;width:41.66666674%}.column.is-offset-5-desktop{margin-left:41.66666674%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333337%}.column.is-offset-7-desktop{margin-left:58.33333337%}.column.is-8-desktop{flex:none;width:66.66666674%}.column.is-offset-8-desktop{margin-left:66.66666674%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333337%}.column.is-offset-10-desktop{margin-left:83.33333337%}.column.is-11-desktop{flex:none;width:91.66666674%}.column.is-offset-11-desktop{margin-left:91.66666674%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1216px){.column.is-narrow-widescreen{flex:none;width:unset}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-0-widescreen{flex:none;width:0%}.column.is-offset-0-widescreen{margin-left:0%}.column.is-1-widescreen{flex:none;width:8.33333337%}.column.is-offset-1-widescreen{margin-left:8.33333337%}.column.is-2-widescreen{flex:none;width:16.66666674%}.column.is-offset-2-widescreen{margin-left:16.66666674%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333337%}.column.is-offset-4-widescreen{margin-left:33.33333337%}.column.is-5-widescreen{flex:none;width:41.66666674%}.column.is-offset-5-widescreen{margin-left:41.66666674%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333337%}.column.is-offset-7-widescreen{margin-left:58.33333337%}.column.is-8-widescreen{flex:none;width:66.66666674%}.column.is-offset-8-widescreen{margin-left:66.66666674%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333337%}.column.is-offset-10-widescreen{margin-left:83.33333337%}.column.is-11-widescreen{flex:none;width:91.66666674%}.column.is-offset-11-widescreen{margin-left:91.66666674%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1408px){.column.is-narrow-fullhd{flex:none;width:unset}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-0-fullhd{flex:none;width:0%}.column.is-offset-0-fullhd{margin-left:0%}.column.is-1-fullhd{flex:none;width:8.33333337%}.column.is-offset-1-fullhd{margin-left:8.33333337%}.column.is-2-fullhd{flex:none;width:16.66666674%}.column.is-offset-2-fullhd{margin-left:16.66666674%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333337%}.column.is-offset-4-fullhd{margin-left:33.33333337%}.column.is-5-fullhd{flex:none;width:41.66666674%}.column.is-offset-5-fullhd{margin-left:41.66666674%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333337%}.column.is-offset-7-fullhd{margin-left:58.33333337%}.column.is-8-fullhd{flex:none;width:66.66666674%}.column.is-offset-8-fullhd{margin-left:66.66666674%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333337%}.column.is-offset-10-fullhd{margin-left:83.33333337%}.column.is-11-fullhd{flex:none;width:91.66666674%}.column.is-offset-11-fullhd{margin-left:91.66666674%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0 !important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width: 769px),print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1056px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable>.column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){.columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-0-fullhd{--columnGap: 0rem}}.columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){.columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-1-fullhd{--columnGap: .25rem}}.columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){.columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-2-fullhd{--columnGap: .5rem}}.columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){.columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-3-fullhd{--columnGap: .75rem}}.columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){.columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-4-fullhd{--columnGap: 1rem}}.columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){.columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}.columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){.columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}.columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){.columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}.columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){.columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px),print{.columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1055px){.columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1055px){.columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1056px){.columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1056px) and (max-width: 1215px){.columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1216px){.columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1216px) and (max-width: 1407px){.columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1408px){.columns.is-variable.is-8-fullhd{--columnGap: 2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}.tile.is-ancestor{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.tile.is-ancestor:last-child{margin-bottom:-.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:.75rem}.tile.is-child{margin:0 !important}.tile.is-parent{padding:.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px),print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333337%}.tile.is-2{flex:none;width:16.66666674%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333337%}.tile.is-5{flex:none;width:41.66666674%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333337%}.tile.is-8{flex:none;width:66.66666674%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333337%}.tile.is-11{flex:none;width:91.66666674%}.tile.is-12{flex:none;width:100%}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:none}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,0.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1055px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}.hero.is-white a.navbar-item:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white .navbar-link:hover,.hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{color:#fff !important;opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e8e3e4 0%, #fff 71%, #fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,0.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-black a.navbar-item:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black .navbar-link:hover,.hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:0.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{color:#0a0a0a !important;opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:rgba(0,0,0,0.7)}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-light strong{color:inherit}.hero.is-light .title{color:rgba(0,0,0,0.7)}.hero.is-light .subtitle{color:rgba(0,0,0,0.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-light a.navbar-item:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light .navbar-link:hover,.hero.is-light .navbar-link.is-active{background-color:#e8e8e8;color:rgba(0,0,0,0.7)}.hero.is-light .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{color:#f5f5f5 !important;opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}}.hero.is-dark,.content kbd.hero{background-color:#363636;color:#fff}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.content kbd.hero a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-dark strong,.content kbd.hero strong{color:inherit}.hero.is-dark .title,.content kbd.hero .title{color:#fff}.hero.is-dark .subtitle,.content kbd.hero .subtitle{color:rgba(255,255,255,0.9)}.hero.is-dark .subtitle a:not(.button),.content kbd.hero .subtitle a:not(.button),.hero.is-dark .subtitle strong,.content kbd.hero .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-dark .navbar-menu,.content kbd.hero .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.content kbd.hero .navbar-item,.hero.is-dark .navbar-link,.content kbd.hero .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-dark a.navbar-item:hover,.content kbd.hero a.navbar-item:hover,.hero.is-dark a.navbar-item.is-active,.content kbd.hero a.navbar-item.is-active,.hero.is-dark .navbar-link:hover,.content kbd.hero .navbar-link:hover,.hero.is-dark .navbar-link.is-active,.content kbd.hero .navbar-link.is-active{background-color:#292929;color:#fff}.hero.is-dark .tabs a,.content kbd.hero .tabs a{color:#fff;opacity:0.9}.hero.is-dark .tabs a:hover,.content kbd.hero .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a,.content kbd.hero .tabs li.is-active a{color:#363636 !important;opacity:1}.hero.is-dark .tabs.is-boxed a,.content kbd.hero .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a,.content kbd.hero .tabs.is-toggle a{color:#fff}.hero.is-dark .tabs.is-boxed a:hover,.content kbd.hero .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover,.content kbd.hero .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.content kbd.hero .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.content kbd.hero .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#363636}.hero.is-dark.is-bold,.content kbd.hero.is-bold{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}@media screen and (max-width: 768px){.hero.is-dark.is-bold .navbar-menu,.content kbd.hero.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}}.hero.is-primary,.docstring>section>a.hero.docs-sourcelink{background-color:#4eb5de;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.docstring>section>a.hero.docs-sourcelink a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-primary strong,.docstring>section>a.hero.docs-sourcelink strong{color:inherit}.hero.is-primary .title,.docstring>section>a.hero.docs-sourcelink .title{color:#fff}.hero.is-primary .subtitle,.docstring>section>a.hero.docs-sourcelink .subtitle{color:rgba(255,255,255,0.9)}.hero.is-primary .subtitle a:not(.button),.docstring>section>a.hero.docs-sourcelink .subtitle a:not(.button),.hero.is-primary .subtitle strong,.docstring>section>a.hero.docs-sourcelink .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-primary .navbar-menu,.docstring>section>a.hero.docs-sourcelink .navbar-menu{background-color:#4eb5de}}.hero.is-primary .navbar-item,.docstring>section>a.hero.docs-sourcelink .navbar-item,.hero.is-primary .navbar-link,.docstring>section>a.hero.docs-sourcelink .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-primary a.navbar-item:hover,.docstring>section>a.hero.docs-sourcelink a.navbar-item:hover,.hero.is-primary a.navbar-item.is-active,.docstring>section>a.hero.docs-sourcelink a.navbar-item.is-active,.hero.is-primary .navbar-link:hover,.docstring>section>a.hero.docs-sourcelink .navbar-link:hover,.hero.is-primary .navbar-link.is-active,.docstring>section>a.hero.docs-sourcelink .navbar-link.is-active{background-color:#39acda;color:#fff}.hero.is-primary .tabs a,.docstring>section>a.hero.docs-sourcelink .tabs a{color:#fff;opacity:0.9}.hero.is-primary .tabs a:hover,.docstring>section>a.hero.docs-sourcelink .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs li.is-active a{color:#4eb5de !important;opacity:1}.hero.is-primary .tabs.is-boxed a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.docstring>section>a.hero.docs-sourcelink .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#4eb5de}.hero.is-primary.is-bold,.docstring>section>a.hero.is-bold.docs-sourcelink{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}@media screen and (max-width: 768px){.hero.is-primary.is-bold .navbar-menu,.docstring>section>a.hero.is-bold.docs-sourcelink .navbar-menu{background-image:linear-gradient(141deg, #1bc7de 0%, #4eb5de 71%, #5fa9e7 100%)}}.hero.is-link{background-color:#2e63b8;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,0.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-link .navbar-menu{background-color:#2e63b8}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-link a.navbar-item:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link .navbar-link:hover,.hero.is-link .navbar-link.is-active{background-color:#2958a4;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:0.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{color:#2e63b8 !important;opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#2e63b8}.hero.is-link.is-bold{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}@media screen and (max-width: 768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1b6098 0%, #2e63b8 71%, #2d51d2 100%)}}.hero.is-info{background-color:#209cee;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,0.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-info .navbar-menu{background-color:#209cee}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-info a.navbar-item:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info .navbar-link:hover,.hero.is-info .navbar-link.is-active{background-color:#1190e3;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:0.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{color:#209cee !important;opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#209cee}.hero.is-info.is-bold{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}@media screen and (max-width: 768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #05a6d6 0%, #209cee 71%, #3287f5 100%)}}.hero.is-success{background-color:#22c35b;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,0.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-success .navbar-menu{background-color:#22c35b}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-success a.navbar-item:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success .navbar-link:hover,.hero.is-success .navbar-link.is-active{background-color:#1ead51;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:0.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{color:#22c35b !important;opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#22c35b}.hero.is-success.is-bold{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}@media screen and (max-width: 768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #12a02c 0%, #22c35b 71%, #1fdf83 100%)}}.hero.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,0.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,0.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1055px){.hero.is-warning .navbar-menu{background-color:#ffdd57}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-warning a.navbar-item:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning .navbar-link.is-active{background-color:#ffd83e;color:rgba(0,0,0,0.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{color:#ffdd57 !important;opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ffdd57}.hero.is-warning.is-bold{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}@media screen and (max-width: 768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #ffae24 0%, #ffdd57 71%, #fffa71 100%)}}.hero.is-danger{background-color:#da0b00;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1055px){.hero.is-danger .navbar-menu{background-color:#da0b00}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-danger a.navbar-item:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger .navbar-link.is-active{background-color:#c10a00;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:0.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{color:#da0b00 !important;opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#da0b00}.hero.is-danger.is-bold{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}@media screen and (max-width: 768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #a70013 0%, #da0b00 71%, #f43500 100%)}}.hero.is-small .hero-body,#documenter .docs-sidebar form.docs-search>input.hero .hero-body{padding:1.5rem}@media screen and (min-width: 769px),print{.hero.is-medium .hero-body{padding:9rem 4.5rem}}@media screen and (min-width: 769px),print{.hero.is-large .hero-body{padding:18rem 6rem}}.hero.is-halfheight .hero-body,.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}.hero.is-halfheight .hero-body>.container,.hero.is-fullheight .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.container{flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}.hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px),print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-head,.hero-foot{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}@media screen and (min-width: 769px),print{.hero-body{padding:3rem 3rem}}.section{padding:3rem 1.5rem}@media screen and (min-width: 1056px){.section{padding:3rem 3rem}.section.is-medium{padding:9rem 4.5rem}.section.is-large{padding:18rem 6rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem}h1 .docs-heading-anchor,h1 .docs-heading-anchor:hover,h1 .docs-heading-anchor:visited,h2 .docs-heading-anchor,h2 .docs-heading-anchor:hover,h2 .docs-heading-anchor:visited,h3 .docs-heading-anchor,h3 .docs-heading-anchor:hover,h3 .docs-heading-anchor:visited,h4 .docs-heading-anchor,h4 .docs-heading-anchor:hover,h4 .docs-heading-anchor:visited,h5 .docs-heading-anchor,h5 .docs-heading-anchor:hover,h5 .docs-heading-anchor:visited,h6 .docs-heading-anchor,h6 .docs-heading-anchor:hover,h6 .docs-heading-anchor:visited{color:#222}h1 .docs-heading-anchor-permalink,h2 .docs-heading-anchor-permalink,h3 .docs-heading-anchor-permalink,h4 .docs-heading-anchor-permalink,h5 .docs-heading-anchor-permalink,h6 .docs-heading-anchor-permalink{visibility:hidden;vertical-align:middle;margin-left:0.5em;font-size:0.7rem}h1 .docs-heading-anchor-permalink::before,h2 .docs-heading-anchor-permalink::before,h3 .docs-heading-anchor-permalink::before,h4 .docs-heading-anchor-permalink::before,h5 .docs-heading-anchor-permalink::before,h6 .docs-heading-anchor-permalink::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f0c1"}h1:hover .docs-heading-anchor-permalink,h2:hover .docs-heading-anchor-permalink,h3:hover .docs-heading-anchor-permalink,h4:hover .docs-heading-anchor-permalink,h5:hover .docs-heading-anchor-permalink,h6:hover .docs-heading-anchor-permalink{visibility:visible}.docs-dark-only{display:none !important}pre{position:relative;overflow:hidden}pre code,pre code.hljs{padding:0 .75rem !important;overflow:auto;display:block}pre code:first-of-type,pre code.hljs:first-of-type{padding-top:0.5rem !important}pre code:last-of-type,pre code.hljs:last-of-type{padding-bottom:0.5rem !important}pre .copy-button{opacity:0.2;transition:opacity 0.2s;position:absolute;right:0em;top:0em;padding:0.5em;width:2.5em;height:2.5em;background:transparent;border:none;font-family:"Font Awesome 6 Free";color:#222;cursor:pointer;text-align:center}pre .copy-button:focus,pre .copy-button:hover{opacity:1;background:rgba(34,34,34,0.1);color:#2e63b8}pre .copy-button.success{color:#259a12;opacity:1}pre .copy-button.error{color:#cb3c33;opacity:1}pre:hover .copy-button{opacity:1}.admonition{background-color:#b5b5b5;border-style:solid;border-width:1px;border-color:#363636;border-radius:4px;font-size:1rem}.admonition strong{color:currentColor}.admonition.is-small,#documenter .docs-sidebar form.docs-search>input.admonition{font-size:.75rem}.admonition.is-medium{font-size:1.25rem}.admonition.is-large{font-size:1.5rem}.admonition.is-default{background-color:#b5b5b5;border-color:#363636}.admonition.is-default>.admonition-header{background-color:#363636;color:#fff}.admonition.is-default>.admonition-body{color:#fff}.admonition.is-info{background-color:#def0fc;border-color:#209cee}.admonition.is-info>.admonition-header{background-color:#209cee;color:#fff}.admonition.is-info>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-success{background-color:#bdf4d1;border-color:#22c35b}.admonition.is-success>.admonition-header{background-color:#22c35b;color:#fff}.admonition.is-success>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-warning{background-color:#fff3c5;border-color:#ffdd57}.admonition.is-warning>.admonition-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.admonition.is-warning>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-danger{background-color:#ffaba7;border-color:#da0b00}.admonition.is-danger>.admonition-header{background-color:#da0b00;color:#fff}.admonition.is-danger>.admonition-body{color:rgba(0,0,0,0.7)}.admonition.is-compat{background-color:#bdeff5;border-color:#1db5c9}.admonition.is-compat>.admonition-header{background-color:#1db5c9;color:#fff}.admonition.is-compat>.admonition-body{color:rgba(0,0,0,0.7)}.admonition-header{color:#fff;background-color:#363636;align-items:center;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.5rem .75rem;position:relative}.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;margin-right:.75rem;content:"\f06a"}details.admonition.is-details>.admonition-header{list-style:none}details.admonition.is-details>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f055"}details.admonition.is-details[open]>.admonition-header:before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f056"}.admonition-body{color:#222;padding:0.5rem .75rem}.admonition-body pre{background-color:#f5f5f5}.admonition-body code{background-color:rgba(0,0,0,0.05)}.docstring{margin-bottom:1em;background-color:rgba(0,0,0,0);border:1px solid #dbdbdb;box-shadow:2px 2px 3px rgba(10,10,10,0.1);max-width:100%}.docstring>header{cursor:pointer;display:flex;flex-grow:1;align-items:stretch;padding:0.5rem .75rem;background-color:#f5f5f5;box-shadow:0 0.125em 0.25em rgba(10,10,10,0.1);box-shadow:none;border-bottom:1px solid #dbdbdb;overflow:auto}.docstring>header code{background-color:transparent}.docstring>header .docstring-article-toggle-button{min-width:1.1rem;padding:0.2rem 0.2rem 0.2rem 0}.docstring>header .docstring-binding{margin-right:0.3em}.docstring>header .docstring-category{margin-left:0.3em}.docstring>section{position:relative;padding:.75rem .75rem;border-bottom:1px solid #dbdbdb}.docstring>section:last-child{border-bottom:none}.docstring>section>a.docs-sourcelink{transition:opacity 0.3s;opacity:0;position:absolute;right:.375rem;bottom:.375rem}.docstring>section>a.docs-sourcelink:focus{opacity:1 !important}.docstring:hover>section>a.docs-sourcelink{opacity:0.2}.docstring:focus-within>section>a.docs-sourcelink{opacity:0.2}.docstring>section:hover a.docs-sourcelink{opacity:1}.documenter-example-output{background-color:#fff}.outdated-warning-overlay{position:fixed;top:0;left:0;right:0;box-shadow:0 0 10px rgba(0,0,0,0.3);z-index:999;background-color:#ffaba7;color:rgba(0,0,0,0.7);border-bottom:3px solid #da0b00;padding:10px 35px;text-align:center;font-size:15px}.outdated-warning-overlay .outdated-warning-closer{position:absolute;top:calc(50% - 10px);right:18px;cursor:pointer;width:12px}.outdated-warning-overlay a{color:#2e63b8}.outdated-warning-overlay a:hover{color:#363636}.content pre{border:1px solid #dbdbdb}.content code{font-weight:inherit}.content a code{color:#2e63b8}.content a:hover code{color:#363636}.content h1 code,.content h2 code,.content h3 code,.content h4 code,.content h5 code,.content h6 code{color:#222}.content table{display:block;width:initial;max-width:100%;overflow-x:auto}.content blockquote>ul:first-child,.content blockquote>ol:first-child,.content .admonition-body>ul:first-child,.content .admonition-body>ol:first-child{margin-top:0}pre,code{font-variant-ligatures:no-contextual}.breadcrumb a.is-disabled{cursor:default;pointer-events:none}.breadcrumb a.is-disabled,.breadcrumb a.is-disabled:hover{color:#222}.hljs{background:initial !important}.katex .katex-mathml{top:0;right:0}.katex-display,mjx-container,.MathJax_Display{margin:0.5em 0 !important}html{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto}li.no-marker{list-style:none}#documenter .docs-main>article{overflow-wrap:break-word}#documenter .docs-main>article .math-container{overflow-x:auto;overflow-y:hidden}@media screen and (min-width: 1056px){#documenter .docs-main{max-width:52rem;margin-left:20rem;padding-right:1rem}}@media screen and (max-width: 1055px){#documenter .docs-main{width:100%}#documenter .docs-main>article{max-width:52rem;margin-left:auto;margin-right:auto;margin-bottom:1rem;padding:0 1rem}#documenter .docs-main>header,#documenter .docs-main>nav{max-width:100%;width:100%;margin:0}}#documenter .docs-main header.docs-navbar{background-color:#fff;border-bottom:1px solid #dbdbdb;z-index:2;min-height:4rem;margin-bottom:1rem;display:flex}#documenter .docs-main header.docs-navbar .breadcrumb{flex-grow:1;overflow-x:hidden}#documenter .docs-main header.docs-navbar .docs-sidebar-button{display:block;font-size:1.5rem;padding-bottom:0.1rem;margin-right:1rem}#documenter .docs-main header.docs-navbar .docs-right{display:flex;white-space:nowrap;gap:1rem;align-items:center}#documenter .docs-main header.docs-navbar .docs-right .docs-icon,#documenter .docs-main header.docs-navbar .docs-right .docs-label{display:inline-block}#documenter .docs-main header.docs-navbar .docs-right .docs-label{padding:0;margin-left:0.3em}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar .docs-right .docs-navbar-link{margin-left:0.4rem;margin-right:0.4rem}}#documenter .docs-main header.docs-navbar>*{margin:auto 0}@media screen and (max-width: 1055px){#documenter .docs-main header.docs-navbar{position:sticky;top:0;padding:0 1rem;transition-property:top, box-shadow;-webkit-transition-property:top, box-shadow;transition-duration:0.3s;-webkit-transition-duration:0.3s}#documenter .docs-main header.docs-navbar.headroom--not-top{box-shadow:.2rem 0rem .4rem #bbb;transition-duration:0.7s;-webkit-transition-duration:0.7s}#documenter .docs-main header.docs-navbar.headroom--unpinned.headroom--not-top.headroom--not-bottom{top:-4.5rem;transition-duration:0.7s;-webkit-transition-duration:0.7s}}#documenter .docs-main section.footnotes{border-top:1px solid #dbdbdb}#documenter .docs-main section.footnotes li .tag:first-child,#documenter .docs-main section.footnotes li .docstring>section>a.docs-sourcelink:first-child,#documenter .docs-main section.footnotes li .content kbd:first-child,.content #documenter .docs-main section.footnotes li kbd:first-child{margin-right:1em;margin-bottom:0.4em}#documenter .docs-main .docs-footer{display:flex;flex-wrap:wrap;margin-left:0;margin-right:0;border-top:1px solid #dbdbdb;padding-top:1rem;padding-bottom:1rem}@media screen and (max-width: 1055px){#documenter .docs-main .docs-footer{padding-left:1rem;padding-right:1rem}}#documenter .docs-main .docs-footer .docs-footer-nextpage,#documenter .docs-main .docs-footer .docs-footer-prevpage{flex-grow:1}#documenter .docs-main .docs-footer .docs-footer-nextpage{text-align:right}#documenter .docs-main .docs-footer .flexbox-break{flex-basis:100%;height:0}#documenter .docs-main .docs-footer .footer-message{font-size:0.8em;margin:0.5em auto 0 auto;text-align:center}#documenter .docs-sidebar{display:flex;flex-direction:column;color:#0a0a0a;background-color:#f5f5f5;border-right:1px solid #dbdbdb;padding:0;flex:0 0 18rem;z-index:5;font-size:1rem;position:fixed;left:-18rem;width:18rem;height:100%;transition:left 0.3s}#documenter .docs-sidebar.visible{left:0;box-shadow:.4rem 0rem .8rem #bbb}@media screen and (min-width: 1056px){#documenter .docs-sidebar.visible{box-shadow:none}}@media screen and (min-width: 1056px){#documenter .docs-sidebar{left:0;top:0}}#documenter .docs-sidebar .docs-logo{margin-top:1rem;padding:0 1rem}#documenter .docs-sidebar .docs-logo>img{max-height:6rem;margin:auto}#documenter .docs-sidebar .docs-package-name{flex-shrink:0;font-size:1.5rem;font-weight:700;text-align:center;white-space:nowrap;overflow:hidden;padding:0.5rem 0}#documenter .docs-sidebar .docs-package-name .docs-autofit{max-width:16.2rem}#documenter .docs-sidebar .docs-package-name a,#documenter .docs-sidebar .docs-package-name a:hover{color:#0a0a0a}#documenter .docs-sidebar .docs-version-selector{border-top:1px solid #dbdbdb;display:none;padding:0.5rem}#documenter .docs-sidebar .docs-version-selector.visible{display:flex}#documenter .docs-sidebar ul.docs-menu{flex-grow:1;user-select:none;border-top:1px solid #dbdbdb;padding-bottom:1.5rem}#documenter .docs-sidebar ul.docs-menu>li>.tocitem{font-weight:bold}#documenter .docs-sidebar ul.docs-menu>li li{font-size:.95rem;margin-left:1em;border-left:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu input.collapse-toggle{display:none}#documenter .docs-sidebar ul.docs-menu ul.collapsed{display:none}#documenter .docs-sidebar ul.docs-menu input:checked~ul.collapsed{display:block}#documenter .docs-sidebar ul.docs-menu label.tocitem{display:flex}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-label{flex-grow:2}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron{display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1;font-size:.75rem;margin-left:1rem;margin-top:auto;margin-bottom:auto}#documenter .docs-sidebar ul.docs-menu label.tocitem .docs-chevron::before{font-family:"Font Awesome 6 Free";font-weight:900;content:"\f054"}#documenter .docs-sidebar ul.docs-menu input:checked~label.tocitem .docs-chevron::before{content:"\f078"}#documenter .docs-sidebar ul.docs-menu .tocitem{display:block;padding:0.5rem 0.5rem}#documenter .docs-sidebar ul.docs-menu .tocitem,#documenter .docs-sidebar ul.docs-menu .tocitem:hover{color:#0a0a0a;background:#f5f5f5}#documenter .docs-sidebar ul.docs-menu a.tocitem:hover,#documenter .docs-sidebar ul.docs-menu label.tocitem:hover{color:#0a0a0a;background-color:#ebebeb}#documenter .docs-sidebar ul.docs-menu li.is-active{border-top:1px solid #dbdbdb;border-bottom:1px solid #dbdbdb;background-color:#fff}#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem,#documenter .docs-sidebar ul.docs-menu li.is-active .tocitem:hover{background-color:#fff;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu li.is-active ul.internal .tocitem:hover{background-color:#ebebeb;color:#0a0a0a}#documenter .docs-sidebar ul.docs-menu>li.is-active:first-child{border-top:none}#documenter .docs-sidebar ul.docs-menu ul.internal{margin:0 0.5rem 0.5rem;border-top:1px solid #dbdbdb}#documenter .docs-sidebar ul.docs-menu ul.internal li{font-size:.85rem;border-left:none;margin-left:0;margin-top:0.5rem}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem{width:100%;padding:0}#documenter .docs-sidebar ul.docs-menu ul.internal .tocitem::before{content:"⚬";margin-right:0.4em}#documenter .docs-sidebar form.docs-search{margin:auto;margin-top:0.5rem;margin-bottom:0.5rem}#documenter .docs-sidebar form.docs-search>input{width:14.4rem}#documenter .docs-sidebar #documenter-search-query{color:#707070;width:14.4rem;box-shadow:inset 0 1px 2px rgba(10,10,10,0.1)}@media screen and (min-width: 1056px){#documenter .docs-sidebar ul.docs-menu{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar ul.docs-menu::-webkit-scrollbar-thumb:hover{background:#ccc}}@media screen and (max-width: 1055px){#documenter .docs-sidebar{overflow-y:auto;-webkit-overflow-scroll:touch}#documenter .docs-sidebar::-webkit-scrollbar{width:.3rem;background:none}#documenter .docs-sidebar::-webkit-scrollbar-thumb{border-radius:5px 0px 0px 5px;background:#e0e0e0}#documenter .docs-sidebar::-webkit-scrollbar-thumb:hover{background:#ccc}}kbd.search-modal-key-hints{border-radius:0.25rem;border:1px solid rgba(0,0,0,0.6);box-shadow:0 2px 0 1px rgba(0,0,0,0.6);cursor:default;font-size:0.9rem;line-height:1.5;min-width:0.75rem;text-align:center;padding:0.1rem 0.3rem;position:relative;top:-1px}.search-min-width-50{min-width:50%}.search-min-height-100{min-height:100%}.search-modal-card-body{max-height:calc(100vh - 15rem)}.search-result-link{border-radius:0.7em;transition:all 300ms}.search-result-link:hover,.search-result-link:focus{background-color:rgba(0,128,128,0.1)}.search-result-link .property-search-result-badge,.search-result-link .search-filter{transition:all 300ms}.property-search-result-badge,.search-filter{padding:0.15em 0.5em;font-size:0.8em;font-style:italic;text-transform:none !important;line-height:1.5;color:#f5f5f5;background-color:rgba(51,65,85,0.501961);border-radius:0.6rem}.search-result-link:hover .property-search-result-badge,.search-result-link:hover .search-filter,.search-result-link:focus .property-search-result-badge,.search-result-link:focus .search-filter{color:#f1f5f9;background-color:#333}.search-filter{color:#333;background-color:#f5f5f5;transition:all 300ms}.search-filter:hover,.search-filter:focus{color:#333}.search-filter-selected{color:#f5f5f5;background-color:rgba(139,0,139,0.5)}.search-filter-selected:hover,.search-filter-selected:focus{color:#f5f5f5}.search-result-highlight{background-color:#ffdd57;color:black}.search-divider{border-bottom:1px solid #dbdbdb}.search-result-title{width:85%;color:#333}.search-result-code-title{font-size:0.875rem;font-family:"JuliaMono","SFMono-Regular","Menlo","Consolas","Liberation Mono","DejaVu Sans Mono",monospace}#search-modal .modal-card-body::-webkit-scrollbar,#search-modal .filter-tabs::-webkit-scrollbar{height:10px;width:10px;background-color:transparent}#search-modal .modal-card-body::-webkit-scrollbar-thumb,#search-modal .filter-tabs::-webkit-scrollbar-thumb{background-color:gray;border-radius:1rem}#search-modal .modal-card-body::-webkit-scrollbar-track,#search-modal .filter-tabs::-webkit-scrollbar-track{-webkit-box-shadow:inset 0 0 6px rgba(0,0,0,0.6);background-color:transparent}.w-100{width:100%}.gap-2{gap:0.5rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.ansi span.sgr1{font-weight:bolder}.ansi span.sgr2{font-weight:lighter}.ansi span.sgr3{font-style:italic}.ansi span.sgr4{text-decoration:underline}.ansi span.sgr7{color:#fff;background-color:#222}.ansi span.sgr8{color:transparent}.ansi span.sgr8 span{color:transparent}.ansi span.sgr9{text-decoration:line-through}.ansi span.sgr30{color:#242424}.ansi span.sgr31{color:#a7201f}.ansi span.sgr32{color:#066f00}.ansi span.sgr33{color:#856b00}.ansi span.sgr34{color:#2149b0}.ansi span.sgr35{color:#7d4498}.ansi span.sgr36{color:#007989}.ansi span.sgr37{color:gray}.ansi span.sgr40{background-color:#242424}.ansi span.sgr41{background-color:#a7201f}.ansi span.sgr42{background-color:#066f00}.ansi span.sgr43{background-color:#856b00}.ansi span.sgr44{background-color:#2149b0}.ansi span.sgr45{background-color:#7d4498}.ansi span.sgr46{background-color:#007989}.ansi span.sgr47{background-color:gray}.ansi span.sgr90{color:#616161}.ansi span.sgr91{color:#cb3c33}.ansi span.sgr92{color:#0e8300}.ansi span.sgr93{color:#a98800}.ansi span.sgr94{color:#3c5dcd}.ansi span.sgr95{color:#9256af}.ansi span.sgr96{color:#008fa3}.ansi span.sgr97{color:#f5f5f5}.ansi span.sgr100{background-color:#616161}.ansi span.sgr101{background-color:#cb3c33}.ansi span.sgr102{background-color:#0e8300}.ansi span.sgr103{background-color:#a98800}.ansi span.sgr104{background-color:#3c5dcd}.ansi span.sgr105{background-color:#9256af}.ansi span.sgr106{background-color:#008fa3}.ansi span.sgr107{background-color:#f5f5f5}code.language-julia-repl>span.hljs-meta{color:#066f00;font-weight:bolder}/*! + Theme: Default + Description: Original highlight.js style + Author: (c) Ivan Sagalaev + Maintainer: @highlightjs/core-team + Website: https://highlightjs.org/ + License: see project LICENSE + Touched: 2021 +*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#F3F3F3;color:#444}.hljs-comment{color:#697070}.hljs-tag,.hljs-punctuation{color:#444a}.hljs-tag .hljs-name,.hljs-tag .hljs-attr{color:#444}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta .hljs-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-operator,.hljs-selector-pseudo{color:#ab5656}.hljs-literal{color:#695}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}.gap-4{gap:1rem} diff --git a/v1.5.0/assets/themeswap.js b/v1.5.0/assets/themeswap.js new file mode 100644 index 00000000000..9f5eebe6aa2 --- /dev/null +++ b/v1.5.0/assets/themeswap.js @@ -0,0 +1,84 @@ +// Small function to quickly swap out themes. Gets put into the tag.. +function set_theme_from_local_storage() { + // Initialize the theme to null, which means default + var theme = null; + // If the browser supports the localstorage and is not disabled then try to get the + // documenter theme + if (window.localStorage != null) { + // Get the user-picked theme from localStorage. May be `null`, which means the default + // theme. + theme = window.localStorage.getItem("documenter-theme"); + } + // Check if the users preference is for dark color scheme + var darkPreference = + window.matchMedia("(prefers-color-scheme: dark)").matches === true; + // Initialize a few variables for the loop: + // + // - active: will contain the index of the theme that should be active. Note that there + // is no guarantee that localStorage contains sane values. If `active` stays `null` + // we either could not find the theme or it is the default (primary) theme anyway. + // Either way, we then need to stick to the primary theme. + // + // - disabled: style sheets that should be disabled (i.e. all the theme style sheets + // that are not the currently active theme) + var active = null; + var disabled = []; + var primaryLightTheme = null; + var primaryDarkTheme = null; + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + // The tag of each style sheet is expected to have a data-theme-name attribute + // which must contain the name of the theme. The names in localStorage much match this. + var themename = ss.ownerNode.getAttribute("data-theme-name"); + // attribute not set => non-theme stylesheet => ignore + if (themename === null) continue; + // To distinguish the default (primary) theme, it needs to have the data-theme-primary + // attribute set. + if (ss.ownerNode.getAttribute("data-theme-primary") !== null) { + primaryLightTheme = themename; + } + // Check if the theme is primary dark theme so that we could store its name in darkTheme + if (ss.ownerNode.getAttribute("data-theme-primary-dark") !== null) { + primaryDarkTheme = themename; + } + // If we find a matching theme (and it's not the default), we'll set active to non-null + if (themename === theme) active = i; + // Store the style sheets of inactive themes so that we could disable them + if (themename !== theme) disabled.push(ss); + } + var activeTheme = null; + if (active !== null) { + // If we did find an active theme, we'll (1) add the theme--$(theme) class to + document.getElementsByTagName("html")[0].className = "theme--" + theme; + activeTheme = theme; + } else { + // If we did _not_ find an active theme, then we need to fall back to the primary theme + // which can either be dark or light, depending on the user's OS preference. + var activeTheme = darkPreference ? primaryDarkTheme : primaryLightTheme; + // In case it somehow happens that the relevant primary theme was not found in the + // preceding loop, we abort without doing anything. + if (activeTheme === null) { + console.error("Unable to determine primary theme."); + return; + } + // When switching to the primary light theme, then we must not have a class name + // for the tag. That's only for non-primary or the primary dark theme. + if (darkPreference) { + document.getElementsByTagName("html")[0].className = + "theme--" + activeTheme; + } else { + document.getElementsByTagName("html")[0].className = ""; + } + } + for (var i = 0; i < document.styleSheets.length; i++) { + var ss = document.styleSheets[i]; + // The tag of each style sheet is expected to have a data-theme-name attribute + // which must contain the name of the theme. The names in localStorage much match this. + var themename = ss.ownerNode.getAttribute("data-theme-name"); + // attribute not set => non-theme stylesheet => ignore + if (themename === null) continue; + // we'll disable all the stylesheets, except for the active one + ss.disabled = !(themename == activeTheme); + } +} +set_theme_from_local_storage(); diff --git a/v1.5.0/assets/warner.js b/v1.5.0/assets/warner.js new file mode 100644 index 00000000000..3f6f5d0083a --- /dev/null +++ b/v1.5.0/assets/warner.js @@ -0,0 +1,52 @@ +function maybeAddWarning() { + // DOCUMENTER_NEWEST is defined in versions.js, DOCUMENTER_CURRENT_VERSION and DOCUMENTER_STABLE + // in siteinfo.js. + // If either of these are undefined something went horribly wrong, so we abort. + if ( + window.DOCUMENTER_NEWEST === undefined || + window.DOCUMENTER_CURRENT_VERSION === undefined || + window.DOCUMENTER_STABLE === undefined + ) { + return; + } + + // Current version is not a version number, so we can't tell if it's the newest version. Abort. + if (!/v(\d+\.)*\d+/.test(window.DOCUMENTER_CURRENT_VERSION)) { + return; + } + + // Current version is newest version, so no need to add a warning. + if (window.DOCUMENTER_NEWEST === window.DOCUMENTER_CURRENT_VERSION) { + return; + } + + // Add a noindex meta tag (unless one exists) so that search engines don't index this version of the docs. + if (document.body.querySelector('meta[name="robots"]') === null) { + const meta = document.createElement("meta"); + meta.name = "robots"; + meta.content = "noindex"; + + document.getElementsByTagName("head")[0].appendChild(meta); + } + + const div = document.createElement("div"); + div.classList.add("outdated-warning-overlay"); + const closer = document.createElement("button"); + closer.classList.add("outdated-warning-closer", "delete"); + closer.addEventListener("click", function () { + document.body.removeChild(div); + }); + const href = window.documenterBaseURL + "/../" + window.DOCUMENTER_STABLE; + div.innerHTML = + 'This documentation is not for the latest stable release, but for either the development version or an older release.
Click here to go to the documentation for the latest stable release.'; + div.appendChild(closer); + document.body.appendChild(div); +} + +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", maybeAddWarning); +} else { + maybeAddWarning(); +} diff --git a/v1.5.0/comparisons/cppfortran/index.html b/v1.5.0/comparisons/cppfortran/index.html new file mode 100644 index 00000000000..654cfc5a7f5 --- /dev/null +++ b/v1.5.0/comparisons/cppfortran/index.html @@ -0,0 +1,2 @@ + +Getting Started with Julia's SciML for the C++/Fortran User · Overview of Julia's SciML

Getting Started with Julia's SciML for the C++/Fortran User

You don't need help if you're a Fortran guru. I'm just kidding, you're not a Lisp developer. If you're coming from C++ or Fortran, you may be familiar with high-performance computing environments similar to SciML, such as PETSc, Trilinos, or Sundials. The following are some points to help the transition.

Why SciML? High-Level Workflow Reasons

If you're coming from “hardcore” C++/Fortran computing environments, some things to check out with Julia's SciML are:

  • Interactivity - use the interactive REPL to easily investigate numerical details.
  • Metaprogramming performance tools - tools like LoopVectorization.jl can be used to generate faster code than even some of the most hand-optimized C++/Fortran code. Current benchmarks show this SIMD-optimized Julia code outperforming OpenBLAS and MKL BLAS implementations in many performance regimes.
  • Symbolic modeling languages - writing models by hand can leave a lot of performance on the table. Using high-level modeling tools like ModelingToolkit can automate symbolic simplifications, which improve the stability and performance of numerical solvers. On complex models, even the best handwritten C++/Fortran code is orders of magnitude behind the code that symbolic tearing algorithms can achieve!
  • Composable Library Components - In C++/Fortran environments, every package feels like a silo. Arrays made for PETSc cannot easily be used in Trilinos, and converting Sundials NVector outputs to DataFrames for post-simulation data processing is a process itself. The Julia SciML environment embraces interoperability. Don't wait for SciML to do it: by using generic coding with JIT compilation, these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Wrappers to the Libraries You Know and Trust - Moving to SciML does not have to be a quick transition. SciML has extensive wrappers to many widely-used classical solver environments such as SUNDIALS and Hairer's classic Fortran ODE solvers (dopri5, dop853, etc.). Using these wrapped solvers is painless and can be swapped in for the Julia versions with one line of code. This gives you a way to incrementally adopt new features/methods while retaining the older pieces you know and trust.
  • Don't Start from Scratch - SciML builds on the extensive Base library of Julia, and thus grows and improves with every update to the language. With hundreds of monthly contributors to SciML and hundreds of monthly contributors to Julia, SciML is one of the most actively developed open-source scientific computing ecosystems out there!
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, Sundials/Hairer in purple/red represent C++/Fortrans most commonly used solvers:

Why SciML? Some Technical Details

Let's face the facts, in the open benchmarks the pure-Julia solvers tend to outperform the classic “best” C++ and Fortran solvers in almost every example (with a few notable exceptions). But why?

The answer is two-fold: Julia is as fast as C++/Fortran, and the algorithms are what matter.

Julia is as Fast as C++/Fortran

While Julia code looks high level like Python or MATLAB, its performance is on par with C++ and Fortran. At a technical level, when Julia code is type-stable, i.e. that the types that are returned from a function are deducible at compile-time from the types that go into a function, then Julia can optimize it as much as C++ or Fortran by automatically devirtualizing all dynamic behavior and compile-time optimizing the quasi-static code. This is not an empirical statement, it's a provable type-theoretic result. The resulting compiler used on the resulting quasi-static representation is LLVM, the same optimizing compiler used by clang and LFortran.

For more details on how Julia code is optimized and how to optimize your own Julia code, check out this chapter from the SciML Book.

SciML's Julia Algorithms Have Performance Advantages in Many Common Regimes

There are many ways which Julia's algorithms achieve performance advantages. Some facts to highlight include:

Let's Dig Deep Into One Case: Adjoints of ODEs for Solving Inverse Problems

To really highlight how JIT compilation and automatic differentiation integration can change algorithms, let's look at the problem of differentiating an ODE solver. As is derived and discussed in detail at a seminar with the American Statistical Association, there are many ways to implement well-known “adjoint” methods which are required for performance. Each has different stability and performance trade-offs, and Julia's SciML is the only system to systemically offer all of the trade-off options. In many cases, using analytical adjoints of a solver is not advised due to performance reasons, with the trade-off described in detail here. Likewise, even when analytical adjoints are used, it turns out that for general nonlinear equations there is a trick which uses automatic differentiation in the construction of the analytical adjoint to improve its performance. As demonstrated in this publication, this can lead to about 2-3 orders of magnitude performance improvements. These AD-enhanced adjoints are showcased as the seeding methods in this plot:

Unless one directly defines special “vjp” functions, this is how the Julia SciML methods achieve orders of magnitude performance advantages over CVODES's adjoints and PETSC's TS-adjoint.

Moral of the story, even there are many reasons to use automatic differentiation of a solver, and even if an analytical adjoint rule is used for some specific performance reason, that analytical expression can often times be accelerated by orders of magnitude itself by embedding some form of automatic differentiation into it. This is just one algorithm of many which are optimized in this fashion.

diff --git a/v1.5.0/comparisons/matlab/index.html b/v1.5.0/comparisons/matlab/index.html new file mode 100644 index 00000000000..0954779b529 --- /dev/null +++ b/v1.5.0/comparisons/matlab/index.html @@ -0,0 +1,2 @@ + +Getting Started with Julia's SciML for the MATLAB User · Overview of Julia's SciML

Getting Started with Julia's SciML for the MATLAB User

If you're a MATLAB user who has looked into Julia for some performance improvements, you may have noticed that the standard library does not have all of the “batteries” included with a base MATLAB installation. Where's the ODE solver? Where's fmincon and fsolve? Those scientific computing functionalities are the pieces provided by the Julia SciML ecosystem!

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from MATLAB to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Julia is quick to learn from MATLAB - Most ODE codes can be translated in a few minutes. If you need help, check out the QuantEcon MATLAB-Python-Julia Cheat Sheet.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Free and Open Source - If you want to know how things are being computed, just look at our GitHub organization. Lots of individuals use Julia's SciML to research how the algorithms actually work because of how accessible and tweakable the ecosystem is!
  • Composable Library Components - In MATLAB environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, MATLAB in orange represents MATLAB's most commonly used solvers:

Need a case study?

Check out this talk from NASA Scientists getting a 15,000x acceleration by switching from Simulink to Julia's ModelingToolkit!

Need Help Translating from MATLAB to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

MATLAB to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

MATLAB FunctionSciML-Supported Julia packages
plotPlots, Makie
sparseSparseArrays
interp1DataInterpolations
\, gmres, cgLinearSolve
fsolveNonlinearSolve
quadIntegrals
fminconOptimization
odeXXDifferentialEquations
ode45Tsit5
ode113VCABM
ode23sRosenbrock23
ode15sQNDF or FBDF
ode15iIDA
bvp4c and bvp5cDifferentialEquations
Simulink, SimscapeModelingToolkit
fftFFTW
chebfunApproxFun
diff --git a/v1.5.0/comparisons/python/index.html b/v1.5.0/comparisons/python/index.html new file mode 100644 index 00000000000..c8ef5407f87 --- /dev/null +++ b/v1.5.0/comparisons/python/index.html @@ -0,0 +1,2 @@ + +Getting Started with Julia's SciML for the Python User · Overview of Julia's SciML

Getting Started with Julia's SciML for the Python User

If you're a Python user who has looked into Julia, you're probably wondering what is the equivalent to SciPy is. And you found it: it's the SciML ecosystem! To a Python developer, SciML is SciPy, but with the high-performance GPU, capabilities of PyTorch, and neural network capabilities, all baked right in. With SciML, there is no “separate world” of machine learning sublanguages: there is just one cohesive package ecosystem.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from SciPy to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Composable Library Components - In Python environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, SciPy in yellow represents Python's most commonly used solvers:

Need Help Translating from Python to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

Python to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

Workflow ElementSciML-Supported Julia packages
MatplotlibPlots, Makie
scipy.specialSpecialFunctions
scipy.linalg.solveLinearSolve
scipy.integrateIntegrals
scipy.optimizeOptimization
scipy.optimize.fsolveNonlinearSolve
scipy.interpolateDataInterpolations
scipy.fftFFTW
scipy.linalgJulia's Built-In Linear Algebra
scipy.sparseSparseArrays, ARPACK
odeint/solve_ivpDifferentialEquations
scipy.integrate.solve_bvpBoundary-value problem
PyTorchFlux, Lux
gillespy2Catalyst, JumpProcesses
scipy.optimize.approx_fprimeFiniteDiff
autogradForwardDiff*, Enzyme*, DiffEqSensitivity
StanTuring
sympySymbolics

Why is Differentiable Programming Important for Scientific Computing?

Check out this blog post that goes into detail on how training neural networks in tandem with simulation improves performance by orders of magnitude. But can't you use analytical adjoint definitions? You can, but there are tricks to mix automatic differentiation into the adjoint definitions for a few orders of magnitude improvement too, as explained in this blog post.

These facts, along with many others, compose to algorithmic improvements with the implementation improvements, which leads to orders of magnitude improvements!

diff --git a/v1.5.0/comparisons/r/index.html b/v1.5.0/comparisons/r/index.html new file mode 100644 index 00000000000..7d5c111bd13 --- /dev/null +++ b/v1.5.0/comparisons/r/index.html @@ -0,0 +1,2 @@ + +Getting Started with Julia's SciML for the R User · Overview of Julia's SciML

Getting Started with Julia's SciML for the R User

If you're an R user who has looked into Julia, you're probably wondering where all of the scientific computing packages are. How do I solve ODEs? Solve f(x)=0 for x? Etc. SciML is the ecosystem for doing this with Julia.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from R to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Composable Library Components - In R environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • A Global Harmonious Documentation for Scientific Computing - R's documentation for scientific computing is scattered in a bunch of individual packages where the developers do not talk to each other! This not only leads to documentation differences, but also “style” differences: one package uses tol while the other uses atol. With Julia's SciML, the whole ecosystem is considered together, and inconsistencies are handled at the global level. The goal is to be working in one environment with one language.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, deSolve in blue represents R's most commonly used solver:

Need Help Translating from R to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

R to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

R Function/PackageSciML-Supported Julia packages
data.frameDataFrames
plotPlots, Makie
ggplot2AlgebraOfGraphics
deSolveDifferentialEquations
StanTuring

Want to See the Power of Julia?

Check out this R-Bloggers blog post on diffeqr, a package which uses ModelingToolkit to translate R code to Julia, and achieves 350x acceleration over R's popular deSolve ODE solver package. But when the solve is done purely in Julia, it achieves 2777x acceleration over deSolve!

diff --git a/v1.5.0/getting_started/find_root/index.html b/v1.5.0/getting_started/find_root/index.html new file mode 100644 index 00000000000..e0d65a1392c --- /dev/null +++ b/v1.5.0/getting_started/find_root/index.html @@ -0,0 +1,69 @@ + +Find the root of an equation (i.e. solve f(u)=0) · Overview of Julia's SciML

Find the root of an equation (i.e. solve f(u)=0)

A nonlinear system $f(u) = 0$ is specified by defining a function f(u,p), where p are the parameters of the system. Many problems can be written in such a way that solving a nonlinear rootfinding problem gives the solution. For example:

  • Do you want to know $u$ such that $4^u + 6^u = 7^u$? Then solve $f(u) = 4^u + 6^u - 7^u = 0$ for u!
  • If you have an ODE $u' = f(u)$, what is the point where the solution will be completely still, i.e. u' = 0?

All of these problems are solved by using a numerical rootfinder. Let's solve our first rootfind problem!

Required Dependencies

The following parts of the SciML Ecosystem will be used in this tutorial:

ModuleDescription
ModelingToolkit.jlThe symbolic modeling environment
NonlinearSolve.jlThe numerical solvers for nonlinear equations

Problem Setup

For example, the following solves the vector equation:

\[\begin{aligned} +0 &= σ*(y-x)\\ +0 &= x*(ρ-z)-y\\ +0 &= x*y - β*z\\ +\end{aligned}\]

With the parameter values $\sigma = 10.0$, $\rho = 26.0$, $\beta = 8/3$.

# Import the packages
+using ModelingToolkit, NonlinearSolve
+
+# Define the nonlinear system
+@variables x=1.0 y=0.0 z=0.0
+@parameters σ=10.0 ρ=26.0 β=8 / 3
+
+eqs = [0 ~ σ * (y - x),
+    0 ~ x * (ρ - z) - y,
+    0 ~ x * y - β * z]
+@mtkbuild ns = NonlinearSystem(eqs, [x, y, z], [σ, ρ, β])
+
+# Convert the symbolic system into a numerical system
+prob = NonlinearProblem(ns, [])
+
+# Solve the numerical problem
+sol = solve(prob, NewtonRaphson())
+
+# Analyze the solution
+@show sol[[x,y,z]], sol.resid
([-2.129924444096732e-29, -5.537803554651503e-28, -2.398137151871876e-28], [-5.32481111024183e-27, 6.395032404991669e-28])

Step-by-Step Solution

Step 1: Import the Packages

To do this tutorial, we will need a few components:

To start, let's add these packages as demonstrated in the installation tutorial:

using Pkg
+Pkg.add(["ModelingToolkit", "NonlinearSolve"])

Now we're ready. Let's load in these packages:

# Import the packages
+using ModelingToolkit, NonlinearSolve

Step 2: Define the Nonlinear System

Now let's define our nonlinear system. We use the ModelingToolkit.@variabes statement to declare our 3 state variables:

# Define the nonlinear system
+@variables x=1.0 y=0.0 z=0.0

\[ \begin{equation} +\left[ +\begin{array}{c} +x \\ +y \\ +z \\ +\end{array} +\right] +\end{equation} + \]

Notice that we are using the form state = initial condition. This is a nice shorthand for coupling an initial condition to our states. We now must similarly define our parameters, which we can associate default values via the form parameter = default value. This looks like:

@parameters σ=10.0 ρ=26.0 β=8 / 3

\[ \begin{equation} +\left[ +\begin{array}{c} +\sigma \\ +\rho \\ +\beta \\ +\end{array} +\right] +\end{equation} + \]

Now we create an array of equations to define our nonlinear system that must be satisfied. This looks as follows:

Note

Note that in ModelingToolkit and Symbolics, ~ is used for equation equality. This is separate from = which is the “assignment operator” in the Julia programming language. For example, x = x + 1 is a valid assignment in a programming language, and it is invalid for that to represent “equality”, which is why a separate operator is used!

eqs = [0 ~ σ * (y - x),
+    0 ~ x * (ρ - z) - y,
+    0 ~ x * y - β * z]

\[ \begin{align} +0 =& \left( - x + y \right) \sigma \\ +0 =& - y + x \left( - z + \rho \right) \\ +0 =& x y - z \beta +\end{align} + \]

Finally, we bring these pieces together, the equation along with its states and parameters, define our NonlinearSystem:

@mtkbuild ns = NonlinearSystem(eqs, [x, y, z], [σ, ρ, β])

\[ \begin{align} +0 =& \left( - x + y \right) \sigma \\ +0 =& x y - z \beta +\end{align} + \]

Step 3: Convert the Symbolic Problem to a Numerical Problem

Now that we have created our system, let's turn it into a numerical problem to approximate. This is done with the NonlinearProblem constructor, that transforms it from a symbolic ModelingToolkit representation to a numerical NonlinearSolve representation. We need to tell it the numerical details for whether to override any of the default values for the initial conditions and parameters.

In this case, we will use the default values for all our variables, so we will pass a blank override []. This looks like:

# Convert the symbolic system into a numerical system
+prob = NonlinearProblem(ns, [])
NonlinearProblem with uType Vector{Float64}. In-place: true
+u0: 2-element Vector{Float64}:
+ 1.0
+ 0.0

If we did want to change the initial condition of x to 2.0 and the parameter σ to 4.0, we would do [x => 2.0, σ => 4.0]. This looks like:

prob2 = NonlinearProblem(ns, [x => 2.0, σ => 4.0])
NonlinearProblem with uType Vector{Float64}. In-place: true
+u0: 2-element Vector{Float64}:
+ 2.0
+ 0.0

Step 4: Solve the Numerical Problem

Now we solve the nonlinear system. For this, we choose a solver from the NonlinearSolve.jl's solver options. We will choose NewtonRaphson as follows:

# Solve the numerical problem
+sol = solve(prob, NewtonRaphson())
retcode: Success
+u: 2-element Vector{Float64}:
+ -2.129924444096732e-29
+ -2.398137151871876e-28

Step 5: Analyze the Solution

Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:

typeof(sol)
SciMLBase.NonlinearSolution{Float64, 1, Vector{Float64}, Vector{Float64}, SciMLBase.NonlinearProblem{Vector{Float64}, true, ModelingToolkit.MTKParameters{Tuple{Vector{Float64}}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, Nothing, Nothing}, SciMLBase.NonlinearFunction{true, SciMLBase.FullSpecialize, ModelingToolkit.var"#f#529"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x0bec91c5, 0x7102a3b4, 0x25790b05, 0xeedeb041, 0xb28da2c7), Nothing}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x85b9a698, 0x76e4b08e, 0x07ba5224, 0xe2c014ba, 0x43cce4c2), Nothing}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.var"#generated_observed#532"{ModelingToolkit.NonlinearSystem, Dict{Any, Any}}, Nothing, ModelingToolkit.NonlinearSystem, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}, NonlinearSolve.GeneralizedFirstOrderAlgorithm{nothing, :NewtonRaphson, NonlinearSolve.NoLineSearch, Missing, NonlinearSolve.NewtonDescent{Nothing, typeof(NonlinearSolve.DEFAULT_PRECS)}, Nothing, Nothing, Nothing}, Nothing, Nothing, NonlinearSolve.ImmutableNLStats, NonlinearSolve.NonlinearSolveTrace{false, false, NonlinearSolve.TraceMinimal, Nothing, SciMLBase.NonlinearProblem{Vector{Float64}, true, ModelingToolkit.MTKParameters{Tuple{Vector{Float64}}, Tuple{}, Tuple{}, Tuple{}, Tuple{}, Nothing, Nothing}, SciMLBase.NonlinearFunction{true, SciMLBase.FullSpecialize, ModelingToolkit.var"#f#529"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x0bec91c5, 0x7102a3b4, 0x25790b05, 0xeedeb041, 0xb28da2c7), Nothing}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x85b9a698, 0x76e4b08e, 0x07ba5224, 0xe2c014ba, 0x43cce4c2), Nothing}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, ModelingToolkit.var"#generated_observed#532"{ModelingToolkit.NonlinearSystem, Dict{Any, Any}}, Nothing, ModelingToolkit.NonlinearSystem, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardNonlinearProblem}}}

From this, we can see that it is an NonlinearSolution. We can see the documentation for how to use the NonlinearSolution by checking the NonlinearSolve.jl solution type page. For example, the solution is stored as .u. What is the solution to our nonlinear system, and what is the final residual value? We can check it as follows:

# Analyze the solution
+@show sol[[x,y,z]], sol.resid
([-2.129924444096732e-29, -5.537803554651503e-28, -2.398137151871876e-28], [-5.32481111024183e-27, 6.395032404991669e-28])
diff --git a/v1.5.0/getting_started/first_optimization/index.html b/v1.5.0/getting_started/first_optimization/index.html new file mode 100644 index 00000000000..786040dd8c3 --- /dev/null +++ b/v1.5.0/getting_started/first_optimization/index.html @@ -0,0 +1,32 @@ + +Solve your first optimization problem · Overview of Julia's SciML

Solve your first optimization problem

Numerical optimization is the process of finding some numerical values that minimize some equation.

  • How much fuel should you put into an airplane to have the minimum weight that can go to its destination?
  • What parameters should I choose for my simulation so that it minimizes the distance of its predictions from my experimental data?

All of these are examples of problems solved by numerical optimization. Let's solve our first optimization problem!

Required Dependencies

The following parts of the SciML Ecosystem will be used in this tutorial:

ModuleDescription
Optimization.jlThe numerical optimization package
OptimizationNLopt.jlThe NLopt optimizers we will use
ForwardDiff.jlThe automatic differentiation library for gradients

Problem Setup

First, what are we solving? Let's take a look at the Rosenbrock equation:

\[L(u,p) = (p_1 - u_1)^2 + p_2 * (u_2 - u_1)^2\]

What we want to do is find the values of $u_1$ and $u_2$ such that $L$ achieves its minimum value possible. We will do this under a few constraints: we want to find this optimum within some bounded domain, i.e. $u_i \in [-1,1]$. This should be done with the parameter values $p_1 = 1.0$ and $p_2 = 100.0$. What should $u = [u_1,u_2]$ be to achieve this goal? Let's dive in!

Note

The upper and lower bounds are optional for the solver! If your problem does not need to have such bounds, just leave off the parts with lb and ub!

Copy-Pastable Code

# Import the package
+using Optimization, OptimizationNLopt, ForwardDiff
+
+# Define the problem to optimize
+L(u, p) = (p[1] - u[1])^2 + p[2] * (u[2] - u[1]^2)^2
+u0 = zeros(2)
+p = [1.0, 100.0]
+optfun = OptimizationFunction(L, Optimization.AutoForwardDiff())
+prob = OptimizationProblem(optfun, u0, p, lb = [-1.0, -1.0], ub = [1.0, 1.0])
+
+# Solve the optimization problem
+sol = solve(prob, NLopt.LD_LBFGS())
+
+# Analyze the solution
+@show sol.u, L(sol.u, p)
([1.0, 1.0], 0.0)

Step-by-Step Solution

Step 1: Import the packages

To do this tutorial, we will need a few components:

Note that Optimization.jl is an interface for optimizers, and thus we always have to choose which optimizer we want to use. Here we choose to demonstrate OptimizationNLopt because of its efficiency and versatility. But there are many other possible choices. Check out the solver compatibility chart for a quick overview of what optimizer packages offer.

To start, let's add these packages as demonstrated in the installation tutorial:

using Pkg
+Pkg.add(["Optimization", "OptimizationNLopt", "ForwardDiff"])

Now we're ready. Let's load in these packages:

using Optimization, OptimizationNLopt, ForwardDiff

Step 2: Define the Optimization Problem

Now let's define our problem to optimize. We start by defining our loss function. In Optimization.jl's OptimizationProblem interface, the states are given by an array u. Thus we can designate u[1] to be u_1 and u[2] to be u_2, similarly with our parameters, and write out the loss function on a vector-defined state as follows:

# Define the problem to optimize
+L(u, p) = (p[1] - u[1])^2 + p[2] * (u[2] - u[1]^2)^2
L (generic function with 1 method)

Next we need to create an OptimizationFunction where we tell Optimization.jl to use the ForwardDiff.jl package for creating the gradient and other derivatives required by the optimizer.

#Create the OptimizationFunction
+optfun = OptimizationFunction(L, Optimization.AutoForwardDiff())
(::SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}) (generic function with 1 method)

Now we need to define our OptimizationProblem. If you need help remembering how to define the OptimizationProblem, you can always refer to the Optimization.jl problem definition page.

Thus what we need to define is an initial condition u0 and our parameter vector p. We will make our initial condition have both values as zero, which is done by the Julia shorthand zeros(2) that creates a vector [0.0,0.0]. We manually define the parameter vector p to input our values. Then we set the lower bound and upper bound for the optimization as follows:

u0 = zeros(2)
+p = [1.0, 100.0]
+prob = OptimizationProblem(optfun, u0, p, lb = [-1.0, -1.0], ub = [1.0, 1.0])
OptimizationProblem. In-place: true
+u0: 2-element Vector{Float64}:
+ 0.0
+ 0.0

Note about defining uniform bounds

Note that we can simplify the code a bit for the lower and upper bound definition by using the Julia Base command ones, which returns a vector where each value is a one. Thus for example, ones(2) is equivalent to [1.0,1.0]. Therefore -1 * ones(2) is equivalent to [-1.0,-1.0], meaning we could have written our problem as follows:

prob = OptimizationProblem(optfun, u0, p, lb = -1 * ones(2), ub = ones(2))
OptimizationProblem. In-place: true
+u0: 2-element Vector{Float64}:
+ 0.0
+ 0.0

Step 3: Solve the Optimization Problem

Now we solve the OptimizationProblem that we have defined. This is done by passing our OptimizationProblem along with a chosen solver to the solve command. At the beginning, we explained that we will use the OptimizationNLopt set of solvers, which are documented in the OptimizationNLopt page. From here, we are choosing the NLopt.LD_LBFGS() for its mixture of robustness and performance. To perform this solve, we do the following:

# Solve the optimization problem
+sol = solve(prob, NLopt.LD_LBFGS())
retcode: Success
+u: 2-element Vector{Float64}:
+ 1.0
+ 1.0

Step 4: Analyze the Solution

Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:

typeof(sol)
SciMLBase.OptimizationSolution{Float64, 1, Vector{Float64}, OptimizationBase.OptimizationCache{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), OptimizationForwardDiffExt.var"#38#56"{ForwardDiff.GradientConfig{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}}}, OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}}, OptimizationForwardDiffExt.var"#41#59"{ForwardDiff.HessianConfig{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}, 2}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}}}, OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}}, OptimizationForwardDiffExt.var"#44#62", Nothing, OptimizationForwardDiffExt.var"#48#66"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Nothing, Nothing, OptimizationForwardDiffExt.var"#53#71"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}}, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, OptimizationBase.ReInitCache{Vector{Float64}, Vector{Float64}}, Vector{Float64}, Vector{Float64}, Nothing, Nothing, Nothing, NLopt.Algorithm, Base.Iterators.Cycle{Tuple{OptimizationBase.NullData}}, Bool, OptimizationBase.NullCallback}, NLopt.Algorithm, Float64, NLopt.Opt, SciMLBase.OptimizationStats}

From this, we can see that it is an OptimizationSolution. We can see the documentation for how to use the OptimizationSolution by checking the Optimization.jl solution type page. For example, the solution is stored as .u. What is the solution to our optimization, and what is the final loss value? We can check it as follows:

# Analyze the solution
+@show sol.u, L(sol.u, p)
([1.0, 1.0], 0.0)
diff --git a/v1.5.0/getting_started/first_simulation/6b2ae665.svg b/v1.5.0/getting_started/first_simulation/6b2ae665.svg new file mode 100644 index 00000000000..dcbe5a96eb2 --- /dev/null +++ b/v1.5.0/getting_started/first_simulation/6b2ae665.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/first_simulation/778780f6.svg b/v1.5.0/getting_started/first_simulation/778780f6.svg new file mode 100644 index 00000000000..4e30c5564bb --- /dev/null +++ b/v1.5.0/getting_started/first_simulation/778780f6.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/first_simulation/8da7844b.svg b/v1.5.0/getting_started/first_simulation/8da7844b.svg new file mode 100644 index 00000000000..87e14486492 --- /dev/null +++ b/v1.5.0/getting_started/first_simulation/8da7844b.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/first_simulation/a7a12805.svg b/v1.5.0/getting_started/first_simulation/a7a12805.svg new file mode 100644 index 00000000000..5b70d4fcf73 --- /dev/null +++ b/v1.5.0/getting_started/first_simulation/a7a12805.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/first_simulation/index.html b/v1.5.0/getting_started/first_simulation/index.html new file mode 100644 index 00000000000..0b99342c5c1 --- /dev/null +++ b/v1.5.0/getting_started/first_simulation/index.html @@ -0,0 +1,198 @@ + +Build and run your first simulation with Julia's SciML · Overview of Julia's SciML

Build and run your first simulation with Julia's SciML

In this tutorial, we will build and run our first simulation with SciML!

Note

This tutorial assumes that you have already installed Julia on your system. If you have not done so already, please follow the installation tutorial first.

To build our simulation, we will use the ModelingToolkit system for modeling and simulation. ModelingToolkit is a bit higher level than directly defining code for a differential equation system: it's a symbolic system that will automatically simplify our models, optimize our code, and generate compelling visualizations. Sounds neat? Let's dig in.

Required Dependencies

The following parts of the SciML Ecosystem will be used in this tutorial:

ModuleDescription
ModelingToolkit.jlThe symbolic modeling environment
DifferentialEquations.jlThe differential equation solvers
Plots.jlThe plotting and visualization package

Our Problem: Simulate the Lotka-Volterra Predator-Prey Dynamics

The dynamics of our system are given by the Lotka-Volterra dynamical system: Let $x(t)$ be the number of rabbits in the environment and $y(t)$ be the number of wolves. The equation that defines the evolution of the species is given as follows:

\[\begin{align} +\frac{dx}{dt} &= \alpha x - \beta x y\\ +\frac{dy}{dt} &= -\gamma y + \delta x y +\end{align}\]

where $\alpha, \beta, \gamma, \delta$ are parameters. Starting from equal numbers of rabbits and wolves, $x(0) = 1$ and $y(0) = 1$, we want to simulate this system from time $t_0 = 0$ to $t_f = 10$. Luckily, a local guide provided us with some parameters that seem to match the system! These are $\alpha = 1.5$, $\beta = 1.0$, $\gamma = 3.0$, $\delta = 1.0$. How many rabbits and wolves will there be 10 months from now? And if z = x + y, i.e. the total number of animals at a given time, can we visualize this total number of animals at each time?

Solution as Copy-Pastable Code

using ModelingToolkit, DifferentialEquations, Plots
+
+# Define our state variables: state(t) = initial condition
+@variables t x(t)=1 y(t)=1 z(t)=2
+
+# Define our parameters
+@parameters α=1.5 β=1.0 γ=3.0 δ=1.0
+
+# Define our differential: takes the derivative with respect to `t`
+D = Differential(t)
+
+# Define the differential equations
+eqs = [D(x) ~ α * x - β * x * y
+       D(y) ~ -γ * y + δ * x * y
+       z ~ x + y]
+
+# Bring these pieces together into an ODESystem with independent variable t
+@mtkbuild sys = ODESystem(eqs, t)
+
+# Convert from a symbolic to a numerical problem to simulate
+tspan = (0.0, 10.0)
+prob = ODEProblem(sys, [], tspan)
+
+# Solve the ODE
+sol = solve(prob)
+
+# Plot the solution
+p1 = plot(sol, title = "Rabbits vs Wolves")
+p2 = plot(sol, idxs = z, title = "Total Animals")
+
+plot(p1, p2, layout = (2, 1))
Example block output

Step-by-Step Solution

Step 1: Install and Import the Required Packages

To do this tutorial, we will need a few components:

To start, let's add these packages as demonstrated in the installation tutorial:

using Pkg
+Pkg.add(["ModelingToolkit", "DifferentialEquations", "Plots"])

Now we're ready. Let's load in these packages:

using ModelingToolkit, DifferentialEquations, Plots

Step 2: Define our ODE Equations

Now let's define our ODEs. We use the ModelingToolkit.@variabes statement to declare our variables. We have the independent variable time t, and then define our 3 state variables:

# Define our state variables: state(t) = initial condition
+@variables t x(t)=1 y(t)=1 z(t)=2

\[ \begin{equation} +\left[ +\begin{array}{c} +t \\ +x\left( t \right) \\ +y\left( t \right) \\ +z\left( t \right) \\ +\end{array} +\right] +\end{equation} + \]

Notice here that we use the form state = default, where on the right-hand side the default value of a state is interpreted to be its initial condition. This is then done similarly for parameters, where the default value is now the parameter value:

# Define our parameters
+@parameters α=1.5 β=1.0 γ=3.0 δ=1.0

\[ \begin{equation} +\left[ +\begin{array}{c} +\alpha \\ +\beta \\ +\gamma \\ +\delta \\ +\end{array} +\right] +\end{equation} + \]

Note

Julia's text editors like VS Code are compatible with Unicode defined in a LaTeX form. Thus if you write \alpha into your REPL and then press Tab, it will auto-complete that into the α symbol. That can make your code look a lot more like the mathematical expressions!

Next, we define our set of differential equations. To define the Differential operator D, we need to first tell it what to differentiate with respect to, here the independent variable t, Then, once we have the operator, we apply that into the equations.

Note

Note that in ModelingToolkit and Symbolics, ~ is used for equation equality. This is separate from = which is the “assignment operator” in the Julia programming language. For example, x = x + 1 is a valid assignment in a programming language, and it is invalid for that to represent “equality”, which is why a separate operator is used!

# Define our differential: takes the derivative with respect to `t`
+D = Differential(t)
+
+# Define the differential equations
+eqs = [D(x) ~ α * x - β * x * y
+       D(y) ~ -γ * y + δ * x * y
+       z ~ x + y]

\[ \begin{align} +\frac{\mathrm{d} x\left( t \right)}{\mathrm{d}t} =& x\left( t \right) \alpha - x\left( t \right) y\left( t \right) \beta \\ +\frac{\mathrm{d} y\left( t \right)}{\mathrm{d}t} =& - y\left( t \right) \gamma + x\left( t \right) y\left( t \right) \delta \\ +z\left( t \right) =& x\left( t \right) + y\left( t \right) +\end{align} + \]

Notice that in the display, it will automatically generate LaTeX. If one is interested in generating this LaTeX locally, one can simply do:

using Latexify # add the package first
+latexify(eqs)

Step 3: Define the ODEProblem

Now we bring these pieces together. In ModelingToolkit, we can bring these pieces together to represent an ODESystem with the following:

# Bring these pieces together into an ODESystem with independent variable t
+@mtkbuild sys = ODESystem(eqs, t)

\[ \begin{align} +\frac{\mathrm{d} x\left( t \right)}{\mathrm{d}t} =& x\left( t \right) \alpha - x\left( t \right) y\left( t \right) \beta \\ +\frac{\mathrm{d} y\left( t \right)}{\mathrm{d}t} =& - y\left( t \right) \gamma + x\left( t \right) y\left( t \right) \delta +\end{align} + \]

Notice that in our equations we have an algebraic equation z ~ x + y. This is not a differential equation but an algebraic equation, and thus we call this set of equations a Differential-Algebraic Equation (DAE). The symbolic system of ModelingToolkit can eliminate such equations to return simpler forms to numerically approximate.

Notice that what is returned is an ODESystem, but now with the simplified set of equations. z has been turned into an “observable”, i.e. a state that is not computed but can be constructed on-demand. This is one of the ways that SciML reaches its speed: you can have 100,000 equations, but solve only 1,000 to then automatically reconstruct the full set. Here, it's just 3 equations to 2, but as models get more complex, the symbolic system will find ever more clever interactions!

Now that we have simplified our system, let's turn it into a numerical problem to approximate. This is done with the ODEProblem constructor, that transforms it from a symbolic ModelingToolkit representation to a numerical DifferentialEquations representation. We need to tell it the numerical details now:

  1. Whether to override any of the default values for the initial conditions and parameters.
  2. What is the initial time point.
  3. How long to integrate it for.

In this case, we will use the default values for all our variables, so we will pass a blank override []. If for example we did want to change the initial condition of x to 2.0 and α to 4.0, we would do [x => 2.0, α => 4.0]. Then secondly, we pass a tuple for the time span, (0.0,10.0) meaning start at 0.0 and end at 10.0. This looks like:

# Convert from a symbolic to a numerical problem to simulate
+tspan = (0.0, 10.0)
+prob = ODEProblem(sys, [], tspan)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
+timespan: (0.0, 10.0)
+u0: 2-element Vector{Float64}:
+ 1.0
+ 1.0

Step 4: Solve the ODE System

Now we solve the ODE system. Julia's SciML solvers have a defaulting system that can automatically determine an appropriate solver for a given system, so we can just tell it to solve:

# Solve the ODE
+sol = solve(prob)
retcode: Success
+Interpolation: 3rd order Hermite
+t: 34-element Vector{Float64}:
+  0.0
+  0.0776084743154256
+  0.23264513699277584
+  0.4291185174543143
+  0.6790821987497083
+  0.9444046158046306
+  1.2674601546021105
+  1.6192913303893046
+  1.9869754428624007
+  2.2640902393538296
+  ⋮
+  7.584863345264154
+  7.978068981329682
+  8.48316543760351
+  8.719248247740158
+  8.949206788834692
+  9.200185054623292
+  9.438029017301554
+  9.711808134779586
+ 10.0
+u: 34-element Vector{Vector{Float64}}:
+ [1.0, 1.0]
+ [1.0454942346944578, 0.8576684823217128]
+ [1.1758715885138271, 0.6394595703175443]
+ [1.419680960717083, 0.4569962601282089]
+ [1.8767193950080012, 0.3247334292791134]
+ [2.588250064553348, 0.26336255535952197]
+ [3.860708909220769, 0.2794458098285261]
+ [5.750812667710401, 0.522007253793458]
+ [6.8149789991301635, 1.9177826328390826]
+ [4.392999292571394, 4.1946707928506015]
+ ⋮
+ [2.6142539677883248, 0.26416945387526314]
+ [4.24107612719179, 0.3051236762922018]
+ [6.791123785297775, 1.1345287797146668]
+ [6.26537067576476, 2.741693507540315]
+ [3.780765111887945, 4.431165685863443]
+ [1.816420140681737, 4.064056625315896]
+ [1.1465021407690763, 2.791170661621642]
+ [0.9557986135403417, 1.623562295185047]
+ [1.0337581256020802, 0.9063703842885995]

Step 5: Visualize the Solution

Now let's visualize the solution! Notice that our solution only has two states. If we recall, the simplified system only has two states: z was symbolically eliminated. We can access any of the values, even the eliminated values, using the symbolic variable as the index. For example:

sol[z]
34-element Vector{Float64}:
+ 2.0
+ 1.9031627170161705
+ 1.8153311588313714
+ 1.876677220845292
+ 2.2014528242871148
+ 2.8516126199128697
+ 4.1401547190492956
+ 6.272819921503858
+ 8.732761631969247
+ 8.587670085421996
+ ⋮
+ 2.8784234216635878
+ 4.546199803483992
+ 7.925652565012442
+ 9.007064183305074
+ 8.21193079775139
+ 5.880476765997633
+ 3.9376728023907184
+ 2.5793609087253886
+ 1.9401285098906798

returns the time series of the observable z at time points corresponding to sol.t. We can use this with the automated plotting functionality. First let's create a plot of x and y over time using plot(sol) which will plot all of the states. Then next, we will explicitly tell it to make a plot with the index being z, i.e. idxs=z.

Note

Note that one can pass an array of indices as well, so idxs=[x,y,z] would make a plot with all three lines together!

# Plot the solution
+p1 = plot(sol, title = "Rabbits vs Wolves")
Example block output
p2 = plot(sol, idxs = z, title = "Total Animals")
Example block output

Finally, let's make a plot where we merge these two plot elements. To do so, we can take our two plot objects, p1 and p2, and make a plot with both of them. Then we tell Plots to do a layout of (2,1), or 2 rows and 1 columns. Let's see what happens when we bring these together:

plot(p1, p2, layout = (2, 1))
Example block output

And tada, we have a full analysis of our ecosystem!

Bonus Step: Emoji Variables

If you made it this far, then congrats, you get to learn a fun fact! Since Julia code can use Unicode, emojis work for variable names. Here's the simulation using emojis of rabbits and wolves to define the system:

using ModelingToolkit, DifferentialEquations
+@parameters α=1.5 β=1.0 γ=3.0 δ=1.0
+@variables t 🐰(t)=1.0 🐺(t)=1.0
+D = Differential(t)
+eqs = [D(🐰) ~ α * 🐰 - β * 🐰 * 🐺,
+    D(🐺) ~ -γ * 🐺 + δ * 🐰 * 🐺]
+
+@mtkbuild sys = ODESystem(eqs, t)
+prob = ODEProblem(sys, [], (0.0, 10.0))
+sol = solve(prob)
retcode: Success
+Interpolation: 3rd order Hermite
+t: 34-element Vector{Float64}:
+  0.0
+  0.0776084743154256
+  0.23264513699277584
+  0.4291185174543143
+  0.6790821987497083
+  0.9444046158046306
+  1.2674601546021105
+  1.6192913303893046
+  1.9869754428624007
+  2.2640902393538296
+  ⋮
+  7.584863345264154
+  7.978068981329682
+  8.48316543760351
+  8.719248247740158
+  8.949206788834692
+  9.200185054623292
+  9.438029017301554
+  9.711808134779586
+ 10.0
+u: 34-element Vector{Vector{Float64}}:
+ [1.0, 1.0]
+ [1.0454942346944578, 0.8576684823217128]
+ [1.1758715885138271, 0.6394595703175443]
+ [1.419680960717083, 0.4569962601282089]
+ [1.8767193950080012, 0.3247334292791134]
+ [2.588250064553348, 0.26336255535952197]
+ [3.860708909220769, 0.2794458098285261]
+ [5.750812667710401, 0.522007253793458]
+ [6.8149789991301635, 1.9177826328390826]
+ [4.392999292571394, 4.1946707928506015]
+ ⋮
+ [2.6142539677883248, 0.26416945387526314]
+ [4.24107612719179, 0.3051236762922018]
+ [6.791123785297775, 1.1345287797146668]
+ [6.26537067576476, 2.741693507540315]
+ [3.780765111887945, 4.431165685863443]
+ [1.816420140681737, 4.064056625315896]
+ [1.1465021407690763, 2.791170661621642]
+ [0.9557986135403417, 1.623562295185047]
+ [1.0337581256020802, 0.9063703842885995]

Now go make your professor mad that they have to grade a fully emojified code. I'll vouch for you: the documentation told you to do this.

diff --git a/v1.5.0/getting_started/fit_simulation/2321e184.svg b/v1.5.0/getting_started/fit_simulation/2321e184.svg new file mode 100644 index 00000000000..d6086674a8f --- /dev/null +++ b/v1.5.0/getting_started/fit_simulation/2321e184.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/fit_simulation/5207edff.svg b/v1.5.0/getting_started/fit_simulation/5207edff.svg new file mode 100644 index 00000000000..e0e4607497f --- /dev/null +++ b/v1.5.0/getting_started/fit_simulation/5207edff.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/getting_started/fit_simulation/index.html b/v1.5.0/getting_started/fit_simulation/index.html new file mode 100644 index 00000000000..0de1d9ea484 --- /dev/null +++ b/v1.5.0/getting_started/fit_simulation/index.html @@ -0,0 +1,147 @@ + +Fit a simulation to a dataset · Overview of Julia's SciML

Fit a simulation to a dataset

Running simulations is only half of the battle. Many times, in order to make the simulation realistic, you need to fit the simulation to data. The SciML ecosystem has integration with automatic differentiation and adjoint methods to automatically make the fitting process stable and efficient. Let's see this in action.

Required Dependencies

The following parts of the SciML Ecosystem will be used in this tutorial:

ModuleDescription
DifferentialEquations.jlThe differential equation solvers
Optimization.jlThe numerical optimization package
OptimizationPolyalgorithms.jlThe optimizers we will use
SciMLSensitivity.jlThe connection of the SciML ecosystems to differentiation

Along with the following general ecosystem packages:

ModuleDescription
Plots.jlThe plotting and visualization package
ForwardDiff.jlThe automatic differentiation package

Problem Setup: Fitting Lotka-Volterra Data

Assume that we know that the dynamics of our system are given by the Lotka-Volterra dynamical system: Let $x(t)$ be the number of rabbits in the environment and $y(t)$ be the number of wolves. This is the same dynamical system as the first tutorial! The equation that defines the evolution of the species is given as follows:

\[\begin{align} +\frac{dx}{dt} &= \alpha x - \beta x y\\ +\frac{dy}{dt} &= -\gamma y + \delta x y +\end{align}\]

where $\alpha, \beta, \gamma, \delta$ are parameters. Starting from equal numbers of rabbits and wolves, $x(0) = 1$ and $y(0) = 1$.

Now, in the first tutorial, we assumed:

Luckily, a local guide provided us with some parameters that seem to match the system!

Sadly, magical nymphs do not always show up and give us parameters. Thus in this case, we will need to use Optimization.jl to optimize the model parameters to best fit some experimental data. We are given experimentally observed data of both rabbit and wolf populations over a time span of $t_0 = 0$ to $t_f = 10$ at every $\Delta t = 1$. Can we figure out what the parameter values should be directly from the data?

Solution as Copy-Pastable Code

using DifferentialEquations, Optimization, OptimizationPolyalgorithms, SciMLSensitivity
+using ForwardDiff, Plots
+
+# Define experimental data
+t_data = 0:10
+x_data = [1.000 2.773 6.773 0.971 1.886 6.101 1.398 1.335 4.353 3.247 1.034]
+y_data = [1.000 0.259 2.015 1.908 0.323 0.629 3.458 0.508 0.314 4.547 0.906]
+xy_data = vcat(x_data, y_data)
+
+# Plot the provided data
+scatter(t_data, xy_data', label=["x Data" "y Data"])
+
+# Setup the ODE function
+function lotka_volterra!(du, u, p, t)
+    x, y = u
+    α, β, δ, γ = p
+    du[1] = dx = α * x - β * x * y
+    du[2] = dy = -δ * y + γ * x * y
+end
+
+# Initial condition
+u0 = [1.0, 1.0]
+
+# Simulation interval
+tspan = (0.0, 10.0)
+
+# LV equation parameter. p = [α, β, δ, γ]
+pguess = [1.0, 1.2, 2.5, 1.2]
+
+# Set up the ODE problem with our guessed parameter values
+prob = ODEProblem(lotka_volterra!, u0, tspan, pguess)
+
+# Solve the ODE problem with our guessed parameter values
+initial_sol = solve(prob, saveat = 1)
+
+# View the guessed model solution
+plt = plot(initial_sol, label = ["x Prediction" "y Prediction"])
+scatter!(plt, t_data, xy_data', label = ["x Data" "y Data"])
+
+# Define a loss metric function to be minimized
+function loss(newp)
+    newprob = remake(prob, p = newp)
+    sol = solve(newprob, saveat = 1)
+    loss = sum(abs2, sol .- xy_data)
+    return loss, sol
+end
+
+# Define a callback function to monitor optimization progress
+function callback(p, l, sol)
+    display(l)
+    plt = plot(sol, ylim = (0, 6), label = ["Current x Prediction" "Current y Prediction"])
+    scatter!(plt, t_data, xy_data', label = ["x Data" "y Data"])
+    display(plt)
+    return false
+end
+
+# Set up the optimization problem with our loss function and initial guess
+adtype = AutoForwardDiff()
+pguess = [1.0, 1.2, 2.5, 1.2]
+optf = OptimizationFunction((x, _) -> loss(x), adtype)
+optprob = OptimizationProblem(optf, pguess)
+
+# Optimize the ODE parameters for best fit to our data
+pfinal = solve(optprob, PolyOpt(),
+               callback = callback,
+               maxiters = 200)
+α, β, γ, δ = round.(pfinal, digits=1)
4-element Vector{Float64}:
+ 1.5
+ 1.0
+ 3.1
+ 1.0

Step-by-Step Solution

Step 1: Install and Import the Required Packages

To do this tutorial, we will need a few components. This is done using the Julia Pkg REPL:

using Pkg
+Pkg.add([
+            "DifferentialEquations",
+            "Optimization",
+            "OptimizationPolyalgorithms",
+            "SciMLSensitivity",
+            "ForwardDiff",
+            "Plots",
+        ])

Now we're ready. Let's load in these packages:

using DifferentialEquations, Optimization, OptimizationPolyalgorithms, SciMLSensitivity
+using ForwardDiff, Plots

Step 2: View the Training Data

In our example, we are given observed values for x and y populations at eleven instances in time. Let's make that the training data for our Lotka-Volterra dynamical system model.

# Define experimental data
+t_data = 0:10
+x_data = [1.000 2.773 6.773 0.971 1.886 6.101 1.398 1.335 4.353 3.247 1.034]
+y_data = [1.000 0.259 2.015 1.908 0.323 0.629 3.458 0.508 0.314 4.547 0.906]
+xy_data = vcat(x_data, y_data)
+
+# Plot the provided data
+scatter(t_data, xy_data', label=["x Data" "y Data"])
Example block output
Note

The Array xy_data above has been oriented with time instances as columns so that it can be directly compared with an ODESolution object. (See Solution Handling for more information on accessing DifferentialEquation.jl solution data.) However, plotting an Array with Plots.jl requires the variables to be columns and the time instances to be rows. Thus, whenever the experimental data is plotted, the transpose xy_data' will be used.

Step 3: Set Up the ODE Model

We know that our system will behave according to the Lotka-Volterra ODE model, so let's set up that model with an initial guess at the parameter values: \alpha, \beta, \gamma, and \delta. Unlike the first tutorial, which used ModelingToolkit, let's demonstrate using DifferentialEquations.jl to directly define the ODE for the numerical solvers.

To do this, we define a vector-based mutating function that calculates the derivatives for our system. We will define our system as a vector u = [x,y], and thus u[1] = x and u[2] = y. This means that we need to calculate the derivative as du = [dx,dy]. Our parameters will simply be the vector p = [α, β, δ, γ]. Writing down the Lotka-Volterra equations in the DifferentialEquations.jl direct form thus looks like the following:

function lotka_volterra!(du, u, p, t)
+    x, y = u
+    α, β, δ, γ = p
+    du[1] = dx = α * x - β * x * y
+    du[2] = dy = -δ * y + γ * x * y
+end
lotka_volterra! (generic function with 1 method)

Now we need to define the initial condition, time span, and parameter vector in order to solve this differential equation. We do not currently know the parameter values, but we will guess some values to start with and optimize them later. Following the problem setup, this looks like:

# Initial condition
+u0 = [1.0, 1.0]
+
+# Simulation interval
+tspan = (0.0, 10.0)
+
+# LV equation parameter. p = [α, β, δ, γ]
+pguess = [1.0, 1.2, 2.5, 1.2]
4-element Vector{Float64}:
+ 1.0
+ 1.2
+ 2.5
+ 1.2

Now we bring these pieces all together to define the ODEProblem and solve it. Note that we solve this equation with the keyword argument saveat = 1 so that it saves a point at every $\Delta t = 1$ to match our experimental data.

# Set up the ODE problem with our guessed parameter values
+prob = ODEProblem(lotka_volterra!, u0, tspan, pguess)
+
+# Solve the ODE problem with our guessed parameter values
+initial_sol = solve(prob, saveat = 1)
+
+# View the guessed model solution
+plt = plot(initial_sol, label = ["x Prediction" "y Prediction"])
+scatter!(plt, t_data, xy_data', label = ["x Data" "y Data"])
Example block output
Clearly the parameter values that we guessed are not correct to model this system.
+However, we can use Optimization.jl together with DifferentialEquations.jl
+to fit our parameters to our training data.
Note

For more details on using DifferentialEquations.jl, check out the getting started with DifferentialEquations.jl tutorial.

Step 4: Set Up the Loss Function for Optimization

Now let's start the optimization process. First, let's define a loss function to be minimized. (It is also sometimes referred to as a cost function.) For our loss function, we want to take a set of parameters, create a new ODE which has everything the same except for the changed parameters, solve this ODE with new parameters, and compare the ODE solution against the provided data. In this case, the loss returned from the loss function is a quantification of the difference between the current solution and the desired solution. When this difference is minimized, our model prediction will closely approximate the observed system data.

To change our parameter values, there is a useful functionality in the SciML problems interface called remake which creates a new version of an existing SciMLProblem with the aspect you want changed. For example, if we wanted to change the initial condition u0 of our ODE, we could do remake(prob, u0 = newu0) For our case, we want to change around just the parameters, so we can do remake(prob, p = newp). It is faster to remake an existing SciMLProblem than to create a new problem every iteration.

Note

remake can change multiple items at once by passing more keyword arguments, i.e., remake(prob, u0 = newu0, p = newp). This can be used to extend the example to simultaneously learn the initial conditions and parameters!

Now use remake to build the loss function. After we solve the new problem, we will calculate the sum of squared errors as our loss metric. The sum of squares can be quickly written in Julia via sum(abs2,x). Using this information, our loss function looks like:

function loss(newp)
+    newprob = remake(prob, p = newp)
+    sol = solve(newprob, saveat = 1)
+    l = sum(abs2, sol .- xy_data)
+    return l, sol
+end
loss (generic function with 1 method)

Notice that our loss function returns the loss value as the first return, but returns extra information (the ODE solution with the new parameters) as an extra return argument. We will explain why this extra return information is helpful in the next section.

Step 5: Solve the Optimization Problem

This step will look very similar to the first optimization tutorial, except now we have a new loss function loss which returns both the loss value and the associated ODE solution. (In the previous tutorial, L only returned the loss value.) The Optimization.solve function can accept an optional callback function to monitor the optimization process using extra arguments returned from loss.

The callback syntax is always:

callback(
+    optimization variables,
+    the current loss value,
+    other arguments returned from the loss function, ...
+)

In this case, we will provide the callback the arguments (p, l, sol), since it always takes the current state of the optimization first (p) then the returns from the loss function (l, sol). The return value of the callback function should default to false. Optimization.solve will halt if/when the callback function returns true instead. Typically the return statement would monitor the loss value and stop once some criteria is reached, e.g. return loss < 0.0001, but we will stop after a set number of iterations instead. More details about callbacks in Optimization.jl can be found here.

function callback(p, l, sol)
+    display(l)
+    plt = plot(sol, ylim = (0, 6), label = ["Current x Prediction" "Current y Prediction"])
+    scatter!(plt, t_data, xy_data', label = ["x Data" "y Data"])
+    display(plt)
+    return false
+end
callback (generic function with 1 method)

With this callback function, every step of the optimization will display both the loss value and a plot of how the solution compares to the training data.

Now, just like the first optimization tutorial, we set up our OptimizationFunction and OptimizationProblem, and then solve the OptimizationProblem. We will initialize the OptimizationProblem with the same pguess we used when setting up the ODE Model in Step 3. Observe how Optimization.solve brings the model closer to the experimental data as it iterates towards better ODE parameter values!

Note that we are using the PolyOpt() solver choice here which is discussed https://docs.sciml.ai/Optimization/dev/optimization_packages/polyopt/ since parameter estimation of non-linear differential equations is generally a non-convex problem so we want to run a stochastic algorithm (Adam) to get close to the minimum and then finish off with a quasi-newton method (L-BFGS) to find the optima. Together, this looks like:

# Set up the optimization problem with our loss function and initial guess
+adtype = AutoForwardDiff()
+pguess = [1.0, 1.2, 2.5, 1.2]
+optf = OptimizationFunction((x, _) -> loss(x), adtype)
+optprob = OptimizationProblem(optf, pguess)
+
+# Optimize the ODE parameters for best fit to our data
+pfinal = solve(optprob,
+               PolyOpt(),
+               callback = callback,
+               maxiters = 200)
+α, β, γ, δ = round.(pfinal, digits=1)
4-element Vector{Float64}:
+ 1.5
+ 1.0
+ 3.1
+ 1.0
Note

When referencing the documentation for DifferentialEquations.jl and Optimization.jl simultaneously, note that the variables f, u, and p will refer to different quantities.

DifferentialEquations.jl:

\[\frac{du}{dt} = f(u,p,t)\]

  • f in ODEProblem is the function defining the derivative du in the ODE.

    Here: lotka_volterra!

  • u in ODEProblem contains the state variables of f.

    Here: x and y

  • p in ODEProblem contains the parameter variables of f.

    Here: \alpha, \beta, \gamma, and \delta

  • t is the independent (time) variable.

    Here: indirectly defined with tspan in ODEProblem and saveat in solve

Optimization.jl:

\[\min_{u} f(u,p)\]

  • f in OptimizationProblem is the function to minimize (optimize).

    Here: the anonymous function (x, _) -> loss(x)

  • u in OptimizationProblem contains the state variables of f to be optimized.

    Here: the ODE parameters \alpha, \beta, \gamma, and \delta stored in p

  • p in OptimizationProblem contains any fixed

hyperparameters of f.

Here: our `loss` function does not require any hyperparameters, so we pass `_` for this `p`.
diff --git a/v1.5.0/getting_started/getting_started/index.html b/v1.5.0/getting_started/getting_started/index.html new file mode 100644 index 00000000000..b3f5de81030 --- /dev/null +++ b/v1.5.0/getting_started/getting_started/index.html @@ -0,0 +1,2 @@ + +Getting Started with Julia's SciML · Overview of Julia's SciML

Getting Started with Julia's SciML

Quickly: What is Julia's SciML Ecosystem?

Julia's SciML is:

  • SciPy or MATLAB's standard library but in Julia, but
  • Runs orders of magnitude faster, even outperforms C and Fortran libraries, and
  • Is fully compatible with machine learning and automatic differentiation,
  • All while having an easy-to-use high level interactive development environment.

Interested?

Introductory Tutorials

Note

Each of the SciML packages starts with its own introductory tutorial as well! Once you have started to get the hang of a few things, start checking out the introductory tutorials of the different packages. For example, the DifferentialEquations.jl getting started tutorial is a fun one!

Coming from...

Are you familiar with other scientific computing tools? Take a look at the guided introductions below.

diff --git a/v1.5.0/getting_started/installation/index.html b/v1.5.0/getting_started/installation/index.html new file mode 100644 index 00000000000..8ea359152ea --- /dev/null +++ b/v1.5.0/getting_started/installation/index.html @@ -0,0 +1,3 @@ + +Installing SciML Software · Overview of Julia's SciML

Installing SciML Software

Step 1: Install Julia

Download Julia using this website.

Note

Some Linux distributions do weird and incorrect things with Julia installations! Please install Julia using the binaries provided by the official JuliaLang website!

To ensure that you have installed Julia correctly, open it up and type versioninfo() in the REPL. It should look like the following:

(with the CPU/OS/etc. details matching your computer!)

If you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms

Optional Step 1.5: Get VS Code Setup with the Julia Extension

You can run SciML with Julia in any development environment you please, but our recommended environment is VS Code. For more information on using Julia with VS Code, check out the Julia VS Code Extension website. Let's install it!

First download VS Code from the official website.

Next, open Visual Studio Code and click Extensions.

Then, search for “Julia” in the search bar on the top of the extension tab, click on the “Julia” extension, and click the install button on the tab that opens up.

To make sure your installation is correct, try running some code. Open a new file by either going to the top left navigation bar File |> New Text File, or hitting Ctrl+n. Name your new file test.jl (important: the Julia VS Code functionality only turns on when using a .jl file!). Next, type 1+1 and hit Ctrl+Enter. A Julia REPL should pop up and the result 2 should be displayed. Your environment should look something like this:

For more help on using the VS Code editor with Julia, check out the VS Code in Julia documentation. Useful keyboard commands can be found here.

Once again, if you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms

Step 2: Install a SciML Package

SciML is over 130 Julia packages. That's too much stuff to give someone in a single download! Thus instead, the SciML organization divides its functionality into composable modules that can be mixed and matched as required. Installing SciML ecosystem functionality is equivalent to installation of such packages.

For example, do you need the differential equation solver? Then install DifferentialEquations via the command:

using Pkg;
+Pkg.add("DifferentialEquations");

in the Julia REPL. Or, for a more robust REPL experience, hit the ] command to make the blue pkg> REPL environment start, and type in add DifferentialEquations. The package REPL environment will have nice extras like auto-complete that will be useful in the future. This command should run an installation sequence and precompile all of the packages (precompile = "run a bunch of performance optimizations!"). Don't be surprised if this installation process takes ~10 minutes on older computers. During the installation, it should look like this:

And that's it!

How do I test that my installed correctly?

The best way is to build and run your first simulation!

diff --git a/v1.5.0/highlevels/array_libraries/index.html b/v1.5.0/highlevels/array_libraries/index.html new file mode 100644 index 00000000000..e1a9be92253 --- /dev/null +++ b/v1.5.0/highlevels/array_libraries/index.html @@ -0,0 +1,25 @@ + +Modeling Array Libraries · Overview of Julia's SciML

Modeling Array Libraries

RecursiveArrayTools.jl: Arrays of Arrays and Even Deeper

Sometimes, when one is creating a model, basic array types are not enough for expressing a complex concept. RecursiveArrayTools.jl gives many types, such as VectorOfArray and ArrayPartition, which allow for easily building nested array models in a way that conforms to the standard AbstractArray interface. While standard Vector{Array{Float64,N}} types may not be compatible with many equation solver libraries, these wrapped forms like VectorOfArray{Vector{Array{Float64,N}}} are, making it easy to use these more exotic array constructions.

Note that SciML's interfaces use RecursiveArrayTools.jl extensively, for example, with the timeseries solution types being AbstractVectorOfArray.

LabelledArrays.jl: Named Variables in Arrays without Overhead

Sometimes, you want to use a full domain-specific language like ModelingToolkit. Other times, you wish arrays just had a slightly nicer syntax. Don't you wish you could write the Lorenz equations like:

function lorenz_f(du, u, p, t)
+    du.x = p.σ * (u.y - u.x)
+    du.y = u.x * (p.ρ - u.z) - u.y
+    du.z = u.x * u.y - p.β * u.z
+end

without losing any efficiency? LabelledArrays.jl provides the array types to do just that. All the . accesses are resolved at compile-time, so it's a zero-overhead interface.

Note

We recommend using ComponentArrays.jl for any instance where nested accesses are required, or where the . accesses need to be views to subsets of the array.

MultiScaleArrays.jl: Multiscale Modeling to Compose with Equation Solvers

How do you encode such real-world structures in a manner that is compatible with the SciML equation solver libraries? MultiScaleArrays.jl is an answer. MultiScaleArrays.jl gives a highly flexible interface for defining multi-level types, which generates a corresponding interface as an AbstractArray. MultiScaleArrays.jl's flexibility includes the ease of resizing, allowing for models where the number of equations grows and shrinks as agents (cells) in the model divide and die.

Note

We recommend using ComponentArrays.jl instead in any instance where the resizing functionality is not used.

Third-Party Libraries to Note

ComponentArrays.jl: Arrays with Arbitrarily Nested Named Components

What if you had a set of arrays of arrays with names, but you wanted to represent them on a single contiguous vector so that linear algebra was as fast as possible, while retaining . named accesses with zero-overhead? This is what ComponentArrays.jl provides, and as such it is one of the top recommendations of AbstractArray types to be used. Multi-level definitions such as x = ComponentArray(a=5, b=[(a=20., b=0), (a=33., b=0), (a=44., b=3)], c=c) are common-place, and allow for accessing via x.b.a etc. without any performance loss. ComponentArrays are fully compatible with the SciML equation solvers. They thus can be used as initial conditions. Here's a demonstration of the Lorenz equation using ComponentArrays with Parameters.jl's @unpack:

using ComponentArrays
+using DifferentialEquations
+using Parameters: @unpack
+
+tspan = (0.0, 20.0)
+
+## Lorenz system
+function lorenz!(D, u, p, t; f = 0.0)
+    @unpack σ, ρ, β = p
+    @unpack x, y, z = u
+
+    D.x = σ * (y - x)
+    D.y = x * (ρ - z) - y - f
+    D.z = x * y - β * z
+    return nothing
+end
+
+lorenz_p = (σ = 10.0, ρ = 28.0, β = 8 / 3)
+lorenz_ic = ComponentArray(x = 0.0, y = 0.0, z = 0.0)
+lorenz_prob = ODEProblem(lorenz!, lorenz_ic, tspan, lorenz_p)

Is that beautiful? Yes, it is.

StaticArrays.jl: Statically-Defined Arrays

StaticArrays.jl is a library for statically-defined arrays. Because these arrays have type-level information for size, they recompile the solvers for every new size. They can be dramatically faster for small sizes (up to approximately size 10), but for larger equations they increase compile time with little to no benefit.

CUDA.jl: NVIDIA CUDA-Based GPU Array Computations

CUDA.jl is the library for defining arrays which live on NVIDIA GPUs (CuArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus, using CUDA.jl's CuArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a CuArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

AMDGPU.jl: AMD-Based GPU Array Computations

AMDGPU.jl is the library for defining arrays which live on AMD GPUs (ROCArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus using AMDGPU.jl's ROCArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a ROCArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

FillArrays.jl: Lazy Arrays

FillArrays.jl is a library for defining arrays with lazy values. For example, an O(1) representation of the identity matrix is given by Eye{Int}(5). FillArrays.jl is used extensively throughout the ecosystem to improve runtime and memory performance.

BandedMatrices.jl: Fast Banded Matrices

Banded matrices show up in many equation solver contexts, such as the Jacobians of many partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BandedMatrices.jl is a specialized format specifically for BandedMatrices which can be used to greatly improve performance of operations on a banded matrix.

BlockBandedMatrices.jl: Fast Block-Banded Matrices

Block banded matrices show up in many equation solver contexts, such as the Jacobians of many systems of partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BlockBandedMatrices.jl is a specialized format specifically for BlockBandedMatrices which can be used to greatly improve performance of operations on a block-banded matrix.

diff --git a/v1.5.0/highlevels/developer_documentation/index.html b/v1.5.0/highlevels/developer_documentation/index.html new file mode 100644 index 00000000000..529608ac222 --- /dev/null +++ b/v1.5.0/highlevels/developer_documentation/index.html @@ -0,0 +1,3 @@ + +Developer Documentation · Overview of Julia's SciML

Developer Documentation

For uniformity and clarity, the SciML Open-Source Software Organization has many well-defined rules and practices for its development. However, we stress one important principle:

Do not be deterred from contributing if you think you do not know everything. No one knows everything. These rules and styles are designed for iterative contributions. Open pull requests and contribute what you can with what you know, and the maintainers will help you learn and do the rest!

If you need any help contributing, please feel welcome joining our community channels.

We welcome everybody.

Getting Started With Contributing to SciML

To get started contributing to SciML, check out the following resources:

SciMLStyle: The SciML Style Guide for Julia

SciML Code Style

This is a style guide for how to program in Julia for SciML contributions. It describes everything one needs to know, from preferred naming schemes of functions to fundamental dogmas for designing traits. We stress that this style guide is meant to be comprehensive for the sake of designing automatic formatters and teaching desired rules, but complete knowledge and adherence to the style guide is not required for contributions!

COLPRAC: Contributor's Guide on Collaborative Practices for Community Packages

ColPrac: Contributor's Guide on Collaborative Practices for Community Packages

What are the rules for when PRs should be merged? What are the rules for whether to tag a major, minor, or patch release? All of these development rules are defined in COLPRAC.

DiffEq Developer Documentation

There are many solver libraries which share similar internals, such as OrdinaryDiffEq.jl, StochasticDiffEq.jl, and DelayDiffEq.jl. This section of the documentation describes the internal systems of these packages and how they are used to quickly write efficient solvers.

Third-Party Libraries to Note

Documenter.jl

Documenter.jl is the documentation generation library that the SciML organization uses, and thus its documentation is the documentation of the documentation.

JuliaFormatter.jl

JuliaFormatter.jl is the formatter used by the SciML organization to enforce the SciML Style. Setting style = "sciml" in a .JuliaFormatter.toml file of a repo and using the standard FormatCheck.yml as part of continuous integration makes JuliaFormatter check for SciML Style compliance on pull requests.

To run JuliaFormatter in a SciML repository, do:

using JuliaFormatter, DevedPackage
+JuliaFormatter.format(pkgdir(DevedPackage))

which will reformat the code according to the SciML Style.

GitHub Actions Continuous Integrations

The SciML Organization uses continuous integration testing to always ensure tests are passing when merging pull requests. The organization uses the GitHub Actions supplied by Julia Actions to accomplish this. Common continuous integration scripts are:

  • CI.yml, the standard CI script
  • Downstream.yml, used to specify packages for downstream testing. This will make packages which depend on the current package also be tested to ensure that “non-breaking changes” do not actually break other packages.
  • Documentation.yml, used to run the documentation automatic generation with Documenter.jl
  • FormatCheck.yml, used to check JuliaFormatter SciML Style compliance

CompatHelper

CompatHelper is used to automatically create pull requests whenever a dependent package is upper bounded. The results of CompatHelper PRs should be checked to ensure that the latest version of the dependencies are grabbed for the test process. After successful CompatHelper PRs, i.e. if the increase of the upper bound did not cause a break to the tests, a new version tag should follow. It is set up by adding the CompatHelper.yml GitHub action.

TagBot

TagBot automatically creates tags in the GitHub repository whenever a package is registered to the Julia General repository. It is set up by adding the TagBot.yml GitHub action.

diff --git a/v1.5.0/highlevels/equation_solvers/index.html b/v1.5.0/highlevels/equation_solvers/index.html new file mode 100644 index 00000000000..8e0f7adebac --- /dev/null +++ b/v1.5.0/highlevels/equation_solvers/index.html @@ -0,0 +1,2 @@ + +Equation Solvers · Overview of Julia's SciML

Equation Solvers

The SciML Equation Solvers cover a large set of SciMLProblems with SciMLAlgorithms that are efficient, numerically stable, and flexible. These methods tie into libraries like SciMLSensitivity.jl to be fully differentiable and compatible with machine learning pipelines, and are designed for integration with applications like parameter estimation, global sensitivity analysis, and more.

LinearSolve.jl: Unified Interface for Linear Solvers

LinearSolve.jl is the canonical library for solving LinearProblems. It includes:

  • Fast pure Julia LU factorizations which outperform standard BLAS
  • KLU for faster sparse LU factorization on unstructured matrices
  • UMFPACK for faster sparse LU factorization on matrices with some repeated structure
  • MKLPardiso wrappers for handling many sparse matrices faster than SuiteSparse (KLU, UMFPACK) methods
  • GPU-offloading for large dense matrices
  • Wrappers to all of the Krylov implementations (Krylov.jl, IterativeSolvers.jl, KrylovKit.jl) for easy testing of all of them. LinearSolve.jl handles the API differences, especially with the preconditioner definitions
  • A polyalgorithm that smartly chooses between these methods
  • A caching interface which automates caching of symbolic factorizations and numerical factorizations as optimally as possible
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

NonlinearSolve.jl: Unified Interface for Nonlinear Solvers

NonlinearSolve.jl is the canonical library for solving NonlinearProblems. It includes:

  • Fast non-allocating implementations on static arrays of common methods (Newton-Rhapson)
  • Bracketing methods (Bisection, Falsi) for methods with known upper and lower bounds (IntervalNonlinearProblem)
  • Wrappers to common other solvers (NLsolve.jl, MINPACK, KINSOL from Sundials) for trust region methods, line search-based approaches, etc.
  • Built over the LinearSolve.jl API for maximum flexibility and performance in the solving approach
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

DifferentialEquations.jl: Unified Interface for Differential Equation Solvers

DifferentialEquations.jl is the canonical library for solving DEProblems. This includes:

  • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem)
  • Ordinary differential equations (ODEs) (ODEProblem)
  • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
  • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
  • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
  • Random differential equations (RODEs or RDEs) (RODEProblem)
  • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
  • Delay differential equations (DDEs) (DDEProblem)
  • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
  • Stochastic delay differential equations (SDDEs) (SDDEProblem)
  • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
  • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)

The well-optimized DifferentialEquations solvers benchmark as some of the fastest implementations of classic algorithms. It also includes algorithms from recent research which routinely outperform the “standard” C/Fortran methods, and algorithms optimized for high-precision and HPC applications. Simultaneously, it wraps the classic C/Fortran methods, making it easy to switch over to them whenever necessary. Solving differential equations with different methods from different languages and packages can be done by changing one line of code, allowing for easy benchmarking to ensure you are using the fastest method possible.

DifferentialEquations.jl integrates with the Julia package sphere. Examples are:

  • GPU acceleration through CUDAnative.jl and CuArrays.jl
  • Automated sparsity detection with Symbolics.jl
  • Automatic Jacobian coloring with SparseDiffTools.jl, allowing for fast solutions to problems with sparse or structured (Tridiagonal, Banded, BlockBanded, etc.) Jacobians
  • Allowing the specification of linear solvers for maximal efficiency
  • Progress meter integration with the Juno IDE for estimated time to solution
  • Automatic plotting of time series and phase plots
  • Built-in interpolations
  • Wraps for common C/Fortran methods, like Sundials and Hairer's radau
  • Arbitrary precision with BigFloats and Arbfloats
  • Arbitrary array types, allowing the definition of differential equations on matrices and distributed arrays
  • Unit-checked arithmetic with Unitful

Optimization.jl: Unified Interface for Optimization

Optimization.jl is the canonical library for solving OptimizationProblems. It includes wrappers of most of the Julia nonlinear optimization ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

Integrals.jl: Unified Interface for Numerical Integration

Integrals.jl is the canonical library for solving IntegralsProblems. It includes wrappers of most of the Julia quadrature ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

  • Gauss-Kronrod quadrature
  • Cubature methods (both h and p cubature)
  • Adaptive Monte Carlo methods

JumpProcesses.jl: Stochastic Simulation Algorithms for Jump Processes, Jump-ODEs, and Jump-Diffusions

JumpProcesses.jl is the library for Poisson jump processes, also known as chemical master equations or Gillespie simulations, for simulating chemical reaction networks and other applications. It allows for solving with many methods, including:

  • Direct: the Gillespie Direct method SSA.
  • RDirect: A variant of Gillespie's Direct method that uses rejection to sample the next reaction.
  • DirectCR: The Composition-Rejection Direct method of Slepoy et al. For large networks and linear chain-type networks, it will often give better performance than Direct. (Requires dependency graph, see below.)
  • DirectFW: the Gillespie Direct method SSA with FunctionWrappers. This aggregator uses a different internal storage format for collections of ConstantRateJumps.
  • FRM: the Gillespie first reaction method SSA. Direct should generally offer better performance and be preferred to FRM.
  • FRMFW: the Gillespie first reaction method SSA with FunctionWrappers.
  • NRM: The Gibson-Bruck Next Reaction Method. For some reaction network structures, this may offer better performance than Direct (for example, large, linear chains of reactions). (Requires dependency graph, see below.)
  • RSSA: The Rejection SSA (RSSA) method of Thanh et al. With RSSACR, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • RSSACR: The Rejection SSA (RSSA) with Composition-Rejection method of Thanh et al. With RSSA, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • SortingDirect: The Sorting Direct Method of McCollum et al. It will usually offer performance as good as Direct, and for some systems can offer substantially better performance. (Requires dependency graph, see below.)

The design of JumpProcesses.jl composes with DifferentialEquations.jl, allowing for discrete stochastic chemical reactions to be easily mixed with differential equation models, allowing for simulation of hybrid systems, jump diffusions, and differential equations driven by Levy processes.

In addition, JumpProcesses's interfaces allow for solving with regular jump methods, such as adaptive Tau-Leaping.

Third-Party Libraries to Note

JuMP.jl: Julia for Mathematical Programming

While Optimization.jl is the preferred library for nonlinear optimization, for all other forms of optimization Julia for Mathematical Programming (JuMP) is the star. JuMP is the leading choice in Julia for doing:

  • Linear Programming
  • Quadratic Programming
  • Convex Programming
  • Conic Programming
  • Semidefinite Programming
  • Mixed-Complementarity Programming
  • Integer Programming
  • Mixed Integer (nonlinear/linear) Programming
  • (Mixed Integer) Second Order Conic Programming

JuMP can also be used for some nonlinear programming, though the Optimization.jl bindings to the JuMP solvers (via MathOptInterface.jl) is generally preferred.

FractionalDiffEq.jl: Fractional Differential Equation Solvers

FractionalDiffEq.jl is a set of high-performance solvers for fractional differential equations.

ManifoldDiffEq.jl: Solvers for Differential Equations on Manifolds

ManifoldDiffEq.jl is a set of high-performance solvers for differential equations on manifolds using methods such as Lie Group actions and frozen coefficients (Crouch-Grossman methods). These solvers can in many cases out-perform the OrdinaryDiffEq.jl nonautonomous operator ODE solvers by using methods specialized on manifold definitions of ManifoldsBase.

Manopt.jl: Optimization on Manifolds

ManOpt.jl allows for easy and efficient solving of nonlinear optimization problems on manifolds.

diff --git a/v1.5.0/highlevels/function_approximation/index.html b/v1.5.0/highlevels/function_approximation/index.html new file mode 100644 index 00000000000..5a616e285f6 --- /dev/null +++ b/v1.5.0/highlevels/function_approximation/index.html @@ -0,0 +1,2 @@ + +Function Approximation · Overview of Julia's SciML

Function Approximation

While SciML is not an ecosystem for machine learning, SciML has many libraries for doing machine learning with its equation solver libraries and machine learning libraries which are integrated into the equation solvers.

Surrogates.jl: Easy Generation of Differentiable Surrogate Models

Surrogates.jl is a library for generating surrogate approximations to computationally expensive simulations. It has the following high-dimensional function approximators:

  • Kriging
  • Kriging using Stheno
  • Radial Basis
  • Wendland
  • Linear
  • Second Order Polynomial
  • Support Vector Machines (Wait for LIBSVM resolution)
  • Neural Networks
  • Random Forests
  • Lobachevsky splines
  • Inverse-distance
  • Polynomial expansions
  • Variable fidelity
  • Mixture of experts (Waiting GaussianMixtures package to work on v1.5)
  • Earth
  • Gradient Enhanced Kriging

ReservoirComputing.jl: Fast and Flexible Reservoir Computing Methods

ReservoirComputing.jl is a library for doing machine learning using reservoir computing techniques, such as with methods like Echo State Networks (ESNs). Its reservoir computing methods make it stabilized for usage with difficult equations like stiff dynamics, chaotic equations, and more.

Third-Party Libraries to Note

Flux.jl: the ML library that doesn't make you tensor

Flux.jl is the most popular machine learning library in the Julia programming language. SciML's libraries are heavily tested with it and its automatic differentiation engine Zygote.jl for composability and compatibility.

Lux.jl: Explicitly Parameterized Neural Networks in Julia

Lux.jl is a library for fully explicitly parameterized neural networks. Thus, while alternative interfaces are required to use Flux with many equation solvers (i.e. Flux.destructure), Lux.jl's explicit design marries effortlessly with the SciML equation solver libraries. For this reason, SciML's library are also heavily tested with Lux to ensure compatibility with neural network definitions from here.

SimpleChains.jl: Fast Small-Scale Machine Learning

SimpleChains.jl is a library specialized for small-scale machine learning. It uses non-allocating mutating forms to be highly efficient for the cases where matrix multiplication kernels cannot overcome the common overheads of machine learning libraries. Thus for SciML cases with small neural networks (<100 node layers) and non-batched usage (many/most use cases), SimpleChains.jl can be the fastest choice for the neural network definitions.

NNLib.jl: Neural Network Primitives with Multiple Backends

NNLib.jl is the core library which defines the handling of common functions, like conv and how they map to device accelerators such as the NVIDIA cudnn. This library can thus be used to directly grab many of the core functions used in machine learning, such as common activation functions and gather/scatter operations, without depending on the given style of any machine learning library.

GeometricFlux.jl: Geometric Deep Learning and Graph Neural Networks

GeometricFlux.jl is a library for graph neural networks and geometric deep learning. It is the one that is used and tested by the SciML developers for mixing with equation solver applications.

AbstractGPs.jl: Fast and Flexible Gaussian Processes

AbstractGPs.jl is the fast and flexible Gaussian Process library that is used by the SciML packages and recommended for downstream usage.

MLDatasets.jl: Common Machine Learning Datasets

MLDatasets.jl is a common interface for accessing common machine learning datasets. For example, if you want to run a test on MNIST data, MLDatasets is the quickest way to obtain it.

MLUtils.jl: Utility Functions for Machine Learning Pipelines

MLUtils.jl is a library of utility functions for making writing common machine learning pipelines easier. This includes functionality for:

  • An extensible dataset interface (numobs and getobs).
  • Data iteration and data loaders (eachobs and DataLoader).
  • Lazy data views (obsview).
  • Resampling procedures (undersample and oversample).
  • Train/test splits (splitobs)
  • Data partitioning and aggregation tools (batch, unbatch, chunk, group_counts, group_indices).
  • Folds for cross-validation (kfolds, leavepout).
  • Datasets lazy transformations (mapobs, filterobs, groupobs, joinobs, shuffleobs).
  • Toy datasets for demonstration purpose.
  • Other data handling utilities (flatten, normalise, unsqueeze, stack, unstack).
diff --git a/v1.5.0/highlevels/implicit_layers/index.html b/v1.5.0/highlevels/implicit_layers/index.html new file mode 100644 index 00000000000..53eafe855fa --- /dev/null +++ b/v1.5.0/highlevels/implicit_layers/index.html @@ -0,0 +1,2 @@ + +Implicit Layer Deep Learning · Overview of Julia's SciML

Implicit Layer Deep Learning

Implicit layer deep learning is a field which uses implicit rules, such as differential equations and nonlinear solvers, to define the layers of neural networks. This field has brought the potential to automatically optimize network depth and improve training performance. SciML's differentiable solver ecosystem is specifically designed to accommodate implicit layer methodologies, and provides libraries with pre-built layers for common methods.

DiffEqFlux.jl: High Level Pre-Built Architectures for Implicit Deep Learning

DiffEqFlux.jl is a library of pre-built architectures for implicit deep learning, including layer definitions for methods like:

DeepEquilibriumNetworks.jl: Deep Equilibrium Models Made Fast

DeepEquilibriumNetworks.jl is a library of optimized layer implementations for Deep Equilibrium Models (DEQs). It uses special training techniques such as implicit-explicit regularization in order to accelerate the convergence over traditional implementations, all while using the optimized and flexible SciML libraries under the hood.

diff --git a/v1.5.0/highlevels/interfaces/index.html b/v1.5.0/highlevels/interfaces/index.html new file mode 100644 index 00000000000..8101f1f8cf6 --- /dev/null +++ b/v1.5.0/highlevels/interfaces/index.html @@ -0,0 +1,2 @@ + +The SciML Interface Libraries · Overview of Julia's SciML

The SciML Interface Libraries

SciMLBase.jl: The SciML Common Interface

SciMLBase.jl defines the core interfaces of the SciML libraries, such as the definitions of abstract types like SciMLProblem, along with their instantiations like ODEProblem. While SciMLBase.jl is insufficient to solve any equations, it holds all the equation definitions, and thus downstream libraries which wish to allow for using SciML solvers without depending on any solvers can directly depend on SciMLBase.jl.

SciMLOperators.jl: The AbstractSciMLOperator Interface

SciMLOperators.jl defines the interface for how matrix-free linear and affine operators are defined and used throughout the SciML ecosystem.

DiffEqNoiseProcess.jl: The SciML Common Noise Interface

DiffEqNoiseProcess.jl defines the common interface for stochastic noise processes used by the equation solvers of the SciML ecosystem.

CommonSolve.jl: The Common Definition of Solve

CommonSolve.jl is the library that defines the solve, solve!, and init interfaces which are used throughout all the SciML equation solvers. It's defined as an extremely lightweight library so that other ecosystems can build on the same solve definition without clashing with SciML when both export.

Static.jl: A Shared Interface for Static Compile-Time Computation

Static.jl is a set of statically parameterized types for performing operations in a statically-defined (compiler-optimized) way with respect to values.

DiffEqBase.jl: A Library of Shared Components for Differential Equation Solvers

DiffEqBase.jl is the core shared component of the DifferentialEquations.jl ecosystem. It's not intended for non-developer users to interface directly with, instead it's used for the common functionality for uniformity of implementation between the solver libraries.

Third-Party Libraries to Note

ArrayInterface.jl: Extensions to the Julia AbstractArray Interface

ArrayInterface.jl are traits and functions which extend the Julia Base AbstractArray interface, giving a much larger set of queries to allow for writing high-performance generic code over all array types. For example, functions include can_change_size to know if an AbstractArray type is compatible with resize!, fast_scalar_indexing to know whether direct scalar indexing A[i] is optimized, and functions like findstructralnz to get the structural non-zeros of arbitrary sparse and structured matrices.

Adapt.jl: Conversion to Allow Chip-Generic Programs

Adapt.jl makes it possible to write code that is generic to the compute devices, i.e. code that works on both CPUs and GPUs. It defines the adapt function which acts like convert(T, x), but without the restriction of returning a T. This allows you to “convert” wrapper types, like Adjoint to be GPU compatible (for example) without throwing away the wrapper.

Example usage:

adapt(CuArray, ::Adjoint{Array})::Adjoint{CuArray}

AbstractFFTs.jl: High Level Shared Interface for Fast Fourier Transformation Libraries

AbstractFFTs.jl defines the common interface for Fast Fourier Transformations (FFTs) in Julia. Similar to SciMLBase.jl, AbstractFFTs.jl is not a solver library but instead a shared API which is extended by solver libraries such as FFTW.jl. Code written using AbstractFFTs.jl can be made compatible with FFT libraries without having an explicit dependency on a solver.

GPUArrays.jl: Common Interface for GPU-Based Array Types

GPUArrays.jl defines the shared higher-level operations for GPU-based array types, like CUDA.jl's CuArray and AMDGPU.jl's ROCmArray. Packages in SciML use the designation x isa AbstractGPUArray in order to find out if a user's operation is on the GPU and specialize computations.

RecipesBase.jl: Standard Plotting Recipe Interface

RecipesBase.jl defines the common interface for plotting recipes, composable transformations of Julia data types into simpler data types for visualization with libraries such as Plots.jl and Makie.jl. SciML libraries attempt to always include plot recipes wherever possible for ease of visualization.

Tables.jl: Common Interface for Tabular Data Types

Tables.jl is a common interface for defining tabular data structures, such as DataFrames.jl. SciML's libraries extend the Tables.jl interface to allow for automated conversions into data frame libraries without explicit dependence on any singular implementation.

diff --git a/v1.5.0/highlevels/inverse_problems/index.html b/v1.5.0/highlevels/inverse_problems/index.html new file mode 100644 index 00000000000..7d0d86a6795 --- /dev/null +++ b/v1.5.0/highlevels/inverse_problems/index.html @@ -0,0 +1,2 @@ + +Parameter Estimation, Bayesian Analysis, and Inverse Problems · Overview of Julia's SciML

Parameter Estimation, Bayesian Analysis, and Inverse Problems

Parameter estimation for models and equations, also known as dynamic data analysis, solving the inverse problem, or Bayesian posterior estimation (when done probabilistically), is provided by the SciML tools for the equations in its set. In this introduction, we briefly present the relevant packages that facilitate parameter estimation, namely:

We also provide information regarding the respective strengths of these packages so that you can easily decide which one suits your needs best.

SciMLSensitivity.jl: Local Sensitivity Analysis and Automatic Differentiation Support for Solvers

SciMLSensitivity.jl is the system for local sensitivity, which all other inverse problem methods rely on. This package defines the interactions between the equation solvers and automatic differentiation, defining fast overloads for forward and adjoint (reverse) sensitivity analysis for fast gradient and Jacobian calculations with respect to model inputs. Its documentation covers how to use direct differentiation of equation solvers in conjunction with tools like Optimization.jl to perform model calibration of ODEs against data, PDE-constrained optimization, nonlinear optimal controls analysis, and much more. As a lower level tool, this library is very versatile, feature-rich, and high-performance, giving all the tools required but not directly providing a higher level interface.

Note

Sensitivity analysis is kept in a separate library from the solvers (SciMLSensitivity.jl), in order to not require all equation solvers to have a dependency on all automatic differentiation libraries. If automatic differentiation is applied to a solver library without importing SciMLSensitivity.jl, an error is thrown letting the user know to import SciMLSensitivity.jl for the functionality to exist.

DataDrivenDiffEq.jl: Data-Driven Modeling and Equation Discovery

The distinguishing feature of this package is that its ultimate goal is to identify the differential equation model that generated the input data. Depending on the user's needs, the package can provide structural identification of a given differential equation (output in a symbolic form) or structural estimation (output as a function for prediction purposes).

DiffEqParamEstim.jl: Simplified Parameter Estimation Interface

This package is for simplified parameter estimation. While not as flexible of a system like DiffEqFlux.jl, it provides ready-made functions for doing standard optimization procedures like L2 fitting and MAP estimates. Among other features, it allows for the optimization of parameters in ODEs, stochastic problems, and delay differential equations.

DiffEqBayes.jl: Simplified Bayesian Estimation Interface

As the name suggests, this package has been designed to provide the estimation of differential equations parameters by Bayesian methods. It works in conjunction with Turing.jl, CmdStan.jl, DynamicHMC.jl, and ApproxBayes.jl. While not as flexible as direct usage of DiffEqFlux.jl or Turing.jl, DiffEqBayes.jl can be an approachable interface for those not familiar with Bayesian estimation, and provides a nice way to use Stan from pure Julia.

Third-Party Tools of Note

Turing.jl: A Flexible Probabilistic Programming Language for Bayesian Analysis

In the context of differential equations and parameter estimation, Turing.jl allows for a Bayesian estimation of differential equations (used in conjunction with the high-level package DiffEqBayes.jl). For more examples on combining Turing.jl with DiffEqBayes.jl, see the documentation below. It is important to note that Turing.jl can also perform Bayesian estimation without relying on DiffEqBayes.jl (for an example, consult this tutorial).

Topopt.jl: Topology Optimization in Julia

Topopt.jl solves topology optimization problems which are inverse problems on partial differential equations, solving for an optimal domain.

Recommended Automatic Differentiation Libraries

Solving inverse problems commonly requires using automatic differentiation (AD). SciML includes extensive support for automatic differentiation throughout its solvers, though some AD libraries are more tested than others. The following libraries are the current recommendations of the SciML developers.

ForwardDiff.jl: Operator-Overloading Forward Mode Automatic Differentiation

ForwardDiff.jl is a library for operator-overloading based forward-mode automatic differentiation. It's commonly used as the default method for generating Jacobians throughout the SciML solver libraries.

Note

Because ForwardDiff.jl uses an operator overloading approach, uses of ForwardDiff.jl require that any caches for non-allocating mutating code allows for Dual numbers. To allow such code to be ForwardDiff.jl-compatible, see PreallocationTools.jl.

Enzyme.jl: LLVM-Level Forward and Reverse Mode Automatic Differentiation

Enzyme.jl is an LLVM-level AD library for forward and reverse automatic differentiation. It supports many features required for high performance, such as being able to differentiate mutating and interleave compiler optimization with the AD passes. However, it does not support all of the Julia runtime, and thus some code with many dynamic behaviors and garbage collection (GC) invocations can be incompatible with Enzyme. Enzyme.jl is quickly becoming the new standard AD for SciML.

Zygote.jl: Julia-Level Source-to-Source Reverse Mode Automatic Differentiation

Zygote.jl is the current standard user-level reverse-mode automatic differentiation library for the SciML solvers. User-level means that many library tutorials, like in SciMLSensitivity.jl and DiffEqFlux.jl, showcase user code using Zygote.jl. This is because Zygote.jl is the AD engine associated with the Flux machine learning library. However, Zygote.jl has many limitations which limits its performance in equation solver contexts, such as an inability to handle mutation and introducing many small allocations and type-instabilities. For this reason, the SciML equation solvers define differentiation overloads using ChainRules.jl, meaning that the equation solvers tend not to use Zygote.jl internally even if the user code uses Zygote.gradient. In this manner, the speed and performance of more advanced techniques can be preserved while using the Julia standard.

FiniteDiff.jl: Fast Finite Difference Approximations

FiniteDiff.jl is the preferred fallback library for numerical differentiation and is commonly used by SciML solver libraries when automatic differentiation is disabled.

SparseDiffTools.jl: Tools for Fast Automatic Differentiation with Sparse Operators

SparseDiffTools.jl is a library for sparse automatic differentiation. It's used internally by many of the SciML equation solver libraries, which explicitly expose interfaces for colorvec color vectors generated by SparseDiffTools.jl's methods. SparseDiffTools.jl also includes many features useful to users, such as operators for matrix-free Jacobian-vector and Hessian-vector products.

diff --git a/v1.5.0/highlevels/learning_resources/index.html b/v1.5.0/highlevels/learning_resources/index.html new file mode 100644 index 00000000000..865294ae5a1 --- /dev/null +++ b/v1.5.0/highlevels/learning_resources/index.html @@ -0,0 +1,2 @@ + +Curated Learning, Teaching, and Training Resources · Overview of Julia's SciML

Curated Learning, Teaching, and Training Resources

While the SciML documentation is made to be comprehensive, there will always be good alternative resources. The purpose of this section of the documentation is to highlight the alternative resources which can be helpful for learning how to use the SciML Open-Source Software libraries.

JuliaCon and SciMLCon Videos

Many tutorials and introductions to packages have been taught through previous JuliaCon/SciMLCon workshops and talks. The following is a curated list of such training videos:

SciML Book: Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications

The book Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications is a compilation of the lecture notes from the MIT Course 18.337J/6.338J: Parallel Computing and Scientific Machine Learning. It contains a walkthrough of many of the methods implemented in the SciML libraries, as well as how to understand much of the functionality at a deeper level. This course was intended for MIT graduate students in engineering, computer science, and mathematics and thus may have a high prerequisite requirement than many other resources.

sir-julia: Various implementations of the classical SIR model in Julia

For those who like to learn by example, the repository sir-julia is a great resource! It showcases how to use the SciML libraries in many different ways to simulate different variations of the classic SIR epidemic model.

Other Books Featuring SciML

diff --git a/v1.5.0/highlevels/model_libraries_and_importers/index.html b/v1.5.0/highlevels/model_libraries_and_importers/index.html new file mode 100644 index 00000000000..bba6963b540 --- /dev/null +++ b/v1.5.0/highlevels/model_libraries_and_importers/index.html @@ -0,0 +1,2 @@ + +Model Libraries and Importers · Overview of Julia's SciML

Model Libraries and Importers

Models are passed on from generation to generation. Many models are not built from scratch but have a legacy of the known physics, biology, and chemistry embedded into them. Julia's SciML offers a range of pre-built modeling tools, from reusable acausal components to direct imports from common file formats.

ModelingToolkitStandardLibrary.jl: A Standard Library for ModelingToolkit

Given the composable nature of acausal modeling systems, it's helpful to not have to define every component from scratch and instead build off a common base of standard components. ModelingToolkitStandardLibrary.jl is that library. It provides components for standard models to start building everything from circuits and engines to robots.

DiffEqCallbacks.jl: Pre-Made Callbacks for DifferentialEquations.jl

DiffEqCallbacks.jl has many event handling and callback definitions which allow for quickly building up complex differential equation models. It includes:

  • Callbacks for specialized output and saving procedures
  • Callbacks for enforcing domain constraints, positivity, and manifolds
  • Timed callbacks for periodic dosing, presetting of tstops, and more
  • Callbacks for determining and terminating at steady state
  • Callbacks for controlling stepsizes and enforcing CFL conditions
  • Callbacks for quantifying uncertainty with respect to numerical errors

SBMLToolkit.jl: SBML Import

SBMLToolkit.jl is a library for reading SBML files into the standard formats for Catalyst.jl and ModelingToolkit.jl. There are well over one thousand biological models available in the BioModels Repository.

CellMLToolkit.jl: CellML Import

CellMLToolkit.jl is a library for reading CellML files into the standard formats for ModelingToolkit.jl. There are several hundred biological models available in the CellML Model Repository.

ReactionNetworkImporters.jl: BioNetGen Import

ReactionNetworkImporters.jl is a library for reading BioNetGen .net files and various stoichiometry matrix representations into the standard formats for Catalyst.jl and ModelingToolkit.jl.

diff --git a/v1.5.0/highlevels/modeling_languages/index.html b/v1.5.0/highlevels/modeling_languages/index.html new file mode 100644 index 00000000000..b8bfd7b51be --- /dev/null +++ b/v1.5.0/highlevels/modeling_languages/index.html @@ -0,0 +1,2 @@ + +Modeling Languages · Overview of Julia's SciML

Modeling Languages

While in theory one can build perfect code for all models from scratch, in practice many scientists and engineers need or want some help! The SciML modeling tools provide a higher level interface over the equation solver, which helps the translation from good models to good simulations in a way that abstracts away the mathematical and computational details without giving up performance.

ModelingToolkit.jl: Acausal Symbolic Modeling

Acausal modeling is an extension of causal modeling that is more composable and allows for more code reuse. Build a model of an electric engine, then build a model of a battery, and now declare connections by stating "the voltage at the engine equals the voltage at the connector of the battery", and generate the composed model. The tool for this is ModelingToolkit.jl. ModelingToolkit.jl is a sophisticated symbolic modeling library which allows for specifying these types of large-scale differential equation models in a simple way, abstracting away the computational details. However, its symbolic analysis allows for generating much more performant code for differential-algebraic equations than most users could ever write by hand, with its structural_simplify automatically correcting the model to improve parallelism, numerical stability, and automatically remove variables which it can show are redundant.

ModelingToolkit.jl is the base of the SciML symbolic modeling ecosystem, defining the AbstractSystem types, such as ODESystem, SDESystem, OptimizationSystem, PDESystem, and more, which are then used by all the other modeling tools. As such, when using other modeling tools like Catalyst.jl, the reference for all the things that can be done with the symbolic representation is simply ModelingToolkit.jl.

Catalyst.jl: Chemical Reaction Networks (CRN), Systems Biology, and Quantitative Systems Pharmacology (QSP) Modeling

Catalyst.jl is a modeling interface for efficient simulation of mass action ODE, chemical Langevin SDE, and stochastic chemical kinetics jump process (i.e. chemical master equation) models for chemical reaction networks and population processes. It uses a highly intuitive chemical reaction syntax interface, which generates all the extra functionality necessary for the fastest use with JumpProcesses.jl, DifferentialEquations.jl, and higher level SciML libraries. Its ReactionSystem type is a programmable extension of the ModelingToolkit AbstractSystem interface, meaning that complex reaction systems are represented symbolically, and then compiled to optimized representations automatically when converting ReactionSystems to concrete ODE/SDE/jump process representations. Catalyst also provides functionality to support chemical reaction network and steady-state analysis.

For an overview of the library, see Modeling Biochemical Systems with Catalyst.jl - Samuel Isaacson

NBodySimulator.jl: A differentiable simulator for N-body problems, including astrophysical and molecular dynamics

NBodySimulator.jl is a differentiable simulator for N-body problems, including astrophysical and molecular dynamics. It uses the DifferentialEquations.jl solvers, allowing for one to choose between a large variety of symplectic integration schemes. It implements many of the thermostats required for doing standard molecular dynamics approximations.

DiffEqFinancial.jl: Financial models for use in the DifferentialEquations ecosystem

The goal of DiffEqFinancial.jl is to be a feature-complete set of solvers for the types of problems found in libraries like QuantLib, such as the Heston process or the Black-Scholes model.

ParameterizedFunctions.jl: Simple Differential Equation Definitions Made Easy

This image that went viral is actually runnable code from ParameterizedFunctions.jl. Define equations and models using a very simple high-level syntax and let the code generation tools build symbolic fast Jacobian, gradient, etc. functions for you.

Third-Party Tools of Note

MomentClosure.jl: Automated Generation of Moment Closure Equations

MomentClosure.jl is a library for generating the moment closure equations for a given chemical master equation or stochastic differential equation. Thus instead of solving a stochastic model thousands of times to find the mean and variance, this library can generate the deterministic equations for how the mean and variance evolve in order to be solved in a single run. MomentClosure.jl uses Catalyst ReactionSystem and ModelingToolkit SDESystem types as the input for its symbolic generation processes.

Agents.jl: Agent-Based Modeling Framework in Julia

If one wants to do agent-based modeling in Julia, Agents.jl is the go-to library. It's fast and flexible, making it a solid foundation for any agent-based model.

Unitful.jl: A Julia package for physical units

Supports not only SI units, but also any other unit system. Unitful.jl has minimal run-time penalty of units. Includes facilities for dimensional analysis, and integrates easily with the usual mathematical operations and collections that are defined in Julia.

ReactionMechanismSimulator.jl: Simulation and Analysis of Large Chemical Reaction Systems

ReactionMechanismSimulator.jl is a tool for simulating and analyzing large chemical reaction mechanisms. It interfaces with the ReactionMechanismGenerator suite for automatically constructing reaction pathways from chemical components to quickly build realistic models of chemical systems.

FiniteStateProjection.jl: Direct Solution of Chemical Master Equations

FiniteStateProjection.jl is a library for finite state projection direct solving of the chemical master equation. It automatically converts the Catalyst ReactionSystem definitions into ModelingToolkit ODESystem representations for the evolution of probability distributions to allow for directly solving the weak form of the stochastic model.

AlgebraicPetri.jl: Applied Category Theory of Modeling

AlgebraicPetri.jl is a library for automating the intuitive generation of dynamical models using a Category theory-based approach.

QuantumOptics.jl: Simulating quantum systems.

QuantumOptics.jl makes it easy to simulate various kinds of quantum systems. It is inspired by the Quantum Optics Toolbox for MATLAB and the Python framework QuTiP.

diff --git a/v1.5.0/highlevels/numerical_utilities/index.html b/v1.5.0/highlevels/numerical_utilities/index.html new file mode 100644 index 00000000000..a1aa26e4ed4 --- /dev/null +++ b/v1.5.0/highlevels/numerical_utilities/index.html @@ -0,0 +1,2 @@ + +SciML Numerical Utility Libraries · Overview of Julia's SciML

SciML Numerical Utility Libraries

ExponentialUtilities.jl: Faster Matrix Exponentials

ExponentialUtilities.jl is a library for efficient computation of matrix exponentials. While Julia has a built-in exp(A) method, ExponentialUtilities.jl offers many features around this to improve performance in scientific contexts, including:

  • Faster methods for (non-allocating) matrix exponentials via exponential!
  • Methods for computing matrix exponential that are generic to number types and arrays (i.e. GPUs)
  • Methods for computing Arnoldi iterations on Krylov subspaces
  • Direct computation of exp(t*A)*v, i.e. exponentiation of a matrix times a vector, without computing the matrix exponential
  • Direct computation of ϕ_m(t*A)*v operations, where ϕ_0(z) = exp(z) and ϕ_(k+1)(z) = (ϕ_k(z) - 1) / z

ExponentialUtilities.jl includes complex adaptive time stepping techniques such as KIOPS in order to perform these calculations in a fast and numerically-stable way.

QuasiMonteCarlo.jl: Fast Quasi-Random Number Generation

QuasiMonteCarlo.jl is a library for fast generation of low discrepancy Quasi-Monte Carlo samples, using methods like:

  • GridSample(dx) where the grid is given by lb:dx[i]:ub in the ith direction.
  • UniformSample for uniformly distributed random numbers.
  • SobolSample for the Sobol sequence.
  • LatinHypercubeSample for a Latin Hypercube.
  • LatticeRuleSample for a randomly-shifted rank-1 lattice rule.
  • LowDiscrepancySample(base) where base[i] is the base in the ith direction.
  • GoldenSample for a Golden Ratio sequence.
  • KroneckerSample(alpha, s0) for a Kronecker sequence, where alpha is a length-d vector of irrational numbers (often sqrt(d)) and s0 is a length-d seed vector (often 0).
  • SectionSample(x0, sampler) where sampler is any sampler above and x0 is a vector of either NaN for a free dimension or some scalar for a constrained dimension.

DataInterpolations.jl: One-Dimensional Interpolations

DataInterpolations.jl is a library of one-dimensional interpolation schemes which are composable with automatic differentiation and the SciML ecosystem. It includes direct interpolation methods and regression techniques for handling noisy data. Its methods include:

  • ConstantInterpolation(u,t) - A piecewise constant interpolation.

  • LinearInterpolation(u,t) - A linear interpolation.

  • QuadraticInterpolation(u,t) - A quadratic interpolation.

  • LagrangeInterpolation(u,t,n) - A Lagrange interpolation of order n.

  • QuadraticSpline(u,t) - A quadratic spline interpolation.

  • CubicSpline(u,t) - A cubic spline interpolation.

  • BSplineInterpolation(u,t,d,pVec,knotVec) - An interpolation B-spline. This is a B-spline which hits each of the data points. The argument choices are:

    • d - degree of B-spline
    • pVec - Symbol to Parameters Vector, pVec = :Uniform for uniform spaced parameters and pVec = :ArcLen for parameters generated by chord length method.
    • knotVec - Symbol to Knot Vector, knotVec = :Uniform for uniform knot vector, knotVec = :Average for average spaced knot vector.
  • BSplineApprox(u,t,d,h,pVec,knotVec) - A regression B-spline which smooths the fitting curve. The argument choices are the same as the BSplineInterpolation, with the additional parameter h<length(t) which is the number of control points to use, with smaller h indicating more smoothing.

  • Curvefit(u,t,m,p,alg) - An interpolation which is done by fitting a user-given functional form m(t,p) where p is the vector of parameters. The user's input p is an initial value for a least-square fitting, alg is the algorithm choice used to optimize the cost function (sum of squared deviations) via Optim.jl and optimal ps are used in the interpolation.

These interpolations match the SciML interfaces and have direct support for packages like ModelingToolkit.jl.

PoissonRandom.jl: Fast Poisson Random Number Generation

PoissonRandom.jl is just fast Poisson random number generation for Poisson processes, like chemical master equations.

PreallocationTools.jl: Write Non-Allocating Code Easier

PreallocationTools.jl is a library of tools for writing non-allocating code that interacts well with advanced features like automatic differentiation and symbolics.

RuntimeGeneratedFunctions.jl: Efficient Staged Programming in Julia

RuntimeGeneratedFunctions.jl allows for staged programming in Julia, compiling functions at runtime with full optimizations. This is used by many libraries such as ModelingToolkit.jl to allow for runtime code generation for improved performance.

EllipsisNotation.jl: Implementation of Ellipsis Array Slicing

EllipsisNotation.jl defines the ellipsis array slicing notation for Julia. It uses .. as a catch-all for “all dimensions”, allowing for indexing like [..,1] to mean [:,:,:,1] on four dimensional arrays, in a way that is generic to the number of dimensions in the underlying array.

Third-Party Libraries to Note

Distributions.jl: Representations of Probability Distributions

Distributions.jl is a library for defining distributions in Julia. It's used all throughout the SciML libraries for specifications of probability distributions.

Note

For full compatibility with automatic differentiation, see DistributionsAD.jl

FFTW.jl: Fastest Fourier Transformation in the West

FFTW.jl is the preferred library for fast Fourier Transformations on the CPU.

SpecialFunctions.jl: Implementations of Mathematical Special Functions

SpecialFunctions.jl is a library of implementations of special functions, like Bessel functions and error functions (erf). This library is compatible with automatic differentiation.

LoopVectorization.jl: Automated Loop Accelerator

LoopVectorization.jl is a library which provides the @turbo and @tturbo macros for accelerating the computation of loops. This can be used to accelerating the model functions sent to the equation solvers, for example, accelerating handwritten PDE discretizations.

Polyester.jl: Cheap Threads

Polyester.jl is a cheaper version of threads for Julia, which use a set pool of threads for lower overhead. Note that Polyester does not compose with the standard Julia composable threading infrastructure, and thus one must take care not to compose two levels of Polyester, as this will oversubscribe the computation and lead to performance degradation. Many SciML solvers have options to use Polyester for threading to achieve the top performance.

Tullio.jl: Fast Tensor Calculations and Einstein Notation

Tullio.jl is a library for fast tensor calculations with Einstein notation. It allows for defining operations which are compatible with automatic differentiation, GPUs, and more.

ParallelStencil.jl: High-Level Code for Parallelized Stencil Computations

ParallelStencil.jl is a library for writing high-level code for parallelized stencil computations. It is compatible with SciML equation solvers and is thus a good way to generate GPU and distributed parallel model code.

Julia Utilities

StaticCompiler.jl

StaticCompiler.jl is a package for generating static binaries from Julia code. It only supports a subset of Julia, so not all equation solver algorithms are compatible with StaticCompiler.jl.

PackageCompiler.jl

PackageCompiler.jl is a package for generating shared libraries from Julia code. It builds the entirety of Julia by bundling a system image with the Julia runtime. It thus builds complete binaries that can hold all the functionality of SciML. Furthermore, it can also be used to generate new system images to decrease startup times and remove JIT-compilation from SciML usage.

diff --git a/v1.5.0/highlevels/parameter_analysis/index.html b/v1.5.0/highlevels/parameter_analysis/index.html new file mode 100644 index 00000000000..238dc25771d --- /dev/null +++ b/v1.5.0/highlevels/parameter_analysis/index.html @@ -0,0 +1,2 @@ + +Parameter Analysis Utilities · Overview of Julia's SciML

Parameter Analysis Utilities

GlobalSensitivity.jl: Global Sensitivity Analysis

Derivatives calculate the local sensitivity of a model, i.e. the change in the simulation's outcome if one were to change the parameter with respect to some chosen part of the parameter space. But how does a simulation's output change “in general” with respect to a given parameter? That is what global sensitivity analysis (GSA) computes, and thus GlobalSensitivity.jl is the way to answer that question. GlobalSensitivity.jl includes a wide array of methods, including:

  • Morris's method
  • Sobol's method
  • Regression methods (PCC, SRC, Pearson)
  • eFAST
  • Delta Moment-Independent method
  • Derivative-based Global Sensitivity Measures (DGSM)
  • EASI
  • Fractional Factorial method
  • Random Balance Design FAST method

StructuralIdentifiability.jl: Identifiability Analysis Made Simple

Performing parameter estimation from a data set means attempting to recover parameters like reaction rates by fitting some model to the data. But how do you know whether you have enough data to even consider getting the “correct” parameters back? StructuralIdentifiability.jl allows for running a structural identifiability analysis on a given model to determine whether it's theoretically possible to recover the correct parameters. It can state whether a given type of output data can be used to globally recover the parameters (i.e. only a unique parameter set for the model produces a given output), whether the parameters are only locally identifiable (i.e. there are finitely many parameter sets which could generate the seen data), or whether it's unidentifiable (there are infinitely many parameters which generate the same output data).

For more information on what StructuralIdentifiability.jl is all about, see the SciMLCon 2022 tutorial video.

MinimallyDisruptiveCurves.jl

MinimallyDisruptiveCurves.jl is a library for finding relationships between parameters of models, finding the curves on which the solution is constant.

Third-Party Libraries to Note

SIAN.jl: Structural Identifiability Analyzer

SIAN.jl is a structural identifiability analysis package which uses an entirely different algorithm from StructuralIdentifiability.jl. For information on the differences between the two approaches, see the Structural Identifiability Tools in Julia tutorial.

DynamicalSystems.jl: A Suite of Dynamical Systems Analysis

DynamicalSystems.jl is an entire ecosystem of dynamical systems analysis methods, for computing measures of chaos (dimension estimation, Lyapunov coefficients), generating delay embeddings, and much more. It uses the SciML tools for its internal equation solving and thus shares much of its API, adding a layer of new tools for extended analyses.

For more information, watch the tutorial Introduction to DynamicalSystems.jl.

BifurcationKit.jl

BifurcationKit.jl is a tool for performing bifurcation analysis. It uses and composes with many SciML equation solvers.

ReachabilityAnalysis.jl

ReachabilityAnalysis.jl is a library for performing reachability analysis of dynamical systems, determining for a given uncertainty interval the full set of possible outcomes from a dynamical system.

ControlSystems.jl

ControlSystems.jl is a library for building and analyzing control systems.

diff --git a/v1.5.0/highlevels/partial_differential_equation_solvers/index.html b/v1.5.0/highlevels/partial_differential_equation_solvers/index.html new file mode 100644 index 00000000000..d70931c003d --- /dev/null +++ b/v1.5.0/highlevels/partial_differential_equation_solvers/index.html @@ -0,0 +1,2 @@ + +Partial Differential Equations (PDE) · Overview of Julia's SciML

Partial Differential Equations (PDE)

NeuralPDE.jl: Physics-Informed Neural Network (PINN) PDE Solvers

NeuralPDE.jl is a partial differential equation solver library which uses physics-informed neural networks (PINNs) to solve the equations. It uses the ModelingToolkit.jl symbolic PDESystem as its input and can handle a wide variety of equation types, including systems of partial differential equations, partial differential-algebraic equations, and integro-differential equations. Its benefit is its flexibility, and it can be used to easily generate surrogate solutions over entire parameter ranges. However, its downside is solver speed: PINN solvers tend to be a lot slower than other methods for solving PDEs.

MethodOflines.jl: Automated Finite Difference Method (FDM)

MethodOflines.jl is a partial differential equation solver library which automates the discretization of PDEs via the finite difference method. It uses the ModelingToolkit.jl symbolic PDESystem as its input, and generates AbstractSystems and SciMLProblems whose numerical solution gives the solution to the PDE.

FEniCS.jl: Wrappers for the Finite Element Method (FEM)

FEniCS.jl is a wrapper for the popular FEniCS finite element method library.

HighDimPDE.jl: High-dimensional PDE Solvers

HighDimPDE.jl is a partial differential equation solver library which implements algorithms that break down the curse of dimensionality to solve the equations. It implements deep-learning based and Picard-iteration based methods to approximately solve high-dimensional, nonlinear, non-local PDEs in up to 10,000 dimensions. Its cons are accuracy: high-dimensional solvers are stochastic, and might result in wrong solutions if the solver meta-parameters are not appropriate.

NeuralOperators.jl: (Fourier) Neural Operators and DeepONets for PDE Solving

NeuralOperators.jl is a library for operator learning based PDE solvers. This includes techniques like:

  • Fourier Neural Operators (FNO)
  • Deep Operator Networks (DeepONets)
  • Markov Neural Operators (MNO)

Currently, its connection to PDE solving must be specified manually, though an interface for ModelingToolkit PDESystems is in progress.

DiffEqOperators.jl: Operators for Finite Difference Method (FDM) Discretizations

DiffEqOperators.jl is a library for defining finite difference operators to easily perform manual FDM semi-discretizations of partial differential equations. This library is fairly incomplete and most cases should receive better performance using MethodOflines.jl.

Third-Party Libraries to Note

A more exhaustive list of Julia PDE packages can be found here: https://github.com/JuliaPDE/SurveyofPDEPackages

ApproxFun.jl: Automated Spectral Discretizations

ApproxFun.jl is a package for approximating functions in basis sets. One particular use case is with spectral basis sets, such as Chebyshev functions and Fourier decompositions, making it easy to represent spectral and pseudospectral discretizations of partial differential equations as ordinary differential equations for the SciML equation solvers.

Ferrite.jl: Finite Element Toolbox for Julia

Ferrite.jl is a performant and extensible library which provides algorithms and data structures to develop finite element software. This library aims at users which need fine grained control over all algorithmic details, as for example often necessary in research when developing new grid-based PDE discretizations or other more advanced problem formulations for example found in continuum mechanics.

Gridap.jl: Julia-Based Tools for Finite Element Discretizations

Gridap.jl is a package for grid-based approximation of partial differential equations, particularly notable for its use of conforming and nonconforming finite element (FEM) discretizations.

Trixi.jl: Adaptive High-Order Numerical Simulations of Hyperbolic Equations

Trixi.jl is a package for numerical simulation of hyperbolic conservation laws, i.e. a large set of hyperbolic partial differential equations, which interfaces and uses the SciML ordinary differential equation solvers.

VoronoiFVM.jl: Tools for the Voronoi Finite Volume Discretizations

VoronoiFVM.jl is a library for generating FVM discretizations of systems of PDEs. It interfaces with many of the SciML equation solver libraries to allow for ease of discretization and flexibility in the solver choice.

diff --git a/v1.5.0/highlevels/plots_visualization/index.html b/v1.5.0/highlevels/plots_visualization/index.html new file mode 100644 index 00000000000..b7c345673d1 --- /dev/null +++ b/v1.5.0/highlevels/plots_visualization/index.html @@ -0,0 +1,2 @@ + +SciML-Supported Plotting and Visualization Libraries · Overview of Julia's SciML

SciML-Supported Plotting and Visualization Libraries

The following libraries are the plotting and visualization libraries which are supported and co-developed by the SciML developers. Other libraries may be used, though these are the libraries used in the tutorials and which have special hooks to ensure ergonomic usage with SciML tooling.

Plots.jl

Plots.jl is the current standard plotting system for the SciML ecosystem. SciML types attempt to include plot recipes for as many types as possible, allowing for automatic visualization with the Plots.jl system. All current tutorials and documentation default to using Plots.jl.

Makie.jl

Makie.jl is a high-performance interactive plotting system for the Julia programming language. It's planned to be the default plotting system used by the SciML organization in the near future.

diff --git a/v1.5.0/highlevels/symbolic_learning/index.html b/v1.5.0/highlevels/symbolic_learning/index.html new file mode 100644 index 00000000000..1a37e1463e9 --- /dev/null +++ b/v1.5.0/highlevels/symbolic_learning/index.html @@ -0,0 +1,2 @@ + +Symbolic Learning and Artificial Intelligence · Overview of Julia's SciML

Symbolic Learning and Artificial Intelligence

Symbolic learning, the classical artificial intelligence, is a set of methods for learning symbolic equations from data and numerical functions. SciML offers an array of symbolic learning utilities which connect with the other machine learning and equation solver functionalities to make it easy to embed prior knowledge and discover missing physics. For more information, see Universal Differential Equations for Scientific Machine Learning.

DataDrivenDiffEq.jl: Data-Driven Modeling and Automated Discovery of Dynamical Systems

DataDrivenDiffEq.jl is a general interface for data-driven modeling, containing a large array of techniques such as:

  • Koopman operator methods (Dynamic-Mode Decomposition (DMD) and variations)
  • Sparse Identification of Dynamical Systems (SINDy and variations like iSINDy)
  • Sparse regression methods (STSLQ, SR3, etc.)
  • PDEFind
  • Wrappers for SymbolicRegression.jl
  • AI Feynman
  • OccamNet

SymbolicNumericIntegration.jl: Symbolic Integration via Numerical Methods

SymbolicNumericIntegration.jl is a package computing the solution to symbolic integration problem using numerical methods (numerical integration mixed with sparse regression).

Third-Party Libraries to Note

SymbolicRegression.jl

SymbolicRegression.jl is a symbolic regression library which uses genetic algorithms with parallelization to achieve fast and robust symbolic learning.

diff --git a/v1.5.0/highlevels/symbolic_tools/index.html b/v1.5.0/highlevels/symbolic_tools/index.html new file mode 100644 index 00000000000..f7a322f4676 --- /dev/null +++ b/v1.5.0/highlevels/symbolic_tools/index.html @@ -0,0 +1,2 @@ + +Symbolic Model Tooling and JuliaSymbolics · Overview of Julia's SciML

Symbolic Model Tooling and JuliaSymbolics

JuliaSymbolics is a sister organization of SciML. It spawned out of the symbolic modeling tools being developed within SciML (ModelingToolkit.jl) to become its own organization dedicated to building a fully-featured Julia-based Computer Algebra System (CAS). As such, the two organizations are closely aligned in terms of its developer community, and many of the SciML libraries use Symbolics.jl extensively.

ModelOrderReduction.jl: Automated Model Reduction for Fast Approximations of Solutions

ModelOrderReduction.jl is a package for automating the reduction of models. These methods function a submodel with a projection, where solving the smaller model provides approximation information about the full model. MOR.jl uses ModelingToolkit.jl as a system description and automatically transforms equations to the subform, defining the observables to automatically lazily reconstruct the full model on-demand in a fast and stable form.

Symbolics.jl: The Computer Algebra System (CAS) of the Julia Programming Language

Symbolics.jl is the CAS of the Julia programming language. If something needs to be done symbolically, most likely Symbolics.jl is the answer.

MetaTheory.jl: E-Graphs to Automate Symbolic Transformations

Metatheory.jl is a library for defining e-graph rewriters for use on the common symbolic interface. This can be used to do all sorts of analysis and code transformations, such as improving code performance, numerical stability, and more. See Automated Code Optimization with E-Graphs for more details.

SymbolicUtils.jl: Define Your Own Computer Algebra System

SymbolicUtils.jl is the underlying utility library and rule-based rewriting language on which Symbolics.jl is developed. Symbolics.jl is standardized type and rule definitions built using SymbolicUtils.jl. However, if non-standard types are required, such as symbolic computing over Fock algebras, then SymbolicUtils.jl is the library from which the new symbolic types can be implemented.

diff --git a/v1.5.0/highlevels/uncertainty_quantification/index.html b/v1.5.0/highlevels/uncertainty_quantification/index.html new file mode 100644 index 00000000000..9e9b7d55ef2 --- /dev/null +++ b/v1.5.0/highlevels/uncertainty_quantification/index.html @@ -0,0 +1,2 @@ + +Uncertainty Quantification · Overview of Julia's SciML

Uncertainty Quantification

There's always uncertainty in our models. Whether it's in the form of the model's equations or in the model's parameters, the uncertainty in our simulation's output often needs to be quantified. The following tools automate this process.

For Measurements.jl vs MonteCarloMeasurements.jl vs Intervals.jl, and the relation to other methods, see the Uncertainty Programming chapter of the SciML Book.

PolyChaos.jl: Intrusive Polynomial Chaos Expansions Made Unintrusive

PolyChaos.jl is a library for calculating intrusive polynomial chaos expansions (PCE) on arbitrary Julia functions. This allows for inputting representations of probability distributions into functions to compute the output distribution in an expansion representation. While normally this would require deriving the PCE-expanded equations by hand, PolyChaos.jl does this at the compiler level using Julia's multiple dispatch, giving a high-performance implementation to a normally complex and tedious mathematical transformation.

SciMLExpectations.jl: Fast Calculations of Expectations of Equation Solutions

SciMLExpectations.jl is a library for accelerating the calculation of expectations of equation solutions with respect to input probability distributions, allowing for applications like robust optimization with respect to uncertainty. It uses Koopman operator techniques to calculate these expectations without requiring the propagation of uncertainties through a solver, effectively performing the adjoint of uncertainty quantification and being much more efficient in the process.

Third-Party Libraries to Note

Measurements.jl: Automated Linear Error Propagation

Measurements.jl is a library for automating linear error propagation. Uncertain numbers are defined as x = 3.8 ± 0.4 and are pushed through calculations using a normal distribution approximation in order to compute an approximate uncertain output. Measurements.jl uses a dictionary-based approach to keep track of correlations to improve the accuracy over naive implementations, though note that linear error propagation theory still has some major issues handling some types of equations, as described in detail in the MonteCarloMeasurements.jl documentation.

MonteCarloMeasurements.jl: Automated Monte Carlo Error Propagation

MonteCarloMeasurements.jl is a library for automating the uncertainty quantification of equation solution using Monte Carlo methods. It defines number types which sample from an input distribution to receive a representative set of parameters that propagate through the solver to calculate a representative set of possible solutions. Note that Monte Carlo techniques can be expensive but are exact, in the sense that as the number of sample points increases to infinity it will compute a correct approximation of the output uncertainty.

ProbNumDiffEq.jl: Probabilistic Numerics Based Differential Equation Solvers

ProbNumDiffEq.jl is a set of probabilistic numerical ODE solvers which compute the solution of a differential equation along with a posterior distribution to estimate its numerical approximation error. Thus these specialized integrators compute an uncertainty output similar to the ProbInts technique of DiffEqUncertainty, but use specialized integration techniques in order to do it much faster for specific kinds of equations.

TaylorIntegration.jl: Taylor Series Integration for Rigorous Numerical Bounds

TaylorIntegration.jl is a library for Taylor series integrators, which has special functionality for computing the interval bound of possible solutions with respect to numerical approximation error.

IntervalArithmetic.jl: Rigorous Numerical Intervals

IntervalArithmetic.jl is a library for performing interval arithmetic calculations on arbitrary Julia code. Interval arithmetic computes rigorous computations with respect to finite-precision floating-point arithmetic, i.e. its intervals are guaranteed to include the true solution. However, interval arithmetic intervals can grow at exponential rates in many problems, thus being unsuitable for analyses in many equation solver contexts.

diff --git a/v1.5.0/index.html b/v1.5.0/index.html new file mode 100644 index 00000000000..102e94f91e6 --- /dev/null +++ b/v1.5.0/index.html @@ -0,0 +1,574 @@ + +SciML: Open Source Software for Scientific Machine Learning with Julia · Overview of Julia's SciML

SciML: Differentiable Modeling and Simulation Combined with Machine Learning

The SciML organization is a collection of tools for solving equations and modeling systems developed in the Julia programming language with bindings to other languages such as R and Python. The organization provides well-maintained tools which compose together as a coherent ecosystem. It has a coherent development principle, unified APIs over large collections of equation solvers, pervasive differentiability and sensitivity analysis, and features many of the highest performance and parallel implementations one can find.

Scientific Machine Learning (SciML) = Scientific Computing + Machine Learning

Where to Start?

And for diving into the details, use the bar on the top to navigate to the submodule of interest!

Reproducibility

The documentation of the [SciML Showcase](@ref showcase) was built using these direct dependencies,
Status `/var/lib/buildkite-agent/builds/gpuci-5/julialang/scimldocs/docs/Project.toml`
+  [0bf59076] AdvancedHMC v0.6.1
+  [6e4b80f9] BenchmarkTools v1.5.0
+  [336ed68f] CSV v0.10.14
+ [052768ef] CUDA v5.3.3
+  [b0b7db55] ComponentArrays v0.15.13
+  [2445eb08] DataDrivenDiffEq v1.4.1
+  [5b588203] DataDrivenSparse v0.1.2
+  [a93c6f00] DataFrames v1.6.1
+  [071ae1c0] DiffEqGPU v3.4.1
+  [0c46a032] DifferentialEquations v7.13.0
+  [31c24e10] Distributions v0.25.108
+  [e30172f5] Documenter v1.4.1
+ [5b8099bc] DomainSets v0.6.7
+  [587475ba] Flux v0.14.15
+  [f6369f11] ForwardDiff v0.10.36
+  [40713840] IncompleteLU v0.2.1
+  [de52edbc] Integrals v4.4.1
+  [d3d80556] LineSearches v7.2.0
+  [7ed4a6bd] LinearSolve v2.30.1
+ [b2108857] Lux v0.5.47
+  [d0bbae9a] LuxCUDA v0.3.2
+  [c7f686f2] MCMCChains v6.0.6
+  [eff96d63] Measurements v2.11.0
+  [94925ecb] MethodOfLines v0.11.0
+  [961ee093] ModelingToolkit v9.15.0
+  [87ed4bf0] MultiDocumenter v0.7.0
+  [315f7962] NeuralPDE v5.16.0
+ [8913a72c] NonlinearSolve v3.11.0
+ [7f7a1694] Optimization v3.24.3
+  [fd9f6733] OptimizationMOI v0.4.2
+  [4e6fcdb7] OptimizationNLopt v0.2.0
+  [36348300] OptimizationOptimJL v0.3.1
+  [42dfb2eb] OptimizationOptimisers v0.2.1
+  [500b13db] OptimizationPolyalgorithms v0.2.1
+  [1dea7af3] OrdinaryDiffEq v6.80.0
+  [91a5bcdd] Plots v1.40.4
+  [afe9f18d] SciMLExpectations v2.2.0
+ [1ed8b502] SciMLSensitivity v7.56.2
+  [860ef19b] StableRNGs v1.0.2
+  [90137ffa] StaticArrays v1.9.4
+  [f3b207a7] StatsPlots v0.15.7
+  [1986cc42] Unitful v1.20.0
+  [e88e6eb3] Zygote v0.6.70
+  [76f85450] LibGit2
+  [37e2e46d] LinearAlgebra
+  [44cfe95a] Pkg v1.10.0
+  [de0858da] Printf
+  [9a3f8284] Random
+  [10745b16] Statistics v1.10.0
+Info Packages marked with  and  have new versions available. Those with  may be upgradable, but those with  are restricted by compatibility constraints from upgrading. To see why use `status --outdated`
and using this machine and Julia version.
Julia Version 1.10.3
+Commit 0b4590a5507 (2024-04-30 10:59 UTC)
+Build Info:
+  Official https://julialang.org/ release
+Platform Info:
+  OS: Linux (x86_64-linux-gnu)
+  CPU: 48 × AMD EPYC 7402 24-Core Processor
+  WORD_SIZE: 64
+  LIBM: libopenlibm
+  LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
+Threads: 1 default, 0 interactive, 1 GC (on 2 virtual cores)
+Environment:
+  JULIA_CPU_THREADS = 2
+  JULIA_DEBUG = Documenter
+  JULIA_DEPOT_PATH = /root/.cache/julia-buildkite-plugin/depots/0183cc98-c3b4-4959-aaaa-6c0d5f351407
+  LD_LIBRARY_PATH = /usr/local/nvidia/lib:/usr/local/nvidia/lib64
+  JULIA_PKG_SERVER =
A more complete overview of all dependencies and their versions is also provided.
Status `/var/lib/buildkite-agent/builds/gpuci-5/julialang/scimldocs/docs/Manifest.toml`
+ [47edcb42] ADTypes v0.2.7
+  [a4c015fc] ANSIColoredPrinters v0.0.1
+  [621f4979] AbstractFFTs v1.5.0
+  [80f14c24] AbstractMCMC v5.2.0
+  [1520ce14] AbstractTrees v0.4.5
+  [7d9f7c33] Accessors v0.1.36
+  [79e6a3ab] Adapt v4.0.4
+  [0bf59076] AdvancedHMC v0.6.1
+  [66dad0bd] AliasTables v1.1.3
+  [dce04be8] ArgCheck v2.3.0
+  [ec485272] ArnoldiMethod v0.4.0
+  [7d9fca2a] Arpack v0.5.4
+  [4fba245c] ArrayInterface v7.10.0
+  [4c555306] ArrayLayouts v1.9.3
+  [a9b6321e] Atomix v0.1.0
+ [13072b0f] AxisAlgorithms v1.0.1
+  [39de3d68] AxisArrays v0.4.7
+  [ab4f0b2a] BFloat16s v0.5.0
+  [aae01518] BandedMatrices v1.7.0
+ [198e06fe] BangBang v0.3.40
+  [9718e550] Baselet v0.1.1
+  [6e4b80f9] BenchmarkTools v1.5.0
+  [e2ed5e7c] Bijections v0.1.6
+  [d1d4a3ce] BitFlags v0.1.8
+  [62783981] BitTwiddlingConvenienceFunctions v0.1.5
+  [764a87c0] BoundaryValueDiffEq v5.7.1
+  [fa961155] CEnum v0.5.0
+  [2a0fbf3d] CPUSummary v0.2.5
+  [00ebfdb7] CSTParser v3.4.3
+  [336ed68f] CSV v0.10.14
+ [052768ef] CUDA v5.3.3
+ [1af6417a] CUDA_Runtime_Discovery v0.2.4
+  [49dc2e85] Calculus v0.5.1
+  [7057c7e9] Cassette v0.3.13
+  [082447d4] ChainRules v1.66.0
+  [d360d2e6] ChainRulesCore v1.23.0
+  [ae650224] ChunkSplitters v2.4.2
+  [fb6a15b2] CloseOpenIntervals v0.1.12
+  [aaaa29a8] Clustering v0.15.7
+  [523fee87] CodecBzip2 v0.8.2
+  [944b1d66] CodecZlib v0.7.4
+  [35d6a980] ColorSchemes v3.25.0
+  [3da002f7] ColorTypes v0.11.5
+  [c3611d14] ColorVectorSpace v0.10.0
+  [5ae59095] Colors v0.12.11
+  [861a8166] Combinatorics v1.0.2
+  [a80b9123] CommonMark v0.8.12
+  [38540f10] CommonSolve v0.2.4
+  [bbf7d656] CommonSubexpressions v0.3.0
+  [34da2185] Compat v4.15.0
+  [b0b7db55] ComponentArrays v0.15.13
+  [b152e2b5] CompositeTypes v0.1.4
+  [a33af91c] CompositionsBase v0.1.2
+  [2569d6c7] ConcreteStructs v0.2.3
+  [f0e56b4a] ConcurrentUtilities v2.4.1
+  [88cd18e8] ConsoleProgressMonitor v0.1.2
+  [187b0558] ConstructionBase v1.5.5
+  [6add18c4] ContextVariablesX v0.1.3
+  [d38c429a] Contour v0.6.3
+  [adafc99b] CpuId v0.3.1
+  [a8cc5b0e] Crayons v4.1.1
+  [667455a9] Cubature v1.5.1
+  [9a962f9c] DataAPI v1.16.0
+  [2445eb08] DataDrivenDiffEq v1.4.1
+  [5b588203] DataDrivenSparse v0.1.2
+  [a93c6f00] DataFrames v1.6.1
+  [82cc6244] DataInterpolations v5.0.0
+  [864edb3b] DataStructures v0.18.20
+  [e2d170a0] DataValueInterfaces v1.0.0
+  [244e2a9f] DefineSingletons v0.1.2
+  [bcd4f6db] DelayDiffEq v5.47.3
+  [8bb1440f] DelimitedFiles v1.9.1
+ [2b5f629d] DiffEqBase v6.151.1
+  [459566f4] DiffEqCallbacks v3.6.2
+  [071ae1c0] DiffEqGPU v3.4.1
+  [77a26b50] DiffEqNoiseProcess v5.21.0
+  [163ba53b] DiffResults v1.1.0
+  [b552c78f] DiffRules v1.15.1
+  [0c46a032] DifferentialEquations v7.13.0
+  [b4f34e82] Distances v0.10.11
+  [31c24e10] Distributions v0.25.108
+  [ffbed154] DocStringExtensions v0.9.3
+  [e30172f5] Documenter v1.4.1
+ [5b8099bc] DomainSets v0.6.7
+  [fa6b7ba4] DualNumbers v0.6.8
+  [7c1d4256] DynamicPolynomials v0.5.7
+ [06fc5a27] DynamicQuantities v0.13.2
+  [da5c29d0] EllipsisNotation v1.8.0
+  [4e289a0a] EnumX v1.0.4
+ [7da242da] Enzyme v0.11.20
+ [f151be2c] EnzymeCore v0.6.6
+  [460bff9d] ExceptionUnwrapping v0.1.10
+  [d4d017d3] ExponentialUtilities v1.26.1
+  [e2ba6199] ExprTools v0.1.10
+  [c87230d0] FFMPEG v0.4.1
+  [7a1cc6ca] FFTW v1.8.0
+  [cc61a311] FLoops v0.2.1
+  [b9860ae5] FLoopsBase v0.1.1
+  [9d29842c] FastAlmostBandedMatrices v0.1.2
+ [7034ab61] FastBroadcast v0.2.8
+  [9aa1b823] FastClosures v0.3.2
+  [29a986be] FastLapackInterface v2.0.4
+  [48062228] FilePathsBase v0.9.21
+  [1a297f60] FillArrays v1.11.0
+  [64ca27bc] FindFirstFunctions v1.2.0
+  [6a86dc24] FiniteDiff v2.23.1
+  [53c48c17] FixedPointNumbers v0.8.5
+  [587475ba] Flux v0.14.15
+  [1fa38f19] Format v1.3.7
+  [f6369f11] ForwardDiff v0.10.36
+  [f62d2435] FunctionProperties v0.1.2
+  [069b7b12] FunctionWrappers v1.1.3
+  [77dc65aa] FunctionWrappersWrappers v0.1.3
+  [d9f16b24] Functors v0.4.10
+  [0c68f7d7] GPUArrays v10.1.1
+  [46192b85] GPUArraysCore v0.1.6
+ [61eb1bfa] GPUCompiler v0.25.0
+  [28b8d3ca] GR v0.73.5
+  [c145ed77] GenericSchur v0.5.4
+  [d7ba0133] Git v1.3.1
+  [c27321d9] Glob v1.3.1
+  [86223c79] Graphs v1.11.0
+  [42e2da0e] Grisu v1.0.2
+  [708ec375] Gumbo v0.8.2
+  [19dc6840] HCubature v1.6.0
+  [cd3eb016] HTTP v1.10.8
+  [3e5b6fbb] HostCPUFeatures v0.1.16
+  [34004b35] HypergeometricFunctions v0.3.23
+  [ac1192a8] HypertextLiteral v0.9.5
+  [b5f81e59] IOCapture v0.2.4
+  [7869d1d1] IRTools v0.4.14
+  [615f187c] IfElse v0.1.1
+  [40713840] IncompleteLU v0.2.1
+  [d25df0c9] Inflate v0.1.4
+  [22cec73e] InitialValues v0.3.1
+  [842dd82b] InlineStrings v1.4.0
+  [505f98c9] InplaceOps v0.3.0
+  [18e54dd8] IntegerMathUtils v0.1.2
+  [de52edbc] Integrals v4.4.1
+ [a98d9a8b] Interpolations v0.14.0
+  [8197267c] IntervalSets v0.7.10
+  [3587e190] InverseFunctions v0.1.14
+  [41ab1584] InvertedIndices v1.3.0
+  [92d709cd] IrrationalConstants v0.2.2
+  [c8e1da08] IterTools v1.10.0
+  [82899510] IteratorInterfaceExtensions v1.0.0
+  [1019f520] JLFzf v0.1.7
+  [692b3bcd] JLLWrappers v1.5.0
+  [682c06a0] JSON v0.21.4
+  [98e50ef6] JuliaFormatter v1.0.56
+  [b14d175d] JuliaVariables v0.2.4
+  [ccbc3e58] JumpProcesses v9.11.1
+  [ef3ab10e] KLU v0.6.0
+ [63c18a36] KernelAbstractions v0.9.18
+  [5ab0869b] KernelDensity v0.6.9
+  [ba0b0d4f] Krylov v0.9.6
+ [929cbde3] LLVM v6.6.3
+  [8b046642] LLVMLoopInfo v1.0.0
+  [b964fa9f] LaTeXStrings v1.3.1
+  [2ee39098] LabelledArrays v1.16.0
+  [984bce1d] LambertW v0.4.6
+  [23fbe1c1] Latexify v0.16.3
+  [73f95e8e] LatticeRules v0.0.1
+  [10f19ff3] LayoutPointers v0.1.15
+  [0e77f7df] LazilyInitializedFields v1.2.2
+ [5078a376] LazyArrays v1.10.0
+  [1d6d02ad] LeftChildRightSiblingTrees v0.2.0
+  [2d8b4e74] LevyArea v1.0.0
+  [d3d80556] LineSearches v7.2.0
+  [7ed4a6bd] LinearSolve v2.30.1
+  [6fdf6af0] LogDensityProblems v2.1.1
+  [996a588d] LogDensityProblemsAD v1.9.0
+  [2ab3a3ac] LogExpFunctions v0.3.27
+  [e6f89c97] LoggingExtras v1.0.3
+  [bdcacae8] LoopVectorization v0.12.170
+ [b2108857] Lux v0.5.47
+  [d0bbae9a] LuxCUDA v0.3.2
+  [bb33d45b] LuxCore v0.1.15
+  [34f89e08] LuxDeviceUtils v0.1.20
+ [82251201] LuxLib v0.3.22
+  [c7f686f2] MCMCChains v6.0.6
+  [be115224] MCMCDiagnosticTools v0.3.10
+  [e80e1ace] MLJModelInterface v1.9.6
+  [d8e11817] MLStyle v0.4.17
+  [f1d291b0] MLUtils v0.4.4
+  [1914dd2f] MacroTools v0.5.13
+  [d125e4d3] ManualMemory v0.1.8
+  [d0879d2d] MarkdownAST v0.1.2
+  [b8f27783] MathOptInterface v1.30.0
+ [a3b82374] MatrixFactorizations v2.2.0
+  [bb5d69b7] MaybeInplace v0.1.3
+  [739be429] MbedTLS v1.1.9
+  [eff96d63] Measurements v2.11.0
+  [442fdcdd] Measures v0.3.2
+  [94925ecb] MethodOfLines v0.11.0
+ [128add7d] MicroCollections v0.1.4
+  [e1d29d7a] Missings v1.2.0
+  [961ee093] ModelingToolkit v9.15.0
+  [4886b29c] MonteCarloIntegration v0.2.0
+  [0987c9cc] MonteCarloMeasurements v1.1.6
+  [46d2c3a1] MuladdMacro v0.2.4
+  [87ed4bf0] MultiDocumenter v0.7.0
+  [102ac46a] MultivariatePolynomials v0.5.5
+  [6f286f6a] MultivariateStats v0.10.2
+  [d8a4904e] MutableArithmetics v1.4.4
+  [d41bc354] NLSolversBase v7.8.3
+  [76087f3c] NLopt v1.0.2
+  [2774e3e8] NLsolve v4.5.1
+  [872c559c] NNlib v0.9.17
+  [5da4648a] NVTX v0.3.4
+  [77ba4419] NaNMath v1.0.2
+  [71a1bf82] NameResolution v0.1.5
+  [c020b1a1] NaturalSort v1.0.0
+  [b8a86587] NearestNeighbors v0.4.16
+  [315f7962] NeuralPDE v5.16.0
+  [2bd173c7] NodeJS v2.0.0
+ [8913a72c] NonlinearSolve v3.11.0
+  [d8793406] ObjectFile v0.4.1
+  [510215fc] Observables v0.5.5
+  [6fe1bfb0] OffsetArrays v1.14.0
+  [67456a42] OhMyThreads v0.5.2
+  [0b1bfda6] OneHotArrays v0.2.5
+  [4d8831e6] OpenSSL v1.4.3
+  [429524aa] Optim v1.9.4
+  [3bd65402] Optimisers v0.3.3
+ [7f7a1694] Optimization v3.24.3
+ [bca83a33] OptimizationBase v0.0.5
+  [fd9f6733] OptimizationMOI v0.4.2
+  [4e6fcdb7] OptimizationNLopt v0.2.0
+  [36348300] OptimizationOptimJL v0.3.1
+  [42dfb2eb] OptimizationOptimisers v0.2.1
+  [500b13db] OptimizationPolyalgorithms v0.2.1
+  [bac558e1] OrderedCollections v1.6.3
+  [1dea7af3] OrdinaryDiffEq v6.80.0
+  [a7812802] PDEBase v0.1.10
+  [90014a1f] PDMats v0.11.31
+  [65ce6f38] PackageExtensionCompat v1.0.2
+  [d96e819e] Parameters v0.12.3
+  [69de0a69] Parsers v2.8.1
+  [570af359] PartialFunctions v1.2.0
+  [b98c9c47] Pipe v1.3.0
+  [ccf2f8ad] PlotThemes v3.1.0
+  [995b91a9] PlotUtils v1.4.1
+  [91a5bcdd] Plots v1.40.4
+  [e409e4f3] PoissonRandom v0.4.4
+  [f517fe37] Polyester v0.7.14
+  [1d0040c9] PolyesterWeave v0.2.1
+  [2dfb63ee] PooledArrays v1.4.3
+  [85a6dd25] PositiveFactorizations v0.2.4
+  [d236fae5] PreallocationTools v0.4.21
+  [aea7be01] PrecompileTools v1.2.1
+  [21216c6a] Preferences v1.4.3
+  [8162dcfd] PrettyPrint v0.2.0
+  [08abe8d2] PrettyTables v2.3.1
+  [27ebfcd6] Primes v0.5.6
+  [33c8b6b6] ProgressLogging v0.1.4
+  [92933f4c] ProgressMeter v1.10.0
+  [43287f4e] PtrArrays v1.2.0
+  [1fd47b50] QuadGK v2.9.4
+  [8a4e6c94] QuasiMonteCarlo v0.3.3
+  [74087812] Random123 v1.7.0
+  [e6cf234a] RandomNumbers v1.5.3
+  [b3c3ace0] RangeArrays v0.3.2
+  [c84ed2f1] Ratios v0.4.5
+  [c1ae055f] RealDot v0.1.0
+  [3cdcf5f2] RecipesBase v1.3.4
+  [01d81517] RecipesPipeline v0.6.12
+  [731186ca] RecursiveArrayTools v3.19.0
+  [f2c3362d] RecursiveFactorization v0.2.23
+  [189a3867] Reexport v1.2.2
+  [2792f1a3] RegistryInstances v0.1.0
+  [05181044] RelocatableFolders v1.0.1
+  [ae029012] Requires v1.3.0
+  [ae5879a3] ResettableStacks v1.1.1
+  [37e2e3b7] ReverseDiff v1.15.3
+  [79098fc4] Rmath v0.7.1
+  [7e49a35a] RuntimeGeneratedFunctions v0.5.13
+  [94e857df] SIMDTypes v0.1.0
+  [476501e8] SLEEFPirates v0.6.42
+  [0bca4576] SciMLBase v2.39.0
+  [afe9f18d] SciMLExpectations v2.2.0
+  [c0aeaf25] SciMLOperators v0.3.8
+ [1ed8b502] SciMLSensitivity v7.56.2
+  [53ae85a6] SciMLStructures v1.2.0
+  [30f210dd] ScientificTypesBase v3.0.0
+  [6c6a2e73] Scratch v1.2.1
+  [91c51154] SentinelArrays v1.4.3
+  [efcf1570] Setfield v1.1.1
+  [605ecd9f] ShowCases v0.1.0
+  [992d4aef] Showoff v1.0.3
+  [777ac1f9] SimpleBufferStream v1.1.0
+  [05bca326] SimpleDiffEq v1.11.1
+ [727e6d20] SimpleNonlinearSolve v1.8.0
+  [699a6c99] SimpleTraits v0.9.4
+  [ce78b400] SimpleUnPack v1.1.0
+  [ed01d8cd] Sobol v1.5.0
+  [a2af1166] SortingAlgorithms v1.2.1
+ [47a9eef4] SparseDiffTools v2.18.0
+  [dc90abb0] SparseInverseSubset v0.1.2
+  [e56a9233] Sparspak v0.3.9
+  [276daf66] SpecialFunctions v2.4.0
+  [171d559e] SplittablesBase v0.1.15
+  [860ef19b] StableRNGs v1.0.2
+  [91464d47] StableTasks v0.1.5
+  [aedffcd0] Static v0.8.10
+  [0d7ed370] StaticArrayInterface v1.5.0
+  [90137ffa] StaticArrays v1.9.4
+  [1e83bf80] StaticArraysCore v1.4.2
+  [64bff920] StatisticalTraits v3.2.0
+  [82ae8749] StatsAPI v1.7.0
+  [2913bbd2] StatsBase v0.34.3
+  [4c63d2b9] StatsFuns v1.3.1
+  [f3b207a7] StatsPlots v0.15.7
+  [9672c7b4] SteadyStateDiffEq v2.2.0
+  [789caeaf] StochasticDiffEq v6.65.1
+  [7792a7ef] StrideArraysCore v0.5.6
+  [892a3eda] StringManipulation v0.3.4
+  [09ab397b] StructArrays v0.6.18
+  [53d494c1] StructIO v0.3.0
+  [c3572dad] Sundials v4.24.0
+  [2efcf032] SymbolicIndexingInterface v0.3.21
+  [19f23fe9] SymbolicLimits v0.2.0
+ [d1185830] SymbolicUtils v1.5.1
+  [0c5d862f] Symbolics v5.28.0
+  [ab02a1b2] TableOperations v1.2.0
+  [3783bdb8] TableTraits v1.0.1
+  [bd369af6] Tables v1.11.1
+  [ed4db957] TaskLocalValues v0.1.1
+  [62fd8b95] TensorCore v0.1.1
+ [8ea1fca8] TermInterface v0.3.3
+  [5d786b92] TerminalLoggers v0.1.7
+  [1c621080] TestItems v0.1.1
+  [8290d209] ThreadingUtilities v0.5.2
+  [a759f4b9] TimerOutputs v0.5.24
+  [0796e94c] Tokenize v0.5.29
+  [9f7883ad] Tracker v0.2.34
+  [3bb67fe8] TranscodingStreams v0.10.8
+ [28d57a85] Transducers v0.4.80
+  [d5829a12] TriangularSolve v0.2.0
+  [410a4b4d] Tricks v0.1.8
+  [781d530d] TruncatedStacktraces v1.4.0
+  [5c2747f8] URIs v1.5.1
+  [3a884ed6] UnPack v1.0.2
+  [1cfade01] UnicodeFun v0.4.1
+  [1986cc42] Unitful v1.20.0
+  [45397f5d] UnitfulLatexify v1.6.3
+  [a7c27f48] Unityper v0.1.6
+  [013be700] UnsafeAtomics v0.2.1
+  [d80eeb9a] UnsafeAtomicsLLVM v0.1.4
+  [41fe7b60] Unzip v0.2.0
+  [3d5dd08c] VectorizationBase v0.21.67
+  [19fa3120] VertexSafeGraphs v0.2.0
+  [ea10d353] WeakRefStrings v1.4.2
+  [d49dbf32] WeightInitializers v0.1.7
+  [cc8bc4a8] Widgets v0.6.6
+ [efce3f68] WoodburyMatrices v0.5.6
+  [76eceee3] WorkerUtilities v1.6.1
+  [e88e6eb3] Zygote v0.6.70
+  [700de1a5] ZygoteRules v0.2.5
+  [02a925ec] cuDNN v1.3.1
+ [68821587] Arpack_jll v3.5.1+1
+  [6e34b625] Bzip2_jll v1.0.8+1
+ [4ee394cb] CUDA_Driver_jll v0.8.1+0
+ [76a88914] CUDA_Runtime_jll v0.12.1+0
+ [62b44479] CUDNN_jll v9.0.0+1
+  [83423d85] Cairo_jll v1.18.0+2
+  [7bc98958] Cubature_jll v1.0.5+0
+ [7cc45869] Enzyme_jll v0.0.102+0
+  [2702e6a9] EpollShim_jll v0.0.20230411+0
+  [2e619515] Expat_jll v2.6.2+0
+ [b22a6f82] FFMPEG_jll v4.4.4+1
+  [f5851436] FFTW_jll v3.3.10+0
+  [a3f928ae] Fontconfig_jll v2.13.96+0
+  [d7e528f0] FreeType2_jll v2.13.2+0
+  [559328eb] FriBidi_jll v1.0.14+0
+  [0656b61e] GLFW_jll v3.3.9+0
+  [d2c73de3] GR_jll v0.73.5+0
+  [78b55507] Gettext_jll v0.21.0+0
+  [f8c6e375] Git_jll v2.44.0+2
+  [7746bdde] Glib_jll v2.80.2+0
+  [3b182d85] Graphite2_jll v1.3.14+0
+  [528830af] Gumbo_jll v0.10.2+0
+  [2e76f6c2] HarfBuzz_jll v2.8.1+1
+  [1d5cc7b8] IntelOpenMP_jll v2024.1.0+0
+  [aacddb02] JpegTurbo_jll v3.0.3+0
+  [9c1d0b0a] JuliaNVTXCallbacks_jll v0.2.1+0
+  [c1c5ebd0] LAME_jll v3.100.2+0
+ [88015f11] LERC_jll v3.0.0+1
+  [dad2f222] LLVMExtra_jll v0.0.29+0
+  [1d63c593] LLVMOpenMP_jll v15.0.7+0
+  [dd4b983a] LZO_jll v2.10.2+0
+ [e9f186c6] Libffi_jll v3.2.2+1
+  [d4300ac3] Libgcrypt_jll v1.8.11+0
+  [7e76a0d4] Libglvnd_jll v1.6.0+0
+  [7add5ba3] Libgpg_error_jll v1.49.0+0
+  [94ce4f54] Libiconv_jll v1.17.0+0
+  [4b2f31a3] Libmount_jll v2.40.1+0
+ [89763e89] Libtiff_jll v4.5.1+1
+  [38a345b3] Libuuid_jll v2.40.1+0
+  [856f044c] MKL_jll v2024.1.0+0
+  [079eb43e] NLopt_jll v2.7.1+0
+  [e98f9f5b] NVTX_jll v3.1.0+2
+  [e7412a2a] Ogg_jll v1.3.5+1
+  [458c3c95] OpenSSL_jll v3.0.13+1
+  [efe28fd5] OpenSpecFun_jll v0.5.5+0
+  [91d4177d] Opus_jll v1.3.2+0
+  [30392449] Pixman_jll v0.43.4+0
+ [c0090381] Qt6Base_jll v6.5.3+1
+  [f50d1b31] Rmath_jll v0.4.2+0
+ [fb77eaff] Sundials_jll v5.2.2+0
+  [a44049a8] Vulkan_Loader_jll v1.3.243+0
+  [a2964d1f] Wayland_jll v1.21.0+1
+  [2381bf8a] Wayland_protocols_jll v1.31.0+0
+  [02c8fc9c] XML2_jll v2.12.7+0
+  [aed1982a] XSLT_jll v1.1.34+0
+  [ffd25f8a] XZ_jll v5.4.6+0
+  [f67eecfb] Xorg_libICE_jll v1.1.1+0
+  [c834827a] Xorg_libSM_jll v1.2.4+0
+  [4f6342f7] Xorg_libX11_jll v1.8.6+0
+  [0c0b7dd1] Xorg_libXau_jll v1.0.11+0
+  [935fb764] Xorg_libXcursor_jll v1.2.0+4
+  [a3789734] Xorg_libXdmcp_jll v1.1.4+0
+  [1082639a] Xorg_libXext_jll v1.3.6+0
+  [d091e8ba] Xorg_libXfixes_jll v5.0.3+4
+  [a51aa0fd] Xorg_libXi_jll v1.7.10+4
+  [d1454406] Xorg_libXinerama_jll v1.1.4+4
+  [ec84b674] Xorg_libXrandr_jll v1.5.2+4
+  [ea2f1a96] Xorg_libXrender_jll v0.9.11+0
+  [14d82f49] Xorg_libpthread_stubs_jll v0.1.1+0
+  [c7cfdc94] Xorg_libxcb_jll v1.15.0+0
+  [cc61e674] Xorg_libxkbfile_jll v1.1.2+0
+  [e920d4aa] Xorg_xcb_util_cursor_jll v0.1.4+0
+  [12413925] Xorg_xcb_util_image_jll v0.4.0+1
+  [2def613f] Xorg_xcb_util_jll v0.4.0+1
+  [975044d2] Xorg_xcb_util_keysyms_jll v0.4.0+1
+  [0d47668e] Xorg_xcb_util_renderutil_jll v0.3.9+1
+  [c22f9ab0] Xorg_xcb_util_wm_jll v0.4.1+1
+  [35661453] Xorg_xkbcomp_jll v1.4.6+0
+  [33bec58e] Xorg_xkeyboard_config_jll v2.39.0+0
+  [c5fb5394] Xorg_xtrans_jll v1.5.0+0
+  [3161d3a3] Zstd_jll v1.5.6+0
+  [35ca27e7] eudev_jll v3.2.9+0
+ [214eeab7] fzf_jll v0.43.0+0
+  [1a1c6b14] gperf_jll v3.1.1+0
+  [a4ae2306] libaom_jll v3.9.0+0
+  [0ac62f75] libass_jll v0.15.1+0
+  [2db6ffa8] libevdev_jll v1.11.0+0
+  [f638f0a6] libfdk_aac_jll v2.0.2+0
+  [36db933b] libinput_jll v1.18.0+0
+  [b53b4c65] libpng_jll v1.6.43+1
+  [f27f6e37] libvorbis_jll v1.3.7+1
+  [009596ad] mtdev_jll v1.1.6+0
+  [1317d2d5] oneTBB_jll v2021.12.0+0
+  [1270edf5] x264_jll v2021.5.5+0
+  [dfaa095f] x265_jll v3.5.0+0
+  [d8fb68d0] xkbcommon_jll v1.4.1+1
+  [0dad84c5] ArgTools v1.1.1
+  [56f22d72] Artifacts
+  [2a0f44e3] Base64
+  [ade2ca70] Dates
+  [8ba89e20] Distributed
+  [f43a241f] Downloads v1.6.0
+  [7b1f6079] FileWatching
+  [9fa8497b] Future
+  [b77e0a4c] InteractiveUtils
+  [4af54fe1] LazyArtifacts
+  [b27032c2] LibCURL v0.6.4
+  [76f85450] LibGit2
+  [8f399da3] Libdl
+  [37e2e46d] LinearAlgebra
+  [56ddb016] Logging
+  [d6f4376e] Markdown
+  [a63ad114] Mmap
+  [ca575930] NetworkOptions v1.2.0
+  [44cfe95a] Pkg v1.10.0
+  [de0858da] Printf
+  [9abbd945] Profile
+  [3fa0cd96] REPL
+  [9a3f8284] Random
+  [ea8e919c] SHA v0.7.0
+  [9e88b42a] Serialization
+  [1a1011a3] SharedArrays
+  [6462fe0b] Sockets
+  [2f01184e] SparseArrays v1.10.0
+  [10745b16] Statistics v1.10.0
+  [4607b0f0] SuiteSparse
+  [fa267f1f] TOML v1.0.3
+  [a4e569a6] Tar v1.10.0
+  [8dfed614] Test
+  [cf7118a7] UUIDs
+  [4ec0a83e] Unicode
+  [e66e0078] CompilerSupportLibraries_jll v1.1.1+0
+  [deac9b47] LibCURL_jll v8.4.0+0
+  [e37daf67] LibGit2_jll v1.6.4+0
+  [29816b5a] LibSSH2_jll v1.11.0+1
+  [c8ffd9c3] MbedTLS_jll v2.28.2+1
+  [14a3606d] MozillaCACerts_jll v2023.1.10
+  [4536629a] OpenBLAS_jll v0.3.23+4
+  [05823500] OpenLibm_jll v0.8.1+2
+  [efcefdf7] PCRE2_jll v10.42.0+1
+  [bea87d4a] SuiteSparse_jll v7.2.1+1
+  [83775a58] Zlib_jll v1.2.13+1
+  [8e850b90] libblastrampoline_jll v5.8.0+1
+  [8e850ede] nghttp2_jll v1.52.0+1
+  [3f19e933] p7zip_jll v17.4.0+2
+Info Packages marked with  and  have new versions available. Those with  may be upgradable, but those with  are restricted by compatibility constraints from upgrading. To see why use `status --outdated -m`

You can also download the manifest file and the project file.

diff --git a/v1.5.0/objects.inv b/v1.5.0/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..8418a3f59edfe03ea1fe17f1db26d6abd725b1a4 GIT binary patch literal 11954 zcmV;jE=|!RAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkUc4cyQ zX=QgHZ)PA$b!=&2CvzZEV`)uH3L_v^WpZMd? zav*PJAarPHb0B7EY-J#6b0A}HZE$jBb8}^6Aa!$TZf78RY-wUH3V58&eQR^vwzA-N z{t9eKuGn=0>&8h=?orjPl%9_6O0pu!cI|#qQ8Sdpm@}NihwaI)-+tgtkVB4iclV2} zA%X4&2sHYQd^yj)i@KTb&&!#RKM8R&%P-FN#fMe46gOpC%`*7!q4}0pnRqBGe4j0w z{2`x-i*)vsFEeqTrPVTDK8kO7^CbSOE%G#Z%$f!s-PKK6HQ9VG`0b+H&~#6{=Lh0O z^|fezsF~glx_k+L6-COt15|*;`T5fFEAB zZ~pV&-z2kgu}Z7FE|>M*YTZ2fgXz89s6zP2*B7WP0s0Y)< z!R`6MVHZ=?hoqV`kn1kw*=hxEn=0*{Fxz4huA_hZx4lyZnXuMR<+mBEjy?T{i?H)@ zPuv0!wRhDs3u2MiH7=di)4I-Qbre$2W=|ZnO$i?*p8;c7i{reWm0z<;TyQ&arC{B! z#mVA6o6qrKhcV_$Sm?+3!$Vdf^GpkIqSj??$-7V2S)HfLyJgl^X>nK1)_GD%{wI`7*86;t+d_KM?rwdYLX@wj9J&Th|Dqtm3Hcd-Ew^SSJr~{@^); z9IU1N4cq;)TmtWgITu&3&~TPFP5CNcE+1EI6t#K>%lGP|JebY0BC80w`sDI#39EJi z4=(9Dz<+*R>bW=u zzA3NNOYuSB!%qYA0aQD9q32z_>RC|wWp}7IO*wl?>En)_QdnYl&3cu^x0iYAY^>3v@0Ff^o^ zcOWoAe&$S@bMW4^AeB|{ubr0YTn={G0};+S%Rl0Kccv5E#$WU7n+sb%gN>d+vjUdD z2i*+D)>!7MMZ%L=S@XO;<&RHA1`D&^(}(U|&FkMqG0<$!tS7T^oYwggpJaDRD(M3n zHrsQ)$O)|Eg<4pKDe8~M%j%4~!)oL1E(I&z0(Wy~3*3zy>!`ka8+IA6mgAE*E=dbq zPk3Gx>GH8nAG1FE-G+O-7;&4N>t`L%cSU{=yD!gbSpW08e6fPVxqp;{eH21*u3z(n z>(?%Bv+0_$Ec%f7jqJ8mXl~&t4i1qJAJFeTOlei6YfEtts-TrKbqDyy4k=hJyzZh5 zX0V~VXbp4u*dWgckT^U3?q447>_OJwAudGlJ8xV?+0=J%=C^4P(L07)?lA+AH|>hP zI~=FbsL>zllLs|Atq(8)+BE43_V{0&N?^ZCC=PIMPCc~#o4mSK#P6M;B&e-mwa3S z<7xF$>cJXmsXm;z)UVWf>{Os=x!ye-#OZqVRavZ$p3<_WuMZmlR34D;B|cx43)s+-Udxm3 zt8|H9qLvrwJd+>+>&CrHVSwB3xQKC{w?ysHFV4K@3`EdtVSxw)A{-#eHOThx{SRR^ z&@{mGE$3-9m-=*&+(KFgF=qAqU~!Nm00*=P-Nl|%+`=-egv0@9SeAqi^30Q!Vw4U` zOR$)R zy%Xv5>gQ9C{Co`@VI_$Ai^9H>vRmgR%Ic>-oN2R;vLWC^EQErHiaSC^1lmykD( zy0Yo}c{qtBKNqV%3UQzo!y5T7!xI)Bam=VjWb{Nf!F*Vu-J-0RmA*cOvo+7EH|@HQMed14fpeYph<(Gl^6b)n(n za$C`FXC*PTF+1dMN_b9!3>2IPWlgq?VHR7u<>DAnYV` zCnFu{MGc*JEbqLrSeP=cK(ub)tF~1(eF*P@A@l+!%HMgETN;JeHqqiFu2m!{y=yWh5_K@UlILlOiI?fxD(VZhP8GT?*;mz$J#kkoTbjs#(*@=HWO`r8b|@32S@~u6V+S3EQJ+);Ehrp@bQs z1;6==QWG1mntkV~H5Zam$oNoDlpORgcuy&yAel+I?ai(r+}V9_Y|t9_W0aZ`S+ZqWwdMHHlw5SLj~H7 zGzKksW8xA>(D-8wi;f*Vo4Mi017DLuLiDqVF#{7CmawoKOPvD?`K5*Bu*%B}WcWX_ zVkK`YP}8wF=#>vuxscarE~4Y*_d)B&C=jUFU_*foh0{=ALvf8}CdNgUkqkLH+r^%; z6d*rUSvv3k4l&E+jthu*u?NaSBj}w_?-Dd;l=F55Om;1Ak=Md^4X|&DUjiQHf)NG` z%QZjkD^mf9AFJqDGa{CUrJ0||kP`t%(#uc#%6vf5i+-0JeLOy(DZc!4c6K^<*%?Gi*1+*- zhX-JtGR_MDkQ^?oKNd>0`HYrvt&N>3zDOO0bKVvc_E`W^Svq^5h6IRiQ{H8DLO*f2 zA~QKz*4YBrvvQ8JhzeUWzHoX1SV*K}sKkaeRPAzSN%iVu;zZ;{PaGAKH_hnoM&%uq zD-^7Osp6nczNh3~Ol0E7aNm@p)gtLO`VTv9leV?f2JGYvONoDm~ahy*|RSTtP< zh3e{*BNXKP>trQ`Z^2c^iB@TWm`*>q4wp;qWmkD zpJ1@K>qiM{P6+gl1%+!O1V(R3Slbu$PMCMeMGC9BEaq%G=aYk%a=*d7Mhk=PIAtSt zkkOGc5nY#Jz4`i0`ZXFc42ZQXDQ0asy-=g!=JMBsHbT!+qg&6V#0?Q@UGl)*O|gxHU$?4-XuKlF&hII03DS zlkZKYytSZp;mOUWM$JW7=AOpUI%sJ1PDIqDRag+H_~8l7c1#b1!|4WeOb&w|qpPYQ z`yquj0JcGERT21Bbsd1r637@bwSY4o*ak9{@MFn@eO9Wl6E|A)8BC)z(I))>Eml89 z)!X;3>cX1K0wfh z&yL>(wh*R;iaDv14{fCd>3#XmbNXCoDSJ?mL$(yK(_?{(XlV{y{0tKyLr*P)?+dS= z==O7TyFc4}_65Yu2IZTwZR8bf*0Nfp%aFN5l}hR^u)Cn{!s(tI1GCN91h&CRqFRy% znGS6}buP=iMjrxjF)QP7I0Kr)VMx?sB0G%2)^1~925|~ajZ2nc|=z52Fg5#(*mSfyODyCVlijk`v5R#)Jj*<j$G);(pyGB zby4Hen~FR#0HI+B^SC3Gx-gRaWk+fo_Al>lmz9OQ_DMO?v^QsH0wdw$fLg*wtJy(l zVmz+1Rh8A+gGT!nx0J#qy$;hX>>(}^q^Dr(5G#W2lv`uF`yG){X&s=cKLFj|jC*T0kfCf7F)RAYK(;<#cSPUe8)^&ys6m2lJ`WweynzzIU z$OP|4<|zs`Ebh=@8Anft-}4CQ8JDA8GFvcji8ql~AP7_BsZ#rZv-ffS@7Zok{y;~d zk~V+eaYmrGLM5%rb2lL&a)K$z_uyrasB!}amIz_F1qZC-gL3JDEZc;YPjs%=$_Z1; zBa==%O6ZA#c=hg71L56{-t}6!XlgfSIkB67GLBSjY) zTPWi2BDs=imr#vq&P-!oDe|x^zwDbF(%@q`Uore{@-_8;v#K}WuBxynn6yZZjU=~u~-(|(YHz)Fa zm9C!17^L}_b+M5(f_C*p7VIJ+tJ5SjK8-?mrfe3~**fon&dKFrIbW;jiLz1w*G`BB z+VX1snw>539=gbt`TY5ERL{<$)4@tT_pRC_B9LA_yT!Esy zNM|fMzy9;)>WwsZxhYHCAy5VI^pOZB0T7Aj0L*AWsGj7_qyiKm79;fyx$Yd7 zuKrL9o+A}|Rtr5xH195A)51k8XpW5SGWk?i<+99AKV2x@23Vqrt5z>{Cd(&~0vDLj zQqQWaQHsa2Bi1|$SQDB~gFg&P&9040UcJ=0H4H)oAd>U4Tz$$gf=WFK)Bt>MV^hj% zn*JJt?o0U{_)&r!`5oU2r$cgjdi&YLC1sd_#0eb1k%dYn&g|!`Zl(=FAT}tf3AbK}6hkG^!Y-!gh~}J&x7Y zEfCWc)pd!ONMzI&MPkf+Yn2Md#8IKg2PY)$oME*#`4jz~V&Zfm3x+H>MwB3dD5N0M z@8rg>?G=ga35q0c73D6s_N{X>mXj0Wi@SoBwi<5z4l9qT6)K?ee&yct}GX!W5@Y=sr%w zoavMJ1*#(US5u-2JwY#1q{@`2z(Cc${nj7kW-DA!DJH{c^1rjWE-8krsTZ^1q|qpUX9&}truu)(a=@-gNuQRlJ;_0Z(EqT4@`82LmnEPX#CK@;~?%U~~ zn6Rp;(O0|M*51S#mHmQ1KNpx%t*ui*<7NSkL1TF=u%NB#pbgmM1jLac2n&fq@7QneKoY94 zpPX`9v4tQloWM={aLe)x-F*?kLz>`NOffp0hZ_noXp04IqAz))Yo@5O4$5+Bim&ME z5%?{Fp4-L=Y$SkTeMnckN(#h5sBbSf@IrLaAHNi@)~YwL2yiFs%XwFsHztK>KO{Kn#qxzW>1 z@D?;LuZ_SRT3`+F$W(J$K*knM&6UUA5$qgpW~u`8h8iiqx|QD?4yJo2Hhd(r7LX|k z0?(_j=^ZpwrSwIL8Eq(jdRnM8k7wP*xhxbnXr9tW&daP`{?N!p`X!SfA0Sp>jcN6J2%#FKVieMRIfCp5XYG-b^GedO{Fv z4Wudc7COj%&%{>fBO`Kk0t&t9&41#$D+Iw7VoI=L-0XTg9G07eiPD??njFei(Qs$L=w@GW?z9zDvJkLZ=)s+eTT-#GrL zGBbpb1gKFc2g!EJ=o1X#z_3G)UEMOJ_`!(lTlBtCiN@@Wu%T~LqPYzu`lbZQ2GM!a z#z6k+hwx67aVl5r41 ze_dxBQ-qpJKg*oJn+;-XpLrf?I}+i56CpUEz>yBtKX`gPx0g;Y@d@d;URQi+~9 zsY~=?3>9pg$398axBwX}7rL4Tm}IG6_pO;p#o&YXhNhrYU_VM@Tn zEJqp6?uY`fV zfl-r~u3be{X0~*XmT;Dr%WF`h%7ra(q8>|rj#GFKI+Wu0LtD3}RF03t6g1h0rb8Z! zOzN@V=YsnQ+YfWs+X`*u6r^s2Nsd{^GhY3Lkvk_}vn6FC4fvQl;qq||Tv~bqjvnGv zKs`zh>Mzu7v7_LQF>5Vs=vcX|9##?>WNq(=71q2|kr{qf16yU(F^)TRZ#kG%zCJy^ zc=OWM`Yt`38#;<2teJXzfl*i?Rgqyj^-moezEi1}feIRC$EHtn{u|ccuCYKUPdV`2 zAL(0MnscdS+ACOR46`K7qM^Bj1Xtz2$aBg7BW*frwM_4BU z6lS9jA_?i@J??brM&UAz&N*#S)Jnf_m0^}`k-DW zO=a-R){3Oi3+17mVx}2FM{H^g!af2ADxW1j!7Gj01OadFD}=N zxb6B(dIBR{;LdUx1Ky*nYb?i8#B@|;=cr?XMJp=ws2zehOM5CVa=W&8-AAZCj#Pbc zaSV7^=(#w4p~`y(D9JgSz*-W7Y1>zAkMi}4^}hU!R%}=Bm50vBA($rwyo}~suEwP6~jWE=( zy~>vR#_y@95k!rV^)YCJ$Tm9u^kdt~{yosN^pCHJDq|R+=j*X0kla3|gitC}MNtHlDDe~)4XsHG zhvN!F}h5bW?N@E zsV-VSNM>3anZ$;=_}P;4JPIPC66O~>zS)KfFm>8r6s9mRZ7KUDY}cZQdA!5@oO4t6 zEd5DYPaP1Za6La&K52EsLq5C8no8a6fMpo)9y0WfQMrD~`bXpbRw>6F6r@OxK+>g6 zsBS`c6Wk4rM<&(xqAi-7Y^aX0gdWyxi`7RwYzev>tyYTC=zZ5Y^CKv!dd477#%b&=$EI zKzFh^|FO#@;ujfhI%mT>C9VeUlrZ-Sd4=P3qz2t=Nc@5qQ4lTNk$n3MvR?go4O|%D zyso;ylc1>UGtLyNMhB%|H=ikLif|9)#jrcL$4@U4EfDJozEwpCKZ4RTIu6VMVhssc z*ZBA(IY$6RHg{OjWx4)ImcgrtyfnWD4qSt7hZ* zrChYCx6r+l!xW2}U!=gLXPL9>`MK0D#t)|h(CqLKWEVAWYJM*C3lrL~O;E4Di+>%C z<^8oMmX~jxYSu;OR!*e{>IyS1Y%&zz)+#5f<_S(K^R67Q0JCEFgDU?^@9uG zvgq1fALn(|(gjmTZS^(VDq#5X5)^mlBwmUKoO5t4BkWq83Me#S?&2YE%51sC)jS#% zag(XY44q-g2HRB~FsiH2T@$AS^6gVzQE`g?fGpQLb}zM1a# z*3o(2fuhfPd?B0{$!)qW$|}5;i=WDyjBd4eFUdki5vlTVShhn9d&sjAqkzPMEoq33 zNIew{&AY4%*;%9p2}4Vamu*T#9FR>f&aM8jFZqd5rnb#=4Z%{>g9o^SSUpjinkv|T z(=HZiwceKxZNV2!f1o1dBW{B803iM@2(Id{aR_WcTOa*0ba4rZZ{{BRPTl-1E?jah zs2>35;qBJlx2z9SH6`WKQrw6xRzn=wrg4sOaoWsW3MA2xhyhzj+S;hkJtx%@OO<2c ziU#Pg_e`_l?`*;Ou>LvKKWnP_T>-4aMrb-G-}CVLgK(>f7+}H!MjKB9^AF18V@*Xw zc#1~NG$lE!4(g^ooqQgvk-{ycQpV+NzR29bm~m@QV^JCA+u*U3VrF@)>?!gW&z}lgQEn85Vs3D}29BB4H8a%S35wjth%Avs4-;uNrkWFX zF_C2nm%l!3!vcUe7))DHdfbafFuVBtOwwMA9*K_ns5^9`k4d0DqHCz;%(w8zC(voj zX@!(`g$AW-851bMpb}lJ@*SR#j-v~ zh3jeEf{x)4x)oEYbhBQEpvV*CNMTO}86+gMC-sLg!h0%|OLcz6$1fVNy}^qSz?PPH z*rMt}Aweo;5x6gC@+C`KHp}93g`xMCRI8TX0vDk=DJN;24`f-yvqxe`D4=f>nmBoa z`U$@u7hmCiHnbya73kRV5$<@_!1EcY#SpKsjeKH$@~esCOnm( zXK`#~P=q!#hH?>F(%Uxqjz}+8- z7oJWDj_DxM;j$x9>Hf-P4}?yus^2aTu7AGV1L4g^it&-a1o&UW&ZIVw*Tde3=|P+JhYbR3Y1D!=0ihi}=*W z8XnOIqDS}q9*MxxB%CgG-FDxKq<44{)wi*R;=^tu+ zak9NHz6fQXz8kL8HA%m{3`#}5zO>n1LV~c| zi(G|;g$oy9Y1LK1N|ezmqPk6p@=`V{R?D<-dsO0DXna4KPLOR%nLf9S#m}s~PsgGq zV%67o$LU5*Dbh&U3z)uK-2?sh?b~63BV~EGyHMRtc(#td)X`BYTxoJB=Q}r)GX$n1 zvvp9X4x3W%6E~g6uYb9fIu*Z&Q(a80ZU~8^=p&172&p(a>ATykHr8R^QGQU-MCU4~y(sd> ztaB;!Caba851#+rf)+05SH$Vem5ml{P-sBUKBeiVi(nnUB%G+mOj1)P^(wN`3k4OCd^xJUy7!wV(Tp{c%8 zhh^4rmj;h;`LGb%dxfuFO7yVP*K~;kSt#x9o)Rp1?G4;xrsCSPWjC%S>0mi zV%84IKHPYP)xizw#GCPZBhr_t5>y?Bu8%|-k*;;e%i0a@(GZhcuH27!PnLDIKou0W zl#;0X{NKF=@EIK6sI9=^zEU!HLV?&dmQtn+*Mk!d*qh|DazS7`9*5~UjNLd83_F_` zy=ED@@fa9T$yJHvk$7=y#z%!8$HxjF2w_3c<|Gh_72U>(cVo)!nY3Q#=2Fh>JpLnu;tgmD4he%^@wU&#xLg;h&mQ`&aNzHV*C@mhWG>Yy4=+ z0(GW?Gic%t^AeuF&z8@O^B6#aGuA;fM3gYCbqt8LC!6T}x#yKsW+f_`^x**w$O9a? zw_=Kk&i8>UGgAQE7HY5_nDer(%^AL-IO8Z6&o6SGf1W5%zm<$s?Up;oL&@`B!;<&ed`0jL#m}4TIkJ^qz9N4rM zKUqF@oYCj$)FM~*;Ttq?;muI00*|s9JC8SyJ$7Kkpp(UJ0DhDrZH0Co+c9(w!zqWR zk=K=8>AAxD^%uH#Tlqt^NgSQb#}%CZOQ$RYIji}pZ@{*EM_lRphO@IFq9CFp zL@1yg^K2SoLlX{I-<)o_o&if40vfCdCHTA+c?)ik{Te!To=4?G=6YhH&X@Nu$^iV_Xofv4COk>j*c5_nWodllg%OLK_M zcNmXE*rC~3&`!ZT%2_43OEq;0oZYsdhdU+y`0gTklom5JwW`D>8jP}hDKE0nR1dUbt07^T3OK^aQmEY_D?H6X zAA0-tEwqDaLcdO1zm8r1d&DMS~a((;@0D7*mbc#Yp!%OvmX{P1mai2X_z*VmfGtgjUE4 zrI5Q~%W&Q3=URh8%)SJ(xk9w)knTt?!?mEp%0wVtli#OD6dNf#y48ug5QEZ0cnc}| zg`85chkoV|{(h!C$p=YR5C>?0kbY}hQMZ%=ER0#&)+B-`MRKbmD_zL+;d^06C=sf) z^%I$rDt>=5D(Z8F7=!#6f_Y#SFr>qGTlQ>po@D1e4Z{f91N^D(v{VwICx=uT$W6!e3Qqwl!`j zEP357O}UZ{xqg0j3itDb-2^pL*vdI>#k^hU>|PeLQ2TXWD(1~Kmq{ZTpSjhGhI!8> zL<3~9a_ziSCj{4Z#@>m#y;vs&k24JGE00woFiD~maknZ9C#dkl5}Eyi1wIaQe4af2_%vua*V6zWZjCVGM+S9obp;o;0thgX(0% z+^6lR2+ppOGX`sn_(0nsd$d<&LUpoX_FQ&@gHz|a>{PqVG4xE{M-tM<%|Dgo;DA*P zRVb)}p|Z9y!l~R-$B7-A){%UeKeQD`CH>DxHLMXeR^I2$AMHKJPy7YY9Gfp&OpkXm z-TUbrGWQZ>p&$zj+0CJ^!;9QJ^ZGR&1Nm2W{n)yMROt6I`_`08s(Qxq&6u+{xa-X` zy1U4%Sj|;}4Kkfskldz^hh_iCJFF{GV(zobd1)mrkUt{j!-q_77D}WpxQSRC9oUG> z4TM?*Mg3q>v6i|vue{FRqH&Fw)Whrc&42#8Ql$Pdt literal 0 HcmV?d00001 diff --git a/v1.5.0/overview/index.html b/v1.5.0/overview/index.html new file mode 100644 index 00000000000..4e78911efa9 --- /dev/null +++ b/v1.5.0/overview/index.html @@ -0,0 +1,2 @@ + +Detailed Overview of the SciML Software Ecosystem · Overview of Julia's SciML

Detailed Overview of the SciML Software Ecosystem

SciML: Combining High-Performance Scientific Computing and Machine Learning

SciML is not standard machine learning, SciML is the combination of scientific computing techniques with machine learning. Thus the SciML organization is not an organization for machine learning libraries (see FluxML for machine learning in Julia), rather SciML is an organization dedicated to the development of scientific computing tools which work seamlessly in conjunction with next-generation machine learning workflows. This includes:

  • High-performance and accurate tools for standard scientific computing modeling and simulation
  • Compatibility with differentiable programming and automatic differentiation
  • Tools for building complex multiscale models
  • Methods for handling inverse problems, model calibration, controls, and Bayesian analysis
  • Symbolic modeling tools for generating efficient code for numerical equation solvers
  • Methods for automatic discovery of (bio)physical equations

and much more. For an overview of the broad goals of the SciML organization, watch:

Overview of Computational Science in Julia with SciML

Below is a simplification of the user-facing packages for use in scientific computing and SciML workflows.

Workflow ElementSciML-Supported Julia packages
Plotting and VisualizationPlots*, Makie*
Sparse matrixSparseArrays*
Interpolation/approximationDataInterpolations*, ApproxFun*
Linear system / least squaresLinearSolve
Nonlinear system / rootfindingNonlinearSolve
Polynomial rootsPolynomials*
IntegrationIntegrals
Nonlinear OptimizationOptimization
Other Optimization (linear, quadratic, convex, etc.)JuMP*
Initial-value problemDifferentialEquations
Boundary-value problemDifferentialEquations
Continuous-Time Markov Chains (Poisson Jumps), Jump DiffusionsJumpProcesses
Finite differencesFiniteDifferences*, FiniteDiff*
Automatic DifferentiationForwardDiff*, Enzyme*, DiffEqSensitivity
Bayesian ModelingTuring*
Deep LearningFlux*
Acausal Modeling / DAEsModelingToolkit
Chemical Reaction NetworksCatalyst
Symbolic ComputingSymbolics
Fast Fourier TransformFFTW*
Partial Differential Equation DiscretizationsAssociated Julia packages
–-–-
Finite DifferencesMethodOfLines
Discontinuous GalerkinTrixi*
Finite ElementGridap*
Physics-Informed Neural NetworksNeuralPDE
Neural OperatorsNeuralOperators
High Dimensional Deep LearningHighDimPDE

* Denotes a non-SciML package that is heavily tested against as part of SciML workflows and has frequent collaboration with the SciML developers.

SciML Mind Map

Domains of SciML

The SciML common interface covers the following domains:

  • Linear systems (LinearProblem)

    • Direct methods for dense and sparse
    • Iterative solvers with preconditioning
  • Nonlinear Systems (NonlinearProblem)

    • Systems of nonlinear equations
    • Scalar bracketing systems
  • Integrals (quadrature) (IntegralProblem)

  • Differential Equations

    • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem and JumpProblem)
    • Ordinary differential equations (ODEs) (ODEProblem)
    • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
    • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
    • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
    • Random differential equations (RODEs or RDEs) (RODEProblem)
    • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
    • Delay differential equations (DDEs) (DDEProblem)
    • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
    • Stochastic delay differential equations (SDDEs) (SDDEProblem)
    • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
    • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)
  • Optimization (OptimizationProblem)

    • Nonlinear (constrained) optimization
  • (Stochastic/Delay/Differential-Algebraic) Partial Differential Equations (PDESystem)

    • Finite difference and finite volume methods
    • Interfaces to finite element methods
    • Physics-Informed Neural Networks (PINNs)
    • Integro-Differential Equations
    • Fractional Differential Equations
  • Specialized Forms

    • Partial Integro-Differential Equations (PIPDEProblem)
  • Data-driven modeling

    • Discrete-time data-driven dynamical systems (DiscreteDataDrivenProblem)
    • Continuous-time data-driven dynamical systems (ContinuousDataDrivenProblem)
    • Symbolic regression (DirectDataDrivenProblem)
  • Uncertainty quantification and expected values (ExpectationProblem)

The SciML common interface also includes ModelingToolkit.jl for defining such systems symbolically, allowing for optimizations like automated generation of parallel code, symbolic simplification, and generation of sparsity patterns.

Inverse Problems, Parameter Estimation, and Structural Identification

Parameter estimation and inverse problems are solved directly on their constituent problem types using tools like SciMLSensitivity.jl. Thus for example, there is no ODEInverseProblem, and instead ODEProblem is used to find the parameters p that solve the inverse problem. Check out the SciMLSensitivity documentation for a discussion on connections to automatic differentiation, optimization, and adjoints.

Common Interface High-Level Overview

The SciML interface is common as the usage of arguments is standardized across all of the problem domains. Underlying high-level ideas include:

  • All domains use the same interface of defining a AbstractSciMLProblem which is then solved via solve(prob,alg;kwargs), where alg is a AbstractSciMLAlgorithm. The keyword argument namings are standardized across the organization.
  • AbstractSciMLProblems are generally defined by a AbstractSciMLFunction which can define extra details about a model function, such as its analytical Jacobian, its sparsity patterns and so on.
  • There is an organization-wide method for defining linear and nonlinear solvers used within other solvers, giving maximum control of performance to the user.
  • Types used within the packages are defined by the input types. For example, packages attempt to internally use the type of the initial condition as the type for the state within differential equation solvers.
  • solve calls should be thread-safe and parallel-safe.
  • init(prob,alg;kwargs) returns an iterator which allows for directly iterating over the solution process
  • High performance is key. Any performance that is not at the top level is considered a bug and should be reported as such.
  • All functions have an in-place and out-of-place form, where the in-place form is made to utilize mutation for high performance on large-scale problems and the out-of-place form is for compatibility with tooling like static arrays and some reverse-mode automatic differentiation systems.

Flowchart Example for PDE-Constrained Optimal Control

The following example showcases how the pieces of the common interface connect to solve a problem that mixes inference, symbolics, and numerics.

External Binding Libraries

  • diffeqr

    • Solving differential equations in R using DifferentialEquations.jl with ModelingToolkit for JIT compilation and GPU-acceleration
  • diffeqpy

    • Solving differential equations in Python using DifferentialEquations.jl

Note About Third-Party Libraries

The SciML documentation references and recommends many third-party libraries for improving ones modeling, simulation, and analysis workflow in Julia. Take these as a positive affirmation of the quality of these libraries, as these libraries are commonly tested by SciML developers who are in contact with the development teams of these groups. It also documents the libraries which are commonly chosen by SciML as dependencies. Do not take omissions as negative affirmations against a given library, i.e. a library left off of the list by SciML is not a negative endorsement. Rather, it means that compatibility with SciML is untested, SciML developers may have a personal preference for another choice, or SciML developers may be simply unaware of the library's existence. If one would like to add a third-party library to the SciML documentation, open a pull request with the requested text.

Note that the libraries in this documentation are only those that are meant to be used in the SciML extended universe of modeling, simulation, and analysis and thus there are many high-quality libraries in other domains (machine learning, data science, etc.) which are purposefully not included. For an overview of the Julia package ecosystem, see the JuliaHub Search Engine.

diff --git a/v1.5.0/search_index.js b/v1.5.0/search_index.js new file mode 100644 index 00000000000..3d52ec25cf8 --- /dev/null +++ b/v1.5.0/search_index.js @@ -0,0 +1,3 @@ +var documenterSearchIndex = {"docs": +[{"location":"showcase/missing_physics/#autocomplete","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"One of the most time-consuming parts of modeling is building the model. How do you know when your model is correct? When you solve an inverse problem to calibrate your model to data, who you gonna call if there are no parameters that make the model the data? This is the problem that the Universal Differential Equation (UDE) approach solves: the ability to start from the model you have, and suggest minimal mechanistic extensions that would allow the model to fit the data. In this showcase, we will show how to take a partially correct model and auto-complete it to find the missing physics.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"note: Note\nFor a scientific background on the universal differential equation approach, check out Universal Differential Equations for Scientific Machine Learning","category":"page"},{"location":"showcase/missing_physics/#Starting-Point:-The-Packages-To-Use","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Starting Point: The Packages To Use","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"There are many packages which are used as part of this showcase. Let's detail what they are and how they are used. For the neural network training:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Module Description\nOrdinaryDiffEq.jl (DifferentialEquations.jl) The numerical differential equation solvers\nSciMLSensitivity.jl The adjoint methods, defines gradients of ODE solvers\nOptimization.jl The optimization library\nOptimizationOptimisers.jl The optimization solver package with Adam\nOptimizationOptimJL.jl The optimization solver package with LBFGS\nLineSearches.jl Line search algorithms package to be used with LBFGS","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"For the symbolic model discovery:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Module Description\nModelingToolkit.jl The symbolic modeling environment\nDataDrivenDiffEq.jl The symbolic regression interface\nDataDrivenSparse.jl The sparse regression symbolic regression solvers\nZygote.jl The automatic differentiation library for fast gradients","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Julia standard libraries:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Module Description\nLinearAlgebra Required for the norm function\nStatistics Required for the mean function","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"And external libraries:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Module Description\nLux.jl The deep learning (neural network) framework\nComponentArrays.jl For the ComponentArray type to match Lux to SciML\nPlots.jl The plotting and visualization library\nStableRNGs.jl Stable random seeding","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"note: Note\nThe deep learning framework Flux.jl could be used in place of Lux, though most tutorials in SciML generally prefer Lux.jl due to its explicit parameter interface, leading to nicer code. Both share the same internal implementations of core kernels, and thus have very similar feature support and performance.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# SciML Tools\nusing OrdinaryDiffEq, ModelingToolkit, DataDrivenDiffEq, SciMLSensitivity, DataDrivenSparse\nusing Optimization, OptimizationOptimisers, OptimizationOptimJL, LineSearches\n\n# Standard Libraries\nusing LinearAlgebra, Statistics\n\n# External Libraries\nusing ComponentArrays, Lux, Zygote, Plots, StableRNGs\ngr()\n\n# Set a random seed for reproducible behaviour\nrng = StableRNG(1111)","category":"page"},{"location":"showcase/missing_physics/#Problem-Setup","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Problem Setup","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"In order to know that we have automatically discovered the correct model, we will use generated data from a known model. This model will be the Lotka-Volterra equations. These equations are given by:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"beginaligned\nfracdxdt = alpha x - beta x y \nfracdydt = -delta y + gamma x y \nendaligned","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"This is a model of rabbits and wolves. alpha x is the exponential growth of rabbits in isolation, -beta x y and gamma x y are the interaction effects of wolves eating rabbits, and -delta y is the term for how wolves die hungry in isolation.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now assume that we have never seen rabbits and wolves in the same room. We only know the two effects alpha x and -delta y. Can we use Scientific Machine Learning to automatically discover an extension to what we already know? That is what we will solve with the universal differential equation.","category":"page"},{"location":"showcase/missing_physics/#Generating-the-Training-Data","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Generating the Training Data","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"First, let's generate training data from the Lotka-Volterra equations. This is straightforward and standard DifferentialEquations.jl usage. Our sample data is thus generated as follows:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"function lotka!(du, u, p, t)\n α, β, γ, δ = p\n du[1] = α * u[1] - β * u[2] * u[1]\n du[2] = γ * u[1] * u[2] - δ * u[2]\nend\n\n# Define the experimental parameter\ntspan = (0.0, 5.0)\nu0 = 5.0f0 * rand(rng, 2)\np_ = [1.3, 0.9, 0.8, 1.8]\nprob = ODEProblem(lotka!, u0, tspan, p_)\nsolution = solve(prob, Vern7(), abstol = 1e-12, reltol = 1e-12, saveat = 0.25)\n\n# Add noise in terms of the mean\nX = Array(solution)\nt = solution.t\n\nx̄ = mean(X, dims = 2)\nnoise_magnitude = 5e-3\nXₙ = X .+ (noise_magnitude * x̄) .* randn(rng, eltype(X), size(X))\n\nplot(solution, alpha = 0.75, color = :black, label = [\"True Data\" nothing])\nscatter!(t, transpose(Xₙ), color = :red, label = [\"Noisy Data\" nothing])","category":"page"},{"location":"showcase/missing_physics/#Definition-of-the-Universal-Differential-Equation","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Definition of the Universal Differential Equation","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now let's define our UDE. We will use Lux.jl to define the neural network as follows:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"rbf(x) = exp.(-(x .^ 2))\n\n# Multilayer FeedForward\nconst U = Lux.Chain(Lux.Dense(2, 5, rbf), Lux.Dense(5, 5, rbf), Lux.Dense(5, 5, rbf),\n Lux.Dense(5, 2))\n# Get the initial parameters and state variables of the model\np, st = Lux.setup(rng, U)\nconst _st = st","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"We then define the UDE as a dynamical system that is u' = known(u) + NN(u) like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Define the hybrid model\nfunction ude_dynamics!(du, u, p, t, p_true)\n û = U(u, p, _st)[1] # Network prediction\n du[1] = p_true[1] * u[1] + û[1]\n du[2] = -p_true[4] * u[2] + û[2]\nend\n\n# Closure with the known parameter\nnn_dynamics!(du, u, p, t) = ude_dynamics!(du, u, p, t, p_)\n# Define the problem\nprob_nn = ODEProblem(nn_dynamics!, Xₙ[:, 1], tspan, p)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Notice that the most important part of this is that the neural network does not have hard-coded weights. The weights of the neural network are the parameters of the ODE system. This means that if we change the parameters of the ODE system, then we will have updated the internal neural networks to new weights. Keep that in mind for the next part.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"... and tada: now we have a neural network integrated into our dynamical system!","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"note: Note\nEven if the known physics is only approximate or correct, it can be helpful to improve the fitting process! Check out this JuliaCon talk which dives into this issue.","category":"page"},{"location":"showcase/missing_physics/#Setting-Up-the-Training-Loop","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Setting Up the Training Loop","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now let's build a training loop around our UDE. First, let's make a function predict which runs our simulation at new neural network weights. Recall that the weights of the neural network are the parameters of the ODE, so what we need to do in predict is update our ODE to our new parameters and then run it.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"For this update step, we will use the remake function from the SciMLProblem interface. remake works by specifying key = value pairs to update in the problem fields. Thus to update u0, we would add a keyword argument u0 = .... To update the parameters, we'd do p = .... The field names can be acquired from the problem documentation (or the docstrings!).","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Knowing this, our predict function looks like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"function predict(θ, X = Xₙ[:, 1], T = t)\n _prob = remake(prob_nn, u0 = X, tspan = (T[1], T[end]), p = θ)\n Array(solve(_prob, Vern7(), saveat = T,\n abstol = 1e-6, reltol = 1e-6, \n sensealg=QuadratureAdjoint(autojacvec=ReverseDiffVJP(true))))\nend","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"There are many choices for the combination of sensitivity algorithm and automatic differentiation library (see Choosing a Sensitivity Algorithm. For example, you could have used sensealg=ForwardDiffSensitivity().","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now, for our loss function, we solve the ODE at our new parameters and check its L2 loss against the dataset. Using our predict function, this looks like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"function loss(θ)\n X̂ = predict(θ)\n mean(abs2, Xₙ .- X̂)\nend","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Lastly, what we will need to track our optimization is to define a callback as defined by the OptimizationProblem's solve interface. Because our function only returns one value, the loss l, the callback will be a function of the current parameters θ and l. Let's setup a callback prints every 50 steps the current loss:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"losses = Float64[]\n\ncallback = function (p, l)\n push!(losses, l)\n if length(losses) % 50 == 0\n println(\"Current loss after $(length(losses)) iterations: $(losses[end])\")\n end\n return false\nend","category":"page"},{"location":"showcase/missing_physics/#Training","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Training","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now we're ready to train! To run the training process, we will need to build an OptimizationProblem. Because we have a lot of parameters, we will use Zygote.jl. Optimization.jl makes the choice of automatic differentiation easy, just by specifying an adtype in the OptimizationFunction construction","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Knowing this, we can build our OptimizationProblem as follows:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"adtype = Optimization.AutoZygote()\noptf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)\noptprob = Optimization.OptimizationProblem(optf, ComponentVector{Float64}(p))","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now... we optimize it. We will use a mixed strategy. First, let's do some iterations of ADAM because it's better at finding a good general area of parameter space, but then we will move to BFGS which will quickly hone in on a local minimum. Note that if we only use ADAM it will take a ton of iterations, and if we only use BFGS we normally end up in a bad local minimum, so this combination tends to be a good one for UDEs.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Thus we first solve the optimization problem with ADAM. Choosing a learning rate of 0.1 (tuned to be as high as possible that doesn't tend to make the loss shoot up), we see:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"res1 = Optimization.solve(optprob, OptimizationOptimisers.Adam(), callback = callback, maxiters = 5000)\nprintln(\"Training loss after $(length(losses)) iterations: $(losses[end])\")","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now we use the optimization result of the first run as the initial condition of the second optimization, and run it with BFGS. This looks like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"optprob2 = Optimization.OptimizationProblem(optf, res1.u)\nres2 = Optimization.solve(optprob2, LBFGS(linesearch = BackTracking()), callback = callback, maxiters = 1000)\nprintln(\"Final training loss after $(length(losses)) iterations: $(losses[end])\")\n\n# Rename the best candidate\np_trained = res2.u","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"and bingo, we have a trained UDE.","category":"page"},{"location":"showcase/missing_physics/#Visualizing-the-Trained-UDE","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Visualizing the Trained UDE","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"How well did our neural network do? Let's take a look:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Plot the losses\npl_losses = plot(1:5000, losses[1:5000], yaxis = :log10, xaxis = :log10,\n xlabel = \"Iterations\", ylabel = \"Loss\", label = \"ADAM\", color = :blue)\nplot!(5001:length(losses), losses[5001:end], yaxis = :log10, xaxis = :log10,\n xlabel = \"Iterations\", ylabel = \"Loss\", label = \"LBFGS\", color = :red)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Next, we compare the original data to the output of the UDE predictor. Note that we can even create more samples from the underlying model by simply adjusting the time steps!","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"## Analysis of the trained network\n# Plot the data and the approximation\nts = first(solution.t):(mean(diff(solution.t)) / 2):last(solution.t)\nX̂ = predict(p_trained, Xₙ[:, 1], ts)\n# Trained on noisy data vs real solution\npl_trajectory = plot(ts, transpose(X̂), xlabel = \"t\", ylabel = \"x(t), y(t)\", color = :red,\n label = [\"UDE Approximation\" nothing])\nscatter!(solution.t, transpose(Xₙ), color = :black, label = [\"Measurements\" nothing])","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Let's see how well the unknown term has been approximated:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Ideal unknown interactions of the predictor\nȲ = [-p_[2] * (X̂[1, :] .* X̂[2, :])'; p_[3] * (X̂[1, :] .* X̂[2, :])']\n# Neural network guess\nŶ = U(X̂, p_trained, st)[1]\n\npl_reconstruction = plot(ts, transpose(Ŷ), xlabel = \"t\", ylabel = \"U(x,y)\", color = :red,\n label = [\"UDE Approximation\" nothing])\nplot!(ts, transpose(Ȳ), color = :black, label = [\"True Interaction\" nothing])","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"And have a nice look at all the information:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Plot the error\npl_reconstruction_error = plot(ts, norm.(eachcol(Ȳ - Ŷ)), yaxis = :log, xlabel = \"t\",\n ylabel = \"L2-Error\", label = nothing, color = :red)\npl_missing = plot(pl_reconstruction, pl_reconstruction_error, layout = (2, 1))\n\npl_overall = plot(pl_trajectory, pl_missing)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"That looks pretty good. And if we are happy with deep learning, we can leave it at that: we have trained a neural network to capture our missing dynamics.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"But...","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Can we also make it print out the LaTeX for what the missing equations were? Find out more after the break!","category":"page"},{"location":"showcase/missing_physics/#Symbolic-regression-via-sparse-regression-(SINDy-based)","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Symbolic regression via sparse regression (SINDy based)","text":"","category":"section"},{"location":"showcase/missing_physics/#This-part-of-the-showcase-is-still-a-work-in-progress...-shame-on-us.-But-be-back-in-a-jiffy-and-we'll-have-it-done.","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"This part of the showcase is still a work in progress... shame on us. But be back in a jiffy and we'll have it done.","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Okay, that was a quick break, and that's good because this next part is pretty cool. Let's use DataDrivenDiffEq.jl to transform our trained neural network from machine learning mumbo jumbo into predictions of missing mechanistic equations. To do this, we first generate a symbolic basis that represents the space of mechanistic functions we believe this neural network should map to. Let's choose a bunch of polynomial functions:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"@variables u[1:2]\nb = polynomial_basis(u, 4)\nbasis = Basis(b, u);","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now let's define our DataDrivenProblems for the sparse regressions. To assess the capability of the sparse regression, we will look at 3 cases:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"What if we trained no neural network and tried to automatically uncover the equations from the original noisy data? This is the approach in the literature known as structural identification of dynamical systems (SINDy). We will call this the full problem. This will assess whether this incorporation of prior information was helpful.\nWhat if we trained the neural network using the ideal right-hand side missing derivative functions? This is the value computed in the plots above as Ȳ. This will tell us whether the symbolic discovery could work in ideal situations.\nDo the symbolic regression directly on the function y = NN(x), i.e. the trained learned neural network. This is what we really want, and will tell us how to extend our known equations.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"To define the full problem, we need to define a DataDrivenProblem that has the time series of the solution X, the time points of the solution t, and the derivative at each time point of the solution, obtained by the ODE solution's interpolation. We can just use an interpolation to get the derivative:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"full_problem = ContinuousDataDrivenProblem(Xₙ, t)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Now for the other two symbolic regressions, we are regressing input/outputs of the missing terms, and thus we directly define the datasets as the input/output mappings like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"ideal_problem = DirectDataDrivenProblem(X̂, Ȳ)\nnn_problem = DirectDataDrivenProblem(X̂, Ŷ)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Let's solve the data-driven problems using sparse regression. We will use the ADMM method, which requires we define a set of shrinking cutoff values λ, and we do this like:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"λ = 1e-1\nopt = ADMM(λ)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"This is one of many methods for sparse regression, consult the DataDrivenDiffEq.jl documentation for more information on the algorithm choices. Taking this, let's solve each of the sparse regressions:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"options = DataDrivenCommonOptions(maxiters = 10_000,\n normalize = DataNormalization(ZScoreTransform),\n selector = bic, digits = 1,\n data_processing = DataProcessing(split = 0.9,\n batchsize = 30,\n shuffle = true,\n rng = StableRNG(1111)))\n\nfull_res = solve(full_problem, basis, opt, options = options)\nfull_eqs = get_basis(full_res)\nprintln(full_res)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"options = DataDrivenCommonOptions(maxiters = 10_000,\n normalize = DataNormalization(ZScoreTransform),\n selector = bic, digits = 1,\n data_processing = DataProcessing(split = 0.9,\n batchsize = 30,\n shuffle = true,\n rng = StableRNG(1111)))\n\nideal_res = solve(ideal_problem, basis, opt, options = options)\nideal_eqs = get_basis(ideal_res)\nprintln(ideal_res)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"options = DataDrivenCommonOptions(maxiters = 10_000,\n normalize = DataNormalization(ZScoreTransform),\n selector = bic, digits = 1,\n data_processing = DataProcessing(split = 0.9,\n batchsize = 30,\n shuffle = true,\n rng = StableRNG(1111)))\n\nnn_res = solve(nn_problem, basis, opt, options = options)\nnn_eqs = get_basis(nn_res)\nprintln(nn_res)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Note that we passed the identical options into each of the solve calls to get the same data for each call.","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"We already saw that the full problem has failed to identify the correct equations of motion. To have a closer look, we can inspect the corresponding equations:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"for eqs in (full_eqs, ideal_eqs, nn_eqs)\n println(eqs)\n println(get_parameter_map(eqs))\n println()\nend","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"Next, we want to predict with our model. To do so, we embed the basis into a function like before:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Define the recovered, hybrid model\nfunction recovered_dynamics!(du, u, p, t)\n û = nn_eqs(u, p) # Recovered equations\n du[1] = p_[1] * u[1] + û[1]\n du[2] = -p_[4] * u[2] + û[2]\nend\n\nestimation_prob = ODEProblem(recovered_dynamics!, u0, tspan, get_parameter_values(nn_eqs))\nestimate = solve(estimation_prob, Tsit5(), saveat = solution.t)\n\n# Plot\nplot(solution)\nplot!(estimate)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"We are still a bit off, so we fine tune the parameters by simply minimizing the residuals between the UDE predictor and our recovered parametrized equations:","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"function parameter_loss(p)\n Y = reduce(hcat, map(Base.Fix2(nn_eqs, p), eachcol(X̂)))\n sum(abs2, Ŷ .- Y)\nend\n\noptf = Optimization.OptimizationFunction((x, p) -> parameter_loss(x), adtype)\noptprob = Optimization.OptimizationProblem(optf, get_parameter_values(nn_eqs))\nparameter_res = Optimization.solve(optprob, Optim.LBFGS(), maxiters = 1000)","category":"page"},{"location":"showcase/missing_physics/#Simulation","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Simulation","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"# Look at long term prediction\nt_long = (0.0, 50.0)\nestimation_prob = ODEProblem(recovered_dynamics!, u0, t_long, parameter_res)\nestimate_long = solve(estimation_prob, Tsit5(), saveat = 0.1) # Using higher tolerances here results in exit of julia\nplot(estimate_long)","category":"page"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"true_prob = ODEProblem(lotka!, u0, t_long, p_)\ntrue_solution_long = solve(true_prob, Tsit5(), saveat = estimate_long.t)\nplot!(true_solution_long)","category":"page"},{"location":"showcase/missing_physics/#Post-Processing-and-Plots","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Post Processing and Plots","text":"","category":"section"},{"location":"showcase/missing_physics/","page":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","title":"Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations","text":"c1 = 3 # RGBA(174/255,192/255,201/255,1) # Maroon\nc2 = :orange # RGBA(132/255,159/255,173/255,1) # Red\nc3 = :blue # RGBA(255/255,90/255,0,1) # Orange\nc4 = :purple # RGBA(153/255,50/255,204/255,1) # Purple\n\np1 = plot(t, abs.(Array(solution) .- estimate)' .+ eps(Float32),\n lw = 3, yaxis = :log, title = \"Timeseries of UODE Error\",\n color = [3 :orange], xlabel = \"t\",\n label = [\"x(t)\" \"y(t)\"],\n titlefont = \"Helvetica\", legendfont = \"Helvetica\",\n legend = :topright)\n\n# Plot L₂\np2 = plot3d(X̂[1, :], X̂[2, :], Ŷ[2, :], lw = 3,\n title = \"Neural Network Fit of U2(t)\", color = c1,\n label = \"Neural Network\", xaxis = \"x\", yaxis = \"y\",\n titlefont = \"Helvetica\", legendfont = \"Helvetica\",\n legend = :bottomright)\nplot!(X̂[1, :], X̂[2, :], Ȳ[2, :], lw = 3, label = \"True Missing Term\", color = c2)\n\np3 = scatter(solution, color = [c1 c2], label = [\"x data\" \"y data\"],\n title = \"Extrapolated Fit From Short Training Data\",\n titlefont = \"Helvetica\", legendfont = \"Helvetica\",\n markersize = 5)\n\nplot!(p3, true_solution_long, color = [c1 c2], linestyle = :dot, lw = 5,\n label = [\"True x(t)\" \"True y(t)\"])\nplot!(p3, estimate_long, color = [c3 c4], lw = 1,\n label = [\"Estimated x(t)\" \"Estimated y(t)\"])\nplot!(p3, [2.99, 3.01], [0.0, 10.0], lw = 1, color = :black, label = nothing)\nannotate!([(1.5, 13, text(\"Training \\nData\", 10, :center, :top, :black, \"Helvetica\"))])\nl = @layout [grid(1, 2)\n grid(1, 1)]\nplot(p1, p2, p3, layout = l)","category":"page"},{"location":"highlevels/function_approximation/#Function-Approximation","page":"Function Approximation","title":"Function Approximation","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"While SciML is not an ecosystem for machine learning, SciML has many libraries for doing machine learning with its equation solver libraries and machine learning libraries which are integrated into the equation solvers.","category":"page"},{"location":"highlevels/function_approximation/#Surrogates.jl:-Easy-Generation-of-Differentiable-Surrogate-Models","page":"Function Approximation","title":"Surrogates.jl: Easy Generation of Differentiable Surrogate Models","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"Surrogates.jl is a library for generating surrogate approximations to computationally expensive simulations. It has the following high-dimensional function approximators:","category":"page"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"Kriging\nKriging using Stheno\nRadial Basis\nWendland\nLinear\nSecond Order Polynomial\nSupport Vector Machines (Wait for LIBSVM resolution)\nNeural Networks\nRandom Forests\nLobachevsky splines\nInverse-distance\nPolynomial expansions\nVariable fidelity\nMixture of experts (Waiting GaussianMixtures package to work on v1.5)\nEarth\nGradient Enhanced Kriging","category":"page"},{"location":"highlevels/function_approximation/#ReservoirComputing.jl:-Fast-and-Flexible-Reservoir-Computing-Methods","page":"Function Approximation","title":"ReservoirComputing.jl: Fast and Flexible Reservoir Computing Methods","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"ReservoirComputing.jl is a library for doing machine learning using reservoir computing techniques, such as with methods like Echo State Networks (ESNs). Its reservoir computing methods make it stabilized for usage with difficult equations like stiff dynamics, chaotic equations, and more.","category":"page"},{"location":"highlevels/function_approximation/#Third-Party-Libraries-to-Note","page":"Function Approximation","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/function_approximation/#Flux.jl:-the-ML-library-that-doesn't-make-you-tensor","page":"Function Approximation","title":"Flux.jl: the ML library that doesn't make you tensor","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"Flux.jl is the most popular machine learning library in the Julia programming language. SciML's libraries are heavily tested with it and its automatic differentiation engine Zygote.jl for composability and compatibility.","category":"page"},{"location":"highlevels/function_approximation/#Lux.jl:-Explicitly-Parameterized-Neural-Networks-in-Julia","page":"Function Approximation","title":"Lux.jl: Explicitly Parameterized Neural Networks in Julia","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"Lux.jl is a library for fully explicitly parameterized neural networks. Thus, while alternative interfaces are required to use Flux with many equation solvers (i.e. Flux.destructure), Lux.jl's explicit design marries effortlessly with the SciML equation solver libraries. For this reason, SciML's library are also heavily tested with Lux to ensure compatibility with neural network definitions from here.","category":"page"},{"location":"highlevels/function_approximation/#SimpleChains.jl:-Fast-Small-Scale-Machine-Learning","page":"Function Approximation","title":"SimpleChains.jl: Fast Small-Scale Machine Learning","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"SimpleChains.jl is a library specialized for small-scale machine learning. It uses non-allocating mutating forms to be highly efficient for the cases where matrix multiplication kernels cannot overcome the common overheads of machine learning libraries. Thus for SciML cases with small neural networks (<100 node layers) and non-batched usage (many/most use cases), SimpleChains.jl can be the fastest choice for the neural network definitions.","category":"page"},{"location":"highlevels/function_approximation/#NNLib.jl:-Neural-Network-Primitives-with-Multiple-Backends","page":"Function Approximation","title":"NNLib.jl: Neural Network Primitives with Multiple Backends","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"NNLib.jl is the core library which defines the handling of common functions, like conv and how they map to device accelerators such as the NVIDIA cudnn. This library can thus be used to directly grab many of the core functions used in machine learning, such as common activation functions and gather/scatter operations, without depending on the given style of any machine learning library.","category":"page"},{"location":"highlevels/function_approximation/#GeometricFlux.jl:-Geometric-Deep-Learning-and-Graph-Neural-Networks","page":"Function Approximation","title":"GeometricFlux.jl: Geometric Deep Learning and Graph Neural Networks","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"GeometricFlux.jl is a library for graph neural networks and geometric deep learning. It is the one that is used and tested by the SciML developers for mixing with equation solver applications.","category":"page"},{"location":"highlevels/function_approximation/#AbstractGPs.jl:-Fast-and-Flexible-Gaussian-Processes","page":"Function Approximation","title":"AbstractGPs.jl: Fast and Flexible Gaussian Processes","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"AbstractGPs.jl is the fast and flexible Gaussian Process library that is used by the SciML packages and recommended for downstream usage.","category":"page"},{"location":"highlevels/function_approximation/#MLDatasets.jl:-Common-Machine-Learning-Datasets","page":"Function Approximation","title":"MLDatasets.jl: Common Machine Learning Datasets","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"MLDatasets.jl is a common interface for accessing common machine learning datasets. For example, if you want to run a test on MNIST data, MLDatasets is the quickest way to obtain it.","category":"page"},{"location":"highlevels/function_approximation/#MLUtils.jl:-Utility-Functions-for-Machine-Learning-Pipelines","page":"Function Approximation","title":"MLUtils.jl: Utility Functions for Machine Learning Pipelines","text":"","category":"section"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"MLUtils.jl is a library of utility functions for making writing common machine learning pipelines easier. This includes functionality for:","category":"page"},{"location":"highlevels/function_approximation/","page":"Function Approximation","title":"Function Approximation","text":"An extensible dataset interface (numobs and getobs).\nData iteration and data loaders (eachobs and DataLoader).\nLazy data views (obsview).\nResampling procedures (undersample and oversample).\nTrain/test splits (splitobs)\nData partitioning and aggregation tools (batch, unbatch, chunk, group_counts, group_indices).\nFolds for cross-validation (kfolds, leavepout).\nDatasets lazy transformations (mapobs, filterobs, groupobs, joinobs, shuffleobs).\nToy datasets for demonstration purpose.\nOther data handling utilities (flatten, normalise, unsqueeze, stack, unstack).","category":"page"},{"location":"highlevels/interfaces/#The-SciML-Interface-Libraries","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"","category":"section"},{"location":"highlevels/interfaces/#SciMLBase.jl:-The-SciML-Common-Interface","page":"The SciML Interface Libraries","title":"SciMLBase.jl: The SciML Common Interface","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"SciMLBase.jl defines the core interfaces of the SciML libraries, such as the definitions of abstract types like SciMLProblem, along with their instantiations like ODEProblem. While SciMLBase.jl is insufficient to solve any equations, it holds all the equation definitions, and thus downstream libraries which wish to allow for using SciML solvers without depending on any solvers can directly depend on SciMLBase.jl.","category":"page"},{"location":"highlevels/interfaces/#SciMLOperators.jl:-The-AbstractSciMLOperator-Interface","page":"The SciML Interface Libraries","title":"SciMLOperators.jl: The AbstractSciMLOperator Interface","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"SciMLOperators.jl defines the interface for how matrix-free linear and affine operators are defined and used throughout the SciML ecosystem.","category":"page"},{"location":"highlevels/interfaces/#DiffEqNoiseProcess.jl:-The-SciML-Common-Noise-Interface","page":"The SciML Interface Libraries","title":"DiffEqNoiseProcess.jl: The SciML Common Noise Interface","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"DiffEqNoiseProcess.jl defines the common interface for stochastic noise processes used by the equation solvers of the SciML ecosystem.","category":"page"},{"location":"highlevels/interfaces/#CommonSolve.jl:-The-Common-Definition-of-Solve","page":"The SciML Interface Libraries","title":"CommonSolve.jl: The Common Definition of Solve","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"CommonSolve.jl is the library that defines the solve, solve!, and init interfaces which are used throughout all the SciML equation solvers. It's defined as an extremely lightweight library so that other ecosystems can build on the same solve definition without clashing with SciML when both export.","category":"page"},{"location":"highlevels/interfaces/#Static.jl:-A-Shared-Interface-for-Static-Compile-Time-Computation","page":"The SciML Interface Libraries","title":"Static.jl: A Shared Interface for Static Compile-Time Computation","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"Static.jl is a set of statically parameterized types for performing operations in a statically-defined (compiler-optimized) way with respect to values.","category":"page"},{"location":"highlevels/interfaces/#DiffEqBase.jl:-A-Library-of-Shared-Components-for-Differential-Equation-Solvers","page":"The SciML Interface Libraries","title":"DiffEqBase.jl: A Library of Shared Components for Differential Equation Solvers","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"DiffEqBase.jl is the core shared component of the DifferentialEquations.jl ecosystem. It's not intended for non-developer users to interface directly with, instead it's used for the common functionality for uniformity of implementation between the solver libraries.","category":"page"},{"location":"highlevels/interfaces/#Third-Party-Libraries-to-Note","page":"The SciML Interface Libraries","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/interfaces/#ArrayInterface.jl:-Extensions-to-the-Julia-AbstractArray-Interface","page":"The SciML Interface Libraries","title":"ArrayInterface.jl: Extensions to the Julia AbstractArray Interface","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"ArrayInterface.jl are traits and functions which extend the Julia Base AbstractArray interface, giving a much larger set of queries to allow for writing high-performance generic code over all array types. For example, functions include can_change_size to know if an AbstractArray type is compatible with resize!, fast_scalar_indexing to know whether direct scalar indexing A[i] is optimized, and functions like findstructralnz to get the structural non-zeros of arbitrary sparse and structured matrices.","category":"page"},{"location":"highlevels/interfaces/#Adapt.jl:-Conversion-to-Allow-Chip-Generic-Programs","page":"The SciML Interface Libraries","title":"Adapt.jl: Conversion to Allow Chip-Generic Programs","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"Adapt.jl makes it possible to write code that is generic to the compute devices, i.e. code that works on both CPUs and GPUs. It defines the adapt function which acts like convert(T, x), but without the restriction of returning a T. This allows you to “convert” wrapper types, like Adjoint to be GPU compatible (for example) without throwing away the wrapper.","category":"page"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"Example usage:","category":"page"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"adapt(CuArray, ::Adjoint{Array})::Adjoint{CuArray}","category":"page"},{"location":"highlevels/interfaces/#AbstractFFTs.jl:-High-Level-Shared-Interface-for-Fast-Fourier-Transformation-Libraries","page":"The SciML Interface Libraries","title":"AbstractFFTs.jl: High Level Shared Interface for Fast Fourier Transformation Libraries","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"AbstractFFTs.jl defines the common interface for Fast Fourier Transformations (FFTs) in Julia. Similar to SciMLBase.jl, AbstractFFTs.jl is not a solver library but instead a shared API which is extended by solver libraries such as FFTW.jl. Code written using AbstractFFTs.jl can be made compatible with FFT libraries without having an explicit dependency on a solver.","category":"page"},{"location":"highlevels/interfaces/#GPUArrays.jl:-Common-Interface-for-GPU-Based-Array-Types","page":"The SciML Interface Libraries","title":"GPUArrays.jl: Common Interface for GPU-Based Array Types","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"GPUArrays.jl defines the shared higher-level operations for GPU-based array types, like CUDA.jl's CuArray and AMDGPU.jl's ROCmArray. Packages in SciML use the designation x isa AbstractGPUArray in order to find out if a user's operation is on the GPU and specialize computations.","category":"page"},{"location":"highlevels/interfaces/#RecipesBase.jl:-Standard-Plotting-Recipe-Interface","page":"The SciML Interface Libraries","title":"RecipesBase.jl: Standard Plotting Recipe Interface","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"RecipesBase.jl defines the common interface for plotting recipes, composable transformations of Julia data types into simpler data types for visualization with libraries such as Plots.jl and Makie.jl. SciML libraries attempt to always include plot recipes wherever possible for ease of visualization.","category":"page"},{"location":"highlevels/interfaces/#Tables.jl:-Common-Interface-for-Tabular-Data-Types","page":"The SciML Interface Libraries","title":"Tables.jl: Common Interface for Tabular Data Types","text":"","category":"section"},{"location":"highlevels/interfaces/","page":"The SciML Interface Libraries","title":"The SciML Interface Libraries","text":"Tables.jl is a common interface for defining tabular data structures, such as DataFrames.jl. SciML's libraries extend the Tables.jl interface to allow for automated conversions into data frame libraries without explicit dependence on any singular implementation.","category":"page"},{"location":"highlevels/parameter_analysis/#Parameter-Analysis-Utilities","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"","category":"section"},{"location":"highlevels/parameter_analysis/#GlobalSensitivity.jl:-Global-Sensitivity-Analysis","page":"Parameter Analysis Utilities","title":"GlobalSensitivity.jl: Global Sensitivity Analysis","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"Derivatives calculate the local sensitivity of a model, i.e. the change in the simulation's outcome if one were to change the parameter with respect to some chosen part of the parameter space. But how does a simulation's output change “in general” with respect to a given parameter? That is what global sensitivity analysis (GSA) computes, and thus GlobalSensitivity.jl is the way to answer that question. GlobalSensitivity.jl includes a wide array of methods, including:","category":"page"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"Morris's method\nSobol's method\nRegression methods (PCC, SRC, Pearson)\neFAST\nDelta Moment-Independent method\nDerivative-based Global Sensitivity Measures (DGSM)\nEASI\nFractional Factorial method\nRandom Balance Design FAST method","category":"page"},{"location":"highlevels/parameter_analysis/#StructuralIdentifiability.jl:-Identifiability-Analysis-Made-Simple","page":"Parameter Analysis Utilities","title":"StructuralIdentifiability.jl: Identifiability Analysis Made Simple","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"Performing parameter estimation from a data set means attempting to recover parameters like reaction rates by fitting some model to the data. But how do you know whether you have enough data to even consider getting the “correct” parameters back? StructuralIdentifiability.jl allows for running a structural identifiability analysis on a given model to determine whether it's theoretically possible to recover the correct parameters. It can state whether a given type of output data can be used to globally recover the parameters (i.e. only a unique parameter set for the model produces a given output), whether the parameters are only locally identifiable (i.e. there are finitely many parameter sets which could generate the seen data), or whether it's unidentifiable (there are infinitely many parameters which generate the same output data).","category":"page"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"For more information on what StructuralIdentifiability.jl is all about, see the SciMLCon 2022 tutorial video.","category":"page"},{"location":"highlevels/parameter_analysis/#MinimallyDisruptiveCurves.jl","page":"Parameter Analysis Utilities","title":"MinimallyDisruptiveCurves.jl","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"MinimallyDisruptiveCurves.jl is a library for finding relationships between parameters of models, finding the curves on which the solution is constant.","category":"page"},{"location":"highlevels/parameter_analysis/#Third-Party-Libraries-to-Note","page":"Parameter Analysis Utilities","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/parameter_analysis/#SIAN.jl:-Structural-Identifiability-Analyzer","page":"Parameter Analysis Utilities","title":"SIAN.jl: Structural Identifiability Analyzer","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"SIAN.jl is a structural identifiability analysis package which uses an entirely different algorithm from StructuralIdentifiability.jl. For information on the differences between the two approaches, see the Structural Identifiability Tools in Julia tutorial.","category":"page"},{"location":"highlevels/parameter_analysis/#DynamicalSystems.jl:-A-Suite-of-Dynamical-Systems-Analysis","page":"Parameter Analysis Utilities","title":"DynamicalSystems.jl: A Suite of Dynamical Systems Analysis","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"DynamicalSystems.jl is an entire ecosystem of dynamical systems analysis methods, for computing measures of chaos (dimension estimation, Lyapunov coefficients), generating delay embeddings, and much more. It uses the SciML tools for its internal equation solving and thus shares much of its API, adding a layer of new tools for extended analyses.","category":"page"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"For more information, watch the tutorial Introduction to DynamicalSystems.jl.","category":"page"},{"location":"highlevels/parameter_analysis/#BifurcationKit.jl","page":"Parameter Analysis Utilities","title":"BifurcationKit.jl","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"BifurcationKit.jl is a tool for performing bifurcation analysis. It uses and composes with many SciML equation solvers.","category":"page"},{"location":"highlevels/parameter_analysis/#ReachabilityAnalysis.jl","page":"Parameter Analysis Utilities","title":"ReachabilityAnalysis.jl","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"ReachabilityAnalysis.jl is a library for performing reachability analysis of dynamical systems, determining for a given uncertainty interval the full set of possible outcomes from a dynamical system.","category":"page"},{"location":"highlevels/parameter_analysis/#ControlSystems.jl","page":"Parameter Analysis Utilities","title":"ControlSystems.jl","text":"","category":"section"},{"location":"highlevels/parameter_analysis/","page":"Parameter Analysis Utilities","title":"Parameter Analysis Utilities","text":"ControlSystems.jl is a library for building and analyzing control systems.","category":"page"},{"location":"showcase/optimization_under_uncertainty/#optimization_under_uncertainty","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"","category":"section"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"This tutorial showcases how to leverage the efficient Koopman expectation method from SciMLExpectations to perform optimization under uncertainty. We demonstrate this by using a bouncing ball model with an uncertain model parameter. We also demonstrate its application to problems with probabilistic constraints, in particular a special class of constraints called chance constraints.","category":"page"},{"location":"showcase/optimization_under_uncertainty/#System-Model","page":"Optimization Under Uncertainty","title":"System Model","text":"","category":"section"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"First let's consider a 2D bouncing ball, where the states are the horizontal position x, horizontal velocity dotx, vertical position y, and vertical velocity doty. This model has two system parameters, acceleration due to gravity and coefficient of restitution (models energy loss when the ball impacts the ground). We can simulate such a system using ContinuousCallback as","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"using DifferentialEquations, Plots\n\nfunction ball!(du, u, p, t)\n du[1] = u[2]\n du[2] = 0.0\n du[3] = u[4]\n du[4] = -p[1]\nend\n\nground_condition(u, t, integrator) = u[3]\nground_affect!(integrator) = integrator.u[4] = -integrator.p[2] * integrator.u[4]\nground_cb = ContinuousCallback(ground_condition, ground_affect!)\n\nu0 = [0.0, 2.0, 50.0, 0.0]\ntspan = (0.0, 50.0)\np = [9.807, 0.9]\n\nprob = ODEProblem(ball!, u0, tspan, p)\nsol = solve(prob, Tsit5(), callback = ground_cb)\nplot(sol, vars = (1, 3), label = nothing, xlabel = \"x\", ylabel = \"y\")","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"For this particular problem, we wish to measure the impact distance from a point y=25 on a wall at x=25. So, we introduce an additional callback that terminates the simulation on wall impact.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"stop_condition(u, t, integrator) = u[1] - 25.0\nstop_cb = ContinuousCallback(stop_condition, terminate!)\ncbs = CallbackSet(ground_cb, stop_cb)\n\ntspan = (0.0, 1500.0)\nprob = ODEProblem(ball!, u0, tspan, p)\nsol = solve(prob, Tsit5(), callback = cbs)\nplot(sol, vars = (1, 3), label = nothing, xlabel = \"x\", ylabel = \"y\")","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"To help visualize this problem, we plot as follows, where the star indicates a desired impact location","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"rectangle(xc, yc, w, h) = Shape(xc .+ [-w, w, w, -w] ./ 2.0, yc .+ [-h, -h, h, h] ./ 2.0)\n\nbegin\n plot(sol, vars = (1, 3), label = nothing, lw = 3, c = :black)\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n ylims!(0.0, 50.0)\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/#Considering-Uncertainty","page":"Optimization Under Uncertainty","title":"Considering Uncertainty","text":"","category":"section"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We now wish to introduce uncertainty in p[2], the coefficient of restitution. This is defined via a continuous univariate distribution from Distributions.jl. We can then run a Monte Carlo simulation of 100 trajectories via the EnsembleProblem interface.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"using Distributions\n\ncor_dist = truncated(Normal(0.9, 0.02), 0.9 - 3 * 0.02, 1.0)\ntrajectories = 100\n\nprob_func(prob, i, repeat) = remake(prob, p = [p[1], rand(cor_dist)])\nensemble_prob = EnsembleProblem(prob, prob_func = prob_func)\nensemblesol = solve(ensemble_prob, Tsit5(), EnsembleThreads(), trajectories = trajectories,\n callback = cbs)\n\nbegin # plot\n plot(ensemblesol, vars = (1, 3), lw = 1)\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n plot!(sol, vars = (1, 3), label = nothing, lw = 3, c = :black, ls = :dash)\n xlims!(0.0, 27.5)\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Here, we plot the first 350 Monte Carlo simulations along with the trajectory corresponding to the mean of the distribution (dashed line).","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We now wish to compute the expected squared impact distance from the star. This is called an “observation” of our system or an “observable” of interest.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We define this observable as","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"obs(sol, p) = abs2(sol[3, end] - 25)","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"With the observable defined, we can compute the expected squared miss distance from our Monte Carlo simulation results as","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"mean_ensemble = mean([obs(sol, p) for sol in ensemblesol])","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Alternatively, we can use the Koopman() algorithm in SciMLExpectations.jl to compute this expectation much more efficiently as","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"using SciMLExpectations\ngd = GenericDistribution(cor_dist)\nh(x, u, p) = u, [p[1]; x[1]]\nsm = SystemMap(prob, Tsit5(), callback = cbs)\nexprob = ExpectationProblem(sm, obs, h, gd; nout = 1)\nsol = solve(exprob, Koopman(), ireltol = 1e-5)\nsol.u","category":"page"},{"location":"showcase/optimization_under_uncertainty/#Optimization-Under-Uncertainty","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"","category":"section"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We now wish to optimize the initial position (x_0y_0) and horizontal velocity (dotx_0) of the system to minimize the expected squared miss distance from the star, where x_0inleft-1000right, y_0inleft13right, and dotx_0inleft1050right. We will demonstrate this using a gradient-based optimization approach from NLopt.jl using ForwardDiff.jl AD through the expectation calculation.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"using Optimization, OptimizationNLopt, OptimizationMOI\nmake_u0(θ) = [θ[1], θ[2], θ[3], 0.0]\nfunction 𝔼_loss(θ, pars)\n prob = ODEProblem(ball!, make_u0(θ), tspan, p)\n sm = SystemMap(prob, Tsit5(), callback = cbs)\n exprob = ExpectationProblem(sm, obs, h, gd; nout = 1)\n sol = solve(exprob, Koopman(), ireltol = 1e-5)\n sol.u\nend\nopt_f = OptimizationFunction(𝔼_loss, Optimization.AutoForwardDiff())\nopt_ini = [-1.0, 2.0, 50.0]\nopt_lb = [-100.0, 1.0, 10.0]\nopt_ub = [0.0, 3.0, 50.0]\nopt_prob = OptimizationProblem(opt_f, opt_ini; lb = opt_lb, ub = opt_ub)\noptimizer = OptimizationMOI.MOI.OptimizerWithAttributes(NLopt.Optimizer,\n \"algorithm\" => :LD_MMA)\nopt_sol = solve(opt_prob, optimizer)\nminx = opt_sol.u","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Let's now visualize 100 Monte Carlo simulations","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"ensembleprob = EnsembleProblem(remake(prob, u0 = make_u0(minx)), prob_func = prob_func)\nensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(), trajectories = 100,\n callback = cbs)\n\nbegin\n plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)\n plot!(solve(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = cbs),\n vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n ylims!(0.0, 50.0)\n xlims!(minx[1], 27.5)\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Looks pretty good! But, how long did it take? Let's benchmark.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"@time solve(opt_prob, optimizer)","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Not bad for bound constrained optimization under uncertainty of a hybrid system!","category":"page"},{"location":"showcase/optimization_under_uncertainty/#Probabilistic-Constraints","page":"Optimization Under Uncertainty","title":"Probabilistic Constraints","text":"","category":"section"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"With this approach, we can also consider probabilistic constraints. Let us now consider a wall at x=20 with height 25.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"constraint = [20.0, 25.0]\nbegin\n plot(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black,\n label = nothing)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n ylims!(0.0, 50.0)\n xlims!(minx[1], 27.5)\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We now wish to minimize the same loss function as before, but introduce an inequality constraint such that the solution must have less than a 1% chance of colliding with the wall at x=20. This class of probabilistic constraints is called a chance constraint.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"To do this, we first introduce a new callback and solve the system using the previous optimal solution","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"constraint_condition(u, t, integrator) = u[1] - constraint[1]\nfunction constraint_affect!(integrator)\n integrator.u[3] < constraint[2] ? terminate!(integrator) : nothing\nend\nconstraint_cb = ContinuousCallback(constraint_condition, constraint_affect!,\n save_positions = (true, false));\nconstraint_cbs = CallbackSet(ground_cb, stop_cb, constraint_cb)\n\nensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(), trajectories = 500,\n callback = constraint_cbs)\n\nbegin\n plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)\n plot!(solve(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = constraint_cbs),\n vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)\n\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n ylims!(0.0, 50.0)\n xlims!(minx[1], 27.5)\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"That doesn't look good!","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We now need a second observable for the system. To compute a probability of impact, we use an indicator function for if a trajectory impacts the wall. In other words, this functions returns 1 if the trajectory hits the wall and 0 otherwise.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"function constraint_obs(sol, p)\n sol((constraint[1] - sol[1, 1]) / sol[2, 1])[3] <= constraint[2] ? one(sol[1, end]) :\n zero(sol[1, end])\nend","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Using the previously computed optimal initial conditions, let's compute the probability of hitting this wall","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"sm = SystemMap(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = cbs)\nexprob = ExpectationProblem(sm, constraint_obs, h, gd; nout = 1)\nsol = solve(exprob, Koopman(), ireltol = 1e-5)\nsol.u","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We then set up the constraint function for NLopt just as before.","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"function 𝔼_constraint(res, θ, pars)\n prob = ODEProblem(ball!, make_u0(θ), tspan, p)\n sm = SystemMap(prob, Tsit5(), callback = cbs)\n exprob = ExpectationProblem(sm, constraint_obs, h, gd; nout = 1)\n sol = solve(exprob, Koopman(), ireltol = 1e-5)\n res .= sol.u\nend\nopt_lcons = [-Inf]\nopt_ucons = [0.01]\noptimizer = OptimizationMOI.MOI.OptimizerWithAttributes(NLopt.Optimizer,\n \"algorithm\" => :LD_MMA)\nopt_f = OptimizationFunction(𝔼_loss, Optimization.AutoForwardDiff(), cons = 𝔼_constraint)\nopt_prob = OptimizationProblem(opt_f, opt_ini; lb = opt_lb, ub = opt_ub, lcons = opt_lcons,\n ucons = opt_ucons)\nopt_sol = solve(opt_prob, optimizer)\nminx2 = opt_sol.u","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"The probability of impacting the wall is now","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"container = zeros(1)\n𝔼_constraint(container, minx2, nothing)\nλ = container[1]","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"We can check if this is within tolerance by","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"λ <= 0.01 + 1e-5","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"Again, we plot some Monte Carlo simulations from this result as follows","category":"page"},{"location":"showcase/optimization_under_uncertainty/","page":"Optimization Under Uncertainty","title":"Optimization Under Uncertainty","text":"ensembleprob = EnsembleProblem(remake(prob, u0 = make_u0(minx2)), prob_func = prob_func)\nensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(),\n trajectories = 500, callback = constraint_cbs)\n\nbegin\n plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)\n plot!(solve(remake(prob, u0 = make_u0(minx2)), Tsit5(), callback = constraint_cbs),\n vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)\n plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black)\n\n xlabel!(\"x [m]\")\n ylabel!(\"y [m]\")\n plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)\n scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)\n ylims!(0.0, 50.0)\n xlims!(minx[1], 27.5)\nend","category":"page"},{"location":"getting_started/getting_started/#getting_started","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"","category":"section"},{"location":"getting_started/getting_started/#Quickly:-What-is-Julia's-SciML-Ecosystem?","page":"Getting Started with Julia's SciML","title":"Quickly: What is Julia's SciML Ecosystem?","text":"","category":"section"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"Julia's SciML is:","category":"page"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"SciPy or MATLAB's standard library but in Julia, but\nRuns orders of magnitude faster, even outperforms C and Fortran libraries, and\nIs fully compatible with machine learning and automatic differentiation,\nAll while having an easy-to-use high level interactive development environment.","category":"page"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"Interested?","category":"page"},{"location":"getting_started/getting_started/#Introductory-Tutorials","page":"Getting Started with Julia's SciML","title":"Introductory Tutorials","text":"","category":"section"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"How do I install SciML software?\nBuild and run your first simulation\nSolve your first optimization problem\nFit a simulation to a dataset\nFind the root of an equation (i.e. solve f(x)=0)","category":"page"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"note: Note\nEach of the SciML packages starts with its own introductory tutorial as well! Once you have started to get the hang of a few things, start checking out the introductory tutorials of the different packages. For example, the DifferentialEquations.jl getting started tutorial is a fun one!","category":"page"},{"location":"getting_started/getting_started/#Coming-from...","page":"Getting Started with Julia's SciML","title":"Coming from...","text":"","category":"section"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"Are you familiar with other scientific computing tools? Take a look at the guided introductions below.","category":"page"},{"location":"getting_started/getting_started/","page":"Getting Started with Julia's SciML","title":"Getting Started with Julia's SciML","text":"Introduction to Julia's SciML for the Python User\nIntroduction to Julia's SciML for the MATLAB User\nIntroduction to Julia's SciML for the R User\nIntroduction to Julia's SciML for the C++/Fortran User","category":"page"},{"location":"showcase/symbolic_analysis/#symbolic_analysis","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"The mixture of symbolic computing with numeric computing, which we call symbolic-numeric programming, is one of the central features of the SciML ecosystem. With core aspects like the Symbolics.jl Computer Algebra System and its integration via ModelingToolkit.jl, the SciML ecosystem gracefully mixes analytical symbolic computations with the numerical solver processes to accelerate solvers, give additional information (sparsity, identifiability), automatically fix numerical stability issues, and more.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"In this showcase, we will highlight two aspects of symbolic-numeric programming.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Automated index reduction of DAEs. While arbitrary differential-algebraic equation systems can be written in DifferentialEquations.jl, not all mathematical formulations of a system are equivalent. Some are numerically difficult to solve, or even require special solvers. Some are easy. Can we recognize which formulations are hard and automatically transform them into the easy ones? Yes.\nStructural parameter identifiability. When fitting parameters to data, there's always assumptions about whether there is a unique parameter set that achieves such a data fit. But is this actually the case? The structural identifiability tooling allows one to analytically determine whether, in the limit of infinite data on a subset of observables, one could in theory uniquely identify the parameters (global identifiability), identify the parameters up to a discrete set (local identifiability), or whether there's an infinite manifold of solutions to the inverse problem (nonidentifiable).","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Let's dig into these two cases!","category":"page"},{"location":"showcase/symbolic_analysis/#Automated-Index-Reduction-of-DAEs","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Automated Index Reduction of DAEs","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"In many cases one may accidentally write down a DAE that is not easily solvable by numerical methods. In this tutorial, we will walk through an example of a pendulum which accidentally generates an index-3 DAE, and show how to use the modelingtoolkitize to correct the model definition before solving.","category":"page"},{"location":"showcase/symbolic_analysis/#Copy-Pastable-Example","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Copy-Pastable Example","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using ModelingToolkit\nusing LinearAlgebra\nusing OrdinaryDiffEq\nusing Plots\n\nfunction pendulum!(du, u, p, t)\n x, dx, y, dy, T = u\n g, L = p\n du[1] = dx\n du[2] = T * x\n du[3] = dy\n du[4] = T * y - g\n du[5] = x^2 + y^2 - L^2\n return nothing\nend\npendulum_fun! = ODEFunction(pendulum!, mass_matrix = Diagonal([1, 1, 1, 1, 0]))\nu0 = [1.0, 0, 0, 0, 0]\np = [9.8, 1]\ntspan = (0, 10.0)\npendulum_prob = ODEProblem(pendulum_fun!, u0, tspan, p)\ntraced_sys = modelingtoolkitize(pendulum_prob)\npendulum_sys = structural_simplify(dae_index_lowering(traced_sys))\nprob = ODEProblem(pendulum_sys, [], tspan)\nsol = solve(prob, Rodas5P(), abstol = 1e-8, reltol = 1e-8)\nplot(sol, vars = unknowns(traced_sys))","category":"page"},{"location":"showcase/symbolic_analysis/#Explanation","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Explanation","text":"","category":"section"},{"location":"showcase/symbolic_analysis/#Attempting-to-Solve-the-Equation","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Attempting to Solve the Equation","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"In this tutorial, we will look at the pendulum system:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"beginaligned\n x^prime = v_x\n v_x^prime = Tx\n y^prime = v_y\n v_y^prime = Ty - g\n 0 = x^2 + y^2 - L^2\nendaligned","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"As a good DifferentialEquations.jl user, one would follow the mass matrix DAE tutorial to arrive at code for simulating the model:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using OrdinaryDiffEq, LinearAlgebra\nfunction pendulum!(du, u, p, t)\n x, dx, y, dy, T = u\n g, L = p\n du[1] = dx\n du[2] = T * x\n du[3] = dy\n du[4] = T * y - g\n du[5] = x^2 + y^2 - L^2\nend\npendulum_fun! = ODEFunction(pendulum!, mass_matrix = Diagonal([1, 1, 1, 1, 0]))\nu0 = [1.0, 0, 0, 0, 0];\np = [9.8, 1];\ntspan = (0, 10.0);\npendulum_prob = ODEProblem(pendulum_fun!, u0, tspan, p)\nsolve(pendulum_prob, Rodas5P())","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"However, one will quickly be greeted with the unfortunate message:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"┌ Warning: First function call produced NaNs. Exiting.\n└ @ OrdinaryDiffEq C:\\Users\\accou\\.julia\\packages\\OrdinaryDiffEq\\yCczp\\src\\initdt.jl:76\n┌ Warning: Automatic dt set the starting dt as NaN, causing instability.\n└ @ OrdinaryDiffEq C:\\Users\\accou\\.julia\\packages\\OrdinaryDiffEq\\yCczp\\src\\solve.jl:485\n┌ Warning: NaN dt detected. Likely a NaN value in the state, parameters, or derivative value caused this outcome.\n└ @ SciMLBase C:\\Users\\accou\\.julia\\packages\\SciMLBase\\DrPil\\src\\integrator_interface.jl:325","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Did you implement the DAE incorrectly? No. Is the solver broken? No.","category":"page"},{"location":"showcase/symbolic_analysis/#Understanding-DAE-Index","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Understanding DAE Index","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"It turns out that this is a property of the DAE that we are attempting to solve. This kind of DAE is known as an index-3 DAE. For a complete discussion of DAE index, see this article. Essentially, the issue here is that we have 4 differential variables (x, v_x, y, v_y) and one algebraic variable T (which we can know because there is no D(T) term in the equations). An index-1 DAE always satisfies that the Jacobian of the algebraic equations is non-singular. Here, the first 4 equations are differential equations, with the last term the algebraic relationship. However, the partial derivative of x^2 + y^2 - L^2 w.r.t. T is zero, and thus the Jacobian of the algebraic equations is the zero matrix, and thus it's singular. This is a quick way to see whether the DAE is index 1!","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"The problem with higher order DAEs is that the matrices used in Newton solves are singular or close to singular when applied to such problems. Because of this fact, the nonlinear solvers (or Rosenbrock methods) break down, making them difficult to solve. The classic paper DAEs are not ODEs goes into detail on this and shows that many methods are no longer convergent when index is higher than one. So, it's not necessarily the fault of the solver or the implementation: this is known.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"But that's not a satisfying answer, so what do you do about it?","category":"page"},{"location":"showcase/symbolic_analysis/#Transforming-Higher-Order-DAEs-to-Index-1-DAEs","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Transforming Higher Order DAEs to Index-1 DAEs","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"It turns out that higher order DAEs can be transformed into lower order DAEs. If you differentiate the last equation two times and perform a substitution, you can arrive at the following set of equations:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"beginaligned\nx^prime = v_x \nv_x^prime = x T \ny^prime = v_y \nv_y^prime = y T - g \n0 = 2 left(v_x^2 + v_y^2 + y ( y T - g ) + T x^2 right)\nendaligned","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Note that this is mathematically equivalent to the equation that we had before, but the Jacobian w.r.t. T of the algebraic equation is no longer zero because of the substitution. This means that if you wrote down this version of the model, it will be index-1 and solve correctly! In fact, this is how DAE index is commonly defined: the number of differentiations it takes to transform the DAE into an ODE, where an ODE is an index-0 DAE by substituting out all of the algebraic relationships.","category":"page"},{"location":"showcase/symbolic_analysis/#Automating-the-Index-Reduction","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Automating the Index Reduction","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"However, requiring the user to sit there and work through this process on potentially millions of equations is an unfathomable mental overhead. But, we can avoid this by using methods like the Pantelides algorithm for automatically performing this reduction to index 1. While this requires the ModelingToolkit symbolic form, we use modelingtoolkitize to transform the numerical code into symbolic code, run structural_simplify to simplify the system and lower the index, then transform back to numerical code with ODEProblem, and solve with a numerical solver. Let's try that out:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"traced_sys = modelingtoolkitize(pendulum_prob)\npendulum_sys = structural_simplify(traced_sys)\nprob = ODEProblem(pendulum_sys, Pair[], tspan)\nsol = solve(prob, Rodas5P())\n\nusing Plots\nplot(sol, vars = unknowns(traced_sys))","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Note that plotting using unknowns(traced_sys) is done so that any variables which are symbolically eliminated, or any variable reordering done for enhanced parallelism/performance, still show up in the resulting plot and the plot is shown in the same order as the original numerical code.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Note that we can even go a bit further. If we use the ODEProblem constructor, we represent the mass matrix DAE of the index-reduced system, which can be solved via:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"traced_sys = modelingtoolkitize(pendulum_prob)\npendulum_sys = structural_simplify(dae_index_lowering(traced_sys))\nprob = ODEProblem(pendulum_sys, Pair[], tspan)\nsol = solve(prob, Rodas5P(), abstol = 1e-8, reltol = 1e-8)\nplot(sol, vars = unknowns(traced_sys))","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"And there you go: this has transformed the model from being too hard to solve with implicit DAE solvers, to something that is easily solved.","category":"page"},{"location":"showcase/symbolic_analysis/#Parameter-Identifiability-in-ODE-Models","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Parameter Identifiability in ODE Models","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Ordinary differential equations are commonly used for modeling real-world processes. The problem of parameter identifiability is one of the key design challenges for mathematical models. A parameter is said to be identifiable if one can recover its value from experimental data. Structural identifiability is a theoretical property of a model that answers this question. In this tutorial, we will show how to use StructuralIdentifiability.jl with ModelingToolkit.jl to assess identifiability of parameters in ODE models. The theory behind StructuralIdentifiability.jl is presented in paper [4].","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We will start by illustrating local identifiability in which a parameter is known up to finitely many values, and then proceed to determining global identifiability, that is, which parameters can be identified uniquely.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"To install StructuralIdentifiability.jl, simply run","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using Pkg\nPkg.add(\"StructuralIdentifiability\")","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"The package has a standalone data structure for ordinary differential equations, but is also compatible with ODESystem type from ModelingToolkit.jl.","category":"page"},{"location":"showcase/symbolic_analysis/#Local-Identifiability","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Local Identifiability","text":"","category":"section"},{"location":"showcase/symbolic_analysis/#Input-System","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Input System","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We will consider the following model:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"begincases\nfracdx_4dt = - frack_5 x_4k_6 + x_4\nfracdx_5dt = frack_5 x_4k_6 + x_4 - frack_7 x_5(k_8 + x_5 + x_6)\nfracdx_6dt = frack_7 x_5(k_8 + x_5 + x_6) - frack_9 x_6 (k_10 - x_6) k_10\nfracdx_7dt = frack_9 x_6 (k_10 - x_6) k_10\ny_1 = x_4\ny_2 = x_5endcases","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"This model describes the biohydrogenation[1] process[2] with unknown initial conditions.","category":"page"},{"location":"showcase/symbolic_analysis/#Using-the-ODESystem-object","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Using the ODESystem object","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"To define the ode system in Julia, we use ModelingToolkit.jl.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We first define the parameters, variables, differential equations and the output equations.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using StructuralIdentifiability, ModelingToolkit\n\n# define parameters and variables\n@variables t x4(t) x5(t) x6(t) x7(t) y1(t) y2(t)\n@parameters k5 k6 k7 k8 k9 k10\nD = Differential(t)\n\n# define equations\neqs = [\n D(x4) ~ -k5 * x4 / (k6 + x4),\n D(x5) ~ k5 * x4 / (k6 + x4) - k7 * x5 / (k8 + x5 + x6),\n D(x6) ~ k7 * x5 / (k8 + x5 + x6) - k9 * x6 * (k10 - x6) / k10,\n D(x7) ~ k9 * x6 * (k10 - x6) / k10,\n]\n\n# define the output functions (quantities that can be measured)\nmeasured_quantities = [y1 ~ x4, y2 ~ x5]\n\n# define the system\nde = ODESystem(eqs, t, name = :Biohydrogenation)","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"After that, we are ready to check the system for local identifiability:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"# query local identifiability\n# we pass the ode-system\nlocal_id_all = assess_local_identifiability(de, measured_quantities = measured_quantities,\n p = 0.99)\n# [ Info: Preproccessing `ModelingToolkit.ODESystem` object\n# 6-element Vector{Bool}:\n# 1\n# 1\n# 1\n# 1\n# 1\n# 1","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We can see that all unknowns (except x_7) and all parameters are locally identifiable with probability 0.99.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Let's try to check specific parameters and their combinations","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"to_check = [k5, k7, k10 / k9, k5 + k6]\nlocal_id_some = assess_local_identifiability(de, measured_quantities = measured_quantities,\n funcs_to_check = to_check, p = 0.99)\n# 4-element Vector{Bool}:\n# 1\n# 1\n# 1\n# 1","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Notice that in this case, everything (except the state variable x_7) is locally identifiable, including combinations such as k_10k_9 k_5+k_6","category":"page"},{"location":"showcase/symbolic_analysis/#Global-Identifiability","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Global Identifiability","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"In this part tutorial, let us cover an example problem of querying the ODE for globally identifiable parameters.","category":"page"},{"location":"showcase/symbolic_analysis/#Input-System-2","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Input System","text":"","category":"section"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Let us consider the following four-dimensional model with two outputs:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"begincases\nx_1(t) = -b x_1(t) + frac1 c + x_4(t)\nx_2(t) = alpha x_1(t) - beta x_2(t)\nx_3(t) = gamma x_2(t) - delta x_3(t)\nx_4(t) = sigma x_4(t) frac(gamma x_2(t) - delta x_3(t)) x_3(t)\ny(t) = x_1(t)\nendcases","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We will run a global identifiability check on this enzyme dynamics[3] model. We will use the default settings: the probability of correctness will be p=0.99 and we are interested in identifiability of all possible parameters.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Global identifiability needs information about local identifiability first, but the function we chose here will take care of that extra step for us.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Note: as of writing this tutorial, UTF-symbols such as Greek characters are not supported by one of the project's dependencies, see this issue.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using StructuralIdentifiability, ModelingToolkit\n@parameters b c a beta g delta sigma\n@variables t x1(t) x2(t) x3(t) x4(t) y(t) y2(t)\nD = Differential(t)\n\neqs = [\n D(x1) ~ -b * x1 + 1 / (c + x4),\n D(x2) ~ a * x1 - beta * x2,\n D(x3) ~ g * x2 - delta * x3,\n D(x4) ~ sigma * x4 * (g * x2 - delta * x3) / x3,\n]\n\nmeasured_quantities = [y ~ x1 + x2, y2 ~ x2]\n\node = ODESystem(eqs, t, name = :GoodwinOsc)\n\n@time global_id = assess_identifiability(ode, measured_quantities = measured_quantities)\n# 30.672594 seconds (100.97 M allocations: 6.219 GiB, 3.15% gc time, 0.01% compilation time)\n# Dict{Num, Symbol} with 7 entries:\n# a => :globally\n# b => :globally\n# beta => :globally\n# c => :globally\n# sigma => :globally\n# g => :nonidentifiable\n# delta => :globally","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"We can see that only parameters a, g are unidentifiable, and everything else can be uniquely recovered.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Let us consider the same system but with two inputs, and we will find out identifiability with probability 0.9 for parameters c and b:","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"using StructuralIdentifiability, ModelingToolkit\n@parameters b c a beta g delta sigma\n@variables t x1(t) x2(t) x3(t) x4(t) y(t) u1(t) [input = true] u2(t) [input = true]\nD = Differential(t)\n\neqs = [\n D(x1) ~ -b * x1 + 1 / (c + x4),\n D(x2) ~ a * x1 - beta * x2 - u1,\n D(x3) ~ g * x2 - delta * x3 + u2,\n D(x4) ~ sigma * x4 * (g * x2 - delta * x3) / x3,\n]\nmeasured_quantities = [y ~ x1 + x2, y2 ~ x2]\n\n# check only 2 parameters\nto_check = [b, c]\n\node = ODESystem(eqs, t, name = :GoodwinOsc)\n\nglobal_id = assess_identifiability(ode, measured_quantities = measured_quantities,\n funcs_to_check = to_check, p = 0.9)\n# Dict{Num, Symbol} with 2 entries:\n# b => :globally\n# c => :globally","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"Both parameters b, c are globally identifiable with probability 0.9 in this case.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"[1]: R. Munoz-Tamayo, L. Puillet, J.B. Daniel, D. Sauvant, O. Martin, M. Taghipoor, P. Blavy Review: To be or not to be an identifiable model. Is this a relevant question in animal science modelling?, Animal, Vol 12 (4), 701-712, 2018. The model is the ODE system (3) in Supplementary Material 2, initial conditions are assumed to be unknown.","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"[2]: Moate P.J., Boston R.C., Jenkins T.C. and Lean I.J., Kinetics of Ruminal Lipolysis of Triacylglycerol and Biohydrogenationof Long-Chain Fatty Acids: New Insights from Old Data, Journal of Dairy Science 91, 731–742, 2008","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"[3]: Goodwin, B.C. Oscillatory behavior in enzymatic control processes, Advances in Enzyme Regulation, Vol 3 (C), 425-437, 1965","category":"page"},{"location":"showcase/symbolic_analysis/","page":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","title":"Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability","text":"[4]: Dong, R., Goodbrake, C., Harrington, H. A., & Pogudin, G. Computing input-output projections of dynamical models with applications to structural identifiability. arXiv preprint arXiv:2111.00991.","category":"page"},{"location":"highlevels/symbolic_learning/#Symbolic-Learning-and-Artificial-Intelligence","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"","category":"section"},{"location":"highlevels/symbolic_learning/","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"Symbolic learning, the classical artificial intelligence, is a set of methods for learning symbolic equations from data and numerical functions. SciML offers an array of symbolic learning utilities which connect with the other machine learning and equation solver functionalities to make it easy to embed prior knowledge and discover missing physics. For more information, see Universal Differential Equations for Scientific Machine Learning.","category":"page"},{"location":"highlevels/symbolic_learning/#DataDrivenDiffEq.jl:-Data-Driven-Modeling-and-Automated-Discovery-of-Dynamical-Systems","page":"Symbolic Learning and Artificial Intelligence","title":"DataDrivenDiffEq.jl: Data-Driven Modeling and Automated Discovery of Dynamical Systems","text":"","category":"section"},{"location":"highlevels/symbolic_learning/","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"DataDrivenDiffEq.jl is a general interface for data-driven modeling, containing a large array of techniques such as:","category":"page"},{"location":"highlevels/symbolic_learning/","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"Koopman operator methods (Dynamic-Mode Decomposition (DMD) and variations)\nSparse Identification of Dynamical Systems (SINDy and variations like iSINDy)\nSparse regression methods (STSLQ, SR3, etc.)\nPDEFind\nWrappers for SymbolicRegression.jl\nAI Feynman\nOccamNet","category":"page"},{"location":"highlevels/symbolic_learning/#SymbolicNumericIntegration.jl:-Symbolic-Integration-via-Numerical-Methods","page":"Symbolic Learning and Artificial Intelligence","title":"SymbolicNumericIntegration.jl: Symbolic Integration via Numerical Methods","text":"","category":"section"},{"location":"highlevels/symbolic_learning/","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"SymbolicNumericIntegration.jl is a package computing the solution to symbolic integration problem using numerical methods (numerical integration mixed with sparse regression).","category":"page"},{"location":"highlevels/symbolic_learning/#Third-Party-Libraries-to-Note","page":"Symbolic Learning and Artificial Intelligence","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/symbolic_learning/#SymbolicRegression.jl","page":"Symbolic Learning and Artificial Intelligence","title":"SymbolicRegression.jl","text":"","category":"section"},{"location":"highlevels/symbolic_learning/","page":"Symbolic Learning and Artificial Intelligence","title":"Symbolic Learning and Artificial Intelligence","text":"SymbolicRegression.jl is a symbolic regression library which uses genetic algorithms with parallelization to achieve fast and robust symbolic learning.","category":"page"},{"location":"highlevels/array_libraries/#Modeling-Array-Libraries","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"","category":"section"},{"location":"highlevels/array_libraries/#RecursiveArrayTools.jl:-Arrays-of-Arrays-and-Even-Deeper","page":"Modeling Array Libraries","title":"RecursiveArrayTools.jl: Arrays of Arrays and Even Deeper","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Sometimes, when one is creating a model, basic array types are not enough for expressing a complex concept. RecursiveArrayTools.jl gives many types, such as VectorOfArray and ArrayPartition, which allow for easily building nested array models in a way that conforms to the standard AbstractArray interface. While standard Vector{Array{Float64,N}} types may not be compatible with many equation solver libraries, these wrapped forms like VectorOfArray{Vector{Array{Float64,N}}} are, making it easy to use these more exotic array constructions.","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Note that SciML's interfaces use RecursiveArrayTools.jl extensively, for example, with the timeseries solution types being AbstractVectorOfArray.","category":"page"},{"location":"highlevels/array_libraries/#LabelledArrays.jl:-Named-Variables-in-Arrays-without-Overhead","page":"Modeling Array Libraries","title":"LabelledArrays.jl: Named Variables in Arrays without Overhead","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Sometimes, you want to use a full domain-specific language like ModelingToolkit. Other times, you wish arrays just had a slightly nicer syntax. Don't you wish you could write the Lorenz equations like:","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"function lorenz_f(du, u, p, t)\n du.x = p.σ * (u.y - u.x)\n du.y = u.x * (p.ρ - u.z) - u.y\n du.z = u.x * u.y - p.β * u.z\nend","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"without losing any efficiency? LabelledArrays.jl provides the array types to do just that. All the . accesses are resolved at compile-time, so it's a zero-overhead interface.","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"note: Note\nWe recommend using ComponentArrays.jl for any instance where nested accesses are required, or where the . accesses need to be views to subsets of the array.","category":"page"},{"location":"highlevels/array_libraries/#MultiScaleArrays.jl:-Multiscale-Modeling-to-Compose-with-Equation-Solvers","page":"Modeling Array Libraries","title":"MultiScaleArrays.jl: Multiscale Modeling to Compose with Equation Solvers","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"(Image: )","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"How do you encode such real-world structures in a manner that is compatible with the SciML equation solver libraries? MultiScaleArrays.jl is an answer. MultiScaleArrays.jl gives a highly flexible interface for defining multi-level types, which generates a corresponding interface as an AbstractArray. MultiScaleArrays.jl's flexibility includes the ease of resizing, allowing for models where the number of equations grows and shrinks as agents (cells) in the model divide and die.","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"note: Note\nWe recommend using ComponentArrays.jl instead in any instance where the resizing functionality is not used.","category":"page"},{"location":"highlevels/array_libraries/#Third-Party-Libraries-to-Note","page":"Modeling Array Libraries","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/array_libraries/#ComponentArrays.jl:-Arrays-with-Arbitrarily-Nested-Named-Components","page":"Modeling Array Libraries","title":"ComponentArrays.jl: Arrays with Arbitrarily Nested Named Components","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"What if you had a set of arrays of arrays with names, but you wanted to represent them on a single contiguous vector so that linear algebra was as fast as possible, while retaining . named accesses with zero-overhead? This is what ComponentArrays.jl provides, and as such it is one of the top recommendations of AbstractArray types to be used. Multi-level definitions such as x = ComponentArray(a=5, b=[(a=20., b=0), (a=33., b=0), (a=44., b=3)], c=c) are common-place, and allow for accessing via x.b.a etc. without any performance loss. ComponentArrays are fully compatible with the SciML equation solvers. They thus can be used as initial conditions. Here's a demonstration of the Lorenz equation using ComponentArrays with Parameters.jl's @unpack:","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"using ComponentArrays\nusing DifferentialEquations\nusing Parameters: @unpack\n\ntspan = (0.0, 20.0)\n\n## Lorenz system\nfunction lorenz!(D, u, p, t; f = 0.0)\n @unpack σ, ρ, β = p\n @unpack x, y, z = u\n\n D.x = σ * (y - x)\n D.y = x * (ρ - z) - y - f\n D.z = x * y - β * z\n return nothing\nend\n\nlorenz_p = (σ = 10.0, ρ = 28.0, β = 8 / 3)\nlorenz_ic = ComponentArray(x = 0.0, y = 0.0, z = 0.0)\nlorenz_prob = ODEProblem(lorenz!, lorenz_ic, tspan, lorenz_p)","category":"page"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Is that beautiful? Yes, it is.","category":"page"},{"location":"highlevels/array_libraries/#StaticArrays.jl:-Statically-Defined-Arrays","page":"Modeling Array Libraries","title":"StaticArrays.jl: Statically-Defined Arrays","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"StaticArrays.jl is a library for statically-defined arrays. Because these arrays have type-level information for size, they recompile the solvers for every new size. They can be dramatically faster for small sizes (up to approximately size 10), but for larger equations they increase compile time with little to no benefit.","category":"page"},{"location":"highlevels/array_libraries/#CUDA.jl:-NVIDIA-CUDA-Based-GPU-Array-Computations","page":"Modeling Array Libraries","title":"CUDA.jl: NVIDIA CUDA-Based GPU Array Computations","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"CUDA.jl is the library for defining arrays which live on NVIDIA GPUs (CuArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus, using CUDA.jl's CuArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a CuArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.","category":"page"},{"location":"highlevels/array_libraries/#AMDGPU.jl:-AMD-Based-GPU-Array-Computations","page":"Modeling Array Libraries","title":"AMDGPU.jl: AMD-Based GPU Array Computations","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"AMDGPU.jl is the library for defining arrays which live on AMD GPUs (ROCArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus using AMDGPU.jl's ROCArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a ROCArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.","category":"page"},{"location":"highlevels/array_libraries/#FillArrays.jl:-Lazy-Arrays","page":"Modeling Array Libraries","title":"FillArrays.jl: Lazy Arrays","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"FillArrays.jl is a library for defining arrays with lazy values. For example, an O(1) representation of the identity matrix is given by Eye{Int}(5). FillArrays.jl is used extensively throughout the ecosystem to improve runtime and memory performance.","category":"page"},{"location":"highlevels/array_libraries/#BandedMatrices.jl:-Fast-Banded-Matrices","page":"Modeling Array Libraries","title":"BandedMatrices.jl: Fast Banded Matrices","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Banded matrices show up in many equation solver contexts, such as the Jacobians of many partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BandedMatrices.jl is a specialized format specifically for BandedMatrices which can be used to greatly improve performance of operations on a banded matrix.","category":"page"},{"location":"highlevels/array_libraries/#BlockBandedMatrices.jl:-Fast-Block-Banded-Matrices","page":"Modeling Array Libraries","title":"BlockBandedMatrices.jl: Fast Block-Banded Matrices","text":"","category":"section"},{"location":"highlevels/array_libraries/","page":"Modeling Array Libraries","title":"Modeling Array Libraries","text":"Block banded matrices show up in many equation solver contexts, such as the Jacobians of many systems of partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BlockBandedMatrices.jl is a specialized format specifically for BlockBandedMatrices which can be used to greatly improve performance of operations on a block-banded matrix.","category":"page"},{"location":"comparisons/r/#r","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"","category":"section"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"If you're an R user who has looked into Julia, you're probably wondering where all of the scientific computing packages are. How do I solve ODEs? Solve f(x)=0 for x? Etc. SciML is the ecosystem for doing this with Julia.","category":"page"},{"location":"comparisons/r/#Why-SciML?-High-Level-Workflow-Reasons","page":"Getting Started with Julia's SciML for the R User","title":"Why SciML? High-Level Workflow Reasons","text":"","category":"section"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"Performance - The key reason people are moving from R to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.\nComposable Library Components - In R environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.\nA Global Harmonious Documentation for Scientific Computing - R's documentation for scientific computing is scattered in a bunch of individual packages where the developers do not talk to each other! This not only leads to documentation differences, but also “style” differences: one package uses tol while the other uses atol. With Julia's SciML, the whole ecosystem is considered together, and inconsistencies are handled at the global level. The goal is to be working in one environment with one language.\nEasier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.\nMix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.","category":"page"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"In this plot, deSolve in blue represents R's most commonly used solver:","category":"page"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"(Image: )","category":"page"},{"location":"comparisons/r/#Need-Help-Translating-from-R-to-Julia?","page":"Getting Started with Julia's SciML for the R User","title":"Need Help Translating from R to Julia?","text":"","category":"section"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"The following resources can be particularly helpful when adopting Julia for SciML for the first time:","category":"page"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"The Julia Manual's Noteworthy Differences from R page\nTutorials on Data Wrangling and Plotting in Julia (Sections 4 and 5) written for folks with a background in R.\nDouble-check your results with deSolveDiffEq.jl (automatically converts and runs ODE definitions with R's deSolve solvers)\nUse RCall.jl to more incrementally move code to Julia.\nComparisons between R and Julia from the DataFrames package. And an accessible starting point for Julia's DataFrames.","category":"page"},{"location":"comparisons/r/#R-to-Julia-SciML-Functionality-Translations","page":"Getting Started with Julia's SciML for the R User","title":"R to Julia SciML Functionality Translations","text":"","category":"section"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"The following chart will help you get quickly acquainted with Julia's SciML Tools:","category":"page"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"R Function/Package SciML-Supported Julia packages\ndata.frame DataFrames\nplot Plots, Makie\nggplot2 AlgebraOfGraphics\ndeSolve DifferentialEquations\nStan Turing","category":"page"},{"location":"comparisons/r/#Want-to-See-the-Power-of-Julia?","page":"Getting Started with Julia's SciML for the R User","title":"Want to See the Power of Julia?","text":"","category":"section"},{"location":"comparisons/r/","page":"Getting Started with Julia's SciML for the R User","title":"Getting Started with Julia's SciML for the R User","text":"Check out this R-Bloggers blog post on diffeqr, a package which uses ModelingToolkit to translate R code to Julia, and achieves 350x acceleration over R's popular deSolve ODE solver package. But when the solve is done purely in Julia, it achieves 2777x acceleration over deSolve!","category":"page"},{"location":"showcase/showcase/#showcase","page":"The SciML Showcase","title":"The SciML Showcase","text":"","category":"section"},{"location":"showcase/showcase/","page":"The SciML Showcase","title":"The SciML Showcase","text":"The SciML Showcase is a display of some cool things that can be done by connecting SciML software.","category":"page"},{"location":"showcase/showcase/","page":"The SciML Showcase","title":"The SciML Showcase","text":"note: Note\nThe SciML Showcase is not meant to be training/tutorials, but inspirational demonstrations! If you're looking for simple examples to get started with, check out the getting started section.","category":"page"},{"location":"showcase/showcase/","page":"The SciML Showcase","title":"The SciML Showcase","text":"Want to see some cool things that you can do with SciML? Check out the following:","category":"page"},{"location":"showcase/showcase/","page":"The SciML Showcase","title":"The SciML Showcase","text":"Scientific machine learning: incorporating prior physics into automated model discovery\nAuto-complete mechanistic models by embedding machine learning into differential equations\nBayesian automated model discovery with quantified uncertainties and probability estimates\nDiscovering the Relativistic Corrections to Binary Black Hole Dynamics\nSolving big difficult equations with parallelism, speed, and accuracy\nAutomated Efficient Solution of Nonlinear Partial Differential Equations\nGPU-Accelerated Physics-Informed Neural Network PDE Solvers\nMassively Data-Parallel ODE Solving on GPUs\nGPU-Accelerated Stochastic Partial Differential Equations\nUseful cool wonky things that are hard to find anywhere else\nAutomatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System\nSymbolic-Numeric Analysis of Parameter Identifiability and Model Stability\nOptimization Under Uncertainty","category":"page"},{"location":"highlevels/equation_solvers/#Equation-Solvers","page":"Equation Solvers","title":"Equation Solvers","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"The SciML Equation Solvers cover a large set of SciMLProblems with SciMLAlgorithms that are efficient, numerically stable, and flexible. These methods tie into libraries like SciMLSensitivity.jl to be fully differentiable and compatible with machine learning pipelines, and are designed for integration with applications like parameter estimation, global sensitivity analysis, and more.","category":"page"},{"location":"highlevels/equation_solvers/#LinearSolve.jl:-Unified-Interface-for-Linear-Solvers","page":"Equation Solvers","title":"LinearSolve.jl: Unified Interface for Linear Solvers","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"LinearSolve.jl is the canonical library for solving LinearProblems. It includes:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Fast pure Julia LU factorizations which outperform standard BLAS\nKLU for faster sparse LU factorization on unstructured matrices\nUMFPACK for faster sparse LU factorization on matrices with some repeated structure\nMKLPardiso wrappers for handling many sparse matrices faster than SuiteSparse (KLU, UMFPACK) methods\nGPU-offloading for large dense matrices\nWrappers to all of the Krylov implementations (Krylov.jl, IterativeSolvers.jl, KrylovKit.jl) for easy testing of all of them. LinearSolve.jl handles the API differences, especially with the preconditioner definitions\nA polyalgorithm that smartly chooses between these methods\nA caching interface which automates caching of symbolic factorizations and numerical factorizations as optimally as possible\nCompatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.","category":"page"},{"location":"highlevels/equation_solvers/#NonlinearSolve.jl:-Unified-Interface-for-Nonlinear-Solvers","page":"Equation Solvers","title":"NonlinearSolve.jl: Unified Interface for Nonlinear Solvers","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"NonlinearSolve.jl is the canonical library for solving NonlinearProblems. It includes:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Fast non-allocating implementations on static arrays of common methods (Newton-Rhapson)\nBracketing methods (Bisection, Falsi) for methods with known upper and lower bounds (IntervalNonlinearProblem)\nWrappers to common other solvers (NLsolve.jl, MINPACK, KINSOL from Sundials) for trust region methods, line search-based approaches, etc.\nBuilt over the LinearSolve.jl API for maximum flexibility and performance in the solving approach\nCompatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.","category":"page"},{"location":"highlevels/equation_solvers/#DifferentialEquations.jl:-Unified-Interface-for-Differential-Equation-Solvers","page":"Equation Solvers","title":"DifferentialEquations.jl: Unified Interface for Differential Equation Solvers","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"DifferentialEquations.jl is the canonical library for solving DEProblems. This includes:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem)\nOrdinary differential equations (ODEs) (ODEProblem)\nSplit and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)\nStochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)\nStochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)\nRandom differential equations (RODEs or RDEs) (RODEProblem)\nDifferential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)\nDelay differential equations (DDEs) (DDEProblem)\nNeutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)\nStochastic delay differential equations (SDDEs) (SDDEProblem)\nExperimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)\nMixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"The well-optimized DifferentialEquations solvers benchmark as some of the fastest implementations of classic algorithms. It also includes algorithms from recent research which routinely outperform the “standard” C/Fortran methods, and algorithms optimized for high-precision and HPC applications. Simultaneously, it wraps the classic C/Fortran methods, making it easy to switch over to them whenever necessary. Solving differential equations with different methods from different languages and packages can be done by changing one line of code, allowing for easy benchmarking to ensure you are using the fastest method possible.","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"DifferentialEquations.jl integrates with the Julia package sphere. Examples are:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"GPU acceleration through CUDAnative.jl and CuArrays.jl\nAutomated sparsity detection with Symbolics.jl\nAutomatic Jacobian coloring with SparseDiffTools.jl, allowing for fast solutions to problems with sparse or structured (Tridiagonal, Banded, BlockBanded, etc.) Jacobians\nAllowing the specification of linear solvers for maximal efficiency\nProgress meter integration with the Juno IDE for estimated time to solution\nAutomatic plotting of time series and phase plots\nBuilt-in interpolations\nWraps for common C/Fortran methods, like Sundials and Hairer's radau\nArbitrary precision with BigFloats and Arbfloats\nArbitrary array types, allowing the definition of differential equations on matrices and distributed arrays\nUnit-checked arithmetic with Unitful","category":"page"},{"location":"highlevels/equation_solvers/#Optimization.jl:-Unified-Interface-for-Optimization","page":"Equation Solvers","title":"Optimization.jl: Unified Interface for Optimization","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Optimization.jl is the canonical library for solving OptimizationProblems. It includes wrappers of most of the Julia nonlinear optimization ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"OptimizationBBO for BlackBoxOptim.jl\nOptimizationEvolutionary for Evolutionary.jl (see also this documentation)\nOptimizationGCMAES for GCMAES.jl\nOptimizationMOI for MathOptInterface.jl (usage of algorithm via MathOptInterface API; see also the API documentation)\nOptimizationMetaheuristics for Metaheuristics.jl (see also this documentation)\nOptimizationMultistartOptimization for MultistartOptimization.jl (see also this documentation)\nOptimizationNLopt for NLopt.jl (usage via the NLopt API; see also the available algorithms)\nOptimizationNOMAD for NOMAD.jl (see also this documentation)\nOptimizationNonconvex for Nonconvex.jl (see also this documentation)\nOptimizationQuadDIRECT for QuadDIRECT.jl\nOptimizationSpeedMapping for SpeedMapping.jl (see also this documentation)","category":"page"},{"location":"highlevels/equation_solvers/#Integrals.jl:-Unified-Interface-for-Numerical-Integration","page":"Equation Solvers","title":"Integrals.jl: Unified Interface for Numerical Integration","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Integrals.jl is the canonical library for solving IntegralsProblems. It includes wrappers of most of the Julia quadrature ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Gauss-Kronrod quadrature\nCubature methods (both h and p cubature)\nAdaptive Monte Carlo methods","category":"page"},{"location":"highlevels/equation_solvers/#JumpProcesses.jl:-Stochastic-Simulation-Algorithms-for-Jump-Processes,-Jump-ODEs,-and-Jump-Diffusions","page":"Equation Solvers","title":"JumpProcesses.jl: Stochastic Simulation Algorithms for Jump Processes, Jump-ODEs, and Jump-Diffusions","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"JumpProcesses.jl is the library for Poisson jump processes, also known as chemical master equations or Gillespie simulations, for simulating chemical reaction networks and other applications. It allows for solving with many methods, including:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Direct: the Gillespie Direct method SSA.\nRDirect: A variant of Gillespie's Direct method that uses rejection to sample the next reaction.\nDirectCR: The Composition-Rejection Direct method of Slepoy et al. For large networks and linear chain-type networks, it will often give better performance than Direct. (Requires dependency graph, see below.)\nDirectFW: the Gillespie Direct method SSA with FunctionWrappers. This aggregator uses a different internal storage format for collections of ConstantRateJumps.\nFRM: the Gillespie first reaction method SSA. Direct should generally offer better performance and be preferred to FRM.\nFRMFW: the Gillespie first reaction method SSA with FunctionWrappers.\nNRM: The Gibson-Bruck Next Reaction Method. For some reaction network structures, this may offer better performance than Direct (for example, large, linear chains of reactions). (Requires dependency graph, see below.)\nRSSA: The Rejection SSA (RSSA) method of Thanh et al. With RSSACR, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)\nRSSACR: The Rejection SSA (RSSA) with Composition-Rejection method of Thanh et al. With RSSA, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)\nSortingDirect: The Sorting Direct Method of McCollum et al. It will usually offer performance as good as Direct, and for some systems can offer substantially better performance. (Requires dependency graph, see below.)","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"The design of JumpProcesses.jl composes with DifferentialEquations.jl, allowing for discrete stochastic chemical reactions to be easily mixed with differential equation models, allowing for simulation of hybrid systems, jump diffusions, and differential equations driven by Levy processes.","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"In addition, JumpProcesses's interfaces allow for solving with regular jump methods, such as adaptive Tau-Leaping.","category":"page"},{"location":"highlevels/equation_solvers/#Third-Party-Libraries-to-Note","page":"Equation Solvers","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/equation_solvers/#JuMP.jl:-Julia-for-Mathematical-Programming","page":"Equation Solvers","title":"JuMP.jl: Julia for Mathematical Programming","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"While Optimization.jl is the preferred library for nonlinear optimization, for all other forms of optimization Julia for Mathematical Programming (JuMP) is the star. JuMP is the leading choice in Julia for doing:","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"Linear Programming\nQuadratic Programming\nConvex Programming\nConic Programming\nSemidefinite Programming\nMixed-Complementarity Programming\nInteger Programming\nMixed Integer (nonlinear/linear) Programming\n(Mixed Integer) Second Order Conic Programming","category":"page"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"JuMP can also be used for some nonlinear programming, though the Optimization.jl bindings to the JuMP solvers (via MathOptInterface.jl) is generally preferred.","category":"page"},{"location":"highlevels/equation_solvers/#FractionalDiffEq.jl:-Fractional-Differential-Equation-Solvers","page":"Equation Solvers","title":"FractionalDiffEq.jl: Fractional Differential Equation Solvers","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"FractionalDiffEq.jl is a set of high-performance solvers for fractional differential equations.","category":"page"},{"location":"highlevels/equation_solvers/#ManifoldDiffEq.jl:-Solvers-for-Differential-Equations-on-Manifolds","page":"Equation Solvers","title":"ManifoldDiffEq.jl: Solvers for Differential Equations on Manifolds","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"ManifoldDiffEq.jl is a set of high-performance solvers for differential equations on manifolds using methods such as Lie Group actions and frozen coefficients (Crouch-Grossman methods). These solvers can in many cases out-perform the OrdinaryDiffEq.jl nonautonomous operator ODE solvers by using methods specialized on manifold definitions of ManifoldsBase.","category":"page"},{"location":"highlevels/equation_solvers/#Manopt.jl:-Optimization-on-Manifolds","page":"Equation Solvers","title":"Manopt.jl: Optimization on Manifolds","text":"","category":"section"},{"location":"highlevels/equation_solvers/","page":"Equation Solvers","title":"Equation Solvers","text":"ManOpt.jl allows for easy and efficient solving of nonlinear optimization problems on manifolds.","category":"page"},{"location":"comparisons/matlab/#matlab","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"","category":"section"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"If you're a MATLAB user who has looked into Julia for some performance improvements, you may have noticed that the standard library does not have all of the “batteries” included with a base MATLAB installation. Where's the ODE solver? Where's fmincon and fsolve? Those scientific computing functionalities are the pieces provided by the Julia SciML ecosystem!","category":"page"},{"location":"comparisons/matlab/#Why-SciML?-High-Level-Workflow-Reasons","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Why SciML? High-Level Workflow Reasons","text":"","category":"section"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"Performance - The key reason people are moving from MATLAB to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.\nJulia is quick to learn from MATLAB - Most ODE codes can be translated in a few minutes. If you need help, check out the QuantEcon MATLAB-Python-Julia Cheat Sheet.\nPackage Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.\nFree and Open Source - If you want to know how things are being computed, just look at our GitHub organization. Lots of individuals use Julia's SciML to research how the algorithms actually work because of how accessible and tweakable the ecosystem is!\nComposable Library Components - In MATLAB environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.\nEasier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.\nMix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.","category":"page"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"In this plot, MATLAB in orange represents MATLAB's most commonly used solvers:","category":"page"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"(Image: )","category":"page"},{"location":"comparisons/matlab/#Need-a-case-study?","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Need a case study?","text":"","category":"section"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"Check out this talk from NASA Scientists getting a 15,000x acceleration by switching from Simulink to Julia's ModelingToolkit!","category":"page"},{"location":"comparisons/matlab/#Need-Help-Translating-from-MATLAB-to-Julia?","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Need Help Translating from MATLAB to Julia?","text":"","category":"section"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"The following resources can be particularly helpful when adopting Julia for SciML for the first time:","category":"page"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"QuantEcon MATLAB-Python-Julia Cheat Sheet\nThe Julia Manual's Noteworthy Differences from MATLAB page\nDouble-check your results with MATLABDiffEq.jl (automatically converts and runs ODE definitions with MATLAB's solvers)\nUse MATLAB.jl to more incrementally move code to Julia.","category":"page"},{"location":"comparisons/matlab/#MATLAB-to-Julia-SciML-Functionality-Translations","page":"Getting Started with Julia's SciML for the MATLAB User","title":"MATLAB to Julia SciML Functionality Translations","text":"","category":"section"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"The following chart will help you get quickly acquainted with Julia's SciML Tools:","category":"page"},{"location":"comparisons/matlab/","page":"Getting Started with Julia's SciML for the MATLAB User","title":"Getting Started with Julia's SciML for the MATLAB User","text":"MATLAB Function SciML-Supported Julia packages\nplot Plots, Makie\nsparse SparseArrays\ninterp1 DataInterpolations\n\\, gmres, cg LinearSolve\nfsolve NonlinearSolve\nquad Integrals\nfmincon Optimization\nodeXX DifferentialEquations\node45 Tsit5\node113 VCABM\node23s Rosenbrock23\node15s QNDF or FBDF\node15i IDA\nbvp4c and bvp5c DifferentialEquations\nSimulink, Simscape ModelingToolkit\nfft FFTW\nchebfun ApproxFun","category":"page"},{"location":"highlevels/inverse_problems/#parameter_estimation","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"Parameter estimation for models and equations, also known as dynamic data analysis, solving the inverse problem, or Bayesian posterior estimation (when done probabilistically), is provided by the SciML tools for the equations in its set. In this introduction, we briefly present the relevant packages that facilitate parameter estimation, namely:","category":"page"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"SciMLSensitivity.jl\nDiffEqFlux.jl\nTuring.jl\nDataDrivenDiffEq.jl\nDiffEqParamEstim.jl\nDiffEqBayes.jl","category":"page"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"We also provide information regarding the respective strengths of these packages so that you can easily decide which one suits your needs best.","category":"page"},{"location":"highlevels/inverse_problems/#SciMLSensitivity.jl:-Local-Sensitivity-Analysis-and-Automatic-Differentiation-Support-for-Solvers","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"SciMLSensitivity.jl: Local Sensitivity Analysis and Automatic Differentiation Support for Solvers","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"SciMLSensitivity.jl is the system for local sensitivity, which all other inverse problem methods rely on. This package defines the interactions between the equation solvers and automatic differentiation, defining fast overloads for forward and adjoint (reverse) sensitivity analysis for fast gradient and Jacobian calculations with respect to model inputs. Its documentation covers how to use direct differentiation of equation solvers in conjunction with tools like Optimization.jl to perform model calibration of ODEs against data, PDE-constrained optimization, nonlinear optimal controls analysis, and much more. As a lower level tool, this library is very versatile, feature-rich, and high-performance, giving all the tools required but not directly providing a higher level interface.","category":"page"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"note: Note\nSensitivity analysis is kept in a separate library from the solvers (SciMLSensitivity.jl), in order to not require all equation solvers to have a dependency on all automatic differentiation libraries. If automatic differentiation is applied to a solver library without importing SciMLSensitivity.jl, an error is thrown letting the user know to import SciMLSensitivity.jl for the functionality to exist.","category":"page"},{"location":"highlevels/inverse_problems/#DataDrivenDiffEq.jl:-Data-Driven-Modeling-and-Equation-Discovery","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"DataDrivenDiffEq.jl: Data-Driven Modeling and Equation Discovery","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"The distinguishing feature of this package is that its ultimate goal is to identify the differential equation model that generated the input data. Depending on the user's needs, the package can provide structural identification of a given differential equation (output in a symbolic form) or structural estimation (output as a function for prediction purposes).","category":"page"},{"location":"highlevels/inverse_problems/#DiffEqParamEstim.jl:-Simplified-Parameter-Estimation-Interface","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"DiffEqParamEstim.jl: Simplified Parameter Estimation Interface","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"This package is for simplified parameter estimation. While not as flexible of a system like DiffEqFlux.jl, it provides ready-made functions for doing standard optimization procedures like L2 fitting and MAP estimates. Among other features, it allows for the optimization of parameters in ODEs, stochastic problems, and delay differential equations.","category":"page"},{"location":"highlevels/inverse_problems/#DiffEqBayes.jl:-Simplified-Bayesian-Estimation-Interface","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"DiffEqBayes.jl: Simplified Bayesian Estimation Interface","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"As the name suggests, this package has been designed to provide the estimation of differential equations parameters by Bayesian methods. It works in conjunction with Turing.jl, CmdStan.jl, DynamicHMC.jl, and ApproxBayes.jl. While not as flexible as direct usage of DiffEqFlux.jl or Turing.jl, DiffEqBayes.jl can be an approachable interface for those not familiar with Bayesian estimation, and provides a nice way to use Stan from pure Julia.","category":"page"},{"location":"highlevels/inverse_problems/#Third-Party-Tools-of-Note","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Third-Party Tools of Note","text":"","category":"section"},{"location":"highlevels/inverse_problems/#Turing.jl:-A-Flexible-Probabilistic-Programming-Language-for-Bayesian-Analysis","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Turing.jl: A Flexible Probabilistic Programming Language for Bayesian Analysis","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"In the context of differential equations and parameter estimation, Turing.jl allows for a Bayesian estimation of differential equations (used in conjunction with the high-level package DiffEqBayes.jl). For more examples on combining Turing.jl with DiffEqBayes.jl, see the documentation below. It is important to note that Turing.jl can also perform Bayesian estimation without relying on DiffEqBayes.jl (for an example, consult this tutorial).","category":"page"},{"location":"highlevels/inverse_problems/#Topopt.jl:-Topology-Optimization-in-Julia","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Topopt.jl: Topology Optimization in Julia","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"Topopt.jl solves topology optimization problems which are inverse problems on partial differential equations, solving for an optimal domain.","category":"page"},{"location":"highlevels/inverse_problems/#Recommended-Automatic-Differentiation-Libraries","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Recommended Automatic Differentiation Libraries","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"Solving inverse problems commonly requires using automatic differentiation (AD). SciML includes extensive support for automatic differentiation throughout its solvers, though some AD libraries are more tested than others. The following libraries are the current recommendations of the SciML developers.","category":"page"},{"location":"highlevels/inverse_problems/#ForwardDiff.jl:-Operator-Overloading-Forward-Mode-Automatic-Differentiation","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"ForwardDiff.jl: Operator-Overloading Forward Mode Automatic Differentiation","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"ForwardDiff.jl is a library for operator-overloading based forward-mode automatic differentiation. It's commonly used as the default method for generating Jacobians throughout the SciML solver libraries.","category":"page"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"note: Note\nBecause ForwardDiff.jl uses an operator overloading approach, uses of ForwardDiff.jl require that any caches for non-allocating mutating code allows for Dual numbers. To allow such code to be ForwardDiff.jl-compatible, see PreallocationTools.jl.","category":"page"},{"location":"highlevels/inverse_problems/#Enzyme.jl:-LLVM-Level-Forward-and-Reverse-Mode-Automatic-Differentiation","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Enzyme.jl: LLVM-Level Forward and Reverse Mode Automatic Differentiation","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"Enzyme.jl is an LLVM-level AD library for forward and reverse automatic differentiation. It supports many features required for high performance, such as being able to differentiate mutating and interleave compiler optimization with the AD passes. However, it does not support all of the Julia runtime, and thus some code with many dynamic behaviors and garbage collection (GC) invocations can be incompatible with Enzyme. Enzyme.jl is quickly becoming the new standard AD for SciML.","category":"page"},{"location":"highlevels/inverse_problems/#Zygote.jl:-Julia-Level-Source-to-Source-Reverse-Mode-Automatic-Differentiation","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Zygote.jl: Julia-Level Source-to-Source Reverse Mode Automatic Differentiation","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"Zygote.jl is the current standard user-level reverse-mode automatic differentiation library for the SciML solvers. User-level means that many library tutorials, like in SciMLSensitivity.jl and DiffEqFlux.jl, showcase user code using Zygote.jl. This is because Zygote.jl is the AD engine associated with the Flux machine learning library. However, Zygote.jl has many limitations which limits its performance in equation solver contexts, such as an inability to handle mutation and introducing many small allocations and type-instabilities. For this reason, the SciML equation solvers define differentiation overloads using ChainRules.jl, meaning that the equation solvers tend not to use Zygote.jl internally even if the user code uses Zygote.gradient. In this manner, the speed and performance of more advanced techniques can be preserved while using the Julia standard.","category":"page"},{"location":"highlevels/inverse_problems/#FiniteDiff.jl:-Fast-Finite-Difference-Approximations","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"FiniteDiff.jl: Fast Finite Difference Approximations","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"FiniteDiff.jl is the preferred fallback library for numerical differentiation and is commonly used by SciML solver libraries when automatic differentiation is disabled.","category":"page"},{"location":"highlevels/inverse_problems/#SparseDiffTools.jl:-Tools-for-Fast-Automatic-Differentiation-with-Sparse-Operators","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"SparseDiffTools.jl: Tools for Fast Automatic Differentiation with Sparse Operators","text":"","category":"section"},{"location":"highlevels/inverse_problems/","page":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","title":"Parameter Estimation, Bayesian Analysis, and Inverse Problems","text":"SparseDiffTools.jl is a library for sparse automatic differentiation. It's used internally by many of the SciML equation solver libraries, which explicitly expose interfaces for colorvec color vectors generated by SparseDiffTools.jl's methods. SparseDiffTools.jl also includes many features useful to users, such as operators for matrix-free Jacobian-vector and Hessian-vector products.","category":"page"},{"location":"getting_started/find_root/#find_root","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"A nonlinear system f(u) = 0 is specified by defining a function f(u,p), where p are the parameters of the system. Many problems can be written in such a way that solving a nonlinear rootfinding problem gives the solution. For example:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Do you want to know u such that 4^u + 6^u = 7^u? Then solve f(u) = 4^u + 6^u - 7^u = 0 for u!\nIf you have an ODE u = f(u), what is the point where the solution will be completely still, i.e. u' = 0?","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"All of these problems are solved by using a numerical rootfinder. Let's solve our first rootfind problem!","category":"page"},{"location":"getting_started/find_root/#Required-Dependencies","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Required Dependencies","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"The following parts of the SciML Ecosystem will be used in this tutorial:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Module Description\nModelingToolkit.jl The symbolic modeling environment\nNonlinearSolve.jl The numerical solvers for nonlinear equations","category":"page"},{"location":"getting_started/find_root/#Problem-Setup","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Problem Setup","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"For example, the following solves the vector equation:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"beginaligned\n0 = σ*(y-x)\n0 = x*(ρ-z)-y\n0 = x*y - β*z\nendaligned","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"With the parameter values sigma = 100, rho = 260, beta = 83.","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Import the packages\nusing ModelingToolkit, NonlinearSolve\n\n# Define the nonlinear system\n@variables x=1.0 y=0.0 z=0.0\n@parameters σ=10.0 ρ=26.0 β=8 / 3\n\neqs = [0 ~ σ * (y - x),\n 0 ~ x * (ρ - z) - y,\n 0 ~ x * y - β * z]\n@mtkbuild ns = NonlinearSystem(eqs, [x, y, z], [σ, ρ, β])\n\n# Convert the symbolic system into a numerical system\nprob = NonlinearProblem(ns, [])\n\n# Solve the numerical problem\nsol = solve(prob, NewtonRaphson())\n\n# Analyze the solution\n@show sol[[x,y,z]], sol.resid","category":"page"},{"location":"getting_started/find_root/#Step-by-Step-Solution","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step-by-Step Solution","text":"","category":"section"},{"location":"getting_started/find_root/#Step-1:-Import-the-Packages","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step 1: Import the Packages","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"To do this tutorial, we will need a few components:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"ModelingToolkit.jl, our modeling environment\nNonlinearSolve.jl, the nonlinear system solvers","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"To start, let's add these packages as demonstrated in the installation tutorial:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"using Pkg\nPkg.add([\"ModelingToolkit\", \"NonlinearSolve\"])","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now we're ready. Let's load in these packages:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Import the packages\nusing ModelingToolkit, NonlinearSolve","category":"page"},{"location":"getting_started/find_root/#Step-2:-Define-the-Nonlinear-System","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step 2: Define the Nonlinear System","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now let's define our nonlinear system. We use the ModelingToolkit.@variabes statement to declare our 3 state variables:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Define the nonlinear system\n@variables x=1.0 y=0.0 z=0.0","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Notice that we are using the form state = initial condition. This is a nice shorthand for coupling an initial condition to our states. We now must similarly define our parameters, which we can associate default values via the form parameter = default value. This looks like:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"@parameters σ=10.0 ρ=26.0 β=8 / 3","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now we create an array of equations to define our nonlinear system that must be satisfied. This looks as follows:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"note: Note\nNote that in ModelingToolkit and Symbolics, ~ is used for equation equality. This is separate from = which is the “assignment operator” in the Julia programming language. For example, x = x + 1 is a valid assignment in a programming language, and it is invalid for that to represent “equality”, which is why a separate operator is used!","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"eqs = [0 ~ σ * (y - x),\n 0 ~ x * (ρ - z) - y,\n 0 ~ x * y - β * z]","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Finally, we bring these pieces together, the equation along with its states and parameters, define our NonlinearSystem:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"@mtkbuild ns = NonlinearSystem(eqs, [x, y, z], [σ, ρ, β])","category":"page"},{"location":"getting_started/find_root/#Step-3:-Convert-the-Symbolic-Problem-to-a-Numerical-Problem","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step 3: Convert the Symbolic Problem to a Numerical Problem","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now that we have created our system, let's turn it into a numerical problem to approximate. This is done with the NonlinearProblem constructor, that transforms it from a symbolic ModelingToolkit representation to a numerical NonlinearSolve representation. We need to tell it the numerical details for whether to override any of the default values for the initial conditions and parameters.","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"In this case, we will use the default values for all our variables, so we will pass a blank override []. This looks like:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Convert the symbolic system into a numerical system\nprob = NonlinearProblem(ns, [])","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"If we did want to change the initial condition of x to 2.0 and the parameter σ to 4.0, we would do [x => 2.0, σ => 4.0]. This looks like:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"prob2 = NonlinearProblem(ns, [x => 2.0, σ => 4.0])","category":"page"},{"location":"getting_started/find_root/#Step-4:-Solve-the-Numerical-Problem","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step 4: Solve the Numerical Problem","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now we solve the nonlinear system. For this, we choose a solver from the NonlinearSolve.jl's solver options. We will choose NewtonRaphson as follows:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Solve the numerical problem\nsol = solve(prob, NewtonRaphson())","category":"page"},{"location":"getting_started/find_root/#Step-5:-Analyze-the-Solution","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Step 5: Analyze the Solution","text":"","category":"section"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"typeof(sol)","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"From this, we can see that it is an NonlinearSolution. We can see the documentation for how to use the NonlinearSolution by checking the NonlinearSolve.jl solution type page. For example, the solution is stored as .u. What is the solution to our nonlinear system, and what is the final residual value? We can check it as follows:","category":"page"},{"location":"getting_started/find_root/","page":"Find the root of an equation (i.e. solve f(u)=0)","title":"Find the root of an equation (i.e. solve f(u)=0)","text":"# Analyze the solution\n@show sol[[x,y,z]], sol.resid","category":"page"},{"location":"highlevels/uncertainty_quantification/#Uncertainty-Quantification","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"There's always uncertainty in our models. Whether it's in the form of the model's equations or in the model's parameters, the uncertainty in our simulation's output often needs to be quantified. The following tools automate this process.","category":"page"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"For Measurements.jl vs MonteCarloMeasurements.jl vs Intervals.jl, and the relation to other methods, see the Uncertainty Programming chapter of the SciML Book.","category":"page"},{"location":"highlevels/uncertainty_quantification/#PolyChaos.jl:-Intrusive-Polynomial-Chaos-Expansions-Made-Unintrusive","page":"Uncertainty Quantification","title":"PolyChaos.jl: Intrusive Polynomial Chaos Expansions Made Unintrusive","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"PolyChaos.jl is a library for calculating intrusive polynomial chaos expansions (PCE) on arbitrary Julia functions. This allows for inputting representations of probability distributions into functions to compute the output distribution in an expansion representation. While normally this would require deriving the PCE-expanded equations by hand, PolyChaos.jl does this at the compiler level using Julia's multiple dispatch, giving a high-performance implementation to a normally complex and tedious mathematical transformation.","category":"page"},{"location":"highlevels/uncertainty_quantification/#SciMLExpectations.jl:-Fast-Calculations-of-Expectations-of-Equation-Solutions","page":"Uncertainty Quantification","title":"SciMLExpectations.jl: Fast Calculations of Expectations of Equation Solutions","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"SciMLExpectations.jl is a library for accelerating the calculation of expectations of equation solutions with respect to input probability distributions, allowing for applications like robust optimization with respect to uncertainty. It uses Koopman operator techniques to calculate these expectations without requiring the propagation of uncertainties through a solver, effectively performing the adjoint of uncertainty quantification and being much more efficient in the process.","category":"page"},{"location":"highlevels/uncertainty_quantification/#Third-Party-Libraries-to-Note","page":"Uncertainty Quantification","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/#Measurements.jl:-Automated-Linear-Error-Propagation","page":"Uncertainty Quantification","title":"Measurements.jl: Automated Linear Error Propagation","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"Measurements.jl is a library for automating linear error propagation. Uncertain numbers are defined as x = 3.8 ± 0.4 and are pushed through calculations using a normal distribution approximation in order to compute an approximate uncertain output. Measurements.jl uses a dictionary-based approach to keep track of correlations to improve the accuracy over naive implementations, though note that linear error propagation theory still has some major issues handling some types of equations, as described in detail in the MonteCarloMeasurements.jl documentation.","category":"page"},{"location":"highlevels/uncertainty_quantification/#MonteCarloMeasurements.jl:-Automated-Monte-Carlo-Error-Propagation","page":"Uncertainty Quantification","title":"MonteCarloMeasurements.jl: Automated Monte Carlo Error Propagation","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"MonteCarloMeasurements.jl is a library for automating the uncertainty quantification of equation solution using Monte Carlo methods. It defines number types which sample from an input distribution to receive a representative set of parameters that propagate through the solver to calculate a representative set of possible solutions. Note that Monte Carlo techniques can be expensive but are exact, in the sense that as the number of sample points increases to infinity it will compute a correct approximation of the output uncertainty.","category":"page"},{"location":"highlevels/uncertainty_quantification/#ProbNumDiffEq.jl:-Probabilistic-Numerics-Based-Differential-Equation-Solvers","page":"Uncertainty Quantification","title":"ProbNumDiffEq.jl: Probabilistic Numerics Based Differential Equation Solvers","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"ProbNumDiffEq.jl is a set of probabilistic numerical ODE solvers which compute the solution of a differential equation along with a posterior distribution to estimate its numerical approximation error. Thus these specialized integrators compute an uncertainty output similar to the ProbInts technique of DiffEqUncertainty, but use specialized integration techniques in order to do it much faster for specific kinds of equations.","category":"page"},{"location":"highlevels/uncertainty_quantification/#TaylorIntegration.jl:-Taylor-Series-Integration-for-Rigorous-Numerical-Bounds","page":"Uncertainty Quantification","title":"TaylorIntegration.jl: Taylor Series Integration for Rigorous Numerical Bounds","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"TaylorIntegration.jl is a library for Taylor series integrators, which has special functionality for computing the interval bound of possible solutions with respect to numerical approximation error.","category":"page"},{"location":"highlevels/uncertainty_quantification/#IntervalArithmetic.jl:-Rigorous-Numerical-Intervals","page":"Uncertainty Quantification","title":"IntervalArithmetic.jl: Rigorous Numerical Intervals","text":"","category":"section"},{"location":"highlevels/uncertainty_quantification/","page":"Uncertainty Quantification","title":"Uncertainty Quantification","text":"IntervalArithmetic.jl is a library for performing interval arithmetic calculations on arbitrary Julia code. Interval arithmetic computes rigorous computations with respect to finite-precision floating-point arithmetic, i.e. its intervals are guaranteed to include the true solution. However, interval arithmetic intervals can grow at exponential rates in many problems, thus being unsuitable for analyses in many equation solver contexts.","category":"page"},{"location":"getting_started/installation/#installation","page":"Installing SciML Software","title":"Installing SciML Software","text":"","category":"section"},{"location":"getting_started/installation/#Step-1:-Install-Julia","page":"Installing SciML Software","title":"Step 1: Install Julia","text":"","category":"section"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"Download Julia using this website.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"note: Note\nSome Linux distributions do weird and incorrect things with Julia installations! Please install Julia using the binaries provided by the official JuliaLang website!","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"To ensure that you have installed Julia correctly, open it up and type versioninfo() in the REPL. It should look like the following:","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(Image: )","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(with the CPU/OS/etc. details matching your computer!)","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"If you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms","category":"page"},{"location":"getting_started/installation/#Optional-Step-1.5:-Get-VS-Code-Setup-with-the-Julia-Extension","page":"Installing SciML Software","title":"Optional Step 1.5: Get VS Code Setup with the Julia Extension","text":"","category":"section"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"You can run SciML with Julia in any development environment you please, but our recommended environment is VS Code. For more information on using Julia with VS Code, check out the Julia VS Code Extension website. Let's install it!","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"First download VS Code from the official website.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"Next, open Visual Studio Code and click Extensions.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(Image: )","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"Then, search for “Julia” in the search bar on the top of the extension tab, click on the “Julia” extension, and click the install button on the tab that opens up.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(Image: )","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"To make sure your installation is correct, try running some code. Open a new file by either going to the top left navigation bar File |> New Text File, or hitting Ctrl+n. Name your new file test.jl (important: the Julia VS Code functionality only turns on when using a .jl file!). Next, type 1+1 and hit Ctrl+Enter. A Julia REPL should pop up and the result 2 should be displayed. Your environment should look something like this:","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(Image: )","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"For more help on using the VS Code editor with Julia, check out the VS Code in Julia documentation. Useful keyboard commands can be found here.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"Once again, if you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms","category":"page"},{"location":"getting_started/installation/#Step-2:-Install-a-SciML-Package","page":"Installing SciML Software","title":"Step 2: Install a SciML Package","text":"","category":"section"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"SciML is over 130 Julia packages. That's too much stuff to give someone in a single download! Thus instead, the SciML organization divides its functionality into composable modules that can be mixed and matched as required. Installing SciML ecosystem functionality is equivalent to installation of such packages.","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"For example, do you need the differential equation solver? Then install DifferentialEquations via the command:","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"using Pkg;\nPkg.add(\"DifferentialEquations\");","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"in the Julia REPL. Or, for a more robust REPL experience, hit the ] command to make the blue pkg> REPL environment start, and type in add DifferentialEquations. The package REPL environment will have nice extras like auto-complete that will be useful in the future. This command should run an installation sequence and precompile all of the packages (precompile = \"run a bunch of performance optimizations!\"). Don't be surprised if this installation process takes ~10 minutes on older computers. During the installation, it should look like this:","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"(Image: )","category":"page"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"And that's it!","category":"page"},{"location":"getting_started/installation/#How-do-I-test-that-my-installed-correctly?","page":"Installing SciML Software","title":"How do I test that my installed correctly?","text":"","category":"section"},{"location":"getting_started/installation/","page":"Installing SciML Software","title":"Installing SciML Software","text":"The best way is to build and run your first simulation!","category":"page"},{"location":"highlevels/plots_visualization/#SciML-Supported-Plotting-and-Visualization-Libraries","page":"SciML-Supported Plotting and Visualization Libraries","title":"SciML-Supported Plotting and Visualization Libraries","text":"","category":"section"},{"location":"highlevels/plots_visualization/","page":"SciML-Supported Plotting and Visualization Libraries","title":"SciML-Supported Plotting and Visualization Libraries","text":"The following libraries are the plotting and visualization libraries which are supported and co-developed by the SciML developers. Other libraries may be used, though these are the libraries used in the tutorials and which have special hooks to ensure ergonomic usage with SciML tooling.","category":"page"},{"location":"highlevels/plots_visualization/#Plots.jl","page":"SciML-Supported Plotting and Visualization Libraries","title":"Plots.jl","text":"","category":"section"},{"location":"highlevels/plots_visualization/","page":"SciML-Supported Plotting and Visualization Libraries","title":"SciML-Supported Plotting and Visualization Libraries","text":"Plots.jl is the current standard plotting system for the SciML ecosystem. SciML types attempt to include plot recipes for as many types as possible, allowing for automatic visualization with the Plots.jl system. All current tutorials and documentation default to using Plots.jl.","category":"page"},{"location":"highlevels/plots_visualization/#Makie.jl","page":"SciML-Supported Plotting and Visualization Libraries","title":"Makie.jl","text":"","category":"section"},{"location":"highlevels/plots_visualization/","page":"SciML-Supported Plotting and Visualization Libraries","title":"SciML-Supported Plotting and Visualization Libraries","text":"Makie.jl is a high-performance interactive plotting system for the Julia programming language. It's planned to be the default plotting system used by the SciML organization in the near future.","category":"page"},{"location":"highlevels/model_libraries_and_importers/#Model-Libraries-and-Importers","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"Models are passed on from generation to generation. Many models are not built from scratch but have a legacy of the known physics, biology, and chemistry embedded into them. Julia's SciML offers a range of pre-built modeling tools, from reusable acausal components to direct imports from common file formats.","category":"page"},{"location":"highlevels/model_libraries_and_importers/#ModelingToolkitStandardLibrary.jl:-A-Standard-Library-for-ModelingToolkit","page":"Model Libraries and Importers","title":"ModelingToolkitStandardLibrary.jl: A Standard Library for ModelingToolkit","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"Given the composable nature of acausal modeling systems, it's helpful to not have to define every component from scratch and instead build off a common base of standard components. ModelingToolkitStandardLibrary.jl is that library. It provides components for standard models to start building everything from circuits and engines to robots.","category":"page"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"(Image: )","category":"page"},{"location":"highlevels/model_libraries_and_importers/#DiffEqCallbacks.jl:-Pre-Made-Callbacks-for-DifferentialEquations.jl","page":"Model Libraries and Importers","title":"DiffEqCallbacks.jl: Pre-Made Callbacks for DifferentialEquations.jl","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"DiffEqCallbacks.jl has many event handling and callback definitions which allow for quickly building up complex differential equation models. It includes:","category":"page"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"Callbacks for specialized output and saving procedures\nCallbacks for enforcing domain constraints, positivity, and manifolds\nTimed callbacks for periodic dosing, presetting of tstops, and more\nCallbacks for determining and terminating at steady state\nCallbacks for controlling stepsizes and enforcing CFL conditions\nCallbacks for quantifying uncertainty with respect to numerical errors","category":"page"},{"location":"highlevels/model_libraries_and_importers/#SBMLToolkit.jl:-SBML-Import","page":"Model Libraries and Importers","title":"SBMLToolkit.jl: SBML Import","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"SBMLToolkit.jl is a library for reading SBML files into the standard formats for Catalyst.jl and ModelingToolkit.jl. There are well over one thousand biological models available in the BioModels Repository.","category":"page"},{"location":"highlevels/model_libraries_and_importers/#CellMLToolkit.jl:-CellML-Import","page":"Model Libraries and Importers","title":"CellMLToolkit.jl: CellML Import","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"CellMLToolkit.jl is a library for reading CellML files into the standard formats for ModelingToolkit.jl. There are several hundred biological models available in the CellML Model Repository.","category":"page"},{"location":"highlevels/model_libraries_and_importers/#ReactionNetworkImporters.jl:-BioNetGen-Import","page":"Model Libraries and Importers","title":"ReactionNetworkImporters.jl: BioNetGen Import","text":"","category":"section"},{"location":"highlevels/model_libraries_and_importers/","page":"Model Libraries and Importers","title":"Model Libraries and Importers","text":"ReactionNetworkImporters.jl is a library for reading BioNetGen .net files and various stoichiometry matrix representations into the standard formats for Catalyst.jl and ModelingToolkit.jl.","category":"page"},{"location":"comparisons/cppfortran/#cppfortran","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"You don't need help if you're a Fortran guru. I'm just kidding, you're not a Lisp developer. If you're coming from C++ or Fortran, you may be familiar with high-performance computing environments similar to SciML, such as PETSc, Trilinos, or Sundials. The following are some points to help the transition.","category":"page"},{"location":"comparisons/cppfortran/#Why-SciML?-High-Level-Workflow-Reasons","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Why SciML? High-Level Workflow Reasons","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"If you're coming from “hardcore” C++/Fortran computing environments, some things to check out with Julia's SciML are:","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"Interactivity - use the interactive REPL to easily investigate numerical details.\nMetaprogramming performance tools - tools like LoopVectorization.jl can be used to generate faster code than even some of the most hand-optimized C++/Fortran code. Current benchmarks show this SIMD-optimized Julia code outperforming OpenBLAS and MKL BLAS implementations in many performance regimes.\nSymbolic modeling languages - writing models by hand can leave a lot of performance on the table. Using high-level modeling tools like ModelingToolkit can automate symbolic simplifications, which improve the stability and performance of numerical solvers. On complex models, even the best handwritten C++/Fortran code is orders of magnitude behind the code that symbolic tearing algorithms can achieve!\nComposable Library Components - In C++/Fortran environments, every package feels like a silo. Arrays made for PETSc cannot easily be used in Trilinos, and converting Sundials NVector outputs to DataFrames for post-simulation data processing is a process itself. The Julia SciML environment embraces interoperability. Don't wait for SciML to do it: by using generic coding with JIT compilation, these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.\nWrappers to the Libraries You Know and Trust - Moving to SciML does not have to be a quick transition. SciML has extensive wrappers to many widely-used classical solver environments such as SUNDIALS and Hairer's classic Fortran ODE solvers (dopri5, dop853, etc.). Using these wrapped solvers is painless and can be swapped in for the Julia versions with one line of code. This gives you a way to incrementally adopt new features/methods while retaining the older pieces you know and trust.\nDon't Start from Scratch - SciML builds on the extensive Base library of Julia, and thus grows and improves with every update to the language. With hundreds of monthly contributors to SciML and hundreds of monthly contributors to Julia, SciML is one of the most actively developed open-source scientific computing ecosystems out there!\nEasier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.\nMix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"In this plot, Sundials/Hairer in purple/red represent C++/Fortrans most commonly used solvers:","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"(Image: )","category":"page"},{"location":"comparisons/cppfortran/#Why-SciML?-Some-Technical-Details","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Why SciML? Some Technical Details","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"Let's face the facts, in the open benchmarks the pure-Julia solvers tend to outperform the classic “best” C++ and Fortran solvers in almost every example (with a few notable exceptions). But why?","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"The answer is two-fold: Julia is as fast as C++/Fortran, and the algorithms are what matter.","category":"page"},{"location":"comparisons/cppfortran/#Julia-is-as-Fast-as-C/Fortran","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Julia is as Fast as C++/Fortran","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"While Julia code looks high level like Python or MATLAB, its performance is on par with C++ and Fortran. At a technical level, when Julia code is type-stable, i.e. that the types that are returned from a function are deducible at compile-time from the types that go into a function, then Julia can optimize it as much as C++ or Fortran by automatically devirtualizing all dynamic behavior and compile-time optimizing the quasi-static code. This is not an empirical statement, it's a provable type-theoretic result. The resulting compiler used on the resulting quasi-static representation is LLVM, the same optimizing compiler used by clang and LFortran.","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"For more details on how Julia code is optimized and how to optimize your own Julia code, check out this chapter from the SciML Book.","category":"page"},{"location":"comparisons/cppfortran/#SciML's-Julia-Algorithms-Have-Performance-Advantages-in-Many-Common-Regimes","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"SciML's Julia Algorithms Have Performance Advantages in Many Common Regimes","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"There are many ways which Julia's algorithms achieve performance advantages. Some facts to highlight include:","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"Julia is at the forefront of numerical methods research in many domains. This is highlighted in the differential equation solver comparisons, where the Julia solvers were the first to incorporate “newer” optimized Runge-Kutta tableaus, around half a decade before other software. Since then, the literature has only continued to evolve, and only Julia's SciML keeps up. At this point, many of the publication's first implementation is in OrdinaryDiffEq.jl with benchmark results run on the SciML Open Benchmarking platform!\nJulia does not take low-level mathematical functions for granted. The common openlibm implementation of mathematical functions used in many open source projects is maintained by the Julia and SciML developers! However, in modern Julia, every function from log to ^ has been reimplemented in the Julia standard library to improve numerical correctness and performance. For example, Pumas, the nonlinear mixed effects estimation system built on SciML, and used by Moderna for the vaccine trials, notes in its paper that approximations to such math libraries itself gave a 2x performance improvement in even the most simple non-stiff ODE solvers over matching Fortran implementations. Pure Julia linear algebra tooling, like RecursiveFactorization.jl for LU-factorization, outperforms common LU-factorization implementations used in open-source projects like OpenBLAS by around 5x! This should not be surprising though, given that OpenBLAS was a prior MIT Julia Lab project!\nCompilers are limited on the transformations that they can perform because they do not have high-level context-dependent mathematical knowledge. Julia's SciML makes extensive use of customized symbolic-based compiler transformations to improve performance with context-based code optimizations. Things like sparsity patterns are automatically deduced from code and optimized on. Nonlinear equations are symbolically-torn, changing large nonlinear systems into sequential solving of much smaller systems and benefiting from an O(n^3) cost reduction. These can be orders of magnitude cost reductions which come for free, and unless you know every trick in the book it will be difficult to match SciML's performance!\nPervasive automatic differentiation mixed with compiler tricks wins battles. Many high-performance libraries in C++ and Fortran cannot assume that all of its code is compatible with automatic differentiation, and thus many internal performance tricks are not applied. For example, ForwardDiff.jl's chunk seeding allows for a single call to f to generate multiple columns of a Jacobian. When mixed with sparse coloring tools, entire Jacobians can be constructed with just a few f calls. Studies in applications have shown this greatly outperforms finite differencing, especially when Julia's implicit multithreading is used.","category":"page"},{"location":"comparisons/cppfortran/#Let's-Dig-Deep-Into-One-Case:-Adjoints-of-ODEs-for-Solving-Inverse-Problems","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Let's Dig Deep Into One Case: Adjoints of ODEs for Solving Inverse Problems","text":"","category":"section"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"To really highlight how JIT compilation and automatic differentiation integration can change algorithms, let's look at the problem of differentiating an ODE solver. As is derived and discussed in detail at a seminar with the American Statistical Association, there are many ways to implement well-known “adjoint” methods which are required for performance. Each has different stability and performance trade-offs, and Julia's SciML is the only system to systemically offer all of the trade-off options. In many cases, using analytical adjoints of a solver is not advised due to performance reasons, with the trade-off described in detail here. Likewise, even when analytical adjoints are used, it turns out that for general nonlinear equations there is a trick which uses automatic differentiation in the construction of the analytical adjoint to improve its performance. As demonstrated in this publication, this can lead to about 2-3 orders of magnitude performance improvements. These AD-enhanced adjoints are showcased as the seeding methods in this plot:","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"(Image: )","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"Unless one directly defines special “vjp” functions, this is how the Julia SciML methods achieve orders of magnitude performance advantages over CVODES's adjoints and PETSC's TS-adjoint.","category":"page"},{"location":"comparisons/cppfortran/","page":"Getting Started with Julia's SciML for the C++/Fortran User","title":"Getting Started with Julia's SciML for the C++/Fortran User","text":"Moral of the story, even there are many reasons to use automatic differentiation of a solver, and even if an analytical adjoint rule is used for some specific performance reason, that analytical expression can often times be accelerated by orders of magnitude itself by embedding some form of automatic differentiation into it. This is just one algorithm of many which are optimized in this fashion.","category":"page"},{"location":"getting_started/first_optimization/#first_opt","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Numerical optimization is the process of finding some numerical values that minimize some equation.","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"How much fuel should you put into an airplane to have the minimum weight that can go to its destination?\nWhat parameters should I choose for my simulation so that it minimizes the distance of its predictions from my experimental data?","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"All of these are examples of problems solved by numerical optimization. Let's solve our first optimization problem!","category":"page"},{"location":"getting_started/first_optimization/#Required-Dependencies","page":"Solve your first optimization problem","title":"Required Dependencies","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"The following parts of the SciML Ecosystem will be used in this tutorial:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Module Description\nOptimization.jl The numerical optimization package\nOptimizationNLopt.jl The NLopt optimizers we will use\nForwardDiff.jl The automatic differentiation library for gradients","category":"page"},{"location":"getting_started/first_optimization/#Problem-Setup","page":"Solve your first optimization problem","title":"Problem Setup","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"First, what are we solving? Let's take a look at the Rosenbrock equation:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"L(up) = (p_1 - u_1)^2 + p_2 * (u_2 - u_1)^2","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"What we want to do is find the values of u_1 and u_2 such that L achieves its minimum value possible. We will do this under a few constraints: we want to find this optimum within some bounded domain, i.e. u_i in -11. This should be done with the parameter values p_1 = 10 and p_2 = 1000. What should u = u_1u_2 be to achieve this goal? Let's dive in!","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"note: Note\nThe upper and lower bounds are optional for the solver! If your problem does not need to have such bounds, just leave off the parts with lb and ub!","category":"page"},{"location":"getting_started/first_optimization/#Copy-Pastable-Code","page":"Solve your first optimization problem","title":"Copy-Pastable Code","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"# Import the package\nusing Optimization, OptimizationNLopt, ForwardDiff\n\n# Define the problem to optimize\nL(u, p) = (p[1] - u[1])^2 + p[2] * (u[2] - u[1]^2)^2\nu0 = zeros(2)\np = [1.0, 100.0]\noptfun = OptimizationFunction(L, Optimization.AutoForwardDiff())\nprob = OptimizationProblem(optfun, u0, p, lb = [-1.0, -1.0], ub = [1.0, 1.0])\n\n# Solve the optimization problem\nsol = solve(prob, NLopt.LD_LBFGS())\n\n# Analyze the solution\n@show sol.u, L(sol.u, p)","category":"page"},{"location":"getting_started/first_optimization/#Step-by-Step-Solution","page":"Solve your first optimization problem","title":"Step-by-Step Solution","text":"","category":"section"},{"location":"getting_started/first_optimization/#Step-1:-Import-the-packages","page":"Solve your first optimization problem","title":"Step 1: Import the packages","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"To do this tutorial, we will need a few components:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Optimization.jl, the optimization interface.\nOptimizationNLopt.jl, the optimizers we will use.\nForwardDiff.jl, the automatic differentiation library for gradients","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Note that Optimization.jl is an interface for optimizers, and thus we always have to choose which optimizer we want to use. Here we choose to demonstrate OptimizationNLopt because of its efficiency and versatility. But there are many other possible choices. Check out the solver compatibility chart for a quick overview of what optimizer packages offer.","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"To start, let's add these packages as demonstrated in the installation tutorial:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"using Pkg\nPkg.add([\"Optimization\", \"OptimizationNLopt\", \"ForwardDiff\"])","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Now we're ready. Let's load in these packages:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"using Optimization, OptimizationNLopt, ForwardDiff","category":"page"},{"location":"getting_started/first_optimization/#Step-2:-Define-the-Optimization-Problem","page":"Solve your first optimization problem","title":"Step 2: Define the Optimization Problem","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Now let's define our problem to optimize. We start by defining our loss function. In Optimization.jl's OptimizationProblem interface, the states are given by an array u. Thus we can designate u[1] to be u_1 and u[2] to be u_2, similarly with our parameters, and write out the loss function on a vector-defined state as follows:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"# Define the problem to optimize\nL(u, p) = (p[1] - u[1])^2 + p[2] * (u[2] - u[1]^2)^2","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Next we need to create an OptimizationFunction where we tell Optimization.jl to use the ForwardDiff.jl package for creating the gradient and other derivatives required by the optimizer.","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"#Create the OptimizationFunction\noptfun = OptimizationFunction(L, Optimization.AutoForwardDiff())","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Now we need to define our OptimizationProblem. If you need help remembering how to define the OptimizationProblem, you can always refer to the Optimization.jl problem definition page.","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Thus what we need to define is an initial condition u0 and our parameter vector p. We will make our initial condition have both values as zero, which is done by the Julia shorthand zeros(2) that creates a vector [0.0,0.0]. We manually define the parameter vector p to input our values. Then we set the lower bound and upper bound for the optimization as follows:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"u0 = zeros(2)\np = [1.0, 100.0]\nprob = OptimizationProblem(optfun, u0, p, lb = [-1.0, -1.0], ub = [1.0, 1.0])","category":"page"},{"location":"getting_started/first_optimization/#Note-about-defining-uniform-bounds","page":"Solve your first optimization problem","title":"Note about defining uniform bounds","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Note that we can simplify the code a bit for the lower and upper bound definition by using the Julia Base command ones, which returns a vector where each value is a one. Thus for example, ones(2) is equivalent to [1.0,1.0]. Therefore -1 * ones(2) is equivalent to [-1.0,-1.0], meaning we could have written our problem as follows:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"prob = OptimizationProblem(optfun, u0, p, lb = -1 * ones(2), ub = ones(2))","category":"page"},{"location":"getting_started/first_optimization/#Step-3:-Solve-the-Optimization-Problem","page":"Solve your first optimization problem","title":"Step 3: Solve the Optimization Problem","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Now we solve the OptimizationProblem that we have defined. This is done by passing our OptimizationProblem along with a chosen solver to the solve command. At the beginning, we explained that we will use the OptimizationNLopt set of solvers, which are documented in the OptimizationNLopt page. From here, we are choosing the NLopt.LD_LBFGS() for its mixture of robustness and performance. To perform this solve, we do the following:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"# Solve the optimization problem\nsol = solve(prob, NLopt.LD_LBFGS())","category":"page"},{"location":"getting_started/first_optimization/#Step-4:-Analyze-the-Solution","page":"Solve your first optimization problem","title":"Step 4: Analyze the Solution","text":"","category":"section"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"typeof(sol)","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"From this, we can see that it is an OptimizationSolution. We can see the documentation for how to use the OptimizationSolution by checking the Optimization.jl solution type page. For example, the solution is stored as .u. What is the solution to our optimization, and what is the final loss value? We can check it as follows:","category":"page"},{"location":"getting_started/first_optimization/","page":"Solve your first optimization problem","title":"Solve your first optimization problem","text":"# Analyze the solution\n@show sol.u, L(sol.u, p)","category":"page"},{"location":"showcase/massively_parallel_gpu/#datagpu","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/#Before-we-start:-the-two-ways-to-accelerate-ODE-solvers-with-GPUs","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Before we start: the two ways to accelerate ODE solvers with GPUs","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Before we dive deeper, let us remark that there are two very different ways that one can accelerate an ODE solution with GPUs. There is one case where u is very big and f is very expensive but very structured, and you use GPUs to accelerate the computation of said f. The other use case is where u is very small, but you want to solve the ODE f over many different initial conditions (u0) or parameters p. In that case, you can use GPUs to parallelize over different parameters and initial conditions. In other words:","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Type of Problem SciML Solution\nAccelerate a big ODE Use CUDA.jl's CuArray as u0\nSolve the same ODE with many u0 and p Use DiffEqGPU.jl's EnsembleGPUArray and EnsembleGPUKernel","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"This showcase will focus on the latter case. For the former, see the massively parallel GPU ODE solving showcase.","category":"page"},{"location":"showcase/massively_parallel_gpu/#Supported-GPUs","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Supported GPUs","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"SciML's GPU support extends to a wide array of hardware, including:","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"GPU Manufacturer GPU Kernel Language Julia Support Package Backend Type\nNVIDIA CUDA CUDA.jl CUDA.CUDABackend()\nAMD ROCm AMDGPU.jl AMDGPU.ROCBackend()\nIntel OneAPI OneAPI.jl oneAPI.oneAPIBackend()\nApple (M-Series) Metal Metal.jl Metal.MetalBackend()","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"For this tutorial we will demonstrate the CUDA backend for NVIDIA GPUs, though any of the other GPUs can be used by simply swapping out the backend choice.","category":"page"},{"location":"showcase/massively_parallel_gpu/#Problem-Setup","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Problem Setup","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Let's say we wanted to quantify the uncertainty in the solution of a differential equation. One simple way to do this would be to a Monte Carlo simulation of the same ODE, randomly jiggling around some parameters according to an uncertainty distribution. We could do that on a CPU, but that's not hip. What's hip are GPUs! GPUs have thousands of cores, so could we make each core of our GPU solve the same ODE, but with different parameters? The ensembling tools of DiffEqGPU.jl solve exactly this issue, and today you will learn how to master the GPUniverse.","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Let's dive right in.","category":"page"},{"location":"showcase/massively_parallel_gpu/#Defining-the-Ensemble-Problem-for-CPU","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Defining the Ensemble Problem for CPU","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"DifferentialEquations.jl has an ensemble interface for solving many ODEs. DiffEqGPU conveniently uses exactly the same interface, so just a change of a few characters is all that's required to change a CPU-parallelized code into a GPU-parallelized code. Given that, let's start with the CPU-parallelized code.","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Let's implement the Lorenz equation out-of-place. If you don't know what that means, see the getting started with DifferentialEquations.jl","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"using DiffEqGPU, OrdinaryDiffEq, StaticArrays, CUDA\nfunction lorenz(u, p, t)\n σ = p[1]\n ρ = p[2]\n β = p[3]\n du1 = σ * (u[2] - u[1])\n du2 = u[1] * (ρ - u[3]) - u[2]\n du3 = u[1] * u[2] - β * u[3]\n return SVector{3}(du1, du2, du3)\nend\n\nu0 = @SVector [1.0f0; 0.0f0; 0.0f0]\ntspan = (0.0f0, 10.0f0)\np = @SVector [10.0f0, 28.0f0, 8 / 3.0f0]\nprob = ODEProblem{false}(lorenz, u0, tspan, p)","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Notice we use SVectors, i.e. StaticArrays, in order to define our arrays. This is important for later, since the GPUs will want a fully non-allocating code to build a kernel on.","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Now, from this problem, we build an EnsembleProblem as per the DifferentialEquations.jl specification. A prob_func jiggles the parameters and we solve 10_000 trajectories:","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"prob_func = (prob, i, repeat) -> remake(prob, p = (@SVector rand(Float32, 3)) .* p)\nmonteprob = EnsembleProblem(prob, prob_func = prob_func, safetycopy = false)\nsol = solve(monteprob, Tsit5(), EnsembleThreads(), trajectories = 10_000, saveat = 1.0f0)","category":"page"},{"location":"showcase/massively_parallel_gpu/#Taking-the-Ensemble-to-the-GPU","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Taking the Ensemble to the GPU","text":"","category":"section"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Now uhh, we just change EnsembleThreads() to EnsembleGPUArray()","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"sol = solve(monteprob, Tsit5(), EnsembleGPUArray(CUDA.CUDABackend()), trajectories = 10_000, saveat = 1.0f0)","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Or for a more efficient version, EnsembleGPUKernel(). But that requires special solvers, so we also change to GPUTsit5().","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"sol = solve(monteprob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()), trajectories = 10_000)","category":"page"},{"location":"showcase/massively_parallel_gpu/","page":"Massively Data-Parallel ODE Solving on GPUs","title":"Massively Data-Parallel ODE Solving on GPUs","text":"Okay, so that was anticlimactic, but that's the point: if it were harder than that, it wouldn't be automatic! Now go check out DiffEqGPU.jl's documentation for more details, that's the end of our show.","category":"page"},{"location":"showcase/ode_types/#ode_types","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"One of the nice things about DifferentialEquations.jl is that it is designed with Julia's type system in mind. What this means is, if you have properly defined a Number type, you can use this number type in DifferentialEquations.jl's algorithms! There's more than a few useful/interesting types that can be used:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Julia Type Name Julia Package Use case\nBigFloat Base Julia Higher precision solutions\nArbFloat ArbFloats.jl More efficient higher precision solutions\nMeasurement Measurements.jl Uncertainty propagation\nParticles MonteCarloMeasurements.jl Uncertainty propagation\nUnitful Unitful.jl Unit-checked arithmetic\nQuaternion Quaternions.jl Quaternions, duh.\nFun ApproxFun.jl Representing PDEs as ODEs in function spaces\nAbstractOrthoPoly PolyChaos.jl Polynomial Chaos Expansion (PCE) for uncertainty quantification\nNum Symbolics.jl Build symbolic expressions of ODE solution approximations\nTaylor TaylorSeries.jl Build a Taylor series around a solution point\nDual ForwardDiff.jl Perform forward-mode automatic differentiation\nTrackedArray\\TrackedReal ReverseDiff.jl Perform reverse-mode automatic differentiation","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"and on and on. That's only a subset of types people have effectively used on the SciML tools.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"We will look into the BigFloat, Measurement, and Unitful cases to demonstrate the utility of alternative numerical types.","category":"page"},{"location":"showcase/ode_types/#How-Type-Support-Works-in-DifferentialEquations.jl-/-SciML","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"How Type Support Works in DifferentialEquations.jl / SciML","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"DifferentialEquations.jl determines the numbers to use in its solvers via the types that are designated by tspan and the initial condition u0 of the problem. It will keep the time values in the same type as tspan, and the solution values in the same type as the initial condition.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"note: Note\nSupport for this feature is restricted to the native algorithms of OrdinaryDiffEq.jl. The other solvers such as Sundials.jl, and ODEInterface.jl are incompatible with some number systems.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"warn: Warn\nAdaptive timestepping requires that the time type is compatible with sqrt and ^ functions. Thus for example, tspan cannot be Int if adaptive timestepping is chosen.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Let's use this feature in some cool ways!","category":"page"},{"location":"showcase/ode_types/#Arbitrary-Precision:-Rationals-and-BigFloats","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Arbitrary Precision: Rationals and BigFloats","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Let's solve the linear ODE. First, define an easy way to get ODEProblems for the linear ODE:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using DifferentialEquations\nf(u, p, t) = p * u\nprob_ode_linear = ODEProblem(f, 1 / 2, (0.0, 1.0), 1.01);","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Next, let's solve it using Float64s. To do so, we just need to set u0 to a Float64 (which is done by the default) and dt should be a float as well.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"sol = solve(prob_ode_linear, Tsit5())","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Notice that both the times and the solutions were saved as Float64. Let's change the state to use BigFloat values. We do this by changing the u0 to use BigFloats like:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"prob_ode_linear_bigu = ODEProblem(f, big(1 / 2), (0.0, 1.0), 1.01);\nsol = solve(prob_ode_linear_bigu, Tsit5())","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Now we see that u is in arbitrary precision BigFloats, while t is in Float64. We can then change t to be arbitrary precision BigFloats by changing the types of the tspan like:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"prob_ode_linear_big = ODEProblem(f, big(1 / 2), (big(0.0), big(1.0)), 1.01);\nsol = solve(prob_ode_linear_big, Tsit5())","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Now let's send it into the bizarre territory. Let's use rational values for everything. Let's start by making the time type Rational. Rationals are incompatible with adaptive time stepping since they do not have an L2 norm (this can be worked around by defining internalnorm, but we will skip that in this tutorial). To account for this, let's turn off adaptivity as well. Thus the following is a valid use of rational time (and parameter):","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"prob = ODEProblem(f, 1 / 2, (0 // 1, 1 // 1), 101 // 100);\nsol = solve(prob, RK4(), dt = 1 // 2^(6), adaptive = false)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Now let's change the state to use Rational{BigInt}. You will see that we will need to use the arbitrary-sized integers because... well... there's a reason people use floating-point numbers with ODE solvers:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"prob = ODEProblem(f, BigInt(1) // BigInt(2), (0 // 1, 1 // 1), 101 // 100);\nsol = solve(prob, RK4(), dt = 1 // 2^(6), adaptive = false)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Yeah...","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"sol[end]","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"That's one huge fraction! 0 floating-point error ODE solve achieved.","category":"page"},{"location":"showcase/ode_types/#Unit-Checked-Arithmetic-via-Unitful.jl","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Unit Checked Arithmetic via Unitful.jl","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Units and dimensional analysis are standard tools across the sciences for checking the correctness of your equation. However, most ODE solvers only allow for the equation to be in dimensionless form, leaving it up to the user to both convert the equation to a dimensionless form, punch in the equations, and hopefully not make an error along the way.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"DifferentialEquations.jl allows for one to use Unitful.jl to have unit-checked arithmetic natively in the solvers. Given the dispatch implementation of the Unitful, this has little overhead because the unit checks occur at compile-time and not at runtime, and thus it does not have a runtime effect unless conversions are required (i.e. converting cm to m), which automatically adds a floating-point operation for the multiplication.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Let's see this in action.","category":"page"},{"location":"showcase/ode_types/#Using-Unitful","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Using Unitful","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"To use Unitful, you need to have the package installed. Then you can add units to your variables. For example:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using Unitful\nt = 1.0u\"s\"","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Notice that t is a variable with units in seconds. If we make another value with seconds, they can add:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"t2 = 1.02u\"s\"\nt + t2","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"and they can multiply:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"t * t2","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"You can even do rational roots:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"sqrt(t)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Many operations work. These operations will check to make sure units are correct, and will throw an error for incorrect operations:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"t + sqrt(t)","category":"page"},{"location":"showcase/ode_types/#Using-Unitful-with-DifferentialEquations.jl","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Using Unitful with DifferentialEquations.jl","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Just like with other number systems, you can choose the units for your numbers by simply specifying the units of the initial condition and the timespan. For example, to solve the linear ODE where the variable has units of Newton's and t is in seconds, we would use:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using DifferentialEquations\nf(u, p, t) = 0.5 * u\nu0 = 1.5u\"N\"\nprob = ODEProblem(f, u0, (0.0u\"s\", 1.0u\"s\"))\n#sol = solve(prob,Tsit5())","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Notice that we received a unit mismatch error. This is correctly so! Remember that for an ODE:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"fracdydt = f(ty)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"we must have that f is a rate, i.e. f is a change in y per unit time. So, we need to fix the units of f in our example to be N/s. Notice that we then do not receive an error if we do the following:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"f(y, p, t) = 0.5 * y / 3.0u\"s\"\nprob = ODEProblem(f, u0, (0.0u\"s\", 1.0u\"s\"))\nsol = solve(prob, Tsit5())","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"This gives a normal solution object. Notice that the values are all with the correct units:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"print(sol[:])","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"And when we plot the solution, it automatically adds the units:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using Plots\ngr()\nplot(sol, lw = 3)","category":"page"},{"location":"showcase/ode_types/#Measurements.jl:-Numbers-with-Linear-Uncertainty-Propagation","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Measurements.jl: Numbers with Linear Uncertainty Propagation","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The result of a measurement should be given as a number with an attached uncertainty, besides the physical unit, and all operations performed involving the result of the measurement should propagate the uncertainty, taking care of correlation between quantities.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"There is a Julia package for dealing with numbers with uncertainties: Measurements.jl. Thanks to Julia's features, DifferentialEquations.jl easily works together with Measurements.jl out-of-the-box.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Let's try to automate uncertainty propagation through number types on some classical physics examples!","category":"page"},{"location":"showcase/ode_types/#Warning-about-Measurement-type","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Warning about Measurement type","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Before going on with the tutorial, we must point up a subtlety of Measurements.jl that you should be aware of:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using Measurements\n5.23 ± 0.14 === 5.23 ± 0.14","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"(5.23 ± 0.14) - (5.23 ± 0.14)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"(5.23 ± 0.14) / (5.23 ± 0.14)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The two numbers above, even though have the same nominal value and the same uncertainties, are actually two different measurements that only by chance share the same figures and their difference and their ratio have a non-zero uncertainty. It is common in physics to get very similar, or even equal, results for a repeated measurement, but the two measurements are not the same thing.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Instead, if you have one measurement and want to perform some operations involving it, you have to assign it to a variable:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"x = 5.23 ± 0.14\nx === x","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"x - x","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"x / x","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"With that in mind, let's start using Measurements.jl for realsies.","category":"page"},{"location":"showcase/ode_types/#Automated-UQ-on-an-ODE:-Radioactive-Decay-of-Carbon-14","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automated UQ on an ODE: Radioactive Decay of Carbon-14","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The rate of decay of carbon-14 is governed by a first order linear ordinary differential equation:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"fracmathrmdu(t)mathrmdt = -fracu(t)tau","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"where tau is the mean lifetime of carbon-14, which is related to the half-life t_12 = (5730 pm 40) years by the relation tau = t_12ln(2). Writing this in DifferentialEquations.jl syntax, this looks like:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"# Half-life and mean lifetime of radiocarbon, in years\nt_12 = 5730 ± 40\nτ = t_12 / log(2)\n\n#Setup\nu₀ = 1 ± 0\ntspan = (0.0, 10000.0)\n\n#Define the problem\nradioactivedecay(u, p, t) = -u / τ\n\n#Pass to solver\nprob = ODEProblem(radioactivedecay, u₀, tspan)\nsol = solve(prob, Tsit5(), reltol = 1e-8)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"And bingo: numbers with uncertainty went in, so numbers with uncertainty came out. But can we trust those values for the uncertainty?","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"We can check the uncertainty quantification by evaluating an analytical solution to the ODE. Since it's a linear ODE, the analytical solution is simply given by the exponential:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"u = exp.(-sol.t / τ)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"How do the two solutions compare?","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"plot(sol.t, sol.u, label = \"Numerical\", xlabel = \"Years\", ylabel = \"Fraction of Carbon-14\")\nplot!(sol.t, u, label = \"Analytic\")","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The two curves are perfectly superimposed, indicating that the numerical solution matches the analytic one. We can check that also the uncertainties are correctly propagated in the numerical solution:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"println(\"Quantity of carbon-14 after \", sol.t[11], \" years:\")\nprintln(\"Numerical: \", sol[11])\nprintln(\"Analytic: \", u[11])","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Bullseye. Both the value of the numerical solution and its uncertainty match the analytic solution within the requested tolerance. We can also note that close to 5730 years after the beginning of the decay (half-life of the radioisotope), the fraction of carbon-14 that survived is about 0.5.","category":"page"},{"location":"showcase/ode_types/#Simple-pendulum:-Small-angles-approximation","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Simple pendulum: Small angles approximation","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The next problem we are going to study is the simple pendulum in the approximation of small angles. We address this simplified case because there exists an easy analytic solution to compare.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"The differential equation we want to solve is:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"ddottheta + fracgL theta = 0","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"where g = (979 pm 002)mathrmmmathrms^2 is the gravitational acceleration measured where the experiment is carried out, and L = (100 pm 001)mathrmm is the length of the pendulum.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"When you set up the problem for DifferentialEquations.jl remember to define the measurements as variables, as seen above.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"using DifferentialEquations, Measurements, Plots\n\ng = 9.79 ± 0.02; # Gravitational constants\nL = 1.00 ± 0.01; # Length of the pendulum\n\n#Initial Conditions\nu₀ = [0 ± 0, π / 60 ± 0.01] # Initial speed and initial angle\ntspan = (0.0, 6.3)\n\n#Define the problem\nfunction simplependulum(du, u, p, t)\n θ = u[1]\n dθ = u[2]\n du[1] = dθ\n du[2] = -(g / L) * θ\nend\n\n#Pass to solvers\nprob = ODEProblem(simplependulum, u₀, tspan)\nsol = solve(prob, Tsit5(), reltol = 1e-6)","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"And that's it! What about comparing it this time to the analytical solution?","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"u = u₀[2] .* cos.(sqrt(g / L) .* sol.t)\n\nplot(sol.t, getindex.(sol.u, 2), label = \"Numerical\")\nplot!(sol.t, u, label = \"Analytic\")","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Bingo. Also in this case there is a perfect superimposition between the two curves, including their uncertainties.","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"We can also have a look at the difference between the two solutions:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"plot(sol.t, getindex.(sol.u, 2) .- u, label = \"\")","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Tiny difference on the order of the chosen 1e-6 tolerance.","category":"page"},{"location":"showcase/ode_types/#Simple-pendulum:-Arbitrary-amplitude","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Simple pendulum: Arbitrary amplitude","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Now that we know how to solve differential equations involving numbers with uncertainties, we can solve the simple pendulum problem without any approximation. This time, the differential equation to solve is the following:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"ddottheta + fracgL sin(theta) = 0","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"That would be done via:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"g = 9.79 ± 0.02; # Gravitational constants\nL = 1.00 ± 0.01; # Length of the pendulum\n\n#Initial Conditions\nu₀ = [0 ± 0, π / 3 ± 0.02] # Initial speed and initial angle\ntspan = (0.0, 6.3)\n\n#Define the problem\nfunction simplependulum(du, u, p, t)\n θ = u[1]\n dθ = u[2]\n du[1] = dθ\n du[2] = -(g / L) * sin(θ)\nend\n\n#Pass to solvers\nprob = ODEProblem(simplependulum, u₀, tspan)\nsol = solve(prob, Tsit5(), reltol = 1e-6)\n\nplot(sol.t, getindex.(sol.u, 2), label = \"Numerical\")","category":"page"},{"location":"showcase/ode_types/#Warning-about-Linear-Uncertainty-Propagation","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Warning about Linear Uncertainty Propagation","text":"","category":"section"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Measurements.jl uses linear uncertainty propagation, which has an error associated with it. MonteCarloMeasurements.jl has a page which showcases where this method can lead to incorrect uncertainty measurements. Thus for more nonlinear use cases, it's suggested that one uses one of the more powerful UQ methods, such as:","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"MonteCarloMeasurements.jl\nPolyChaos.jl\nSciMLExpectations.jl\nThe ProbInts Uncertainty Quantification callbacks","category":"page"},{"location":"showcase/ode_types/","page":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","title":"Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System","text":"Basically, types can make the algorithm you want to run exceedingly simple to do, but make sure it's the correct algorithm!","category":"page"},{"location":"showcase/pinngpu/#pinngpu","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Machine learning is all the rage. Everybody thinks physics is cool.","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Therefore, using machine learning to solve physics equations? 🧠💥","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"So let's be cool and use a physics-informed neural network (PINN) to solve the Heat Equation. Let's be even cooler by using GPUs (ironically, creating even more heat, but it's the heat equation so that's cool).","category":"page"},{"location":"showcase/pinngpu/#Step-1:-Import-Libraries","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 1: Import Libraries","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"To solve PDEs using neural networks, we will use the NeuralPDE.jl package. This package uses ModelingToolkit's symbolic PDESystem as an input, and it generates an Optimization.jl OptimizationProblem which, when solved, gives the weights of the neural network that solve the PDE. In the end, our neural network NN satisfies the PDE equations and is thus the solution to the PDE! Thus our packages look like:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"# High Level Interface\nusing NeuralPDE\nimport ModelingToolkit: Interval\n\n# Optimization Libraries\nusing Optimization, OptimizationOptimisers\n\n# Machine Learning Libraries and Helpers\nusing Lux, LuxCUDA, ComponentArrays\nconst gpud = gpu_device() # allocate a GPU device\n\n# Standard Libraries\nusing Printf, Random\n\n# Plotting\nusing Plots","category":"page"},{"location":"showcase/pinngpu/#Problem-Setup","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Problem Setup","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Let's solve the 2+1-dimensional Heat Equation. This is the PDE:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"_t u(x y t) = ^2_x u(x y t) + ^2_y u(x y t) ","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"with the initial and boundary conditions:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"beginalign*\nu(x y 0) = e^x+y cos(x + y) \nu(0 y t) = e^y cos(y + 4t) \nu(2 y t) = e^2+y cos(2 + y + 4t) \nu(x 0 t) = e^x cos(x + 4t) \nu(x 2 t) = e^x+2 cos(x + 2 + 4t) \nendalign*","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"on the space and time domain:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"x in 0 2 y in 0 2 t in 0 2 ","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"with physics-informed neural networks.","category":"page"},{"location":"showcase/pinngpu/#Step-2:-Define-the-PDESystem","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 2: Define the PDESystem","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"First, let's use ModelingToolkit's PDESystem to represent the PDE. To do this, basically just copy-paste the PDE definition into Julia code. This looks like:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"@parameters t x y\n@variables u(..)\nDxx = Differential(x)^2\nDyy = Differential(y)^2\nDt = Differential(t)\nt_min = 0.0\nt_max = 2.0\nx_min = 0.0\nx_max = 2.0\ny_min = 0.0\ny_max = 2.0\n\n# 2D PDE\neq = Dt(u(t, x, y)) ~ Dxx(u(t, x, y)) + Dyy(u(t, x, y))\n\nanalytic_sol_func(t, x, y) = exp(x + y) * cos(x + y + 4t)\n# Initial and boundary conditions\nbcs = [u(t_min, x, y) ~ analytic_sol_func(t_min, x, y),\n u(t, x_min, y) ~ analytic_sol_func(t, x_min, y),\n u(t, x_max, y) ~ analytic_sol_func(t, x_max, y),\n u(t, x, y_min) ~ analytic_sol_func(t, x, y_min),\n u(t, x, y_max) ~ analytic_sol_func(t, x, y_max)]\n\n# Space and time domains\ndomains = [t ∈ Interval(t_min, t_max),\n x ∈ Interval(x_min, x_max),\n y ∈ Interval(y_min, y_max)]\n\n@named pde_system = PDESystem(eq, bcs, domains, [t, x, y], [u(t, x, y)])","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"note: Note\nWe used the wildcard form of the variable definition @variables u(..) which then requires that we always specify what the dependent variables of u are. This is because in the boundary conditions we change from using u(t,x,y) to more specific points and lines, like u(t,x_max,y).","category":"page"},{"location":"showcase/pinngpu/#Step-3:-Define-the-Lux-Neural-Network","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 3: Define the Lux Neural Network","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Now let's define the neural network that will act as our solution. We will use a simple multi-layer perceptron, like:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"using Lux\ninner = 25\nchain = Chain(Dense(3, inner, Lux.σ),\n Dense(inner, inner, Lux.σ),\n Dense(inner, inner, Lux.σ),\n Dense(inner, inner, Lux.σ),\n Dense(inner, 1))\nps = Lux.setup(Random.default_rng(), chain)[1]","category":"page"},{"location":"showcase/pinngpu/#Step-4:-Place-it-on-the-GPU.","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 4: Place it on the GPU.","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Just plop it on that sucker. We must ensure that our initial parameters for the neural network are on the GPU. If that is done, then the internal computations will all take place on the GPU. This is done by using the gpud function (i.e. the GPU device we created at the start) on the initial parameters, like:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"ps = ps |> ComponentArray |> gpud .|> Float64","category":"page"},{"location":"showcase/pinngpu/#Step-5:-Discretize-the-PDE-via-a-PINN-Training-Strategy","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 5: Discretize the PDE via a PINN Training Strategy","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"strategy = GridTraining(0.05)\ndiscretization = PhysicsInformedNN(chain,\n strategy,\n init_params = ps)\nprob = discretize(pde_system, discretization)","category":"page"},{"location":"showcase/pinngpu/#Step-6:-Solve-the-Optimization-Problem","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 6: Solve the Optimization Problem","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"callback = function (p, l)\n println(\"Current loss is: $l\")\n return false\nend\n\nres = Optimization.solve(prob, Adam(0.01); callback = callback, maxiters = 2500);","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"We then use the remake function to rebuild the PDE problem to start a new optimization at the optimized parameters, and continue with a lower learning rate:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"prob = remake(prob, u0 = res.u)\nres = Optimization.solve(prob, Adam(0.001); callback = callback, maxiters = 2500);","category":"page"},{"location":"showcase/pinngpu/#Step-7:-Inspect-the-PINN's-Solution","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"Step 7: Inspect the PINN's Solution","text":"","category":"section"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"Finally, we inspect the solution:","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"phi = discretization.phi\nts, xs, ys = [infimum(d.domain):0.1:supremum(d.domain) for d in domains]\nu_real = [analytic_sol_func(t, x, y) for t in ts for x in xs for y in ys]\nu_predict = [first(Array(phi([t, x, y], res.u))) for t in ts for x in xs for y in ys]\n\nfunction plot_(res)\n # Animate\n anim = @animate for (i, t) in enumerate(0:0.05:t_max)\n @info \"Animating frame $i...\"\n u_real = reshape([analytic_sol_func(t, x, y) for x in xs for y in ys],\n (length(xs), length(ys)))\n u_predict = reshape([Array(phi([t, x, y], res.u))[1] for x in xs for y in ys],\n length(xs), length(ys))\n u_error = abs.(u_predict .- u_real)\n title = @sprintf(\"predict, t = %.3f\", t)\n p1 = plot(xs, ys, u_predict, st = :surface, label = \"\", title = title)\n title = @sprintf(\"real\")\n p2 = plot(xs, ys, u_real, st = :surface, label = \"\", title = title)\n title = @sprintf(\"error\")\n p3 = plot(xs, ys, u_error, st = :contourf, label = \"\", title = title)\n plot(p1, p2, p3)\n end\n gif(anim, \"3pde.gif\", fps = 10)\nend\n\nplot_(res)","category":"page"},{"location":"showcase/pinngpu/","page":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","title":"GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers","text":"(Image: 3pde)","category":"page"},{"location":"showcase/brusselator/#brusselator","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Solving nonlinear partial differential equations (PDEs) is hard. Solving nonlinear PDEs fast and accurately is even harder. Doing it all in an automated method from just a symbolic description is just plain fun. That's what we'd demonstrate here: how to solve a nonlinear PDE from a purely symbolic definition using the combination of ModelingToolkit, MethodOfLines, and DifferentialEquations.jl.","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"note: Note\nThis example is a combination of the Brusselator tutorial from MethodOfLines.jl and the Solving Large Stiff Equations tutorial from DifferentialEquations.jl.","category":"page"},{"location":"showcase/brusselator/#Required-Dependencies","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Required Dependencies","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"The following parts of the SciML Ecosystem will be used in this tutorial:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Module Description\nModelingToolkit.jl The symbolic modeling environment\nMethodOfLines.jl The symbolic PDE discretization tooling\nDifferentialEquations.jl The numerical differential equation solvers\nLinearSolve.jl The numerical linear solvers","category":"page"},{"location":"showcase/brusselator/#Problem-Setup","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Problem Setup","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"The Brusselator PDE is defined as follows:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"beginalign\nfracpartial upartial t = 1 + u^2v - 44u + alpha(fracpartial^2 upartial x^2 + fracpartial^2 upartial y^2) + f(x y t)\nfracpartial vpartial t = 34u - u^2v + alpha(fracpartial^2 vpartial x^2 + fracpartial^2 vpartial y^2)\nendalign","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"where","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"f(x y t) = begincases\n5 quad textif (x-03)^2+(y-06)^2 01^2 text and t 11 \n0 quad textelse\nendcases","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"and the initial conditions are","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"beginalign\nu(x y 0) = 22cdot (y(1-y))^32 \nv(x y 0) = 27cdot (x(1-x))^32\nendalign","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"with the periodic boundary condition","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"beginalign\nu(x+1yt) = u(xyt) \nu(xy+1t) = u(xyt)\nendalign","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"We wish to obtain the solution to this PDE on a timespan of t in 0115.","category":"page"},{"location":"showcase/brusselator/#Defining-the-symbolic-PDEsystem-with-ModelingToolkit.jl","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Defining the symbolic PDEsystem with ModelingToolkit.jl","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"With ModelingToolkit.jl, we first symbolically define the system, see also the docs for PDESystem:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"using ModelingToolkit, MethodOfLines, OrdinaryDiffEq, LinearSolve, DomainSets\n\n@parameters x y t\n@variables u(..) v(..)\nDt = Differential(t)\nDx = Differential(x)\nDy = Differential(y)\nDxx = Differential(x)^2\nDyy = Differential(y)^2\n\n∇²(u) = Dxx(u) + Dyy(u)\n\nbrusselator_f(x, y, t) = (((x - 0.3)^2 + (y - 0.6)^2) <= 0.1^2) * (t >= 1.1) * 5.0\n\nx_min = y_min = t_min = 0.0\nx_max = y_max = 1.0\nt_max = 11.5\n\nα = 10.0\n\nu0(x, y, t) = 22(y * (1 - y))^(3 / 2)\nv0(x, y, t) = 27(x * (1 - x))^(3 / 2)\n\neq = [\n Dt(u(x, y, t)) ~ 1.0 + v(x, y, t) * u(x, y, t)^2 - 4.4 * u(x, y, t) +\n α * ∇²(u(x, y, t)) + brusselator_f(x, y, t),\n Dt(v(x, y, t)) ~ 3.4 * u(x, y, t) - v(x, y, t) * u(x, y, t)^2 + α * ∇²(v(x, y, t))]\n\ndomains = [x ∈ Interval(x_min, x_max),\n y ∈ Interval(y_min, y_max),\n t ∈ Interval(t_min, t_max)]\n\n# Periodic BCs\nbcs = [u(x, y, 0) ~ u0(x, y, 0),\n u(0, y, t) ~ u(1, y, t),\n u(x, 0, t) ~ u(x, 1, t), v(x, y, 0) ~ v0(x, y, 0),\n v(0, y, t) ~ v(1, y, t),\n v(x, 0, t) ~ v(x, 1, t)]\n\n@named pdesys = PDESystem(eq, bcs, domains, [x, y, t], [u(x, y, t), v(x, y, t)])","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Looks just like the LaTeX description, right? Now let's solve it.","category":"page"},{"location":"showcase/brusselator/#Automated-symbolic-discretization-with-MethodOfLines.jl","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated symbolic discretization with MethodOfLines.jl","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Next we create the discretization. Here we will use the finite difference method via method of lines. Method of lines is a method of recognizing that a discretization of a partial differential equation transforms it into a new numerical problem. For example:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Discretization Form Numerical Problem Type\nFinite Difference, Finite Volume, Finite Element, discretizing all variables NonlinearProblem\nFinite Difference, Finite Volume, Finite Element, discretizing all variables except time ODEProblem/DAEProblem\nPhysics-Informed Neural Network OptimizationProblem\nFeynman-Kac Formula SDEProblem\nUniversal Stochastic Differential Equation (High dimensional PDEs) OptimizationProblem inverse problem over SDEProblem","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Thus the process of solving a PDE is fundamentally about transforming its symbolic form to a standard numerical problem and solving the standard numerical problem using one of the solvers in the SciML ecosystem! Here we will demonstrate one of the most classic methods: the finite difference method. Since the Brusselator is a time-dependent PDE with heavy stiffness in the time-domain, we will leave time undiscretized, which means that we will use the finite difference method in the x and y domains to obtain a representation of the equation at `u_i = u(x_i,y_i)grid point values, obtaining an ODEu_i' = \\ldots that defines how the values at the grid points evolve over time.","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"To do this, we use the MOLFiniteDifference construct of MethodOfLines.jl as follows:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"N = 32\n\ndx = (x_max - x_min) / N\ndy = (y_max - y_min) / N\n\norder = 2\n\ndiscretization = MOLFiniteDifference([x => dx, y => dy], t, approx_order = order,\n grid_align = center_align)","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Next, we discretize the system, converting the PDESystem in to an ODEProblem:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"prob = discretize(pdesys, discretization);","category":"page"},{"location":"showcase/brusselator/#Solving-the-PDE","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Solving the PDE","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Now your problem can be solved with an appropriate ODE solver. This is just your standard DifferentialEquations.jl usage, though we'll return to this point in a bit to talk about efficiency:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"sol = solve(prob, TRBDF2(), saveat = 0.1);","category":"page"},{"location":"showcase/brusselator/#Examining-Results-via-the-Symbolic-Solution-Interface","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Examining Results via the Symbolic Solution Interface","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Now that we have solved the ODE representation of the PDE, we have an PDETimeSeriesSolution that wraps an ODESolution, which we can get with sol.original_sol. If we look at the original sol, it represents u_i = ldots at each of the grid points. If you check sol.original_sol.u inside the solution, that's those values... but that's not very helpful. How do you interpret original_sol[1]? How do you interpret original_sol[1,:]?","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"To make the handling of such cases a lot simpler, MethodOfLines.jl implements a symbolic interface for the solution object that allows for interpreting the computation through its original representation. For example, if we want to know how to interpret the values of the grid corresponding to the independent variables, we can just index using symbolic variables:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"discrete_x = sol[x];\ndiscrete_y = sol[y];\ndiscrete_t = sol[t];","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"What this tells us is that, for a solution at a given time point, say original_sol[1] for the solution at the initial time (the initial condition), the value original_sol[1][1] is the solution at the grid point (discrete_x[1], discrete_y[1]). For values that are not the initial time point, original_sol[i] corresponds to the solution at discrete_t[i].","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"But we also have two dependent variables, u and v. How do we interpret which of the results correspond to the different dependent variables? This is done by indexing the solution by the dependent variables! For example:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"solu = sol[u(x, y, t)];\nsolv = sol[v(x, y, t)];","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"This then gives an array of results for the u and v separately, each dimension corresponding to the discrete form of the independent variables.","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Using this high-level indexing, we can create an animation of the solution of the Brusselator as follows. For u we receive:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"using Plots\nanim = @animate for k in 1:length(discrete_t)\n heatmap(solu[2:end, 2:end, k], title = \"$(discrete_t[k])\") # 2:end since end = 1, periodic condition\nend\ngif(anim, \"plots/Brusselator2Dsol_u.gif\", fps = 8)","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"(Image: Brusselator2Dsol_u)","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"and for v:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"anim = @animate for k in 1:length(discrete_t)\n heatmap(solv[2:end, 2:end, k], title = \"$(discrete_t[k])\")\nend\ngif(anim, \"plots/Brusselator2Dsol_v.gif\", fps = 8)","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"(Image: Brusselator2Dsol_v)","category":"page"},{"location":"showcase/brusselator/#Improving-the-Solution-Process","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Improving the Solution Process","text":"","category":"section"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Now, if all we needed was a single solution, then we're done. Budda bing budda boom, we got a solution, we're outta here. But if for example we're solving an inverse problem on a PDE, or we need to bump it up to higher accuracy, then we will need to make sure we solve this puppy more efficiently. So let's dive into how this can be done.","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"First of all, large PDEs generally are stiff and thus require an implicit solver. However, their stiffness is generally governed by a nonlinear system which as a sparse Jacobian. Handling that implicit system with sparsity is key to solving the system efficiently, so let's do that!","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"In order to enable such options, we simply need to pass the ModelingToolkit.jl problem construction options to the discretize call. This looks like:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"# Analytical Jacobian expression and sparse Jacobian\nprob_sparse = discretize(pdesys, discretization; jac = true, sparse = true)","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"Now when we solve the problem it will be a lot faster. We can use BenchmarkTools.jl to assess this performance difference:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"using BenchmarkTools\n@btime sol = solve(prob, TRBDF2(), saveat = 0.1);\n@btime sol = solve(prob_sparse, TRBDF2(), saveat = 0.1);","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"But we can further improve this as well. Instead of just using the default linear solver, we can change this to a Newton-Krylov method by passing in the GMRES method:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"@btime sol = solve(prob_sparse, TRBDF2(linsolve = KrylovJL_GMRES()), saveat = 0.1);","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"But to further improve performance, we can use an iLU preconditioner. This looks like as follows:","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"using IncompleteLU\nfunction incompletelu(W, du, u, p, t, newW, Plprev, Prprev, solverdata)\n if newW === nothing || newW\n Pl = ilu(convert(AbstractMatrix, W), τ = 50.0)\n else\n Pl = Plprev\n end\n Pl, nothing\nend\n\n@btime solve(prob_sparse,\n TRBDF2(linsolve = KrylovJL_GMRES(), precs = incompletelu, concrete_jac = true),\n save_everystep = false);","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"And now we're zooming! For more information on these performance improvements, check out the deeper dive in the DifferentialEquations.jl tutorials.","category":"page"},{"location":"showcase/brusselator/","page":"Automated Efficient Solution of Nonlinear Partial Differential Equations","title":"Automated Efficient Solution of Nonlinear Partial Differential Equations","text":"If you're interested in figuring out what's the fastest current solver for this kind of PDE, check out the Brusselator benchmark in SciMLBenchmarks.jl","category":"page"},{"location":"comparisons/python/#python","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"","category":"section"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"If you're a Python user who has looked into Julia, you're probably wondering what is the equivalent to SciPy is. And you found it: it's the SciML ecosystem! To a Python developer, SciML is SciPy, but with the high-performance GPU, capabilities of PyTorch, and neural network capabilities, all baked right in. With SciML, there is no “separate world” of machine learning sublanguages: there is just one cohesive package ecosystem.","category":"page"},{"location":"comparisons/python/#Why-SciML?-High-Level-Workflow-Reasons","page":"Getting Started with Julia's SciML for the Python User","title":"Why SciML? High-Level Workflow Reasons","text":"","category":"section"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"Performance - The key reason people are moving from SciPy to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.\nPackage Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.\nComposable Library Components - In Python environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.\nEasier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.\nMix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.","category":"page"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"In this plot, SciPy in yellow represents Python's most commonly used solvers:","category":"page"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"(Image: )","category":"page"},{"location":"comparisons/python/#Need-Help-Translating-from-Python-to-Julia?","page":"Getting Started with Julia's SciML for the Python User","title":"Need Help Translating from Python to Julia?","text":"","category":"section"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"The following resources can be particularly helpful when adopting Julia for SciML for the first time:","category":"page"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"The Julia Manual's Noteworthy Differences from Python page\nDouble-check your results with SciPyDiffEq.jl (automatically converts and runs ODE definitions with SciPy's solvers)\nUse PyCall.jl to more incrementally move code to Julia.","category":"page"},{"location":"comparisons/python/#Python-to-Julia-SciML-Functionality-Translations","page":"Getting Started with Julia's SciML for the Python User","title":"Python to Julia SciML Functionality Translations","text":"","category":"section"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"The following chart will help you get quickly acquainted with Julia's SciML Tools:","category":"page"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"Workflow Element SciML-Supported Julia packages\nMatplotlib Plots, Makie\nscipy.special SpecialFunctions\nscipy.linalg.solve LinearSolve\nscipy.integrate Integrals\nscipy.optimize Optimization\nscipy.optimize.fsolve NonlinearSolve\nscipy.interpolate DataInterpolations\nscipy.fft FFTW\nscipy.linalg Julia's Built-In Linear Algebra\nscipy.sparse SparseArrays, ARPACK\nodeint/solve_ivp DifferentialEquations\nscipy.integrate.solve_bvp Boundary-value problem\nPyTorch Flux, Lux\ngillespy2 Catalyst, JumpProcesses\nscipy.optimize.approx_fprime FiniteDiff\nautograd ForwardDiff*, Enzyme*, DiffEqSensitivity\nStan Turing\nsympy Symbolics","category":"page"},{"location":"comparisons/python/#Why-is-Differentiable-Programming-Important-for-Scientific-Computing?","page":"Getting Started with Julia's SciML for the Python User","title":"Why is Differentiable Programming Important for Scientific Computing?","text":"","category":"section"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"Check out this blog post that goes into detail on how training neural networks in tandem with simulation improves performance by orders of magnitude. But can't you use analytical adjoint definitions? You can, but there are tricks to mix automatic differentiation into the adjoint definitions for a few orders of magnitude improvement too, as explained in this blog post.","category":"page"},{"location":"comparisons/python/","page":"Getting Started with Julia's SciML for the Python User","title":"Getting Started with Julia's SciML for the Python User","text":"These facts, along with many others, compose to algorithmic improvements with the implementation improvements, which leads to orders of magnitude improvements!","category":"page"},{"location":"getting_started/first_simulation/#first_sim","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"In this tutorial, we will build and run our first simulation with SciML!","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"note: Note\nThis tutorial assumes that you have already installed Julia on your system. If you have not done so already, please follow the installation tutorial first.","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"To build our simulation, we will use the ModelingToolkit system for modeling and simulation. ModelingToolkit is a bit higher level than directly defining code for a differential equation system: it's a symbolic system that will automatically simplify our models, optimize our code, and generate compelling visualizations. Sounds neat? Let's dig in.","category":"page"},{"location":"getting_started/first_simulation/#Required-Dependencies","page":"Build and run your first simulation with Julia's SciML","title":"Required Dependencies","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"The following parts of the SciML Ecosystem will be used in this tutorial:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Module Description\nModelingToolkit.jl The symbolic modeling environment\nDifferentialEquations.jl The differential equation solvers\nPlots.jl The plotting and visualization package","category":"page"},{"location":"getting_started/first_simulation/#Our-Problem:-Simulate-the-Lotka-Volterra-Predator-Prey-Dynamics","page":"Build and run your first simulation with Julia's SciML","title":"Our Problem: Simulate the Lotka-Volterra Predator-Prey Dynamics","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"The dynamics of our system are given by the Lotka-Volterra dynamical system: Let x(t) be the number of rabbits in the environment and y(t) be the number of wolves. The equation that defines the evolution of the species is given as follows:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"beginalign\nfracdxdt = alpha x - beta x y\nfracdydt = -gamma y + delta x y\nendalign","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"where alpha beta gamma delta are parameters. Starting from equal numbers of rabbits and wolves, x(0) = 1 and y(0) = 1, we want to simulate this system from time t_0 = 0 to t_f = 10. Luckily, a local guide provided us with some parameters that seem to match the system! These are alpha = 15, beta = 10, gamma = 30, delta = 10. How many rabbits and wolves will there be 10 months from now? And if z = x + y, i.e. the total number of animals at a given time, can we visualize this total number of animals at each time?","category":"page"},{"location":"getting_started/first_simulation/#Solution-as-Copy-Pastable-Code","page":"Build and run your first simulation with Julia's SciML","title":"Solution as Copy-Pastable Code","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"using ModelingToolkit, DifferentialEquations, Plots\n\n# Define our state variables: state(t) = initial condition\n@variables t x(t)=1 y(t)=1 z(t)=2\n\n# Define our parameters\n@parameters α=1.5 β=1.0 γ=3.0 δ=1.0\n\n# Define our differential: takes the derivative with respect to `t`\nD = Differential(t)\n\n# Define the differential equations\neqs = [D(x) ~ α * x - β * x * y\n D(y) ~ -γ * y + δ * x * y\n z ~ x + y]\n\n# Bring these pieces together into an ODESystem with independent variable t\n@mtkbuild sys = ODESystem(eqs, t)\n\n# Convert from a symbolic to a numerical problem to simulate\ntspan = (0.0, 10.0)\nprob = ODEProblem(sys, [], tspan)\n\n# Solve the ODE\nsol = solve(prob)\n\n# Plot the solution\np1 = plot(sol, title = \"Rabbits vs Wolves\")\np2 = plot(sol, idxs = z, title = \"Total Animals\")\n\nplot(p1, p2, layout = (2, 1))","category":"page"},{"location":"getting_started/first_simulation/#Step-by-Step-Solution","page":"Build and run your first simulation with Julia's SciML","title":"Step-by-Step Solution","text":"","category":"section"},{"location":"getting_started/first_simulation/#Step-1:-Install-and-Import-the-Required-Packages","page":"Build and run your first simulation with Julia's SciML","title":"Step 1: Install and Import the Required Packages","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"To do this tutorial, we will need a few components:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"ModelingToolkit.jl, our modeling environment\nDifferentialEquations.jl, the differential equation solvers\nPlots.jl, our visualization tool","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"To start, let's add these packages as demonstrated in the installation tutorial:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"using Pkg\nPkg.add([\"ModelingToolkit\", \"DifferentialEquations\", \"Plots\"])","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now we're ready. Let's load in these packages:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"using ModelingToolkit, DifferentialEquations, Plots","category":"page"},{"location":"getting_started/first_simulation/#Step-2:-Define-our-ODE-Equations","page":"Build and run your first simulation with Julia's SciML","title":"Step 2: Define our ODE Equations","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now let's define our ODEs. We use the ModelingToolkit.@variabes statement to declare our variables. We have the independent variable time t, and then define our 3 state variables:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Define our state variables: state(t) = initial condition\n@variables t x(t)=1 y(t)=1 z(t)=2","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Notice here that we use the form state = default, where on the right-hand side the default value of a state is interpreted to be its initial condition. This is then done similarly for parameters, where the default value is now the parameter value:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Define our parameters\n@parameters α=1.5 β=1.0 γ=3.0 δ=1.0","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"note: Note\nJulia's text editors like VS Code are compatible with Unicode defined in a LaTeX form. Thus if you write \\alpha into your REPL and then press Tab, it will auto-complete that into the α symbol. That can make your code look a lot more like the mathematical expressions!","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Next, we define our set of differential equations. To define the Differential operator D, we need to first tell it what to differentiate with respect to, here the independent variable t, Then, once we have the operator, we apply that into the equations.","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"note: Note\nNote that in ModelingToolkit and Symbolics, ~ is used for equation equality. This is separate from = which is the “assignment operator” in the Julia programming language. For example, x = x + 1 is a valid assignment in a programming language, and it is invalid for that to represent “equality”, which is why a separate operator is used!","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Define our differential: takes the derivative with respect to `t`\nD = Differential(t)\n\n# Define the differential equations\neqs = [D(x) ~ α * x - β * x * y\n D(y) ~ -γ * y + δ * x * y\n z ~ x + y]","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Notice that in the display, it will automatically generate LaTeX. If one is interested in generating this LaTeX locally, one can simply do:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"using Latexify # add the package first\nlatexify(eqs)","category":"page"},{"location":"getting_started/first_simulation/#Step-3:-Define-the-ODEProblem","page":"Build and run your first simulation with Julia's SciML","title":"Step 3: Define the ODEProblem","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now we bring these pieces together. In ModelingToolkit, we can bring these pieces together to represent an ODESystem with the following:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Bring these pieces together into an ODESystem with independent variable t\n@mtkbuild sys = ODESystem(eqs, t)","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Notice that in our equations we have an algebraic equation z ~ x + y. This is not a differential equation but an algebraic equation, and thus we call this set of equations a Differential-Algebraic Equation (DAE). The symbolic system of ModelingToolkit can eliminate such equations to return simpler forms to numerically approximate.","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Notice that what is returned is an ODESystem, but now with the simplified set of equations. z has been turned into an “observable”, i.e. a state that is not computed but can be constructed on-demand. This is one of the ways that SciML reaches its speed: you can have 100,000 equations, but solve only 1,000 to then automatically reconstruct the full set. Here, it's just 3 equations to 2, but as models get more complex, the symbolic system will find ever more clever interactions!","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now that we have simplified our system, let's turn it into a numerical problem to approximate. This is done with the ODEProblem constructor, that transforms it from a symbolic ModelingToolkit representation to a numerical DifferentialEquations representation. We need to tell it the numerical details now:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Whether to override any of the default values for the initial conditions and parameters.\nWhat is the initial time point.\nHow long to integrate it for.","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"In this case, we will use the default values for all our variables, so we will pass a blank override []. If for example we did want to change the initial condition of x to 2.0 and α to 4.0, we would do [x => 2.0, α => 4.0]. Then secondly, we pass a tuple for the time span, (0.0,10.0) meaning start at 0.0 and end at 10.0. This looks like:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Convert from a symbolic to a numerical problem to simulate\ntspan = (0.0, 10.0)\nprob = ODEProblem(sys, [], tspan)","category":"page"},{"location":"getting_started/first_simulation/#Step-4:-Solve-the-ODE-System","page":"Build and run your first simulation with Julia's SciML","title":"Step 4: Solve the ODE System","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now we solve the ODE system. Julia's SciML solvers have a defaulting system that can automatically determine an appropriate solver for a given system, so we can just tell it to solve:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Solve the ODE\nsol = solve(prob)","category":"page"},{"location":"getting_started/first_simulation/#Step-5:-Visualize-the-Solution","page":"Build and run your first simulation with Julia's SciML","title":"Step 5: Visualize the Solution","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now let's visualize the solution! Notice that our solution only has two states. If we recall, the simplified system only has two states: z was symbolically eliminated. We can access any of the values, even the eliminated values, using the symbolic variable as the index. For example:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"sol[z]","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"returns the time series of the observable z at time points corresponding to sol.t. We can use this with the automated plotting functionality. First let's create a plot of x and y over time using plot(sol) which will plot all of the states. Then next, we will explicitly tell it to make a plot with the index being z, i.e. idxs=z.","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"note: Note\nNote that one can pass an array of indices as well, so idxs=[x,y,z] would make a plot with all three lines together!","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"# Plot the solution\np1 = plot(sol, title = \"Rabbits vs Wolves\")","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"p2 = plot(sol, idxs = z, title = \"Total Animals\")","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Finally, let's make a plot where we merge these two plot elements. To do so, we can take our two plot objects, p1 and p2, and make a plot with both of them. Then we tell Plots to do a layout of (2,1), or 2 rows and 1 columns. Let's see what happens when we bring these together:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"plot(p1, p2, layout = (2, 1))","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"And tada, we have a full analysis of our ecosystem!","category":"page"},{"location":"getting_started/first_simulation/#Bonus-Step:-Emoji-Variables","page":"Build and run your first simulation with Julia's SciML","title":"Bonus Step: Emoji Variables","text":"","category":"section"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"If you made it this far, then congrats, you get to learn a fun fact! Since Julia code can use Unicode, emojis work for variable names. Here's the simulation using emojis of rabbits and wolves to define the system:","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"using ModelingToolkit, DifferentialEquations\n@parameters α=1.5 β=1.0 γ=3.0 δ=1.0\n@variables t 🐰(t)=1.0 🐺(t)=1.0\nD = Differential(t)\neqs = [D(🐰) ~ α * 🐰 - β * 🐰 * 🐺,\n D(🐺) ~ -γ * 🐺 + δ * 🐰 * 🐺]\n\n@mtkbuild sys = ODESystem(eqs, t)\nprob = ODEProblem(sys, [], (0.0, 10.0))\nsol = solve(prob)","category":"page"},{"location":"getting_started/first_simulation/","page":"Build and run your first simulation with Julia's SciML","title":"Build and run your first simulation with Julia's SciML","text":"Now go make your professor mad that they have to grade a fully emojified code. I'll vouch for you: the documentation told you to do this.","category":"page"},{"location":"highlevels/numerical_utilities/#SciML-Numerical-Utility-Libraries","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"","category":"section"},{"location":"highlevels/numerical_utilities/#ExponentialUtilities.jl:-Faster-Matrix-Exponentials","page":"SciML Numerical Utility Libraries","title":"ExponentialUtilities.jl: Faster Matrix Exponentials","text":"","category":"section"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"ExponentialUtilities.jl is a library for efficient computation of matrix exponentials. While Julia has a built-in exp(A) method, ExponentialUtilities.jl offers many features around this to improve performance in scientific contexts, including:","category":"page"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"Faster methods for (non-allocating) matrix exponentials via exponential!\nMethods for computing matrix exponential that are generic to number types and arrays (i.e. GPUs)\nMethods for computing Arnoldi iterations on Krylov subspaces\nDirect computation of exp(t*A)*v, i.e. exponentiation of a matrix times a vector, without computing the matrix exponential\nDirect computation of ϕ_m(t*A)*v operations, where ϕ_0(z) = exp(z) and ϕ_(k+1)(z) = (ϕ_k(z) - 1) / z","category":"page"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"ExponentialUtilities.jl includes complex adaptive time stepping techniques such as KIOPS in order to perform these calculations in a fast and numerically-stable way.","category":"page"},{"location":"highlevels/numerical_utilities/#QuasiMonteCarlo.jl:-Fast-Quasi-Random-Number-Generation","page":"SciML Numerical Utility Libraries","title":"QuasiMonteCarlo.jl: Fast Quasi-Random Number Generation","text":"","category":"section"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"QuasiMonteCarlo.jl is a library for fast generation of low discrepancy Quasi-Monte Carlo samples, using methods like:","category":"page"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"GridSample(dx) where the grid is given by lb:dx[i]:ub in the ith direction.\nUniformSample for uniformly distributed random numbers.\nSobolSample for the Sobol sequence.\nLatinHypercubeSample for a Latin Hypercube.\nLatticeRuleSample for a randomly-shifted rank-1 lattice rule.\nLowDiscrepancySample(base) where base[i] is the base in the ith direction.\nGoldenSample for a Golden Ratio sequence.\nKroneckerSample(alpha, s0) for a Kronecker sequence, where alpha is a length-d vector of irrational numbers (often sqrt(d)) and s0 is a length-d seed vector (often 0).\nSectionSample(x0, sampler) where sampler is any sampler above and x0 is a vector of either NaN for a free dimension or some scalar for a constrained dimension.","category":"page"},{"location":"highlevels/numerical_utilities/#DataInterpolations.jl:-One-Dimensional-Interpolations","page":"SciML Numerical Utility Libraries","title":"DataInterpolations.jl: One-Dimensional Interpolations","text":"","category":"section"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"DataInterpolations.jl is a library of one-dimensional interpolation schemes which are composable with automatic differentiation and the SciML ecosystem. It includes direct interpolation methods and regression techniques for handling noisy data. Its methods include:","category":"page"},{"location":"highlevels/numerical_utilities/","page":"SciML Numerical Utility Libraries","title":"SciML Numerical Utility Libraries","text":"ConstantInterpolation(u,t) - A piecewise constant interpolation.\nLinearInterpolation(u,t) - A linear interpolation.\nQuadraticInterpolation(u,t) - A quadratic interpolation.\nLagrangeInterpolation(u,t,n) - A Lagrange interpolation of order n.\nQuadraticSpline(u,t) - A quadratic spline interpolation.\nCubicSpline(u,t) - A cubic spline interpolation.\nBSplineInterpolation(u,t,d,pVec,knotVec) - An interpolation B-spline. This is a B-spline which hits each of the data points. The argument choices are:\nd - degree of B-spline\npVec - Symbol to Parameters Vector, pVec = :Uniform for uniform spaced parameters and pVec = :ArcLen for parameters generated by chord length method.\nknotVec - Symbol to Knot Vector, knotVec = :Uniform for uniform knot vector, knotVec = :Average for average spaced knot vector.\nBSplineApprox(u,t,d,h,pVec,knotVec) - A regression B-spline which smooths the fitting curve. The argument choices are the same as the BSplineInterpolation, with the additional parameter hThe setup of the data and the ODEs for the Newtonian ODE model","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"\n#=\n ODE models for orbital mechanics\n=#\n\nfunction NewtonianOrbitModel(u, model_params, t)\n #=\n Defines system of odes which describes motion of\n point like particle with Newtonian physics, uses\n\n u[1] = χ\n u[2] = ϕ\n\n where, p, M, and e are constants\n =#\n χ, ϕ = u\n p, M, e = model_params\n\n numer = (1 + e * cos(χ))^2\n denom = M * (p^(3 / 2))\n\n χ̇ = numer / denom\n ϕ̇ = numer / denom\n\n return [χ̇, ϕ̇]\n\nend\n\nfunction RelativisticOrbitModel(u, model_params, t)\n #=\n Defines system of odes which describes motion of\n point like particle in schwarzschild background, uses\n\n u[1] = χ\n u[2] = ϕ\n\n where, p, M, and e are constants\n =#\n χ, ϕ = u\n p, M, e = model_params\n\n numer = (p - 2 - 2 * e * cos(χ)) * (1 + e * cos(χ))^2\n denom = sqrt((p - 2)^2 - 4 * e^2)\n\n χ̇ = numer * sqrt(p - 6 - 2 * e * cos(χ)) / (M * (p^2) * denom)\n ϕ̇ = numer / (M * (p^(3 / 2)) * denom)\n\n return [χ̇, ϕ̇]\n\nend\n\nfunction AbstractNNOrbitModel(u, model_params, t; NN=nothing, NN_params=nothing)\n #=\n Defines system of odes which describes motion of\n point like particle with Newtonian physics, uses\n\n u[1] = χ\n u[2] = ϕ\n\n where, p, M, and e are constants\n =#\n χ, ϕ = u\n p, M, e = model_params\n\n if isnothing(NN)\n nn = [1, 1]\n else\n nn = 1 .+ NN([u[1]], NN_params, st)[1]\n end\n\n numer = (1 + e * cos(χ))^2\n denom = M * (p^(3 / 2))\n\n χ̇ = (numer / denom) * nn[1]\n ϕ̇ = (numer / denom) * nn[2]\n\n return [χ̇, ϕ̇]\n\nend\n\nfunction AbstractNROrbitModel(u, model_params, t;\n NN_chiphi=nothing, NN_chiphi_params=nothing,\n NN_pe=nothing, NN_pe_params=nothing)\n #=\n Defines system of odes which describes motion of\n point like particle with Newtonian physics, uses\n\n u[1] = χ\n u[2] = ϕ\n u[3] = p\n u[4] = e\n\n q is the mass ratio\n =#\n χ, ϕ, p, e = u\n q = model_params[1]\n M = 1.0\n\n if p <= 0\n println(\"p = \", p)\n end\n\n if isnothing(NN_chiphi)\n nn_chiphi = [1, 1]\n else\n nn_chiphi = 1 .+ NN_chiphi(u, NN_chiphi_params, st)\n end\n\n if isnothing(NN_pe)\n nn_pe = [0, 0]\n else\n nn_pe = NN_pe(u, NN_pe_params, st)\n end\n\n numer = (1 + e * cos(χ))^2\n denom = M * (abs(p)^(3 / 2))\n\n χ̇ = (numer / denom) * nn_chiphi[1]\n ϕ̇ = (numer / denom) * nn_chiphi[2]\n ṗ = nn_pe[1]\n ė = nn_pe[2]\n\n return [χ̇, ϕ̇, ṗ, ė]\nend\n\n#=\n Axiliary functions for orbital mechanics\n=#\nusing DelimitedFiles\n\nfunction soln2orbit(soln, model_params=nothing)\n #=\n Performs change of variables:\n (χ(t),ϕ(t)) ↦ (x(t),y(t))\n =#\n if size(soln, 1) == 2\n χ = soln[1, :]\n ϕ = soln[2, :]\n if length(model_params) == 3\n p, M, e = model_params\n else\n error(\"model_params must have length 3 when size(soln,2) = 2\")\n end\n elseif size(soln, 1) == 4\n χ = soln[1, :]\n ϕ = soln[2, :]\n p = soln[3, :]\n e = soln[4, :]\n else\n error(\"size(soln,2) must be either 2 or 4\")\n end\n\n r = p ./ (1 .+ e .* cos.(χ))\n x = r .* cos.(ϕ)\n y = r .* sin.(ϕ)\n\n orbit = vcat(x', y')\n return orbit\nend\n\nfunction orbit2tensor(orbit, component, mass=1.0)\n #=\n Construct trace-free moment tensor Ι(t) for orbit from BH orbit (x(t),y(t))\n\n component defines the Cartesion indices in x,y. For example,\n I_{22} is the yy component of the moment tensor.\n =#\n x = orbit[1, :]\n y = orbit[2, :]\n\n Ixx = x .^ 2\n Iyy = y .^ 2\n Ixy = x .* y\n trace = Ixx .+ Iyy\n\n if component[1] == 1 && component[2] == 1\n tmp = Ixx .- (1.0 ./ 3.0) .* trace\n elseif component[1] == 2 && component[2] == 2\n tmp = Iyy .- (1.0 ./ 3.0) .* trace\n else\n tmp = Ixy\n end\n\n return mass .* tmp\nend\n\nfunction d_dt(v::AbstractVector, dt)\n # uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0\n a = -3 / 2 * v[1] + 2 * v[2] - 1 / 2 * v[3]\n b = (v[3:end] .- v[1:end-2]) / 2\n c = 3 / 2 * v[end] - 2 * v[end-1] + 1 / 2 * v[end-2]\n return [a; b; c] / dt\nend\n\nfunction d2_dt2(v::AbstractVector, dt)\n # uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0\n a = 2 * v[1] - 5 * v[2] + 4 * v[3] - v[4]\n b = v[1:end-2] .- 2 * v[2:end-1] .+ v[3:end]\n c = 2 * v[end] - 5 * v[end-1] + 4 * v[end-2] - v[end-3]\n return [a; b; c] / (dt^2)\nend\n\nfunction h_22_quadrupole_components(dt, orbit, component, mass=1.0)\n #=\n x(t) and y(t) inputs are the trajectory of the orbiting BH.\n\n WARNING: assuming x and y are on a uniform grid of spacing dt\n x_index and y_index are 1,2,3 for x, y, and z indices.\n =#\n\n mtensor = orbit2tensor(orbit, component, mass)\n mtensor_ddot = d2_dt2(mtensor, dt)\n\n # return mtensor\n return 2 * mtensor_ddot\nend\n\nfunction h_22_quadrupole(dt, orbit, mass=1.0)\n h11 = h_22_quadrupole_components(dt, orbit, (1, 1), mass)\n h22 = h_22_quadrupole_components(dt, orbit, (2, 2), mass)\n h12 = h_22_quadrupole_components(dt, orbit, (1, 2), mass)\n return h11, h12, h22\nend\n\nfunction h_22_strain_one_body(dt, orbit)\n\n h11, h12, h22 = h_22_quadrupole(dt, orbit)\n\n h₊ = h11 - h22\n hₓ = 2.0 * h12\n\n scaling_const = sqrt(pi / 5)\n return scaling_const * h₊, -scaling_const * hₓ\nend\n\nfunction h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)\n h11_1, h12_1, h22_1 = h_22_quadrupole(dt, orbit1, mass1)\n h11_2, h12_2, h22_2 = h_22_quadrupole(dt, orbit2, mass2)\n h11 = h11_1 + h11_2\n h12 = h12_1 + h12_2\n h22 = h22_1 + h22_2\n return h11, h12, h22\nend\n\nfunction h_22_strain_two_body(dt, orbit1, mass1, orbit2, mass2)\n # compute (2,2) mode strain from orbits of BH 1 of mass1 and BH2 of mass 2\n\n @assert abs(mass1 + mass2 - 1.0) < 1e-12 \"Masses do not sum to unity\"\n\n h11, h12, h22 = h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)\n\n h₊ = h11 - h22\n hₓ = 2.0 * h12\n\n scaling_const = sqrt(pi / 5)\n return scaling_const * h₊, -scaling_const * hₓ\nend\n\nfunction one2two(path, m1, m2)\n #=\n We need a very crude 2-body path\n\n Assume the 1-body motion is a newtonian 2-body position vector r = r1 - r2\n and use Newtonian formulas to get r1, r2\n (e.g. Theoretical Mechanics of Particles and Continua 4.3)\n =#\n\n M = m1 + m2\n r1 = m2 / M .* path\n r2 = -m1 / M .* path\n\n return r1, r2\nend\n\nfunction compute_waveform(dt, soln, mass_ratio, model_params=nothing)\n\n @assert mass_ratio <= 1.0 \"mass_ratio must be <= 1\"\n @assert mass_ratio >= 0.0 \"mass_ratio must be non-negative\"\n\n orbit = soln2orbit(soln, model_params)\n if mass_ratio > 0\n mass1 = mass_ratio / (1.0 + mass_ratio)\n mass2 = 1.0 / (1.0 + mass_ratio)\n\n orbit1, orbit2 = one2two(orbit, mass1, mass2)\n waveform = h_22_strain_two_body(dt, orbit1, mass1, orbit2, mass2)\n else\n waveform = h_22_strain_one_body(dt, orbit)\n end\n return waveform\nend\n\nfunction interpolate_time_series(tsteps, tdata, fdata)\n\n @assert length(tdata) == length(fdata) \"lengths of tdata and fdata must match\"\n\n interp_fdata = zeros(length(tsteps))\n for j = 1:length(tsteps)\n for i = 1:length(tdata)-1\n if tdata[i] <= tsteps[j] < tdata[i+1]\n weight = (tsteps[j] - tdata[i]) / (tdata[i+1] - tdata[i])\n interp_fdata[j] = (1 - weight) * fdata[i] + weight * fdata[i+1]\n break\n end\n end\n end\n\n return interp_fdata\nend\n\nfunction file2waveform(tsteps, filename=\"waveform.txt\")\n\n # read in file\n f = open(filename, \"r\")\n data = readdlm(f)\n tdata = data[:, 1]\n wdata = data[:, 2]\n\n # interpolate data to tsteps\n waveform = interpolate_time_series(tsteps, tdata, wdata)\n\n return waveform\nend\n\nfunction file2trajectory(tsteps, filename=\"trajectoryA.txt\")\n\n # read in file\n f = open(filename, \"r\")\n data = readdlm(f)\n tdata = data[:, 1]\n xdata = data[:, 2]\n ydata = data[:, 3]\n\n # interpolate data to tsteps\n x = interpolate_time_series(tsteps, tdata, xdata)\n y = interpolate_time_series(tsteps, tdata, ydata)\n\n return x, y\nend","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"","category":"page"},{"location":"showcase/blackhole/#Testing-the-Model-Setup","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Testing the Model Setup","text":"","category":"section"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Now let's test the relativistic orbital model. Let's choose a few parameters of interest:","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"mass_ratio = 0.0 # test particle\nu0 = Float64[pi, 0.0] # initial conditions\ndatasize = 250\ntspan = (0.0f0, 6.0f4) # timespace for GW waveform\ntsteps = range(tspan[1], tspan[2], length = datasize) # time at each timestep\ndt_data = tsteps[2] - tsteps[1] \ndt = 100.0\nmodel_params = [100.0, 1.0, 0.5]; # p, M, e","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"and demonstrate the gravitational waveform:","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"prob = ODEProblem(RelativisticOrbitModel, u0, tspan, model_params)\nsoln = Array(solve(prob, RK4(), saveat = tsteps, dt = dt, adaptive=false))\nwaveform = compute_waveform(dt_data, soln, mass_ratio, model_params)[1]\nplt = plot(tsteps, waveform,\n markershape=:circle, markeralpha = 0.25,\n linewidth = 2, alpha = 0.5,\n label=\"waveform data\", xlabel=\"Time\", ylabel=\"Waveform\")","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Looks great! ","category":"page"},{"location":"showcase/blackhole/#Automating-the-Discovery-of-Relativistic-Equations-from-Newtonian-Physics","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Automating the Discovery of Relativistic Equations from Newtonian Physics","text":"","category":"section"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Now let's learn the relativistic corrections directly from the data. To define the UDE, we will define a Lux neural network and pass it into our Newtonian Physics + Neural Network ODE definition from above:","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"NN = Lux.Chain((x) -> cos.(x),\n Lux.Dense(1, 32, cos),\n Lux.Dense(32, 32, cos),\n Lux.Dense(32, 2))\np, st = Lux.setup(rng, NN)\nNN_params = ComponentArray{Float64}(p)\n\nfunction ODE_model(u, NN_params, t)\n du = AbstractNNOrbitModel(u, model_params, t, NN=NN, NN_params=NN_params)\n return du\nend","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Next, we can compute the orbital trajectory and gravitational waveform using the neural network with its initial weights. ","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"prob_nn = ODEProblem(ODE_model, u0, tspan, NN_params)\nsoln_nn = Array(solve(prob_nn, RK4(), u0 = u0, p = NN_params, saveat = tsteps, dt = dt, adaptive=false))\nwaveform_nn = compute_waveform(dt_data, soln_nn, mass_ratio, model_params)[1]\nplot!(plt, tsteps, waveform_nn,\n markershape=:circle, markeralpha = 0.25,\n linewidth = 2, alpha = 0.5,\n label=\"waveform NN\")\ndisplay(plt)","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"This is the model before training. ","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Next, we define the objective (loss) function to be minimized when training the neural differential equations.","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"function loss(NN_params)\n first_obs_to_use_for_training = 1\n last_obs_to_use_for_training = length(waveform)\n obs_to_use_for_training = first_obs_to_use_for_training:last_obs_to_use_for_training \n \n pred = Array(solve(prob_nn, RK4(), u0 = u0, p = NN_params, saveat = tsteps, dt = dt, adaptive=false))\n pred_waveform = compute_waveform(dt_data, pred, mass_ratio, model_params)[1]\n\n loss = ( sum(abs2, view(waveform,obs_to_use_for_training) .- view(pred_waveform,obs_to_use_for_training) ) )\n return loss, pred_waveform\nend","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"We can test the loss function and see that it returns a pair, a scalar loss and an array with the predicted waveform.","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"loss(NN_params)","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"We'll use the following callback to save the history of the loss values.","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"losses = []\n\ncallback(θ,l,pred_waveform; doplot = true) = begin\n push!(losses, l)\n #= Disable plotting as it trains since in docs\n display(l)\n # plot current prediction against data\n plt = plot(tsteps, waveform,\n markershape=:circle, markeralpha = 0.25,\n linewidth = 2, alpha = 0.5,\n label=\"wform data (h22)\", legend=:topleft)\n plot!(plt, tsteps, pred_waveform,\n markershape=:circle, markeralpha = 0.25,\n linewidth = 2, alpha = 0.5,\n label = \"wform NN\")\n if doplot\n display(plot(plt))\n end\n # Tell sciml_train to not halt the optimization. If return true, then\n # optimization stops.\n =#\n return false\nend","category":"page"},{"location":"showcase/blackhole/#Running-the-Training","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Running the Training","text":"","category":"section"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"The next cell initializes the weights of the neural network and then trains the neural network. Training uses the BFGS optimizers. This seems to give good results because the Newtonian model seems to give a very good initial guess.","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"NN_params = NN_params .* 0 + Float64(1e-4) * randn(StableRNG(2031), eltype(NN_params), size(NN_params))\n\nadtype = Optimization.AutoZygote()\noptf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)\noptprob = Optimization.OptimizationProblem(optf, ComponentVector{Float64}(NN_params))\nres1 = Optimization.solve(optprob, OptimizationOptimisers.Adam(0.001f0), callback=callback, maxiters=100)\noptprob = Optimization.OptimizationProblem(optf, res1.u)\nres2 = Optimization.solve(optprob, BFGS(initial_stepnorm=0.01, linesearch=LineSearches.BackTracking()), callback=callback, maxiters=20)","category":"page"},{"location":"showcase/blackhole/#Result-Analysis","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Result Analysis","text":"","category":"section"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Now, we'll plot the learned solutions of the neural ODE and compare them to our full physical model and the Newtonian model. ","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"reference_solution = solve(remake(prob, p = model_params, saveat = tsteps, tspan=tspan),\n RK4(), dt = dt, adaptive=false)\n\noptimized_solution = solve(remake(prob_nn, p = res2.minimizer, saveat = tsteps, tspan=tspan),\n RK4(), dt = dt, adaptive=false)\nNewtonian_prob = ODEProblem(NewtonianOrbitModel, u0, tspan, model_params)\n\nNewtonian_solution = solve(remake(Newtonian_prob, p = model_params, saveat = tsteps, tspan=tspan),\n RK4(), dt = dt, adaptive=false)\n\ntrue_orbit = soln2orbit(reference_solution, model_params)\npred_orbit = soln2orbit(optimized_solution, model_params)\nNewt_orbit = soln2orbit(Newtonian_solution, model_params)\n\ntrue_waveform = compute_waveform(dt_data, reference_solution, mass_ratio, model_params)[1]\npred_waveform = compute_waveform(dt_data, optimized_solution, mass_ratio, model_params)[1]\nNewt_waveform = compute_waveform(dt_data, Newtonian_solution, mass_ratio, model_params)[1]\n\ntrue_orbit = soln2orbit(reference_solution, model_params)\npred_orbit = soln2orbit(optimized_solution, model_params)\nNewt_orbit = soln2orbit(Newtonian_solution, model_params)\nplt = plot(true_orbit[1,:], true_orbit[2,:], linewidth = 2, label = \"truth\")\nplot!(plt, pred_orbit[1,:], pred_orbit[2,:], linestyle = :dash, linewidth = 2, label = \"prediction\")\nplot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = \"Newtonian\")","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"plt = plot(tsteps,true_waveform, linewidth = 2, label = \"truth\", xlabel=\"Time\", ylabel=\"Waveform\")\nplot!(plt,tsteps,pred_waveform, linestyle = :dash, linewidth = 2, label = \"prediction\")\nplot!(plt,tsteps,Newt_waveform, linewidth = 2, label = \"Newtonian\")","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"Now we'll do the same, but extrapolating the model out in time.","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"factor=5\n\nextended_tspan = (tspan[1], factor*tspan[2])\nextended_tsteps = range(tspan[1], factor*tspan[2], length = factor*datasize)\nreference_solution = solve(remake(prob, p = model_params, saveat = extended_tsteps, tspan=extended_tspan),\n RK4(), dt = dt, adaptive=false)\noptimized_solution = solve(remake(prob_nn, p = res2.minimizer, saveat = extended_tsteps, tspan=extended_tspan),\n RK4(), dt = dt, adaptive=false)\nNewtonian_prob = ODEProblem(NewtonianOrbitModel, u0, tspan, model_params)\nNewtonian_solution = solve(remake(Newtonian_prob, p = model_params, saveat = extended_tsteps, tspan=extended_tspan),\n RK4(), dt = dt, adaptive=false)\ntrue_orbit = soln2orbit(reference_solution, model_params)\npred_orbit = soln2orbit(optimized_solution, model_params)\nNewt_orbit = soln2orbit(Newtonian_solution, model_params)\nplt = plot(true_orbit[1,:], true_orbit[2,:], linewidth = 2, label = \"truth\")\nplot!(plt, pred_orbit[1,:], pred_orbit[2,:], linestyle = :dash, linewidth = 2, label = \"prediction\")\nplot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = \"Newtonian\")","category":"page"},{"location":"showcase/blackhole/","page":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","title":"Discovering the Relativistic Corrections to Binary Black Hole Dynamics","text":"true_waveform = compute_waveform(dt_data, reference_solution, mass_ratio, model_params)[1]\npred_waveform = compute_waveform(dt_data, optimized_solution, mass_ratio, model_params)[1]\nNewt_waveform = compute_waveform(dt_data, Newtonian_solution, mass_ratio, model_params)[1]\nplt = plot(extended_tsteps,true_waveform, linewidth = 2, label = \"truth\", xlabel=\"Time\", ylabel=\"Waveform\")\nplot!(plt,extended_tsteps,pred_waveform, linestyle = :dash, linewidth = 2, label = \"prediction\")\nplot!(plt,extended_tsteps,Newt_waveform, linewidth = 2, label = \"Newtonian\")","category":"page"},{"location":"highlevels/implicit_layers/#Implicit-Layer-Deep-Learning","page":"Implicit Layer Deep Learning","title":"Implicit Layer Deep Learning","text":"","category":"section"},{"location":"highlevels/implicit_layers/","page":"Implicit Layer Deep Learning","title":"Implicit Layer Deep Learning","text":"Implicit layer deep learning is a field which uses implicit rules, such as differential equations and nonlinear solvers, to define the layers of neural networks. This field has brought the potential to automatically optimize network depth and improve training performance. SciML's differentiable solver ecosystem is specifically designed to accommodate implicit layer methodologies, and provides libraries with pre-built layers for common methods.","category":"page"},{"location":"highlevels/implicit_layers/#DiffEqFlux.jl:-High-Level-Pre-Built-Architectures-for-Implicit-Deep-Learning","page":"Implicit Layer Deep Learning","title":"DiffEqFlux.jl: High Level Pre-Built Architectures for Implicit Deep Learning","text":"","category":"section"},{"location":"highlevels/implicit_layers/","page":"Implicit Layer Deep Learning","title":"Implicit Layer Deep Learning","text":"DiffEqFlux.jl is a library of pre-built architectures for implicit deep learning, including layer definitions for methods like:","category":"page"},{"location":"highlevels/implicit_layers/","page":"Implicit Layer Deep Learning","title":"Implicit Layer Deep Learning","text":"Neural Ordinary Differential Equations (Neural ODEs)\nCollocation-Based Neural ODEs (Neural ODEs without a solver, by far the fastest way!)\nMultiple Shooting Neural Ordinary Differential Equations\nNeural Stochastic Differential Equations (Neural SDEs)\nNeural Differential-Algebraic Equations (Neural DAEs)\nNeural Delay Differential Equations (Neural DDEs)\nAugmented Neural ODEs\nHamiltonian Neural Networks (with specialized second order and symplectic integrators)\nContinuous Normalizing Flows (CNF) and FFJORD","category":"page"},{"location":"highlevels/implicit_layers/#DeepEquilibriumNetworks.jl:-Deep-Equilibrium-Models-Made-Fast","page":"Implicit Layer Deep Learning","title":"DeepEquilibriumNetworks.jl: Deep Equilibrium Models Made Fast","text":"","category":"section"},{"location":"highlevels/implicit_layers/","page":"Implicit Layer Deep Learning","title":"Implicit Layer Deep Learning","text":"DeepEquilibriumNetworks.jl is a library of optimized layer implementations for Deep Equilibrium Models (DEQs). It uses special training techniques such as implicit-explicit regularization in order to accelerate the convergence over traditional implementations, all while using the optimized and flexible SciML libraries under the hood.","category":"page"},{"location":"getting_started/fit_simulation/#fit_simulation","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Running simulations is only half of the battle. Many times, in order to make the simulation realistic, you need to fit the simulation to data. The SciML ecosystem has integration with automatic differentiation and adjoint methods to automatically make the fitting process stable and efficient. Let's see this in action.","category":"page"},{"location":"getting_started/fit_simulation/#Required-Dependencies","page":"Fit a simulation to a dataset","title":"Required Dependencies","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"The following parts of the SciML Ecosystem will be used in this tutorial:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Module Description\nDifferentialEquations.jl The differential equation solvers\nOptimization.jl The numerical optimization package\nOptimizationPolyalgorithms.jl The optimizers we will use\nSciMLSensitivity.jl The connection of the SciML ecosystems to differentiation","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Along with the following general ecosystem packages:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Module Description\nPlots.jl The plotting and visualization package\nForwardDiff.jl The automatic differentiation package","category":"page"},{"location":"getting_started/fit_simulation/#Problem-Setup:-Fitting-Lotka-Volterra-Data","page":"Fit a simulation to a dataset","title":"Problem Setup: Fitting Lotka-Volterra Data","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Assume that we know that the dynamics of our system are given by the Lotka-Volterra dynamical system: Let x(t) be the number of rabbits in the environment and y(t) be the number of wolves. This is the same dynamical system as the first tutorial! The equation that defines the evolution of the species is given as follows:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"beginalign\nfracdxdt = alpha x - beta x y\nfracdydt = -gamma y + delta x y\nendalign","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"where alpha beta gamma delta are parameters. Starting from equal numbers of rabbits and wolves, x(0) = 1 and y(0) = 1.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now, in the first tutorial, we assumed:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Luckily, a local guide provided us with some parameters that seem to match the system!","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Sadly, magical nymphs do not always show up and give us parameters. Thus in this case, we will need to use Optimization.jl to optimize the model parameters to best fit some experimental data. We are given experimentally observed data of both rabbit and wolf populations over a time span of t_0 = 0 to t_f = 10 at every Delta t = 1. Can we figure out what the parameter values should be directly from the data?","category":"page"},{"location":"getting_started/fit_simulation/#Solution-as-Copy-Pastable-Code","page":"Fit a simulation to a dataset","title":"Solution as Copy-Pastable Code","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"using DifferentialEquations, Optimization, OptimizationPolyalgorithms, SciMLSensitivity\nusing ForwardDiff, Plots\n\n# Define experimental data\nt_data = 0:10\nx_data = [1.000 2.773 6.773 0.971 1.886 6.101 1.398 1.335 4.353 3.247 1.034]\ny_data = [1.000 0.259 2.015 1.908 0.323 0.629 3.458 0.508 0.314 4.547 0.906]\nxy_data = vcat(x_data, y_data)\n\n# Plot the provided data\nscatter(t_data, xy_data', label=[\"x Data\" \"y Data\"])\n\n# Setup the ODE function\nfunction lotka_volterra!(du, u, p, t)\n x, y = u\n α, β, δ, γ = p\n du[1] = dx = α * x - β * x * y\n du[2] = dy = -δ * y + γ * x * y\nend\n\n# Initial condition\nu0 = [1.0, 1.0]\n\n# Simulation interval\ntspan = (0.0, 10.0)\n\n# LV equation parameter. p = [α, β, δ, γ]\npguess = [1.0, 1.2, 2.5, 1.2]\n\n# Set up the ODE problem with our guessed parameter values\nprob = ODEProblem(lotka_volterra!, u0, tspan, pguess)\n\n# Solve the ODE problem with our guessed parameter values\ninitial_sol = solve(prob, saveat = 1)\n\n# View the guessed model solution\nplt = plot(initial_sol, label = [\"x Prediction\" \"y Prediction\"])\nscatter!(plt, t_data, xy_data', label = [\"x Data\" \"y Data\"])\n\n# Define a loss metric function to be minimized\nfunction loss(newp)\n newprob = remake(prob, p = newp)\n sol = solve(newprob, saveat = 1)\n loss = sum(abs2, sol .- xy_data)\n return loss, sol\nend\n\n# Define a callback function to monitor optimization progress\nfunction callback(p, l, sol)\n display(l)\n plt = plot(sol, ylim = (0, 6), label = [\"Current x Prediction\" \"Current y Prediction\"])\n scatter!(plt, t_data, xy_data', label = [\"x Data\" \"y Data\"])\n display(plt)\n return false\nend\n\n# Set up the optimization problem with our loss function and initial guess\nadtype = AutoForwardDiff()\npguess = [1.0, 1.2, 2.5, 1.2]\noptf = OptimizationFunction((x, _) -> loss(x), adtype)\noptprob = OptimizationProblem(optf, pguess)\n\n# Optimize the ODE parameters for best fit to our data\npfinal = solve(optprob, PolyOpt(),\n callback = callback,\n maxiters = 200)\nα, β, γ, δ = round.(pfinal, digits=1)","category":"page"},{"location":"getting_started/fit_simulation/#Step-by-Step-Solution","page":"Fit a simulation to a dataset","title":"Step-by-Step Solution","text":"","category":"section"},{"location":"getting_started/fit_simulation/#Step-1:-Install-and-Import-the-Required-Packages","page":"Fit a simulation to a dataset","title":"Step 1: Install and Import the Required Packages","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"To do this tutorial, we will need a few components. This is done using the Julia Pkg REPL:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"using Pkg\nPkg.add([\n \"DifferentialEquations\",\n \"Optimization\",\n \"OptimizationPolyalgorithms\",\n \"SciMLSensitivity\",\n \"ForwardDiff\",\n \"Plots\",\n ])","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now we're ready. Let's load in these packages:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"using DifferentialEquations, Optimization, OptimizationPolyalgorithms, SciMLSensitivity\nusing ForwardDiff, Plots","category":"page"},{"location":"getting_started/fit_simulation/#Step-2:-View-the-Training-Data","page":"Fit a simulation to a dataset","title":"Step 2: View the Training Data","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"In our example, we are given observed values for x and y populations at eleven instances in time. Let's make that the training data for our Lotka-Volterra dynamical system model.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"# Define experimental data\nt_data = 0:10\nx_data = [1.000 2.773 6.773 0.971 1.886 6.101 1.398 1.335 4.353 3.247 1.034]\ny_data = [1.000 0.259 2.015 1.908 0.323 0.629 3.458 0.508 0.314 4.547 0.906]\nxy_data = vcat(x_data, y_data)\n\n# Plot the provided data\nscatter(t_data, xy_data', label=[\"x Data\" \"y Data\"])","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"note: Note\nThe Array xy_data above has been oriented with time instances as columns so that it can be directly compared with an ODESolution object. (See Solution Handling for more information on accessing DifferentialEquation.jl solution data.) However, plotting an Array with Plots.jl requires the variables to be columns and the time instances to be rows. Thus, whenever the experimental data is plotted, the transpose xy_data' will be used.","category":"page"},{"location":"getting_started/fit_simulation/#Step-3:-Set-Up-the-ODE-Model","page":"Fit a simulation to a dataset","title":"Step 3: Set Up the ODE Model","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"We know that our system will behave according to the Lotka-Volterra ODE model, so let's set up that model with an initial guess at the parameter values: \\alpha, \\beta, \\gamma, and \\delta. Unlike the first tutorial, which used ModelingToolkit, let's demonstrate using DifferentialEquations.jl to directly define the ODE for the numerical solvers.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"To do this, we define a vector-based mutating function that calculates the derivatives for our system. We will define our system as a vector u = [x,y], and thus u[1] = x and u[2] = y. This means that we need to calculate the derivative as du = [dx,dy]. Our parameters will simply be the vector p = [α, β, δ, γ]. Writing down the Lotka-Volterra equations in the DifferentialEquations.jl direct form thus looks like the following:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"function lotka_volterra!(du, u, p, t)\n x, y = u\n α, β, δ, γ = p\n du[1] = dx = α * x - β * x * y\n du[2] = dy = -δ * y + γ * x * y\nend","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now we need to define the initial condition, time span, and parameter vector in order to solve this differential equation. We do not currently know the parameter values, but we will guess some values to start with and optimize them later. Following the problem setup, this looks like:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"# Initial condition\nu0 = [1.0, 1.0]\n\n# Simulation interval\ntspan = (0.0, 10.0)\n\n# LV equation parameter. p = [α, β, δ, γ]\npguess = [1.0, 1.2, 2.5, 1.2]","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now we bring these pieces all together to define the ODEProblem and solve it. Note that we solve this equation with the keyword argument saveat = 1 so that it saves a point at every Delta t = 1 to match our experimental data.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"# Set up the ODE problem with our guessed parameter values\nprob = ODEProblem(lotka_volterra!, u0, tspan, pguess)\n\n# Solve the ODE problem with our guessed parameter values\ninitial_sol = solve(prob, saveat = 1)\n\n# View the guessed model solution\nplt = plot(initial_sol, label = [\"x Prediction\" \"y Prediction\"])\nscatter!(plt, t_data, xy_data', label = [\"x Data\" \"y Data\"])","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Clearly the parameter values that we guessed are not correct to model this system.\nHowever, we can use Optimization.jl together with DifferentialEquations.jl\nto fit our parameters to our training data.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"note: Note\nFor more details on using DifferentialEquations.jl, check out the getting started with DifferentialEquations.jl tutorial.","category":"page"},{"location":"getting_started/fit_simulation/#Step-4:-Set-Up-the-Loss-Function-for-Optimization","page":"Fit a simulation to a dataset","title":"Step 4: Set Up the Loss Function for Optimization","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now let's start the optimization process. First, let's define a loss function to be minimized. (It is also sometimes referred to as a cost function.) For our loss function, we want to take a set of parameters, create a new ODE which has everything the same except for the changed parameters, solve this ODE with new parameters, and compare the ODE solution against the provided data. In this case, the loss returned from the loss function is a quantification of the difference between the current solution and the desired solution. When this difference is minimized, our model prediction will closely approximate the observed system data.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"To change our parameter values, there is a useful functionality in the SciML problems interface called remake which creates a new version of an existing SciMLProblem with the aspect you want changed. For example, if we wanted to change the initial condition u0 of our ODE, we could do remake(prob, u0 = newu0) For our case, we want to change around just the parameters, so we can do remake(prob, p = newp). It is faster to remake an existing SciMLProblem than to create a new problem every iteration.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"note: Note\nremake can change multiple items at once by passing more keyword arguments, i.e., remake(prob, u0 = newu0, p = newp). This can be used to extend the example to simultaneously learn the initial conditions and parameters!","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now use remake to build the loss function. After we solve the new problem, we will calculate the sum of squared errors as our loss metric. The sum of squares can be quickly written in Julia via sum(abs2,x). Using this information, our loss function looks like:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"function loss(newp)\n newprob = remake(prob, p = newp)\n sol = solve(newprob, saveat = 1)\n l = sum(abs2, sol .- xy_data)\n return l, sol\nend","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Notice that our loss function returns the loss value as the first return, but returns extra information (the ODE solution with the new parameters) as an extra return argument. We will explain why this extra return information is helpful in the next section.","category":"page"},{"location":"getting_started/fit_simulation/#Step-5:-Solve-the-Optimization-Problem","page":"Fit a simulation to a dataset","title":"Step 5: Solve the Optimization Problem","text":"","category":"section"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"This step will look very similar to the first optimization tutorial, except now we have a new loss function loss which returns both the loss value and the associated ODE solution. (In the previous tutorial, L only returned the loss value.) The Optimization.solve function can accept an optional callback function to monitor the optimization process using extra arguments returned from loss.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"The callback syntax is always:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"callback(\n optimization variables,\n the current loss value,\n other arguments returned from the loss function, ...\n)","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"In this case, we will provide the callback the arguments (p, l, sol), since it always takes the current state of the optimization first (p) then the returns from the loss function (l, sol). The return value of the callback function should default to false. Optimization.solve will halt if/when the callback function returns true instead. Typically the return statement would monitor the loss value and stop once some criteria is reached, e.g. return loss < 0.0001, but we will stop after a set number of iterations instead. More details about callbacks in Optimization.jl can be found here.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"function callback(p, l, sol)\n display(l)\n plt = plot(sol, ylim = (0, 6), label = [\"Current x Prediction\" \"Current y Prediction\"])\n scatter!(plt, t_data, xy_data', label = [\"x Data\" \"y Data\"])\n display(plt)\n return false\nend","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"With this callback function, every step of the optimization will display both the loss value and a plot of how the solution compares to the training data.","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Now, just like the first optimization tutorial, we set up our OptimizationFunction and OptimizationProblem, and then solve the OptimizationProblem. We will initialize the OptimizationProblem with the same pguess we used when setting up the ODE Model in Step 3. Observe how Optimization.solve brings the model closer to the experimental data as it iterates towards better ODE parameter values!","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"Note that we are using the PolyOpt() solver choice here which is discussed https://docs.sciml.ai/Optimization/dev/optimization_packages/polyopt/ since parameter estimation of non-linear differential equations is generally a non-convex problem so we want to run a stochastic algorithm (Adam) to get close to the minimum and then finish off with a quasi-newton method (L-BFGS) to find the optima. Together, this looks like:","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"# Set up the optimization problem with our loss function and initial guess\nadtype = AutoForwardDiff()\npguess = [1.0, 1.2, 2.5, 1.2]\noptf = OptimizationFunction((x, _) -> loss(x), adtype)\noptprob = OptimizationProblem(optf, pguess)\n\n# Optimize the ODE parameters for best fit to our data\npfinal = solve(optprob,\n PolyOpt(),\n callback = callback,\n maxiters = 200)\nα, β, γ, δ = round.(pfinal, digits=1)","category":"page"},{"location":"getting_started/fit_simulation/","page":"Fit a simulation to a dataset","title":"Fit a simulation to a dataset","text":"note: Note\nWhen referencing the documentation for DifferentialEquations.jl and Optimization.jl simultaneously, note that the variables f, u, and p will refer to different quantities.DifferentialEquations.jl:fracdudt = f(upt)f in ODEProblem is the function defining the derivative du in the ODE.\nHere: lotka_volterra!\nu in ODEProblem contains the state variables of f.\nHere: x and y\np in ODEProblem contains the parameter variables of f.\nHere: \\alpha, \\beta, \\gamma, and \\delta\nt is the independent (time) variable.\nHere: indirectly defined with tspan in ODEProblem and saveat in solveOptimization.jl:min_u f(up)f in OptimizationProblem is the function to minimize (optimize).\nHere: the anonymous function (x, _) -> loss(x)\nu in OptimizationProblem contains the state variables of f to be optimized.\nHere: the ODE parameters \\alpha, \\beta, \\gamma, and \\delta stored in p\np in OptimizationProblem contains any fixedhyperparameters of f.Here: our `loss` function does not require any hyperparameters, so we pass `_` for this `p`.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#Partial-Differential-Equations-(PDE)","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/#NeuralPDE.jl:-Physics-Informed-Neural-Network-(PINN)-PDE-Solvers","page":"Partial Differential Equations (PDE)","title":"NeuralPDE.jl: Physics-Informed Neural Network (PINN) PDE Solvers","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"NeuralPDE.jl is a partial differential equation solver library which uses physics-informed neural networks (PINNs) to solve the equations. It uses the ModelingToolkit.jl symbolic PDESystem as its input and can handle a wide variety of equation types, including systems of partial differential equations, partial differential-algebraic equations, and integro-differential equations. Its benefit is its flexibility, and it can be used to easily generate surrogate solutions over entire parameter ranges. However, its downside is solver speed: PINN solvers tend to be a lot slower than other methods for solving PDEs.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#MethodOflines.jl:-Automated-Finite-Difference-Method-(FDM)","page":"Partial Differential Equations (PDE)","title":"MethodOflines.jl: Automated Finite Difference Method (FDM)","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"MethodOflines.jl is a partial differential equation solver library which automates the discretization of PDEs via the finite difference method. It uses the ModelingToolkit.jl symbolic PDESystem as its input, and generates AbstractSystems and SciMLProblems whose numerical solution gives the solution to the PDE.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#FEniCS.jl:-Wrappers-for-the-Finite-Element-Method-(FEM)","page":"Partial Differential Equations (PDE)","title":"FEniCS.jl: Wrappers for the Finite Element Method (FEM)","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"FEniCS.jl is a wrapper for the popular FEniCS finite element method library.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#HighDimPDE.jl:-High-dimensional-PDE-Solvers","page":"Partial Differential Equations (PDE)","title":"HighDimPDE.jl: High-dimensional PDE Solvers","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"HighDimPDE.jl is a partial differential equation solver library which implements algorithms that break down the curse of dimensionality to solve the equations. It implements deep-learning based and Picard-iteration based methods to approximately solve high-dimensional, nonlinear, non-local PDEs in up to 10,000 dimensions. Its cons are accuracy: high-dimensional solvers are stochastic, and might result in wrong solutions if the solver meta-parameters are not appropriate.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#NeuralOperators.jl:-(Fourier)-Neural-Operators-and-DeepONets-for-PDE-Solving","page":"Partial Differential Equations (PDE)","title":"NeuralOperators.jl: (Fourier) Neural Operators and DeepONets for PDE Solving","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"NeuralOperators.jl is a library for operator learning based PDE solvers. This includes techniques like:","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"Fourier Neural Operators (FNO)\nDeep Operator Networks (DeepONets)\nMarkov Neural Operators (MNO)","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"Currently, its connection to PDE solving must be specified manually, though an interface for ModelingToolkit PDESystems is in progress.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#DiffEqOperators.jl:-Operators-for-Finite-Difference-Method-(FDM)-Discretizations","page":"Partial Differential Equations (PDE)","title":"DiffEqOperators.jl: Operators for Finite Difference Method (FDM) Discretizations","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"DiffEqOperators.jl is a library for defining finite difference operators to easily perform manual FDM semi-discretizations of partial differential equations. This library is fairly incomplete and most cases should receive better performance using MethodOflines.jl.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#Third-Party-Libraries-to-Note","page":"Partial Differential Equations (PDE)","title":"Third-Party Libraries to Note","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"A more exhaustive list of Julia PDE packages can be found here: https://github.com/JuliaPDE/SurveyofPDEPackages","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#ApproxFun.jl:-Automated-Spectral-Discretizations","page":"Partial Differential Equations (PDE)","title":"ApproxFun.jl: Automated Spectral Discretizations","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"ApproxFun.jl is a package for approximating functions in basis sets. One particular use case is with spectral basis sets, such as Chebyshev functions and Fourier decompositions, making it easy to represent spectral and pseudospectral discretizations of partial differential equations as ordinary differential equations for the SciML equation solvers.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#Ferrite.jl:-Finite-Element-Toolbox-for-Julia","page":"Partial Differential Equations (PDE)","title":"Ferrite.jl: Finite Element Toolbox for Julia","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"Ferrite.jl is a performant and extensible library which provides algorithms and data structures to develop finite element software. This library aims at users which need fine grained control over all algorithmic details, as for example often necessary in research when developing new grid-based PDE discretizations or other more advanced problem formulations for example found in continuum mechanics.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#Gridap.jl:-Julia-Based-Tools-for-Finite-Element-Discretizations","page":"Partial Differential Equations (PDE)","title":"Gridap.jl: Julia-Based Tools for Finite Element Discretizations","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"Gridap.jl is a package for grid-based approximation of partial differential equations, particularly notable for its use of conforming and nonconforming finite element (FEM) discretizations.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#Trixi.jl:-Adaptive-High-Order-Numerical-Simulations-of-Hyperbolic-Equations","page":"Partial Differential Equations (PDE)","title":"Trixi.jl: Adaptive High-Order Numerical Simulations of Hyperbolic Equations","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"Trixi.jl is a package for numerical simulation of hyperbolic conservation laws, i.e. a large set of hyperbolic partial differential equations, which interfaces and uses the SciML ordinary differential equation solvers.","category":"page"},{"location":"highlevels/partial_differential_equation_solvers/#VoronoiFVM.jl:-Tools-for-the-Voronoi-Finite-Volume-Discretizations","page":"Partial Differential Equations (PDE)","title":"VoronoiFVM.jl: Tools for the Voronoi Finite Volume Discretizations","text":"","category":"section"},{"location":"highlevels/partial_differential_equation_solvers/","page":"Partial Differential Equations (PDE)","title":"Partial Differential Equations (PDE)","text":"VoronoiFVM.jl is a library for generating FVM discretizations of systems of PDEs. It interfaces with many of the SciML equation solver libraries to allow for ease of discretization and flexibility in the solver choice.","category":"page"},{"location":"showcase/gpu_spde/#gpuspde","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Let's solve stochastic PDEs in Julia using GPU parallelism. To do this, we will use the type-genericness of the DifferentialEquations.jl library in order to write a code that uses within-method GPU-parallelism on the system of PDEs. The OrdinaryDiffEq.jl solvers of DifferentialEquations.jl, including implicit solvers with GMRES, etc., and the same for SDEs, DAEs, DDEs, etc. are all GPU-compatible with a fast form of broadcast.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"note: Note\nThe non-native Julia solvers, like Sundials are incompatible with arbitrary input types and thus not compatible with GPUs.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Let's dive into showing how to accelerate ODE solving with GPUs!","category":"page"},{"location":"showcase/gpu_spde/#Before-we-start:-the-two-ways-to-accelerate-ODE-solvers-with-GPUs","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Before we start: the two ways to accelerate ODE solvers with GPUs","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Before we dive deeper, let us remark that there are two very different ways that one can accelerate an ODE solution with GPUs. There is one case where u is very big and f is very expensive, but very structured, and you use GPUs to accelerate the computation of said f. The other use case is where u is very small but you want to solve the ODE f over many different initial conditions (u0) or parameters p. In that case, you can use GPUs to parallelize over different parameters and initial conditions. In other words:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Type of Problem SciML Solution\nAccelerate a big ODE Use CUDA.jl's CuArray as u0\nSolve the same ODE with many u0 and p Use DiffEqGPU.jl's EnsembleGPUArray and EnsembleGPUKernel","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"This showcase will focus on the former case. For the latter, see the massively parallel GPU ODE solving showcase.","category":"page"},{"location":"showcase/gpu_spde/#Our-Problem:-2-dimensional-Reaction-Diffusion-Equations","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Our Problem: 2-dimensional Reaction-Diffusion Equations","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"The reaction-diffusion equation is a PDE commonly handled in systems biology, which is a diffusion equation plus a nonlinear reaction term. The dynamics are defined as:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"u_t = D Delta u + f(tu)","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"But this doesn't need to only have a single “reactant” u: this can be a vector of reactants and the f is then the nonlinear vector equations describing how these different pieces react together. Let's settle on a specific equation to make this easier to explain. Let's use a simple model of a 3-component system where A can diffuse through space to bind with the non-diffusive B to form the complex C (also non-diffusive, assume B is too big and gets stuck in a cell which causes C=A+B to be stuck as well). Other than the binding, we make each of these undergo a simple birth-death process, and we write down the equations which result from mass-action kinetics. If this all is meaningless to you, just understand that it gives the system of PDEs:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"beginalign\nA_t = D Delta A + alpha_A(x) - beta_A A - r_1 A B + r_2 C\nB_t = alpha_B - beta_B B - r_1 A B + r_2 C\nC_t = alpha_C - beta_C C + r_1 A B - r_2 C\nendalign","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"One addition that was made to the model is that we let alpha_A(x) be the production of A, and we let that be a function of space so that way it only is produced on one side of our equation. Let's make it a constant when x>80, and 0 otherwise, and let our spatial domain be x in 0100 and y in 0100.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"This model is spatial: each reactant u(txy) is defined at each point in space, and all of the reactions are local, meaning that f at spatial point (xy) only uses u_i(txy). This is an important fact which will come up later for parallelization.","category":"page"},{"location":"showcase/gpu_spde/#Discretizing-the-PDE-into-ODEs","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Discretizing the PDE into ODEs","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"In order to solve this via a method of lines (MOL) approach, we need to discretize the PDE into a system of ODEs. Let's do a simple uniformly-spaced grid finite difference discretization. Choose dx = 1 and dy = 1 so that we have 100*100=10000 points for each reactant. Notice how fast that grows! Put the reactants in a matrix such that A[i,j] = A(x_j,y_i), i.e. the columns of the matrix are the x values and the rows are the y values (this way looking at the matrix is essentially like looking at the discretized space).","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"So now we have 3 matrices (A, B, and C) for our reactants. How do we discretize the PDE? In this case, the diffusion term simply becomes a tridiagonal matrix M where 1-21 is the central band. You can notice that MA performs diffusion along the columns of A, and so this is diffusion along the y. Similarly, AM flips the indices and thus does diffusion along the rows of A making this diffusion along x. Thus D(M_yA + AM_x) is the discretized Laplacian (we could have separate diffusion constants and dx neq dy if we want by using different constants on the M, but let's not do that for this simple example. We leave that as an exercise for the reader). We enforced a Neumann boundary condition with zero derivative (also known as a no-flux boundary condition) by reflecting the changes over the boundary. Thus the derivative operator is generated as:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using LinearAlgebra\n\n# Define the constants for the PDE\nconst α₂ = 1.0\nconst α₃ = 1.0\nconst β₁ = 1.0\nconst β₂ = 1.0\nconst β₃ = 1.0\nconst r₁ = 1.0\nconst r₂ = 1.0\nconst D = 100.0\nconst γ₁ = 0.1\nconst γ₂ = 0.1\nconst γ₃ = 0.1\nconst N = 100\nconst X = reshape([i for i in 1:100 for j in 1:100], N, N)\nconst Y = reshape([j for i in 1:100 for j in 1:100], N, N)\nconst α₁ = 1.0 .* (X .>= 80)\n\nconst Mx = Tridiagonal([1.0 for i in 1:(N - 1)], [-2.0 for i in 1:N],\n [1.0 for i in 1:(N - 1)])\nconst My = copy(Mx)\n# Do the reflections, different for x and y operators\nMx[2, 1] = 2.0\nMx[end - 1, end] = 2.0\nMy[1, 2] = 2.0\nMy[end, end - 1] = 2.0","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"note: Note\nWe could have also done these discretization steps using DiffEqOperators.jl or MethodOfLines.jl. However, we are going to keep it in this form, so we can show the full code, making it easier to see how to define GPU-ready code!","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Since all of the reactions are local, we only have each point in space react separately. Thus this represents itself as element-wise equations on the reactants. Thus we can write it out quite simply. The ODE which then represents the PDE is thus in pseudo Julia code:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"DA = D * (Mx * A + A * My)\n@. DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n@. α₂ - β₂ * B - r₁ * A * B + r₂ * C\n@. α₃ - β₃ * C + r₁ * A * B - r₂ * C","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Note here that I am using α₁ as a matrix (or row-vector, since that will broadcast just fine) where every point in space with x<80 has this zero, and all of the others have it as a constant. The other coefficients are all scalars.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"How do we do this with the ODE solver?","category":"page"},{"location":"showcase/gpu_spde/#Our-Representation-via-Views-of-3-Tensors","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Our Representation via Views of 3-Tensors","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"We can represent our problem with a 3-dimensional tensor, taking each 2-dimensional slice as our (A,B,C). This means that we can define:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"u0 = zeros(N, N, 3);","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Now we can decompose it like:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"A = @view u[:, :, 1]\nB = @view u[:, :, 2]\nC = @view u[:, :, 3]\ndA = @view du[:, :, 1]\ndB = @view du[:, :, 2]\ndC = @view du[:, :, 3]","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"These views will not construct new arrays and will instead just be pointers to the (contiguous) memory pieces, so this is a nice and efficient way to handle this. Together, our ODE using this tensor as its container can be written as follows:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"function f(du, u, p, t)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n DA = D * (Mx * A + A * My)\n @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"where this is using @. to do inplace updates on our du to say how the full tensor should update in time. Note that we can make this more efficient by adding some cache variables to the diffusion matrix multiplications and using mul!, but let's ignore that for now.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Together, the ODE which defines our PDE is thus:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using DifferentialEquations\n\nprob = ODEProblem(f, u0, (0.0, 100.0))\n@time sol = solve(prob, ROCK2());","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"@time sol = solve(prob, ROCK2());","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"if I want to solve it on t in 0100. Done! The solution gives back our tensors (and interpolates to create new ones if you use sol(t)). We can plot it in Plots.jl:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using Plots\np1 = surface(X, Y, sol[end][:, :, 1], title = \"[A]\")\np2 = surface(X, Y, sol[end][:, :, 2], title = \"[B]\")\np3 = surface(X, Y, sol[end][:, :, 3], title = \"[C]\")\nplot(p1, p2, p3, layout = grid(3, 1))","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"and see the pretty gradients. Using this 2nd order ROCK method we solve this equation in about 2 seconds. That's okay.","category":"page"},{"location":"showcase/gpu_spde/#Some-Optimizations","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Some Optimizations","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"There are some optimizations that can still be done. When we do A*B as matrix multiplication, we create another temporary matrix. These allocations can bog down the system. Instead, we can pre-allocate the outputs and use the inplace functions mul! to make better use of memory. The easiest way to store these cache arrays are constant globals, but you can use closures (anonymous functions which capture data, i.e. (x)->f(x,y)) or call-overloaded types to do it without globals. The globals way (the easy way) is simply:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"const MyA = zeros(N, N)\nconst AMx = zeros(N, N)\nconst DA = zeros(N, N)\nfunction f(du, u, p, t)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n mul!(MyA, My, A)\n mul!(AMx, A, Mx)\n @. DA = D * (MyA + AMx)\n @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"For reference, closures looks like:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"MyA = zeros(N, N)\nAMx = zeros(N, N)\nDA = zeros(N, N)\nfunction f_full(du, u, p, t, MyA, AMx, DA)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n mul!(MyA, My, A)\n mul!(AMx, A, Mx)\n @. DA = D * (MyA + AMx)\n @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend\nf(du, u, p, t) = f_full(du, u, p, t, MyA, AMx, DA)","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"and a call overloaded type looks like:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"struct MyFunction{T} <: Function\n MyA::T\n AMx::T\n DA::T\nend\n\n# Now define the overload\nfunction (ff::MyFunction)(du, u, p, t)\n # This is a function which references itself via ff\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n mul!(ff.MyA, My, A)\n mul!(ff.AMx, A, Mx)\n @. ff.DA = D * (ff.MyA + ff.AMx)\n @. dA = f.DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend\n\nMyA = zeros(N, N)\nAMx = zeros(N, N)\nDA = zeros(N, N)\n\nf = MyFunction(MyA, AMx, DA)\n# Now f(du,u,p,t) is our function!","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"These last two ways enclose the pointer to our cache arrays locally but still present a function f(du,u,p,t) to the ODE solver.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Now, since PDEs are large, many times we don't care about getting the whole timeseries. Using the output controls from DifferentialEquations.jl, we can make it only output the final timepoint.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"prob = ODEProblem(f, u0, (0.0, 100.0))\n@time sol = solve(prob, ROCK2(), progress = true, save_everystep = false,\n save_start = false);\n@time sol = solve(prob, ROCK2(), progress = true, save_everystep = false,\n save_start = false);","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Around 0.4 seconds. Much better. Also, if you're using VS Code, this'll give you a nice progress bar, so you can track how it's going.","category":"page"},{"location":"showcase/gpu_spde/#Quick-Note-About-Performance","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Quick Note About Performance","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"note: Note\nWe are using the ROCK2 method here because it's a method for stiff equations with eigenvalues that are real-dominated (as opposed to dominated by the imaginary parts). If we wanted to use a more conventional implicit ODE solver, we would need to make use of the sparsity pattern. This is covered in the advanced ODE tutorial It turns out that ROCK2 is more efficient anyway (and doesn't require sparsity handling), so we will keep this setup.","category":"page"},{"location":"showcase/gpu_spde/#Quick-Summary:-full-PDE-ODE-Code","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Quick Summary: full PDE ODE Code","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"As a summary, here's a full PDE code:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using OrdinaryDiffEq, LinearAlgebra\n\n# Define the constants for the PDE\nconst α₂ = 1.0\nconst α₃ = 1.0\nconst β₁ = 1.0\nconst β₂ = 1.0\nconst β₃ = 1.0\nconst r₁ = 1.0\nconst r₂ = 1.0\nconst D = 100.0\nconst γ₁ = 0.1\nconst γ₂ = 0.1\nconst γ₃ = 0.1\nconst N = 100\nconst X = reshape([i for i in 1:100 for j in 1:100], N, N)\nconst Y = reshape([j for i in 1:100 for j in 1:100], N, N)\nconst α₁ = 1.0 .* (X .>= 80)\n\nconst Mx = Array(Tridiagonal([1.0 for i in 1:(N - 1)], [-2.0 for i in 1:N],\n [1.0 for i in 1:(N - 1)]))\nconst My = copy(Mx)\nMx[2, 1] = 2.0\nMx[end - 1, end] = 2.0\nMy[1, 2] = 2.0\nMy[end, end - 1] = 2.0\n\n# Define the initial condition as normal arrays\nu0 = zeros(N, N, 3)\n\nconst MyA = zeros(N, N);\nconst AMx = zeros(N, N);\nconst DA = zeros(N, N)\n# Define the discretized PDE as an ODE function\nfunction f(du, u, p, t)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n mul!(MyA, My, A)\n mul!(AMx, A, Mx)\n @. DA = D * (MyA + AMx)\n @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend\n\n# Solve the ODE\nprob = ODEProblem(f, u0, (0.0, 100.0))\nsol = solve(prob, ROCK2(), progress = true, save_everystep = false, save_start = false)\n\nusing Plots;\ngr();\np1 = surface(X, Y, sol[end][:, :, 1], title = \"[A]\")\np2 = surface(X, Y, sol[end][:, :, 2], title = \"[B]\")\np3 = surface(X, Y, sol[end][:, :, 3], title = \"[C]\")\nplot(p1, p2, p3, layout = grid(3, 1))","category":"page"},{"location":"showcase/gpu_spde/#Making-Use-of-GPU-Parallelism","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"Making Use of GPU Parallelism","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"That was all using the CPU. How do we turn on GPU parallelism with DifferentialEquations.jl? Well, you don't. DifferentialEquations.jl \"doesn't have GPU bits\". So, wait... can we not do GPU parallelism? No, this is the glory of type-genericness, especially in broadcasted operations. To make things use the GPU, we simply use a CuArray from CUDA.jl. If instead of zeros(N,M) we used CuArray(zeros(N,M)), then the array lives on the GPU. CuArray naturally overrides broadcast such that dotted operations are performed on the GPU. DifferentialEquations.jl uses broadcast internally, and thus just by putting the array as a CuArray, the array-type will take over how all internal updates are performed and turn this algorithm into a fully GPU-parallelized algorithm that doesn't require copying to the CPU. Wasn't that simple?","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"From that you can probably also see how to multithread everything, or how to set everything up with distributed parallelism. You can make the ODE solvers do whatever you want by defining an array type where the broadcast does whatever special behavior you want.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"So to recap, the entire difference from above is changing to:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using CUDA\nconst gMx = CuArray(Float32.(Mx))\nconst gMy = CuArray(Float32.(My))\nconst gα₁ = CuArray(Float32.(α₁))\ngu0 = CuArray(Float32.(u0))\n\nconst gMyA = CuArray(zeros(Float32, N, N))\nconst AgMx = CuArray(zeros(Float32, N, N))\nconst gDA = CuArray(zeros(Float32, N, N))\nfunction gf(du, u, p, t)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n mul!(gMyA, gMy, A)\n mul!(AgMx, A, gMx)\n @. gDA = D * (gMyA + AgMx)\n @. dA = gDA + gα₁ - β₁ * A - r₁ * A * B + r₂ * C\n @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C\n @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C\nend\n\nprob2 = ODEProblem(gf, gu0, (0.0, 100.0))\nCUDA.allowscalar(false) # makes sure none of the slow fallbacks are used\n@time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false,\n save_start = false);","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"@time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false,\n save_start = false);","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Go have fun.","category":"page"},{"location":"showcase/gpu_spde/#And-Stochastic-PDEs?","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"And Stochastic PDEs?","text":"","category":"section"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Why not make it an SPDE? All that we need to do is extend each of the PDE equations to have a noise function. In this case, let's use multiplicative noise on each reactant. This means that our noise update equation is:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"function g(du, u, p, t)\n A = @view u[:, :, 1]\n B = @view u[:, :, 2]\n C = @view u[:, :, 3]\n dA = @view du[:, :, 1]\n dB = @view du[:, :, 2]\n dC = @view du[:, :, 3]\n @. dA = γ₁ * A\n @. dB = γ₂ * A\n @. dC = γ₃ * A\nend","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"Now we just define and solve the system of SDEs:","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"prob = SDEProblem(f, g, u0, (0.0, 100.0))\n@time sol = solve(prob, SRIW1());","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"using Plots;\ngr();\n\n# Use `Array` to transform the result back into a CPU-based `Array` for plotting\np1 = surface(X, Y, Array(sol[end][:, :, 1]), title = \"[A]\")\np2 = surface(X, Y, Array(sol[end][:, :, 2]), title = \"[B]\")\np3 = surface(X, Y, Array(sol[end][:, :, 3]), title = \"[C]\")\nplot(p1, p2, p3, layout = grid(3, 1))","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"We can see the cool effect that diffusion dampens the noise in [A] but is unable to dampen the noise in [B] which results in a very noisy [C]. The stiff SPDE takes much longer to solve even using high order plus adaptivity because stochastic problems are just that much more difficult (current research topic is to make new algorithms for this!). It gets GPU'd just by using CuArray like before. But there we go: solving systems of stochastic PDEs using high order adaptive algorithms with within-method GPU parallelism. That's gotta be a first? The cool thing is that nobody ever had to implement the GPU-parallelism either, it just exists by virtue of the Julia type system.","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"(Note: We can also use one of the SROCK methods for better performance here, but they will require a choice of dt. This is left to the reader to try.)","category":"page"},{"location":"showcase/gpu_spde/","page":"GPU-Accelerated Stochastic Partial Differential Equations","title":"GPU-Accelerated Stochastic Partial Differential Equations","text":"note: Note\nThis can take a while to solve! An explicit Runge-Kutta algorithm isn't necessarily great here, though to use a stiff solver on a problem of this size requires once again smartly choosing sparse linear solvers. The high order adaptive method is pretty much necessary though, since something like Euler-Maruyama is simply not stable enough to solve this at a reasonable dt. Also, the current algorithms are not so great at handling this problem. Good thing there's a publication coming along with some new stuff...","category":"page"},{"location":"showcase/bayesian_neural_ode/#bnode","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"In this tutorial, we show how SciML can combine the differential equation solvers seamlessly with Bayesian estimation libraries like AdvancedHMC.jl and Turing.jl. This enables converting Neural ODEs to Bayesian Neural ODEs, which enables us to estimate the error in the Neural ODE estimation and forecasting. In this tutorial, a working example of the Bayesian Neural ODE: NUTS sampler is shown.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"note: Note\nFor more details, have a look at this paper: https://arxiv.org/abs/2012.07244","category":"page"},{"location":"showcase/bayesian_neural_ode/#Step-1:-Import-Libraries","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Step 1: Import Libraries","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"For this example, we will need the following libraries:","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"# SciML Libraries\nusing SciMLSensitivity, DifferentialEquations\n\n# ML Tools\nusing Lux, Zygote\n\n# External Tools\nusing Random, Plots, AdvancedHMC, MCMCChains, StatsPlots, ComponentArrays","category":"page"},{"location":"showcase/bayesian_neural_ode/#Setup:-Get-the-data-from-the-Spiral-ODE-example","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Setup: Get the data from the Spiral ODE example","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"We will also need data to fit against. As a demonstration, we will generate our data using a simple cubic ODE u' = A*u^3 as follows:","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"u0 = [2.0; 0.0]\ndatasize = 40\ntspan = (0.0, 1)\ntsteps = range(tspan[1], tspan[2], length = datasize)\nfunction trueODEfunc(du, u, p, t)\n true_A = [-0.1 2.0; -2.0 -0.1]\n du .= ((u .^ 3)'true_A)'\nend\nprob_trueode = ODEProblem(trueODEfunc, u0, tspan)\node_data = Array(solve(prob_trueode, Tsit5(), saveat = tsteps))","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"We will want to train a neural network to capture the dynamics that fit ode_data.","category":"page"},{"location":"showcase/bayesian_neural_ode/#Step-2:-Define-the-Neural-ODE-architecture.","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Step 2: Define the Neural ODE architecture.","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"Note that this step potentially offers a lot of flexibility in the number of layers/ number of units in each layer. It may not necessarily be true that a 100 units architecture is better at prediction/forecasting than a 50 unit architecture. On the other hand, a complicated architecture can take a huge computational time without increasing performance.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"dudt2 = Lux.Chain(x -> x .^ 3,\n Lux.Dense(2, 50, tanh),\n Lux.Dense(50, 2))\n\nrng = Random.default_rng()\np, st = Lux.setup(rng, dudt2)\nconst _st = st\nfunction neuralodefunc(u, p, t)\n dudt2(u, p, _st)[1]\nend\nfunction prob_neuralode(u0, p)\n prob = ODEProblem(neuralodefunc, u0, tspan, p)\n sol = solve(prob, Tsit5(), saveat = tsteps)\nend\np = ComponentArray{Float64}(p)\nconst _p = p","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"Note that the f64 is required to put the Lux neural network into Float64 precision.","category":"page"},{"location":"showcase/bayesian_neural_ode/#Step-3:-Define-the-loss-function-for-the-Neural-ODE.","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Step 3: Define the loss function for the Neural ODE.","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"function predict_neuralode(p)\n p = p isa ComponentArray ? p : convert(typeof(_p),p)\n Array(prob_neuralode(u0, p))\nend\nfunction loss_neuralode(p)\n pred = predict_neuralode(p)\n loss = sum(abs2, ode_data .- pred)\n return loss, pred\nend","category":"page"},{"location":"showcase/bayesian_neural_ode/#Step-4:-Now-we-start-integrating-the-Bayesian-estimation-workflow-as-prescribed-by-the-AdvancedHMC-interface-with-the-NeuralODE-defined-above","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Step 4: Now we start integrating the Bayesian estimation workflow as prescribed by the AdvancedHMC interface with the NeuralODE defined above","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"The AdvancedHMC interface requires us to specify: (a) the Hamiltonian log density and its gradient , (b) the sampler and (c) the step size adaptor function.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"For the Hamiltonian log density, we use the loss function. The θ*θ term denotes the use of Gaussian priors.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"The user can make several modifications to Step 4. The user can try different acceptance ratios, warmup samples and posterior samples. One can also use the Variational Inference (ADVI) framework, which doesn't work quite as well as NUTS. The SGLD (Stochastic Gradient Langevin Descent) sampler is seen to have a better performance than NUTS. Have a look at https://sebastiancallh.github.io/post/langevin/ for a brief introduction to SGLD.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"l(θ) = -sum(abs2, ode_data .- predict_neuralode(θ)) - sum(θ .* θ)\nfunction dldθ(θ)\n x, lambda = Zygote.pullback(l, θ)\n grad = first(lambda(1))\n return x, grad\nend\n\nmetric = DiagEuclideanMetric(length(p))\nh = Hamiltonian(metric, l, dldθ)","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"We use the NUTS sampler with an acceptance ratio of δ= 0.45 in this example. In addition, we use Nesterov Dual Averaging for the Step Size adaptation.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"We sample using 500 warmup samples and 500 posterior samples.","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"integrator = Leapfrog(find_good_stepsize(h, p))\nkernel = HMCKernel(Trajectory{MultinomialTS}(integrator, GeneralisedNoUTurn()))\nadaptor = StanHMCAdaptor(MassMatrixAdaptor(metric), StepSizeAdaptor(0.45, integrator))\nsamples, stats = sample(h, kernel, p, 500, adaptor, 500; progress = true)","category":"page"},{"location":"showcase/bayesian_neural_ode/#Step-5:-Plot-diagnostics","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Step 5: Plot diagnostics","text":"","category":"section"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"Now let's make sure the fit is good. This can be done by looking at the chain mixing plot and the autocorrelation plot. First, let's create the chain mixing plot using the plot recipes from ????","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"samples = hcat(samples...)\nsamples_reduced = samples[1:5, :]\nsamples_reshape = reshape(samples_reduced, (500, 5, 1))\nChain_Spiral = Chains(samples_reshape)\nplot(Chain_Spiral)","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"Now we check the autocorrelation plot:","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"autocorplot(Chain_Spiral)","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"As another diagnostic, let's check the result on retrodicted data. To do this, we generate solutions of the Neural ODE on samples of the neural network parameters, and check the results of the predictions against the data. Let's start by looking at the time series:","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"pl = scatter(tsteps, ode_data[1, :], color = :red, label = \"Data: Var1\", xlabel = \"t\",\n title = \"Spiral Neural ODE\")\nscatter!(tsteps, ode_data[2, :], color = :blue, label = \"Data: Var2\")\nfor k in 1:300\n resol = predict_neuralode(samples[:, 100:end][:, rand(1:400)])\n plot!(tsteps, resol[1, :], alpha = 0.04, color = :red, label = \"\")\n plot!(tsteps, resol[2, :], alpha = 0.04, color = :blue, label = \"\")\nend\n\nlosses = map(x -> loss_neuralode(x)[1], eachcol(samples))\nidx = findmin(losses)[2]\nprediction = predict_neuralode(samples[:, idx])\nplot!(tsteps, prediction[1, :], color = :black, w = 2, label = \"\")\nplot!(tsteps, prediction[2, :], color = :black, w = 2, label = \"Best fit prediction\",\n ylims = (-2.5, 3.5))","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"That showed the time series form. We can similarly do a phase-space plot:","category":"page"},{"location":"showcase/bayesian_neural_ode/","page":"Uncertainty Quantified Deep Bayesian Model Discovery","title":"Uncertainty Quantified Deep Bayesian Model Discovery","text":"pl = scatter(ode_data[1, :], ode_data[2, :], color = :red, label = \"Data\", xlabel = \"Var1\",\n ylabel = \"Var2\", title = \"Spiral Neural ODE\")\nfor k in 1:300\n resol = predict_neuralode(samples[:, 100:end][:, rand(1:400)])\n plot!(resol[1, :], resol[2, :], alpha = 0.04, color = :red, label = \"\")\nend\nplot!(prediction[1, :], prediction[2, :], color = :black, w = 2,\n label = \"Best fit prediction\", ylims = (-2.5, 3))","category":"page"},{"location":"overview/#overview","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"","category":"section"},{"location":"overview/#SciML:-Combining-High-Performance-Scientific-Computing-and-Machine-Learning","page":"Detailed Overview of the SciML Software Ecosystem","title":"SciML: Combining High-Performance Scientific Computing and Machine Learning","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"SciML is not standard machine learning, SciML is the combination of scientific computing techniques with machine learning. Thus the SciML organization is not an organization for machine learning libraries (see FluxML for machine learning in Julia), rather SciML is an organization dedicated to the development of scientific computing tools which work seamlessly in conjunction with next-generation machine learning workflows. This includes:","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"High-performance and accurate tools for standard scientific computing modeling and simulation\nCompatibility with differentiable programming and automatic differentiation\nTools for building complex multiscale models\nMethods for handling inverse problems, model calibration, controls, and Bayesian analysis\nSymbolic modeling tools for generating efficient code for numerical equation solvers\nMethods for automatic discovery of (bio)physical equations","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"and much more. For an overview of the broad goals of the SciML organization, watch:","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The Use and Practice of Scientific Machine Learning\nState of SciML Scientific Machine Learning","category":"page"},{"location":"overview/#Overview-of-Computational-Science-in-Julia-with-SciML","page":"Detailed Overview of the SciML Software Ecosystem","title":"Overview of Computational Science in Julia with SciML","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"Below is a simplification of the user-facing packages for use in scientific computing and SciML workflows.","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"Workflow Element SciML-Supported Julia packages\nPlotting and Visualization Plots*, Makie*\nSparse matrix SparseArrays*\nInterpolation/approximation DataInterpolations*, ApproxFun*\nLinear system / least squares LinearSolve\nNonlinear system / rootfinding NonlinearSolve\nPolynomial roots Polynomials*\nIntegration Integrals\nNonlinear Optimization Optimization\nOther Optimization (linear, quadratic, convex, etc.) JuMP*\nInitial-value problem DifferentialEquations\nBoundary-value problem DifferentialEquations\nContinuous-Time Markov Chains (Poisson Jumps), Jump Diffusions JumpProcesses\nFinite differences FiniteDifferences*, FiniteDiff*\nAutomatic Differentiation ForwardDiff*, Enzyme*, DiffEqSensitivity\nBayesian Modeling Turing*\nDeep Learning Flux*\nAcausal Modeling / DAEs ModelingToolkit\nChemical Reaction Networks Catalyst\nSymbolic Computing Symbolics\nFast Fourier Transform FFTW*\nPartial Differential Equation Discretizations Associated Julia packages\n–- –-\nFinite Differences MethodOfLines\nDiscontinuous Galerkin Trixi*\nFinite Element Gridap*\nPhysics-Informed Neural Networks NeuralPDE\nNeural Operators NeuralOperators\nHigh Dimensional Deep Learning HighDimPDE","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"* Denotes a non-SciML package that is heavily tested against as part of SciML workflows and has frequent collaboration with the SciML developers.","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"(Image: SciML Mind Map)","category":"page"},{"location":"overview/#Domains-of-SciML","page":"Detailed Overview of the SciML Software Ecosystem","title":"Domains of SciML","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The SciML common interface covers the following domains:","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"Linear systems (LinearProblem)\nDirect methods for dense and sparse\nIterative solvers with preconditioning\nNonlinear Systems (NonlinearProblem)\nSystems of nonlinear equations\nScalar bracketing systems\nIntegrals (quadrature) (IntegralProblem)\nDifferential Equations\nDiscrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem and JumpProblem)\nOrdinary differential equations (ODEs) (ODEProblem)\nSplit and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)\nStochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)\nStochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)\nRandom differential equations (RODEs or RDEs) (RODEProblem)\nDifferential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)\nDelay differential equations (DDEs) (DDEProblem)\nNeutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)\nStochastic delay differential equations (SDDEs) (SDDEProblem)\nExperimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)\nMixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)\nOptimization (OptimizationProblem)\nNonlinear (constrained) optimization\n(Stochastic/Delay/Differential-Algebraic) Partial Differential Equations (PDESystem)\nFinite difference and finite volume methods\nInterfaces to finite element methods\nPhysics-Informed Neural Networks (PINNs)\nIntegro-Differential Equations\nFractional Differential Equations\nSpecialized Forms\nPartial Integro-Differential Equations (PIPDEProblem)\nData-driven modeling\nDiscrete-time data-driven dynamical systems (DiscreteDataDrivenProblem)\nContinuous-time data-driven dynamical systems (ContinuousDataDrivenProblem)\nSymbolic regression (DirectDataDrivenProblem)\nUncertainty quantification and expected values (ExpectationProblem)","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The SciML common interface also includes ModelingToolkit.jl for defining such systems symbolically, allowing for optimizations like automated generation of parallel code, symbolic simplification, and generation of sparsity patterns.","category":"page"},{"location":"overview/#Inverse-Problems,-Parameter-Estimation,-and-Structural-Identification","page":"Detailed Overview of the SciML Software Ecosystem","title":"Inverse Problems, Parameter Estimation, and Structural Identification","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"Parameter estimation and inverse problems are solved directly on their constituent problem types using tools like SciMLSensitivity.jl. Thus for example, there is no ODEInverseProblem, and instead ODEProblem is used to find the parameters p that solve the inverse problem. Check out the SciMLSensitivity documentation for a discussion on connections to automatic differentiation, optimization, and adjoints.","category":"page"},{"location":"overview/#Common-Interface-High-Level-Overview","page":"Detailed Overview of the SciML Software Ecosystem","title":"Common Interface High-Level Overview","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The SciML interface is common as the usage of arguments is standardized across all of the problem domains. Underlying high-level ideas include:","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"All domains use the same interface of defining a AbstractSciMLProblem which is then solved via solve(prob,alg;kwargs), where alg is a AbstractSciMLAlgorithm. The keyword argument namings are standardized across the organization.\nAbstractSciMLProblems are generally defined by a AbstractSciMLFunction which can define extra details about a model function, such as its analytical Jacobian, its sparsity patterns and so on.\nThere is an organization-wide method for defining linear and nonlinear solvers used within other solvers, giving maximum control of performance to the user.\nTypes used within the packages are defined by the input types. For example, packages attempt to internally use the type of the initial condition as the type for the state within differential equation solvers.\nsolve calls should be thread-safe and parallel-safe.\ninit(prob,alg;kwargs) returns an iterator which allows for directly iterating over the solution process\nHigh performance is key. Any performance that is not at the top level is considered a bug and should be reported as such.\nAll functions have an in-place and out-of-place form, where the in-place form is made to utilize mutation for high performance on large-scale problems and the out-of-place form is for compatibility with tooling like static arrays and some reverse-mode automatic differentiation systems.","category":"page"},{"location":"overview/#Flowchart-Example-for-PDE-Constrained-Optimal-Control","page":"Detailed Overview of the SciML Software Ecosystem","title":"Flowchart Example for PDE-Constrained Optimal Control","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The following example showcases how the pieces of the common interface connect to solve a problem that mixes inference, symbolics, and numerics.","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"(Image: )","category":"page"},{"location":"overview/#External-Binding-Libraries","page":"Detailed Overview of the SciML Software Ecosystem","title":"External Binding Libraries","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"diffeqr\nSolving differential equations in R using DifferentialEquations.jl with ModelingToolkit for JIT compilation and GPU-acceleration\ndiffeqpy\nSolving differential equations in Python using DifferentialEquations.jl","category":"page"},{"location":"overview/#Note-About-Third-Party-Libraries","page":"Detailed Overview of the SciML Software Ecosystem","title":"Note About Third-Party Libraries","text":"","category":"section"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"The SciML documentation references and recommends many third-party libraries for improving ones modeling, simulation, and analysis workflow in Julia. Take these as a positive affirmation of the quality of these libraries, as these libraries are commonly tested by SciML developers who are in contact with the development teams of these groups. It also documents the libraries which are commonly chosen by SciML as dependencies. Do not take omissions as negative affirmations against a given library, i.e. a library left off of the list by SciML is not a negative endorsement. Rather, it means that compatibility with SciML is untested, SciML developers may have a personal preference for another choice, or SciML developers may be simply unaware of the library's existence. If one would like to add a third-party library to the SciML documentation, open a pull request with the requested text.","category":"page"},{"location":"overview/","page":"Detailed Overview of the SciML Software Ecosystem","title":"Detailed Overview of the SciML Software Ecosystem","text":"Note that the libraries in this documentation are only those that are meant to be used in the SciML extended universe of modeling, simulation, and analysis and thus there are many high-quality libraries in other domains (machine learning, data science, etc.) which are purposefully not included. For an overview of the Julia package ecosystem, see the JuliaHub Search Engine.","category":"page"},{"location":"highlevels/symbolic_tools/#Symbolic-Model-Tooling-and-JuliaSymbolics","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"","category":"section"},{"location":"highlevels/symbolic_tools/","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"JuliaSymbolics is a sister organization of SciML. It spawned out of the symbolic modeling tools being developed within SciML (ModelingToolkit.jl) to become its own organization dedicated to building a fully-featured Julia-based Computer Algebra System (CAS). As such, the two organizations are closely aligned in terms of its developer community, and many of the SciML libraries use Symbolics.jl extensively.","category":"page"},{"location":"highlevels/symbolic_tools/#ModelOrderReduction.jl:-Automated-Model-Reduction-for-Fast-Approximations-of-Solutions","page":"Symbolic Model Tooling and JuliaSymbolics","title":"ModelOrderReduction.jl: Automated Model Reduction for Fast Approximations of Solutions","text":"","category":"section"},{"location":"highlevels/symbolic_tools/","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"ModelOrderReduction.jl is a package for automating the reduction of models. These methods function a submodel with a projection, where solving the smaller model provides approximation information about the full model. MOR.jl uses ModelingToolkit.jl as a system description and automatically transforms equations to the subform, defining the observables to automatically lazily reconstruct the full model on-demand in a fast and stable form.","category":"page"},{"location":"highlevels/symbolic_tools/#Symbolics.jl:-The-Computer-Algebra-System-(CAS)-of-the-Julia-Programming-Language","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolics.jl: The Computer Algebra System (CAS) of the Julia Programming Language","text":"","category":"section"},{"location":"highlevels/symbolic_tools/","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"Symbolics.jl is the CAS of the Julia programming language. If something needs to be done symbolically, most likely Symbolics.jl is the answer.","category":"page"},{"location":"highlevels/symbolic_tools/#MetaTheory.jl:-E-Graphs-to-Automate-Symbolic-Transformations","page":"Symbolic Model Tooling and JuliaSymbolics","title":"MetaTheory.jl: E-Graphs to Automate Symbolic Transformations","text":"","category":"section"},{"location":"highlevels/symbolic_tools/","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"Metatheory.jl is a library for defining e-graph rewriters for use on the common symbolic interface. This can be used to do all sorts of analysis and code transformations, such as improving code performance, numerical stability, and more. See Automated Code Optimization with E-Graphs for more details.","category":"page"},{"location":"highlevels/symbolic_tools/#SymbolicUtils.jl:-Define-Your-Own-Computer-Algebra-System","page":"Symbolic Model Tooling and JuliaSymbolics","title":"SymbolicUtils.jl: Define Your Own Computer Algebra System","text":"","category":"section"},{"location":"highlevels/symbolic_tools/","page":"Symbolic Model Tooling and JuliaSymbolics","title":"Symbolic Model Tooling and JuliaSymbolics","text":"SymbolicUtils.jl is the underlying utility library and rule-based rewriting language on which Symbolics.jl is developed. Symbolics.jl is standardized type and rule definitions built using SymbolicUtils.jl. However, if non-standard types are required, such as symbolic computing over Fock algebras, then SymbolicUtils.jl is the library from which the new symbolic types can be implemented.","category":"page"},{"location":"#SciML:-Differentiable-Modeling-and-Simulation-Combined-with-Machine-Learning","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Differentiable Modeling and Simulation Combined with Machine Learning","text":"","category":"section"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"The SciML organization is a collection of tools for solving equations and modeling systems developed in the Julia programming language with bindings to other languages such as R and Python. The organization provides well-maintained tools which compose together as a coherent ecosystem. It has a coherent development principle, unified APIs over large collections of equation solvers, pervasive differentiability and sensitivity analysis, and features many of the highest performance and parallel implementations one can find.","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"Scientific Machine Learning (SciML) = Scientific Computing + Machine Learning","category":"page"},{"location":"#Where-to-Start?","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"Where to Start?","text":"","category":"section"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"Want to get started running some code? Check out the Getting Started tutorials.\nWhat is SciML? Check out our Overview.\nWant to see some cool end-to-end examples? Check out the SciML Showcase.\nCurious about our performance claims? Check out the SciML Open Benchmarks.\nWant to learn more about how SciML does scientific machine learning? Check out the SciML Book (from MIT's 18.337 graduate course).\nWant to chat with someone? Check out our chat room and forums.\nWant to see our code? Check out the SciML GitHub organization.","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"And for diving into the details, use the bar on the top to navigate to the submodule of interest!","category":"page"},{"location":"#Reproducibility","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"Reproducibility","text":"","category":"section"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
The documentation of the [SciML Showcase](@ref showcase) was built using these direct dependencies,","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"using Pkg # hide\nPkg.status() # hide","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
and using this machine and Julia version.","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"using InteractiveUtils # hide\nversioninfo() # hide","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
A more complete overview of all dependencies and their versions is also provided.","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"using Pkg # hide\nPkg.status(; mode = PKGMODE_MANIFEST) # hide","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"
","category":"page"},{"location":"","page":"SciML: Open Source Software for Scientific Machine Learning with Julia","title":"SciML: Open Source Software for Scientific Machine Learning with Julia","text":"using TOML\nusing Markdown\nversion = TOML.parse(read(\"../../Project.toml\", String))[\"version\"]\nname = TOML.parse(read(\"../../Project.toml\", String))[\"name\"]\nlink_manifest = \"https://github.com/SciML/\" * name * \".jl/tree/gh-pages/v\" * version *\n \"/assets/Manifest.toml\"\nlink_project = \"https://github.com/SciML/\" * name * \".jl/tree/gh-pages/v\" * version *\n \"/assets/Project.toml\"\nMarkdown.parse(\"\"\"You can also download the\n[manifest]($link_manifest)\nfile and the\n[project]($link_project)\nfile.\n\"\"\")","category":"page"}] +} diff --git a/v1.5.0/showcase/bayesian_neural_ode/2117136c.svg b/v1.5.0/showcase/bayesian_neural_ode/2117136c.svg new file mode 100644 index 00000000000..4259c42c42e --- /dev/null +++ b/v1.5.0/showcase/bayesian_neural_ode/2117136c.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/bayesian_neural_ode/9b2a29b1.svg b/v1.5.0/showcase/bayesian_neural_ode/9b2a29b1.svg new file mode 100644 index 00000000000..a000a3223a5 --- /dev/null +++ b/v1.5.0/showcase/bayesian_neural_ode/9b2a29b1.svg @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/bayesian_neural_ode/f47df3bc.svg b/v1.5.0/showcase/bayesian_neural_ode/f47df3bc.svg new file mode 100644 index 00000000000..38757462ee7 --- /dev/null +++ b/v1.5.0/showcase/bayesian_neural_ode/f47df3bc.svg @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/bayesian_neural_ode/faab785d.svg b/v1.5.0/showcase/bayesian_neural_ode/faab785d.svg new file mode 100644 index 00000000000..88364add1a1 --- /dev/null +++ b/v1.5.0/showcase/bayesian_neural_ode/faab785d.svg @@ -0,0 +1,389 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/bayesian_neural_ode/index.html b/v1.5.0/showcase/bayesian_neural_ode/index.html new file mode 100644 index 00000000000..37685343922 --- /dev/null +++ b/v1.5.0/showcase/bayesian_neural_ode/index.html @@ -0,0 +1,79 @@ + +Uncertainty Quantified Deep Bayesian Model Discovery · Overview of Julia's SciML

Uncertainty Quantified Deep Bayesian Model Discovery

In this tutorial, we show how SciML can combine the differential equation solvers seamlessly with Bayesian estimation libraries like AdvancedHMC.jl and Turing.jl. This enables converting Neural ODEs to Bayesian Neural ODEs, which enables us to estimate the error in the Neural ODE estimation and forecasting. In this tutorial, a working example of the Bayesian Neural ODE: NUTS sampler is shown.

Note

For more details, have a look at this paper: https://arxiv.org/abs/2012.07244

Step 1: Import Libraries

For this example, we will need the following libraries:

# SciML Libraries
+using SciMLSensitivity, DifferentialEquations
+
+# ML Tools
+using Lux, Zygote
+
+# External Tools
+using Random, Plots, AdvancedHMC, MCMCChains, StatsPlots, ComponentArrays

Setup: Get the data from the Spiral ODE example

We will also need data to fit against. As a demonstration, we will generate our data using a simple cubic ODE u' = A*u^3 as follows:

u0 = [2.0; 0.0]
+datasize = 40
+tspan = (0.0, 1)
+tsteps = range(tspan[1], tspan[2], length = datasize)
+function trueODEfunc(du, u, p, t)
+    true_A = [-0.1 2.0; -2.0 -0.1]
+    du .= ((u .^ 3)'true_A)'
+end
+prob_trueode = ODEProblem(trueODEfunc, u0, tspan)
+ode_data = Array(solve(prob_trueode, Tsit5(), saveat = tsteps))
2×40 Matrix{Float64}:
+ 2.0  1.97895   1.94728  1.87998  1.74775  …   0.353996   0.53937   0.718119
+ 0.0  0.403905  0.79233  1.15176  1.45561     -1.54217   -1.52816  -1.50614

We will want to train a neural network to capture the dynamics that fit ode_data.

Step 2: Define the Neural ODE architecture.

Note that this step potentially offers a lot of flexibility in the number of layers/ number of units in each layer. It may not necessarily be true that a 100 units architecture is better at prediction/forecasting than a 50 unit architecture. On the other hand, a complicated architecture can take a huge computational time without increasing performance.

dudt2 = Lux.Chain(x -> x .^ 3,
+                   Lux.Dense(2, 50, tanh),
+                   Lux.Dense(50, 2))
+
+rng = Random.default_rng()
+p, st = Lux.setup(rng, dudt2)
+const _st = st
+function neuralodefunc(u, p, t)
+    dudt2(u, p, _st)[1]
+end
+function prob_neuralode(u0, p)
+    prob = ODEProblem(neuralodefunc, u0, tspan, p)
+    sol = solve(prob, Tsit5(), saveat = tsteps)
+end
+p = ComponentArray{Float64}(p)
+const _p = p
ComponentVector{Float64}(layer_1 = Float64[], layer_2 = (weight = [-0.20307107269763947 0.044236913323402405; -0.027195153757929802 -0.15686018764972687; … ; -0.2863834500312805 0.180319145321846; 0.31368470191955566 -0.2432122528553009], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.2406693398952484 -0.09549214690923691 … -0.2698048949241638 -0.23320163786411285; 0.277680903673172 0.07772684842348099 … -0.011612651869654655 -0.0016880881739780307], bias = [0.0; 0.0;;]))

Note that the f64 is required to put the Lux neural network into Float64 precision.

Step 3: Define the loss function for the Neural ODE.

function predict_neuralode(p)
+    p = p isa ComponentArray ? p : convert(typeof(_p),p)
+    Array(prob_neuralode(u0, p))
+end
+function loss_neuralode(p)
+    pred = predict_neuralode(p)
+    loss = sum(abs2, ode_data .- pred)
+    return loss, pred
+end
loss_neuralode (generic function with 1 method)

Step 4: Now we start integrating the Bayesian estimation workflow as prescribed by the AdvancedHMC interface with the NeuralODE defined above

The AdvancedHMC interface requires us to specify: (a) the Hamiltonian log density and its gradient , (b) the sampler and (c) the step size adaptor function.

For the Hamiltonian log density, we use the loss function. The θ*θ term denotes the use of Gaussian priors.

The user can make several modifications to Step 4. The user can try different acceptance ratios, warmup samples and posterior samples. One can also use the Variational Inference (ADVI) framework, which doesn't work quite as well as NUTS. The SGLD (Stochastic Gradient Langevin Descent) sampler is seen to have a better performance than NUTS. Have a look at https://sebastiancallh.github.io/post/langevin/ for a brief introduction to SGLD.

l(θ) = -sum(abs2, ode_data .- predict_neuralode(θ)) - sum(θ .* θ)
+function dldθ(θ)
+    x, lambda = Zygote.pullback(l, θ)
+    grad = first(lambda(1))
+    return x, grad
+end
+
+metric = DiagEuclideanMetric(length(p))
+h = Hamiltonian(metric, l, dldθ)
Hamiltonian(metric=DiagEuclideanMetric([1.0, 1.0, 1.0, 1.0, 1.0, 1 ...]), kinetic=AdvancedHMC.GaussianKinetic())

We use the NUTS sampler with an acceptance ratio of δ= 0.45 in this example. In addition, we use Nesterov Dual Averaging for the Step Size adaptation.

We sample using 500 warmup samples and 500 posterior samples.

integrator = Leapfrog(find_good_stepsize(h, p))
+kernel = HMCKernel(Trajectory{MultinomialTS}(integrator, GeneralisedNoUTurn()))
+adaptor = StanHMCAdaptor(MassMatrixAdaptor(metric), StepSizeAdaptor(0.45, integrator))
+samples, stats = sample(h, kernel, p, 500, adaptor, 500; progress = true)
(ComponentArrays.ComponentVector{Float64, Vector{Float64}, Tuple{ComponentArrays.Axis{(layer_1 = 1:0, layer_2 = ViewAxis(1:150, Axis(weight = ViewAxis(1:100, ShapedAxis((50, 2))), bias = ViewAxis(101:150, ShapedAxis((50, 1))))), layer_3 = ViewAxis(151:252, Axis(weight = ViewAxis(1:100, ShapedAxis((2, 50))), bias = ViewAxis(101:102, ShapedAxis((2, 1))))))}}}[(layer_1 = Float64[], layer_2 = (weight = [-0.20558803512727428 0.06729991970798474; 0.008729782406658268 -0.16815402199198928; … ; -0.2461888027906331 0.1992363292273415; 0.32764019288044716 -0.21448583732392845], bias = [0.020849703027578416; -0.00045329358640152154; … ; 0.010833291230739209; -0.027858159736295313;;]), layer_3 = (weight = [0.26016738744659235 -0.12042955718879322 … -0.24501968006824007 -0.28236899497524204; 0.27514749071355793 0.113358946786598 … 0.0158481532839115 -0.008762154891745678], bias = [-0.002059204668859771; -0.03752433889216422;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.20558803512727428 0.06729991970798474; 0.008729782406658268 -0.16815402199198928; … ; -0.2461888027906331 0.1992363292273415; 0.32764019288044716 -0.21448583732392845], bias = [0.020849703027578416; -0.00045329358640152154; … ; 0.010833291230739209; -0.027858159736295313;;]), layer_3 = (weight = [0.26016738744659235 -0.12042955718879322 … -0.24501968006824007 -0.28236899497524204; 0.27514749071355793 0.113358946786598 … 0.0158481532839115 -0.008762154891745678], bias = [-0.002059204668859771; -0.03752433889216422;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.1815774153287812 0.2635220907222598; 0.02241052945610087 -0.025672729337625814; … ; -0.22520428349823185 0.21766997941500552; 0.7024060570738885 -0.08377803290930888], bias = [-0.35181978060389607; -0.24029310530936557; … ; 0.06010985612609526; 0.3571606276558311;;]), layer_3 = (weight = [1.0235532293282017 0.3914913481532246 … 0.11151095712675232 -0.6525668091094632; 0.4061896065772611 0.04645604043792934 … -0.19704024396199582 -0.04549670501446226], bias = [-0.6631159111105511; -0.08457571594172053;;])), (layer_1 = Float64[], layer_2 = (weight = [0.3167266709296577 0.048006173492643134; 0.3978520383456751 0.15796022515792368; … ; 0.05083031355427394 0.05002175357952356; 0.29807729228091273 0.2065982007748815], bias = [-0.8561072515578158; -0.6550859914911709; … ; -0.09892101836593799; 0.3184255589036596;;]), layer_3 = (weight = [0.19296241745102258 0.7456227206527936 … 0.5018495372054201 -0.5894802128204475; -0.14944142273926347 0.13561299174502428 … -0.30696759854613154 0.15939456644338565], bias = [-0.709584666549449; -0.30149392322400653;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.09860205441121497 -0.10535604440141183; 0.6547318771597813 -0.5536992616068077; … ; -0.7607214422336628 -0.7753536309789543; 1.0280317200678268 -0.1137309947801399], bias = [-0.8208923608300766; -0.6730100582058266; … ; -0.5861170427902823; -0.16610921737039205;;]), layer_3 = (weight = [-0.28079060736354106 -1.0228006223034796 … 0.42138009024189943 -1.3264114851187485; 0.25420877033618505 -0.4225032101251915 … -1.2632689499223473 0.6502756251179534], bias = [-0.8138970640412552; 0.8975238021423992;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.09860205441121497 -0.10535604440141183; 0.6547318771597813 -0.5536992616068077; … ; -0.7607214422336628 -0.7753536309789543; 1.0280317200678268 -0.1137309947801399], bias = [-0.8208923608300766; -0.6730100582058266; … ; -0.5861170427902823; -0.16610921737039205;;]), layer_3 = (weight = [-0.28079060736354106 -1.0228006223034796 … 0.42138009024189943 -1.3264114851187485; 0.25420877033618505 -0.4225032101251915 … -1.2632689499223473 0.6502756251179534], bias = [-0.8138970640412552; 0.8975238021423992;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.29217097592549346 0.970634979708838; -0.29521207266788463 -0.30391263148579617; … ; 0.26240314659984204 -0.5934519240943364; -0.4282173876160483 -0.41038964574023373], bias = [0.9291649586287324; 0.644995352138438; … ; 1.101251764962103; 0.02207076300291802;;]), layer_3 = (weight = [0.06372228524927419 1.3040612937578056 … -0.4939532818501008 1.7839944026807064; -0.3145645127089707 0.26268392057273093 … 1.1125337204801227 -0.09991376941380521], bias = [-0.21204945923792995; -0.894597452701255;;])), (layer_1 = Float64[], layer_2 = (weight = [0.9785647343473955 -0.14040118238407884; 1.4765638077463556 0.7143537146910997; … ; -0.31405487720768155 -0.4840490764889037; -0.5842010725387485 0.4095954441965731], bias = [-1.0850875708740264; -0.5403453782547046; … ; 0.031883860230217574; -1.1403604527640523;;]), layer_3 = (weight = [-0.374846584562504 0.35748995758265767 … 0.8020436397656808 0.04425333675954471; 1.253604487440019 1.1958340889104697 … -0.5775168474527459 -1.2833212542225592], bias = [-0.6311188677380993; 0.201730656683857;;])), (layer_1 = Float64[], layer_2 = (weight = [1.0484712051334917 -0.12333804313732974; 1.5254941177322499 0.7828948231478732; … ; -0.2907516567566175 -0.506171125983122; -0.6259925446095331 0.40366661273825327], bias = [-1.134327469770032; -0.5732780392814205; … ; -0.01775455917021252; -1.2239816689240122;;]), layer_3 = (weight = [-0.3788398423379815 0.2646376475640662 … 0.8995111735203097 -0.030536350932227882; 1.2923497041122625 1.1731479461869474 … -0.5993891563577416 -1.2937363807108735], bias = [-0.7158173432456373; 0.17837788865927132;;])), (layer_1 = Float64[], layer_2 = (weight = [0.5158450385986441 -0.06435527955787396; 0.6214533662748758 0.3138345373100536; … ; -0.43573737481241415 0.25996132046750814; -0.3776450295329728 -0.32015612230084656], bias = [-1.0266929939563858; 1.6322205459728258; … ; 0.4135856904509197; -0.5033147507897805;;]), layer_3 = (weight = [0.42243974357683756 -0.12193091309369088 … -0.20581315061612823 1.2804231929876768; 0.7636741771577187 -0.8850365774821684 … -0.39000887028195846 -1.634214600788479], bias = [-2.0072008205326326; 0.6812054804682616;;]))  …  (layer_1 = Float64[], layer_2 = (weight = [0.12913132090676094 0.22195279577053068; -0.5261629247881109 -0.5313527017568036; … ; 0.913257003823887 -0.3366035814709443; -0.6847439161057232 -0.039244441676086594], bias = [-0.39960319483617207; 0.04909583850431291; … ; -0.37001462147427744; -0.48014433947967844;;]), layer_3 = (weight = [-1.503310671289491 -0.9276054365424801 … 0.09197905953830772 0.6875314984174139; -2.2197049568725054 -0.10059718806451842 … -1.253595927992626 -1.0041760400439437], bias = [-0.8811143466354562; 0.5326621221885817;;])), (layer_1 = Float64[], layer_2 = (weight = [0.12913132090676094 0.22195279577053068; -0.5261629247881109 -0.5313527017568036; … ; 0.913257003823887 -0.3366035814709443; -0.6847439161057232 -0.039244441676086594], bias = [-0.39960319483617207; 0.04909583850431291; … ; -0.37001462147427744; -0.48014433947967844;;]), layer_3 = (weight = [-1.503310671289491 -0.9276054365424801 … 0.09197905953830772 0.6875314984174139; -2.2197049568725054 -0.10059718806451842 … -1.253595927992626 -1.0041760400439437], bias = [-0.8811143466354562; 0.5326621221885817;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.5343497363435821 0.470588130630527; 0.7314677793390783 -0.17238841247413003; … ; 0.12050341106603854 0.12147435770920167; -0.3451365541534841 -1.2294659456947725], bias = [-0.1865415382630694; -1.083547130682699; … ; -1.2759214864900938; -0.004800955445359953;;]), layer_3 = (weight = [0.08150471352081914 0.7488847901867103 … 1.319813451340709 1.6713500560586265; -0.8211060909842312 0.5287957582313625 … -0.5655970123336275 1.0335145237784722], bias = [-0.9267298827270111; 0.9956123919086927;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.36567386504133914 0.3908831447211131; 0.8793677167309495 -0.5748669105066178; … ; 0.5877007406883189 -0.039579257702194295; -0.17901989554176692 -0.5969806279455141], bias = [-0.2707662717250421; -0.8430291366507187; … ; -1.5301669864729632; -0.6174232651222021;;]), layer_3 = (weight = [0.458255963413203 0.32957976877179845 … 0.9838060806640869 1.434077130191355; -0.0914007570411822 0.4301422956077782 … -0.2527072877830681 1.6319018679887292], bias = [-0.7330928888077538; 0.7365231086888745;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.4576702754611351 -0.42019405144392347; 1.021799667375457 -0.5874839814627182; … ; -0.18394347803313887 -0.419529705603943; 0.031214570801567795 0.15149444398841147], bias = [0.0653606021064364; -0.5005881016331252; … ; -0.4173342071967196; 0.5399686901089998;;]), layer_3 = (weight = [0.1253415578377676 1.5034696154235867 … -0.15712742473801264 0.4065292721727852; -0.0731315423963288 0.19861937093116627 … -0.19715690677993838 -0.6411492079954145], bias = [-0.39608676808484694; 0.32423205433128177;;])), (layer_1 = Float64[], layer_2 = (weight = [-0.4576702754611351 -0.42019405144392347; 1.021799667375457 -0.5874839814627182; … ; -0.18394347803313887 -0.419529705603943; 0.031214570801567795 0.15149444398841147], bias = [0.0653606021064364; -0.5005881016331252; … ; -0.4173342071967196; 0.5399686901089998;;]), layer_3 = (weight = [0.1253415578377676 1.5034696154235867 … -0.15712742473801264 0.4065292721727852; -0.0731315423963288 0.19861937093116627 … -0.19715690677993838 -0.6411492079954145], bias = [-0.39608676808484694; 0.32423205433128177;;])), (layer_1 = Float64[], layer_2 = (weight = [0.050167275989957814 0.2875951270435296; 0.6428151276448938 -0.21443354486993388; … ; -0.22982044133857765 -0.2783902824282365; -0.12798056923930357 0.22011804216906278], bias = [-0.3845695161376685; -0.6184074336673536; … ; -0.24018540654159246; 0.7875031910384241;;]), layer_3 = (weight = [-0.04648453277115934 0.9518525805416456 … 0.16640535028613 0.5141539005739459; -0.08398285828169878 0.3931661399142788 … -0.341174517478964 -0.3992535123540945], bias = [-0.2358655973779271; 0.7095906369109675;;])), (layer_1 = Float64[], layer_2 = (weight = [0.19899719115387549 -0.11073108859396155; 0.18450103396173922 0.11725863366322467; … ; -0.41590366889754504 0.5447526456075771; -0.13175795903270351 -0.4234635627283766], bias = [-0.6859105312288231; -0.04130087170215305; … ; -0.08213145292404868; -0.06265587827746662;;]), layer_3 = (weight = [0.27301123572840896 1.4405098755387764 … 0.08285304021745579 0.6558249158224418; -0.23350628300966966 0.26885919415739046 … -0.1994897338602995 0.0776319700043018], bias = [-0.27201207970004154; 0.15613724282488556;;])), (layer_1 = Float64[], layer_2 = (weight = [0.28284027545143237 -0.17779032896834018; 0.14591763998889914 0.09894007422666055; … ; -0.5784109991941787 0.5458418209296682; -0.16219549250953483 -0.4391186210155363], bias = [-0.6660910305603663; -0.11296122327885678; … ; -0.03372344922040379; -0.13156504389470688;;]), layer_3 = (weight = [0.3304723784982743 1.4003079487737176 … 0.038507631693114226 0.5070001396239125; -0.2578709186740715 0.3006044214027692 … -0.22763509466097395 -0.03703037373222895], bias = [-0.2017245095347575; 0.14200154741600435;;])), (layer_1 = Float64[], layer_2 = (weight = [0.029261796456764744 0.18644999481726685; -0.19360354196563148 -0.4855550864937395; … ; -0.511331991871693 0.721933731819698; -0.8464791796976645 0.3083718527502789], bias = [-0.20702805924101123; -0.278699115223286; … ; 0.41415982258507195; 0.04384142205909699;;]), layer_3 = (weight = [0.41162368030237384 1.4501089725736676 … 0.24364401818459486 0.03428506156440415; -0.3316472200393006 -0.05808299560035294 … -0.20987282917884476 -0.9761530888521487], bias = [-0.6052570687121083; 0.7165308484430397;;]))], NamedTuple[(n_steps = 104, is_accept = true, acceptance_rate = 0.32173951527400385, log_density = -261.0594275992608, hamiltonian_energy = 490.08820759413686, hamiltonian_energy_error = -50.885129690598774, max_hamiltonian_energy_error = 2977.145505924246, tree_depth = 6, numerical_error = true, step_size = 0.025, nom_step_size = 0.025, is_adapt = true), (n_steps = 4, is_accept = true, acceptance_rate = 1.3331535266933632e-137, log_density = -261.0594275992608, hamiltonian_energy = 384.350249574772, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 176393.3519592736, tree_depth = 2, numerical_error = true, step_size = 0.1979986151626911, nom_step_size = 0.1979986151626911, is_adapt = true), (n_steps = 33, is_accept = true, acceptance_rate = 0.4099701923870929, log_density = -122.4865601481066, hamiltonian_energy = 367.5947692783018, hamiltonian_energy_error = -19.550136765454226, max_hamiltonian_energy_error = 7227.158803914212, tree_depth = 5, numerical_error = true, step_size = 0.06397471226305036, nom_step_size = 0.06397471226305036, is_adapt = true), (n_steps = 51, is_accept = true, acceptance_rate = 0.16805400878326698, log_density = -80.77512068383038, hamiltonian_energy = 234.95639065234303, hamiltonian_energy_error = -4.219367884781775, max_hamiltonian_energy_error = 1011.6375045048229, tree_depth = 5, numerical_error = true, step_size = 0.04813005200250155, nom_step_size = 0.04813005200250155, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.9227794360123575, log_density = -134.87480358105665, hamiltonian_energy = 215.05720332439267, hamiltonian_energy_error = 0.06821316133331834, max_hamiltonian_energy_error = -0.5313842076900244, tree_depth = 7, numerical_error = false, step_size = 0.019093677332926093, nom_step_size = 0.019093677332926093, is_adapt = true), (n_steps = 28, is_accept = true, acceptance_rate = 0.005834998793932895, log_density = -134.87480358105665, hamiltonian_energy = 245.24455366986706, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 9735.806387336515, tree_depth = 4, numerical_error = true, step_size = 0.06989756592980959, nom_step_size = 0.06989756592980959, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.6084800235117573, log_density = -135.74437952967753, hamiltonian_energy = 268.65620797884094, hamiltonian_energy_error = 0.9971237930679422, max_hamiltonian_energy_error = 4.0653991739375215, tree_depth = 7, numerical_error = false, step_size = 0.017334087615419345, nom_step_size = 0.017334087615419345, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.7422718828369279, log_density = -121.83243734860136, hamiltonian_energy = 254.09896801303805, hamiltonian_energy_error = -0.3543036583854189, max_hamiltonian_energy_error = 7.369640659859954, tree_depth = 7, numerical_error = false, step_size = 0.027158797119780295, nom_step_size = 0.027158797119780295, is_adapt = true), (n_steps = 19, is_accept = true, acceptance_rate = 0.02587776283001818, log_density = -126.31974271991281, hamiltonian_energy = 247.71313590548425, hamiltonian_energy_error = 0.7099337302286699, max_hamiltonian_energy_error = 1325.7576290695922, tree_depth = 4, numerical_error = true, step_size = 0.06660597541342968, nom_step_size = 0.06660597541342968, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.9825313532214871, log_density = -155.53178630305257, hamiltonian_energy = 274.1698726972485, hamiltonian_energy_error = -0.9504991802299969, max_hamiltonian_energy_error = -1.4394907622677238, tree_depth = 7, numerical_error = false, step_size = 0.017340842570566877, nom_step_size = 0.017340842570566877, is_adapt = true)  …  (n_steps = 127, is_accept = true, acceptance_rate = 0.9669330692391371, log_density = -145.67700141412007, hamiltonian_energy = 266.0747473335934, hamiltonian_energy_error = -0.36339442116593546, max_hamiltonian_energy_error = 1.2993037222153134, tree_depth = 7, numerical_error = false, step_size = 0.024753213201858457, nom_step_size = 0.024753213201858457, is_adapt = true), (n_steps = 15, is_accept = true, acceptance_rate = 0.1129642228073525, log_density = -145.67700141412007, hamiltonian_energy = 256.9406844798518, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 4462.040546968416, tree_depth = 3, numerical_error = true, step_size = 0.09241352092070604, nom_step_size = 0.09241352092070604, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.6993676979819111, log_density = -123.66248136639996, hamiltonian_energy = 261.119423573597, hamiltonian_energy_error = 0.44286813743246967, max_hamiltonian_energy_error = 13.856199333105963, tree_depth = 7, numerical_error = false, step_size = 0.04026844579140109, nom_step_size = 0.04026844579140109, is_adapt = true), (n_steps = 24, is_accept = true, acceptance_rate = 0.34494583154200237, log_density = -124.63853264514037, hamiltonian_energy = 244.6815073709703, hamiltonian_energy_error = -0.08686656755585886, max_hamiltonian_energy_error = 2557.997327517342, tree_depth = 4, numerical_error = true, step_size = 0.07578769639153102, nom_step_size = 0.07578769639153102, is_adapt = true), (n_steps = 63, is_accept = true, acceptance_rate = 0.3883799684855486, log_density = -144.90595449270333, hamiltonian_energy = 264.1957789822614, hamiltonian_energy_error = 0.28997033865772437, max_hamiltonian_energy_error = 838.6767000075827, tree_depth = 6, numerical_error = false, step_size = 0.059171208246367075, nom_step_size = 0.059171208246367075, is_adapt = true), (n_steps = 63, is_accept = true, acceptance_rate = 0.01313597711096573, log_density = -144.90595449270333, hamiltonian_energy = 261.33580948261687, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 66.35144880455039, tree_depth = 6, numerical_error = false, step_size = 0.051539285842317574, nom_step_size = 0.051539285842317574, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.9227457976361046, log_density = -133.9449889544607, hamiltonian_energy = 269.7635886001633, hamiltonian_energy_error = -0.07076822881748512, max_hamiltonian_energy_error = -1.2442577421160763, tree_depth = 8, numerical_error = false, step_size = 0.018123178362423303, nom_step_size = 0.018123178362423303, is_adapt = true), (n_steps = 35, is_accept = true, acceptance_rate = 0.7250168218191952, log_density = -113.43179120602302, hamiltonian_energy = 258.151490271365, hamiltonian_energy_error = -0.5538985891923289, max_hamiltonian_energy_error = 1617.106470750091, tree_depth = 5, numerical_error = true, step_size = 0.05765670011394864, nom_step_size = 0.05765670011394864, is_adapt = true), (n_steps = 13, is_accept = true, acceptance_rate = 0.07692307692307693, log_density = -115.58674502861471, hamiltonian_energy = 244.2193252058538, hamiltonian_energy_error = -0.4891241146290213, max_hamiltonian_energy_error = 1222.6189890142773, tree_depth = 3, numerical_error = true, step_size = 0.11256227361909418, nom_step_size = 0.11256227361909418, is_adapt = true), (n_steps = 76, is_accept = true, acceptance_rate = 0.45006815466476185, log_density = -116.98660074777638, hamiltonian_energy = 228.89185529284265, hamiltonian_energy_error = -0.08336028367028803, max_hamiltonian_energy_error = 1184.9677343789883, tree_depth = 6, numerical_error = true, step_size = 0.046784471411363104, nom_step_size = 0.046784471411363104, is_adapt = true)])

Step 5: Plot diagnostics

Now let's make sure the fit is good. This can be done by looking at the chain mixing plot and the autocorrelation plot. First, let's create the chain mixing plot using the plot recipes from ????

samples = hcat(samples...)
+samples_reduced = samples[1:5, :]
+samples_reshape = reshape(samples_reduced, (500, 5, 1))
+Chain_Spiral = Chains(samples_reshape)
+plot(Chain_Spiral)
Example block output

Now we check the autocorrelation plot:

autocorplot(Chain_Spiral)
Example block output

As another diagnostic, let's check the result on retrodicted data. To do this, we generate solutions of the Neural ODE on samples of the neural network parameters, and check the results of the predictions against the data. Let's start by looking at the time series:

pl = scatter(tsteps, ode_data[1, :], color = :red, label = "Data: Var1", xlabel = "t",
+             title = "Spiral Neural ODE")
+scatter!(tsteps, ode_data[2, :], color = :blue, label = "Data: Var2")
+for k in 1:300
+    resol = predict_neuralode(samples[:, 100:end][:, rand(1:400)])
+    plot!(tsteps, resol[1, :], alpha = 0.04, color = :red, label = "")
+    plot!(tsteps, resol[2, :], alpha = 0.04, color = :blue, label = "")
+end
+
+losses = map(x -> loss_neuralode(x)[1], eachcol(samples))
+idx = findmin(losses)[2]
+prediction = predict_neuralode(samples[:, idx])
+plot!(tsteps, prediction[1, :], color = :black, w = 2, label = "")
+plot!(tsteps, prediction[2, :], color = :black, w = 2, label = "Best fit prediction",
+      ylims = (-2.5, 3.5))
Example block output

That showed the time series form. We can similarly do a phase-space plot:

pl = scatter(ode_data[1, :], ode_data[2, :], color = :red, label = "Data", xlabel = "Var1",
+             ylabel = "Var2", title = "Spiral Neural ODE")
+for k in 1:300
+    resol = predict_neuralode(samples[:, 100:end][:, rand(1:400)])
+    plot!(resol[1, :], resol[2, :], alpha = 0.04, color = :red, label = "")
+end
+plot!(prediction[1, :], prediction[2, :], color = :black, w = 2,
+      label = "Best fit prediction", ylims = (-2.5, 3))
Example block output
diff --git a/v1.5.0/showcase/blackhole/17feb703.svg b/v1.5.0/showcase/blackhole/17feb703.svg new file mode 100644 index 00000000000..330f21a5863 --- /dev/null +++ b/v1.5.0/showcase/blackhole/17feb703.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/blackhole/7db8c76f.svg b/v1.5.0/showcase/blackhole/7db8c76f.svg new file mode 100644 index 00000000000..756f56edacc --- /dev/null +++ b/v1.5.0/showcase/blackhole/7db8c76f.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/blackhole/991a7a22.svg b/v1.5.0/showcase/blackhole/991a7a22.svg new file mode 100644 index 00000000000..68f60c40f44 --- /dev/null +++ b/v1.5.0/showcase/blackhole/991a7a22.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/blackhole/be18b50e.svg b/v1.5.0/showcase/blackhole/be18b50e.svg new file mode 100644 index 00000000000..aaf976035eb --- /dev/null +++ b/v1.5.0/showcase/blackhole/be18b50e.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/blackhole/f6eae0f3.svg b/v1.5.0/showcase/blackhole/f6eae0f3.svg new file mode 100644 index 00000000000..d984574934d --- /dev/null +++ b/v1.5.0/showcase/blackhole/f6eae0f3.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/blackhole/index.html b/v1.5.0/showcase/blackhole/index.html new file mode 100644 index 00000000000..170e62a64fd --- /dev/null +++ b/v1.5.0/showcase/blackhole/index.html @@ -0,0 +1,470 @@ + +Discovering the Relativistic Corrections to Binary Black Hole Dynamics · Overview of Julia's SciML

Discovering the Relativistic Corrections to Binary Black Hole Dynamics

In this showcase we will demonstrate using Newtonian mechanics as prior known information in a universal differential equation and learning relativistic corrections to the physics via the gravitational waveform.

This showcase is minimally adapted from Keith et al. 2021.

Starting Point: The Packages To Use

There are many packages which are used as part of this showcase. Let's detail what they are and how they are used. For the neural network training:

ModuleDescription
OrdinaryDiffEq.jl (DifferentialEquations.jl)The numerical differential equation solvers
SciMLSensitivity.jlThe adjoint methods, defines gradients of ODE solvers
Optimization.jlThe optimization library
OptimizationOptimisers.jlThe optimization solver package with Adam
OptimizationOptimJL.jlThe optimization solver package with BFGS

For the symbolic model discovery:

ModuleDescription
ModelingToolkit.jlThe symbolic modeling environment
DataDrivenDiffEq.jlThe symbolic regression interface
DataDrivenSparse.jlThe sparse regression symbolic regression solvers
Zygote.jlThe automatic differentiation library for fast gradients

Julia standard libraries:

ModuleDescription
LinearAlgebraRequired for the norm function
StatisticsRequired for the mean function

And external libraries:

ModuleDescription
Lux.jlThe deep learning (neural network) framework
ComponentArrays.jlFor the ComponentArray type to match Lux to SciML
LineSearches.jlAllows for setting a line search for optimization
DataFrames.jlA nice and easy data handling format
CSV.jlImport and export of CSV files
Plots.jlThe plotting and visualization library
StableRNGs.jlStable random seeding
# SciML Tools
+using OrdinaryDiffEq, ModelingToolkit, DataDrivenDiffEq, SciMLSensitivity, DataDrivenSparse
+using Optimization, OptimizationOptimisers, OptimizationOptimJL
+
+# Standard Libraries
+using LinearAlgebra, Statistics
+
+# External Libraries
+using ComponentArrays, Lux, Zygote, Plots, StableRNGs, DataFrames, CSV, LineSearches
+gr()
+
+# Set a random seed for reproducible behaviour
+rng = StableRNG(1111)
StableRNGs.LehmerRNG(state=0x000000000000000000000000000008af)

Problem Setup

For this example we will use the known relativistic relations to generate data matching the expected LIGO gravitational waveforms. Details can be found in Keith et al. 2021.

Feel free to skip reading this setup code!

The setup of the data and the ODEs for the Newtonian ODE model
#=
+    ODE models for orbital mechanics
+=#
+
+function NewtonianOrbitModel(u, model_params, t)
+    #=
+        Defines system of odes which describes motion of
+        point like particle with Newtonian physics, uses
+
+        u[1] = χ
+        u[2] = ϕ
+
+        where, p, M, and e are constants
+    =#
+    χ, ϕ = u
+    p, M, e = model_params
+
+    numer = (1 + e * cos(χ))^2
+    denom = M * (p^(3 / 2))
+
+    χ̇ = numer / denom
+    ϕ̇ = numer / denom
+
+    return [χ̇, ϕ̇]
+
+end
+
+function RelativisticOrbitModel(u, model_params, t)
+    #=
+        Defines system of odes which describes motion of
+        point like particle in schwarzschild background, uses
+
+        u[1] = χ
+        u[2] = ϕ
+
+        where, p, M, and e are constants
+    =#
+    χ, ϕ = u
+    p, M, e = model_params
+
+    numer = (p - 2 - 2 * e * cos(χ)) * (1 + e * cos(χ))^2
+    denom = sqrt((p - 2)^2 - 4 * e^2)
+
+    χ̇ = numer * sqrt(p - 6 - 2 * e * cos(χ)) / (M * (p^2) * denom)
+    ϕ̇ = numer / (M * (p^(3 / 2)) * denom)
+
+    return [χ̇, ϕ̇]
+
+end
+
+function AbstractNNOrbitModel(u, model_params, t; NN=nothing, NN_params=nothing)
+    #=
+        Defines system of odes which describes motion of
+        point like particle with Newtonian physics, uses
+
+        u[1] = χ
+        u[2] = ϕ
+
+        where, p, M, and e are constants
+    =#
+    χ, ϕ = u
+    p, M, e = model_params
+
+    if isnothing(NN)
+        nn = [1, 1]
+    else
+        nn = 1 .+ NN([u[1]], NN_params, st)[1]
+    end
+
+    numer = (1 + e * cos(χ))^2
+    denom = M * (p^(3 / 2))
+
+    χ̇ = (numer / denom) * nn[1]
+    ϕ̇ = (numer / denom) * nn[2]
+
+    return [χ̇, ϕ̇]
+
+end
+
+function AbstractNROrbitModel(u, model_params, t;
+    NN_chiphi=nothing, NN_chiphi_params=nothing,
+    NN_pe=nothing, NN_pe_params=nothing)
+    #=
+        Defines system of odes which describes motion of
+        point like particle with Newtonian physics, uses
+
+        u[1] = χ
+        u[2] = ϕ
+        u[3] = p
+        u[4] = e
+
+        q is the mass ratio
+    =#
+    χ, ϕ, p, e = u
+    q = model_params[1]
+    M = 1.0
+
+    if p <= 0
+        println("p = ", p)
+    end
+
+    if isnothing(NN_chiphi)
+        nn_chiphi = [1, 1]
+    else
+        nn_chiphi = 1 .+ NN_chiphi(u, NN_chiphi_params, st)
+    end
+
+    if isnothing(NN_pe)
+        nn_pe = [0, 0]
+    else
+        nn_pe = NN_pe(u, NN_pe_params, st)
+    end
+
+    numer = (1 + e * cos(χ))^2
+    denom = M * (abs(p)^(3 / 2))
+
+    χ̇ = (numer / denom) * nn_chiphi[1]
+    ϕ̇ = (numer / denom) * nn_chiphi[2]
+    ṗ = nn_pe[1]
+    ė = nn_pe[2]
+
+    return [χ̇, ϕ̇, ṗ, ė]
+end
+
+#=
+    Axiliary functions for orbital mechanics
+=#
+using DelimitedFiles
+
+function soln2orbit(soln, model_params=nothing)
+    #=
+        Performs change of variables:
+        (χ(t),ϕ(t)) ↦ (x(t),y(t))
+    =#
+    if size(soln, 1) == 2
+        χ = soln[1, :]
+        ϕ = soln[2, :]
+        if length(model_params) == 3
+            p, M, e = model_params
+        else
+            error("model_params must have length 3 when size(soln,2) = 2")
+        end
+    elseif size(soln, 1) == 4
+        χ = soln[1, :]
+        ϕ = soln[2, :]
+        p = soln[3, :]
+        e = soln[4, :]
+    else
+        error("size(soln,2) must be either 2 or 4")
+    end
+
+    r = p ./ (1 .+ e .* cos.(χ))
+    x = r .* cos.(ϕ)
+    y = r .* sin.(ϕ)
+
+    orbit = vcat(x', y')
+    return orbit
+end
+
+function orbit2tensor(orbit, component, mass=1.0)
+    #=
+        Construct trace-free moment tensor Ι(t) for orbit from BH orbit (x(t),y(t))
+
+        component defines the Cartesion indices in x,y. For example,
+        I_{22} is the yy component of the moment tensor.
+    =#
+    x = orbit[1, :]
+    y = orbit[2, :]
+
+    Ixx = x .^ 2
+    Iyy = y .^ 2
+    Ixy = x .* y
+    trace = Ixx .+ Iyy
+
+    if component[1] == 1 && component[2] == 1
+        tmp = Ixx .- (1.0 ./ 3.0) .* trace
+    elseif component[1] == 2 && component[2] == 2
+        tmp = Iyy .- (1.0 ./ 3.0) .* trace
+    else
+        tmp = Ixy
+    end
+
+    return mass .* tmp
+end
+
+function d_dt(v::AbstractVector, dt)
+    # uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0
+    a = -3 / 2 * v[1] + 2 * v[2] - 1 / 2 * v[3]
+    b = (v[3:end] .- v[1:end-2]) / 2
+    c = 3 / 2 * v[end] - 2 * v[end-1] + 1 / 2 * v[end-2]
+    return [a; b; c] / dt
+end
+
+function d2_dt2(v::AbstractVector, dt)
+    # uses second-order one-sided difference stencils at the endpoints; see https://doi.org/10.1090/S0025-5718-1988-0935077-0
+    a = 2 * v[1] - 5 * v[2] + 4 * v[3] - v[4]
+    b = v[1:end-2] .- 2 * v[2:end-1] .+ v[3:end]
+    c = 2 * v[end] - 5 * v[end-1] + 4 * v[end-2] - v[end-3]
+    return [a; b; c] / (dt^2)
+end
+
+function h_22_quadrupole_components(dt, orbit, component, mass=1.0)
+    #=
+        x(t) and y(t) inputs are the trajectory of the orbiting BH.
+
+       WARNING: assuming x and y are on a uniform grid of spacing dt
+        x_index and y_index are 1,2,3 for x, y, and z indices.
+    =#
+
+    mtensor = orbit2tensor(orbit, component, mass)
+    mtensor_ddot = d2_dt2(mtensor, dt)
+
+    # return mtensor
+    return 2 * mtensor_ddot
+end
+
+function h_22_quadrupole(dt, orbit, mass=1.0)
+    h11 = h_22_quadrupole_components(dt, orbit, (1, 1), mass)
+    h22 = h_22_quadrupole_components(dt, orbit, (2, 2), mass)
+    h12 = h_22_quadrupole_components(dt, orbit, (1, 2), mass)
+    return h11, h12, h22
+end
+
+function h_22_strain_one_body(dt, orbit)
+
+    h11, h12, h22 = h_22_quadrupole(dt, orbit)
+
+    h₊ = h11 - h22
+    hₓ = 2.0 * h12
+
+    scaling_const = sqrt(pi / 5)
+    return scaling_const * h₊, -scaling_const * hₓ
+end
+
+function h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
+    h11_1, h12_1, h22_1 = h_22_quadrupole(dt, orbit1, mass1)
+    h11_2, h12_2, h22_2 = h_22_quadrupole(dt, orbit2, mass2)
+    h11 = h11_1 + h11_2
+    h12 = h12_1 + h12_2
+    h22 = h22_1 + h22_2
+    return h11, h12, h22
+end
+
+function h_22_strain_two_body(dt, orbit1, mass1, orbit2, mass2)
+    # compute (2,2) mode strain from orbits of BH 1 of mass1 and BH2 of mass 2
+
+    @assert abs(mass1 + mass2 - 1.0) < 1e-12 "Masses do not sum to unity"
+
+    h11, h12, h22 = h_22_quadrupole_two_body(dt, orbit1, mass1, orbit2, mass2)
+
+    h₊ = h11 - h22
+    hₓ = 2.0 * h12
+
+    scaling_const = sqrt(pi / 5)
+    return scaling_const * h₊, -scaling_const * hₓ
+end
+
+function one2two(path, m1, m2)
+    #=
+        We need a very crude 2-body path
+
+        Assume the 1-body motion is a newtonian 2-body position vector r = r1 - r2
+        and use Newtonian formulas to get r1, r2
+        (e.g. Theoretical Mechanics of Particles and Continua 4.3)
+    =#
+
+    M = m1 + m2
+    r1 = m2 / M .* path
+    r2 = -m1 / M .* path
+
+    return r1, r2
+end
+
+function compute_waveform(dt, soln, mass_ratio, model_params=nothing)
+
+    @assert mass_ratio <= 1.0 "mass_ratio must be <= 1"
+    @assert mass_ratio >= 0.0 "mass_ratio must be non-negative"
+
+    orbit = soln2orbit(soln, model_params)
+    if mass_ratio > 0
+        mass1 = mass_ratio / (1.0 + mass_ratio)
+        mass2 = 1.0 / (1.0 + mass_ratio)
+
+        orbit1, orbit2 = one2two(orbit, mass1, mass2)
+        waveform = h_22_strain_two_body(dt, orbit1, mass1, orbit2, mass2)
+    else
+        waveform = h_22_strain_one_body(dt, orbit)
+    end
+    return waveform
+end
+
+function interpolate_time_series(tsteps, tdata, fdata)
+
+    @assert length(tdata) == length(fdata) "lengths of tdata and fdata must match"
+
+    interp_fdata = zeros(length(tsteps))
+    for j = 1:length(tsteps)
+        for i = 1:length(tdata)-1
+            if tdata[i] <= tsteps[j] < tdata[i+1]
+                weight = (tsteps[j] - tdata[i]) / (tdata[i+1] - tdata[i])
+                interp_fdata[j] = (1 - weight) * fdata[i] + weight * fdata[i+1]
+                break
+            end
+        end
+    end
+
+    return interp_fdata
+end
+
+function file2waveform(tsteps, filename="waveform.txt")
+
+    # read in file
+    f = open(filename, "r")
+    data = readdlm(f)
+    tdata = data[:, 1]
+    wdata = data[:, 2]
+
+    # interpolate data to tsteps
+    waveform = interpolate_time_series(tsteps, tdata, wdata)
+
+    return waveform
+end
+
+function file2trajectory(tsteps, filename="trajectoryA.txt")
+
+    # read in file
+    f = open(filename, "r")
+    data = readdlm(f)
+    tdata = data[:, 1]
+    xdata = data[:, 2]
+    ydata = data[:, 3]
+
+    # interpolate data to tsteps
+    x = interpolate_time_series(tsteps, tdata, xdata)
+    y = interpolate_time_series(tsteps, tdata, ydata)
+
+    return x, y
+end
file2trajectory (generic function with 2 methods)

Testing the Model Setup

Now let's test the relativistic orbital model. Let's choose a few parameters of interest:

mass_ratio = 0.0         # test particle
+u0 = Float64[pi, 0.0]    # initial conditions
+datasize = 250
+tspan = (0.0f0, 6.0f4)   # timespace for GW waveform
+tsteps = range(tspan[1], tspan[2], length = datasize)  # time at each timestep
+dt_data = tsteps[2] - tsteps[1]
+dt = 100.0
+model_params = [100.0, 1.0, 0.5]; # p, M, e
3-element Vector{Float64}:
+ 100.0
+   1.0
+   0.5

and demonstrate the gravitational waveform:

prob = ODEProblem(RelativisticOrbitModel, u0, tspan, model_params)
+soln = Array(solve(prob, RK4(), saveat = tsteps, dt = dt, adaptive=false))
+waveform = compute_waveform(dt_data, soln, mass_ratio, model_params)[1]
+plt = plot(tsteps, waveform,
+           markershape=:circle, markeralpha = 0.25,
+           linewidth = 2, alpha = 0.5,
+           label="waveform data", xlabel="Time", ylabel="Waveform")
Example block output

Looks great!

Automating the Discovery of Relativistic Equations from Newtonian Physics

Now let's learn the relativistic corrections directly from the data. To define the UDE, we will define a Lux neural network and pass it into our Newtonian Physics + Neural Network ODE definition from above:

NN = Lux.Chain((x) -> cos.(x),
+    Lux.Dense(1, 32, cos),
+    Lux.Dense(32, 32, cos),
+    Lux.Dense(32, 2))
+p, st = Lux.setup(rng, NN)
+NN_params = ComponentArray{Float64}(p)
+
+function ODE_model(u, NN_params, t)
+    du = AbstractNNOrbitModel(u, model_params, t, NN=NN, NN_params=NN_params)
+    return du
+end
ODE_model (generic function with 1 method)

Next, we can compute the orbital trajectory and gravitational waveform using the neural network with its initial weights.

prob_nn = ODEProblem(ODE_model, u0, tspan, NN_params)
+soln_nn = Array(solve(prob_nn, RK4(), u0 = u0, p = NN_params, saveat = tsteps, dt = dt, adaptive=false))
+waveform_nn = compute_waveform(dt_data, soln_nn, mass_ratio, model_params)[1]
+plot!(plt, tsteps, waveform_nn,
+           markershape=:circle, markeralpha = 0.25,
+           linewidth = 2, alpha = 0.5,
+           label="waveform NN")
+display(plt)

This is the model before training.

Next, we define the objective (loss) function to be minimized when training the neural differential equations.

function loss(NN_params)
+    first_obs_to_use_for_training = 1
+    last_obs_to_use_for_training = length(waveform)
+    obs_to_use_for_training = first_obs_to_use_for_training:last_obs_to_use_for_training
+
+    pred = Array(solve(prob_nn, RK4(), u0 = u0, p = NN_params, saveat = tsteps, dt = dt, adaptive=false))
+    pred_waveform = compute_waveform(dt_data, pred, mass_ratio, model_params)[1]
+
+    loss = ( sum(abs2, view(waveform,obs_to_use_for_training) .- view(pred_waveform,obs_to_use_for_training) ) )
+    return loss, pred_waveform
+end
loss (generic function with 1 method)

We can test the loss function and see that it returns a pair, a scalar loss and an array with the predicted waveform.

loss(NN_params)
(2.494367614026788, [-0.048380291804041624, -0.04544681892851214, -0.04251334605298285, -0.037742552548713754, -0.03130914583963539, -0.023452056533689883, -0.01447011185297947, -0.004712429709758706, 0.005427584192674962, 0.015525330459250088  …  -0.009032303205709238, 0.0006263870657826993, 0.010308202078072398, 0.01962529698289368, 0.028177185552041076, 0.03561233801991918, 0.041578106006917165, 0.045781536721722034, 0.04798004757242218, 0.05017855842312217])

We'll use the following callback to save the history of the loss values.

losses = []
+
+callback(θ,l,pred_waveform; doplot = true) = begin
+    push!(losses, l)
+    #=  Disable plotting as it trains since in docs
+    display(l)
+    # plot current prediction against data
+    plt = plot(tsteps, waveform,
+        markershape=:circle, markeralpha = 0.25,
+        linewidth = 2, alpha = 0.5,
+        label="wform data (h22)", legend=:topleft)
+    plot!(plt, tsteps, pred_waveform,
+        markershape=:circle, markeralpha = 0.25,
+        linewidth = 2, alpha = 0.5,
+        label = "wform NN")
+    if doplot
+        display(plot(plt))
+    end
+    # Tell sciml_train to not halt the optimization. If return true, then
+    # optimization stops.
+    =#
+    return false
+end
callback (generic function with 1 method)

Running the Training

The next cell initializes the weights of the neural network and then trains the neural network. Training uses the BFGS optimizers. This seems to give good results because the Newtonian model seems to give a very good initial guess.

NN_params = NN_params .* 0 + Float64(1e-4) * randn(StableRNG(2031), eltype(NN_params), size(NN_params))
+
+adtype = Optimization.AutoZygote()
+optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
+optprob = Optimization.OptimizationProblem(optf, ComponentVector{Float64}(NN_params))
+res1 = Optimization.solve(optprob, OptimizationOptimisers.Adam(0.001f0), callback=callback, maxiters=100)
+optprob = Optimization.OptimizationProblem(optf, res1.u)
+res2 = Optimization.solve(optprob, BFGS(initial_stepnorm=0.01, linesearch=LineSearches.BackTracking()), callback=callback, maxiters=20)
retcode: Failure
+u: ComponentVector{Float64}(layer_1 = Float64[], layer_2 = (weight = [0.0073214730865738455; 0.004709231001093825; … ; 0.018930119093878376; 0.006597344866338353;;], bias = [-0.008488384282509684; 0.0046248208320659005; … ; -0.0005185501180706876; -0.007991234610508104;;]), layer_3 = (weight = [-0.03526078962885585 -0.03502744647801473 … -0.0348133656400281 -0.035153627985674826; 0.030846328060675166 0.030685890330478662 … 0.030765473868700245 0.030658550738365622; … ; 0.03133609090884697 0.031486303011273725 … 0.03160877370131913 0.03151949399887447; 0.03195402620648283 0.031678608228911075 … 0.031707238641083636 0.03170640785078559], bias = [-0.035152767032909385; 0.030815209401847152; … ; 0.03155040243368386; 0.03176278015387439;;]), layer_4 = (weight = [0.0012752605486608046 -0.0014836412046943918 … -0.0009600233978235278 -0.0009154386677447193; 0.009059266405021298 0.00026020692348312024 … 0.0016440554751157657 0.0022220556853327867], bias = [-0.011754334801286582; -0.03572286421873408;;]))

Result Analysis

Now, we'll plot the learned solutions of the neural ODE and compare them to our full physical model and the Newtonian model.

reference_solution = solve(remake(prob, p = model_params, saveat = tsteps, tspan=tspan),
+                            RK4(), dt = dt, adaptive=false)
+
+optimized_solution = solve(remake(prob_nn, p = res2.minimizer, saveat = tsteps, tspan=tspan),
+                            RK4(), dt = dt, adaptive=false)
+Newtonian_prob = ODEProblem(NewtonianOrbitModel, u0, tspan, model_params)
+
+Newtonian_solution = solve(remake(Newtonian_prob, p = model_params, saveat = tsteps, tspan=tspan),
+                            RK4(), dt = dt, adaptive=false)
+
+true_orbit = soln2orbit(reference_solution, model_params)
+pred_orbit = soln2orbit(optimized_solution, model_params)
+Newt_orbit = soln2orbit(Newtonian_solution, model_params)
+
+true_waveform = compute_waveform(dt_data, reference_solution, mass_ratio, model_params)[1]
+pred_waveform = compute_waveform(dt_data, optimized_solution, mass_ratio, model_params)[1]
+Newt_waveform = compute_waveform(dt_data, Newtonian_solution, mass_ratio, model_params)[1]
+
+true_orbit = soln2orbit(reference_solution, model_params)
+pred_orbit = soln2orbit(optimized_solution, model_params)
+Newt_orbit = soln2orbit(Newtonian_solution, model_params)
+plt = plot(true_orbit[1,:], true_orbit[2,:], linewidth = 2, label = "truth")
+plot!(plt, pred_orbit[1,:], pred_orbit[2,:], linestyle = :dash, linewidth = 2, label = "prediction")
+plot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = "Newtonian")
Example block output
plt = plot(tsteps,true_waveform, linewidth = 2, label = "truth", xlabel="Time", ylabel="Waveform")
+plot!(plt,tsteps,pred_waveform, linestyle = :dash, linewidth = 2, label = "prediction")
+plot!(plt,tsteps,Newt_waveform, linewidth = 2, label = "Newtonian")
Example block output

Now we'll do the same, but extrapolating the model out in time.

factor=5
+
+extended_tspan = (tspan[1], factor*tspan[2])
+extended_tsteps = range(tspan[1], factor*tspan[2], length = factor*datasize)
+reference_solution = solve(remake(prob, p = model_params, saveat = extended_tsteps, tspan=extended_tspan),
+                            RK4(), dt = dt, adaptive=false)
+optimized_solution = solve(remake(prob_nn, p = res2.minimizer, saveat = extended_tsteps, tspan=extended_tspan),
+                            RK4(), dt = dt, adaptive=false)
+Newtonian_prob = ODEProblem(NewtonianOrbitModel, u0, tspan, model_params)
+Newtonian_solution = solve(remake(Newtonian_prob, p = model_params, saveat = extended_tsteps, tspan=extended_tspan),
+                            RK4(), dt = dt, adaptive=false)
+true_orbit = soln2orbit(reference_solution, model_params)
+pred_orbit = soln2orbit(optimized_solution, model_params)
+Newt_orbit = soln2orbit(Newtonian_solution, model_params)
+plt = plot(true_orbit[1,:], true_orbit[2,:], linewidth = 2, label = "truth")
+plot!(plt, pred_orbit[1,:], pred_orbit[2,:], linestyle = :dash, linewidth = 2, label = "prediction")
+plot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = "Newtonian")
Example block output
true_waveform = compute_waveform(dt_data, reference_solution, mass_ratio, model_params)[1]
+pred_waveform = compute_waveform(dt_data, optimized_solution, mass_ratio, model_params)[1]
+Newt_waveform = compute_waveform(dt_data, Newtonian_solution, mass_ratio, model_params)[1]
+plt = plot(extended_tsteps,true_waveform, linewidth = 2, label = "truth", xlabel="Time", ylabel="Waveform")
+plot!(plt,extended_tsteps,pred_waveform, linestyle = :dash, linewidth = 2, label = "prediction")
+plot!(plt,extended_tsteps,Newt_waveform, linewidth = 2, label = "Newtonian")
Example block output
diff --git a/v1.5.0/showcase/brusselator/index.html b/v1.5.0/showcase/brusselator/index.html new file mode 100644 index 00000000000..c45009dd788 --- /dev/null +++ b/v1.5.0/showcase/brusselator/index.html @@ -0,0 +1,381 @@ + +Automated Efficient Solution of Nonlinear Partial Differential Equations · Overview of Julia's SciML

Automated Efficient Solution of Nonlinear Partial Differential Equations

Solving nonlinear partial differential equations (PDEs) is hard. Solving nonlinear PDEs fast and accurately is even harder. Doing it all in an automated method from just a symbolic description is just plain fun. That's what we'd demonstrate here: how to solve a nonlinear PDE from a purely symbolic definition using the combination of ModelingToolkit, MethodOfLines, and DifferentialEquations.jl.

Required Dependencies

The following parts of the SciML Ecosystem will be used in this tutorial:

ModuleDescription
ModelingToolkit.jlThe symbolic modeling environment
MethodOfLines.jlThe symbolic PDE discretization tooling
DifferentialEquations.jlThe numerical differential equation solvers
LinearSolve.jlThe numerical linear solvers

Problem Setup

The Brusselator PDE is defined as follows:

\[\begin{align} +\frac{\partial u}{\partial t} &= 1 + u^2v - 4.4u + \alpha(\frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2}) + f(x, y, t)\\ +\frac{\partial v}{\partial t} &= 3.4u - u^2v + \alpha(\frac{\partial^2 v}{\partial x^2} + \frac{\partial^2 v}{\partial y^2}) +\end{align}\]

where

\[f(x, y, t) = \begin{cases} +5 & \quad \text{if } (x-0.3)^2+(y-0.6)^2 ≤ 0.1^2 \text{ and } t ≥ 1.1 \\ +0 & \quad \text{else} +\end{cases}\]

and the initial conditions are

\[\begin{align} +u(x, y, 0) &= 22\cdot (y(1-y))^{3/2} \\ +v(x, y, 0) &= 27\cdot (x(1-x))^{3/2} +\end{align}\]

with the periodic boundary condition

\[\begin{align} +u(x+1,y,t) &= u(x,y,t) \\ +u(x,y+1,t) &= u(x,y,t) +\end{align}\]

We wish to obtain the solution to this PDE on a timespan of $t \in [0,11.5]$.

Defining the symbolic PDEsystem with ModelingToolkit.jl

With ModelingToolkit.jl, we first symbolically define the system, see also the docs for PDESystem:

using ModelingToolkit, MethodOfLines, OrdinaryDiffEq, LinearSolve, DomainSets
+
+@parameters x y t
+@variables u(..) v(..)
+Dt = Differential(t)
+Dx = Differential(x)
+Dy = Differential(y)
+Dxx = Differential(x)^2
+Dyy = Differential(y)^2
+
+∇²(u) = Dxx(u) + Dyy(u)
+
+brusselator_f(x, y, t) = (((x - 0.3)^2 + (y - 0.6)^2) <= 0.1^2) * (t >= 1.1) * 5.0
+
+x_min = y_min = t_min = 0.0
+x_max = y_max = 1.0
+t_max = 11.5
+
+α = 10.0
+
+u0(x, y, t) = 22(y * (1 - y))^(3 / 2)
+v0(x, y, t) = 27(x * (1 - x))^(3 / 2)
+
+eq = [
+    Dt(u(x, y, t)) ~ 1.0 + v(x, y, t) * u(x, y, t)^2 - 4.4 * u(x, y, t) +
+                     α * ∇²(u(x, y, t)) + brusselator_f(x, y, t),
+    Dt(v(x, y, t)) ~ 3.4 * u(x, y, t) - v(x, y, t) * u(x, y, t)^2 + α * ∇²(v(x, y, t))]
+
+domains = [x ∈ Interval(x_min, x_max),
+    y ∈ Interval(y_min, y_max),
+    t ∈ Interval(t_min, t_max)]
+
+# Periodic BCs
+bcs = [u(x, y, 0) ~ u0(x, y, 0),
+    u(0, y, t) ~ u(1, y, t),
+    u(x, 0, t) ~ u(x, 1, t), v(x, y, 0) ~ v0(x, y, 0),
+    v(0, y, t) ~ v(1, y, t),
+    v(x, 0, t) ~ v(x, 1, t)]
+
+@named pdesys = PDESystem(eq, bcs, domains, [x, y, t], [u(x, y, t), v(x, y, t)])

\[ \begin{align} +\frac{\mathrm{d}}{\mathrm{d}t} u\left( x, y, t \right) =& 1 + 10 \left( \frac{\mathrm{d}}{\mathrm{d}x} \frac{\mathrm{d}}{\mathrm{d}x} u\left( x, y, t \right) + \frac{\mathrm{d}}{\mathrm{d}y} \frac{\mathrm{d}}{\mathrm{d}y} u\left( x, y, t \right) \right) - 4.4 u\left( x, y, t \right) + 5 \left( \left( -0.3 + x \right)^{2} + \left( -0.6 + y \right)^{2} \leq 0.01 \right) \left( t \geq 1.1 \right) + \left( u\left( x, y, t \right) \right)^{2} v\left( x, y, t \right) \\ +\frac{\mathrm{d}}{\mathrm{d}t} v\left( x, y, t \right) =& 10 \left( \frac{\mathrm{d}}{\mathrm{d}x} \frac{\mathrm{d}}{\mathrm{d}x} v\left( x, y, t \right) + \frac{\mathrm{d}}{\mathrm{d}y} \frac{\mathrm{d}}{\mathrm{d}y} v\left( x, y, t \right) \right) + 3.4 u\left( x, y, t \right) - \left( u\left( x, y, t \right) \right)^{2} v\left( x, y, t \right) +\end{align} + \]

Looks just like the LaTeX description, right? Now let's solve it.

Automated symbolic discretization with MethodOfLines.jl

Next we create the discretization. Here we will use the finite difference method via method of lines. Method of lines is a method of recognizing that a discretization of a partial differential equation transforms it into a new numerical problem. For example:

Discretization FormNumerical Problem Type
Finite Difference, Finite Volume, Finite Element, discretizing all variablesNonlinearProblem
Finite Difference, Finite Volume, Finite Element, discretizing all variables except timeODEProblem/DAEProblem
Physics-Informed Neural NetworkOptimizationProblem
Feynman-Kac FormulaSDEProblem
Universal Stochastic Differential Equation (High dimensional PDEs)OptimizationProblem inverse problem over SDEProblem

Thus the process of solving a PDE is fundamentally about transforming its symbolic form to a standard numerical problem and solving the standard numerical problem using one of the solvers in the SciML ecosystem! Here we will demonstrate one of the most classic methods: the finite difference method. Since the Brusselator is a time-dependent PDE with heavy stiffness in the time-domain, we will leave time undiscretized, which means that we will use the finite difference method in the x and y domains to obtain a representation of the equation at `u_i = u(x_i,y_i)grid point values, obtaining an ODEu_i' = \ldots that defines how the values at the grid points evolve over time.

To do this, we use the MOLFiniteDifference construct of MethodOfLines.jl as follows:

N = 32
+
+dx = (x_max - x_min) / N
+dy = (y_max - y_min) / N
+
+order = 2
+
+discretization = MOLFiniteDifference([x => dx, y => dy], t, approx_order = order,
+                                     grid_align = center_align)
MethodOfLines.MOLFiniteDifference{MethodOfLines.CenterAlignedGrid, MethodOfLines.ScalarizedDiscretization}(Dict{Symbolics.Num, Float64}(y => 0.03125, x => 0.03125), t, 2, MethodOfLines.UpwindScheme(1), MethodOfLines.CenterAlignedGrid(), true, false, MethodOfLines.ScalarizedDiscretization(), true, Any[], Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}())

Next, we discretize the system, converting the PDESystem in to an ODEProblem:

prob = discretize(pdesys, discretization);
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
+timespan: (0.0, 11.5)
+u0: 2048-element Vector{Float64}:
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ ⋮
+ 2.1921268033293604
+ 1.9075279151581102
+ 1.605464573318729
+ 1.2924521756218903
+ 0.9766542925609525
+ 0.668640545523243
+ 0.3829487927768564
+ 0.1422185904446023
+ 0.0

Solving the PDE

Now your problem can be solved with an appropriate ODE solver. This is just your standard DifferentialEquations.jl usage, though we'll return to this point in a bit to talk about efficiency:

sol = solve(prob, TRBDF2(), saveat = 0.1);
retcode: Success
+Interpolation: Dict{Symbolics.Num, Interpolations.GriddedInterpolation{Float64, 3, Array{Float64, 3}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}}}
+t: 116-element Vector{Float64}:
+  0.0
+  0.1
+  0.2
+  0.3
+  0.4
+  0.5
+  0.6
+  0.7
+  0.8
+  0.9
+  ⋮
+ 10.7
+ 10.8
+ 10.9
+ 11.0
+ 11.1
+ 11.2
+ 11.3
+ 11.4
+ 11.5ivs: 3-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
+ t
+ x
+ ydomain:([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9  …  10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5], 0.0:0.03125:1.0, 0.0:0.03125:1.0)
+u: Dict{Symbolics.Num, Array{Float64, 3}} with 2 entries:
+  u(x, y, t) => [0.0 0.115882 … 0.115882 0.0; 0.0 0.115882 … 0.115882 0.0; … ; …
+  v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

Examining Results via the Symbolic Solution Interface

Now that we have solved the ODE representation of the PDE, we have an PDETimeSeriesSolution that wraps an ODESolution, which we can get with sol.original_sol. If we look at the original sol, it represents $u_i' = \ldots$ at each of the grid points. If you check sol.original_sol.u inside the solution, that's those values... but that's not very helpful. How do you interpret original_sol[1]? How do you interpret original_sol[1,:]?

To make the handling of such cases a lot simpler, MethodOfLines.jl implements a symbolic interface for the solution object that allows for interpreting the computation through its original representation. For example, if we want to know how to interpret the values of the grid corresponding to the independent variables, we can just index using symbolic variables:

discrete_x = sol[x];
+discrete_y = sol[y];
+discrete_t = sol[t];
116-element Vector{Float64}:
+  0.0
+  0.1
+  0.2
+  0.3
+  0.4
+  0.5
+  0.6
+  0.7
+  0.8
+  0.9
+  ⋮
+ 10.7
+ 10.8
+ 10.9
+ 11.0
+ 11.1
+ 11.2
+ 11.3
+ 11.4
+ 11.5

What this tells us is that, for a solution at a given time point, say original_sol[1] for the solution at the initial time (the initial condition), the value original_sol[1][1] is the solution at the grid point (discrete_x[1], discrete_y[1]). For values that are not the initial time point, original_sol[i] corresponds to the solution at discrete_t[i].

But we also have two dependent variables, u and v. How do we interpret which of the results correspond to the different dependent variables? This is done by indexing the solution by the dependent variables! For example:

solu = sol[u(x, y, t)];
+solv = sol[v(x, y, t)];
33×33×116 Array{Float64, 3}:
+[:, :, 1] =
+ 0.0       0.0       0.0       0.0       …  0.0       0.0       0.0
+ 0.142219  0.142219  0.142219  0.142219     0.142219  0.142219  0.142219
+ 0.382949  0.382949  0.382949  0.382949     0.382949  0.382949  0.382949
+ 0.668641  0.668641  0.668641  0.668641     0.668641  0.668641  0.668641
+ 0.976654  0.976654  0.976654  0.976654     0.976654  0.976654  0.976654
+ 1.29245   1.29245   1.29245   1.29245   …  1.29245   1.29245   1.29245
+ 1.60546   1.60546   1.60546   1.60546      1.60546   1.60546   1.60546
+ 1.90753   1.90753   1.90753   1.90753      1.90753   1.90753   1.90753
+ 2.19213   2.19213   2.19213   2.19213      2.19213   2.19213   2.19213
+ 2.45397   2.45397   2.45397   2.45397      2.45397   2.45397   2.45397
+ ⋮                                       ⋱  ⋮                   
+ 2.19213   2.19213   2.19213   2.19213      2.19213   2.19213   2.19213
+ 1.90753   1.90753   1.90753   1.90753   …  1.90753   1.90753   1.90753
+ 1.60546   1.60546   1.60546   1.60546      1.60546   1.60546   1.60546
+ 1.29245   1.29245   1.29245   1.29245      1.29245   1.29245   1.29245
+ 0.976654  0.976654  0.976654  0.976654     0.976654  0.976654  0.976654
+ 0.668641  0.668641  0.668641  0.668641     0.668641  0.668641  0.668641
+ 0.382949  0.382949  0.382949  0.382949  …  0.382949  0.382949  0.382949
+ 0.142219  0.142219  0.142219  0.142219     0.142219  0.142219  0.142219
+ 0.0       0.0       0.0       0.0          0.0       0.0       0.0
+
+[:, :, 2] =
+ 0.0      2.02429  2.02429  2.02429  …  2.02429  2.02429  2.02429  2.02429
+ 2.02429  2.02429  2.02429  2.02429     2.02429  2.02429  2.02429  2.02429
+ 2.02428  2.02428  2.02428  2.02428     2.02428  2.02428  2.02428  2.02428
+ 2.02427  2.02427  2.02427  2.02427     2.02427  2.02427  2.02427  2.02427
+ 2.02426  2.02426  2.02426  2.02426     2.02426  2.02426  2.02426  2.02426
+ 2.02424  2.02424  2.02424  2.02424  …  2.02424  2.02424  2.02424  2.02424
+ 2.02422  2.02422  2.02422  2.02422     2.02422  2.02422  2.02422  2.02422
+ 2.0242   2.0242   2.0242   2.0242      2.0242   2.0242   2.0242   2.0242
+ 2.02418  2.02418  2.02418  2.02418     2.02418  2.02418  2.02418  2.02418
+ 2.02416  2.02416  2.02416  2.02416     2.02416  2.02416  2.02416  2.02416
+ ⋮                                   ⋱           ⋮                 
+ 2.02418  2.02418  2.02418  2.02418     2.02418  2.02418  2.02418  2.02418
+ 2.0242   2.0242   2.0242   2.0242   …  2.0242   2.0242   2.0242   2.0242
+ 2.02422  2.02422  2.02422  2.02422     2.02422  2.02422  2.02422  2.02422
+ 2.02424  2.02424  2.02424  2.02424     2.02424  2.02424  2.02424  2.02424
+ 2.02426  2.02426  2.02426  2.02426     2.02426  2.02426  2.02426  2.02426
+ 2.02427  2.02427  2.02427  2.02427     2.02427  2.02427  2.02427  2.02427
+ 2.02428  2.02428  2.02428  2.02428  …  2.02428  2.02428  2.02428  2.02428
+ 2.02429  2.02429  2.02429  2.02429     2.02429  2.02429  2.02429  2.02429
+ 2.02429  2.02429  2.02429  2.02429     2.02429  2.02429  2.02429  2.02429
+
+[:, :, 3] =
+ 0.0      2.0791   2.07909  2.07909  …  2.07909  2.07909  2.0791   2.0791
+ 2.0791   2.0791   2.0791   2.0791      2.0791   2.0791   2.0791   2.0791
+ 2.07911  2.07911  2.07911  2.07911     2.07911  2.07911  2.07911  2.07911
+ 2.07912  2.07912  2.07912  2.07912     2.07912  2.07912  2.07912  2.07912
+ 2.07914  2.07914  2.07914  2.07914     2.07914  2.07914  2.07914  2.07914
+ 2.07916  2.07916  2.07916  2.07916  …  2.07916  2.07916  2.07916  2.07916
+ 2.07919  2.07919  2.07919  2.07919     2.07919  2.07919  2.07919  2.07919
+ 2.07921  2.07921  2.07921  2.07921     2.07921  2.07921  2.07921  2.07921
+ 2.07924  2.07924  2.07924  2.07924     2.07924  2.07924  2.07924  2.07924
+ 2.07927  2.07927  2.07927  2.07927     2.07927  2.07927  2.07927  2.07927
+ ⋮                                   ⋱           ⋮                 
+ 2.07924  2.07924  2.07924  2.07924     2.07924  2.07924  2.07924  2.07924
+ 2.07921  2.07921  2.07921  2.07921  …  2.07921  2.07921  2.07921  2.07921
+ 2.07919  2.07919  2.07919  2.07919     2.07919  2.07919  2.07919  2.07919
+ 2.07916  2.07916  2.07916  2.07916     2.07916  2.07916  2.07916  2.07916
+ 2.07914  2.07914  2.07914  2.07914     2.07914  2.07914  2.07914  2.07914
+ 2.07912  2.07912  2.07912  2.07912     2.07912  2.07912  2.07912  2.07912
+ 2.07911  2.07911  2.07911  2.07911  …  2.07911  2.07911  2.07911  2.07911
+ 2.0791   2.0791   2.0791   2.0791      2.0791   2.0791   2.0791   2.0791
+ 2.0791   2.0791   2.07909  2.07909     2.07909  2.07909  2.0791   2.0791
+
+;;; … 
+
+[:, :, 114] =
+ 0.0      3.73422  3.73422  3.73423  …  3.73421  3.73422  3.73422  3.73422
+ 3.73422  3.73422  3.73422  3.73422     3.73421  3.73421  3.73422  3.73422
+ 3.73422  3.73422  3.73422  3.73422     3.73421  3.73421  3.73421  3.73422
+ 3.73421  3.73422  3.73422  3.73422     3.7342   3.73421  3.73421  3.73421
+ 3.73421  3.73421  3.73421  3.73422     3.7342   3.7342   3.73421  3.73421
+ 3.73421  3.73421  3.73421  3.73421  …  3.7342   3.7342   3.73421  3.73421
+ 3.73421  3.73421  3.73421  3.73421     3.73419  3.7342   3.7342   3.73421
+ 3.7342   3.73421  3.73421  3.73421     3.73419  3.7342   3.7342   3.7342
+ 3.7342   3.73421  3.73421  3.73421     3.73419  3.7342   3.7342   3.7342
+ 3.7342   3.73421  3.73421  3.73421     3.73419  3.7342   3.7342   3.7342
+ ⋮                                   ⋱           ⋮                 
+ 3.73423  3.73423  3.73423  3.73423     3.73422  3.73423  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423  …  3.73423  3.73423  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423     3.73423  3.73423  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423     3.73422  3.73423  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423     3.73422  3.73423  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423     3.73422  3.73422  3.73423  3.73423
+ 3.73423  3.73423  3.73423  3.73423  …  3.73422  3.73422  3.73422  3.73423
+ 3.73422  3.73423  3.73423  3.73423     3.73422  3.73422  3.73422  3.73422
+ 3.73422  3.73422  3.73422  3.73423     3.73421  3.73422  3.73422  3.73422
+
+[:, :, 115] =
+ 0.0      2.6786   2.6786   2.6786   …  2.67859  2.67859  2.67859  2.67859
+ 2.67859  2.67859  2.67859  2.67859     2.67858  2.67859  2.67859  2.67859
+ 2.67859  2.67859  2.67859  2.67859     2.67858  2.67858  2.67859  2.67859
+ 2.67859  2.67859  2.67859  2.67859     2.67857  2.67858  2.67858  2.67859
+ 2.67858  2.67858  2.67859  2.67859     2.67857  2.67858  2.67858  2.67858
+ 2.67858  2.67858  2.67858  2.67858  …  2.67857  2.67857  2.67858  2.67858
+ 2.67858  2.67858  2.67858  2.67858     2.67856  2.67857  2.67857  2.67858
+ 2.67858  2.67858  2.67858  2.67858     2.67856  2.67857  2.67857  2.67858
+ 2.67857  2.67858  2.67858  2.67858     2.67856  2.67857  2.67857  2.67857
+ 2.67857  2.67858  2.67858  2.67858     2.67856  2.67857  2.67857  2.67857
+ ⋮                                   ⋱           ⋮                 
+ 2.6786   2.6786   2.67861  2.67861     2.6786   2.6786   2.6786   2.6786
+ 2.6786   2.6786   2.67861  2.67861  …  2.6786   2.6786   2.6786   2.6786
+ 2.6786   2.67861  2.67861  2.67861     2.6786   2.6786   2.6786   2.6786
+ 2.6786   2.6786   2.67861  2.67861     2.6786   2.6786   2.6786   2.6786
+ 2.6786   2.6786   2.6786   2.67861     2.6786   2.6786   2.6786   2.6786
+ 2.6786   2.6786   2.6786   2.6786      2.67859  2.6786   2.6786   2.6786
+ 2.6786   2.6786   2.6786   2.6786   …  2.67859  2.67859  2.6786   2.6786
+ 2.6786   2.6786   2.6786   2.6786      2.67859  2.67859  2.67859  2.6786
+ 2.67859  2.6786   2.6786   2.6786      2.67859  2.67859  2.67859  2.67859
+
+[:, :, 116] =
+ 0.0      1.51629  1.51629  1.51629  …  1.51628  1.51629  1.51629  1.51629
+ 1.51629  1.51629  1.51629  1.51629     1.51628  1.51628  1.51629  1.51629
+ 1.51629  1.51629  1.51629  1.51629     1.51628  1.51628  1.51628  1.51629
+ 1.51628  1.51629  1.51629  1.51629     1.51628  1.51628  1.51628  1.51628
+ 1.51628  1.51628  1.51628  1.51629     1.51627  1.51628  1.51628  1.51628
+ 1.51628  1.51628  1.51628  1.51628  …  1.51627  1.51628  1.51628  1.51628
+ 1.51628  1.51628  1.51628  1.51628     1.51627  1.51627  1.51628  1.51628
+ 1.51628  1.51628  1.51628  1.51628     1.51627  1.51627  1.51628  1.51628
+ 1.51628  1.51628  1.51628  1.51628     1.51627  1.51627  1.51627  1.51628
+ 1.51628  1.51628  1.51628  1.51628     1.51627  1.51627  1.51627  1.51628
+ ⋮                                   ⋱           ⋮                 
+ 1.5163   1.5163   1.5163   1.5163      1.51629  1.51629  1.51629  1.5163
+ 1.5163   1.5163   1.5163   1.5163   …  1.51629  1.51629  1.51629  1.5163
+ 1.5163   1.5163   1.5163   1.5163      1.51629  1.51629  1.51629  1.5163
+ 1.5163   1.5163   1.5163   1.5163      1.51629  1.51629  1.51629  1.5163
+ 1.5163   1.5163   1.5163   1.5163      1.51629  1.51629  1.51629  1.5163
+ 1.51629  1.5163   1.5163   1.5163      1.51629  1.51629  1.51629  1.51629
+ 1.51629  1.51629  1.51629  1.51629  …  1.51629  1.51629  1.51629  1.51629
+ 1.51629  1.51629  1.51629  1.51629     1.51629  1.51629  1.51629  1.51629
+ 1.51629  1.51629  1.51629  1.51629     1.51628  1.51629  1.51629  1.51629

This then gives an array of results for the u and v separately, each dimension corresponding to the discrete form of the independent variables.

Using this high-level indexing, we can create an animation of the solution of the Brusselator as follows. For u we receive:

using Plots
+anim = @animate for k in 1:length(discrete_t)
+    heatmap(solu[2:end, 2:end, k], title = "$(discrete_t[k])") # 2:end since end = 1, periodic condition
+end
+gif(anim, "plots/Brusselator2Dsol_u.gif", fps = 8)

Brusselator2Dsol_u

and for v:

anim = @animate for k in 1:length(discrete_t)
+    heatmap(solv[2:end, 2:end, k], title = "$(discrete_t[k])")
+end
+gif(anim, "plots/Brusselator2Dsol_v.gif", fps = 8)

Brusselator2Dsol_v

Improving the Solution Process

Now, if all we needed was a single solution, then we're done. Budda bing budda boom, we got a solution, we're outta here. But if for example we're solving an inverse problem on a PDE, or we need to bump it up to higher accuracy, then we will need to make sure we solve this puppy more efficiently. So let's dive into how this can be done.

First of all, large PDEs generally are stiff and thus require an implicit solver. However, their stiffness is generally governed by a nonlinear system which as a sparse Jacobian. Handling that implicit system with sparsity is key to solving the system efficiently, so let's do that!

In order to enable such options, we simply need to pass the ModelingToolkit.jl problem construction options to the discretize call. This looks like:

# Analytical Jacobian expression and sparse Jacobian
+prob_sparse = discretize(pdesys, discretization; jac = true, sparse = true)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
+timespan: (0.0, 11.5)
+u0: 2048-element Vector{Float64}:
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ 0.11588181443634263
+ ⋮
+ 2.1921268033293604
+ 1.9075279151581102
+ 1.605464573318729
+ 1.2924521756218903
+ 0.9766542925609525
+ 0.668640545523243
+ 0.3829487927768564
+ 0.1422185904446023
+ 0.0

Now when we solve the problem it will be a lot faster. We can use BenchmarkTools.jl to assess this performance difference:

using BenchmarkTools
+@btime sol = solve(prob, TRBDF2(), saveat = 0.1);
+@btime sol = solve(prob_sparse, TRBDF2(), saveat = 0.1);
retcode: Success
+Interpolation: Dict{Symbolics.Num, Interpolations.GriddedInterpolation{Float64, 3, Array{Float64, 3}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}}}
+t: 116-element Vector{Float64}:
+  0.0
+  0.1
+  0.2
+  0.3
+  0.4
+  0.5
+  0.6
+  0.7
+  0.8
+  0.9
+  ⋮
+ 10.7
+ 10.8
+ 10.9
+ 11.0
+ 11.1
+ 11.2
+ 11.3
+ 11.4
+ 11.5ivs: 3-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
+ t
+ x
+ ydomain:([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9  …  10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5], 0.0:0.03125:1.0, 0.0:0.03125:1.0)
+u: Dict{Symbolics.Num, Array{Float64, 3}} with 2 entries:
+  u(x, y, t) => [0.0 0.115882 … 0.115882 0.0; 0.0 0.115882 … 0.115882 0.0; … ; …
+  v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

But we can further improve this as well. Instead of just using the default linear solver, we can change this to a Newton-Krylov method by passing in the GMRES method:

@btime sol = solve(prob_sparse, TRBDF2(linsolve = KrylovJL_GMRES()), saveat = 0.1);
retcode: Success
+Interpolation: Dict{Symbolics.Num, Interpolations.GriddedInterpolation{Float64, 3, Array{Float64, 3}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}}}
+t: 116-element Vector{Float64}:
+  0.0
+  0.1
+  0.2
+  0.3
+  0.4
+  0.5
+  0.6
+  0.7
+  0.8
+  0.9
+  ⋮
+ 10.7
+ 10.8
+ 10.9
+ 11.0
+ 11.1
+ 11.2
+ 11.3
+ 11.4
+ 11.5ivs: 3-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
+ t
+ x
+ ydomain:([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9  …  10.6, 10.7, 10.8, 10.9, 11.0, 11.1, 11.2, 11.3, 11.4, 11.5], 0.0:0.03125:1.0, 0.0:0.03125:1.0)
+u: Dict{Symbolics.Num, Array{Float64, 3}} with 2 entries:
+  u(x, y, t) => [0.0 0.115882 … 0.115882 0.0; 0.0 0.115882 … 0.115882 0.0; … ; …
+  v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

But to further improve performance, we can use an iLU preconditioner. This looks like as follows:

using IncompleteLU
+function incompletelu(W, du, u, p, t, newW, Plprev, Prprev, solverdata)
+    if newW === nothing || newW
+        Pl = ilu(convert(AbstractMatrix, W), τ = 50.0)
+    else
+        Pl = Plprev
+    end
+    Pl, nothing
+end
+
+@btime solve(prob_sparse,
+             TRBDF2(linsolve = KrylovJL_GMRES(), precs = incompletelu, concrete_jac = true),
+             save_everystep = false);
retcode: Success
+Interpolation: Dict{Symbolics.Num, Interpolations.GriddedInterpolation{Float64, 3, Array{Float64, 3}, Interpolations.Gridded{Interpolations.Linear{Interpolations.Throw{Interpolations.OnGrid}}}, Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}}}}
+t: 2-element Vector{Float64}:
+  0.0
+ 11.5ivs: 3-element Vector{SymbolicUtils.BasicSymbolic{Real}}:
+ t
+ x
+ ydomain:([0.0, 11.5], 0.0:0.03125:1.0, 0.0:0.03125:1.0)
+u: Dict{Symbolics.Num, Array{Float64, 3}} with 2 entries:
+  u(x, y, t) => [0.0 0.115882 … 0.115882 0.0; 0.0 0.115882 … 0.115882 0.0; … ; …
+  v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

And now we're zooming! For more information on these performance improvements, check out the deeper dive in the DifferentialEquations.jl tutorials.

If you're interested in figuring out what's the fastest current solver for this kind of PDE, check out the Brusselator benchmark in SciMLBenchmarks.jl

diff --git a/v1.5.0/showcase/gpu_spde/3adc1997.svg b/v1.5.0/showcase/gpu_spde/3adc1997.svg new file mode 100644 index 00000000000..03b275ea0ba --- /dev/null +++ b/v1.5.0/showcase/gpu_spde/3adc1997.svg @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/gpu_spde/56d2d928.svg b/v1.5.0/showcase/gpu_spde/56d2d928.svg new file mode 100644 index 00000000000..00a2f3af25a --- /dev/null +++ b/v1.5.0/showcase/gpu_spde/56d2d928.svg @@ -0,0 +1,1399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/gpu_spde/efaa6f6c.svg b/v1.5.0/showcase/gpu_spde/efaa6f6c.svg new file mode 100644 index 00000000000..608b5db460f --- /dev/null +++ b/v1.5.0/showcase/gpu_spde/efaa6f6c.svg @@ -0,0 +1,812 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/gpu_spde/index.html b/v1.5.0/showcase/gpu_spde/index.html new file mode 100644 index 00000000000..7e9250468f3 --- /dev/null +++ b/v1.5.0/showcase/gpu_spde/index.html @@ -0,0 +1,431 @@ + +GPU-Accelerated Stochastic Partial Differential Equations · Overview of Julia's SciML

GPU-Accelerated Stochastic Partial Differential Equations

Let's solve stochastic PDEs in Julia using GPU parallelism. To do this, we will use the type-genericness of the DifferentialEquations.jl library in order to write a code that uses within-method GPU-parallelism on the system of PDEs. The OrdinaryDiffEq.jl solvers of DifferentialEquations.jl, including implicit solvers with GMRES, etc., and the same for SDEs, DAEs, DDEs, etc. are all GPU-compatible with a fast form of broadcast.

Note

The non-native Julia solvers, like Sundials are incompatible with arbitrary input types and thus not compatible with GPUs.

Let's dive into showing how to accelerate ODE solving with GPUs!

Before we start: the two ways to accelerate ODE solvers with GPUs

Before we dive deeper, let us remark that there are two very different ways that one can accelerate an ODE solution with GPUs. There is one case where u is very big and f is very expensive, but very structured, and you use GPUs to accelerate the computation of said f. The other use case is where u is very small but you want to solve the ODE f over many different initial conditions (u0) or parameters p. In that case, you can use GPUs to parallelize over different parameters and initial conditions. In other words:

Type of ProblemSciML Solution
Accelerate a big ODEUse CUDA.jl's CuArray as u0
Solve the same ODE with many u0 and pUse DiffEqGPU.jl's EnsembleGPUArray and EnsembleGPUKernel

This showcase will focus on the former case. For the latter, see the massively parallel GPU ODE solving showcase.

Our Problem: 2-dimensional Reaction-Diffusion Equations

The reaction-diffusion equation is a PDE commonly handled in systems biology, which is a diffusion equation plus a nonlinear reaction term. The dynamics are defined as:

\[u_t = D \Delta u + f(t,u)\]

But this doesn't need to only have a single “reactant” u: this can be a vector of reactants and the $f$ is then the nonlinear vector equations describing how these different pieces react together. Let's settle on a specific equation to make this easier to explain. Let's use a simple model of a 3-component system where A can diffuse through space to bind with the non-diffusive B to form the complex C (also non-diffusive, assume B is too big and gets stuck in a cell which causes C=A+B to be stuck as well). Other than the binding, we make each of these undergo a simple birth-death process, and we write down the equations which result from mass-action kinetics. If this all is meaningless to you, just understand that it gives the system of PDEs:

\[\begin{align} +A_t &= D \Delta A + \alpha_A(x) - \beta_A A - r_1 A B + r_2 C\\ +B_t &= \alpha_B - \beta_B B - r_1 A B + r_2 C\\ +C_t &= \alpha_C - \beta_C C + r_1 A B - r_2 C +\end{align}\]

One addition that was made to the model is that we let $\alpha_A(x)$ be the production of $A$, and we let that be a function of space so that way it only is produced on one side of our equation. Let's make it a constant when x>80, and 0 otherwise, and let our spatial domain be $x \in [0,100]$ and $y \in [0,100]$.

This model is spatial: each reactant $u(t,x,y)$ is defined at each point in space, and all of the reactions are local, meaning that $f$ at spatial point $(x,y)$ only uses $u_i(t,x,y)$. This is an important fact which will come up later for parallelization.

Discretizing the PDE into ODEs

In order to solve this via a method of lines (MOL) approach, we need to discretize the PDE into a system of ODEs. Let's do a simple uniformly-spaced grid finite difference discretization. Choose $dx = 1$ and $dy = 1$ so that we have 100*100=10000 points for each reactant. Notice how fast that grows! Put the reactants in a matrix such that A[i,j] = A(x_j,y_i), i.e. the columns of the matrix are the $x$ values and the rows are the $y$ values (this way looking at the matrix is essentially like looking at the discretized space).

So now we have 3 matrices (A, B, and C) for our reactants. How do we discretize the PDE? In this case, the diffusion term simply becomes a tridiagonal matrix $M$ where $[1,-2,1]$ is the central band. You can notice that $MA$ performs diffusion along the columns of $A$, and so this is diffusion along the $y$. Similarly, $AM$ flips the indices and thus does diffusion along the rows of $A$ making this diffusion along $x$. Thus $D(M_yA + AM_x)$ is the discretized Laplacian (we could have separate diffusion constants and $dx \neq dy$ if we want by using different constants on the $M$, but let's not do that for this simple example. We leave that as an exercise for the reader). We enforced a Neumann boundary condition with zero derivative (also known as a no-flux boundary condition) by reflecting the changes over the boundary. Thus the derivative operator is generated as:

using LinearAlgebra
+
+# Define the constants for the PDE
+const α₂ = 1.0
+const α₃ = 1.0
+const β₁ = 1.0
+const β₂ = 1.0
+const β₃ = 1.0
+const r₁ = 1.0
+const r₂ = 1.0
+const D = 100.0
+const γ₁ = 0.1
+const γ₂ = 0.1
+const γ₃ = 0.1
+const N = 100
+const X = reshape([i for i in 1:100 for j in 1:100], N, N)
+const Y = reshape([j for i in 1:100 for j in 1:100], N, N)
+const α₁ = 1.0 .* (X .>= 80)
+
+const Mx = Tridiagonal([1.0 for i in 1:(N - 1)], [-2.0 for i in 1:N],
+                       [1.0 for i in 1:(N - 1)])
+const My = copy(Mx)
+# Do the reflections, different for x and y operators
+Mx[2, 1] = 2.0
+Mx[end - 1, end] = 2.0
+My[1, 2] = 2.0
+My[end, end - 1] = 2.0
2.0
Note

We could have also done these discretization steps using DiffEqOperators.jl or MethodOfLines.jl. However, we are going to keep it in this form, so we can show the full code, making it easier to see how to define GPU-ready code!

Since all of the reactions are local, we only have each point in space react separately. Thus this represents itself as element-wise equations on the reactants. Thus we can write it out quite simply. The ODE which then represents the PDE is thus in pseudo Julia code:

DA = D * (Mx * A + A * My)
+@. DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+@. α₂ - β₂ * B - r₁ * A * B + r₂ * C
+@. α₃ - β₃ * C + r₁ * A * B - r₂ * C

Note here that I am using α₁ as a matrix (or row-vector, since that will broadcast just fine) where every point in space with x<80 has this zero, and all of the others have it as a constant. The other coefficients are all scalars.

How do we do this with the ODE solver?

Our Representation via Views of 3-Tensors

We can represent our problem with a 3-dimensional tensor, taking each 2-dimensional slice as our (A,B,C). This means that we can define:

u0 = zeros(N, N, 3);
100×100×3 Array{Float64, 3}:
+[:, :, 1] =
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ ⋮                        ⋮              ⋱            ⋮                   
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+
+[:, :, 2] =
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ ⋮                        ⋮              ⋱            ⋮                   
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+
+[:, :, 3] =
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ ⋮                        ⋮              ⋱            ⋮                   
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  …  0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0
+ 0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0     0.0  0.0  0.0  0.0  0.0  0.0  0.0

Now we can decompose it like:

A = @view u[:, :, 1]
+B = @view u[:, :, 2]
+C = @view u[:, :, 3]
+dA = @view du[:, :, 1]
+dB = @view du[:, :, 2]
+dC = @view du[:, :, 3]

These views will not construct new arrays and will instead just be pointers to the (contiguous) memory pieces, so this is a nice and efficient way to handle this. Together, our ODE using this tensor as its container can be written as follows:

function f(du, u, p, t)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    DA = D * (Mx * A + A * My)
+    @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end
f (generic function with 1 method)

where this is using @. to do inplace updates on our du to say how the full tensor should update in time. Note that we can make this more efficient by adding some cache variables to the diffusion matrix multiplications and using mul!, but let's ignore that for now.

Together, the ODE which defines our PDE is thus:

using DifferentialEquations
+
+prob = ODEProblem(f, u0, (0.0, 100.0))
+@time sol = solve(prob, ROCK2());
retcode: Success
+Interpolation: 3rd order Hermite
+t: 125-element Vector{Float64}:
+   0.0
+   2.796123741859731e-5
+   6.437859112070983e-5
+   0.0001355696558501728
+   0.00023376199838581863
+   0.0003776022263950997
+   0.000565057887749957
+   0.0008071655660257587
+   0.0011053533031798865
+   0.001466685803229837
+   ⋮
+   7.947518012781672
+   9.216398069047099
+  11.048709859457816
+  13.932713724920005
+  18.815455951532602
+  27.10742394873848
+  43.60845467747508
+  74.75755579382653
+ 100.0
+u: 125-element Vector{Array{Float64, 3}}:
+ [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0]
+ [3.906344697357476e-10 3.909112473032509e-10 … 2.796119589268521e-5 2.7883165317332937e-5; 3.909112473032509e-10 3.911880248707541e-10 … 2.8039337179064475e-5 2.796119589268521e-5; … ; 3.909112473032509e-10 3.911880248707541e-10 … 2.8039337179064475e-5 2.796119589268521e-5; 3.906344697357476e-10 3.909112473032509e-10 … 2.796119589268521e-5 2.7883165317332937e-5;;; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.7961237409320334e-5 2.79612374093249e-5; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.796123740931577e-5 2.7961237409320334e-5; … ; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.796123740931577e-5 2.7961237409320334e-5; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.7961237409320334e-5 2.79612374093249e-5;;; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.796045559984408e-5 2.7960455599839515e-5; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.7960455599848643e-5 2.796045559984408e-5; … ; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.7960455599848643e-5 2.796045559984408e-5; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.796045559984408e-5 2.7960455599839515e-5]
+ [2.064777915080023e-9 2.07217804373864e-9 … 6.437748464989885e-5 6.396710057888366e-5; 2.07217804373864e-9 2.0796096029871125e-9 … 6.47908131237352e-5 6.437748464989885e-5; … ; 2.07217804373864e-9 2.0796096029871125e-9 … 6.47908131237352e-5 6.437748464989885e-5; 2.064777915080023e-9 2.07217804373864e-9 … 6.437748464989885e-5 6.396710057888366e-5;;; 6.437859104627274e-5 6.437859104627274e-5 … 6.437859095983186e-5 6.437859096018008e-5; 6.437859104627274e-5 6.437859104627273e-5 … 6.437859095948209e-5 6.437859095983186e-5; … ; 6.437859104627274e-5 6.437859104627273e-5 … 6.437859095948209e-5 6.437859095983186e-5; 6.437859104627274e-5 6.437859104627274e-5 … 6.437859095983186e-5 6.437859096018008e-5;;; 6.437444666658912e-5 6.437444666658914e-5 … 6.437444675303001e-5 6.43744467526818e-5; 6.437444666658914e-5 6.437444666658914e-5 … 6.437444675337979e-5 6.437444675303001e-5; … ; 6.437444666658914e-5 6.437444666658914e-5 … 6.437444675337979e-5 6.437444675303001e-5; 6.437444666658912e-5 6.437444666658914e-5 … 6.437444675303001e-5 6.43744467526818e-5]
+ [9.115090300876016e-9 9.18816509527637e-9 … 0.00013555878362043303 0.000133761104469766; 9.18816509527637e-9 9.262006848947153e-9 … 0.00013738531104727627 0.00013555878362043303; … ; 9.18816509527637e-9 9.262006848947153e-9 … 0.00013738531104727627 0.00013555878362043303; 9.115090300876016e-9 9.18816509527637e-9 … 0.00013555878362043303 0.000133761104469766;;; 0.00013556965510873605 0.00013556965510873586 … 0.00013556965429362562 0.00013556965430078604; 0.00013556965510873586 0.00013556965510873567 … 0.0001355696542863866 0.00013556965429362562; … ; 0.00013556965510873586 0.00013556965510873567 … 0.0001355696542863866 0.00013556965429362562; 0.00013556965510873605 0.00013556965510873586 … 0.00013556965429362562 0.00013556965430078604;;; 0.0001355512782014618 0.000135551278201462 … 0.00013555127901657225 0.00013555127900941182; 0.000135551278201462 0.0001355512782014622 … 0.00013555127902381128 0.00013555127901657225; … ; 0.000135551278201462 0.0001355512782014622 … 0.00013555127902381128 0.00013555127901657225; 0.0001355512782014618 0.000135551278201462 … 0.00013555127901657225 0.00013555127900941182]
+ [2.6926897581315367e-8 2.7313507714770143e-8 … 0.00023370489649268138 0.00022845315379793862; 2.7313507714770143e-8 2.7707718844309493e-8 … 0.0002391075039605557 0.00023370489649268138; … ; 2.7313507714770143e-8 2.7707718844309493e-8 … 0.0002391075039605557 0.00023370489649268138; 2.6926897581315367e-8 2.7313507714770143e-8 … 0.00023370489649268138 0.00022845315379793862;;; 0.00023376199441293072 0.00023376199441292722 … 0.0002337619902052695 0.00023376199027161357; 0.00023376199441292722 0.00023376199441292367 … 0.00023376199013754758 0.0002337619902052695; … ; 0.00023376199441292722 0.00023376199441292367 … 0.00023376199013754758 0.0002337619902052695; 0.00023376199441293072 0.00023376199441292722 … 0.0002337619902052695 0.00023376199027161357;;; 0.00023370736165976154 0.0002337073616597651 … 0.00023370736586742275 0.0002337073658010787; 0.0002337073616597651 0.0002337073616597686 … 0.0002337073659351447 0.00023370736586742275; … ; 0.0002337073616597651 0.0002337073616597686 … 0.0002337073659351447 0.00023370736586742275; 0.00023370736165976154 0.0002337073616597651 … 0.00023370736586742275 0.0002337073658010787]
+ [6.961732292649316e-8 7.124591837656885e-8 … 0.00037736420948259527 0.0003640011486945887; 7.124591837656885e-8 7.292787278493182e-8 … 0.0003913522086821116 0.00037736420948259527; … ; 7.124591837656885e-8 7.292787278493182e-8 … 0.0003913522086821116 0.00037736420948259527; 6.961732292649316e-8 7.124591837656885e-8 … 0.00037736420948259527 0.0003640011486945887;;; 0.0003776022093504568 0.0003776022093504163 … 0.00037760219156997705 0.00037760219202269337; 0.0003776022093504163 0.0003776022093503748 … 0.000377602191101566 0.00037760219156997705; … ; 0.0003776022093504163 0.0003776022093503748 … 0.000377602191101566 0.00037760219156997705; 0.0003776022093504568 0.0003776022093504163 … 0.00037760219156997705 0.00037760219202269337;;; 0.00037745967704351697 0.00037745967704355747 … 0.00037745969482399675 0.0003774596943712805; 0.00037745967704355747 0.00037745967704359894 … 0.00037745969529240787 0.00037745969482399675; … ; 0.00037745967704355747 0.00037745967704359894 … 0.00037745969529240787 0.00037745969482399675; 0.00037745967704351697 0.00037745967704355747 … 0.00037745969482399675 0.0003774596943712805]
+ [1.540579894733325e-7 1.5945566561169678e-7 … 0.0005642799709081393 0.0005353147081300882; 1.5945566561169678e-7 1.6512254090905263e-7 … 0.0005952708190357286 0.0005642799709081393; … ; 1.5945566561169678e-7 1.6512254090905263e-7 … 0.0005952708190357286 0.0005642799709081393; 1.540579894733325e-7 1.5945566561169678e-7 … 0.0005642799709081393 0.0005353147081300882;;; 0.0005650578298830339 0.0005650578298827208 … 0.000565057770205711 0.0005650577724579198; 0.0005650578298827208 0.0005650578298823957 … 0.0005650577678343024 0.000565057770205711; … ; 0.0005650578298827208 0.0005650578298823957 … 0.0005650577678343024 0.000565057770205711; 0.0005650578298830339 0.0005650578298827208 … 0.000565057770205711 0.0005650577724579198;;; 0.0005647387130703668 0.0005647387130706799 … 0.0005647387727476897 0.0005647387704954811; 0.0005647387130706799 0.0005647387130710051 … 0.0005647387751190984 0.0005647387727476897; … ; 0.0005647387130706799 0.0005647387130710051 … 0.0005647387751190984 0.0005647387727476897; 0.0005647387130703668 0.0005647387130706799 … 0.0005647387727476897 0.0005647387704954811]
+ [3.0969738789168484e-7 3.2507995129791364e-7 … 0.0008049880902276838 0.0007482706516369002; 3.2507995129791364e-7 3.415619008018545e-7 … 0.0008673145106382796 0.0008049880902276838; … ; 3.2507995129791364e-7 3.415619008018545e-7 … 0.0008673145106382796 0.0008049880902276838; 3.0969738789168484e-7 3.2507995129791364e-7 … 0.0008049880902276838 0.0007482706516369002;;; 0.0008071653959737827 0.0008071653959719099 … 0.0008071652219566872 0.0008071652311307488; 0.0008071653959719099 0.0008071653959699315 … 0.0008071652120858652 0.0008071652219566872; … ; 0.0008071653959719099 0.0008071653959699315 … 0.0008071652120858652 0.0008071652219566872; 0.0008071653959737827 0.0008071653959719099 … 0.0008071652219566872 0.0008071652311307488;;; 0.0008065143898932863 0.0008065143898951592 … 0.0008065145639103818 0.0008065145547363204; 0.0008065143898951592 0.0008065143898971374 … 0.0008065145737812039 0.0008065145639103818; … ; 0.0008065143898951592 0.0008065143898971374 … 0.0008065145737812039 0.0008065145639103818; 0.0008065143898932863 0.0008065143898951592 … 0.0008065145639103818 0.0008065145547363204]
+ [5.705076773905195e-7 6.087951811632106e-7 … 0.0011000514541360741 0.0009988289301903872; 6.087951811632106e-7 6.508085123006421e-7 … 0.0012147497953614846 0.0011000514541360741; … ; 6.087951811632106e-7 6.508085123006421e-7 … 0.0012147497953614846 0.0011000514541360741; 5.705076773905195e-7 6.087951811632106e-7 … 0.0011000514541360741 0.0009988289301903872;;; 0.0011053528638517067 0.001105352863842754 … 0.0011053524171780035 0.0011053524484369427; 0.001105352863842754 0.0011053528638331044 … 0.0011053523826827932 0.0011053524171780035; … ; 0.001105352863842754 0.0011053528638331044 … 0.0011053523826827932 0.0011053524171780035; 0.0011053528638517067 0.001105352863842754 … 0.0011053524171780035 0.0011053524484369427;;; 0.001104132375968241 0.0011041323759771937 … 0.0011041328226419442 0.0011041327913830052; 0.0011041323759771937 0.0011041323759868433 … 0.0011041328571371547 0.0011041328226419442; … ; 0.0011041323759771937 0.0011041323759868433 … 0.0011041328571371547 0.0011041328226419442; 0.001104132375968241 0.0011041323759771937 … 0.0011041328226419442 0.0011041327913830052]
+ [9.837734761082027e-7 1.069728314870665e-6 … 0.0014550919403635942 0.001286939535979884; 1.069728314870665e-6 1.1666270528831613e-6 … 0.0016522401555657791 0.0014550919403635942; … ; 1.069728314870665e-6 1.1666270528831613e-6 … 0.0016522401555657791 0.0014550919403635942; 9.837734761082027e-7 1.069728314870665e-6 … 0.0014550919403635942 0.001286939535979884;;; 0.0014666847725153 0.0014666847724792008 … 0.0014666837305651816 0.0014666838235512587; 0.0014666847724792008 0.0014666847724393811 … 0.0014666836249749018 0.0014666837305651816; … ; 0.0014666847724792008 0.0014666847724393811 … 0.0014666836249749018 0.0014666837305651816; 0.0014666847725153 0.0014666847724792008 … 0.0014666837305651816 0.0014666838235512587;;; 0.001464536697606192 0.0014645366976422912 … 0.0014645377395563106 0.0014645376465702335; 0.0014645366976422912 0.001464536697682111 … 0.0014645378451465904 0.0014645377395563106; … ; 0.0014645366976422912 0.001464536697682111 … 0.0014645378451465904 0.0014645377395563106; 0.001464536697606192 0.0014645366976422912 … 0.0014645377395563106 0.0014645376465702335]
+ ⋮
+ [0.08609805841448885 0.17043647380897894 … 0.5253487807766108 0.26537934143299924; 0.17043632606964465 0.33827122544680704 … 1.0431153649870897 0.5255803265135008; … ; 0.17043632606993778 0.33827122545075483 … 1.0431153649940519 0.5255803265114518; 0.0860980584164456 0.1704364738036493 … 0.5253487807791457 0.26537934143072245;;; 1.4373252284252587 1.3815140561336918 … 1.1874256906451954 1.3236301768644854; 1.381514149094787 1.282410462486973 … 0.9854451339241563 1.187316859958651; … ; 1.3815141490947984 1.2824104624869814 … 0.985445133924186 1.1873168599586434; 1.4373252284252651 1.381514056133681 … 1.1874256906452056 1.3236301768644814;;; 0.5618219481395771 0.617633120431141 … 0.8117214859196411 0.6755169997003484; 0.6176330274700476 0.7167367140778601 … 1.0137020426406766 0.8118303166061864; … ; 0.6176330274700379 0.7167367140778521 … 1.013702042640648 0.811830316606193; 0.5618219481395706 0.6176331204311543 … 0.8117214859196324 0.6755169997003547]
+ [0.08611716284636785 0.1704746875759635 … 0.5254093392748143 0.26540962380931715; 0.17047453796773276 0.3383476574354815 … 1.0432364899869457 0.5256408959749768; … ; 0.17047453797553302 0.33834765742835987 … 1.0432364899764301 0.5256408960020937; 0.08611716284038229 0.17047468757916076 … 0.5254093392661157 0.26540962379923955;;; 1.4378006045760183 1.3819336252553422 … 1.18773425720817 1.3240275973003504; 1.3819337199879635 1.2827436621439265 … 0.9856521249815722 1.187625374811168; … ; 1.3819337199879833 1.2827436621439123 … 0.985652124981564 1.1876253748112293; 1.4378006045760032 1.381933625255349 … 1.1877342572081317 1.3240275973003257;;; 0.5618903141179039 0.6177572934385748 … 0.8119566614857493 0.675663321393566; 0.6177571987059567 0.7169472565499952 … 1.0140387937123465 0.81206554388275; … ; 0.6177571987059367 0.7169472565500083 … 1.0140387937123552 0.8120655438826886; 0.5618903141179188 0.6177572934385721 … 0.8119566614857862 0.6756633213935938]
+ [0.08612424654708097 0.17048885417543524 … 0.5254313531349682 0.26542063413877076; 0.17048870386588985 0.3383759883706147 … 1.0432805110757877 0.5256629134457393; … ; 0.170488703884439 0.33837598835742216 … 1.0432805110973677 0.5256629134235756; 0.08612424653806508 0.1704888541769625 … 0.5254313531595093 0.2654206341270826;;; 1.4379761857637117 1.3820885642569771 … 1.187848575254819 1.3241746260446023; 1.3820886597402475 1.282866672089754 … 0.9857290285708314 1.1877396740994512; … ; 1.3820886597402842 1.282866672089726 … 0.9857290285708875 1.187739674099377; 1.4379761857636837 1.3820885642569687 … 1.1878485752548558 1.3241746260445473;;; 0.5619155910916513 0.6178032125983852 … 0.8120432016005394 0.6757171508107606; 0.617803117115112 0.7170251047656121 … 1.0141627482845308 0.8121521027559123; … ; 0.6178031171150765 0.7170251047656395 … 1.014162748284476 0.8121521027559846; 0.561915591091679 0.6178032125983928 … 0.8120432016005025 0.6757171508108165]
+ [0.08612614505229817 0.17049265173033532 … 0.5254371206649849 0.26542351829363214; 0.17049250123957818 0.33838358348745023 … 1.0432920460466648 0.5256686816795856; … ; 0.17049250124753992 0.33838358348904124 … 1.0432920461154893 0.525668681756715; 0.08612614505402293 0.17049265172194183 … 0.5254371205976006 0.2654235182581309;;; 1.438021748281357 1.3821288252436945 … 1.187878416207984 1.3242128480702355; 1.3821289209378569 1.2828987701027135 … 0.9857493588369103 1.1877695102365726; … ; 1.3821289209378944 1.2828987701026977 … 0.9857493588368392 1.1877695102366979; 1.438021748281391 1.3821288252436945 … 1.1878784162078508 1.3242128480701005;;; 0.5619220947768526 0.6178150178145252 … 0.8120654268502244 0.6757309949879838; 0.6178149221203557 0.7170450729555038 … 1.0141944842213038 0.8121743328216273; … ; 0.6178149221203226 0.7170450729555157 … 1.0141944842213717 0.8121743328215018; 0.5619220947768176 0.6178150178145267 … 0.8120654268503701 0.6757309949881167]
+ [0.08612634833961608 0.17049305911570686 … 0.525437644079961 0.26542377902246334; 0.170492908574816 0.33838439808113263 … 1.0432930934301377 0.5256692048869787; … ; 0.17049290811777018 0.3383843988515875 … 1.0432930950736503 0.5256692045561501; 0.08612634859699825 0.17049305865575506 … 0.52543764304871 0.26542377919106236;;; 1.4380264806956427 1.3821330324299592 … 1.1878815936563463 1.3242168995948893; 1.3821331281551719 1.2829020891783252 … 0.985751330092647 1.187772687201552; … ; 1.3821331281541414 1.2829020891797156 … 0.9857513300952706 1.1877726872013452; 1.4380264806960608 1.3821330324291468 … 1.187881593654247 1.324216899594847;;; 0.5619227864033625 0.6178162346690312 … 0.8120676734426134 0.6757323675040384; 0.6178161389438078 0.7170471779206645 … 1.014197937006328 0.8121765798974236; … ; 0.6178161389448378 0.7170471779192793 … 1.0141979370037266 0.8121765798976581; 0.5619227864028657 0.6178162346698169 … 0.8120676734446789 0.6757323675041291]
+ [0.08612696881535002 0.17049430008770006 … 0.5254400839401973 0.26542499883980797; 0.170494149747826 0.3383868781331526 … 1.043297972434291 0.5256716472137475; … ; 0.17049414848785427 0.3383868800692405 … 1.0432979719282864 0.52567164581839; 0.08612696959032942 0.17049429917277514 … 0.5254400849702624 0.2654249990031393;;; 1.4380418735122498 1.3821466102181006 … 1.1878911197364868 1.3242294633193916; 1.3821467059262218 1.2829128644454508 … 0.9857575482591076 1.1877822109670015; … ; 1.382146705923879 1.282912864448529 … 0.9857575482563709 1.1877822109628993; 1.438041873513753 1.3821466102173778 … 1.1878911197399622 1.3242294633199276;;; 0.5619250181568558 0.6178202814509923 … 0.8120757719326805 0.6757374283497037; 0.6178201857429156 0.7170540272235062 … 1.0142093434101023 0.8121846807021841; … ; 0.6178201857451067 0.7170540272203798 … 1.0142093434128474 0.8121846807062801; 0.5619250181553251 0.6178202814519933 … 0.8120757719293283 0.6757374283492548]
+ [0.08612922537590663 0.17049880553970603 … 0.5254468170856988 0.2654283605002894; 0.17049865619637367 0.33839589998903513 … 1.043311422996803 0.5256783789152208; … ; 0.17049865611834927 0.3383958965948585 … 1.043311416465437 0.5256783762610793; 0.08612922431900134 0.17049880862316633 … 0.5254468158063551 0.2654283641164176;;; 1.4380984980643825 1.3821966010088347 … 1.1879282918441725 1.324277069412198; 1.3821966970513817 1.2829525933075199 … 0.9857827134934911 1.1878193774451082; … ; 1.382196697050343 1.2829525933000296 … 0.9857827134871916 1.1878193774373935; 1.4380984980634006 1.382196601018273 … 1.1879282918421388 1.3242770694226238;;; 0.5619331295432555 0.6178350266002102 … 0.8121033357642147 0.6757545581965154; 0.6178349305571488 0.717079034301209 … 1.0142489141146822 0.8122122501630371; … ; 0.6178349305587992 0.7170790343094964 … 1.0142489141216229 0.8122122501706001; 0.5619331295443876 0.6178350265912546 … 0.8121033357659547 0.6757545581856481]
+ [0.08612916289874369 0.17049870555794155 … 0.5254465298681716 0.26542821481760537; 0.1704985446634098 0.3383956470925995 … 1.0433108263607662 0.5256780918573387; … ; 0.1704985431157662 0.3383956606328835 … 1.043310830082979 0.5256780922557244; 0.08612916976707674 0.17049869290665864 … 0.5254465229505567 0.2654282135126806;;; 1.4380968996603225 1.382195187537549 … 1.1879273351803625 1.3242757919077506; 1.382195283666662 1.2829514630948973 … 0.985782108927835 1.1878184211149487; … ; 1.3821952836761753 1.2829514631315213 … 0.9857821088892916 1.1878184211173373; 1.4380968996762014 1.3821951874955116 … 1.1879273351678405 1.3242757919007564;;; 0.5619328997334134 0.6178346118587885 … 0.8121024642121145 0.6757540074905293; 0.6178345157271027 0.7170783362984251 … 1.014247690465932 0.8122113782805697; … ; 0.6178345157204921 0.7170783362589533 … 1.014247690503209 0.8122113782778801; 0.5619328997173723 0.6178346118966905 … 0.8121024642260316 0.6757540074954401]
+ [0.08612859127580082 0.17049753160171222 … 0.5254451033087721 0.2654275139153849; 0.17049737712645266 0.3383933506216603 … 1.0433079952861508 0.5256766590950411; … ; 0.17049738447304252 0.3383933541276276 … 1.043307974168319 0.525676692339815; 0.08612858333303658 0.17049752682484845 … 0.5254451132469781 0.26542750243477514;;; 1.438083476814153 1.3821833871353062 … 1.1879183610904311 1.324264371017305; 1.3821834831435538 1.2829421710750641 … 0.9857759837772998 1.1878094482264425; … ; 1.3821834831725104 1.2829421710886368 … 0.9857759837559232 1.1878094483020714; 1.4380834767926478 1.3821833871175564 … 1.1879183610832111 1.3242643709998836;;; 0.5619309119155712 0.6178310015970299 … 0.8120960276405288 0.6757500177170583; 0.6178309055900693 0.7170722176531644 … 1.0142384049550173 0.8122049405079206; … ; 0.617830905560228 0.7170722176404384 … 1.0142384049773085 0.8122049404304051; 0.5619309119422641 0.6178310016132098 … 0.8120960276490696 0.6757500177298977]
@time sol = solve(prob, ROCK2());
retcode: Success
+Interpolation: 3rd order Hermite
+t: 125-element Vector{Float64}:
+   0.0
+   2.796123741859731e-5
+   6.437859112070983e-5
+   0.0001355696558501728
+   0.00023376199838581863
+   0.0003776022263950997
+   0.000565057887749957
+   0.0008071655660257587
+   0.0011053533031798865
+   0.001466685803229837
+   ⋮
+   7.947518012781672
+   9.216398069047099
+  11.048709859457816
+  13.932713724920005
+  18.815455951532602
+  27.10742394873848
+  43.60845467747508
+  74.75755579382653
+ 100.0
+u: 125-element Vector{Array{Float64, 3}}:
+ [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0]
+ [3.906344697357476e-10 3.909112473032509e-10 … 2.796119589268521e-5 2.7883165317332937e-5; 3.909112473032509e-10 3.911880248707541e-10 … 2.8039337179064475e-5 2.796119589268521e-5; … ; 3.909112473032509e-10 3.911880248707541e-10 … 2.8039337179064475e-5 2.796119589268521e-5; 3.906344697357476e-10 3.909112473032509e-10 … 2.796119589268521e-5 2.7883165317332937e-5;;; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.7961237409320334e-5 2.79612374093249e-5; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.796123740931577e-5 2.7961237409320334e-5; … ; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.796123740931577e-5 2.7961237409320334e-5; 2.7961237415829508e-5 2.7961237415829508e-5 … 2.7961237409320334e-5 2.79612374093249e-5;;; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.796045559984408e-5 2.7960455599839515e-5; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.7960455599848643e-5 2.796045559984408e-5; … ; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.7960455599848643e-5 2.796045559984408e-5; 2.7960455593334905e-5 2.7960455593334905e-5 … 2.796045559984408e-5 2.7960455599839515e-5]
+ [2.064777915080023e-9 2.07217804373864e-9 … 6.437748464989885e-5 6.396710057888366e-5; 2.07217804373864e-9 2.0796096029871125e-9 … 6.47908131237352e-5 6.437748464989885e-5; … ; 2.07217804373864e-9 2.0796096029871125e-9 … 6.47908131237352e-5 6.437748464989885e-5; 2.064777915080023e-9 2.07217804373864e-9 … 6.437748464989885e-5 6.396710057888366e-5;;; 6.437859104627274e-5 6.437859104627274e-5 … 6.437859095983186e-5 6.437859096018008e-5; 6.437859104627274e-5 6.437859104627273e-5 … 6.437859095948209e-5 6.437859095983186e-5; … ; 6.437859104627274e-5 6.437859104627273e-5 … 6.437859095948209e-5 6.437859095983186e-5; 6.437859104627274e-5 6.437859104627274e-5 … 6.437859095983186e-5 6.437859096018008e-5;;; 6.437444666658912e-5 6.437444666658914e-5 … 6.437444675303001e-5 6.43744467526818e-5; 6.437444666658914e-5 6.437444666658914e-5 … 6.437444675337979e-5 6.437444675303001e-5; … ; 6.437444666658914e-5 6.437444666658914e-5 … 6.437444675337979e-5 6.437444675303001e-5; 6.437444666658912e-5 6.437444666658914e-5 … 6.437444675303001e-5 6.43744467526818e-5]
+ [9.115090300876016e-9 9.18816509527637e-9 … 0.00013555878362043303 0.000133761104469766; 9.18816509527637e-9 9.262006848947153e-9 … 0.00013738531104727627 0.00013555878362043303; … ; 9.18816509527637e-9 9.262006848947153e-9 … 0.00013738531104727627 0.00013555878362043303; 9.115090300876016e-9 9.18816509527637e-9 … 0.00013555878362043303 0.000133761104469766;;; 0.00013556965510873605 0.00013556965510873586 … 0.00013556965429362562 0.00013556965430078604; 0.00013556965510873586 0.00013556965510873567 … 0.0001355696542863866 0.00013556965429362562; … ; 0.00013556965510873586 0.00013556965510873567 … 0.0001355696542863866 0.00013556965429362562; 0.00013556965510873605 0.00013556965510873586 … 0.00013556965429362562 0.00013556965430078604;;; 0.0001355512782014618 0.000135551278201462 … 0.00013555127901657225 0.00013555127900941182; 0.000135551278201462 0.0001355512782014622 … 0.00013555127902381128 0.00013555127901657225; … ; 0.000135551278201462 0.0001355512782014622 … 0.00013555127902381128 0.00013555127901657225; 0.0001355512782014618 0.000135551278201462 … 0.00013555127901657225 0.00013555127900941182]
+ [2.6926897581315367e-8 2.7313507714770143e-8 … 0.00023370489649268138 0.00022845315379793862; 2.7313507714770143e-8 2.7707718844309493e-8 … 0.0002391075039605557 0.00023370489649268138; … ; 2.7313507714770143e-8 2.7707718844309493e-8 … 0.0002391075039605557 0.00023370489649268138; 2.6926897581315367e-8 2.7313507714770143e-8 … 0.00023370489649268138 0.00022845315379793862;;; 0.00023376199441293072 0.00023376199441292722 … 0.0002337619902052695 0.00023376199027161357; 0.00023376199441292722 0.00023376199441292367 … 0.00023376199013754758 0.0002337619902052695; … ; 0.00023376199441292722 0.00023376199441292367 … 0.00023376199013754758 0.0002337619902052695; 0.00023376199441293072 0.00023376199441292722 … 0.0002337619902052695 0.00023376199027161357;;; 0.00023370736165976154 0.0002337073616597651 … 0.00023370736586742275 0.0002337073658010787; 0.0002337073616597651 0.0002337073616597686 … 0.0002337073659351447 0.00023370736586742275; … ; 0.0002337073616597651 0.0002337073616597686 … 0.0002337073659351447 0.00023370736586742275; 0.00023370736165976154 0.0002337073616597651 … 0.00023370736586742275 0.0002337073658010787]
+ [6.961732292649316e-8 7.124591837656885e-8 … 0.00037736420948259527 0.0003640011486945887; 7.124591837656885e-8 7.292787278493182e-8 … 0.0003913522086821116 0.00037736420948259527; … ; 7.124591837656885e-8 7.292787278493182e-8 … 0.0003913522086821116 0.00037736420948259527; 6.961732292649316e-8 7.124591837656885e-8 … 0.00037736420948259527 0.0003640011486945887;;; 0.0003776022093504568 0.0003776022093504163 … 0.00037760219156997705 0.00037760219202269337; 0.0003776022093504163 0.0003776022093503748 … 0.000377602191101566 0.00037760219156997705; … ; 0.0003776022093504163 0.0003776022093503748 … 0.000377602191101566 0.00037760219156997705; 0.0003776022093504568 0.0003776022093504163 … 0.00037760219156997705 0.00037760219202269337;;; 0.00037745967704351697 0.00037745967704355747 … 0.00037745969482399675 0.0003774596943712805; 0.00037745967704355747 0.00037745967704359894 … 0.00037745969529240787 0.00037745969482399675; … ; 0.00037745967704355747 0.00037745967704359894 … 0.00037745969529240787 0.00037745969482399675; 0.00037745967704351697 0.00037745967704355747 … 0.00037745969482399675 0.0003774596943712805]
+ [1.540579894733325e-7 1.5945566561169678e-7 … 0.0005642799709081393 0.0005353147081300882; 1.5945566561169678e-7 1.6512254090905263e-7 … 0.0005952708190357286 0.0005642799709081393; … ; 1.5945566561169678e-7 1.6512254090905263e-7 … 0.0005952708190357286 0.0005642799709081393; 1.540579894733325e-7 1.5945566561169678e-7 … 0.0005642799709081393 0.0005353147081300882;;; 0.0005650578298830339 0.0005650578298827208 … 0.000565057770205711 0.0005650577724579198; 0.0005650578298827208 0.0005650578298823957 … 0.0005650577678343024 0.000565057770205711; … ; 0.0005650578298827208 0.0005650578298823957 … 0.0005650577678343024 0.000565057770205711; 0.0005650578298830339 0.0005650578298827208 … 0.000565057770205711 0.0005650577724579198;;; 0.0005647387130703668 0.0005647387130706799 … 0.0005647387727476897 0.0005647387704954811; 0.0005647387130706799 0.0005647387130710051 … 0.0005647387751190984 0.0005647387727476897; … ; 0.0005647387130706799 0.0005647387130710051 … 0.0005647387751190984 0.0005647387727476897; 0.0005647387130703668 0.0005647387130706799 … 0.0005647387727476897 0.0005647387704954811]
+ [3.0969738789168484e-7 3.2507995129791364e-7 … 0.0008049880902276838 0.0007482706516369002; 3.2507995129791364e-7 3.415619008018545e-7 … 0.0008673145106382796 0.0008049880902276838; … ; 3.2507995129791364e-7 3.415619008018545e-7 … 0.0008673145106382796 0.0008049880902276838; 3.0969738789168484e-7 3.2507995129791364e-7 … 0.0008049880902276838 0.0007482706516369002;;; 0.0008071653959737827 0.0008071653959719099 … 0.0008071652219566872 0.0008071652311307488; 0.0008071653959719099 0.0008071653959699315 … 0.0008071652120858652 0.0008071652219566872; … ; 0.0008071653959719099 0.0008071653959699315 … 0.0008071652120858652 0.0008071652219566872; 0.0008071653959737827 0.0008071653959719099 … 0.0008071652219566872 0.0008071652311307488;;; 0.0008065143898932863 0.0008065143898951592 … 0.0008065145639103818 0.0008065145547363204; 0.0008065143898951592 0.0008065143898971374 … 0.0008065145737812039 0.0008065145639103818; … ; 0.0008065143898951592 0.0008065143898971374 … 0.0008065145737812039 0.0008065145639103818; 0.0008065143898932863 0.0008065143898951592 … 0.0008065145639103818 0.0008065145547363204]
+ [5.705076773905195e-7 6.087951811632106e-7 … 0.0011000514541360741 0.0009988289301903872; 6.087951811632106e-7 6.508085123006421e-7 … 0.0012147497953614846 0.0011000514541360741; … ; 6.087951811632106e-7 6.508085123006421e-7 … 0.0012147497953614846 0.0011000514541360741; 5.705076773905195e-7 6.087951811632106e-7 … 0.0011000514541360741 0.0009988289301903872;;; 0.0011053528638517067 0.001105352863842754 … 0.0011053524171780035 0.0011053524484369427; 0.001105352863842754 0.0011053528638331044 … 0.0011053523826827932 0.0011053524171780035; … ; 0.001105352863842754 0.0011053528638331044 … 0.0011053523826827932 0.0011053524171780035; 0.0011053528638517067 0.001105352863842754 … 0.0011053524171780035 0.0011053524484369427;;; 0.001104132375968241 0.0011041323759771937 … 0.0011041328226419442 0.0011041327913830052; 0.0011041323759771937 0.0011041323759868433 … 0.0011041328571371547 0.0011041328226419442; … ; 0.0011041323759771937 0.0011041323759868433 … 0.0011041328571371547 0.0011041328226419442; 0.001104132375968241 0.0011041323759771937 … 0.0011041328226419442 0.0011041327913830052]
+ [9.837734761082027e-7 1.069728314870665e-6 … 0.0014550919403635942 0.001286939535979884; 1.069728314870665e-6 1.1666270528831613e-6 … 0.0016522401555657791 0.0014550919403635942; … ; 1.069728314870665e-6 1.1666270528831613e-6 … 0.0016522401555657791 0.0014550919403635942; 9.837734761082027e-7 1.069728314870665e-6 … 0.0014550919403635942 0.001286939535979884;;; 0.0014666847725153 0.0014666847724792008 … 0.0014666837305651816 0.0014666838235512587; 0.0014666847724792008 0.0014666847724393811 … 0.0014666836249749018 0.0014666837305651816; … ; 0.0014666847724792008 0.0014666847724393811 … 0.0014666836249749018 0.0014666837305651816; 0.0014666847725153 0.0014666847724792008 … 0.0014666837305651816 0.0014666838235512587;;; 0.001464536697606192 0.0014645366976422912 … 0.0014645377395563106 0.0014645376465702335; 0.0014645366976422912 0.001464536697682111 … 0.0014645378451465904 0.0014645377395563106; … ; 0.0014645366976422912 0.001464536697682111 … 0.0014645378451465904 0.0014645377395563106; 0.001464536697606192 0.0014645366976422912 … 0.0014645377395563106 0.0014645376465702335]
+ ⋮
+ [0.08609805841448885 0.17043647380897894 … 0.5253487807766108 0.26537934143299924; 0.17043632606964465 0.33827122544680704 … 1.0431153649870897 0.5255803265135008; … ; 0.17043632606993778 0.33827122545075483 … 1.0431153649940519 0.5255803265114518; 0.0860980584164456 0.1704364738036493 … 0.5253487807791457 0.26537934143072245;;; 1.4373252284252587 1.3815140561336918 … 1.1874256906451954 1.3236301768644854; 1.381514149094787 1.282410462486973 … 0.9854451339241563 1.187316859958651; … ; 1.3815141490947984 1.2824104624869814 … 0.985445133924186 1.1873168599586434; 1.4373252284252651 1.381514056133681 … 1.1874256906452056 1.3236301768644814;;; 0.5618219481395771 0.617633120431141 … 0.8117214859196411 0.6755169997003484; 0.6176330274700476 0.7167367140778601 … 1.0137020426406766 0.8118303166061864; … ; 0.6176330274700379 0.7167367140778521 … 1.013702042640648 0.811830316606193; 0.5618219481395706 0.6176331204311543 … 0.8117214859196324 0.6755169997003547]
+ [0.08611716284636785 0.1704746875759635 … 0.5254093392748143 0.26540962380931715; 0.17047453796773276 0.3383476574354815 … 1.0432364899869457 0.5256408959749768; … ; 0.17047453797553302 0.33834765742835987 … 1.0432364899764301 0.5256408960020937; 0.08611716284038229 0.17047468757916076 … 0.5254093392661157 0.26540962379923955;;; 1.4378006045760183 1.3819336252553422 … 1.18773425720817 1.3240275973003504; 1.3819337199879635 1.2827436621439265 … 0.9856521249815722 1.187625374811168; … ; 1.3819337199879833 1.2827436621439123 … 0.985652124981564 1.1876253748112293; 1.4378006045760032 1.381933625255349 … 1.1877342572081317 1.3240275973003257;;; 0.5618903141179039 0.6177572934385748 … 0.8119566614857493 0.675663321393566; 0.6177571987059567 0.7169472565499952 … 1.0140387937123465 0.81206554388275; … ; 0.6177571987059367 0.7169472565500083 … 1.0140387937123552 0.8120655438826886; 0.5618903141179188 0.6177572934385721 … 0.8119566614857862 0.6756633213935938]
+ [0.08612424654708097 0.17048885417543524 … 0.5254313531349682 0.26542063413877076; 0.17048870386588985 0.3383759883706147 … 1.0432805110757877 0.5256629134457393; … ; 0.170488703884439 0.33837598835742216 … 1.0432805110973677 0.5256629134235756; 0.08612424653806508 0.1704888541769625 … 0.5254313531595093 0.2654206341270826;;; 1.4379761857637117 1.3820885642569771 … 1.187848575254819 1.3241746260446023; 1.3820886597402475 1.282866672089754 … 0.9857290285708314 1.1877396740994512; … ; 1.3820886597402842 1.282866672089726 … 0.9857290285708875 1.187739674099377; 1.4379761857636837 1.3820885642569687 … 1.1878485752548558 1.3241746260445473;;; 0.5619155910916513 0.6178032125983852 … 0.8120432016005394 0.6757171508107606; 0.617803117115112 0.7170251047656121 … 1.0141627482845308 0.8121521027559123; … ; 0.6178031171150765 0.7170251047656395 … 1.014162748284476 0.8121521027559846; 0.561915591091679 0.6178032125983928 … 0.8120432016005025 0.6757171508108165]
+ [0.08612614505229817 0.17049265173033532 … 0.5254371206649849 0.26542351829363214; 0.17049250123957818 0.33838358348745023 … 1.0432920460466648 0.5256686816795856; … ; 0.17049250124753992 0.33838358348904124 … 1.0432920461154893 0.525668681756715; 0.08612614505402293 0.17049265172194183 … 0.5254371205976006 0.2654235182581309;;; 1.438021748281357 1.3821288252436945 … 1.187878416207984 1.3242128480702355; 1.3821289209378569 1.2828987701027135 … 0.9857493588369103 1.1877695102365726; … ; 1.3821289209378944 1.2828987701026977 … 0.9857493588368392 1.1877695102366979; 1.438021748281391 1.3821288252436945 … 1.1878784162078508 1.3242128480701005;;; 0.5619220947768526 0.6178150178145252 … 0.8120654268502244 0.6757309949879838; 0.6178149221203557 0.7170450729555038 … 1.0141944842213038 0.8121743328216273; … ; 0.6178149221203226 0.7170450729555157 … 1.0141944842213717 0.8121743328215018; 0.5619220947768176 0.6178150178145267 … 0.8120654268503701 0.6757309949881167]
+ [0.08612634833961608 0.17049305911570686 … 0.525437644079961 0.26542377902246334; 0.170492908574816 0.33838439808113263 … 1.0432930934301377 0.5256692048869787; … ; 0.17049290811777018 0.3383843988515875 … 1.0432930950736503 0.5256692045561501; 0.08612634859699825 0.17049305865575506 … 0.52543764304871 0.26542377919106236;;; 1.4380264806956427 1.3821330324299592 … 1.1878815936563463 1.3242168995948893; 1.3821331281551719 1.2829020891783252 … 0.985751330092647 1.187772687201552; … ; 1.3821331281541414 1.2829020891797156 … 0.9857513300952706 1.1877726872013452; 1.4380264806960608 1.3821330324291468 … 1.187881593654247 1.324216899594847;;; 0.5619227864033625 0.6178162346690312 … 0.8120676734426134 0.6757323675040384; 0.6178161389438078 0.7170471779206645 … 1.014197937006328 0.8121765798974236; … ; 0.6178161389448378 0.7170471779192793 … 1.0141979370037266 0.8121765798976581; 0.5619227864028657 0.6178162346698169 … 0.8120676734446789 0.6757323675041291]
+ [0.08612696881535002 0.17049430008770006 … 0.5254400839401973 0.26542499883980797; 0.170494149747826 0.3383868781331526 … 1.043297972434291 0.5256716472137475; … ; 0.17049414848785427 0.3383868800692405 … 1.0432979719282864 0.52567164581839; 0.08612696959032942 0.17049429917277514 … 0.5254400849702624 0.2654249990031393;;; 1.4380418735122498 1.3821466102181006 … 1.1878911197364868 1.3242294633193916; 1.3821467059262218 1.2829128644454508 … 0.9857575482591076 1.1877822109670015; … ; 1.382146705923879 1.282912864448529 … 0.9857575482563709 1.1877822109628993; 1.438041873513753 1.3821466102173778 … 1.1878911197399622 1.3242294633199276;;; 0.5619250181568558 0.6178202814509923 … 0.8120757719326805 0.6757374283497037; 0.6178201857429156 0.7170540272235062 … 1.0142093434101023 0.8121846807021841; … ; 0.6178201857451067 0.7170540272203798 … 1.0142093434128474 0.8121846807062801; 0.5619250181553251 0.6178202814519933 … 0.8120757719293283 0.6757374283492548]
+ [0.08612922537590663 0.17049880553970603 … 0.5254468170856988 0.2654283605002894; 0.17049865619637367 0.33839589998903513 … 1.043311422996803 0.5256783789152208; … ; 0.17049865611834927 0.3383958965948585 … 1.043311416465437 0.5256783762610793; 0.08612922431900134 0.17049880862316633 … 0.5254468158063551 0.2654283641164176;;; 1.4380984980643825 1.3821966010088347 … 1.1879282918441725 1.324277069412198; 1.3821966970513817 1.2829525933075199 … 0.9857827134934911 1.1878193774451082; … ; 1.382196697050343 1.2829525933000296 … 0.9857827134871916 1.1878193774373935; 1.4380984980634006 1.382196601018273 … 1.1879282918421388 1.3242770694226238;;; 0.5619331295432555 0.6178350266002102 … 0.8121033357642147 0.6757545581965154; 0.6178349305571488 0.717079034301209 … 1.0142489141146822 0.8122122501630371; … ; 0.6178349305587992 0.7170790343094964 … 1.0142489141216229 0.8122122501706001; 0.5619331295443876 0.6178350265912546 … 0.8121033357659547 0.6757545581856481]
+ [0.08612916289874369 0.17049870555794155 … 0.5254465298681716 0.26542821481760537; 0.1704985446634098 0.3383956470925995 … 1.0433108263607662 0.5256780918573387; … ; 0.1704985431157662 0.3383956606328835 … 1.043310830082979 0.5256780922557244; 0.08612916976707674 0.17049869290665864 … 0.5254465229505567 0.2654282135126806;;; 1.4380968996603225 1.382195187537549 … 1.1879273351803625 1.3242757919077506; 1.382195283666662 1.2829514630948973 … 0.985782108927835 1.1878184211149487; … ; 1.3821952836761753 1.2829514631315213 … 0.9857821088892916 1.1878184211173373; 1.4380968996762014 1.3821951874955116 … 1.1879273351678405 1.3242757919007564;;; 0.5619328997334134 0.6178346118587885 … 0.8121024642121145 0.6757540074905293; 0.6178345157271027 0.7170783362984251 … 1.014247690465932 0.8122113782805697; … ; 0.6178345157204921 0.7170783362589533 … 1.014247690503209 0.8122113782778801; 0.5619328997173723 0.6178346118966905 … 0.8121024642260316 0.6757540074954401]
+ [0.08612859127580082 0.17049753160171222 … 0.5254451033087721 0.2654275139153849; 0.17049737712645266 0.3383933506216603 … 1.0433079952861508 0.5256766590950411; … ; 0.17049738447304252 0.3383933541276276 … 1.043307974168319 0.525676692339815; 0.08612858333303658 0.17049752682484845 … 0.5254451132469781 0.26542750243477514;;; 1.438083476814153 1.3821833871353062 … 1.1879183610904311 1.324264371017305; 1.3821834831435538 1.2829421710750641 … 0.9857759837772998 1.1878094482264425; … ; 1.3821834831725104 1.2829421710886368 … 0.9857759837559232 1.1878094483020714; 1.4380834767926478 1.3821833871175564 … 1.1879183610832111 1.3242643709998836;;; 0.5619309119155712 0.6178310015970299 … 0.8120960276405288 0.6757500177170583; 0.6178309055900693 0.7170722176531644 … 1.0142384049550173 0.8122049405079206; … ; 0.617830905560228 0.7170722176404384 … 1.0142384049773085 0.8122049404304051; 0.5619309119422641 0.6178310016132098 … 0.8120960276490696 0.6757500177298977]

if I want to solve it on $t \in [0,100]$. Done! The solution gives back our tensors (and interpolates to create new ones if you use sol(t)). We can plot it in Plots.jl:

using Plots
+p1 = surface(X, Y, sol[end][:, :, 1], title = "[A]")
+p2 = surface(X, Y, sol[end][:, :, 2], title = "[B]")
+p3 = surface(X, Y, sol[end][:, :, 3], title = "[C]")
+plot(p1, p2, p3, layout = grid(3, 1))
Example block output

and see the pretty gradients. Using this 2nd order ROCK method we solve this equation in about 2 seconds. That's okay.

Some Optimizations

There are some optimizations that can still be done. When we do A*B as matrix multiplication, we create another temporary matrix. These allocations can bog down the system. Instead, we can pre-allocate the outputs and use the inplace functions mul! to make better use of memory. The easiest way to store these cache arrays are constant globals, but you can use closures (anonymous functions which capture data, i.e. (x)->f(x,y)) or call-overloaded types to do it without globals. The globals way (the easy way) is simply:

const MyA = zeros(N, N)
+const AMx = zeros(N, N)
+const DA = zeros(N, N)
+function f(du, u, p, t)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    mul!(MyA, My, A)
+    mul!(AMx, A, Mx)
+    @. DA = D * (MyA + AMx)
+    @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end

For reference, closures looks like:

MyA = zeros(N, N)
+AMx = zeros(N, N)
+DA = zeros(N, N)
+function f_full(du, u, p, t, MyA, AMx, DA)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    mul!(MyA, My, A)
+    mul!(AMx, A, Mx)
+    @. DA = D * (MyA + AMx)
+    @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end
+f(du, u, p, t) = f_full(du, u, p, t, MyA, AMx, DA)

and a call overloaded type looks like:

struct MyFunction{T} <: Function
+    MyA::T
+    AMx::T
+    DA::T
+end
+
+# Now define the overload
+function (ff::MyFunction)(du, u, p, t)
+    # This is a function which references itself via ff
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    mul!(ff.MyA, My, A)
+    mul!(ff.AMx, A, Mx)
+    @. ff.DA = D * (ff.MyA + ff.AMx)
+    @. dA = f.DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end
+
+MyA = zeros(N, N)
+AMx = zeros(N, N)
+DA = zeros(N, N)
+
+f = MyFunction(MyA, AMx, DA)
+# Now f(du,u,p,t) is our function!

These last two ways enclose the pointer to our cache arrays locally but still present a function f(du,u,p,t) to the ODE solver.

Now, since PDEs are large, many times we don't care about getting the whole timeseries. Using the output controls from DifferentialEquations.jl, we can make it only output the final timepoint.

prob = ODEProblem(f, u0, (0.0, 100.0))
+@time sol = solve(prob, ROCK2(), progress = true, save_everystep = false,
+                  save_start = false);
+@time sol = solve(prob, ROCK2(), progress = true, save_everystep = false,
+                  save_start = false);

Around 0.4 seconds. Much better. Also, if you're using VS Code, this'll give you a nice progress bar, so you can track how it's going.

Quick Note About Performance

Note

We are using the ROCK2 method here because it's a method for stiff equations with eigenvalues that are real-dominated (as opposed to dominated by the imaginary parts). If we wanted to use a more conventional implicit ODE solver, we would need to make use of the sparsity pattern. This is covered in the advanced ODE tutorial It turns out that ROCK2 is more efficient anyway (and doesn't require sparsity handling), so we will keep this setup.

Quick Summary: full PDE ODE Code

As a summary, here's a full PDE code:

using OrdinaryDiffEq, LinearAlgebra
+
+# Define the constants for the PDE
+const α₂ = 1.0
+const α₃ = 1.0
+const β₁ = 1.0
+const β₂ = 1.0
+const β₃ = 1.0
+const r₁ = 1.0
+const r₂ = 1.0
+const D = 100.0
+const γ₁ = 0.1
+const γ₂ = 0.1
+const γ₃ = 0.1
+const N = 100
+const X = reshape([i for i in 1:100 for j in 1:100], N, N)
+const Y = reshape([j for i in 1:100 for j in 1:100], N, N)
+const α₁ = 1.0 .* (X .>= 80)
+
+const Mx = Array(Tridiagonal([1.0 for i in 1:(N - 1)], [-2.0 for i in 1:N],
+                             [1.0 for i in 1:(N - 1)]))
+const My = copy(Mx)
+Mx[2, 1] = 2.0
+Mx[end - 1, end] = 2.0
+My[1, 2] = 2.0
+My[end, end - 1] = 2.0
+
+# Define the initial condition as normal arrays
+u0 = zeros(N, N, 3)
+
+const MyA = zeros(N, N);
+const AMx = zeros(N, N);
+const DA = zeros(N, N)
+# Define the discretized PDE as an ODE function
+function f(du, u, p, t)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    mul!(MyA, My, A)
+    mul!(AMx, A, Mx)
+    @. DA = D * (MyA + AMx)
+    @. dA = DA + α₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end
+
+# Solve the ODE
+prob = ODEProblem(f, u0, (0.0, 100.0))
+sol = solve(prob, ROCK2(), progress = true, save_everystep = false, save_start = false)
+
+using Plots;
+gr();
+p1 = surface(X, Y, sol[end][:, :, 1], title = "[A]")
+p2 = surface(X, Y, sol[end][:, :, 2], title = "[B]")
+p3 = surface(X, Y, sol[end][:, :, 3], title = "[C]")
+plot(p1, p2, p3, layout = grid(3, 1))
Example block output

Making Use of GPU Parallelism

That was all using the CPU. How do we turn on GPU parallelism with DifferentialEquations.jl? Well, you don't. DifferentialEquations.jl "doesn't have GPU bits". So, wait... can we not do GPU parallelism? No, this is the glory of type-genericness, especially in broadcasted operations. To make things use the GPU, we simply use a CuArray from CUDA.jl. If instead of zeros(N,M) we used CuArray(zeros(N,M)), then the array lives on the GPU. CuArray naturally overrides broadcast such that dotted operations are performed on the GPU. DifferentialEquations.jl uses broadcast internally, and thus just by putting the array as a CuArray, the array-type will take over how all internal updates are performed and turn this algorithm into a fully GPU-parallelized algorithm that doesn't require copying to the CPU. Wasn't that simple?

From that you can probably also see how to multithread everything, or how to set everything up with distributed parallelism. You can make the ODE solvers do whatever you want by defining an array type where the broadcast does whatever special behavior you want.

So to recap, the entire difference from above is changing to:

using CUDA
+const gMx = CuArray(Float32.(Mx))
+const gMy = CuArray(Float32.(My))
+const gα₁ = CuArray(Float32.(α₁))
+gu0 = CuArray(Float32.(u0))
+
+const gMyA = CuArray(zeros(Float32, N, N))
+const AgMx = CuArray(zeros(Float32, N, N))
+const gDA = CuArray(zeros(Float32, N, N))
+function gf(du, u, p, t)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    mul!(gMyA, gMy, A)
+    mul!(AgMx, A, gMx)
+    @. gDA = D * (gMyA + AgMx)
+    @. dA = gDA + gα₁ - β₁ * A - r₁ * A * B + r₂ * C
+    @. dB = α₂ - β₂ * B - r₁ * A * B + r₂ * C
+    @. dC = α₃ - β₃ * C + r₁ * A * B - r₂ * C
+end
+
+prob2 = ODEProblem(gf, gu0, (0.0, 100.0))
+CUDA.allowscalar(false) # makes sure none of the slow fallbacks are used
+@time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false,
+                  save_start = false);
retcode: Success
+Interpolation: 1st order linear
+t: 1-element Vector{Float64}:
+ 100.0
+u: 1-element Vector{CUDA.CuArray{Float32, 3, CUDA.Mem.DeviceBuffer}}:
+ [0.30240515 0.3033441 … 0.9317032 0.9354111; 0.30240515 0.3033441 … 0.9317032 0.9354111; … ; 0.30240515 0.3033441 … 0.9317032 0.9354111; 0.30240515 0.3033441 … 0.9317032 0.9354111;;; 1.3027511 1.3027539 … 1.0227388 1.0225928; 1.3027511 1.3027539 … 1.0227388 1.0225928; … ; 1.3027511 1.3027539 … 1.0227388 1.0225928; 1.3027511 1.3027539 … 1.0227388 1.0225928;;; 0.6972486 0.6972462 … 0.97726107 0.9774074; 0.6972486 0.6972462 … 0.97726107 0.9774074; … ; 0.6972486 0.6972462 … 0.97726107 0.9774074; 0.6972486 0.6972462 … 0.97726107 0.9774074]
@time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false,
+                  save_start = false);
retcode: Success
+Interpolation: 1st order linear
+t: 1-element Vector{Float64}:
+ 100.0
+u: 1-element Vector{CUDA.CuArray{Float32, 3, CUDA.Mem.DeviceBuffer}}:
+ [0.30240515 0.3033441 … 0.9317032 0.9354111; 0.30240515 0.3033441 … 0.9317032 0.9354111; … ; 0.30240515 0.3033441 … 0.9317032 0.9354111; 0.30240515 0.3033441 … 0.9317032 0.9354111;;; 1.3027511 1.3027539 … 1.0227388 1.0225928; 1.3027511 1.3027539 … 1.0227388 1.0225928; … ; 1.3027511 1.3027539 … 1.0227388 1.0225928; 1.3027511 1.3027539 … 1.0227388 1.0225928;;; 0.6972486 0.6972462 … 0.97726107 0.9774074; 0.6972486 0.6972462 … 0.97726107 0.9774074; … ; 0.6972486 0.6972462 … 0.97726107 0.9774074; 0.6972486 0.6972462 … 0.97726107 0.9774074]

Go have fun.

And Stochastic PDEs?

Why not make it an SPDE? All that we need to do is extend each of the PDE equations to have a noise function. In this case, let's use multiplicative noise on each reactant. This means that our noise update equation is:

function g(du, u, p, t)
+    A = @view u[:, :, 1]
+    B = @view u[:, :, 2]
+    C = @view u[:, :, 3]
+    dA = @view du[:, :, 1]
+    dB = @view du[:, :, 2]
+    dC = @view du[:, :, 3]
+    @. dA = γ₁ * A
+    @. dB = γ₂ * A
+    @. dC = γ₃ * A
+end
g (generic function with 1 method)

Now we just define and solve the system of SDEs:

prob = SDEProblem(f, g, u0, (0.0, 100.0))
+@time sol = solve(prob, SRIW1());
retcode: Success
+Interpolation: 1st order linear
+t: 81864-element Vector{Float64}:
+   0.0
+   9.999999999999999e-5
+   0.0002125
+   0.00033906249999999995
+   0.0004814453125
+   0.0006416259765625
+   0.0008218292236328125
+   0.0010245578765869141
+   0.0012526276111602785
+   0.0015092060625553133
+   ⋮
+  99.98264695261882
+  99.98415152859347
+  99.98584417656494
+  99.98774840553284
+  99.98989066312174
+  99.99230070290925
+  99.99501199767019
+  99.99806220427625
+ 100.0
+u: 81864-element Vector{Array{Float64, 3}}:
+ [0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0;;; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0; … ; 0.0 0.0 … 0.0 0.0; 0.0 0.0 … 0.0 0.0]
+ [4.999999999999999e-9 4.999999999999999e-9 … 9.993266986255768e-5 9.900777752585893e-5; 4.999999999999999e-9 4.999999999999999e-9 … 0.0001010368360556304 0.00010010825481578078; … ; 4.999999999999999e-9 4.999999999999999e-9 … 0.00010097494349120099 9.99931766079445e-5; 4.999999999999999e-9 4.999999999999999e-9 … 0.00010001114178542265 9.902544382196182e-5;;; 9.999999999999999e-5 9.999999999999999e-5 … 9.994481272337538e-5 9.991956493222374e-5; 9.999999999999999e-5 9.999999999999999e-5 … 9.995738026062749e-5 9.996589117005397e-5; … ; 9.999999999999999e-5 9.999999999999999e-5 … 9.992889797334401e-5 9.993969424138411e-5; 9.999999999999999e-5 9.999999999999999e-5 … 0.00010006593957022918 9.993181487446793e-5;;; 9.999e-5 9.999e-5 … 9.999247759525713e-5 9.991013248866407e-5; 9.999e-5 9.999e-5 … 9.991421381477618e-5 9.991786968535826e-5; … ; 9.999e-5 9.999e-5 … 9.999041638474194e-5 0.00010000740729267339; 9.999e-5 9.999e-5 … 9.996551378600164e-5 0.00010006497183602967]
+ [2.2342887037009974e-8 2.2585078553961164e-8 … 0.0002120576256398184 0.00020796595359414994; 2.2548128722957155e-8 2.2803832826946348e-8 … 0.00021746833700869478 0.00021256558667200932; … ; 2.2567050216282007e-8 2.2790696898647606e-8 … 0.00021700276727063716 0.00021259207385425726; 2.2329146566835608e-8 2.258085126079771e-8 … 0.00021275276606862428 0.00020793796868852677;;; 0.00021250000005368336 0.00021249999230207642 … 0.00021255613297103436 0.0002123546417789151; 0.00021249999116716977 0.00021250000094883372 … 0.00021228502138555947 0.0002125603605116671; … ; 0.00021249999356765157 0.00021249998818708972 … 0.00021222872022084297 0.00021220111703250733; 0.0002124999871426469 0.00021249997753829304 … 0.00021272669511817393 0.0002122919840147873;;; 0.00021245484315084124 0.0002124548568379002 … 0.0002126422084209473 0.00021229323645778495; 0.00021245485529315837 0.00021245482768296508 … 0.00021225071334723066 0.00021217922504308579; … ; 0.00021245486325642153 0.00021245484966021387 … 0.00021232037955973965 0.00021245228556081874; 0.00021245484719633538 0.000212454850586059 … 0.00021256929484744146 0.00021251506568961348]
+ [5.638022178744609e-8 5.7454842492883836e-8 … 0.0003383645357873502 0.0003283541859461794; 5.742730349781019e-8 5.8593694728999896e-8 … 0.00035040792967924587 0.00033898251740101124; … ; 5.744336631251313e-8 5.8455752790924146e-8 … 0.00035039943876821885 0.0003388376130876055; 5.63626240340248e-8 5.7447995057981186e-8 … 0.0003388211536461874 0.00032801268573134386;;; 0.00033906250203078684 0.00033906248229297856 … 0.00033862191075908284 0.0003392350034148456; 0.0003390625095812818 0.0003390624720906611 … 0.0003387467061797332 0.0003386687651557299; … ; 0.00033906252853480685 0.00033906247046279145 … 0.0003387682976641906 0.00033877085987513524; 0.0003390624435674347 0.0003390623700872729 … 0.0003397088393444775 0.0003390045744873208;;; 0.000338947514029265 0.0003389475816088605 … 0.00033905996714592444 0.00033876944501654433; 0.0003389474512668112 0.00033894758369868393 … 0.00033907457185889116 0.00033861888902488816; … ; 0.0003389474834410196 0.0003389475203321115 … 0.00033872732965121543 0.0003394506427101864; 0.00033894761369725353 0.00033894749735981385 … 0.00033904436422860197 0.0003394163896889575]
+ [1.128410314501469e-7 1.1578742130148474e-7 … 0.0004805555847520268 0.00046080104877838774; 1.1558181969474344e-7 1.1930449433572856e-7 … 0.0005034332805665286 0.00048050315236684344; … ; 1.1577868622665776e-7 1.191505821728304e-7 … 0.000502962545218058 0.00048096269102862964; 1.1242554434311394e-7 1.1578712772941256e-7 … 0.00048050279434712595 0.0004602233467058832;;; 0.00048144533619808163 0.0004814453757247544 … 0.0004813763155347458 0.0004815255915866414; 0.0004814453138934873 0.00048144525658497836 … 0.00048116145389505834 0.000480147219063012; … ; 0.00048144528793391363 0.00048144510649268587 … 0.0004810926245190924 0.00048151361660346564; 0.00048144534785714873 0.00048144512106891406 … 0.0004822646130151723 0.00048091079522405477;;; 0.000481213508841751 0.0004812135707431815 … 0.0004802867510379367 0.000481401700388929; 0.00048121332928137444 0.00048121358107956264 … 0.000480878858584533 0.0004807539863640668; … ; 0.00048121343847067 0.00048121352134699284 … 0.00048169310743669794 0.00048110903945958606; 0.0004812138620094453 0.0004812135927951619 … 0.0004814645785139545 0.0004822883387239184]
+ [1.9804241361666085e-7 2.0577855318212156e-7 … 0.0006399790990058781 0.0006048382342111245; 2.0520833647962361e-7 2.1396666156923895e-7 … 0.0006795219442768297 0.0006404550015675432; … ; 2.05495267041425e-7 2.136012091158911e-7 … 0.000679578663099896 0.0006409480507418954; 1.977217629367523e-7 2.0584415975497502e-7 … 0.0006393854196891039 0.0006038037029960561;;; 0.0006416258061349172 0.0006416261341215412 … 0.0006419187149661989 0.0006414402662388502; 0.0006416261608074075 0.0006416258060801009 … 0.0006400857518971021 0.0006413564404501097; … ; 0.0006416260358111474 0.0006416253953721825 … 0.000641563381854087 0.0006416615452299469; 0.0006416262282431012 0.0006416261222129616 … 0.00064281074213491 0.0006418928654788975;;; 0.0006412143834756385 0.000641214567616027 … 0.000640159388425455 0.0006417555164136853; 0.0006412144054032588 0.0006412148108152483 … 0.0006421391538075166 0.0006405391164024541; … ; 0.0006412143746333652 0.0006412145914129932 … 0.0006418494623331608 0.000641658346829403; 0.0006412146131542342 0.0006412142170172808 … 0.0006415208336660056 0.000643283490954239]
+ [3.2120913201029863e-7 3.371350286008162e-7 … 0.0008199814114319861 0.0007619202707145878; 3.36956729775186e-7 3.545871985738421e-7 … 0.0008832746123988234 0.0008191167779231168; … ; 3.370864185969044e-7 3.544443991831787e-7 … 0.0008842904243732365 0.0008211454248327328; 3.2112822816782216e-7 3.37061913933322e-7 … 0.0008183225417135828 0.0007624651862551336;;; 0.0008218293979509894 0.0008218294502105773 … 0.000822356650367036 0.0008227229146179055; 0.000821829663468489 0.0008218299164980073 … 0.0008196892878301027 0.0008216043926054364; … ; 0.0008218295009529642 0.000821827754184268 … 0.0008213118623058603 0.0008236214572132365; 0.0008218295739622707 0.0008218293869546851 … 0.0008228493935850586 0.0008191404947473525;;; 0.0008211541933136826 0.0008211537895128407 … 0.0008190192835801759 0.00082204259346615; 0.0008211538925424467 0.000821154490442462 … 0.0008216242807275192 0.0008199802534578236; … ; 0.0008211543123244169 0.0008211550916172149 … 0.0008193021410638603 0.000822042295548584; 0.000821154338388036 0.0008211535146957901 … 0.0008232686254204366 0.0008221722881695847]
+ [4.915552974624019e-7 5.233280607473795e-7 … 0.0010201823399483675 0.0009334294157249812; 5.224244112847766e-7 5.566345319815105e-7 … 0.001116780332416573 0.0010196611250758865; … ; 5.234559035368601e-7 5.572499832161003e-7 … 0.001120065921168665 0.0010223894958280183; 4.927526128988345e-7 5.238558978090905e-7 … 0.0010194132466115073 0.0009337211196946068;;; 0.0010245571989685807 0.0010245580854016984 … 0.001024676046705185 0.0010246087962376945; 0.0010245583271693314 0.0010245586859585392 … 0.0010219551910219044 0.0010260329948371804; … ; 0.001024557569174125 0.0010245561671542616 … 0.0010244408623661814 0.001025402399730501; 0.0010245584434903953 0.0010245583319543137 … 0.0010243234059732218 0.0010234451692495245;;; 0.0010235086946621215 0.0010235084467826623 … 0.0010230670513976373 0.0010232661244741659; 0.0010235081635800779 0.0010235091876532028 … 0.0010236154463533161 0.001022579370942527; … ; 0.0010235093490704621 0.0010235107090595756 … 0.0010208696870360112 0.001024841170339525; 0.0010235091869402492 0.0010235076931636167 … 0.0010273956470449538 0.0010262025496733046]
+ [7.2526464127447e-7 7.816866685297774e-7 … 0.00124602575535497 0.001119354511401715; 7.815090063586248e-7 8.415551042605222e-7 … 0.0013913303288408494 0.0012464398849083948; … ; 7.828334056738367e-7 8.415135091113003e-7 … 0.0013891882392002312 0.001249257577338885; 7.259139442808663e-7 7.831497781449707e-7 … 0.0012412025206008062 0.001121083423762367;;; 0.0012526257228517958 0.0012526277711441074 … 0.0012556915197280453 0.0012513179865574482; 0.001252627045202016 0.001252628912591954 … 0.0012533896786859765 0.0012515544238977064; … ; 0.0012526261043864886 0.0012526255424168446 … 0.0012525629144556107 0.0012529140260385554; 0.0012526289221182192 0.0012526275848524107 … 0.001255643303170593 0.0012547376244498498;;; 0.0012510604482569524 0.0012510595709522125 … 0.0012511573217161788 0.0012503100050301828; 0.0012510586416208801 0.0012510615708485459 … 0.0012484314256434872 0.001249305852677544; … ; 0.0012510610385957823 0.001251060188980904 … 0.0012474303893917054 0.0012538930457293945; 0.0012510596497230862 0.0012510589919053083 … 0.0012544231247067744 0.0012520680042161243]
+ [1.0379226340924246e-6 1.1338658463052413e-6 … 0.00149815478856125 0.00131775511112547; 1.134839299665943e-6 1.2388271911827592e-6 … 0.001702146098231883 0.0014976918117699006; … ; 1.1324922015308497e-6 1.23725509361734e-6 … 0.001703646193845724 0.0014991385732150923; 1.0383162829746953e-6 1.1339413923897388e-6 … 0.0014929040380725106 0.0013217709110344756;;; 0.0015092000345247906 0.001509207041507046 … 0.0015155921047379567 0.0015093129919832929; 0.0015092058148308731 0.001509207564825981 … 0.0015119788574579373 0.0015079372730961115; … ; 0.001509203508320139 0.0015092039922690445 … 0.0015166261605778835 0.001509211128345217; 0.0015092073303553766 0.0015092047561264437 … 0.0015147980987328523 0.001513711578250902;;; 0.0015069324689990146 0.001506929848449418 … 0.0015073811794570503 0.0015025757699399242; 0.0015069303215981971 0.0015069330139584937 … 0.0015021441546909581 0.001501119059437945; … ; 0.0015069332315423717 0.0015069293691058708 … 0.0015010518030859506 0.0015053933213663895; 0.0015069310421234703 0.0015069305745068994 … 0.001507623514866019 0.0015091762697834587]
+ ⋮
+ [0.0888029096877509 0.17459821989800847 … 0.5659566020273968 0.28489590007781496; 0.17384793535716944 0.3433767202254855 … 1.1316888134405576 0.5741845633734325; … ; 0.18370774434367637 0.3676798989401384 … 1.0678661534897154 0.5400915400752315; 0.09275975255168625 0.18438402690370373 … 0.5358586192064304 0.27313407930594935;;; 1.3943983407962188 1.365064683363119 … 1.0771386446603735 1.2290363995680615; 1.403342089294851 1.5826489400591837 … 0.4544297120100335 1.0899490910482184; … ; 1.4382509881484695 1.249364837943084 … 1.858214843193505 1.2322832796747323; 1.4480027792331618 1.42252794677067 … 1.1719942051866228 1.2272918191679631;;; 0.6084404873763157 0.6618318859095316 … 0.8036665127866154 0.7460642255360344; 0.6193170450402103 0.7065199459411333 … 0.7950091690701123 1.0766263130195033; … ; 0.6829504153682867 0.8930671075675215 … 1.727014997933314 1.0165061458443239; 0.604827772879443 0.7016679132887194 … 0.7389046742427631 0.7353201720500606]
+ [0.08812677864877766 0.17395075583169758 … 0.5665537453199059 0.2843360865865162; 0.17324250695806384 0.34223965388364963 … 1.1315512479932677 0.5728743536656524; … ; 0.18406400970012446 0.3669559648942091 … 1.0699966686807088 0.5414214829095074; 0.09268193940068467 0.18457293780595627 … 0.5378276322483492 0.27282321190191794;;; 1.394824564265437 1.3667463503893935 … 1.074626662056209 1.2287036143125014; 1.4039033763846436 1.5801887477180614 … 0.45462234381530436 1.0907088830972833; … ; 1.438692250975033 1.2506052134486814 … 1.8548744733859017 1.2338514920625814; 1.447662062588055 1.4209403829525766 … 1.172967597884022 1.2272773626390934;;; 0.607955772457739 0.6625669323694972 … 0.8052344737449738 0.744679565391917; 0.6207652450949396 0.7072401848110259 … 0.7923819903550425 1.0793455591214485; … ; 0.682421785647546 0.8917249671486124 … 1.7301190942852787 1.0161048050095565; 0.6045976059526404 0.7014915389324137 … 0.7421973776816366 0.7347110316038835]
+ [0.08744412482339946 0.1727819041290745 … 0.5658607859705233 0.2853783853160719; 0.17171118948858502 0.3392506140744141 … 1.1283200761541503 0.5727612431627491; … ; 0.18334448407368018 0.3654955328376803 … 1.0721973358424723 0.542075627049498; 0.09296664841621417 0.18419609584495752 … 0.5377721588626425 0.27326148599296307;;; 1.3946188846815417 1.3670309977920325 … 1.0738344509357238 1.229685514444894; 1.402993324466604 1.5774752959534726 … 0.45297991946419036 1.092666390074627; … ; 1.4381808741531716 1.2495244858748127 … 1.8535848162039974 1.236535542540787; 1.4473354248816412 1.4214708865622236 … 1.1746136465332024 1.226759206832913;;; 0.6074279213027494 0.6624465252098971 … 0.802718377403433 0.7432959287827593; 0.6201642191232942 0.7058074009485802 … 0.7954492298618335 1.0752449727525892; … ; 0.6825445833399391 0.894591591671955 … 1.719895331469655 1.019236634999582; 0.6044006252101257 0.7011738568639916 … 0.7431881657776385 0.7348356725528754]
+ [0.08714673120676447 0.17273126226775812 … 0.5672217002135729 0.2864816025697441; 0.17153485007223368 0.33894205851454196 … 1.1281734911416177 0.5697946581919249; … ; 0.18351928584889024 0.3646148416489589 … 1.073536178729755 0.5411423234131244; 0.09213247799188934 0.1840733548187912 … 0.5399081211255258 0.2723031261969213;;; 1.3955003570943754 1.3666225129757101 … 1.0722283913509851 1.2308413008097692; 1.4022017583629083 1.5783087133099094 … 0.4453854392555083 1.0960022125767994; … ; 1.4389383654833618 1.2497220389378372 … 1.8514955900694718 1.2364289372919697; 1.4476668861897373 1.4224893184177652 … 1.1726278998672919 1.2271429671360383;;; 0.6073146859709102 0.6622971306320872 … 0.8058329411913255 0.7423954299455177; 0.6208316358906134 0.7080905776195563 … 0.7959897489047922 1.0727934311910903; … ; 0.6824222008090488 0.8949004743412072 … 1.7187467184429486 1.0181335137151908; 0.6041148514524287 0.701026521604945 … 0.741803608334157 0.7341987312632963]
+ [0.08709961798110187 0.17330157718566608 … 0.5667935350435072 0.28720170597591466; 0.17183214741119382 0.33996913125892453 … 1.1320225820991945 0.5696573666768218; … ; 0.18368011246792731 0.365619163460639 … 1.0764674493931279 0.5376703290573096; 0.09279287777925697 0.1846524458350931 … 0.5433417067490955 0.27398781937779254;;; 1.3959695740391487 1.3660491722988617 … 1.074249254401438 1.2321075011171796; 1.4019946752877757 1.5823121225130656 … 0.45237093589853805 1.0947580741626688; … ; 1.4396927698926234 1.251898893683045 … 1.8459348222226282 1.2362216843664557; 1.4480809453094758 1.4229930072465249 … 1.1725897380498447 1.227221080924986;;; 0.6071139651207498 0.6626698286500559 … 0.8017616318715741 0.739265539450289; 0.619816375035542 0.7057427603228779 … 0.7958169170734177 1.068389559914979; … ; 0.6812947149941133 0.8924647644810054 … 1.7149362891311128 1.0165364974115871; 0.6043098652699919 0.7008837117619825 … 0.7428424408493959 0.7340726012379694]
+ [0.08670747226368904 0.1720732412824046 … 0.5638486165991743 0.2868044847850307; 0.17153567664466693 0.34091901862832996 … 1.128763816269046 0.5667467692290885; … ; 0.18319916560847432 0.3621732323902501 … 1.0766299796516174 0.5376122722549752; 0.09269262205655991 0.18280568969905822 … 0.542881203537783 0.27288788958416743;;; 1.395941205372005 1.3647564759224193 … 1.0747373005265282 1.2341251360301482; 1.4026479385030393 1.5827398512934339 … 0.4473582704372596 1.092558227518651; … ; 1.4403913494885874 1.2553671970167306 … 1.839261794893753 1.2347316419745793; 1.44797820368913 1.4220355439833134 … 1.1705215021679836 1.2304715942048279;;; 0.606815740153256 0.6630495266719596 … 0.8016817902822447 0.7400240758497403; 0.6192696688355493 0.7062097788555307 … 0.8028683615625609 1.0651095366623304; … ; 0.6831167831048701 0.8935523057401721 … 1.7185915471438782 1.0161032308581333; 0.6038605859140539 0.7015088593979426 … 0.7389204122509956 0.7315694221193821]
+ [0.08706412476894541 0.17149801081453286 … 0.5684267163576143 0.28728102815271367; 0.17088958084140204 0.34107748557485096 … 1.1299570888111612 0.56557976727312; … ; 0.18301426074768876 0.3609703681383834 … 1.0737749440498419 0.5401318445328422; 0.092461558846252 0.1833616726297861 … 0.541208552141637 0.2731607869101833;;; 1.3961578051164025 1.3659636648476023 … 1.0713216923366802 1.233785734460648; 1.40220761459017 1.5816527110366525 … 0.45415462360688336 1.0978946636622862; … ; 1.4395705952012197 1.2549537754567253 … 1.8344384951118173 1.241081719527249; 1.4485446542908198 1.421751103156443 … 1.1736898765819086 1.2312769596756454;;; 0.606899832858506 0.6629189848343566 … 0.7978176984353516 0.7383928644980627; 0.6185019697512422 0.7058314409652338 … 0.8034323670711179 1.0622132996626352; … ; 0.6834253536361339 0.8922318903097685 … 1.722575229892914 1.0161156319470672; 0.6036010535669848 0.7025996104015407 … 0.7385699844025526 0.7309254629484969]
+ [0.08748868915664564 0.1728830639817135 … 0.5670745484618192 0.28688455598578533; 0.1717944786528095 0.34224360700672446 … 1.126920800593798 0.5661471449063982; … ; 0.18278841618605876 0.3628404185176353 … 1.0766229178955506 0.5393062233258019; 0.09155437936067941 0.18282548590274605 … 0.5403934163642058 0.2731096200179232;;; 1.396063014052708 1.3676946070443115 … 1.0684678648440176 1.2336505147320356; 1.4029453305411868 1.5793253174732038 … 0.45475451111513804 1.0998344989982884; … ; 1.4391649649601774 1.2556172831279309 … 1.8305923622288582 1.2446105535460326; 1.4486332473493109 1.4203487229310137 … 1.1680784611196673 1.2340468060178988;;; 0.6060645898971705 0.6625104784002188 … 0.799155430757452 0.7362380085184613; 0.6177400954044293 0.7069664403790406 … 0.7981748787990909 1.06043186976753; … ; 0.6837171125437815 0.8941488334703178 … 1.7207135290522733 1.01738066577413; 0.6035834023122876 0.7024249000016355 … 0.7366617175094448 0.7310354788445955]
+ [0.08739849063507658 0.17229756155408427 … 0.5665809494188668 0.28641068789798324; 0.17155853047874056 0.3410682711376678 … 1.126894836882235 0.5682182947594874; … ; 0.182957855196809 0.36231886027137783 … 1.0733188735198362 0.5387236094307822; 0.0921223342879792 0.1828312293421862 … 0.5428426993517949 0.27229640859110427;;; 1.3958988641857517 1.3662065496428342 … 1.0695049915462869 1.2352489763419487; 1.4035667550768083 1.5803800383934454 … 0.45125412220403815 1.1001372315821416; … ; 1.4390718059387282 1.255898819397948 … 1.82860277716779 1.2479747641366876; 1.448369011676832 1.4210392731986803 … 1.1689854936818833 1.2333484195050317;;; 0.6058889990089051 0.6625998453635525 … 0.7941861477588316 0.7344792299947688; 0.6181026923480571 0.7080998884711723 … 0.7992706496887313 1.0632982355066403; … ; 0.6826347990496626 0.8911628564676846 … 1.7201745446043357 1.0124146666474105; 0.6033395673201163 0.7032005061118743 … 0.7356393297449392 0.7316437241678302]
using Plots;
+gr();
+
+# Use `Array` to transform the result back into a CPU-based `Array` for plotting
+p1 = surface(X, Y, Array(sol[end][:, :, 1]), title = "[A]")
+p2 = surface(X, Y, Array(sol[end][:, :, 2]), title = "[B]")
+p3 = surface(X, Y, Array(sol[end][:, :, 3]), title = "[C]")
+plot(p1, p2, p3, layout = grid(3, 1))
Example block output

We can see the cool effect that diffusion dampens the noise in [A] but is unable to dampen the noise in [B] which results in a very noisy [C]. The stiff SPDE takes much longer to solve even using high order plus adaptivity because stochastic problems are just that much more difficult (current research topic is to make new algorithms for this!). It gets GPU'd just by using CuArray like before. But there we go: solving systems of stochastic PDEs using high order adaptive algorithms with within-method GPU parallelism. That's gotta be a first? The cool thing is that nobody ever had to implement the GPU-parallelism either, it just exists by virtue of the Julia type system.

(Note: We can also use one of the SROCK methods for better performance here, but they will require a choice of dt. This is left to the reader to try.)

Note

This can take a while to solve! An explicit Runge-Kutta algorithm isn't necessarily great here, though to use a stiff solver on a problem of this size requires once again smartly choosing sparse linear solvers. The high order adaptive method is pretty much necessary though, since something like Euler-Maruyama is simply not stable enough to solve this at a reasonable dt. Also, the current algorithms are not so great at handling this problem. Good thing there's a publication coming along with some new stuff...

diff --git a/v1.5.0/showcase/massively_parallel_gpu/index.html b/v1.5.0/showcase/massively_parallel_gpu/index.html new file mode 100644 index 00000000000..5aae7bb15f7 --- /dev/null +++ b/v1.5.0/showcase/massively_parallel_gpu/index.html @@ -0,0 +1,26 @@ + +Massively Data-Parallel ODE Solving on GPUs · Overview of Julia's SciML

Massively Data-Parallel ODE Solving on GPUs

Before we start: the two ways to accelerate ODE solvers with GPUs

Before we dive deeper, let us remark that there are two very different ways that one can accelerate an ODE solution with GPUs. There is one case where u is very big and f is very expensive but very structured, and you use GPUs to accelerate the computation of said f. The other use case is where u is very small, but you want to solve the ODE f over many different initial conditions (u0) or parameters p. In that case, you can use GPUs to parallelize over different parameters and initial conditions. In other words:

Type of ProblemSciML Solution
Accelerate a big ODEUse CUDA.jl's CuArray as u0
Solve the same ODE with many u0 and pUse DiffEqGPU.jl's EnsembleGPUArray and EnsembleGPUKernel

This showcase will focus on the latter case. For the former, see the massively parallel GPU ODE solving showcase.

Supported GPUs

SciML's GPU support extends to a wide array of hardware, including:

GPU ManufacturerGPU Kernel LanguageJulia Support PackageBackend Type
NVIDIACUDACUDA.jlCUDA.CUDABackend()
AMDROCmAMDGPU.jlAMDGPU.ROCBackend()
IntelOneAPIOneAPI.jloneAPI.oneAPIBackend()
Apple (M-Series)MetalMetal.jlMetal.MetalBackend()

For this tutorial we will demonstrate the CUDA backend for NVIDIA GPUs, though any of the other GPUs can be used by simply swapping out the backend choice.

Problem Setup

Let's say we wanted to quantify the uncertainty in the solution of a differential equation. One simple way to do this would be to a Monte Carlo simulation of the same ODE, randomly jiggling around some parameters according to an uncertainty distribution. We could do that on a CPU, but that's not hip. What's hip are GPUs! GPUs have thousands of cores, so could we make each core of our GPU solve the same ODE, but with different parameters? The ensembling tools of DiffEqGPU.jl solve exactly this issue, and today you will learn how to master the GPUniverse.

Let's dive right in.

Defining the Ensemble Problem for CPU

DifferentialEquations.jl has an ensemble interface for solving many ODEs. DiffEqGPU conveniently uses exactly the same interface, so just a change of a few characters is all that's required to change a CPU-parallelized code into a GPU-parallelized code. Given that, let's start with the CPU-parallelized code.

Let's implement the Lorenz equation out-of-place. If you don't know what that means, see the getting started with DifferentialEquations.jl

using DiffEqGPU, OrdinaryDiffEq, StaticArrays, CUDA
+function lorenz(u, p, t)
+    σ = p[1]
+    ρ = p[2]
+    β = p[3]
+    du1 = σ * (u[2] - u[1])
+    du2 = u[1] * (ρ - u[3]) - u[2]
+    du3 = u[1] * u[2] - β * u[3]
+    return SVector{3}(du1, du2, du3)
+end
+
+u0 = @SVector [1.0f0; 0.0f0; 0.0f0]
+tspan = (0.0f0, 10.0f0)
+p = @SVector [10.0f0, 28.0f0, 8 / 3.0f0]
+prob = ODEProblem{false}(lorenz, u0, tspan, p)
ODEProblem with uType StaticArraysCore.SVector{3, Float32} and tType Float32. In-place: false
+timespan: (0.0f0, 10.0f0)
+u0: 3-element StaticArraysCore.SVector{3, Float32} with indices SOneTo(3):
+ 1.0
+ 0.0
+ 0.0

Notice we use SVectors, i.e. StaticArrays, in order to define our arrays. This is important for later, since the GPUs will want a fully non-allocating code to build a kernel on.

Now, from this problem, we build an EnsembleProblem as per the DifferentialEquations.jl specification. A prob_func jiggles the parameters and we solve 10_000 trajectories:

prob_func = (prob, i, repeat) -> remake(prob, p = (@SVector rand(Float32, 3)) .* p)
+monteprob = EnsembleProblem(prob, prob_func = prob_func, safetycopy = false)
+sol = solve(monteprob, Tsit5(), EnsembleThreads(), trajectories = 10_000, saveat = 1.0f0)
EnsembleSolution Solution of length 10000 with uType:
+SciMLBase.ODESolution{Float32, 2, Vector{StaticArraysCore.SVector{3, Float32}}, Nothing, Nothing, Vector{Float32}, Vector{Vector{StaticArraysCore.SVector{3, Float32}}}, SciMLBase.ODEProblem{StaticArraysCore.SVector{3, Float32}, Tuple{Float32, Float32}, false, StaticArraysCore.SVector{3, Float32}, SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEq.Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, OrdinaryDiffEq.InterpolationData{SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing, Nothing, Nothing}, Vector{StaticArraysCore.SVector{3, Float32}}, Vector{Float32}, Vector{Vector{StaticArraysCore.SVector{3, Float32}}}, Nothing, OrdinaryDiffEq.Tsit5ConstantCache, Nothing}, SciMLBase.DEStats, Nothing, Nothing, Nothing}

Taking the Ensemble to the GPU

Now uhh, we just change EnsembleThreads() to EnsembleGPUArray()

sol = solve(monteprob, Tsit5(), EnsembleGPUArray(CUDA.CUDABackend()), trajectories = 10_000, saveat = 1.0f0)
EnsembleSolution Solution of length 10000 with uType:
+SciMLBase.ODESolution{Float32, 2, uType, Nothing, Nothing, Vector{Float32}, rateType, SciMLBase.ODEProblem{StaticArraysCore.SVector{3, Float32}, Tuple{Float32, Float32}, false, StaticArraysCore.SVector{3, Float32}, SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEq.Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, IType, SciMLBase.DEStats, Nothing, Nothing, Nothing} where {uType, rateType, IType}

Or for a more efficient version, EnsembleGPUKernel(). But that requires special solvers, so we also change to GPUTsit5().

sol = solve(monteprob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()), trajectories = 10_000)
EnsembleSolution Solution of length 10000 with uType:
+SciMLBase.ODESolution{Float32, 2, SubArray{StaticArraysCore.SVector{3, Float32}, 1, Matrix{StaticArraysCore.SVector{3, Float32}}, Tuple{UnitRange{Int64}, Int64}, true}, Nothing, Nothing, SubArray{Float32, 1, Matrix{Float32}, Tuple{UnitRange{Int64}, Int64}, true}, Nothing, DiffEqGPU.ImmutableODEProblem{StaticArraysCore.SVector{3, Float32}, Tuple{Float32, Float32}, false, StaticArraysCore.SVector{3, Float32}, SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing, Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, @NamedTuple{}}, SciMLBase.StandardODEProblem}, DiffEqGPU.GPUTsit5, SciMLBase.LinearInterpolation{SubArray{Float32, 1, Matrix{Float32}, Tuple{UnitRange{Int64}, Int64}, true}, SubArray{StaticArraysCore.SVector{3, Float32}, 1, Matrix{StaticArraysCore.SVector{3, Float32}}, Tuple{UnitRange{Int64}, Int64}, true}}, Nothing, Nothing, Nothing, Nothing}

Okay, so that was anticlimactic, but that's the point: if it were harder than that, it wouldn't be automatic! Now go check out DiffEqGPU.jl's documentation for more details, that's the end of our show.

diff --git a/v1.5.0/showcase/missing_physics/186dcc63.svg b/v1.5.0/showcase/missing_physics/186dcc63.svg new file mode 100644 index 00000000000..de6e71e045a --- /dev/null +++ b/v1.5.0/showcase/missing_physics/186dcc63.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/31abc02c.svg b/v1.5.0/showcase/missing_physics/31abc02c.svg new file mode 100644 index 00000000000..750b618ee1a --- /dev/null +++ b/v1.5.0/showcase/missing_physics/31abc02c.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/4bc5ce80.svg b/v1.5.0/showcase/missing_physics/4bc5ce80.svg new file mode 100644 index 00000000000..522f6380cc5 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/4bc5ce80.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/7257452b.svg b/v1.5.0/showcase/missing_physics/7257452b.svg new file mode 100644 index 00000000000..2a22ed82795 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/7257452b.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/c9af9d34.svg b/v1.5.0/showcase/missing_physics/c9af9d34.svg new file mode 100644 index 00000000000..4f7ebcca538 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/c9af9d34.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/db29de04.svg b/v1.5.0/showcase/missing_physics/db29de04.svg new file mode 100644 index 00000000000..6d102ac050f --- /dev/null +++ b/v1.5.0/showcase/missing_physics/db29de04.svg @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Timeseries of UODE Error + + + + + + + +x(t) + + + +y(t) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Neural Network Fit of U2(t) + + + + + + + +Neural Network + + + +True Missing Term + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Extrapolated Fit From Short Training Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +x data + + + +y data + + + +True x(t) + + + +True y(t) + + + +Estimated x(t) + + + +Estimated y(t) + + +Training + + +Data + + diff --git a/v1.5.0/showcase/missing_physics/e79dc32d.svg b/v1.5.0/showcase/missing_physics/e79dc32d.svg new file mode 100644 index 00000000000..1f090da9825 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/e79dc32d.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/f34dda71.svg b/v1.5.0/showcase/missing_physics/f34dda71.svg new file mode 100644 index 00000000000..19cc53e20f4 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/f34dda71.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/fc0b0254.svg b/v1.5.0/showcase/missing_physics/fc0b0254.svg new file mode 100644 index 00000000000..ccedeb42d07 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/fc0b0254.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/missing_physics/index.html b/v1.5.0/showcase/missing_physics/index.html new file mode 100644 index 00000000000..d5317820097 --- /dev/null +++ b/v1.5.0/showcase/missing_physics/index.html @@ -0,0 +1,362 @@ + +Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations · Overview of Julia's SciML

Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations

One of the most time-consuming parts of modeling is building the model. How do you know when your model is correct? When you solve an inverse problem to calibrate your model to data, who you gonna call if there are no parameters that make the model the data? This is the problem that the Universal Differential Equation (UDE) approach solves: the ability to start from the model you have, and suggest minimal mechanistic extensions that would allow the model to fit the data. In this showcase, we will show how to take a partially correct model and auto-complete it to find the missing physics.

Note

For a scientific background on the universal differential equation approach, check out Universal Differential Equations for Scientific Machine Learning

Starting Point: The Packages To Use

There are many packages which are used as part of this showcase. Let's detail what they are and how they are used. For the neural network training:

ModuleDescription
OrdinaryDiffEq.jl (DifferentialEquations.jl)The numerical differential equation solvers
SciMLSensitivity.jlThe adjoint methods, defines gradients of ODE solvers
Optimization.jlThe optimization library
OptimizationOptimisers.jlThe optimization solver package with Adam
OptimizationOptimJL.jlThe optimization solver package with LBFGS
LineSearches.jlLine search algorithms package to be used with LBFGS

For the symbolic model discovery:

ModuleDescription
ModelingToolkit.jlThe symbolic modeling environment
DataDrivenDiffEq.jlThe symbolic regression interface
DataDrivenSparse.jlThe sparse regression symbolic regression solvers
Zygote.jlThe automatic differentiation library for fast gradients

Julia standard libraries:

ModuleDescription
LinearAlgebraRequired for the norm function
StatisticsRequired for the mean function

And external libraries:

ModuleDescription
Lux.jlThe deep learning (neural network) framework
ComponentArrays.jlFor the ComponentArray type to match Lux to SciML
Plots.jlThe plotting and visualization library
StableRNGs.jlStable random seeding
Note

The deep learning framework Flux.jl could be used in place of Lux, though most tutorials in SciML generally prefer Lux.jl due to its explicit parameter interface, leading to nicer code. Both share the same internal implementations of core kernels, and thus have very similar feature support and performance.

# SciML Tools
+using OrdinaryDiffEq, ModelingToolkit, DataDrivenDiffEq, SciMLSensitivity, DataDrivenSparse
+using Optimization, OptimizationOptimisers, OptimizationOptimJL, LineSearches
+
+# Standard Libraries
+using LinearAlgebra, Statistics
+
+# External Libraries
+using ComponentArrays, Lux, Zygote, Plots, StableRNGs
+gr()
+
+# Set a random seed for reproducible behaviour
+rng = StableRNG(1111)
StableRNGs.LehmerRNG(state=0x000000000000000000000000000008af)

Problem Setup

In order to know that we have automatically discovered the correct model, we will use generated data from a known model. This model will be the Lotka-Volterra equations. These equations are given by:

\[\begin{aligned} +\frac{dx}{dt} &= \alpha x - \beta x y \\ +\frac{dy}{dt} &= -\delta y + \gamma x y \\ +\end{aligned}\]

This is a model of rabbits and wolves. $\alpha x$ is the exponential growth of rabbits in isolation, $-\beta x y$ and $\gamma x y$ are the interaction effects of wolves eating rabbits, and $-\delta y$ is the term for how wolves die hungry in isolation.

Now assume that we have never seen rabbits and wolves in the same room. We only know the two effects $\alpha x$ and $-\delta y$. Can we use Scientific Machine Learning to automatically discover an extension to what we already know? That is what we will solve with the universal differential equation.

Generating the Training Data

First, let's generate training data from the Lotka-Volterra equations. This is straightforward and standard DifferentialEquations.jl usage. Our sample data is thus generated as follows:

function lotka!(du, u, p, t)
+    α, β, γ, δ = p
+    du[1] = α * u[1] - β * u[2] * u[1]
+    du[2] = γ * u[1] * u[2] - δ * u[2]
+end
+
+# Define the experimental parameter
+tspan = (0.0, 5.0)
+u0 = 5.0f0 * rand(rng, 2)
+p_ = [1.3, 0.9, 0.8, 1.8]
+prob = ODEProblem(lotka!, u0, tspan, p_)
+solution = solve(prob, Vern7(), abstol = 1e-12, reltol = 1e-12, saveat = 0.25)
+
+# Add noise in terms of the mean
+X = Array(solution)
+t = solution.t
+
+x̄ = mean(X, dims = 2)
+noise_magnitude = 5e-3
+Xₙ = X .+ (noise_magnitude * x̄) .* randn(rng, eltype(X), size(X))
+
+plot(solution, alpha = 0.75, color = :black, label = ["True Data" nothing])
+scatter!(t, transpose(Xₙ), color = :red, label = ["Noisy Data" nothing])
Example block output

Definition of the Universal Differential Equation

Now let's define our UDE. We will use Lux.jl to define the neural network as follows:

rbf(x) = exp.(-(x .^ 2))
+
+# Multilayer FeedForward
+const U = Lux.Chain(Lux.Dense(2, 5, rbf), Lux.Dense(5, 5, rbf), Lux.Dense(5, 5, rbf),
+              Lux.Dense(5, 2))
+# Get the initial parameters and state variables of the model
+p, st = Lux.setup(rng, U)
+const _st = st
(layer_1 = NamedTuple(), layer_2 = NamedTuple(), layer_3 = NamedTuple(), layer_4 = NamedTuple())

We then define the UDE as a dynamical system that is u' = known(u) + NN(u) like:

# Define the hybrid model
+function ude_dynamics!(du, u, p, t, p_true)
+    û = U(u, p, _st)[1] # Network prediction
+    du[1] = p_true[1] * u[1] + û[1]
+    du[2] = -p_true[4] * u[2] + û[2]
+end
+
+# Closure with the known parameter
+nn_dynamics!(du, u, p, t) = ude_dynamics!(du, u, p, t, p_)
+# Define the problem
+prob_nn = ODEProblem(nn_dynamics!, Xₙ[:, 1], tspan, p)
ODEProblem with uType Vector{Float64} and tType Float64. In-place: true
+timespan: (0.0, 5.0)
+u0: 2-element Vector{Float64}:
+ 3.1463924566781167
+ 1.5423300037202512

Notice that the most important part of this is that the neural network does not have hard-coded weights. The weights of the neural network are the parameters of the ODE system. This means that if we change the parameters of the ODE system, then we will have updated the internal neural networks to new weights. Keep that in mind for the next part.

... and tada: now we have a neural network integrated into our dynamical system!

Note

Even if the known physics is only approximate or correct, it can be helpful to improve the fitting process! Check out this JuliaCon talk which dives into this issue.

Setting Up the Training Loop

Now let's build a training loop around our UDE. First, let's make a function predict which runs our simulation at new neural network weights. Recall that the weights of the neural network are the parameters of the ODE, so what we need to do in predict is update our ODE to our new parameters and then run it.

For this update step, we will use the remake function from the SciMLProblem interface. remake works by specifying key = value pairs to update in the problem fields. Thus to update u0, we would add a keyword argument u0 = .... To update the parameters, we'd do p = .... The field names can be acquired from the problem documentation (or the docstrings!).

Knowing this, our predict function looks like:

function predict(θ, X = Xₙ[:, 1], T = t)
+    _prob = remake(prob_nn, u0 = X, tspan = (T[1], T[end]), p = θ)
+    Array(solve(_prob, Vern7(), saveat = T,
+                abstol = 1e-6, reltol = 1e-6,
+                sensealg=QuadratureAdjoint(autojacvec=ReverseDiffVJP(true))))
+end
predict (generic function with 3 methods)

There are many choices for the combination of sensitivity algorithm and automatic differentiation library (see Choosing a Sensitivity Algorithm. For example, you could have used sensealg=ForwardDiffSensitivity().

Now, for our loss function, we solve the ODE at our new parameters and check its L2 loss against the dataset. Using our predict function, this looks like:

function loss(θ)
+    X̂ = predict(θ)
+    mean(abs2, Xₙ .- X̂)
+end
loss (generic function with 1 method)

Lastly, what we will need to track our optimization is to define a callback as defined by the OptimizationProblem's solve interface. Because our function only returns one value, the loss l, the callback will be a function of the current parameters θ and l. Let's setup a callback prints every 50 steps the current loss:

losses = Float64[]
+
+callback = function (p, l)
+    push!(losses, l)
+    if length(losses) % 50 == 0
+        println("Current loss after $(length(losses)) iterations: $(losses[end])")
+    end
+    return false
+end
#1 (generic function with 1 method)

Training

Now we're ready to train! To run the training process, we will need to build an OptimizationProblem. Because we have a lot of parameters, we will use Zygote.jl. Optimization.jl makes the choice of automatic differentiation easy, just by specifying an adtype in the OptimizationFunction construction

Knowing this, we can build our OptimizationProblem as follows:

adtype = Optimization.AutoZygote()
+optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
+optprob = Optimization.OptimizationProblem(optf, ComponentVector{Float64}(p))
OptimizationProblem. In-place: true
+u0: ComponentVector{Float64}(layer_1 = (weight = [0.49426865577697754 0.5692564249038696; 0.40171918272972107 -0.8665286302566528; … ; 0.47097498178482056 -0.7521204352378845; -0.20216092467308044 -0.3197280168533325], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [0.6822634935379028 -0.6952740550041199 … 0.5011160969734192 0.24313241243362427; -0.39863723516464233 -0.17176461219787598 … -0.6159946322441101 0.18968746066093445; … ; -0.7200708389282227 -0.6787673234939575 … -0.5633968114852905 0.1658746749162674; 0.0014851824380457401 -0.10373303294181824 … 0.09008530527353287 -0.043933477252721786], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.0011237671133130789 0.006483868230134249 … 0.2754976451396942 -0.2874394953250885; 0.04383227229118347 -0.32253962755203247 … 0.09472294896841049 -0.4210013747215271; … ; -0.5179172158241272 -0.6043259501457214 … -0.18625909090042114 0.06577149033546448; -0.2150842249393463 0.2565661072731018 … 0.5849692821502686 0.2193499207496643], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [0.7144760489463806 0.4398183226585388 … -0.8286120891571045 0.04256918653845787; -0.5670844316482544 -0.3962741494178772 … 0.1667986661195755 0.8446723818778992], bias = [0.0; 0.0;;]))

Now... we optimize it. We will use a mixed strategy. First, let's do some iterations of ADAM because it's better at finding a good general area of parameter space, but then we will move to BFGS which will quickly hone in on a local minimum. Note that if we only use ADAM it will take a ton of iterations, and if we only use BFGS we normally end up in a bad local minimum, so this combination tends to be a good one for UDEs.

Thus we first solve the optimization problem with ADAM. Choosing a learning rate of 0.1 (tuned to be as high as possible that doesn't tend to make the loss shoot up), we see:

res1 = Optimization.solve(optprob, OptimizationOptimisers.Adam(), callback = callback, maxiters = 5000)
+println("Training loss after $(length(losses)) iterations: $(losses[end])")
Current loss after 50 iterations: 240907.40812048622
+Current loss after 100 iterations: 171079.09448670733
+Current loss after 150 iterations: 130867.59181981071
+Current loss after 200 iterations: 108175.81919697102
+Current loss after 250 iterations: 92683.05198787761
+Current loss after 300 iterations: 80367.48811924485
+Current loss after 350 iterations: 70059.55070201663
+Current loss after 400 iterations: 61257.68558277132
+Current loss after 450 iterations: 53651.08580887412
+Current loss after 500 iterations: 47008.06470444493
+Current loss after 550 iterations: 41158.83468134578
+Current loss after 600 iterations: 35981.347399573264
+Current loss after 650 iterations: 31385.761553778448
+Current loss after 700 iterations: 27302.945325275745
+Current loss after 750 iterations: 23677.218526860303
+Current loss after 800 iterations: 20461.937285324857
+Current loss after 850 iterations: 17616.785543435544
+Current loss after 900 iterations: 15106.07897133494
+Current loss after 950 iterations: 12897.679899572697
+Current loss after 1000 iterations: 10962.290260726066
+Current loss after 1050 iterations: 9272.98412811566
+Current loss after 1100 iterations: 7804.895149441609
+Current loss after 1150 iterations: 6535.005113732221
+Current loss after 1200 iterations: 5441.998713386727
+Current loss after 1250 iterations: 4506.16127289149
+Current loss after 1300 iterations: 3709.3032558449395
+Current loss after 1350 iterations: 3034.700457982612
+Current loss after 1400 iterations: 2467.0421485359457
+Current loss after 1450 iterations: 1992.3816194839123
+Current loss after 1500 iterations: 1598.0855615560274
+Current loss after 1550 iterations: 1272.7797247349602
+Current loss after 1600 iterations: 1006.2891966063967
+Current loss after 1650 iterations: 789.5728738025371
+Current loss after 1700 iterations: 614.6544329439503
+Current loss after 1750 iterations: 474.55685746837594
+Current loss after 1800 iterations: 363.2417646522111
+Current loss after 1850 iterations: 275.53720126911554
+Current loss after 1900 iterations: 207.04805971494557
+Current loss after 1950 iterations: 154.0655400425799
+Current loss after 2000 iterations: 113.4841698044544
+Current loss after 2050 iterations: 82.72556007775695
+Current loss after 2100 iterations: 59.66823649947678
+Current loss after 2150 iterations: 42.58350060341369
+Current loss after 2200 iterations: 30.077308343181596
+Current loss after 2250 iterations: 21.03805224037106
+Current loss after 2300 iterations: 14.59005966093485
+Current loss after 2350 iterations: 10.0525297067963
+Current loss after 2400 iterations: 6.903577440862018
+Current loss after 2450 iterations: 4.749089044258902
+Current loss after 2500 iterations: 3.296102440727978
+Current loss after 2550 iterations: 2.33048380424851
+Current loss after 2600 iterations: 1.698461527740918
+Current loss after 2650 iterations: 1.29125176927898
+Current loss after 2700 iterations: 1.0329379753430217
+Current loss after 2750 iterations: 0.8714661234068295
+Current loss after 2800 iterations: 0.7719399734635284
+Current loss after 2850 iterations: 0.711448897808427
+Current loss after 2900 iterations: 0.6752009717353449
+Current loss after 2950 iterations: 0.6537894969142511
+Current loss after 3000 iterations: 0.641321795298097
+Current loss after 3050 iterations: 0.6341626182974422
+Current loss after 3100 iterations: 0.6301042695789253
+Current loss after 3150 iterations: 0.6278274469932038
+Current loss after 3200 iterations: 0.6265567042031686
+Current loss after 3250 iterations: 0.6258439624477189
+Current loss after 3300 iterations: 0.6254348109000369
+Current loss after 3350 iterations: 0.6251873850425234
+Current loss after 3400 iterations: 0.6250240332605751
+Current loss after 3450 iterations: 0.6249030527061531
+Current loss after 3500 iterations: 0.6248024765448081
+Current loss after 3550 iterations: 0.6247109569327519
+Current loss after 3600 iterations: 0.6246227420617254
+Current loss after 3650 iterations: 0.6245349665571128
+Current loss after 3700 iterations: 0.6244462212075934
+Current loss after 3750 iterations: 0.6243558146863484
+Current loss after 3800 iterations: 0.6242634011321152
+Current loss after 3850 iterations: 0.6241687966779008
+Current loss after 3900 iterations: 0.6240718912357626
+Current loss after 3950 iterations: 0.6239726071277146
+Current loss after 4000 iterations: 0.6238708801751957
+Current loss after 4050 iterations: 0.6237666512768746
+Current loss after 4100 iterations: 0.6236598627543288
+Current loss after 4150 iterations: 0.6235504568059509
+Current loss after 4200 iterations: 0.6234383748668952
+Current loss after 4250 iterations: 0.623323557347271
+Current loss after 4300 iterations: 0.6232059435236488
+Current loss after 4350 iterations: 0.6230854714909635
+Current loss after 4400 iterations: 0.6229620781376513
+Current loss after 4450 iterations: 0.6228356991296157
+Current loss after 4500 iterations: 0.6227062688977103
+Current loss after 4550 iterations: 0.6225737206267824
+Current loss after 4600 iterations: 0.6224379862457043
+Current loss after 4650 iterations: 0.6222989964181727
+Current loss after 4700 iterations: 0.6221566805342927
+Current loss after 4750 iterations: 0.622010966702976
+Current loss after 4800 iterations: 0.6218617817452029
+Current loss after 4850 iterations: 0.6217090511882264
+Current loss after 4900 iterations: 0.6215526992607816
+Current loss after 4950 iterations: 0.6213926488893756
+Current loss after 5000 iterations: 0.6212288216957349
+Training loss after 5001 iterations: 0.6212288216957349

Now we use the optimization result of the first run as the initial condition of the second optimization, and run it with BFGS. This looks like:

optprob2 = Optimization.OptimizationProblem(optf, res1.u)
+res2 = Optimization.solve(optprob2, LBFGS(linesearch = BackTracking()), callback = callback, maxiters = 1000)
+println("Final training loss after $(length(losses)) iterations: $(losses[end])")
+
+# Rename the best candidate
+p_trained = res2.u
ComponentVector{Float64}(layer_1 = (weight = [0.30260054978138107 0.4578309969403832; 0.5989251580060574 -0.5092733475165517; … ; -0.14985790598798976 -1.0349877433718728; -0.5562467552599903 -0.5702587617338674], bias = [-0.9741825202299292; 0.16347054284464826; … ; -0.28100342830828773; 0.17495036501898847;;]), layer_2 = (weight = [0.9409669476913312 -0.9625137068185611 … 0.5211539526676551 0.09033502013724633; 0.04550894163428188 0.13250276379412923 … -0.37902596230080743 0.23460287210076883; … ; -0.3297756590539087 -0.7684237598959185 … -0.6799289547889726 0.009120753010314321; 1.465325661258508 0.21088900936084756 … 0.379681978456254 0.256986871405923], bias = [-0.696091635007196; 0.09362753798415761; … ; -0.23531342640590622; 0.0819083525380058;;]), layer_3 = (weight = [-0.061251730207942674 -0.19606491853130706 … 0.05566004270141161 -0.7114766274466255; 0.3642977936020697 0.008702465473202302 … 0.3593307953493313 0.011337487687041369; … ; -0.9176094997138524 -0.5633524476775912 … 0.5047188198195783 0.9985371625890069; -0.9945379475790044 -0.24598703566355196 … 0.31636751461908846 0.7759014740065802], bias = [-0.24329374114187124; 0.40331661139372466; … ; -0.1374465664040485; -0.3020721028692106;;]), layer_4 = (weight = [0.6102486417323191 0.19321966988029643 … -2.568681273706919 -1.7594111717364629; -0.5354604051859988 -0.24067345475345125 … 1.6041355776604629 2.2258973180305133], bias = [-1.4313963484979577; 0.9947940897803472;;]))

and bingo, we have a trained UDE.

Visualizing the Trained UDE

How well did our neural network do? Let's take a look:

# Plot the losses
+pl_losses = plot(1:5000, losses[1:5000], yaxis = :log10, xaxis = :log10,
+                 xlabel = "Iterations", ylabel = "Loss", label = "ADAM", color = :blue)
+plot!(5001:length(losses), losses[5001:end], yaxis = :log10, xaxis = :log10,
+      xlabel = "Iterations", ylabel = "Loss", label = "LBFGS", color = :red)
Example block output

Next, we compare the original data to the output of the UDE predictor. Note that we can even create more samples from the underlying model by simply adjusting the time steps!

## Analysis of the trained network
+# Plot the data and the approximation
+ts = first(solution.t):(mean(diff(solution.t)) / 2):last(solution.t)
+X̂ = predict(p_trained, Xₙ[:, 1], ts)
+# Trained on noisy data vs real solution
+pl_trajectory = plot(ts, transpose(X̂), xlabel = "t", ylabel = "x(t), y(t)", color = :red,
+                     label = ["UDE Approximation" nothing])
+scatter!(solution.t, transpose(Xₙ), color = :black, label = ["Measurements" nothing])
Example block output

Let's see how well the unknown term has been approximated:

# Ideal unknown interactions of the predictor
+Ȳ = [-p_[2] * (X̂[1, :] .* X̂[2, :])'; p_[3] * (X̂[1, :] .* X̂[2, :])']
+# Neural network guess
+Ŷ = U(X̂, p_trained, st)[1]
+
+pl_reconstruction = plot(ts, transpose(Ŷ), xlabel = "t", ylabel = "U(x,y)", color = :red,
+                         label = ["UDE Approximation" nothing])
+plot!(ts, transpose(Ȳ), color = :black, label = ["True Interaction" nothing])
Example block output

And have a nice look at all the information:

# Plot the error
+pl_reconstruction_error = plot(ts, norm.(eachcol(Ȳ - Ŷ)), yaxis = :log, xlabel = "t",
+                               ylabel = "L2-Error", label = nothing, color = :red)
+pl_missing = plot(pl_reconstruction, pl_reconstruction_error, layout = (2, 1))
+
+pl_overall = plot(pl_trajectory, pl_missing)
Example block output

That looks pretty good. And if we are happy with deep learning, we can leave it at that: we have trained a neural network to capture our missing dynamics.

But...

Can we also make it print out the LaTeX for what the missing equations were? Find out more after the break!

Symbolic regression via sparse regression (SINDy based)

This part of the showcase is still a work in progress... shame on us. But be back in a jiffy and we'll have it done.

Okay, that was a quick break, and that's good because this next part is pretty cool. Let's use DataDrivenDiffEq.jl to transform our trained neural network from machine learning mumbo jumbo into predictions of missing mechanistic equations. To do this, we first generate a symbolic basis that represents the space of mechanistic functions we believe this neural network should map to. Let's choose a bunch of polynomial functions:

@variables u[1:2]
+b = polynomial_basis(u, 4)
+basis = Basis(b, u);

\[ \begin{align} +\varphi_1 =& 1 \\ +\varphi_2 =& u_1 \\ +\varphi_3 =& u_1^{2} \\ +\varphi_4 =& u_1^{3} \\ +\varphi_5 =& u_1^{4} \\ +\varphi_6 =& u_2 \\ +\varphi_7 =& u_1 u_2 \\ +\varphi_8 =& u_1^{2} u_2 \\ +\varphi_9 =& u_1^{3} u_2 \\ +\varphi_{1 0} =& u_2^{2} \\ +\varphi_{1 1} =& u_2^{2} u_1 \\ +\varphi_{1 2} =& u_2^{2} u_1^{2} \\ +\varphi_{1 3} =& u_2^{3} \\ +\varphi_{1 4} =& u_2^{3} u_1 \\ +\varphi_{1 5} =& u_2^{4} +\end{align} + \]

Now let's define our DataDrivenProblems for the sparse regressions. To assess the capability of the sparse regression, we will look at 3 cases:

  • What if we trained no neural network and tried to automatically uncover the equations from the original noisy data? This is the approach in the literature known as structural identification of dynamical systems (SINDy). We will call this the full problem. This will assess whether this incorporation of prior information was helpful.
  • What if we trained the neural network using the ideal right-hand side missing derivative functions? This is the value computed in the plots above as . This will tell us whether the symbolic discovery could work in ideal situations.
  • Do the symbolic regression directly on the function y = NN(x), i.e. the trained learned neural network. This is what we really want, and will tell us how to extend our known equations.

To define the full problem, we need to define a DataDrivenProblem that has the time series of the solution X, the time points of the solution t, and the derivative at each time point of the solution, obtained by the ODE solution's interpolation. We can just use an interpolation to get the derivative:

full_problem = ContinuousDataDrivenProblem(Xₙ, t)
Continuous DataDrivenProblem{Float64} ##DDProblem#19082 in 2 dimensions and 21 samples

Now for the other two symbolic regressions, we are regressing input/outputs of the missing terms, and thus we directly define the datasets as the input/output mappings like:

ideal_problem = DirectDataDrivenProblem(X̂, Ȳ)
+nn_problem = DirectDataDrivenProblem(X̂, Ŷ)
Direct DataDrivenProblem{Float64} ##DDProblem#19084 in 2 dimensions and 41 samples

Let's solve the data-driven problems using sparse regression. We will use the ADMM method, which requires we define a set of shrinking cutoff values λ, and we do this like:

λ = 1e-1
+opt = ADMM(λ)
DataDrivenSparse.ADMM{Float64, Float64}(0.1, 1.0)

This is one of many methods for sparse regression, consult the DataDrivenDiffEq.jl documentation for more information on the algorithm choices. Taking this, let's solve each of the sparse regressions:

options = DataDrivenCommonOptions(maxiters = 10_000,
+                                  normalize = DataNormalization(ZScoreTransform),
+                                  selector = bic, digits = 1,
+                                  data_processing = DataProcessing(split = 0.9,
+                                                                   batchsize = 30,
+                                                                   shuffle = true,
+                                                                   rng = StableRNG(1111)))
+
+full_res = solve(full_problem, basis, opt, options = options)
+full_eqs = get_basis(full_res)
+println(full_res)
┌ Warning: Number of observations less than batch-size, decreasing the batch-size to 19
+@ MLUtils ~/.cache/julia-buildkite-plugin/depots/0183cc98-c3b4-4959-aaaa-6c0d5f351407/packages/MLUtils/LmmaQ/src/batchview.jl:95
+┌ Warning: Number of observations less than batch-size, decreasing the batch-size to 19
+@ MLUtils ~/.cache/julia-buildkite-plugin/depots/0183cc98-c3b4-4959-aaaa-6c0d5f351407/packages/MLUtils/LmmaQ/src/batchview.jl:95
+"DataDrivenSolution{Float64}" with 2 equations and 4 parameters.
+Returncode: Success
+Residual sum of squares: 84.99147506548834
options = DataDrivenCommonOptions(maxiters = 10_000,
+                                  normalize = DataNormalization(ZScoreTransform),
+                                  selector = bic, digits = 1,
+                                  data_processing = DataProcessing(split = 0.9,
+                                                                   batchsize = 30,
+                                                                   shuffle = true,
+                                                                   rng = StableRNG(1111)))
+
+ideal_res = solve(ideal_problem, basis, opt, options = options)
+ideal_eqs = get_basis(ideal_res)
+println(ideal_res)
"DataDrivenSolution{Float64}" with 2 equations and 2 parameters.
+Returncode: Success
+Residual sum of squares: 12.245215185320248
options = DataDrivenCommonOptions(maxiters = 10_000,
+                                  normalize = DataNormalization(ZScoreTransform),
+                                  selector = bic, digits = 1,
+                                  data_processing = DataProcessing(split = 0.9,
+                                                                   batchsize = 30,
+                                                                   shuffle = true,
+                                                                   rng = StableRNG(1111)))
+
+nn_res = solve(nn_problem, basis, opt, options = options)
+nn_eqs = get_basis(nn_res)
+println(nn_res)
"DataDrivenSolution{Float64}" with 2 equations and 2 parameters.
+Returncode: Success
+Residual sum of squares: 12.422684130447076

Note that we passed the identical options into each of the solve calls to get the same data for each call.

We already saw that the full problem has failed to identify the correct equations of motion. To have a closer look, we can inspect the corresponding equations:

for eqs in (full_eqs, ideal_eqs, nn_eqs)
+    println(eqs)
+    println(get_parameter_map(eqs))
+    println()
+end
Model ##Basis#19085 with 2 equations
+States : u[1] u[2]
+Parameters : p₁ p₂ p₃ p₄
+Independent variable: t
+Equations
+Differential(t)(u[1]) = p₁*u[1] + p₂*u[2] + p₃*(u[2]^2)
+Differential(t)(u[2]) = p₄*u[2]
+
+Pair{SymbolicUtils.BasicSymbolic{Real}, Float64}[p₁ => 0.8, p₂ => -0.2, p₃ => -0.4, p₄ => -0.9]
+
+Model ##Basis#19089 with 2 equations
+States : u[1] u[2]
+Parameters : p₁ p₂
+Independent variable: t
+Equations
+φ₁ = p₁*u[1]*u[2]
+φ₂ = p₂*u[1]*u[2]
+
+Pair{SymbolicUtils.BasicSymbolic{Real}, Float64}[p₁ => -0.8, p₂ => 0.7]
+
+Model ##Basis#19093 with 2 equations
+States : u[1] u[2]
+Parameters : p₁ p₂
+Independent variable: t
+Equations
+φ₁ = p₁*u[1]*u[2]
+φ₂ = p₂*u[1]*u[2]
+
+Pair{SymbolicUtils.BasicSymbolic{Real}, Float64}[p₁ => -0.8, p₂ => 0.7]

Next, we want to predict with our model. To do so, we embed the basis into a function like before:

# Define the recovered, hybrid model
+function recovered_dynamics!(du, u, p, t)
+    û = nn_eqs(u, p) # Recovered equations
+    du[1] = p_[1] * u[1] + û[1]
+    du[2] = -p_[4] * u[2] + û[2]
+end
+
+estimation_prob = ODEProblem(recovered_dynamics!, u0, tspan, get_parameter_values(nn_eqs))
+estimate = solve(estimation_prob, Tsit5(), saveat = solution.t)
+
+# Plot
+plot(solution)
+plot!(estimate)
Example block output

We are still a bit off, so we fine tune the parameters by simply minimizing the residuals between the UDE predictor and our recovered parametrized equations:

function parameter_loss(p)
+    Y = reduce(hcat, map(Base.Fix2(nn_eqs, p), eachcol(X̂)))
+    sum(abs2, Ŷ .- Y)
+end
+
+optf = Optimization.OptimizationFunction((x, p) -> parameter_loss(x), adtype)
+optprob = Optimization.OptimizationProblem(optf, get_parameter_values(nn_eqs))
+parameter_res = Optimization.solve(optprob, Optim.LBFGS(), maxiters = 1000)
retcode: Success
+u: 2-element Vector{Float64}:
+ -0.9002755599681205
+  0.8006775139120063

Simulation

# Look at long term prediction
+t_long = (0.0, 50.0)
+estimation_prob = ODEProblem(recovered_dynamics!, u0, t_long, parameter_res)
+estimate_long = solve(estimation_prob, Tsit5(), saveat = 0.1) # Using higher tolerances here results in exit of julia
+plot(estimate_long)
Example block output
true_prob = ODEProblem(lotka!, u0, t_long, p_)
+true_solution_long = solve(true_prob, Tsit5(), saveat = estimate_long.t)
+plot!(true_solution_long)
Example block output

Post Processing and Plots

c1 = 3 # RGBA(174/255,192/255,201/255,1) # Maroon
+c2 = :orange # RGBA(132/255,159/255,173/255,1) # Red
+c3 = :blue # RGBA(255/255,90/255,0,1) # Orange
+c4 = :purple # RGBA(153/255,50/255,204/255,1) # Purple
+
+p1 = plot(t, abs.(Array(solution) .- estimate)' .+ eps(Float32),
+          lw = 3, yaxis = :log, title = "Timeseries of UODE Error",
+          color = [3 :orange], xlabel = "t",
+          label = ["x(t)" "y(t)"],
+          titlefont = "Helvetica", legendfont = "Helvetica",
+          legend = :topright)
+
+# Plot L₂
+p2 = plot3d(X̂[1, :], X̂[2, :], Ŷ[2, :], lw = 3,
+            title = "Neural Network Fit of U2(t)", color = c1,
+            label = "Neural Network", xaxis = "x", yaxis = "y",
+            titlefont = "Helvetica", legendfont = "Helvetica",
+            legend = :bottomright)
+plot!(X̂[1, :], X̂[2, :], Ȳ[2, :], lw = 3, label = "True Missing Term", color = c2)
+
+p3 = scatter(solution, color = [c1 c2], label = ["x data" "y data"],
+             title = "Extrapolated Fit From Short Training Data",
+             titlefont = "Helvetica", legendfont = "Helvetica",
+             markersize = 5)
+
+plot!(p3, true_solution_long, color = [c1 c2], linestyle = :dot, lw = 5,
+      label = ["True x(t)" "True y(t)"])
+plot!(p3, estimate_long, color = [c3 c4], lw = 1,
+      label = ["Estimated x(t)" "Estimated y(t)"])
+plot!(p3, [2.99, 3.01], [0.0, 10.0], lw = 1, color = :black, label = nothing)
+annotate!([(1.5, 13, text("Training \nData", 10, :center, :top, :black, "Helvetica"))])
+l = @layout [grid(1, 2)
+             grid(1, 1)]
+plot(p1, p2, p3, layout = l)
Example block output
diff --git a/v1.5.0/showcase/ode_types/40dab875.svg b/v1.5.0/showcase/ode_types/40dab875.svg new file mode 100644 index 00000000000..194d49a31ce --- /dev/null +++ b/v1.5.0/showcase/ode_types/40dab875.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/ode_types/58302a4e.svg b/v1.5.0/showcase/ode_types/58302a4e.svg new file mode 100644 index 00000000000..c37a019a300 --- /dev/null +++ b/v1.5.0/showcase/ode_types/58302a4e.svg @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/ode_types/9b60f1eb.svg b/v1.5.0/showcase/ode_types/9b60f1eb.svg new file mode 100644 index 00000000000..94d8cc90aec --- /dev/null +++ b/v1.5.0/showcase/ode_types/9b60f1eb.svg @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/ode_types/ad46406c.svg b/v1.5.0/showcase/ode_types/ad46406c.svg new file mode 100644 index 00000000000..08256e9d85a --- /dev/null +++ b/v1.5.0/showcase/ode_types/ad46406c.svg @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/ode_types/f36ad9a8.svg b/v1.5.0/showcase/ode_types/f36ad9a8.svg new file mode 100644 index 00000000000..1c14e4ba6c4 --- /dev/null +++ b/v1.5.0/showcase/ode_types/f36ad9a8.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/ode_types/index.html b/v1.5.0/showcase/ode_types/index.html new file mode 100644 index 00000000000..e7f92e93a49 --- /dev/null +++ b/v1.5.0/showcase/ode_types/index.html @@ -0,0 +1,308 @@ + +Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System · Overview of Julia's SciML

Automatic Uncertainty Quantification, Arbitrary Precision, and Unit Checking in ODE Solutions using Julia's Type System

One of the nice things about DifferentialEquations.jl is that it is designed with Julia's type system in mind. What this means is, if you have properly defined a Number type, you can use this number type in DifferentialEquations.jl's algorithms! There's more than a few useful/interesting types that can be used:

Julia Type NameJulia PackageUse case
BigFloatBase JuliaHigher precision solutions
ArbFloatArbFloats.jlMore efficient higher precision solutions
MeasurementMeasurements.jlUncertainty propagation
ParticlesMonteCarloMeasurements.jlUncertainty propagation
UnitfulUnitful.jlUnit-checked arithmetic
QuaternionQuaternions.jlQuaternions, duh.
FunApproxFun.jlRepresenting PDEs as ODEs in function spaces
AbstractOrthoPolyPolyChaos.jlPolynomial Chaos Expansion (PCE) for uncertainty quantification
NumSymbolics.jlBuild symbolic expressions of ODE solution approximations
TaylorTaylorSeries.jlBuild a Taylor series around a solution point
DualForwardDiff.jlPerform forward-mode automatic differentiation
TrackedArray\TrackedRealReverseDiff.jlPerform reverse-mode automatic differentiation

and on and on. That's only a subset of types people have effectively used on the SciML tools.

We will look into the BigFloat, Measurement, and Unitful cases to demonstrate the utility of alternative numerical types.

How Type Support Works in DifferentialEquations.jl / SciML

DifferentialEquations.jl determines the numbers to use in its solvers via the types that are designated by tspan and the initial condition u0 of the problem. It will keep the time values in the same type as tspan, and the solution values in the same type as the initial condition.

Note

Support for this feature is restricted to the native algorithms of OrdinaryDiffEq.jl. The other solvers such as Sundials.jl, and ODEInterface.jl are incompatible with some number systems.

Warn

Adaptive timestepping requires that the time type is compatible with sqrt and ^ functions. Thus for example, tspan cannot be Int if adaptive timestepping is chosen.

Let's use this feature in some cool ways!

Arbitrary Precision: Rationals and BigFloats

Let's solve the linear ODE. First, define an easy way to get ODEProblems for the linear ODE:

using DifferentialEquations
+f(u, p, t) = p * u
+prob_ode_linear = ODEProblem(f, 1 / 2, (0.0, 1.0), 1.01);
ODEProblem with uType Float64 and tType Float64. In-place: false
+timespan: (0.0, 1.0)
+u0: 0.5

Next, let's solve it using Float64s. To do so, we just need to set u0 to a Float64 (which is done by the default) and dt should be a float as well.

sol = solve(prob_ode_linear, Tsit5())
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 5-element Vector{Float64}:
+ 0.0
+ 0.09964258706516003
+ 0.3457024247583422
+ 0.6776921908052249
+ 1.0
+u: 5-element Vector{Float64}:
+ 0.5
+ 0.552938681151017
+ 0.7089376245893466
+ 0.9913594502399236
+ 1.3728004409033037

Notice that both the times and the solutions were saved as Float64. Let's change the state to use BigFloat values. We do this by changing the u0 to use BigFloats like:

prob_ode_linear_bigu = ODEProblem(f, big(1 / 2), (0.0, 1.0), 1.01);
+sol = solve(prob_ode_linear_bigu, Tsit5())
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 5-element Vector{Float64}:
+ 0.0
+ 0.09964258706516002
+ 0.3457024247583421
+ 0.6776921908052249
+ 1.0
+u: 5-element Vector{BigFloat}:
+ 0.5
+ 0.5529386811510169868158546583396554107562766958646715721373574023383501046221058
+ 0.7089376245893467747946683740114247908183375873155184947921708376129135715459387
+ 0.9913594502399245129177568740015245483252784799862388832829909311574503717103213
+ 1.372800440903305197219668813808289181933806034675853174012933503735877101067491

Now we see that u is in arbitrary precision BigFloats, while t is in Float64. We can then change t to be arbitrary precision BigFloats by changing the types of the tspan like:

prob_ode_linear_big = ODEProblem(f, big(1 / 2), (big(0.0), big(1.0)), 1.01);
+sol = solve(prob_ode_linear_big, Tsit5())
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 5-element Vector{BigFloat}:
+ 0.0
+ 0.09964258706516002757241113786493079821949560824572094442904017056206815655027755
+ 0.3457024247583421308145661100153752226739293846153111762313695785692066646211486
+ 0.6776921908052248538004732061437054858600791539496176542941317413488563178090448
+ 1.0
+u: 5-element Vector{BigFloat}:
+ 0.5
+ 0.5529386811510169905121549222942681803517017137036250612133811084046740072664042
+ 0.7089376245893467829092172805583925956947513313925386404738921107616392796707183
+ 0.9913594502399245078379256583106538498562594798883926568710576464510438939970046
+ 1.372800440903305274187428016868058103324428725450247680936213844886721036701247

Now let's send it into the bizarre territory. Let's use rational values for everything. Let's start by making the time type Rational. Rationals are incompatible with adaptive time stepping since they do not have an L2 norm (this can be worked around by defining internalnorm, but we will skip that in this tutorial). To account for this, let's turn off adaptivity as well. Thus the following is a valid use of rational time (and parameter):

prob = ODEProblem(f, 1 / 2, (0 // 1, 1 // 1), 101 // 100);
+sol = solve(prob, RK4(), dt = 1 // 2^(6), adaptive = false)
retcode: Success
+Interpolation: 3rd order Hermite
+t: 65-element Vector{Rational{Int64}}:
+   0
+  1//64
+  1//32
+  3//64
+  1//16
+  5//64
+  3//32
+  7//64
+  1//8
+  9//64
+   ⋮
+  7//8
+ 57//64
+ 29//32
+ 59//64
+ 15//16
+ 61//64
+ 31//32
+ 63//64
+   1
+u: 65-element Vector{Float64}:
+ 0.5
+ 0.5079532157789419
+ 0.5160329388403366
+ 0.5242411814636141
+ 0.5325799879363893
+ 0.5410514350635981
+ 0.549657632684732
+ 0.5584007241993002
+ 0.5672828871006491
+ 0.5763063335182743
+ ⋮
+ 1.2099787760366485
+ 1.2292252206241676
+ 1.2487778074652507
+ 1.268641406190701
+ 1.288820963889771
+ 1.3093215063422494
+ 1.3301481392701477
+ 1.3513060496092948
+ 1.3728005068011595

Now let's change the state to use Rational{BigInt}. You will see that we will need to use the arbitrary-sized integers because... well... there's a reason people use floating-point numbers with ODE solvers:

prob = ODEProblem(f, BigInt(1) // BigInt(2), (0 // 1, 1 // 1), 101 // 100);
+sol = solve(prob, RK4(), dt = 1 // 2^(6), adaptive = false)
retcode: Success
+Interpolation: 3rd order Hermite
+t: 65-element Vector{Rational{Int64}}:
+   0
+  1//64
+  1//32
+  3//64
+  1//16
+  5//64
+  3//32
+  7//64
+  1//8
+  9//64
+   ⋮
+  7//8
+ 57//64
+ 29//32
+ 59//64
+ 15//16
+ 61//64
+ 31//32
+ 63//64
+   1
+u: 65-element Vector{Rational{BigInt}}:
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         1//2
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         13635265310428667//26843545600000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         185920460085779372649467295396889//360287970189639680000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         2535074799906565070064434989240252460736488216963//4835703278458516698824704000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         34566417478507880850358857402427148787055026137565875648030878321//64903710731685345356631204115251200000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         471322273150493660801770967151032391984466213543795788952681156195576797027228107//871122859317602466466238995025326621327360000000000000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         6426604241121310927369897121054534260287845822775576065191752910027218849129163851685338960943369//11692013098647223345629478661730264157247460343808000000000000000000000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         87628453872815159549919436744286633306700458799675030242287144817323241473991649398590738650552963396600101159123//156927543384667019095894735580191660402558886111600862822400000000000000000000000000000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        1194837217298495123489429765132896187014406474671976544708139096975464385034479106227218239981906730284477718437811007486707779041//2106245833371143733958360553673408646377901908010982225086219550720000000000000000000000000000000000000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        16291922460639289757947281837298870307759032284133099989470765273134679312684297502599368900453650828381789478033888032849237996811196931228168347//28269553036454149273332760011886696253239742350009903329945699220681916416000000000000000000000000000000000000000000000000000000000000000000000000
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          ⋮
+                                                                                                                                  3476651764144701299310823013868414852914252425511969801823326943470139627183050321356269729758757892616986280081068426854388132587192659833281759109495586510217757379507472058821725242337421483829232094724350000335051444864163716743131954661196447426549808629937028209252581525400046451480100419001530953781616768025169970806686494551090052818656160455734295279711817930495039244376027618813690810243490836308240922572885036008357232995165091370374018505314343843108268301984782218425989406930319958551532270117232742567343778042005440462725562350111368484320102066864357344195777652146963879004877113342262696777549666508001903654324815937791481538838675335919013649404331120990596974956064711019198691285927797569234244700072843046601685002725165218418237056611786017220421490343908940716757353909791039304274005391221502042135010059552204316515216866746639520694954996904124971579780497757666750446881//2873316320086756454205652005706207886829487380916701497268289374190875758638147354923588066229040681914626081324682241425350209449285219103061691508162945093459145235278159647906758878132917284580285004541144156524655039141064404379679426100372681576010961105039478156124917692281743798746817307433826768839799128901030530861680784239247749388313984379590631715911498407693680085160154180294124335267854340370884940503485168233544639735700169786044364881920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                                                                                                  47405069196082873328585408620421318517516390291920914673056124180124925970261893410339173429287494238135595611089781966147422284876218622543131269354235054173066292325370254052047479196233718967762509800342189006216218284815334686783879790109432868299224476127915815042082361972609813617003873110744660057301821702132621624893170611073772099444022185151482507338829550979383225592740578974181160289252871652171292405008199989659405158877156438081779650473274842639963837184419397179015646801970478919138945275747462931559006763638612060474604554509550795966812356642042917363452960338457115020031120789490076363823059477978169077204763046262491762113637668511018482223361774121845706177451044161738746050766877434757946831223565527239248794315463305271779949208058882442095280247508627968155300497343796852202862275891120750390256408617409094008210261398024974884224628684715716894544417457681835995541069229911923137627//38564998830736521417281865696453025806593491967131023221754800625044118265468851210705360385717536794615180260494208076605798671660719333199513807806252394423283413430106003596332513246682903994829528690198205120921557533726473585751382193953592127439965050261476810842071573684505878854588706623484573925925903505747545471088867712185004135201289273405614415899438276535626346098904241020877974002916168099951885406379295536200413493190419727789712076165429067776000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                                                                                  646380695547819379379462110595350483323442009248798219582259024446464544132551698473809581856967370658487548204659626702292564992976158496529375784071763787592253430041646066314009418251081347658033077807894727674506660673057920454240886643468816490881054458605117293952007109054634081637211268136338650821833722847677488664849766203163787324732106652618777185431293544445474668250279073481131086314724562094446770240396090985922895943040057962860047030005371781373835035785147257040477418516657611117881834875218299885716266834779541157085670534199549342497110048855301431141761423177209449504715692545645531288355844442793377192971285135291013238861059535547536381876669229982900292241340160011803760056601165836520905723932492682377301319454029065863067972071145347687240835433388266357742534589282848560823758438409092468036851229133683325521477136527739510675196517661031060688353455828921203165442555541627063437450443175007153209//517610652338411247125091194937906278248634591141457661513916951298640145335453006427092274839221143832965212887398076520128024933571973574771371398838386057405297005067351460185957906049968291062814308810921896100805671839805065813156369093210647278367856544550122347590861343331896786250613857746265095538581506488867049470623751042202917069732186894727238934606968195284747923033659051938664223591447345684161896856058575310936125171656160723031361663708684162205273292800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                                                                  8813572275333935103416906132960621777114439444141647438438393753862988179987938832721184273969585102967467754980010070157566337119239854562632863958739529252701552386911176964405034482000877845003064456723043889756774450867335661101187923620690769719662220354335695798311755154012564019508697637433705198641352232164934271731689599505104756286149010104803971173588887614751600240293596938071050020381715583108625023759753393738598032521536448316590020179966102744430869710510004750450586729772303515586404571938281315619339180632083313992191945702244726898267871642409305486953268724327679433424951407071104066109102285627362450306825448652531631455682741766958888491690416428140178416796287551293015562399117395448453688862961061347809034853245381286200796207330060769671545355757344311231491079771497941834167729303081908176522671807233326506847483489756135442309818267518863626272611798974800987095037233771816523002200031070842864277033671134642403//6947252574545944471877627197737088174346755392521537393659097358399012979651430037341372277527182721482180237678288966210172977571138121768185158859627001581181653918534439996364172765366419849849364181449231848010219624385221589633232036842015330311191725363944820361567168306503513658105903059201890160889134614375299267401072260772210764407187169348166518951608784413937917928229658547784150744532806296935881538019052501315074027366329988944810663524927964212077525097869475840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                                                 120175396306816661567962374621260628614816898908130603456791258506661752158816764138355946608581111648754811275356266553194146487289970011521206302938350516439692698830565485671063124957581001985813711933633645259078108062496048585468892270573397374250419348298467866026065051327496126625966211919529492809946883329115587011078666703280156236855586771535787690208072551405979966710615670765008341976837702247734425622133716186858699168908901364438717264342619451907519562821993757807949284311972035986557650598491323972524603931519064752851585706054312058594719949638576121660783232383108957295631067768960287620832338037163277354938280475722726742662910468041915790311921524235141338322754706846323314939020948898862794933449368601120381306723818943912893036079998982040701877643402517997677027213445418199720233720320010396665109155653989028150312257462380364161291864607152883841218256979741199145521849881542278617665978410806969940456720443825181089585213684966801//93244445639770729862957501651127871609648939295598894004396565397511723957132517156291414749188392311819502398767993997219818753659311707791315470545820707967860914422798962606432752916695795974088280267869564598517299876599783853712075728174759257553768635074864690629768384949250922720794309199432719070009410782760880699063638360466965433587592874066215113935387298888055887737745183249936814734070168263882738171006284743922624810491863481443760464848830272021035557849901868779569152000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                                 1638623412429354568616301751922853165062178143570237809868003552419139731525207008014840385057094808550364022265598937908854560007761359201302534206737402807692400464255340884583551113600457074478398193829260671903408623257256918638344550520063772668911716725034710930551991674894972611899808216730842062998272110294468577188489521117566036367472120519200995130413089843947574203037759878714438894957215775888827327087684601532223092366221531321381581156578870580679772475683937879311488116796619715835741276270959196507639605482261723621713433086664848878328456065693446846127336706287037161239359880305409587491274511777885262373075163575581721009527514233124879843185501554931387437408536169975692089151929986328911859307334752043996902855680228690265685371832496623752200243917392455804140656929928494581593961635191153288675520454159469305085294704574693513943256409827056994632177252792094052051470442150934455756986752540284228302747677207523056397782475349694314971666973684267//1251505764238953380310790723217063156492278350986520395258292901865744044288949584763845459354175586006508115805319015342448238968794450346355026058791097531879778895383050816179236228126428300279367584898068436076222415813190335413631917039956177449583366403740944868375040179411785414948859053607735844243893605388086697470737326815552111955066160454615751415166882205681178758918321833875017541716382217695604557573133901205035650986064847896555168936823386256828536078182639385054790440032665600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                                 22343064972354224957479728113350949780887535331771171875613387648500150040113223878247360980060744795749139600967047698773976023825716749550816790048959630214024291450253822775597752506859958652993156369432205621106046955897352932772730437075711261897922223752076981370603845666571148563739751397868267477530534170057941586126867460170518844864494697419135689305804862898660459973467138685238383474453740580946286484621665119314190873607079738136863819984192230557369652571594272717804907202344994813159997266200695798241334728503709447203221423207356469728025768552535361151641594813114163751201865741331096235472064289773307514336130797690384014695762583913450057967476452114645805950514182594981422860829708262919876496710557833096659829409940579069682311025892212895827818852274344280241244125649458665933112767576600946408242226001592726350162502705017014799678405577891527233732317745485132196617377835361746048692485877388072155967761600004670740471374233078485232398111732065728284486083682089//16797426025505597180323426475367106769690204981299732607723004644694712665399418877354675409763379446686211251695080855446054459199265402449658467899173553735531149248066277025612272731441890321839848252186585707866380747311767925077561613338740335684791398530164032080655694478936221481797309836746050823857727758891755480154571048997687953221061814590197326795648367049015650538387689411549829040931804163870543930391122605951634723435058354534121380135661044065795059797970422730537112837730462261575680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+                 304653618746195407227163730322053916014053723110422517841663212509580133414870563836575120110686536695480977952772624365535866244332873061241508781399832428387630674513930691330101904718500293023050050607427115063669681175960942195506424032272471651202997578108749930421242453943184047368369010644749823498643293649551273090398280784531128183631032000069615743032947667239062468509040079935236177208481442271959808690696140664325113131314265183037989326932456072811588119452547655042672272627027134583718064095094039463733284097409615865832861209712359926308642772539377944587409962967122237590175479982785779905543006714406871097094026357618247456813205608858618077379847671759450329112666484299745038339155180488295039857022873030587080343463926426043822286460042109518151839354796204791318240797287518363486427798004869303012233120170679276644118435222844774404863091415468587316888561285613163612304906504998288703317237135069355519646441949776015247310544320628566775036316038856240879188327554671006066340045363//225451235739143130482621660669882103656123857644433259761609693674437158756273421423885518367590980693612040313054990119426585607799410158579879393738800746006890372530436409579627705493048468302253321227325456578709735148712759856718454352234022223757002566466115585318472006322496350419162828280010585455071241504098321847789561501104635433430119850185353627418544411222894525170437245598787501266228575781564409246128662754026769046536188789298827011803275711261889543970772915009224750475981532113842946965504000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ 4154032919386558883432944248380343483762044089219885824293861963690668280133800624271545564442460641100421478069957127705133139131053171319939289915624722195403241736871340745589519387833493153871994750550507166424767604170338332253959630697516305444248796250106488696552824425774652891031781638156634640665726706553562695794716367646798636566490125595141712720380867485868916531456648814528917577693417533965049279568879801863167212171389128029079788394889712773514836798543384276326561054294342851708282050876790968869065128360584151770000714515194551497614161342119347668187950856166437783338125107242946094385126468080818490755092469614835748767521966870937090173768929887202086899128132689201712566935821453568568851761907310360889009454819233203019261511646422045122043461427963067831419822632761257565485308244276118163333934078610669354885645888806741789229076806586507072844471249752898840782835318816592414922484506856439857852070928805249944302969170900303083044962139908567605824428891872081720287044135359380045755621121//3025955263570019164018502277869853398058543745963126397283707470775892712704232437030043920740033026198847216426264951289188498307633591122471111874163926157374989814610878574225506571713008520940845805558579429855707382314196875257835647882856218717417250856125102284683546912020709544155188247379716859572950811281937944702307676679453365814328593305957854274867553594143460475201489987084725797475032257007739929467758191052369579260681352907875927458926484892315482757871323905647524505025315981027903769053444125491200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Yeah...

sol[end]
4154032919386558883432944248380343483762044089219885824293861963690668280133800624271545564442460641100421478069957127705133139131053171319939289915624722195403241736871340745589519387833493153871994750550507166424767604170338332253959630697516305444248796250106488696552824425774652891031781638156634640665726706553562695794716367646798636566490125595141712720380867485868916531456648814528917577693417533965049279568879801863167212171389128029079788394889712773514836798543384276326561054294342851708282050876790968869065128360584151770000714515194551497614161342119347668187950856166437783338125107242946094385126468080818490755092469614835748767521966870937090173768929887202086899128132689201712566935821453568568851761907310360889009454819233203019261511646422045122043461427963067831419822632761257565485308244276118163333934078610669354885645888806741789229076806586507072844471249752898840782835318816592414922484506856439857852070928805249944302969170900303083044962139908567605824428891872081720287044135359380045755621121//3025955263570019164018502277869853398058543745963126397283707470775892712704232437030043920740033026198847216426264951289188498307633591122471111874163926157374989814610878574225506571713008520940845805558579429855707382314196875257835647882856218717417250856125102284683546912020709544155188247379716859572950811281937944702307676679453365814328593305957854274867553594143460475201489987084725797475032257007739929467758191052369579260681352907875927458926484892315482757871323905647524505025315981027903769053444125491200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

That's one huge fraction! 0 floating-point error ODE solve achieved.

Unit Checked Arithmetic via Unitful.jl

Units and dimensional analysis are standard tools across the sciences for checking the correctness of your equation. However, most ODE solvers only allow for the equation to be in dimensionless form, leaving it up to the user to both convert the equation to a dimensionless form, punch in the equations, and hopefully not make an error along the way.

DifferentialEquations.jl allows for one to use Unitful.jl to have unit-checked arithmetic natively in the solvers. Given the dispatch implementation of the Unitful, this has little overhead because the unit checks occur at compile-time and not at runtime, and thus it does not have a runtime effect unless conversions are required (i.e. converting cm to m), which automatically adds a floating-point operation for the multiplication.

Let's see this in action.

Using Unitful

To use Unitful, you need to have the package installed. Then you can add units to your variables. For example:

using Unitful
+t = 1.0u"s"
1.0 s

Notice that t is a variable with units in seconds. If we make another value with seconds, they can add:

t2 = 1.02u"s"
+t + t2
2.02 s

and they can multiply:

t * t2
1.02 s^2

You can even do rational roots:

sqrt(t)
1.0 s^1/2

Many operations work. These operations will check to make sure units are correct, and will throw an error for incorrect operations:

t + sqrt(t)

Using Unitful with DifferentialEquations.jl

Just like with other number systems, you can choose the units for your numbers by simply specifying the units of the initial condition and the timespan. For example, to solve the linear ODE where the variable has units of Newton's and t is in seconds, we would use:

using DifferentialEquations
+f(u, p, t) = 0.5 * u
+u0 = 1.5u"N"
+prob = ODEProblem(f, u0, (0.0u"s", 1.0u"s"))
+#sol = solve(prob,Tsit5())
ODEProblem with uType Unitful.Quantity{Float64, 𝐋 𝐌 𝐓^-2, Unitful.FreeUnits{(N,), 𝐋 𝐌 𝐓^-2, nothing}} and tType Unitful.Quantity{Float64, 𝐓, Unitful.FreeUnits{(s,), 𝐓, nothing}}. In-place: false
+timespan: (0.0 s, 1.0 s)
+u0: 1.5 N

Notice that we received a unit mismatch error. This is correctly so! Remember that for an ODE:

\[\frac{dy}{dt} = f(t,y)\]

we must have that f is a rate, i.e. f is a change in y per unit time. So, we need to fix the units of f in our example to be N/s. Notice that we then do not receive an error if we do the following:

f(y, p, t) = 0.5 * y / 3.0u"s"
+prob = ODEProblem(f, u0, (0.0u"s", 1.0u"s"))
+sol = solve(prob, Tsit5())
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 3-element Vector{Unitful.Quantity{Float64, 𝐓, Unitful.FreeUnits{(s,), 𝐓, nothing}}}:
+                 0.0 s
+ 0.14311598261241779 s
+                 1.0 s
+u: 3-element Vector{Unitful.Quantity{Float64, 𝐋 𝐌 𝐓^-2, Unitful.FreeUnits{(N,), 𝐋 𝐌 𝐓^-2, nothing}}}:
+                1.5 N
+ 1.5362091208988309 N
+ 1.7720406194871123 N

This gives a normal solution object. Notice that the values are all with the correct units:

print(sol[:])
Unitful.Quantity{Float64, 𝐋 𝐌 𝐓^-2, Unitful.FreeUnits{(N,), 𝐋 𝐌 𝐓^-2, nothing}}[1.5 N, 1.5362091208988309 N, 1.7720406194871123 N]

And when we plot the solution, it automatically adds the units:

using Plots
+gr()
+plot(sol, lw = 3)
Example block output

Measurements.jl: Numbers with Linear Uncertainty Propagation

The result of a measurement should be given as a number with an attached uncertainty, besides the physical unit, and all operations performed involving the result of the measurement should propagate the uncertainty, taking care of correlation between quantities.

There is a Julia package for dealing with numbers with uncertainties: Measurements.jl. Thanks to Julia's features, DifferentialEquations.jl easily works together with Measurements.jl out-of-the-box.

Let's try to automate uncertainty propagation through number types on some classical physics examples!

Warning about Measurement type

Before going on with the tutorial, we must point up a subtlety of Measurements.jl that you should be aware of:

using Measurements
+5.23 ± 0.14 === 5.23 ± 0.14
false
(5.23 ± 0.14) - (5.23 ± 0.14)

\[0.0 \pm 0.2\]

(5.23 ± 0.14) / (5.23 ± 0.14)

\[1.0 \pm 0.038\]

The two numbers above, even though have the same nominal value and the same uncertainties, are actually two different measurements that only by chance share the same figures and their difference and their ratio have a non-zero uncertainty. It is common in physics to get very similar, or even equal, results for a repeated measurement, but the two measurements are not the same thing.

Instead, if you have one measurement and want to perform some operations involving it, you have to assign it to a variable:

x = 5.23 ± 0.14
+x === x
true
x - x

\[0.0 \pm 0.0\]

x / x

\[1.0 \pm 0.0\]

With that in mind, let's start using Measurements.jl for realsies.

Automated UQ on an ODE: Radioactive Decay of Carbon-14

The rate of decay of carbon-14 is governed by a first order linear ordinary differential equation:

\[\frac{\mathrm{d}u(t)}{\mathrm{d}t} = -\frac{u(t)}{\tau}\]

where $\tau$ is the mean lifetime of carbon-14, which is related to the half-life $t_{1/2} = (5730 \pm 40)$ years by the relation $\tau = t_{1/2}/\ln(2)$. Writing this in DifferentialEquations.jl syntax, this looks like:

# Half-life and mean lifetime of radiocarbon, in years
+t_12 = 5730 ± 40
+τ = t_12 / log(2)
+
+#Setup
+u₀ = 1 ± 0
+tspan = (0.0, 10000.0)
+
+#Define the problem
+radioactivedecay(u, p, t) = -u / τ
+
+#Pass to solver
+prob = ODEProblem(radioactivedecay, u₀, tspan)
+sol = solve(prob, Tsit5(), reltol = 1e-8)
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 15-element Vector{Float64}:
+     0.0
+     0.15287276015505386
+     1.6816003617055924
+    16.968876377210975
+   169.84163653226483
+   630.950980263131
+  1273.5405688759733
+  2036.820743933165
+  2960.4188421148647
+  4014.4723211748314
+  5207.541628507064
+  6524.062666423843
+  7962.817489456584
+  9515.823531448306
+ 10000.0
+u: 15-element Vector{Measurements.Measurement{Float64}}:
+        1.0 ± 0.0
+ 0.99998151 ± 1.3e-7
+  0.9997966 ± 1.4e-6
+   0.997949 ± 1.4e-5
+    0.97966 ± 0.00014
+    0.92652 ± 0.00049
+    0.85722 ± 0.00092
+     0.7816 ± 0.0013
+      0.699 ± 0.0017
+     0.6153 ± 0.0021
+     0.5326 ± 0.0023
+     0.4542 ± 0.0025
+     0.3817 ± 0.0026
+     0.3163 ± 0.0025
+     0.2983 ± 0.0025

And bingo: numbers with uncertainty went in, so numbers with uncertainty came out. But can we trust those values for the uncertainty?

We can check the uncertainty quantification by evaluating an analytical solution to the ODE. Since it's a linear ODE, the analytical solution is simply given by the exponential:

u = exp.(-sol.t / τ)
15-element Vector{Measurements.Measurement{Float64}}:
+        1.0 ± 0.0
+ 0.99998151 ± 1.3e-7
+  0.9997966 ± 1.4e-6
+   0.997949 ± 1.4e-5
+    0.97966 ± 0.00014
+    0.92652 ± 0.00049
+    0.85722 ± 0.00092
+     0.7816 ± 0.0013
+      0.699 ± 0.0017
+     0.6153 ± 0.0021
+     0.5326 ± 0.0023
+     0.4542 ± 0.0025
+     0.3817 ± 0.0026
+     0.3163 ± 0.0025
+     0.2983 ± 0.0025

How do the two solutions compare?

plot(sol.t, sol.u, label = "Numerical", xlabel = "Years", ylabel = "Fraction of Carbon-14")
+plot!(sol.t, u, label = "Analytic")
Example block output

The two curves are perfectly superimposed, indicating that the numerical solution matches the analytic one. We can check that also the uncertainties are correctly propagated in the numerical solution:

println("Quantity of carbon-14 after ", sol.t[11], " years:")
+println("Numerical: ", sol[11])
+println("Analytic:  ", u[11])
Quantity of carbon-14 after 5207.541628507064 years:
+Numerical: 0.5326 ± 0.0023
+Analytic:  0.5326 ± 0.0023

Bullseye. Both the value of the numerical solution and its uncertainty match the analytic solution within the requested tolerance. We can also note that close to 5730 years after the beginning of the decay (half-life of the radioisotope), the fraction of carbon-14 that survived is about 0.5.

Simple pendulum: Small angles approximation

The next problem we are going to study is the simple pendulum in the approximation of small angles. We address this simplified case because there exists an easy analytic solution to compare.

The differential equation we want to solve is:

\[\ddot{\theta} + \frac{g}{L} \theta = 0\]

where $g = (9.79 \pm 0.02)~\mathrm{m}/\mathrm{s}^2$ is the gravitational acceleration measured where the experiment is carried out, and $L = (1.00 \pm 0.01)~\mathrm{m}$ is the length of the pendulum.

When you set up the problem for DifferentialEquations.jl remember to define the measurements as variables, as seen above.

using DifferentialEquations, Measurements, Plots
+
+g = 9.79 ± 0.02; # Gravitational constants
+L = 1.00 ± 0.01; # Length of the pendulum
+
+#Initial Conditions
+u₀ = [0 ± 0, π / 60 ± 0.01] # Initial speed and initial angle
+tspan = (0.0, 6.3)
+
+#Define the problem
+function simplependulum(du, u, p, t)
+    θ = u[1]
+    dθ = u[2]
+    du[1] = dθ
+    du[2] = -(g / L) * θ
+end
+
+#Pass to solvers
+prob = ODEProblem(simplependulum, u₀, tspan)
+sol = solve(prob, Tsit5(), reltol = 1e-6)
retcode: Success
+Interpolation: specialized 4th order "free" interpolation
+t: 68-element Vector{Float64}:
+ 0.0
+ 0.07248248631909444
+ 0.11977474504982777
+ 0.17806767401040355
+ 0.2389097135174905
+ 0.3037539550992628
+ 0.3717638639722829
+ 0.4426963668621525
+ 0.5162669123311059
+ 0.5923146283944006
+ ⋮
+ 5.525954290783653
+ 5.627441172884416
+ 5.728575515652614
+ 5.829199971234117
+ 5.929629941324541
+ 6.030620315734677
+ 6.13325058923572
+ 6.239645256049916
+ 6.3
+u: 68-element Vector{Vector{Measurements.Measurement{Float64}}}:
+ [0.0 ± 0.0, 0.052 ± 0.01]
+ [0.00376 ± 0.00072, 0.051 ± 0.0097]
+ [0.0061 ± 0.0012, 0.0487 ± 0.0093]
+ [0.0088 ± 0.0017, 0.0444 ± 0.0085]
+ [0.0114 ± 0.0022, 0.0384 ± 0.0073]
+ [0.0136 ± 0.0026, 0.0304 ± 0.0058]
+ [0.0154 ± 0.0029, 0.0208 ± 0.004]
+ [0.0164 ± 0.0031, 0.0097 ± 0.0019]
+ [0.0167 ± 0.0032, -0.00233 ± 0.00062]
+ [0.0161 ± 0.0031, -0.0146 ± 0.0028]
+ ⋮
+ [-0.0167 ± 0.0032, 0.0006 ± 0.0046]
+ [-0.0158 ± 0.0031, 0.0169 ± 0.0055]
+ [-0.0134 ± 0.0027, 0.0315 ± 0.0071]
+ [-0.0096 ± 0.0023, 0.0429 ± 0.0087]
+ [-0.0049 ± 0.0018, 0.0501 ± 0.0097]
+ [0.00033 ± 0.0016, 0.0523 ± 0.01]
+ [0.0056 ± 0.0019, 0.0493 ± 0.0096]
+ [0.0104 ± 0.0024, 0.0409 ± 0.0085]
+ [0.0127 ± 0.0026, 0.0341 ± 0.0076]

And that's it! What about comparing it this time to the analytical solution?

u = u₀[2] .* cos.(sqrt(g / L) .* sol.t)
+
+plot(sol.t, getindex.(sol.u, 2), label = "Numerical")
+plot!(sol.t, u, label = "Analytic")
Example block output

Bingo. Also in this case there is a perfect superimposition between the two curves, including their uncertainties.

We can also have a look at the difference between the two solutions:

plot(sol.t, getindex.(sol.u, 2) .- u, label = "")
Example block output

Tiny difference on the order of the chosen 1e-6 tolerance.

Simple pendulum: Arbitrary amplitude

Now that we know how to solve differential equations involving numbers with uncertainties, we can solve the simple pendulum problem without any approximation. This time, the differential equation to solve is the following:

\[\ddot{\theta} + \frac{g}{L} \sin(\theta) = 0\]

That would be done via:

g = 9.79 ± 0.02; # Gravitational constants
+L = 1.00 ± 0.01; # Length of the pendulum
+
+#Initial Conditions
+u₀ = [0 ± 0, π / 3 ± 0.02] # Initial speed and initial angle
+tspan = (0.0, 6.3)
+
+#Define the problem
+function simplependulum(du, u, p, t)
+    θ = u[1]
+    dθ = u[2]
+    du[1] = dθ
+    du[2] = -(g / L) * sin(θ)
+end
+
+#Pass to solvers
+prob = ODEProblem(simplependulum, u₀, tspan)
+sol = solve(prob, Tsit5(), reltol = 1e-6)
+
+plot(sol.t, getindex.(sol.u, 2), label = "Numerical")
Example block output

Warning about Linear Uncertainty Propagation

Measurements.jl uses linear uncertainty propagation, which has an error associated with it. MonteCarloMeasurements.jl has a page which showcases where this method can lead to incorrect uncertainty measurements. Thus for more nonlinear use cases, it's suggested that one uses one of the more powerful UQ methods, such as:

Basically, types can make the algorithm you want to run exceedingly simple to do, but make sure it's the correct algorithm!

diff --git a/v1.5.0/showcase/optimization_under_uncertainty/0cea76ad.svg b/v1.5.0/showcase/optimization_under_uncertainty/0cea76ad.svg new file mode 100644 index 00000000000..5a6eb5bb614 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/0cea76ad.svg @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/67d2dd6c.svg b/v1.5.0/showcase/optimization_under_uncertainty/67d2dd6c.svg new file mode 100644 index 00000000000..263716bb531 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/67d2dd6c.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/79ee2585.svg b/v1.5.0/showcase/optimization_under_uncertainty/79ee2585.svg new file mode 100644 index 00000000000..22d86837f77 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/79ee2585.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/7da7676f.svg b/v1.5.0/showcase/optimization_under_uncertainty/7da7676f.svg new file mode 100644 index 00000000000..c8336117ce9 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/7da7676f.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/ab0e7f3e.svg b/v1.5.0/showcase/optimization_under_uncertainty/ab0e7f3e.svg new file mode 100644 index 00000000000..c25c692f604 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/ab0e7f3e.svg @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/c967a9a6.svg b/v1.5.0/showcase/optimization_under_uncertainty/c967a9a6.svg new file mode 100644 index 00000000000..636b1ea3589 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/c967a9a6.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/e73b93f0.svg b/v1.5.0/showcase/optimization_under_uncertainty/e73b93f0.svg new file mode 100644 index 00000000000..01b256a0a96 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/e73b93f0.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/f3625363.svg b/v1.5.0/showcase/optimization_under_uncertainty/f3625363.svg new file mode 100644 index 00000000000..66e864b8eeb --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/f3625363.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/optimization_under_uncertainty/index.html b/v1.5.0/showcase/optimization_under_uncertainty/index.html new file mode 100644 index 00000000000..54347bda275 --- /dev/null +++ b/v1.5.0/showcase/optimization_under_uncertainty/index.html @@ -0,0 +1,174 @@ + +Optimization Under Uncertainty · Overview of Julia's SciML

Optimization Under Uncertainty

This tutorial showcases how to leverage the efficient Koopman expectation method from SciMLExpectations to perform optimization under uncertainty. We demonstrate this by using a bouncing ball model with an uncertain model parameter. We also demonstrate its application to problems with probabilistic constraints, in particular a special class of constraints called chance constraints.

System Model

First let's consider a 2D bouncing ball, where the states are the horizontal position $x$, horizontal velocity $\dot{x}$, vertical position $y$, and vertical velocity $\dot{y}$. This model has two system parameters, acceleration due to gravity and coefficient of restitution (models energy loss when the ball impacts the ground). We can simulate such a system using ContinuousCallback as

using DifferentialEquations, Plots
+
+function ball!(du, u, p, t)
+    du[1] = u[2]
+    du[2] = 0.0
+    du[3] = u[4]
+    du[4] = -p[1]
+end
+
+ground_condition(u, t, integrator) = u[3]
+ground_affect!(integrator) = integrator.u[4] = -integrator.p[2] * integrator.u[4]
+ground_cb = ContinuousCallback(ground_condition, ground_affect!)
+
+u0 = [0.0, 2.0, 50.0, 0.0]
+tspan = (0.0, 50.0)
+p = [9.807, 0.9]
+
+prob = ODEProblem(ball!, u0, tspan, p)
+sol = solve(prob, Tsit5(), callback = ground_cb)
+plot(sol, vars = (1, 3), label = nothing, xlabel = "x", ylabel = "y")
Example block output

For this particular problem, we wish to measure the impact distance from a point $y=25$ on a wall at $x=25$. So, we introduce an additional callback that terminates the simulation on wall impact.

stop_condition(u, t, integrator) = u[1] - 25.0
+stop_cb = ContinuousCallback(stop_condition, terminate!)
+cbs = CallbackSet(ground_cb, stop_cb)
+
+tspan = (0.0, 1500.0)
+prob = ODEProblem(ball!, u0, tspan, p)
+sol = solve(prob, Tsit5(), callback = cbs)
+plot(sol, vars = (1, 3), label = nothing, xlabel = "x", ylabel = "y")
Example block output

To help visualize this problem, we plot as follows, where the star indicates a desired impact location

rectangle(xc, yc, w, h) = Shape(xc .+ [-w, w, w, -w] ./ 2.0, yc .+ [-h, -h, h, h] ./ 2.0)
+
+begin
+    plot(sol, vars = (1, 3), label = nothing, lw = 3, c = :black)
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    ylims!(0.0, 50.0)
+end
Example block output

Considering Uncertainty

We now wish to introduce uncertainty in p[2], the coefficient of restitution. This is defined via a continuous univariate distribution from Distributions.jl. We can then run a Monte Carlo simulation of 100 trajectories via the EnsembleProblem interface.

using Distributions
+
+cor_dist = truncated(Normal(0.9, 0.02), 0.9 - 3 * 0.02, 1.0)
+trajectories = 100
+
+prob_func(prob, i, repeat) = remake(prob, p = [p[1], rand(cor_dist)])
+ensemble_prob = EnsembleProblem(prob, prob_func = prob_func)
+ensemblesol = solve(ensemble_prob, Tsit5(), EnsembleThreads(), trajectories = trajectories,
+    callback = cbs)
+
+begin # plot
+    plot(ensemblesol, vars = (1, 3), lw = 1)
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    plot!(sol, vars = (1, 3), label = nothing, lw = 3, c = :black, ls = :dash)
+    xlims!(0.0, 27.5)
+end
Example block output

Here, we plot the first 350 Monte Carlo simulations along with the trajectory corresponding to the mean of the distribution (dashed line).

We now wish to compute the expected squared impact distance from the star. This is called an “observation” of our system or an “observable” of interest.

We define this observable as

obs(sol, p) = abs2(sol[3, end] - 25)
obs (generic function with 1 method)

With the observable defined, we can compute the expected squared miss distance from our Monte Carlo simulation results as

mean_ensemble = mean([obs(sol, p) for sol in ensemblesol])
42.485800772977925

Alternatively, we can use the Koopman() algorithm in SciMLExpectations.jl to compute this expectation much more efficiently as

using SciMLExpectations
+gd = GenericDistribution(cor_dist)
+h(x, u, p) = u, [p[1]; x[1]]
+sm = SystemMap(prob, Tsit5(), callback = cbs)
+exprob = ExpectationProblem(sm, obs, h, gd; nout = 1)
+sol = solve(exprob, Koopman(), ireltol = 1e-5)
+sol.u
36.008628214148686

Optimization Under Uncertainty

We now wish to optimize the initial position ($x_0,y_0$) and horizontal velocity ($\dot{x}_0$) of the system to minimize the expected squared miss distance from the star, where $x_0\in\left[-100,0\right]$, $y_0\in\left[1,3\right]$, and $\dot{x}_0\in\left[10,50\right]$. We will demonstrate this using a gradient-based optimization approach from NLopt.jl using ForwardDiff.jl AD through the expectation calculation.

using Optimization, OptimizationNLopt, OptimizationMOI
+make_u0(θ) = [θ[1], θ[2], θ[3], 0.0]
+function 𝔼_loss(θ, pars)
+    prob = ODEProblem(ball!, make_u0(θ), tspan, p)
+    sm = SystemMap(prob, Tsit5(), callback = cbs)
+    exprob = ExpectationProblem(sm, obs, h, gd; nout = 1)
+    sol = solve(exprob, Koopman(), ireltol = 1e-5)
+    sol.u
+end
+opt_f = OptimizationFunction(𝔼_loss, Optimization.AutoForwardDiff())
+opt_ini = [-1.0, 2.0, 50.0]
+opt_lb = [-100.0, 1.0, 10.0]
+opt_ub = [0.0, 3.0, 50.0]
+opt_prob = OptimizationProblem(opt_f, opt_ini; lb = opt_lb, ub = opt_ub)
+optimizer = OptimizationMOI.MOI.OptimizerWithAttributes(NLopt.Optimizer,
+    "algorithm" => :LD_MMA)
+opt_sol = solve(opt_prob, optimizer)
+minx = opt_sol.u
3-element Vector{Float64}:
+  0.0
+  2.442846992738232
+ 49.21237595923405

Let's now visualize 100 Monte Carlo simulations

ensembleprob = EnsembleProblem(remake(prob, u0 = make_u0(minx)), prob_func = prob_func)
+ensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(), trajectories = 100,
+    callback = cbs)
+
+begin
+    plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)
+    plot!(solve(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = cbs),
+        vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    ylims!(0.0, 50.0)
+    xlims!(minx[1], 27.5)
+end
Example block output

Looks pretty good! But, how long did it take? Let's benchmark.

@time solve(opt_prob, optimizer)
retcode: Success
+u: 3-element Vector{Float64}:
+  0.0
+  2.442846992738232
+ 49.21237595923405

Not bad for bound constrained optimization under uncertainty of a hybrid system!

Probabilistic Constraints

With this approach, we can also consider probabilistic constraints. Let us now consider a wall at $x=20$ with height 25.

constraint = [20.0, 25.0]
+begin
+    plot(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black,
+        label = nothing)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    ylims!(0.0, 50.0)
+    xlims!(minx[1], 27.5)
+end
Example block output

We now wish to minimize the same loss function as before, but introduce an inequality constraint such that the solution must have less than a 1% chance of colliding with the wall at $x=20$. This class of probabilistic constraints is called a chance constraint.

To do this, we first introduce a new callback and solve the system using the previous optimal solution

constraint_condition(u, t, integrator) = u[1] - constraint[1]
+function constraint_affect!(integrator)
+    integrator.u[3] < constraint[2] ? terminate!(integrator) : nothing
+end
+constraint_cb = ContinuousCallback(constraint_condition, constraint_affect!,
+    save_positions = (true, false));
+constraint_cbs = CallbackSet(ground_cb, stop_cb, constraint_cb)
+
+ensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(), trajectories = 500,
+    callback = constraint_cbs)
+
+begin
+    plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)
+    plot!(solve(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = constraint_cbs),
+        vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)
+
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    ylims!(0.0, 50.0)
+    xlims!(minx[1], 27.5)
+end
Example block output

That doesn't look good!

We now need a second observable for the system. To compute a probability of impact, we use an indicator function for if a trajectory impacts the wall. In other words, this functions returns 1 if the trajectory hits the wall and 0 otherwise.

function constraint_obs(sol, p)
+    sol((constraint[1] - sol[1, 1]) / sol[2, 1])[3] <= constraint[2] ? one(sol[1, end]) :
+    zero(sol[1, end])
+end
constraint_obs (generic function with 1 method)

Using the previously computed optimal initial conditions, let's compute the probability of hitting this wall

sm = SystemMap(remake(prob, u0 = make_u0(minx)), Tsit5(), callback = cbs)
+exprob = ExpectationProblem(sm, constraint_obs, h, gd; nout = 1)
+sol = solve(exprob, Koopman(), ireltol = 1e-5)
+sol.u
0.9988981583360147

We then set up the constraint function for NLopt just as before.

function 𝔼_constraint(res, θ, pars)
+    prob = ODEProblem(ball!, make_u0(θ), tspan, p)
+    sm = SystemMap(prob, Tsit5(), callback = cbs)
+    exprob = ExpectationProblem(sm, constraint_obs, h, gd; nout = 1)
+    sol = solve(exprob, Koopman(), ireltol = 1e-5)
+    res .= sol.u
+end
+opt_lcons = [-Inf]
+opt_ucons = [0.01]
+optimizer = OptimizationMOI.MOI.OptimizerWithAttributes(NLopt.Optimizer,
+    "algorithm" => :LD_MMA)
+opt_f = OptimizationFunction(𝔼_loss, Optimization.AutoForwardDiff(), cons = 𝔼_constraint)
+opt_prob = OptimizationProblem(opt_f, opt_ini; lb = opt_lb, ub = opt_ub, lcons = opt_lcons,
+    ucons = opt_ucons)
+opt_sol = solve(opt_prob, optimizer)
+minx2 = opt_sol.u
3-element Vector{Float64}:
+ -0.8933087539118127
+  2.0005561486579375
+ 50.0

The probability of impacting the wall is now

container = zeros(1)
+𝔼_constraint(container, minx2, nothing)
+λ = container[1]
0.0024804394521740487

We can check if this is within tolerance by

λ <= 0.01 + 1e-5
true

Again, we plot some Monte Carlo simulations from this result as follows

ensembleprob = EnsembleProblem(remake(prob, u0 = make_u0(minx2)), prob_func = prob_func)
+ensemblesol = solve(ensembleprob, Tsit5(), EnsembleThreads(),
+    trajectories = 500, callback = constraint_cbs)
+
+begin
+    plot(ensemblesol, vars = (1, 3), lw = 1, alpha = 0.1)
+    plot!(solve(remake(prob, u0 = make_u0(minx2)), Tsit5(), callback = constraint_cbs),
+        vars = (1, 3), label = nothing, c = :black, lw = 3, ls = :dash)
+    plot!([constraint[1], constraint[1]], [0.0, constraint[2]], lw = 5, c = :black)
+
+    xlabel!("x [m]")
+    ylabel!("y [m]")
+    plot!(rectangle(27.5, 25, 5, 50), c = :red, label = nothing)
+    scatter!([25], [25], marker = :star, ms = 10, label = nothing, c = :green)
+    ylims!(0.0, 50.0)
+    xlims!(minx[1], 27.5)
+end
Example block output
diff --git a/v1.5.0/showcase/pinngpu/index.html b/v1.5.0/showcase/pinngpu/index.html new file mode 100644 index 00000000000..c04f19ed7aa --- /dev/null +++ b/v1.5.0/showcase/pinngpu/index.html @@ -0,0 +1,99 @@ + +GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers · Overview of Julia's SciML

GPU-Accelerated Physics-Informed Neural Network (PINN) PDE Solvers

Machine learning is all the rage. Everybody thinks physics is cool.

Therefore, using machine learning to solve physics equations? 🧠💥

So let's be cool and use a physics-informed neural network (PINN) to solve the Heat Equation. Let's be even cooler by using GPUs (ironically, creating even more heat, but it's the heat equation so that's cool).

Step 1: Import Libraries

To solve PDEs using neural networks, we will use the NeuralPDE.jl package. This package uses ModelingToolkit's symbolic PDESystem as an input, and it generates an Optimization.jl OptimizationProblem which, when solved, gives the weights of the neural network that solve the PDE. In the end, our neural network NN satisfies the PDE equations and is thus the solution to the PDE! Thus our packages look like:

# High Level Interface
+using NeuralPDE
+import ModelingToolkit: Interval
+
+# Optimization Libraries
+using Optimization, OptimizationOptimisers
+
+# Machine Learning Libraries and Helpers
+using Lux, LuxCUDA, ComponentArrays
+const gpud = gpu_device() # allocate a GPU device
+
+# Standard Libraries
+using Printf, Random
+
+# Plotting
+using Plots

Problem Setup

Let's solve the 2+1-dimensional Heat Equation. This is the PDE:

\[∂_t u(x, y, t) = ∂^2_x u(x, y, t) + ∂^2_y u(x, y, t) \, ,\]

with the initial and boundary conditions:

\[\begin{align*} +u(x, y, 0) &= e^{x+y} \cos(x + y) \, ,\\ +u(0, y, t) &= e^{y} \cos(y + 4t) \, ,\\ +u(2, y, t) &= e^{2+y} \cos(2 + y + 4t) \, ,\\ +u(x, 0, t) &= e^{x} \cos(x + 4t) \, ,\\ +u(x, 2, t) &= e^{x+2} \cos(x + 2 + 4t) \, , +\end{align*}\]

on the space and time domain:

\[x \in [0, 2] \, ,\ y \in [0, 2] \, , \ t \in [0, 2] \, ,\]

with physics-informed neural networks.

Step 2: Define the PDESystem

First, let's use ModelingToolkit's PDESystem to represent the PDE. To do this, basically just copy-paste the PDE definition into Julia code. This looks like:

@parameters t x y
+@variables u(..)
+Dxx = Differential(x)^2
+Dyy = Differential(y)^2
+Dt = Differential(t)
+t_min = 0.0
+t_max = 2.0
+x_min = 0.0
+x_max = 2.0
+y_min = 0.0
+y_max = 2.0
+
+# 2D PDE
+eq = Dt(u(t, x, y)) ~ Dxx(u(t, x, y)) + Dyy(u(t, x, y))
+
+analytic_sol_func(t, x, y) = exp(x + y) * cos(x + y + 4t)
+# Initial and boundary conditions
+bcs = [u(t_min, x, y) ~ analytic_sol_func(t_min, x, y),
+    u(t, x_min, y) ~ analytic_sol_func(t, x_min, y),
+    u(t, x_max, y) ~ analytic_sol_func(t, x_max, y),
+    u(t, x, y_min) ~ analytic_sol_func(t, x, y_min),
+    u(t, x, y_max) ~ analytic_sol_func(t, x, y_max)]
+
+# Space and time domains
+domains = [t ∈ Interval(t_min, t_max),
+    x ∈ Interval(x_min, x_max),
+    y ∈ Interval(y_min, y_max)]
+
+@named pde_system = PDESystem(eq, bcs, domains, [t, x, y], [u(t, x, y)])

\[ \begin{align} +\frac{\mathrm{d}}{\mathrm{d}t} u\left( t, x, y \right) =& \frac{\mathrm{d}}{\mathrm{d}x} \frac{\mathrm{d}}{\mathrm{d}x} u\left( t, x, y \right) + \frac{\mathrm{d}}{\mathrm{d}y} \frac{\mathrm{d}}{\mathrm{d}y} u\left( t, x, y \right) +\end{align} + \]

Note

We used the wildcard form of the variable definition @variables u(..) which then requires that we always specify what the dependent variables of u are. This is because in the boundary conditions we change from using u(t,x,y) to more specific points and lines, like u(t,x_max,y).

Step 3: Define the Lux Neural Network

Now let's define the neural network that will act as our solution. We will use a simple multi-layer perceptron, like:

using Lux
+inner = 25
+chain = Chain(Dense(3, inner, Lux.σ),
+              Dense(inner, inner, Lux.σ),
+              Dense(inner, inner, Lux.σ),
+              Dense(inner, inner, Lux.σ),
+              Dense(inner, 1))
+ps = Lux.setup(Random.default_rng(), chain)[1]
(layer_1 = (weight = Float32[-0.21653835 -0.2788135 0.15845601; -0.4313532 -0.29243907 -0.1872543; … ; 0.45559987 0.33954182 -0.16804923; 0.07471113 -0.35768065 -0.37301898], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = Float32[0.26950684 0.33956987 … -0.30988565 -0.14506042; 0.20739606 -0.21756244 … 0.0719788 0.26596156; … ; -0.18271604 0.20203647 … 0.143592 -0.28776315; 0.06284527 -0.22925755 … -0.2894843 0.20103407], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = Float32[0.29379922 -0.13323869 … -0.2927774 0.34363434; -0.21001212 0.23144989 … 0.11539032 0.34403208; … ; 0.33079174 -0.24242778 … 0.19722833 0.05570956; -0.27379668 -0.32514918 … 0.25954324 -0.31445685], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = Float32[0.27696726 -0.20179878 … -0.13121808 0.021166364; 0.05475002 0.001059555 … 0.049051683 -0.27345127; … ; 0.04456156 -0.19938816 … 0.33973992 -0.0543049; -0.2775214 0.13265593 … -0.17976801 0.30409518], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = Float32[-0.12908761 -0.18089952 … 0.15682809 -0.19021726], bias = Float32[0.0;;]))

Step 4: Place it on the GPU.

Just plop it on that sucker. We must ensure that our initial parameters for the neural network are on the GPU. If that is done, then the internal computations will all take place on the GPU. This is done by using the gpud function (i.e. the GPU device we created at the start) on the initial parameters, like:

ps = ps |> ComponentArray |> gpud .|> Float64
ComponentArrays.ComponentVector{Float64, CUDA.CuArray{Float64, 1, CUDA.Mem.DeviceBuffer}, Tuple{ComponentArrays.Axis{(layer_1 = ViewAxis(1:100, Axis(weight = ViewAxis(1:75, ShapedAxis((25, 3))), bias = ViewAxis(76:100, ShapedAxis((25, 1))))), layer_2 = ViewAxis(101:750, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_3 = ViewAxis(751:1400, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_4 = ViewAxis(1401:2050, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_5 = ViewAxis(2051:2076, Axis(weight = ViewAxis(1:25, ShapedAxis((1, 25))), bias = ViewAxis(26:26, ShapedAxis((1, 1))))))}}}(layer_1 = (weight = [-0.21653835475444794 -0.27881351113319397 0.1584560126066208; -0.43135321140289307 -0.2924390733242035 -0.18725429475307465; … ; 0.4555998742580414 0.33954182267189026 -0.16804923117160797; 0.07471112906932831 -0.35768064856529236 -0.3730189800262451], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [0.2695068418979645 0.3395698666572571 … -0.3098856508731842 -0.14506042003631592; 0.20739606022834778 -0.21756243705749512 … 0.07197879999876022 0.26596155762672424; … ; -0.18271604180335999 0.20203647017478943 … 0.1435920000076294 -0.28776314854621887; 0.06284526735544205 -0.22925755381584167 … -0.28948429226875305 0.2010340690612793], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.2937992215156555 -0.13323868811130524 … -0.2927773892879486 0.34363433718681335; -0.21001212298870087 0.2314498871564865 … 0.11539032310247421 0.34403207898139954; … ; 0.33079174160957336 -0.2424277812242508 … 0.1972283273935318 0.055709559470415115; -0.2737966775894165 -0.32514917850494385 … 0.259543240070343 -0.31445685029029846], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [0.27696725726127625 -0.20179878175258636 … -0.1312180757522583 0.02116636373102665; 0.054750021547079086 0.0010595549829304218 … 0.049051683396101 -0.2734512686729431; … ; 0.044561561197042465 -0.19938816130161285 … 0.33973991870880127 -0.054304901510477066; -0.27752140164375305 0.13265593349933624 … -0.17976801097393036 0.30409517884254456], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [-0.12908761203289032 -0.180899515748024 … 0.15682809054851532 -0.1902172565460205], bias = [0.0;;]))

Step 5: Discretize the PDE via a PINN Training Strategy

strategy = GridTraining(0.05)
+discretization = PhysicsInformedNN(chain,
+                                   strategy,
+                                   init_params = ps)
+prob = discretize(pde_system, discretization)
OptimizationProblem. In-place: true
+u0: ComponentArrays.ComponentVector{Float64, CUDA.CuArray{Float64, 1, CUDA.Mem.DeviceBuffer}, Tuple{ComponentArrays.Axis{(layer_1 = ViewAxis(1:100, Axis(weight = ViewAxis(1:75, ShapedAxis((25, 3))), bias = ViewAxis(76:100, ShapedAxis((25, 1))))), layer_2 = ViewAxis(101:750, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_3 = ViewAxis(751:1400, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_4 = ViewAxis(1401:2050, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_5 = ViewAxis(2051:2076, Axis(weight = ViewAxis(1:25, ShapedAxis((1, 25))), bias = ViewAxis(26:26, ShapedAxis((1, 1))))))}}}(layer_1 = (weight = [-0.21653835475444794 -0.27881351113319397 0.1584560126066208; -0.43135321140289307 -0.2924390733242035 -0.18725429475307465; … ; 0.4555998742580414 0.33954182267189026 -0.16804923117160797; 0.07471112906932831 -0.35768064856529236 -0.3730189800262451], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [0.2695068418979645 0.3395698666572571 … -0.3098856508731842 -0.14506042003631592; 0.20739606022834778 -0.21756243705749512 … 0.07197879999876022 0.26596155762672424; … ; -0.18271604180335999 0.20203647017478943 … 0.1435920000076294 -0.28776314854621887; 0.06284526735544205 -0.22925755381584167 … -0.28948429226875305 0.2010340690612793], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.2937992215156555 -0.13323868811130524 … -0.2927773892879486 0.34363433718681335; -0.21001212298870087 0.2314498871564865 … 0.11539032310247421 0.34403207898139954; … ; 0.33079174160957336 -0.2424277812242508 … 0.1972283273935318 0.055709559470415115; -0.2737966775894165 -0.32514917850494385 … 0.259543240070343 -0.31445685029029846], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [0.27696725726127625 -0.20179878175258636 … -0.1312180757522583 0.02116636373102665; 0.054750021547079086 0.0010595549829304218 … 0.049051683396101 -0.2734512686729431; … ; 0.044561561197042465 -0.19938816130161285 … 0.33973991870880127 -0.054304901510477066; -0.27752140164375305 0.13265593349933624 … -0.17976801097393036 0.30409517884254456], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [-0.12908761203289032 -0.180899515748024 … 0.15682809054851532 -0.1902172565460205], bias = [0.0;;]))

Step 6: Solve the Optimization Problem

callback = function (p, l)
+    println("Current loss is: $l")
+    return false
+end
+
+res = Optimization.solve(prob, Adam(0.01); callback = callback, maxiters = 2500);
retcode: Default
+u: ComponentArrays.ComponentVector{Float64, CUDA.CuArray{Float64, 1, CUDA.Mem.DeviceBuffer}, Tuple{ComponentArrays.Axis{(layer_1 = ViewAxis(1:100, Axis(weight = ViewAxis(1:75, ShapedAxis((25, 3))), bias = ViewAxis(76:100, ShapedAxis((25, 1))))), layer_2 = ViewAxis(101:750, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_3 = ViewAxis(751:1400, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_4 = ViewAxis(1401:2050, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_5 = ViewAxis(2051:2076, Axis(weight = ViewAxis(1:25, ShapedAxis((1, 25))), bias = ViewAxis(26:26, ShapedAxis((1, 1))))))}}}(layer_1 = (weight = [2.04903290815737 -0.07538307307051632 0.22777790044025695; -4.363711101961435 -0.5521094860040026 -0.38988109536165144; … ; 3.3771013815113333 0.4062354497739069 0.3519601032697655; -0.2744715910322122 -0.6153429275262587 -0.7099679896245972], bias = [-0.6197173101161215; 2.976574792762961; … ; -0.5045425478476505; 1.539748848451386;;]), layer_2 = (weight = [0.48827390018302164 0.23701381689799678 … -1.7723233991967386 -1.1435386693282232; 0.15384480251461272 -0.2663292172899997 … 1.3845716346857246 0.4726133614869473; … ; -0.14088706632156028 2.081286142143574 … -1.7525704074985002 0.6705237979524846; 0.29864086448377913 0.04538540548665394 … -1.726921196445183 -0.33780407663426726], bias = [-0.031674535699825555; 0.06628030325919904; … ; 0.16065908064268142; 0.054990350301324466;;]), layer_3 = (weight = [2.0417073616212695 -1.1783434355289153 … 0.8025654135235771 1.8777706890850037; 0.3213655240443304 -0.23510729441309658 … 2.044503105345231 1.1879909457362356; … ; 1.716635125900212 -1.0677188266688769 … 1.336034798847621 1.2810147970428123; 1.375319460632409 -1.1531867749194762 … 1.6805453486035222 1.183338217497328], bias = [0.07219304868703873; -0.21045698126171308; … ; -0.34392614519913245; 0.14867561756342176;;]), layer_4 = (weight = [1.999737531556317 0.5368102923787883 … 1.2187759762881052 1.5220069449149838; 1.4562493570117117 1.1188574864157896 … 1.1227852112905112 1.186441393295572; … ; -1.3821689031972386 -1.2546149384527998 … -0.7911795938033117 -1.4972046808399682; 1.1036471127390057 1.3407225261511717 … 0.8188365711899179 1.676197572206408], bias = [-1.048879675617043; -1.081801863856321; … ; 1.142002491358277; -1.0254743224581535;;]), layer_5 = (weight = [-2.829342898373975 -2.3107218375303558 … 7.313708085133177 -2.0771500065351276], bias = [3.0187012967760025;;]))

We then use the remake function to rebuild the PDE problem to start a new optimization at the optimized parameters, and continue with a lower learning rate:

prob = remake(prob, u0 = res.u)
+res = Optimization.solve(prob, Adam(0.001); callback = callback, maxiters = 2500);
retcode: Default
+u: ComponentArrays.ComponentVector{Float64, CUDA.CuArray{Float64, 1, CUDA.Mem.DeviceBuffer}, Tuple{ComponentArrays.Axis{(layer_1 = ViewAxis(1:100, Axis(weight = ViewAxis(1:75, ShapedAxis((25, 3))), bias = ViewAxis(76:100, ShapedAxis((25, 1))))), layer_2 = ViewAxis(101:750, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_3 = ViewAxis(751:1400, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_4 = ViewAxis(1401:2050, Axis(weight = ViewAxis(1:625, ShapedAxis((25, 25))), bias = ViewAxis(626:650, ShapedAxis((25, 1))))), layer_5 = ViewAxis(2051:2076, Axis(weight = ViewAxis(1:25, ShapedAxis((1, 25))), bias = ViewAxis(26:26, ShapedAxis((1, 1))))))}}}(layer_1 = (weight = [1.9965864090611645 -0.06306092088695883 0.1102543578773271; -4.002877464133143 -0.5229968818804637 -0.43202791700215926; … ; 3.4320695860543626 0.396099099551297 0.3764039771540729; -0.4366373655610087 -0.49769958746112297 -0.5539593550998101], bias = [-0.7236266522366344; 3.1664447453946667; … ; -0.517161379860444; 1.692292589774905;;]), layer_2 = (weight = [0.45478030445566553 0.2892344437913866 … -1.8141398284889778 -1.2414956802432258; 0.10653099790079554 -0.2695749248577215 … 1.3559276840060863 0.4772226666824938; … ; -0.1644617453350173 2.081544954119556 … -1.7866853583386957 0.6041424036724425; 0.3053119517763879 0.1004120298382775 … -1.7284049199950013 -0.37891577287368966], bias = [-0.06694318957359072; 0.03735068035954571; … ; 0.12978222873506964; 0.05222267130551886;;]), layer_3 = (weight = [2.1960291116857347 -1.1797486464758393 … 0.8924716931671871 2.001629917942432; 0.3742401008323339 -0.21844510916152804 … 2.024588643909717 1.13869529646581; … ; 1.7428167432602277 -1.0642773381818178 … 1.4089584734992164 1.359638692595929; 1.4308060154057922 -1.163267623274223 … 1.6977742092942392 1.2139666577452837], bias = [0.10966980071223487; -0.2324478513696482; … ; -0.30056937259722144; 0.15298432384847344;;]), layer_4 = (weight = [2.49603455645492 0.7563683624613512 … 1.4681765759470153 1.5533569681863657; 1.3802072512139676 1.2942270953165425 … 1.2838131479297838 1.2042990400889106; … ; -1.6038339846943879 -1.4046216915913907 … -0.9681287483753553 -1.498124369248894; 1.2129617224955573 1.5022334260364698 … 1.075269659501996 1.7916411135602985], bias = [-0.969925401821548; -1.0691663751234455; … ; 1.0597889036725514; -1.0040722552650927;;]), layer_5 = (weight = [-1.4870608539052952 -1.1894329356475106 … 7.584782402156827 -0.956649521495493], bias = [4.055866363753149;;]))

Step 7: Inspect the PINN's Solution

Finally, we inspect the solution:

phi = discretization.phi
+ts, xs, ys = [infimum(d.domain):0.1:supremum(d.domain) for d in domains]
+u_real = [analytic_sol_func(t, x, y) for t in ts for x in xs for y in ys]
+u_predict = [first(Array(phi([t, x, y], res.u))) for t in ts for x in xs for y in ys]
+
+function plot_(res)
+    # Animate
+    anim = @animate for (i, t) in enumerate(0:0.05:t_max)
+        @info "Animating frame $i..."
+        u_real = reshape([analytic_sol_func(t, x, y) for x in xs for y in ys],
+                         (length(xs), length(ys)))
+        u_predict = reshape([Array(phi([t, x, y], res.u))[1] for x in xs for y in ys],
+                            length(xs), length(ys))
+        u_error = abs.(u_predict .- u_real)
+        title = @sprintf("predict, t = %.3f", t)
+        p1 = plot(xs, ys, u_predict, st = :surface, label = "", title = title)
+        title = @sprintf("real")
+        p2 = plot(xs, ys, u_real, st = :surface, label = "", title = title)
+        title = @sprintf("error")
+        p3 = plot(xs, ys, u_error, st = :contourf, label = "", title = title)
+        plot(p1, p2, p3)
+    end
+    gif(anim, "3pde.gif", fps = 10)
+end
+
+plot_(res)

3pde

diff --git a/v1.5.0/showcase/showcase/index.html b/v1.5.0/showcase/showcase/index.html new file mode 100644 index 00000000000..719c6465e42 --- /dev/null +++ b/v1.5.0/showcase/showcase/index.html @@ -0,0 +1,2 @@ + +The SciML Showcase · Overview of Julia's SciML

The SciML Showcase

The SciML Showcase is a display of some cool things that can be done by connecting SciML software.

Note

The SciML Showcase is not meant to be training/tutorials, but inspirational demonstrations! If you're looking for simple examples to get started with, check out the getting started section.

Want to see some cool things that you can do with SciML? Check out the following:

diff --git a/v1.5.0/showcase/symbolic_analysis/17b5286a.svg b/v1.5.0/showcase/symbolic_analysis/17b5286a.svg new file mode 100644 index 00000000000..8ab7f870b82 --- /dev/null +++ b/v1.5.0/showcase/symbolic_analysis/17b5286a.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/symbolic_analysis/85954770.svg b/v1.5.0/showcase/symbolic_analysis/85954770.svg new file mode 100644 index 00000000000..216abfdb659 --- /dev/null +++ b/v1.5.0/showcase/symbolic_analysis/85954770.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/symbolic_analysis/cca78dd2.svg b/v1.5.0/showcase/symbolic_analysis/cca78dd2.svg new file mode 100644 index 00000000000..ff8ffbd08e3 --- /dev/null +++ b/v1.5.0/showcase/symbolic_analysis/cca78dd2.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/v1.5.0/showcase/symbolic_analysis/index.html b/v1.5.0/showcase/symbolic_analysis/index.html new file mode 100644 index 00000000000..688874d4eb7 --- /dev/null +++ b/v1.5.0/showcase/symbolic_analysis/index.html @@ -0,0 +1,178 @@ + +Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability · Overview of Julia's SciML

Symbolic-Numeric Analysis of Parameter Identifiability and Model Stability

The mixture of symbolic computing with numeric computing, which we call symbolic-numeric programming, is one of the central features of the SciML ecosystem. With core aspects like the Symbolics.jl Computer Algebra System and its integration via ModelingToolkit.jl, the SciML ecosystem gracefully mixes analytical symbolic computations with the numerical solver processes to accelerate solvers, give additional information (sparsity, identifiability), automatically fix numerical stability issues, and more.

In this showcase, we will highlight two aspects of symbolic-numeric programming.

  1. Automated index reduction of DAEs. While arbitrary differential-algebraic equation systems can be written in DifferentialEquations.jl, not all mathematical formulations of a system are equivalent. Some are numerically difficult to solve, or even require special solvers. Some are easy. Can we recognize which formulations are hard and automatically transform them into the easy ones? Yes.
  2. Structural parameter identifiability. When fitting parameters to data, there's always assumptions about whether there is a unique parameter set that achieves such a data fit. But is this actually the case? The structural identifiability tooling allows one to analytically determine whether, in the limit of infinite data on a subset of observables, one could in theory uniquely identify the parameters (global identifiability), identify the parameters up to a discrete set (local identifiability), or whether there's an infinite manifold of solutions to the inverse problem (nonidentifiable).

Let's dig into these two cases!

Automated Index Reduction of DAEs

In many cases one may accidentally write down a DAE that is not easily solvable by numerical methods. In this tutorial, we will walk through an example of a pendulum which accidentally generates an index-3 DAE, and show how to use the modelingtoolkitize to correct the model definition before solving.

Copy-Pastable Example

using ModelingToolkit
+using LinearAlgebra
+using OrdinaryDiffEq
+using Plots
+
+function pendulum!(du, u, p, t)
+    x, dx, y, dy, T = u
+    g, L = p
+    du[1] = dx
+    du[2] = T * x
+    du[3] = dy
+    du[4] = T * y - g
+    du[5] = x^2 + y^2 - L^2
+    return nothing
+end
+pendulum_fun! = ODEFunction(pendulum!, mass_matrix = Diagonal([1, 1, 1, 1, 0]))
+u0 = [1.0, 0, 0, 0, 0]
+p = [9.8, 1]
+tspan = (0, 10.0)
+pendulum_prob = ODEProblem(pendulum_fun!, u0, tspan, p)
+traced_sys = modelingtoolkitize(pendulum_prob)
+pendulum_sys = structural_simplify(dae_index_lowering(traced_sys))
+prob = ODEProblem(pendulum_sys, [], tspan)
+sol = solve(prob, Rodas5P(), abstol = 1e-8, reltol = 1e-8)
+plot(sol, vars = unknowns(traced_sys))
Example block output

Explanation

Attempting to Solve the Equation

In this tutorial, we will look at the pendulum system:

\[\begin{aligned} + x^\prime &= v_x\\ + v_x^\prime &= Tx\\ + y^\prime &= v_y\\ + v_y^\prime &= Ty - g\\ + 0 &= x^2 + y^2 - L^2 +\end{aligned}\]

As a good DifferentialEquations.jl user, one would follow the mass matrix DAE tutorial to arrive at code for simulating the model:

using OrdinaryDiffEq, LinearAlgebra
+function pendulum!(du, u, p, t)
+    x, dx, y, dy, T = u
+    g, L = p
+    du[1] = dx
+    du[2] = T * x
+    du[3] = dy
+    du[4] = T * y - g
+    du[5] = x^2 + y^2 - L^2
+end
+pendulum_fun! = ODEFunction(pendulum!, mass_matrix = Diagonal([1, 1, 1, 1, 0]))
+u0 = [1.0, 0, 0, 0, 0];
+p = [9.8, 1];
+tspan = (0, 10.0);
+pendulum_prob = ODEProblem(pendulum_fun!, u0, tspan, p)
+solve(pendulum_prob, Rodas5P())
retcode: Unstable
+Interpolation: specialized 4rd order "free" stiffness-aware interpolation
+t: 5-element Vector{Float64}:
+ 0.0
+ 1.0e-6
+ 1.1e-5
+ 2.9844380701435048e-5
+ 3.91695328227943e-5
+u: 5-element Vector{Vector{Float64}}:
+ [1.0, 0.0, 0.0, 0.0, 0.0]
+ [1.0, 0.0, -4.90000000000002e-12, -9.800000000000057e-6, 0.0]
+ [1.0, -5.282200000000057e-16, -5.929000000000059e-10, -0.00010780000000000102, 1.2105282010216367e-11]
+ [1.0, -1.7340838651523673e-13, -4.36436659131577e-9, -0.00029247493087406596, 3.630578085102633e-8]
+ [1.0, -1.675311964402635e-12, -7.517836277624264e-9, -0.00038386142166338627, 1.43830729775041e-6]

However, one will quickly be greeted with the unfortunate message:

┌ Warning: First function call produced NaNs. Exiting.
+└ @ OrdinaryDiffEq C:\Users\accou\.julia\packages\OrdinaryDiffEq\yCczp\src\initdt.jl:76
+┌ Warning: Automatic dt set the starting dt as NaN, causing instability.
+└ @ OrdinaryDiffEq C:\Users\accou\.julia\packages\OrdinaryDiffEq\yCczp\src\solve.jl:485
+┌ Warning: NaN dt detected. Likely a NaN value in the state, parameters, or derivative value caused this outcome.
+└ @ SciMLBase C:\Users\accou\.julia\packages\SciMLBase\DrPil\src\integrator_interface.jl:325

Did you implement the DAE incorrectly? No. Is the solver broken? No.

Understanding DAE Index

It turns out that this is a property of the DAE that we are attempting to solve. This kind of DAE is known as an index-3 DAE. For a complete discussion of DAE index, see this article. Essentially, the issue here is that we have 4 differential variables ($x$, $v_x$, $y$, $v_y$) and one algebraic variable $T$ (which we can know because there is no D(T) term in the equations). An index-1 DAE always satisfies that the Jacobian of the algebraic equations is non-singular. Here, the first 4 equations are differential equations, with the last term the algebraic relationship. However, the partial derivative of x^2 + y^2 - L^2 w.r.t. T is zero, and thus the Jacobian of the algebraic equations is the zero matrix, and thus it's singular. This is a quick way to see whether the DAE is index 1!

The problem with higher order DAEs is that the matrices used in Newton solves are singular or close to singular when applied to such problems. Because of this fact, the nonlinear solvers (or Rosenbrock methods) break down, making them difficult to solve. The classic paper DAEs are not ODEs goes into detail on this and shows that many methods are no longer convergent when index is higher than one. So, it's not necessarily the fault of the solver or the implementation: this is known.

But that's not a satisfying answer, so what do you do about it?

Transforming Higher Order DAEs to Index-1 DAEs

It turns out that higher order DAEs can be transformed into lower order DAEs. If you differentiate the last equation two times and perform a substitution, you can arrive at the following set of equations:

\[\begin{aligned} +x^\prime =& v_x \\ +v_x^\prime =& x T \\ +y^\prime =& v_y \\ +v_y^\prime =& y T - g \\ +0 =& 2 \left(v_x^{2} + v_y^{2} + y ( y T - g ) + T x^2 \right) +\end{aligned}\]

Note that this is mathematically equivalent to the equation that we had before, but the Jacobian w.r.t. T of the algebraic equation is no longer zero because of the substitution. This means that if you wrote down this version of the model, it will be index-1 and solve correctly! In fact, this is how DAE index is commonly defined: the number of differentiations it takes to transform the DAE into an ODE, where an ODE is an index-0 DAE by substituting out all of the algebraic relationships.

Automating the Index Reduction

However, requiring the user to sit there and work through this process on potentially millions of equations is an unfathomable mental overhead. But, we can avoid this by using methods like the Pantelides algorithm for automatically performing this reduction to index 1. While this requires the ModelingToolkit symbolic form, we use modelingtoolkitize to transform the numerical code into symbolic code, run structural_simplify to simplify the system and lower the index, then transform back to numerical code with ODEProblem, and solve with a numerical solver. Let's try that out:

traced_sys = modelingtoolkitize(pendulum_prob)
+pendulum_sys = structural_simplify(traced_sys)
+prob = ODEProblem(pendulum_sys, Pair[], tspan)
+sol = solve(prob, Rodas5P())
+
+using Plots
+plot(sol, vars = unknowns(traced_sys))
Example block output

Note that plotting using unknowns(traced_sys) is done so that any variables which are symbolically eliminated, or any variable reordering done for enhanced parallelism/performance, still show up in the resulting plot and the plot is shown in the same order as the original numerical code.

Note that we can even go a bit further. If we use the ODEProblem constructor, we represent the mass matrix DAE of the index-reduced system, which can be solved via:

traced_sys = modelingtoolkitize(pendulum_prob)
+pendulum_sys = structural_simplify(dae_index_lowering(traced_sys))
+prob = ODEProblem(pendulum_sys, Pair[], tspan)
+sol = solve(prob, Rodas5P(), abstol = 1e-8, reltol = 1e-8)
+plot(sol, vars = unknowns(traced_sys))
Example block output

And there you go: this has transformed the model from being too hard to solve with implicit DAE solvers, to something that is easily solved.

Parameter Identifiability in ODE Models

Ordinary differential equations are commonly used for modeling real-world processes. The problem of parameter identifiability is one of the key design challenges for mathematical models. A parameter is said to be identifiable if one can recover its value from experimental data. Structural identifiability is a theoretical property of a model that answers this question. In this tutorial, we will show how to use StructuralIdentifiability.jl with ModelingToolkit.jl to assess identifiability of parameters in ODE models. The theory behind StructuralIdentifiability.jl is presented in paper [4].

We will start by illustrating local identifiability in which a parameter is known up to finitely many values, and then proceed to determining global identifiability, that is, which parameters can be identified uniquely.

To install StructuralIdentifiability.jl, simply run

using Pkg
+Pkg.add("StructuralIdentifiability")

The package has a standalone data structure for ordinary differential equations, but is also compatible with ODESystem type from ModelingToolkit.jl.

Local Identifiability

Input System

We will consider the following model:

\[\begin{cases} +\frac{d\,x_4}{d\,t} = - \frac{k_5 x_4}{k_6 + x_4},\\ +\frac{d\,x_5}{d\,t} = \frac{k_5 x_4}{k_6 + x_4} - \frac{k_7 x_5}{(k_8 + x_5 + x_6)},\\ +\frac{d\,x_6}{d\,t} = \frac{k_7 x_5}{(k_8 + x_5 + x_6)} - \frac{k_9 x_6 (k_{10} - x_6) }{k_{10}},\\ +\frac{d\,x_7}{d\,t} = \frac{k_9 x_6 (k_{10} - x_6)}{ k_{10}},\\ +y_1 = x_4,\\ +y_2 = x_5\end{cases}\]

This model describes the biohydrogenation[1] process[2] with unknown initial conditions.

Using the ODESystem object

To define the ode system in Julia, we use ModelingToolkit.jl.

We first define the parameters, variables, differential equations and the output equations.

using StructuralIdentifiability, ModelingToolkit
+
+# define parameters and variables
+@variables t x4(t) x5(t) x6(t) x7(t) y1(t) y2(t)
+@parameters k5 k6 k7 k8 k9 k10
+D = Differential(t)
+
+# define equations
+eqs = [
+    D(x4) ~ -k5 * x4 / (k6 + x4),
+    D(x5) ~ k5 * x4 / (k6 + x4) - k7 * x5 / (k8 + x5 + x6),
+    D(x6) ~ k7 * x5 / (k8 + x5 + x6) - k9 * x6 * (k10 - x6) / k10,
+    D(x7) ~ k9 * x6 * (k10 - x6) / k10,
+]
+
+# define the output functions (quantities that can be measured)
+measured_quantities = [y1 ~ x4, y2 ~ x5]
+
+# define the system
+de = ODESystem(eqs, t, name = :Biohydrogenation)

After that, we are ready to check the system for local identifiability:

# query local identifiability
+# we pass the ode-system
+local_id_all = assess_local_identifiability(de, measured_quantities = measured_quantities,
+                                            p = 0.99)
+# [ Info: Preproccessing `ModelingToolkit.ODESystem` object
+# 6-element Vector{Bool}:
+#  1
+#  1
+#  1
+#  1
+#  1
+#  1

We can see that all unknowns (except $x_7$) and all parameters are locally identifiable with probability 0.99.

Let's try to check specific parameters and their combinations

to_check = [k5, k7, k10 / k9, k5 + k6]
+local_id_some = assess_local_identifiability(de, measured_quantities = measured_quantities,
+                                             funcs_to_check = to_check, p = 0.99)
+# 4-element Vector{Bool}:
+#  1
+#  1
+#  1
+#  1

Notice that in this case, everything (except the state variable $x_7$) is locally identifiable, including combinations such as $k_{10}/k_9, k_5+k_6$

Global Identifiability

In this part tutorial, let us cover an example problem of querying the ODE for globally identifiable parameters.

Input System

Let us consider the following four-dimensional model with two outputs:

\[\begin{cases} +x_1'(t) = -b x_1(t) + \frac{1 }{ c + x_4(t)},\\ +x_2'(t) = \alpha x_1(t) - \beta x_2(t),\\ +x_3'(t) = \gamma x_2(t) - \delta x_3(t),\\ +x_4'(t) = \sigma x_4(t) \frac{(\gamma x_2(t) - \delta x_3(t))}{ x_3(t)},\\ +y(t) = x_1(t) +\end{cases}\]

We will run a global identifiability check on this enzyme dynamics[3] model. We will use the default settings: the probability of correctness will be p=0.99 and we are interested in identifiability of all possible parameters.

Global identifiability needs information about local identifiability first, but the function we chose here will take care of that extra step for us.

Note: as of writing this tutorial, UTF-symbols such as Greek characters are not supported by one of the project's dependencies, see this issue.

using StructuralIdentifiability, ModelingToolkit
+@parameters b c a beta g delta sigma
+@variables t x1(t) x2(t) x3(t) x4(t) y(t) y2(t)
+D = Differential(t)
+
+eqs = [
+    D(x1) ~ -b * x1 + 1 / (c + x4),
+    D(x2) ~ a * x1 - beta * x2,
+    D(x3) ~ g * x2 - delta * x3,
+    D(x4) ~ sigma * x4 * (g * x2 - delta * x3) / x3,
+]
+
+measured_quantities = [y ~ x1 + x2, y2 ~ x2]
+
+ode = ODESystem(eqs, t, name = :GoodwinOsc)
+
+@time global_id = assess_identifiability(ode, measured_quantities = measured_quantities)
+# 30.672594 seconds (100.97 M allocations: 6.219 GiB, 3.15% gc time, 0.01% compilation time)
+# Dict{Num, Symbol} with 7 entries:
+#   a     => :globally
+#   b     => :globally
+#   beta  => :globally
+#   c     => :globally
+#   sigma => :globally
+#   g     => :nonidentifiable
+#   delta => :globally

We can see that only parameters a, g are unidentifiable, and everything else can be uniquely recovered.

Let us consider the same system but with two inputs, and we will find out identifiability with probability 0.9 for parameters c and b:

using StructuralIdentifiability, ModelingToolkit
+@parameters b c a beta g delta sigma
+@variables t x1(t) x2(t) x3(t) x4(t) y(t) u1(t) [input = true] u2(t) [input = true]
+D = Differential(t)
+
+eqs = [
+    D(x1) ~ -b * x1 + 1 / (c + x4),
+    D(x2) ~ a * x1 - beta * x2 - u1,
+    D(x3) ~ g * x2 - delta * x3 + u2,
+    D(x4) ~ sigma * x4 * (g * x2 - delta * x3) / x3,
+]
+measured_quantities = [y ~ x1 + x2, y2 ~ x2]
+
+# check only 2 parameters
+to_check = [b, c]
+
+ode = ODESystem(eqs, t, name = :GoodwinOsc)
+
+global_id = assess_identifiability(ode, measured_quantities = measured_quantities,
+                                   funcs_to_check = to_check, p = 0.9)
+# Dict{Num, Symbol} with 2 entries:
+#   b => :globally
+#   c => :globally

Both parameters b, c are globally identifiable with probability 0.9 in this case.

diff --git a/v1.5.0/siteinfo.js b/v1.5.0/siteinfo.js new file mode 100644 index 00000000000..4f155ae3d8a --- /dev/null +++ b/v1.5.0/siteinfo.js @@ -0,0 +1 @@ +var DOCUMENTER_CURRENT_VERSION = "v1.5.0"; diff --git a/versions.js b/versions.js index 2e85e1ec1f9..ff76f4bdaee 100644 --- a/versions.js +++ b/versions.js @@ -1,5 +1,6 @@ var DOC_VERSIONS = [ "stable", + "v1.5", "v1.4", "v1.2", "v1.1", @@ -9,5 +10,5 @@ var DOC_VERSIONS = [ "v0.1", "dev", ]; -var DOCUMENTER_NEWEST = "v1.4.0"; +var DOCUMENTER_NEWEST = "v1.5.0"; var DOCUMENTER_STABLE = "stable";