From 8947c2904ac5fefdff9c8267bfe4c3dc29803c95 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Thu, 16 Apr 2026 15:01:12 +0200 Subject: [PATCH 1/3] Fix workflow if conditions to run on push unconditionally --- .github/workflows/CI.yml | 2 +- .github/workflows/Documentation.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e742fcc..593db92 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -10,7 +10,7 @@ on: jobs: call: - if: contains(github.event.pull_request.labels.*.name, 'run ci') + if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run ci') uses: control-toolbox/CTActions/.github/workflows/ci.yml@main with: runs_on: '["ubuntu-latest"]' diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 96b813c..0705b0e 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -10,5 +10,5 @@ on: jobs: call: - if: contains(github.event.pull_request.labels.*.name, 'run documentation') + if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run documentation') uses: control-toolbox/CTActions/.github/workflows/documentation.yml@main From b85af0fca1aa5cd25d8566a6cf6570c991477f2a Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Thu, 16 Apr 2026 15:06:40 +0200 Subject: [PATCH 2/3] Simplify initial guess in tutorial-mam by inlining helper functions --- docs/src/tutorial-mam.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/src/tutorial-mam.md b/docs/src/tutorial-mam.md index ea174dd..37e8b4a 100644 --- a/docs/src/tutorial-mam.md +++ b/docs/src/tutorial-mam.md @@ -1,5 +1,9 @@ # [Minimal Action Method using Optimal Control](@id tutorial-mam) +```@meta +Draft = false +``` + The Minimal Action Method (MAM) is a numerical technique for finding the most probable transition pathway between stable states in stochastic dynamical systems. It achieves this by minimizing an action functional that represents the path's deviation from the deterministic dynamics, effectively identifying the path of least resistance through the system's landscape. This tutorial demonstrates how to implement MAM as an optimal control problem, using the classical Maier-Stein model as a benchmark example. @@ -17,7 +21,7 @@ using Plots, Printf We aim to find the most probable transition path between two stable states of a stochastic dynamical system. For a system with deterministic dynamics $f(x)$ and small noise, the transition path minimizes the action functional: ```math -S[x(\cdot), u(\cdot)] = \int_0^T \|u(t) - f(x(t))\|^2 \, dt +S[x(\cdot), u(\cdot)] = \int_0^T \|u(t) - f(x(t))\|^2 \, \mathrm{d}t ``` subject to the path dynamics: @@ -72,17 +76,10 @@ We provide an initial guess for the path using a simple interpolation with the ` # Time horizon T = 50 -# Helper functions for initial state guess -L(t) = -(1 - t/T) + t/T # Linear interpolation from -1 to 1 -P(t) = 0.3*(-L(t)^2 + 1) # Parabolic arc (approximates saddle crossing) - init = @init ocp(T) begin - # Linear interpolation for x₁ - x₁(t) := L(t) - # Parabolic guess for x₂ - x₂(t) := P(t) - # Control from vector field - u(t) := f(L(t), P(t)) + x₁(t) := -(1 - t/T) + t/T # Linear interpolation from -1 to 1 + x₂(t) := 0.3*(-x₁(t)^2 + 1) # Parabolic arc (approximates saddle crossing) + u(t) := f(x₁(t), x₂(t)) # Control from vector field end nothing # hide ``` From 462874bee603ddf31e65857263c6a8ff5734f0e5 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Thu, 16 Apr 2026 15:37:10 +0200 Subject: [PATCH 3/3] Enable draft mode off, add initial guess visualization in tutorial-mam --- docs/src/assets/Manifest.toml | 49 +++++++++++++++++++---------------- docs/src/tutorial-mam.md | 9 +++---- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/src/assets/Manifest.toml b/docs/src/assets/Manifest.toml index ced7cf3..6814574 100644 --- a/docs/src/assets/Manifest.toml +++ b/docs/src/assets/Manifest.toml @@ -102,9 +102,9 @@ version = "0.4.0" [[deps.ArrayInterface]] deps = ["Adapt", "LinearAlgebra"] -git-tree-sha1 = "78b3a7a536b4b0a747a0f296ea77091ca0a9f9a3" +git-tree-sha1 = "54f895554d05c83e3dd59f6a396671dae8999573" uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" -version = "7.23.0" +version = "7.24.0" [deps.ArrayInterface.extensions] ArrayInterfaceAMDGPUExt = "AMDGPU" @@ -259,9 +259,9 @@ version = "0.9.14" [[deps.CTParser]] deps = ["CTBase", "DocStringExtensions", "MLStyle", "OrderedCollections", "Parameters", "Unicode"] -git-tree-sha1 = "0a57111b2d95d6272bb76f4f6f7c4fee1e40ce82" +git-tree-sha1 = "67c193f4f1e5167123b917bbbdb26947757ed4b0" uuid = "32681960-a1b1-40db-9bff-a1ca817385d1" -version = "0.8.13" +version = "0.8.14" [[deps.CTSolvers]] deps = ["ADNLPModels", "CTBase", "CTModels", "CommonSolve", "DocStringExtensions", "ExaModels", "KernelAbstractions", "NLPModels", "SolverCore"] @@ -485,10 +485,10 @@ uuid = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" version = "0.4.6" [[deps.DiffEqBase]] -deps = ["ArrayInterface", "BracketingNonlinearSolve", "ConcreteStructs", "DocStringExtensions", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLOperators", "SciMLStructures", "Setfield", "Static", "StaticArraysCore", "SymbolicIndexingInterface", "TruncatedStacktraces"] -git-tree-sha1 = "87e2ad6d4ae98505218e2f97cafcfa296dc97d37" +deps = ["ArrayInterface", "BracketingNonlinearSolve", "ConcreteStructs", "DocStringExtensions", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappers", "FunctionWrappersWrappers", "LinearAlgebra", "Logging", "Markdown", "MuladdMacro", "PrecompileTools", "Printf", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLLogging", "SciMLOperators", "SciMLStructures", "Setfield", "Static", "StaticArraysCore", "SymbolicIndexingInterface", "TruncatedStacktraces"] +git-tree-sha1 = "7fc71417fa27888829b800ca3c0a4d3c1d0d99f0" uuid = "2b5f629d-d688-5b77-993f-72d75c75574e" -version = "6.216.0" +version = "6.217.0" [deps.DiffEqBase.extensions] DiffEqBaseCUDAExt = "CUDA" @@ -809,9 +809,9 @@ version = "1.16.0" [[deps.FiniteDiff]] deps = ["ArrayInterface", "LinearAlgebra", "Setfield"] -git-tree-sha1 = "9340ca07ca27093ff68418b7558ca37b05f8aeb1" +git-tree-sha1 = "73e879af0e767bd6dfade7c5b09d7b05657a8284" uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" -version = "2.29.0" +version = "2.30.0" [deps.FiniteDiff.extensions] FiniteDiffBandedMatricesExt = "BandedMatrices" @@ -1556,9 +1556,9 @@ version = "0.2.4" [[deps.MultivariatePolynomials]] deps = ["DataStructures", "LinearAlgebra", "MutableArithmetics", "StarAlgebras"] -git-tree-sha1 = "b45f1ed8448ea20885cb4c5029c2a462fe2682bf" +git-tree-sha1 = "9436679244f099fe5cd8a8053f40696be4e3bdd8" uuid = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3" -version = "0.5.17" +version = "0.5.18" weakdeps = ["ChainRulesCore"] [deps.MultivariatePolynomials.extensions] @@ -1776,10 +1776,10 @@ uuid = "6ad6398a-0878-4a85-9266-38940aa047c8" version = "1.26.0" [[deps.OrdinaryDiffEqCore]] -deps = ["ADTypes", "Accessors", "Adapt", "ArrayInterface", "ConcreteStructs", "DataStructures", "DiffEqBase", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappersWrappers", "InteractiveUtils", "LinearAlgebra", "Logging", "MacroTools", "MuladdMacro", "Polyester", "PrecompileTools", "Preferences", "Random", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLLogging", "SciMLOperators", "SciMLStructures", "Static", "StaticArraysCore", "SymbolicIndexingInterface", "TruncatedStacktraces"] -git-tree-sha1 = "e81202ab680b4649ea2cb63560b9e57833540cfa" +deps = ["ADTypes", "Accessors", "Adapt", "ArrayInterface", "ConcreteStructs", "DataStructures", "DiffEqBase", "DocStringExtensions", "EnumX", "EnzymeCore", "FastBroadcast", "FastClosures", "FastPower", "FunctionWrappersWrappers", "InteractiveUtils", "LinearAlgebra", "Logging", "MacroTools", "MuladdMacro", "Polyester", "PrecompileTools", "Preferences", "Random", "RecursiveArrayTools", "Reexport", "SciMLBase", "SciMLLogging", "SciMLOperators", "SciMLStructures", "Static", "SymbolicIndexingInterface", "TruncatedStacktraces"] +git-tree-sha1 = "31e7d6c8add3a7f449d492fc7d2437cfbe9d6a7a" uuid = "bbf590c4-e513-4bbe-9b18-05decba2e5d8" -version = "3.31.0" +version = "3.32.0" [deps.OrdinaryDiffEqCore.extensions] OrdinaryDiffEqCoreMooncakeExt = "Mooncake" @@ -1933,9 +1933,9 @@ version = "1.14.0" [[deps.OrdinaryDiffEqStabilizedRK]] deps = ["DiffEqBase", "FastBroadcast", "MuladdMacro", "OrdinaryDiffEqCore", "RecursiveArrayTools", "Reexport", "SciMLBase", "StaticArraysCore"] -git-tree-sha1 = "bb33a312858b1e6663099f231323a78b7bb00eb3" +git-tree-sha1 = "764e11fb6a26ee8f2d2d10778d531fd708f35d28" uuid = "358294b1-0aab-51c3-aafe-ad5ab194a2ad" -version = "1.11.0" +version = "1.11.1" [[deps.OrdinaryDiffEqSymplecticRK]] deps = ["DiffEqBase", "FastBroadcast", "MuladdMacro", "OrdinaryDiffEqCore", "Polyester", "RecursiveArrayTools", "Reexport", "SciMLBase"] @@ -2430,22 +2430,25 @@ version = "1.2.1" [[deps.SparseMatrixColorings]] deps = ["ADTypes", "DocStringExtensions", "LinearAlgebra", "PrecompileTools", "Random", "SparseArrays"] -git-tree-sha1 = "1c1be8c6fdfaf9b6c9e156c509e672953b8e6af7" +git-tree-sha1 = "f63d76c7b7c329cf11badd564fd8ba877b09c3fe" uuid = "0a514795-09f3-496d-8182-132a7b665d35" -version = "0.4.26" +version = "0.4.27" [deps.SparseMatrixColorings.extensions] - SparseMatrixColoringsCUDAExt = "CUDA" + SparseMatrixColoringsCUDAExt = ["CUDA", "cuSPARSE"] SparseMatrixColoringsCliqueTreesExt = "CliqueTrees" SparseMatrixColoringsColorsExt = "Colors" + SparseMatrixColoringsGPUArraysExt = "GPUArrays" SparseMatrixColoringsJuMPExt = ["JuMP", "MathOptInterface"] [deps.SparseMatrixColorings.weakdeps] CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" CliqueTrees = "60701a23-6482-424a-84db-faee86b9b1f8" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" + GPUArrays = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7" JuMP = "4076af6c-e467-56ae-b986-b466b2749572" MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee" + cuSPARSE = "b26da814-b3bc-49ef-b0ee-c816305aa060" [[deps.SpecialFunctions]] deps = ["IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"] @@ -2592,9 +2595,9 @@ version = "1.1.0" [[deps.SymbolicUtils]] deps = ["AbstractTrees", "ArrayInterface", "Combinatorics", "ConstructionBase", "DataStructures", "Dictionaries", "DocStringExtensions", "DynamicPolynomials", "EnumX", "ExproniconLite", "Graphs", "LinearAlgebra", "MacroTools", "Moshi", "MultivariatePolynomials", "MutableArithmetics", "NaNMath", "PrecompileTools", "ReadOnlyArrays", "Setfield", "SparseArrays", "SpecialFunctions", "StaticArraysCore", "SymbolicIndexingInterface", "TaskLocalValues", "TermInterface", "WeakCacheSets"] -git-tree-sha1 = "552eaeac659f5802d45c4d936272a712ca13a969" +git-tree-sha1 = "98c23082cba20c6ae17e920600c89e4f6491e618" uuid = "d1185830-fcd6-423d-90d6-eec64667417b" -version = "4.24.1" +version = "4.24.2" [deps.SymbolicUtils.extensions] SymbolicUtilsChainRulesCoreExt = "ChainRulesCore" @@ -2958,9 +2961,9 @@ version = "0.61.1+0" [[deps.libaom_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] -git-tree-sha1 = "371cc681c00a3ccc3fbc5c0fb91f58ba9bec1ecf" +git-tree-sha1 = "850b06095ee71f0135d644ffd8a52850699581ed" uuid = "a4ae2306-e953-59d6-aa16-d00cac43593b" -version = "3.13.1+0" +version = "3.13.3+0" [[deps.libass_jll]] deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Zlib_jll"] diff --git a/docs/src/tutorial-mam.md b/docs/src/tutorial-mam.md index 37e8b4a..2d065d0 100644 --- a/docs/src/tutorial-mam.md +++ b/docs/src/tutorial-mam.md @@ -1,9 +1,5 @@ # [Minimal Action Method using Optimal Control](@id tutorial-mam) -```@meta -Draft = false -``` - The Minimal Action Method (MAM) is a numerical technique for finding the most probable transition pathway between stable states in stochastic dynamical systems. It achieves this by minimizing an action functional that represents the path's deviation from the deterministic dynamics, effectively identifying the path of least resistance through the system's landscape. This tutorial demonstrates how to implement MAM as an optimal control problem, using the classical Maier-Stein model as a benchmark example. @@ -81,7 +77,10 @@ init = @init ocp(T) begin x₂(t) := 0.3*(-x₁(t)^2 + 1) # Parabolic arc (approximates saddle crossing) u(t) := f(x₁(t), x₂(t)) # Control from vector field end -nothing # hide + +# Visualize the initial guess (solve without optimization, max_iter=0) +sol_init = solve(ocp(T); init=init, grid_size=1000, max_iter=0) +plot(sol_init) ``` !!! note "Initial guess strategy"