Skip to content

Commit b61234b

Browse files
authored
Merge pull request #97 from JuliaOpt/add-benchmark
Add benchmark
2 parents e660b9c + a5408e9 commit b61234b

File tree

7 files changed

+181
-13
lines changed

7 files changed

+181
-13
lines changed

examples/testbenchmark.jl

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright 2015, Vincent Leclere, Francois Pacaud and Henri Gerard
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this
4+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
#############################################################################
6+
# Compare different ways of solving a stock problem :
7+
# Min E [\sum_{t=1}^TF c_t u_t]
8+
# s.t. s_{t+1} = s_t + u_t - xi_t, s_0 given
9+
# 0 <= s_t <= 1
10+
# u_min <= u_t <= u_max
11+
# u_t choosen knowing xi_1 .. xi_t
12+
#############################################################################
13+
14+
using StochDynamicProgramming, JuMP, Clp, Distributions, CPLEX
15+
println("library loaded")
16+
17+
run_sddp = true
18+
19+
######## Optimization parameters ########
20+
# choose the LP solver used.
21+
#const SOLVER = ClpSolver()
22+
const SOLVER = CplexSolver(CPX_PARAM_SIMDISPLAY=0)
23+
24+
25+
# convergence test
26+
const MAX_ITER = 1 # maximum iteration of SDDP
27+
28+
######## Stochastic Model Parameters ########
29+
const N_STAGES = 5
30+
const COSTS = rand(N_STAGES)
31+
32+
const CONTROL_MAX = 0.5
33+
const CONTROL_MIN = 0
34+
35+
const XI_MAX = 0.3
36+
const XI_MIN = 0
37+
const N_XI = 10
38+
# initial stock
39+
const S0 = 0.5
40+
41+
# create law of noises
42+
proba = 1/N_XI*ones(N_XI) # uniform probabilities
43+
xi_support = collect(linspace(XI_MIN,XI_MAX,N_XI))
44+
xi_law = NoiseLaw(xi_support, proba)
45+
xi_laws = NoiseLaw[xi_law for t in 1:N_STAGES-1]
46+
47+
# Define dynamic of the stock:
48+
function dynamic(t, x, u, xi)
49+
return [x[1] + u[1] - xi[1]]
50+
end
51+
52+
# Define cost corresponding to each timestep:
53+
function cost_t(t, x, u, w)
54+
return COSTS[t] * u[1]
55+
end
56+
57+
######## Setting up the SPmodel
58+
s_bounds = [(0, 1)]
59+
u_bounds = [(CONTROL_MIN, CONTROL_MAX)]
60+
spmodel = LinearDynamicLinearCostSPmodel(N_STAGES, u_bounds, [S0], cost_t, dynamic, xi_laws)
61+
set_state_bounds(spmodel, s_bounds)
62+
63+
64+
######### Define scenarios
65+
scenarios = StochDynamicProgramming.simulate_scenarios(xi_laws, 1000)
66+
67+
######## Define different scenarios
68+
paramSDDP1 = SDDPparameters(SOLVER, 4, 0, MAX_ITER) #forwardpassnumber, sensibility
69+
paramSDDP2 = SDDPparameters(SOLVER, 10, 0, 2)
70+
71+
######## Define parameters collection
72+
paramSDDP = [paramSDDP1 for i in 1:4]
73+
74+
#Benchmark the collection of parameters
75+
benchmark_parameters(spmodel, paramSDDP, scenarios, 12)

src/SDDPoptimize.jl

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fulfilled.
2121
the stochastic problem we want to optimize
2222
* `param::SDDPparameters`:
2323
the parameters of the SDDP algorithm
24-
* `display::Int64)`:
24+
* `display::Int64`:
2525
Default is `0`
2626
If non null, display progression in terminal every
2727
`n` iterations, where `n` is number specified by display.
@@ -32,20 +32,24 @@ fulfilled.
3232
* `problems::Array{JuMP.Model}`:
3333
the collection of linear problems used to approximate
3434
each value function
35+
* `count_callsolver::Int64`:
36+
number of times the solver has been called
37+
3538
"""
3639
function solve_SDDP(model::SPModel, param::SDDPparameters, display=0::Int64)
3740
# initialize value functions:
3841
V, problems = initialize_value_functions(model, param)
3942
# Run SDDP upon example:
40-
run_SDDP!(model, param, V, problems, display)
41-
return V, problems
43+
count_callsolver = run_SDDP!(model, param, V, problems, display)
44+
return V, problems, count_callsolver
4245
end
4346

47+
4448
function solve_SDDP(model::SPModel, param::SDDPparameters, V::Vector{PolyhedralFunction}, display=0::Int64)
4549
# First step: process value functions if hotstart is called
4650
problems = hotstart_SDDP(model, param, V)
47-
run_SDDP!(model, param, V, problems, display)
48-
return V, problems
51+
count_callsolver = run_SDDP!(model, param, V, problems, display)
52+
return V, problems, count_callsolver
4953
end
5054

5155

@@ -56,6 +60,9 @@ function run_SDDP!(model::SPModel,
5660
problems::Vector{JuMP.Model},
5761
display=0::Int64)
5862

63+
#Initialization of the counter
64+
count_callsolver::Int = 0
65+
5966
if display > 0
6067
println("Initialize cuts")
6168
end
@@ -80,20 +87,23 @@ function run_SDDP!(model::SPModel,
8087
noise_scenarios = simulate_scenarios(model.noises, param.forwardPassNumber)
8188

8289
# Forward pass
83-
stockTrajectories = forward_simulations(model,
90+
_, stockTrajectories,_,callsolver_forward = forward_simulations(model,
8491
param,
8592
problems,
86-
noise_scenarios)[2]
93+
noise_scenarios)
94+
8795

8896
# Backward pass
89-
backward_pass!(model,
97+
callsolver_backward = backward_pass!(model,
9098
param,
9199
V,
92100
problems,
93101
stockTrajectories,
94102
model.noises,
95103
false)
96104

105+
#Update the number of call
106+
count_callsolver += callsolver_forward + callsolver_backward
97107

98108
iteration_count += 1
99109

@@ -138,6 +148,8 @@ function run_SDDP!(model::SPModel,
138148
println("Estimation of cost of the solution (fiability 95\%):",
139149
round(mean(costs),4), " +/- ", round(1.96*std(costs)/sqrt(length(costs)),4))
140150
end
151+
152+
return count_callsolver
141153
end
142154

143155

@@ -169,6 +181,7 @@ function estimate_upper_bound(model::SPModel, param::SDDPparameters,
169181

170182
aleas = simulate_scenarios(model.noises, n_simulation)
171183

184+
callsolver::Int = 0
172185
costs, stockTrajectories, _ = forward_simulations(model,
173186
param,
174187
problem,
@@ -328,7 +341,7 @@ function initialize_value_functions(model::SPModel,
328341
end
329342

330343

331-
backward_pass!(model,
344+
callsolver = backward_pass!(model,
332345
param,
333346
V,
334347
solverProblems,
@@ -552,4 +565,3 @@ function is_cut_relevant(model::SPModel, k::Int, Vt::PolyhedralFunction, solver;
552565
sol = getobjectivevalue(m)
553566
return sol < epsilon
554567
end
555-

src/StochDynamicProgramming.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ export solve_SDDP,
1818
PiecewiseLinearCostSPmodel, extensive_formulation,
1919
PolyhedralFunction, NextStep, forward_simulations,
2020
StochDynProgModel, SDPparameters, solve_DP,
21-
sdp_forward_simulation, sampling, get_control, get_bellman_value
21+
sdp_forward_simulation, sampling, get_control, get_bellman_value,
22+
benchmark_parameters
2223

2324
include("objects.jl")
2425
include("utils.jl")
@@ -27,4 +28,5 @@ include("forwardBackwardIterations.jl")
2728
include("SDDPoptimize.jl")
2829
include("extensiveFormulation.jl")
2930
include("SDPoptimize.jl")
31+
include("compare.jl")
3032
end

src/compare.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Copyright 2015, Vincent Leclere, Francois Pacaud and Henri Gerard
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this
4+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
#############################################################################
6+
# Compare the optimal values and control returned by different instances
7+
# of SDDP on the same problem
8+
#############################################################################
9+
10+
"""
11+
Compare different sets of parameters to solve an instance of SDDP
12+
13+
# Description
14+
Take a collection of SDDP parameters and compare the time of execution,
15+
the memory used, an estimation of the gap to optimality and the number
16+
of calls to the solver
17+
18+
# Arguments
19+
* `model::SPmodel`:
20+
The stochastic problem we want to benchmark
21+
* `SDDParametersCollection::Array{Any,1}`
22+
Collection of SDDPparameters
23+
* `scenarios::Array{Float64,3}`
24+
Set of scenarios used to calculate costs
25+
* `seeds::Int`
26+
The random number generator seeds
27+
28+
# Output
29+
* `Display in the terminal`
30+
Print information in the terminal
31+
"""
32+
function benchmark_parameters(model,
33+
SDDParametersCollection,
34+
scenarios::Array{Float64,3},
35+
seeds::Int)
36+
37+
#Execute a first time each function to compile them
38+
(V, pbs, callsolver), t1, m1 = @timed solve_SDDP(model, SDDParametersCollection[1], 0)
39+
V0, t2, m2 = @timed get_bellman_value(model, SDDParametersCollection[1], 1, V[1], model.initialState)
40+
(upb, costs), t3, m3 = @timed estimate_upper_bound(model, SDDParametersCollection[1], scenarios, pbs)
41+
42+
43+
for sddpparams in SDDParametersCollection
44+
45+
srand(seeds)
46+
47+
(V, pbs, callsolver), t1, m1 = @timed solve_SDDP(model, sddpparams, 0)
48+
V0, t2, m2 = @timed get_bellman_value(model, sddpparams, 1, V[1], model.initialState)
49+
(upb, costs), t3, m3 = @timed estimate_upper_bound(model, sddpparams, scenarios, pbs)
50+
51+
solvingtime = t1
52+
simulationtime = t2+t3
53+
solvingmemory = m1
54+
simulationmemory = m2+m3
55+
56+
print("Instance \t")
57+
print("Solving time = ",round(solvingtime,4),"\t")
58+
print("Solving memory = ", solvingmemory,"\t")
59+
print("Simulation time = ",round(simulationtime,4),"\t")
60+
print("Simulation memory = ", simulationmemory,"\t")
61+
print("Gap < ", round(100*(upb-V0)/V0),"% with prob 97.5%\t")
62+
println("number external solver call = ", callsolver)
63+
end
64+
end

src/forwardBackwardIterations.jl

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,17 @@ scenario according to the current value functions.
3333
* `controls::Array{Float64, 3}`:
3434
the simulated controls trajectories. controls(t,k,:) is the control for
3535
scenario k at time t.
36+
* `callsolver::Int64`:
37+
the number of solver's call'
38+
3639
"""
3740
function forward_simulations(model::SPModel,
3841
param::SDDPparameters,
3942
solverProblems::Vector{JuMP.Model},
4043
xi::Array{Float64})
4144

45+
callsolver::Int = 0
46+
4247
T = model.stageNumber
4348
nb_forward = size(xi)[2]
4449

@@ -69,6 +74,7 @@ function forward_simulations(model::SPModel,
6974
state_t = collect(stocks[t, k, :])
7075
alea_t = collect(xi[t, k, :])
7176

77+
callsolver += 1
7278
status, nextstep = solve_one_step_one_alea(
7379
model,
7480
param,
@@ -89,7 +95,7 @@ function forward_simulations(model::SPModel,
8995
end
9096
end
9197
end
92-
return costs, stocks, controls
98+
return costs, stocks, controls, callsolver
9399
end
94100

95101

@@ -174,6 +180,8 @@ function backward_pass!(model::SPModel,
174180
law,
175181
init=false::Bool)
176182

183+
callsolver::Int = 0
184+
177185
T = model.stageNumber
178186
nb_forward = size(stockTrajectories)[2]
179187

@@ -193,6 +201,7 @@ function backward_pass!(model::SPModel,
193201

194202
alea_t = collect(law[t].support[:, w])
195203

204+
callsolver += 1
196205
solved, nextstep = solve_one_step_one_alea(model, param, solverProblems[t], t, state_t, alea_t)
197206
if solved
198207
subgradient_array[:, w] = nextstep.sub_gradient
@@ -225,4 +234,5 @@ function backward_pass!(model::SPModel,
225234

226235
end
227236
end
237+
return callsolver
228238
end

test/runtests.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,3 @@ include("sddp.jl")
2020

2121
# Test DP:
2222
include("sdp.jl")
23-

test/sddp.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,12 @@ facts("SDDP algorithm: 1D case") do
173173
@fact V[1].betas --> Vdump[1].betas
174174
@fact V[1].lambdas --> Vdump[1].lambdas
175175
end
176+
177+
context("Compare parameters") do
178+
paramSDDP = [params for i in 1:3]
179+
scenarios = StochDynamicProgramming.simulate_scenarios(laws, 1000)
180+
benchmark_parameters(model, paramSDDP, scenarios, 12)
181+
end
176182
end
177183

178184

0 commit comments

Comments
 (0)