Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more binary examples #207

Merged
merged 2 commits into from
May 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions examples/booking_management.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Copyright 2017-19, Oscar Dowson, Eyob Zewdie
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

#=
This example concerns the acceptance of booking requests for rooms in a
hotel in the leadup to a large event.

Each stage, we receive a booking request and can choose to accept or decline
it. Once accepted, bookings cannot be terminated.
=#

using SDDP, GLPK, Test

function booking_management_model(NUMBER_OF_DAYS, NUMBER_OF_ROOMS, NUMBER_OF_REQUESTS)
# maximum revenue that could be accrued.
MAX_REVENUE = (NUMBER_OF_ROOMS + NUMBER_OF_REQUESTS) * NUMBER_OF_DAYS * NUMBER_OF_ROOMS

#=
BOOKING_REQUESTS is a vector of {0,1} arrays of size
(NUMBER_OF_DAYS x NUMBER_OF_ROOMS) if the room is requested.
=#
BOOKING_REQUESTS = Array{Int, 2}[]
for room in 1:NUMBER_OF_ROOMS
for day in 1:NUMBER_OF_DAYS
# note: length_of_stay is 0 indexed to avoid unncecessary +/- 1
# on the indexing
for length_of_stay in 0:(NUMBER_OF_DAYS - day)
booking_request = zeros(Int, (NUMBER_OF_ROOMS, NUMBER_OF_DAYS))
booking_request[room:room, day .+ (0:length_of_stay)] .= 1
push!(BOOKING_REQUESTS, booking_request)
end
end
end

model = SDDP.LinearPolicyGraph(
stages = NUMBER_OF_REQUESTS, upper_bound = MAX_REVENUE,
sense = :Max, optimizer = with_optimizer(GLPK.Optimizer)
) do sp, stage
@variable(sp,
0 <= vacancy[room=1:NUMBER_OF_ROOMS, day=1:NUMBER_OF_DAYS] <= 1,
SDDP.State, initial_value = 1)
@variables(sp, begin
# Accept request for booking of room for length of time.
0 <= accept_request <= 1, Bin
# Accept a booking for an individual room on an individual day.
0 <= room_request_accepted[1:NUMBER_OF_ROOMS, 1:NUMBER_OF_DAYS] <= 1, Bin
# Helper for JuMP.fix
booking_request[1:NUMBER_OF_ROOMS, 1:NUMBER_OF_DAYS]
end)
for room in 1:NUMBER_OF_ROOMS, day in 1:NUMBER_OF_DAYS
@constraints(sp, begin
# Update vacancy if we accept a room request
vacancy[room, day].out == vacancy[room, day].in - room_request_accepted[room, day]
# Can't accept a request of a filled room
room_request_accepted[room, day] <= vacancy[room, day].in
# Can't accept invididual room request if entire request is declined
room_request_accepted[room, day] <= accept_request
# Can't accept request if room not requested
room_request_accepted[room, day] <= booking_request[room, day]
# Accept all individual rooms is entire request is accepted
room_request_accepted[room, day] + (1-accept_request) >= booking_request[room, day]
end)
end
SDDP.parameterize(sp, BOOKING_REQUESTS) do request
JuMP.fix.(booking_request, request)
end
@stageobjective(sp, sum(
(room + stage - 1) * room_request_accepted[room, day]
for room in 1:NUMBER_OF_ROOMS for day in 1:NUMBER_OF_DAYS
)
)
end
end

function booking_management()
m_1_2_5 = booking_management_model(1, 2, 5)
SDDP.train(m_1_2_5, iteration_limit = 10)
@test isapprox(SDDP.calculate_bound(m_1_2_5), 7.25, atol=0.02)

m_2_2_3 = booking_management_model(2, 2, 3)
SDDP.train(m_2_2_3, iteration_limit = 40)
@test isapprox(SDDP.calculate_bound(m_2_2_3), 6.13, atol=0.02)
end

booking_management()
4 changes: 0 additions & 4 deletions examples/sddp.jl_not_updated/BinaryProblems/README.md

This file was deleted.

92 changes: 0 additions & 92 deletions examples/sddp.jl_not_updated/BinaryProblems/booking_management.jl

This file was deleted.

107 changes: 0 additions & 107 deletions examples/sddp.jl_not_updated/BinaryProblems/vehicle_location.jl

This file was deleted.

90 changes: 90 additions & 0 deletions examples/vehicle_location.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2017-19, Oscar Dowson, Eyob Zewdie
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

#=
This problem is a version of the Ambulance dispatch problem. A hospital is
located at 0 on the number line that stretches from 0 to 100. Ambulance bases
are located at points 20, 40, 60, 80, and 100. When not responding to a call,
Ambulances must be located at a base, or the hospital. In this example there are
three ambulances.

Example location:

H B B B B B
0 ---- 20 ---- 40 ---- 60 ---- 80 ---- 100

Each stage, a call comes in from somewhere on the number line. The agent must
decide which ambulance to dispatch. They pay the cost of twice the driving
distance. If an ambulance is not dispatched in a stage, the ambulance can be
relocated to a different base in preparation for future calls. This incurrs a
cost of the driving distance.
=#

using SDDP, GLPK, Test

function vehicle_location_model()
hospital_location = 0
bases = vcat(hospital_location, [20, 40, 60, 80, 100])
vehicles = [1, 2, 3]
requests = 0:2:100

shift_cost(src, dest) = abs(src - dest)
function dispatch_cost(base, request)
return 2 * (abs(request - hospital_location) + abs(request - base))
end

# Initial state of emergency vehicles at bases. All ambulances start at the
# hospital.
initial_state(b, v) = b == hospital_location ? 1.0 : 0.0

model = SDDP.LinearPolicyGraph(
stages = 10, lower_bound = 0.0,
optimizer = with_optimizer(GLPK.Optimizer)) do sp, t
# Current location of each vehicle at each base.
@variable(sp,
0 <= location[b=bases, v=vehicles] <= 1, SDDP.State,
initial_value = initial_state(b, v))

@variables(sp, begin
# Which vehicle is dipatched?
0 <= dispatch[bases, vehicles] <= 1, Bin
# Shifting vehicles between bases: [src, dest, vehicle]
0 <= shift[bases, bases, vehicles] <= 1, Bin
end)

# Flow of vehicles in and out of bases:
@expression(sp, base_balance[b in bases, v in vehicles],
location[b, v].in - dispatch[b, v] - sum(shift[b, :, v]) + sum(shift[:, b, v]))

@constraints(sp, begin
# Only one vehicle dispatched to call.
sum(dispatch) == 1
# Can only dispatch vehicle from base if vehicle is at that base.
[b in bases, v in vehicles], dispatch[b, v] <= location[b, v].in
# Can only shift vehicle if vehicle is at that src base.
[b in bases, v in vehicles], sum(shift[b, :, v]) <= location[b, v].in
# Can only shift vehicle if vehicle is not being dispatched.
[b in bases, v in vehicles], sum(shift[b, :, v]) + dispatch[b, v] <= 1
# Can't shift to same base.
[b in bases, v in vehicles], shift[b, b, v] == 0
# Update states for non-home/non-hospital bases.
[b in bases[2:end], v in vehicles], location[b, v].out == base_balance[b, v]
# Update states for home/hospital bases.
[v in vehicles], location[hospital_location, v].out == base_balance[hospital_location, v] + sum(dispatch[:, v])
end)
SDDP.parameterize(sp, requests) do request
@stageobjective(sp, sum(
# Distance to travel from base to emergency and then to hospital.
dispatch[b, v] * dispatch_cost(b, request) +
# Distance travelled by vehicles relocating bases.
sum(shift_cost(b, dest) * shift[b, dest, v] for dest in bases)
for b in bases, v in vehicles))
end
end
SDDP.train(model, iteration_limit = 50)
@test isapprox(SDDP.calculate_bound(model), 1700.0, atol=5)
end

vehicle_location_model()