Skip to content

Commit 3d706d3

Browse files
committed
[UPD] Add combination of heuristic + exact cuts pruning
1 parent 007f89a commit 3d706d3

File tree

1 file changed

+38
-5
lines changed

1 file changed

+38
-5
lines changed

src/cutpruning.jl

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ function prune_cuts!(model::SPModel,
5858

5959
# If pruning is performed with territory heuristic, update territory
6060
# at given iteration:
61-
if param.pruning[:type] == "territory"
61+
if param.pruning[:type] ["territory", "mixed"]
6262
for t in 1:model.stageNumber-1
6363
states = reshape(trajectories[t, :, :], param.forwardPassNumber, model.dimStates)
6464
find_territory!(territory[t], V[t], states)
@@ -78,13 +78,16 @@ function prune_cuts!(model::SPModel,
7878
elseif param.pruning[:type] == "territory"
7979
# apply heuristic to prune cuts:
8080
V[i] = remove_empty_cuts!(territory[i], V[i])
81+
elseif param.pruning[:type] == "mixed"
82+
# apply mixed heuristic to prune cuts:
83+
V[i] = remove_cuts_usefulness!(model, territory[i], V[i], param.SOLVER)
8184
end
8285
end
8386

8487
# final number of cuts:
8588
ncuts_final = get_total_number_cuts(V)
8689

87-
(verbose > 0) && println(" Deflation: ", ncuts_final/ncuts_initial)
90+
(verbose > 0) && @printf(" Deflation: %.3f \n", ncuts_final/ncuts_initial)
8891
end
8992
end
9093

@@ -105,7 +108,7 @@ function exact_prune_cuts(model::SPModel, params::SDDPparameters, V::PolyhedralF
105108
ncuts = V.numCuts
106109
# Find all active cuts:
107110
if ncuts > 1
108-
active_cuts = Bool[is_cut_relevant(model, i, V, params.SOLVER) for i=1:ncuts]
111+
active_cuts = Bool[is_cut_relevant(model, i, V, params.SOLVER)[1] for i=1:ncuts]
109112
return PolyhedralFunction(V.betas[active_cuts], V.lambdas[active_cuts, :], sum(active_cuts))
110113
else
111114
return V
@@ -146,7 +149,7 @@ function is_cut_relevant(model::SPModel, k::Int, Vt::PolyhedralFunction, solver;
146149
@objective(m, Min, alpha - dot(λ_k, x) - Vt.betas[k])
147150
solve(m)
148151
sol = getobjectivevalue(m)
149-
return sol < epsilon
152+
return (sol < epsilon), getvalue(x)
150153
end
151154

152155

@@ -223,7 +226,7 @@ function add_state!(territory::Territories, V::PolyhedralFunction, x::Array{Floa
223226
end
224227

225228

226-
"""Remove empty cuts in PolyhedralFunction"""
229+
"""Remove empty cuts with heuristic in PolyhedralFunction."""
227230
function remove_empty_cuts!(territory::Territories, V::PolyhedralFunction)
228231
assert(territory.ncuts == V.numCuts)
229232

@@ -238,6 +241,36 @@ function remove_empty_cuts!(territory::Territories, V::PolyhedralFunction)
238241
end
239242

240243

244+
"""Remove empty cuts in PolyhedralFunction with usefulness test."""
245+
function remove_cuts_usefulness!(model::SPModel, territory::Territories, V::PolyhedralFunction, solver)
246+
assert(territory.ncuts == V.numCuts)
247+
248+
nstates = [length(terr) for terr in territory.territories]
249+
# Set of inactive cuts:
250+
inactive_cuts = nstates .== 0
251+
# Set of active cuts:
252+
active_cuts = nstates .> 0
253+
254+
# get index of inactive cuts:
255+
index = collect(1:territory.ncuts)[inactive_cuts]
256+
257+
# Check if inactive cuts are useful or not:
258+
for id in index
259+
status, x = is_cut_relevant(model, id, V, solver)
260+
if status
261+
active_cuts[id] = true
262+
end
263+
end
264+
265+
# Remove useless cuts:
266+
territory.territories = territory.territories[active_cuts]
267+
territory.ncuts = sum(active_cuts)
268+
return PolyhedralFunction(V.betas[active_cuts],
269+
V.lambdas[active_cuts, :],
270+
sum(active_cuts))
271+
end
272+
273+
241274
"""Get cut which approximate the best value function at point `x`."""
242275
function optimalcut(xf::Vector{Float64}, V::PolyhedralFunction)
243276
bestcost = -Inf::Float64

0 commit comments

Comments
 (0)