Skip to content

Commit c035625

Browse files
committed
Merge pull request #65 from leclere/dev-release-v0.1.1
Release v0.1.1
2 parents 7665569 + 7f27207 commit c035625

12 files changed

+441
-487
lines changed

doc/index.rst

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
You can adapt this file completely to your liking, but it should at least
44
contain the root `toctree` directive.
55
6-
StochDynamicProgramming Index
7-
=============================
6+
=======================
7+
StochDynamicProgramming
8+
=======================
89

910
This package implements the Stochastic Dual Dynamic Programming (SDDP) algorithm with Julia. It relies upon MathProgBase_ and JuMP_.
1011

@@ -43,18 +44,14 @@ We have a lot of ideas to implement further :
4344

4445

4546
Contents:
47+
=========
4648

4749
.. toctree::
48-
:maxdepth: 2
50+
install
51+
quickstart
52+
tutorial
4953

5054
.. _MathProgBase: http://mathprogbasejl.readthedocs.org/en/latest/
5155
.. _here: http://www2.isye.gatech.edu/people/faculty/Alex_Shapiro/ONS-FR.pdf
5256
.. _JuMP: http://jump.readthedocs.org/en/latest/
5357

54-
Indices and tables
55-
==================
56-
57-
* :ref:`genindex`
58-
* :ref:`modindex`
59-
* :ref:`search`
60-

doc/install.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
.. _install:
2+
3+
==================
4+
Installation guide
5+
==================
6+
7+
8+
StochDynamicProgramming installation
9+
------------------------------------
10+
11+
To install StochDynamicProgramming::
12+
13+
julia> Pkg.clone("https://github.com/leclere/StochDynamicProgramming.jl")
14+
15+
Once the package is installed, you can import it in the REPL::
16+
17+
julia> using StochDynamicProgramming
18+
19+
20+
Install a linear programming solver
21+
-----------------------------------
22+
23+
SDDP need a linear programming solver to run. Clp is installed by default with StochDynamicProgramming.jl.
24+
25+
Refer to the documentation of JuMP_ to get another solver and interface it with SDDP.
26+
27+
28+
29+
The following solvers have been tested:
30+
31+
.. table:
32+
====== ===========
33+
Solver Is working?
34+
====== ===========
35+
Clp Yes
36+
CPLEX Yes
37+
Gurobi Yes
38+
GLPK **No**
39+
====== ===========
40+
41+
Run Unit-Tests
42+
--------------
43+
To run unit-tests::
44+
45+
$ julia test/runtests.jl
46+
47+
48+
.. _JuMP: http://jump.readthedocs.org/en/latest/installation.html#getting-solvers
49+

doc/quickstart.rst

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
.. _quickstart:
2+
3+
====================
4+
Step-by-step example
5+
====================
6+
7+
This page gives a short introduction to the interface of this package. It explains the resolution with SDDP of a classical example: the management of a dam over one year with random inflow.
8+
9+
Use case
10+
========
11+
In the following, :math:`x_t` will denote the state and :math:`u_t` the control at time :math:`t`.
12+
We will consider a dam, whose dynamic is:
13+
14+
.. math::
15+
x_{t+1} = x_t - u_t + w_t
16+
17+
At time :math:`t`, we have a random inflow :math:`w_t` and we choose to turbine a quantity :math:`u_t` of water.
18+
19+
The turbined water is used to produce electricity, which is being sold at a price :math:`c_t`. At time :math:`t` we gain:
20+
21+
.. math::
22+
C(x_t, u_t, w_t) = c_t \times u_t
23+
24+
We want to minimize the following criterion:
25+
26+
.. math::
27+
J = \underset{x, u}{\min} \sum_{t=0}^{T-1} C(x_t, u_t, w_t)
28+
29+
We will assume that both states and controls are bounded:
30+
31+
.. math::
32+
x_t \in [0, 100], \qquad u_t \in [0, 7]
33+
34+
35+
Problem definition in Julia
36+
===========================
37+
38+
We will consider 52 time steps as we want to find optimal value functions for one year::
39+
40+
N_STAGES = 52
41+
42+
43+
and we consider the following initial position::
44+
45+
X0 = [50]
46+
47+
Note that X0 is a vector.
48+
49+
Dynamic
50+
^^^^^^^
51+
52+
We write the dynamic (which return a vector)::
53+
54+
function dynamic(t, x, u, xi)
55+
return [x[1] + u[1] - xi[1]]
56+
end
57+
58+
59+
Cost
60+
^^^^
61+
62+
we store evolution of costs :math:`c_t` in an array `COSTS`, and we define the cost function (which return a float)::
63+
64+
function cost_t(t, x, u, w)
65+
return COSTS[t] * u[1]
66+
end
67+
68+
Noises
69+
^^^^^^
70+
71+
Noises are defined in an array of Noiselaw. This type defines a discrete probability.
72+
73+
74+
For instance, if we want to define a uniform probability with size :math:`N= 10`, such that:
75+
76+
.. math::
77+
\mathbb{P} \left(X_i = i \right) = \dfrac{1}{N} \qquad \forall i \in 1 .. N
78+
79+
we write::
80+
81+
N = 10
82+
proba = 1/N*ones(N) # uniform probabilities
83+
xi_support = collect(linspace(1,N,N))
84+
xi_law = NoiseLaw(xi_support, proba)
85+
86+
87+
Thus, we could define a different probability laws for each time :math:`t`. Here, we suppose that the probability is constant over time, so we could build the following vector::
88+
89+
xi_laws = NoiseLaw[xi_law for t in 1:N_STAGES-1]
90+
91+
92+
Bounds
93+
^^^^^^
94+
95+
We add bounds over the state and the control::
96+
97+
s_bounds = [(0, 100)]
98+
u_bounds = [(0, 7)]
99+
100+
101+
Problem definition
102+
^^^^^^^^^^^^^^^^^^
103+
104+
As our problem is purely linear, we instantiate::
105+
106+
spmodel = LinearDynamicLinearCostSPmodel(N_STAGES,u_bounds,X0,cost_t,dynamic,xi_laws)
107+
108+
109+
Solver
110+
^^^^^^
111+
We define a SDDP solver for our problem.
112+
113+
First, we need to use a LP solver::
114+
115+
using Clp
116+
SOLVER = ClpSolver()
117+
118+
Clp is automatically installed during package installation. To install different solvers on your machine, refer to the JuMP_ documentation.
119+
120+
Once the solver installed, we define SDDP algorithm parameters::
121+
122+
forwardpassnumber = 2 # number of forward pass
123+
sensibility = 0. # admissible gap between upper and lower bound
124+
max_iter = 20 # maximum number of iterations
125+
126+
paramSDDP = SDDPparameters(SOLVER, forwardpassnumber, sensibility, max_iter)
127+
128+
129+
Now, we solve the problem by computing Bellman values::
130+
131+
V, pbs = solve_SDDP(spmodel, paramSDDP, 10) # display information every 10 iterations
132+
133+
:code:`V` is an array storing the value functions, and :code:`pbs` a vector of JuMP.Model storing each value functions as a linear problem.
134+
135+
We have an exact lower bound given by :code:`V` with the function::
136+
137+
lb_sddp = StochDynamicProgramming.get_lower_bound(spmodel, paramSDDP, V)
138+
139+
140+
Find optimal controls
141+
=====================
142+
143+
Once Bellman functions are computed, we can control our system over assessments scenarios, without assuming knowledge of the future.
144+
145+
We build 1000 scenarios according to the laws stored in :code:`xi_laws`::
146+
147+
scenarios = StochDynamicProgramming.simulate_scenarios(xi_laws,1000)
148+
149+
We compute 1000 simulations of the system over these scenarios::
150+
151+
costsddp, stocks = forward_simulations(spmodel, paramSDDP, V, pbs, scenarios)
152+
153+
:code:`costsddp` returns the costs for each scenario, and :code:`stocks` the evolution of each stock along time, for each scenario.
154+
155+
.. _JuMP: http://jump.readthedocs.io/en/latest/installation.html#coin-or-clp-and-cbc
156+

doc/tutorial.rst

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
2+
========
3+
Advanced functions
4+
========
5+
6+
This page gives an overview of the functions implemented in the package.
7+
8+
In the following, :code:`model` will design a :code:`SPModel` storing the definition of a stochastic problem, and :code:`param` a SDDPparameters instance which stores the parameters specified for SDDP. See quickstart_ for more information about these two objects.
9+
10+
Work with PolyhedralFunction
11+
============================
12+
13+
Get Bellman value at a given point
14+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
To estimate the Bellman value at a given position :code:`xt` with a :code:`PolyhedralFunction` :code:`Vt` ::
16+
17+
vx = get_bellman_value(model, param, t, Vt, xt)
18+
19+
This is a lower bound of the true value.
20+
21+
Get optimal control at a given point
22+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
24+
To get optimal control at a given point :code:`xt` and for a given alea :code:`xi`::
25+
26+
get_control(model, param, lpproblem, t, xt, xi)
27+
28+
where :code:`lpproblem` is the linear problem storing the evaluation of Bellman function at time :math:`t`.
29+
30+
31+
32+
Save and load pre-computed cuts
33+
===============================
34+
35+
Assume that we have computed Bellman functions with SDDP. These functions are stored in a vector of :code:`PolyhedralFunctions` denoted :code:`V`
36+
37+
These functions can be stored in a text file with the command::
38+
39+
StochDynamicProgramming.dump_polyhedral_functions("yourfile.dat", V)
40+
41+
And then be loaded with the function::
42+
43+
Vdump = StochDynamicProgramming.read_polyhedral_functions("yourfile.dat")
44+
45+
46+
47+
Build LP Models with PolyhedralFunctions
48+
=======================================
49+
50+
We can build a vector of :code:`JuMP.Model` with a vector of :code:`PolyhedralFunction` to perform simulation. For this, use the function::
51+
52+
problems = StochDynamicProgramming.hotstart_SDDP(model, param, V)
53+
54+
55+
SDDP hotstart
56+
=============
57+
58+
If cuts are already available, we can hotstart SDDP while overloading the function :code:`solve_SDDP`::
59+
60+
V, pbs = solve_SDDP(model, params, 0, V)
61+
62+
63+
Cuts pruning
64+
============
65+
66+
The more SDDP run, the more cuts you need to store. It is sometimes useful to delete cuts which are useless for the computation of the approximated Bellman functions.
67+
68+
69+
To clean a single :code:`PolyhedralFunction` :code:`Vt`::
70+
71+
Vt = exact_prune_cuts(model, params, Vt)
72+
73+
To clean a vector of :code:`PolyhedralFunction` :code:`V`::
74+
75+
prune_cuts!(model, params, V)
76+
77+
78+
.. _quickstart: quickstart.html

examples/dam.jl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Return a Vector{NoiseLaw}"""
123123
function generate_probability_laws()
124124
aleas = build_scenarios(N_SCENARIOS, build_aleas())
125125

126-
laws = Vector{NoiseLaw}(N_STAGES)
126+
laws = Vector{NoiseLaw}(N_STAGES-1)
127127

128128
# uniform probabilities:
129129
proba = 1/N_SCENARIOS*ones(N_SCENARIOS)
@@ -160,13 +160,11 @@ end
160160

161161

162162
"""Solve the problem."""
163-
function solve_dams(display=false)
163+
function solve_dams(display=0)
164164
model, params = init_problem()
165165

166166
V, pbs = solve_SDDP(model, params, display)
167-
aleas = simulate_scenarios(model.noises ,(model.stageNumber-1,
168-
params.forwardPassNumber , model.dimNoises))
169-
params.forwardPassNumber = 1
167+
aleas = simulate_scenarios(model.noises, params.forwardPassNumber)
170168

171169
costs, stocks = forward_simulations(model, params, V, pbs, aleas)
172170

examples/damsvalley.jl

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ Return a Vector{NoiseLaw}"""
126126
function generate_probability_laws()
127127
aleas = build_scenarios(N_SCENARIOS, build_aleas())
128128

129-
laws = Vector{NoiseLaw}(N_STAGES)
129+
laws = Vector{NoiseLaw}(N_STAGES-1)
130130

131131
# uniform probabilities:
132132
proba = 1/N_SCENARIOS*ones(N_SCENARIOS)
@@ -165,21 +165,12 @@ end
165165

166166

167167
"""Solve the problem."""
168-
function solve_dams(display=false)
169-
168+
function solve_dams(display=0)
170169
model, params = init_problem()
171170

172171
V, pbs = solve_SDDP(model, params, display)
173-
174-
aleas = simulate_scenarios(model.noises,
175-
(model.stageNumber-1,
176-
params.forwardPassNumber,
177-
model.dimNoises))
178-
179-
params.forwardPassNumber = 1
180-
181-
costs, stocks = forward_simulations(model, params, V, pbs, aleas)
182-
172+
aleas = simulate_scenarios(model.noises, params.forwardPassNumber)
173+
costs, stocks, controls = forward_simulations(model, params, V, pbs, aleas)
183174

184175
println("SDDP cost: ", costs)
185176
return stocks, V, controls

0 commit comments

Comments
 (0)