Skip to content
Open
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
19 changes: 10 additions & 9 deletions src/MOI_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,15 @@ function _parse_leaf(m::Optimizer, leaf::MOI.ScalarNonlinearFunction)
error("Vroom: `:sum_distances` arg 1 must be a real matrix; got $(typeof(matrix))")
items = _normalize_items(leaf.args[2])
length(items) >= 3 ||
error("Vroom: `:sum_distances` vector must be `[depot; col; depot]` (≥ 3 entries)")
error("Vroom: `:sum_distances` vector must be `[depot; col; depot]`")
items[1] isa Real ||
error("Vroom: depot_start must be a `Real`; got $(typeof(items[1]))")
items[end] isa Real ||
error("Vroom: depot_end must be a `Real`; got $(typeof(items[end]))")
depot_start = round(Int, items[1])
depot_end = round(Int, items[end])
depot_start == depot_end || error("Vroom: depot_start != depot_end is not supported")
depot = depot_start - 1 # MOI node values are one-based; Vroom is zero-based.
# All interior items must be partition variables of one column.
column = nothing
for k = 2:(length(items)-1)
Expand All @@ -222,7 +223,7 @@ function _parse_leaf(m::Optimizer, leaf::MOI.ScalarNonlinearFunction)
end
end
column === nothing && error("Vroom: `:sum_distances` has no interior variables")
return matrix, depot_start, column::Int
return matrix, depot, column::Int
end

# JuMP can hand us the second `:sum_distances` arg as either a raw
Expand Down Expand Up @@ -295,6 +296,7 @@ function MOI.optimize!(m::Optimizer)
n_locations == size(durations, 2) ||
error("Vroom: distance matrix must be square; got $(size(durations))")
n_clients = m.partition.num_clients
0 <= depot < n_locations || error("Vroom: depot index $(depot + 1) is out of bounds")
customer_locs = [loc for loc = 0:(n_locations-1) if loc != depot]
length(customer_locs) == n_clients || error(
"Vroom: matrix has $(length(customer_locs)) non-depot rows but Partition has ",
Expand Down Expand Up @@ -329,7 +331,7 @@ function MOI.optimize!(m::Optimizer)
truck_col = leaf_columns[r.vehicle+1]
for step in r.steps
step.type == "job" || continue
push!(routes[truck_col], step.location_index)
push!(routes[truck_col], step.location_index + 1)
end
end

Expand Down Expand Up @@ -366,11 +368,10 @@ function MOI.get(m::Optimizer, attr::MOI.ObjectiveValue)
return Float64(m.objective_value)
end

# Vroom assigns customers itself, so individual `VariablePrimal` queries
# don't have a meaningful answer to return — the test reaches into
# `inner.routes` via `read_routes` instead. Return the depot value so
# `JuMP.value(::VariableRef)` at least doesn't throw.
function MOI.get(m::Optimizer, attr::MOI.VariablePrimal, ::MOI.VariableIndex)
# Map each zero-padded Partition proxy to its position in Vroom's route.
function MOI.get(m::Optimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex)
MOI.check_result_index_bounds(m, attr)
return 0.0
row, column = m.variable_to_position[vi]
route = m.routes[column]
return Float64(row <= length(route) ? route[row] : 0)
end
13 changes: 3 additions & 10 deletions test/test_mathoptvrp.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
using JuMP
using Test
using Vroom
import MathOptInterface as MOI
using MathOptVRP

# The wrapper has already stored routes per partition column on the
# inner `Vroom.Optimizer`, so `read_routes` just reads them back.
function _vroom_read_routes(model, _nodes)
return JuMP.unsafe_backend(model).routes
end

@testset "MathOptVRP.test_vrp" begin
# Vroom only supports the VRP variant here, so we invoke that test
# directly rather than running `MathOptVRP.Tests.runtests`.
MathOptVRP.Tests.test_vrp(Vroom.Optimizer; read_routes = _vroom_read_routes)
@testset "$test" for test in [MathOptVRP.Tests.test_tsp, MathOptVRP.Tests.test_vrp]
test(Vroom.Optimizer)
end