From 5c8e28d920571d5bafa5637b6261c1b8cf4ef35c Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 27 Feb 2026 14:20:03 +1300 Subject: [PATCH 1/3] [docs] rename tutorials to more explicit "How to" --- docs/make.jl | 3 +- docs/src/changelog.md | 2 +- docs/src/guides/access_previous_variables.md | 8 +-- docs/src/guides/add_a_custom_cut.md | 2 +- .../add_a_multidimensional_state_variable.md | 2 +- docs/src/guides/add_a_risk_measure.md | 2 +- docs/src/guides/add_integrality.md | 2 +- docs/src/guides/add_multidimensional_noise.md | 2 +- .../add_noise_in_the_constraint_matrix.md | 2 +- docs/src/guides/choose_a_stopping_rule.md | 2 +- docs/src/guides/create_a_belief_state.md | 4 +- .../guides/create_a_general_policy_graph.md | 4 +- docs/src/guides/deterministic_equivalent.md | 51 +++++++++++++++++++ .../improve_computational_performance.md | 2 +- ...ulate_using_a_different_sampling_scheme.md | 2 +- docs/src/guides/use_multithreading.md | 2 +- ..._model.md => write_subproblems_to_file.md} | 45 +--------------- docs/src/index.md | 2 +- 18 files changed, 74 insertions(+), 65 deletions(-) create mode 100644 docs/src/guides/deterministic_equivalent.md rename docs/src/guides/{debug_a_model.md => write_subproblems_to_file.md} (61%) diff --git a/docs/make.jl b/docs/make.jl index ca92743ecf..1670206815 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -173,7 +173,8 @@ Documenter.makedocs(; "guides/choose_a_stopping_rule.md", "guides/create_a_general_policy_graph.md", "guides/add_a_custom_cut.md", - "guides/debug_a_model.md", + "guides/write_subproblems_to_file.md", + "guides/deterministic_equivalent.md", "guides/improve_computational_performance.md", "guides/simulate_using_a_different_sampling_scheme.md", "guides/create_a_belief_state.md", diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 44628bae76..05e8d03e02 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -77,7 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Other - Added documentation [Add a custom cut](@ref) (#832) - - Added documentation [Use multithreading](@ref) (#833) + - Added documentation [How to use multithreading](@ref) (#833) - Fixed a typo in [Risk aversion](@ref) (#835) - Changed to use `test/Project.toml` (#837) - Debug and work around a bug in `HiGHS_jll@1.10` (#836), (#839) diff --git a/docs/src/guides/access_previous_variables.md b/docs/src/guides/access_previous_variables.md index f3fbe90f82..4795efafa1 100644 --- a/docs/src/guides/access_previous_variables.md +++ b/docs/src/guides/access_previous_variables.md @@ -1,4 +1,4 @@ -# Access variables from a previous stage +# How to access variables from a previous stage A common question is "how do I use a variable from a previous stage in a constraint?" @@ -55,8 +55,8 @@ end ## Access a decision from N stages ago This is often useful if you have some inventory problem with a lead time on orders. -In the code below, we assume that the product has a lead time of 5 stages, and we -use a state variable to track the decisions on the production for the last 5 stages. +In the code below, we assume that the product has a lead time of 5 stages, and we +use a state variable to track the decisions on the production for the last 5 stages. The decisions are passed to the next stage by shifting them by one stage. ```@repl @@ -129,7 +129,7 @@ model = SDDP.LinearPolicyGraph( fix(x_pipeline[T+1].out, 0) @stageobjective(sp, u_sell) @constraints(sp, begin - # Shift the orders one stage + # Shift the orders one stage c_pipeline[i=1:T], x_pipeline[i].out == x_pipeline[i+1].in + 1 * u_buy # x_pipeline[1].in are arriving on the inventory x_inventory.out == x_inventory.in - u_sell + x_pipeline[1].in diff --git a/docs/src/guides/add_a_custom_cut.md b/docs/src/guides/add_a_custom_cut.md index bcd0176249..422f52d28d 100644 --- a/docs/src/guides/add_a_custom_cut.md +++ b/docs/src/guides/add_a_custom_cut.md @@ -1,4 +1,4 @@ -# Add a custom cut +# How to add a custom cut Sometimes you may want to add a set of cuts to the value function that you have computed outside of SDDP.jl. The easiest way to achieve this is via the diff --git a/docs/src/guides/add_a_multidimensional_state_variable.md b/docs/src/guides/add_a_multidimensional_state_variable.md index 40e707aa40..7eaa31ce59 100644 --- a/docs/src/guides/add_a_multidimensional_state_variable.md +++ b/docs/src/guides/add_a_multidimensional_state_variable.md @@ -1,4 +1,4 @@ -# Add a multi-dimensional state variable +# How to add a multi-dimensional state variable ```@meta DocTestSetup = quote diff --git a/docs/src/guides/add_a_risk_measure.md b/docs/src/guides/add_a_risk_measure.md index 5dfffcf381..c02261a3c9 100644 --- a/docs/src/guides/add_a_risk_measure.md +++ b/docs/src/guides/add_a_risk_measure.md @@ -1,4 +1,4 @@ -# Add a risk measure +# How to add a risk measure ```@meta DocTestSetup = quote diff --git a/docs/src/guides/add_integrality.md b/docs/src/guides/add_integrality.md index 1a91a4b710..377b1718bc 100644 --- a/docs/src/guides/add_integrality.md +++ b/docs/src/guides/add_integrality.md @@ -2,7 +2,7 @@ CurrentModule = SDDP ``` -# Integrality +# How to add integrality There's nothing special about binary and integer variables in SDDP.jl. Your models may contain a mix of binary, integer, and continuous state and control diff --git a/docs/src/guides/add_multidimensional_noise.md b/docs/src/guides/add_multidimensional_noise.md index baa02eb77c..d70e7c9efe 100644 --- a/docs/src/guides/add_multidimensional_noise.md +++ b/docs/src/guides/add_multidimensional_noise.md @@ -1,4 +1,4 @@ -# Add multi-dimensional noise terms +# How to add multi-dimensional noise terms ```@meta DocTestSetup = quote diff --git a/docs/src/guides/add_noise_in_the_constraint_matrix.md b/docs/src/guides/add_noise_in_the_constraint_matrix.md index 31131185cd..8f16bf3069 100644 --- a/docs/src/guides/add_noise_in_the_constraint_matrix.md +++ b/docs/src/guides/add_noise_in_the_constraint_matrix.md @@ -1,4 +1,4 @@ -# Add noise in the constraint matrix +# How to add noise in the constraint matrix ```@meta DocTestSetup = quote diff --git a/docs/src/guides/choose_a_stopping_rule.md b/docs/src/guides/choose_a_stopping_rule.md index e3c3bbbf3c..2476ab0d18 100644 --- a/docs/src/guides/choose_a_stopping_rule.md +++ b/docs/src/guides/choose_a_stopping_rule.md @@ -1,4 +1,4 @@ -# Choose a stopping rule +# How to choose a stopping rule The theory of SDDP tells us that the algorithm converges to an optimal policy almost surely in a finite number of iterations. In practice, this number is very diff --git a/docs/src/guides/create_a_belief_state.md b/docs/src/guides/create_a_belief_state.md index 8517e019c9..8923123ab5 100644 --- a/docs/src/guides/create_a_belief_state.md +++ b/docs/src/guides/create_a_belief_state.md @@ -4,13 +4,13 @@ DocTestSetup = quote end ``` -# Create a belief state +# How to create a belief state `SDDP.jl` includes an implementation of the algorithm described in Dowson, O., Morton, D.P., & Pagnoncelli, B.K. (2020). Partially observable multistage stochastic optimization. _Operations Research Letters_, 48(4), 505--512. -Given a [`SDDP.Graph`](@ref) object (see [Create a general policy graph](@ref) +Given a [`SDDP.Graph`](@ref) object (see [How to create a general policy graph](@ref) for details), we can define the ambiguity partition using [`SDDP.add_ambiguity_set`](@ref). diff --git a/docs/src/guides/create_a_general_policy_graph.md b/docs/src/guides/create_a_general_policy_graph.md index 9a9b58d172..0e6560209e 100644 --- a/docs/src/guides/create_a_general_policy_graph.md +++ b/docs/src/guides/create_a_general_policy_graph.md @@ -1,4 +1,4 @@ -# Create a general policy graph +# How to create a general policy graph ```@meta DocTestSetup = quote @@ -186,7 +186,7 @@ simulations = SDDP.simulate( Here, `max_depth` controls the number of stages, and `terminate_on_dummy_leaf = false` stops us from terminating early. -See also [Simulate using a different sampling scheme](@ref). +See also [How to simulate using a different sampling scheme](@ref). ## Creating a Markovian graph automatically diff --git a/docs/src/guides/deterministic_equivalent.md b/docs/src/guides/deterministic_equivalent.md new file mode 100644 index 0000000000..13fd8de9ad --- /dev/null +++ b/docs/src/guides/deterministic_equivalent.md @@ -0,0 +1,51 @@ +## How to solve the deterministic equivalent + +Sometimes, it can be helpful to solve the deterministic equivalent of a +problem in order to obtain an exact solution to the problem. To obtain a JuMP +model that represents the deterministic equivalent, use [`SDDP.deterministic_equivalent`](@ref). +The returned model is just a normal JuMP model. Use JuMP to optimize it and +query the solution. + +```jldoctest; filter=r"5.4725[0]+[0-9]" +julia> using SDDP, HiGHS + +julia> model = SDDP.LinearPolicyGraph( + stages = 2, + lower_bound = 0.0, + optimizer = HiGHS.Optimizer, + ) do subproblem, t + @variable(subproblem, x, SDDP.State, initial_value = 1) + @variable(subproblem, y) + @constraint(subproblem, balance, x.in == x.out + y) + SDDP.parameterize(subproblem, [1.1, 2.2]) do ω + @stageobjective(subproblem, ω * x.out) + fix(y, ω) + end + end +A policy graph with 2 nodes. + Node indices: 1, 2 + +julia> det_equiv = SDDP.deterministic_equivalent(model, HiGHS.Optimizer) +A JuMP Model +├ solver: HiGHS +├ objective_sense: MIN_SENSE +│ └ objective_function_type: AffExpr +├ num_variables: 24 +├ num_constraints: 28 +│ ├ AffExpr in MOI.EqualTo{Float64}: 10 +│ ├ VariableRef in MOI.EqualTo{Float64}: 8 +│ ├ VariableRef in MOI.GreaterThan{Float64}: 6 +│ └ VariableRef in MOI.LessThan{Float64}: 4 +└ Names registered in the model: none + +julia> set_silent(det_equiv) + +julia> optimize!(det_equiv) + +julia> objective_value(det_equiv) +-5.472500000000001 +``` + +!!! warning + The deterministic equivalent scales poorly with problem size. Only use this + on small problems! diff --git a/docs/src/guides/improve_computational_performance.md b/docs/src/guides/improve_computational_performance.md index d581feb3e5..b22014bdbd 100644 --- a/docs/src/guides/improve_computational_performance.md +++ b/docs/src/guides/improve_computational_performance.md @@ -1,4 +1,4 @@ -# Improve computational performance +# How to improve computational performance SDDP is a computationally intensive algorithm. Here are some suggestions for how the computational performance can be improved. diff --git a/docs/src/guides/simulate_using_a_different_sampling_scheme.md b/docs/src/guides/simulate_using_a_different_sampling_scheme.md index d68a36fbae..52bc8c0cfa 100644 --- a/docs/src/guides/simulate_using_a_different_sampling_scheme.md +++ b/docs/src/guides/simulate_using_a_different_sampling_scheme.md @@ -1,4 +1,4 @@ -# Simulate using a different sampling scheme +# How to simulate using a different sampling scheme ```@meta DocTestSetup = quote diff --git a/docs/src/guides/use_multithreading.md b/docs/src/guides/use_multithreading.md index e3104f10f9..61eccf7755 100644 --- a/docs/src/guides/use_multithreading.md +++ b/docs/src/guides/use_multithreading.md @@ -1,4 +1,4 @@ -# Use multithreading +# How to use multithreading SDDP.jl can take advantage of the parallel nature of modern computers to solve problems across multiple threads. diff --git a/docs/src/guides/debug_a_model.md b/docs/src/guides/write_subproblems_to_file.md similarity index 61% rename from docs/src/guides/debug_a_model.md rename to docs/src/guides/write_subproblems_to_file.md index 10582de93c..f29e49af36 100644 --- a/docs/src/guides/debug_a_model.md +++ b/docs/src/guides/write_subproblems_to_file.md @@ -1,13 +1,4 @@ -# Debug a model - -Building multistage stochastic programming models is hard. There are a lot of -different pieces that need to be put together, and we typically have no idea of -the optimal policy, so it can be hard (impossible?) to validate the solution. - -That said, here are a few tips to verify and validate models built using -`SDDP.jl`. - -## Writing subproblems to file +# How to write subproblems to file The first step to debug a model is to write out the subproblems to a file in order to check that you are actually building what you think you are building. @@ -92,37 +83,3 @@ End julia> rm("subproblem.lp") # Clean up. ``` - -## Solve the deterministic equivalent - -Sometimes, it can be helpful to solve the deterministic equivalent of a -problem in order to obtain an exact solution to the problem. To obtain a JuMP -model that represents the deterministic equivalent, use [`SDDP.deterministic_equivalent`](@ref). -The returned model is just a normal JuMP model. Use JuMP to optimize it and -query the solution. - -```jldoctest tutorial_eight; filter=r"5.4725[0]+[0-9]" -julia> det_equiv = SDDP.deterministic_equivalent(model, HiGHS.Optimizer) -A JuMP Model -├ solver: HiGHS -├ objective_sense: MIN_SENSE -│ └ objective_function_type: AffExpr -├ num_variables: 24 -├ num_constraints: 28 -│ ├ AffExpr in MOI.EqualTo{Float64}: 10 -│ ├ VariableRef in MOI.EqualTo{Float64}: 8 -│ ├ VariableRef in MOI.GreaterThan{Float64}: 6 -│ └ VariableRef in MOI.LessThan{Float64}: 4 -└ Names registered in the model: none - -julia> set_silent(det_equiv) - -julia> optimize!(det_equiv) - -julia> objective_value(det_equiv) --5.472500000000001 -``` - -!!! warning - The deterministic equivalent scales poorly with problem size. Only use this - on small problems! diff --git a/docs/src/index.md b/docs/src/index.md index a8d32ac2ef..1d639ca768 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -63,7 +63,7 @@ you know where to look for certain things. you've got `SDDP.jl` installed, start by reading [An introduction to SDDP.jl](@ref). * **Guides** contains "how-to" snippets that demonstrate specific topics within - SDDP.jl. A good one to get started on is [Debug a model](@ref). + SDDP.jl. A good one to get started on is [How to add a risk measure](@ref). * **Explanation** contains step-by-step explanations of the theory and algorithms that underpin SDDP.jl. If you want a basic understanding of the From b461dcc27dd6117980f26459a69ef04cd4cbcaed Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 27 Feb 2026 14:48:15 +1300 Subject: [PATCH 2/3] Update --- docs/src/changelog.md | 2 +- docs/src/examples/the_farmers_problem.jl | 2 +- docs/src/explanation/risk.jl | 2 +- docs/src/tutorial/duality_handlers.jl | 2 +- docs/src/tutorial/first_steps.jl | 2 +- docs/src/tutorial/markov_uncertainty.jl | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index 05e8d03e02..54dfa63f51 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -76,7 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Other - - Added documentation [Add a custom cut](@ref) (#832) + - Added documentation [How to add a custom cut](@ref) (#832) - Added documentation [How to use multithreading](@ref) (#833) - Fixed a typo in [Risk aversion](@ref) (#835) - Changed to use `test/Project.toml` (#837) diff --git a/docs/src/examples/the_farmers_problem.jl b/docs/src/examples/the_farmers_problem.jl index 6b86686e2b..b1686c1cb2 100644 --- a/docs/src/examples/the_farmers_problem.jl +++ b/docs/src/examples/the_farmers_problem.jl @@ -247,7 +247,7 @@ end # Now that we've built a model, we need to train it using [`SDDP.train`](@ref). # The keyword `iteration_limit` stops the training after 40 iterations. See -# [Choose a stopping rule](@ref) for other ways to stop the training. +# [How to choose a stopping rule](@ref) for other ways to stop the training. SDDP.train(model; iteration_limit = 40) diff --git a/docs/src/explanation/risk.jl b/docs/src/explanation/risk.jl index e1881f21ba..5ec7e7971f 100644 --- a/docs/src/explanation/risk.jl +++ b/docs/src/explanation/risk.jl @@ -387,7 +387,7 @@ end # This method of solving the dual problem "on-the-side" is used by SDDP.jl # for a number of risk measures, including a distributionally robust risk # measure with the Wasserstein distance. Check out all the risk measures -# that SDDP.jl supports in [Add a risk measure](@ref). +# that SDDP.jl supports in [How to add a risk measure](@ref). # The "on-the-side" method is very general, and it lets us incorporate any # convex risk measure into SDDP. However, this comes at an increased diff --git a/docs/src/tutorial/duality_handlers.jl b/docs/src/tutorial/duality_handlers.jl index 3668743bd7..0733f7f919 100644 --- a/docs/src/tutorial/duality_handlers.jl +++ b/docs/src/tutorial/duality_handlers.jl @@ -9,7 +9,7 @@ # The purpose of this tutorial is to demonstrate trivial examples that expose # the strengths and weaknesses of each duality handler. -# For more information on SDDP.jl's duality handlers, see [Integrality](@ref). +# For more information on SDDP.jl's duality handlers, see [How to add integrality](@ref). # This tutorial uses the following packages: diff --git a/docs/src/tutorial/first_steps.jl b/docs/src/tutorial/first_steps.jl index 5e1342f535..60bd95ccce 100644 --- a/docs/src/tutorial/first_steps.jl +++ b/docs/src/tutorial/first_steps.jl @@ -497,7 +497,7 @@ end # !!! warning # [`SDDP.parameterize`](@ref) can only be called once in each subproblem # definition! If your random variable is multi-variate, read -# [Add multi-dimensional noise terms](@ref). +# [How to add multi-dimensional noise terms](@ref). # #### Transition function and constraints diff --git a/docs/src/tutorial/markov_uncertainty.jl b/docs/src/tutorial/markov_uncertainty.jl index 842945ee0e..a1852a3b10 100644 --- a/docs/src/tutorial/markov_uncertainty.jl +++ b/docs/src/tutorial/markov_uncertainty.jl @@ -107,7 +107,7 @@ end # !!! tip # For more information on [`SDDP.MarkovianPolicyGraph`](@ref)s, read -# [Create a general policy graph](@ref). +# [How to create a general policy graph](@ref). # ## Training and simulating the policy From 7ea2e170763c446efd7ba5d523017327c62e2cc7 Mon Sep 17 00:00:00 2001 From: Oscar Dowson Date: Fri, 27 Feb 2026 15:25:02 +1300 Subject: [PATCH 3/3] Apply suggestion from @odow --- docs/src/guides/deterministic_equivalent.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/guides/deterministic_equivalent.md b/docs/src/guides/deterministic_equivalent.md index 13fd8de9ad..abbc87333c 100644 --- a/docs/src/guides/deterministic_equivalent.md +++ b/docs/src/guides/deterministic_equivalent.md @@ -1,4 +1,4 @@ -## How to solve the deterministic equivalent +# How to solve the deterministic equivalent Sometimes, it can be helpful to solve the deterministic equivalent of a problem in order to obtain an exact solution to the problem. To obtain a JuMP