Skip to content

Commit 1d1dc8a

Browse files
committed
[DEV] Add functions to prune cuts
1 parent cc16ce8 commit 1d1dc8a

File tree

3 files changed

+86
-6
lines changed

3 files changed

+86
-6
lines changed

src/SDDPoptimize.jl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,3 +504,77 @@ function add_cuts_to_model!(model::SPModel, t::Int64, problem::JuMP.Model, V::Po
504504
end
505505
end
506506

507+
508+
"""
509+
Prune all polyhedral functions in input array.
510+
511+
Parameters:
512+
- model (SPModel)
513+
- params (SDDPparameters)
514+
- V Vector{PolyhedralFunction}
515+
Polyhedral functions where cuts will be removed
516+
517+
"""
518+
function prune_cuts!(model::SPModel, params::SDDPparameters, V::Vector{PolyhedralFunction})
519+
for i in 1:length(V)
520+
V[i] = prune_cuts(model, params, V[i])
521+
end
522+
end
523+
524+
525+
"""
526+
Remove useless cuts in PolyhedralFunction.
527+
528+
Parameters:
529+
- model (SPModel)
530+
- params (SDDPparameters)
531+
- V (PolyhedralFunction)
532+
Polyhedral function where cuts will be removed
533+
534+
Return:
535+
- PolyhedralFunction: pruned polyhedral function
536+
537+
"""
538+
function prune_cuts(model::SPModel, params::SDDPparameters, V::PolyhedralFunction)
539+
ncuts = V.numCuts
540+
# Find all active cuts:
541+
active_cuts = Bool[is_cut_active(model, i, V, params.solver) for i=1:ncuts]
542+
return PolyhedralFunction(V.betas[active_cuts], V.lambdas[active_cuts, :], sum(active_cuts))
543+
end
544+
545+
546+
"""
547+
Test whether the cut number k is active in polyhedral function Vt.
548+
549+
Parameters:
550+
- model (SPModel)
551+
- k (Int)
552+
Position of cut to test in PolyhedralFunction object
553+
- Vt (PolyhedralFunction)
554+
Object storing all cuts
555+
- solver
556+
Solver to use to solve linear problem
557+
558+
Return:
559+
- Bool: true if the cut is active, false otherwise
560+
561+
"""
562+
function is_cut_active(model::SPModel, k::Int, Vt::PolyhedralFunction, solver)
563+
564+
m = Model(solver=solver)
565+
@defVar(m, alpha)
566+
@defVar(m, model.xlim[i][1] <= x[i=1:model.dimStates] <= model.xlim[i][2])
567+
568+
for i in 1:Vt.numCuts
569+
if i!=k
570+
lambda = vec(Vt.lambdas[i, :])
571+
@addConstraint(m, Vt.betas[i] + dot(lambda, x) <= alpha)
572+
end
573+
end
574+
575+
λ_k = vec(Vt.lambdas[k, :])
576+
@setObjective(m, Min, alpha - dot(λ_k, x) - Vt.betas[k])
577+
solve(m)
578+
return getObjectiveValue(m) < 0.
579+
end
580+

src/utils.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Remove redundant cuts in Polyhedral Value functions
7878
7979
"""
8080
function remove_cuts(V::PolyhedralFunction)
81-
Vf = hcat(V.lambdas, V.be tas)
81+
Vf = hcat(V.lambdas, V.betas)
8282
Vf = unique(Vf, 1)
8383
return PolyhedralFunction(Vf[:, end], Vf[:, 1:end-1], size(Vf)[1])
8484
end
@@ -89,7 +89,7 @@ Remove redundant cuts in a vector of Polyhedral Functions.
8989
9090
"""
9191
function remove_redundant_cuts!(Vts::Vector{PolyhedralFunction})
92-
n_funct ions = length(Vts)
92+
n_functions = length(Vts)
9393
for i in 1:n_functions
9494
Vts[i] = remove_cuts(Vts[i])
9595
end

test/runtests.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,12 @@ facts("SDDP algorithm: 1D case") do
105105
u_bounds, x0,
106106
cost,
107107
dynamic, laws)
108+
set_state_bounds(model, x_bounds)
108109
# Generate scenarios for forward simulations:
109110
noise_scenarios = simulate_scenarios(model.noises,params.forwardPassNumber)
110111

111112
sddp_costs = 0
112113
context("Linear cost") do
113-
# Instantiate a SDDP linear model:
114-
set_state_bounds(model, x_bounds)
115-
116-
117114
# Compute bellman functions with SDDP:
118115
V, pbs = solve_SDDP(model, params, 0)
119116
@fact typeof(V) --> Vector{StochDynamicProgramming.PolyhedralFunction}
@@ -152,6 +149,15 @@ facts("SDDP algorithm: 1D case") do
152149
@fact mean(sddp_costs) --> roughly(mean(sddp_costs2))
153150
end
154151

152+
context("Cuts pruning") do
153+
v = V[1]
154+
vt = PolyhedralFunction([v.betas[1]; v.betas[1] - 1.], v.lambdas[[1,1],:], 2)
155+
StochDynamicProgramming.prune_cuts!(model, params, V)
156+
isactive1 = StochDynamicProgramming.is_cut_active(model, 1, vt, params.solver)
157+
isactive2 = StochDynamicProgramming.is_cut_active(model, 2, vt, params.solver)
158+
@fact isactive1 --> true
159+
@fact isactive2 --> false
160+
end
155161

156162
context("Piecewise linear cost") do
157163
# Test Piecewise linear costs:

0 commit comments

Comments
 (0)