Booking management
This tutorial was generated using Literate.jl. Download the source as a .jl file. Download the source as a .ipynb file.
This example concerns the acceptance of booking requests for rooms in a hotel in the lead up 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, HiGHS, Testfunction booking_management_model(num_days, num_rooms, num_requests) # maximum revenue that could be accrued. max_revenue = (num_rooms + num_requests) * num_days * num_rooms # booking_requests is a vector of {0,1} arrays of size # (num_days x num_rooms) if the room is requested. booking_requests = Array{Int,2}[] for room in 1:num_rooms for day in 1:num_days # note: length_of_stay is 0 indexed to avoid unnecessary +/- 1 # on the indexing for length_of_stay in 0:(num_days-day) req = zeros(Int, (num_rooms, num_days)) req[room:room, day.+(0:length_of_stay)] .= 1 push!(booking_requests, req) end end end return model = SDDP.LinearPolicyGraph(; stages = num_requests, upper_bound = max_revenue, sense = :Max, optimizer = HiGHS.Optimizer, ) do sp, stage @variable( sp, 0 <= vacancy[room = 1:num_rooms, day = 1:num_days] <= 1, SDDP.State, Bin, 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:num_rooms, 1:num_days] <= 1, Bin # Helper for JuMP.fix req[1:num_rooms, 1:num_days] end ) for room in 1:num_rooms, day in 1:num_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] <= req[room, day] # Accept all individual rooms is entire request is accepted room_request_accepted[room, day] + (1 - accept_request) >= req[room, day] end ) end SDDP.parameterize(sp, booking_requests) do request fix.(req, request) return end @stageobjective( sp, sum( (room + stage - 1) * room_request_accepted[room, day] for room in 1:num_rooms for day in 1:num_days ) ) endendfunction booking_management(duality_handler) m_1_2_5 = booking_management_model(1, 2, 5) SDDP.train(m_1_2_5; log_frequency = 5, duality_handler = duality_handler) if duality_handler == SDDP.ContinuousConicDuality() @test SDDP.calculate_bound(m_1_2_5) >= 7.25 - 1e-4 else @test isapprox(SDDP.calculate_bound(m_1_2_5), 7.25, atol = 0.02) end m_2_2_3 = booking_management_model(2, 2, 3) SDDP.train(m_2_2_3; log_frequency = 10, duality_handler = duality_handler) if duality_handler == SDDP.ContinuousConicDuality() @test SDDP.calculate_bound(m_1_2_5) > 6.13 else @test isapprox(SDDP.calculate_bound(m_2_2_3), 6.13, atol = 0.02) endendbooking_management(SDDP.ContinuousConicDuality())Test PassedNew version of HiGHS stalls booking_management(SDDP.LagrangianDuality())