diff --git a/CMakeLists.txt b/CMakeLists.txt index a71ff1e7ca..bcb961b2d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,6 +122,9 @@ add_definitions(-DBOOST_BIND_GLOBAL_PLACEHOLDERS) find_package(PkgConfig REQUIRED) find_package(Threads REQUIRED) +# Find OpenSSL for vroom library +find_package(OpenSSL REQUIRED) + # resolve vendored libraries set(date_include_dir ${VALHALLA_SOURCE_DIR}/third_party/date/include) set(rapidjson_include_dir ${VALHALLA_SOURCE_DIR}/third_party/rapidjson/include) @@ -204,6 +207,49 @@ endif() set(CMAKE_FIND_PACKAGE_PREFER_CONFIG OFF) +# VROOM library configuration +# Check if libvroom.a exists in the vroom lib directory +set(VROOM_LIB_PATH "/Users/boon.boonsiri/local/backup/vroom/lib/libvroom.a") +if(EXISTS ${VROOM_LIB_PATH}) + message(STATUS "Found libvroom.a at ${VROOM_LIB_PATH}") + set(VROOM_LIBRARY ${VROOM_LIB_PATH}) + set(VROOM_INCLUDE_DIR "/Users/boon.boonsiri/local/backup/vroom/src") + + # Create an imported target for vroom + add_library(vroom STATIC IMPORTED) + set_target_properties(vroom PROPERTIES + IMPORTED_LOCATION ${VROOM_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${VROOM_INCLUDE_DIR} + ) + + # Add required system libraries for vroom + target_link_libraries(vroom INTERFACE + Threads::Threads + OpenSSL::SSL + OpenSSL::Crypto + ) + + # Check for GLPK (similar to the Makefile logic) + find_path(GLPK_INCLUDE_DIR glpk.h + PATHS /usr/include /usr/local/include + ) + if(GLPK_INCLUDE_DIR) + find_library(GLPK_LIBRARY glpk) + if(GLPK_LIBRARY) + message(STATUS "Found GLPK: ${GLPK_LIBRARY}") + target_link_libraries(vroom INTERFACE ${GLPK_LIBRARY}) + target_include_directories(vroom INTERFACE ${GLPK_INCLUDE_DIR}) + endif() + endif() + + set(VROOM_FOUND TRUE) + set(VROOM_FOUND ${VROOM_FOUND} CACHE BOOL "Whether VROOM library was found" FORCE) +else() + message(WARNING "libvroom.a not found at ${VROOM_LIB_PATH}") + set(VROOM_FOUND FALSE) + set(VROOM_FOUND ${VROOM_FOUND} CACHE BOOL "Whether VROOM library was found" FORCE) +endif() + # libprime_server # see https://gitlab.kitware.com/cmake/cmake/-/issues/19467 set(libprime_server_targets "") @@ -313,6 +359,13 @@ if(ENABLE_SERVICES) endforeach() endif() +# VROOM library integration with valhalla +if(VROOM_FOUND) + message(STATUS "VROOM library will be linked to valhalla") +else() + message(WARNING "VROOM library not found - vehicle routing features will not be available") +endif() + # add the scripts to the build folder as well foreach(script valhalla_build_config valhalla_build_elevation valhalla_build_extract valhalla_build_timezones) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 159c60c2e6..3e9bdd6bd9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -208,7 +208,9 @@ target_link_libraries(valhalla $<$:ws2_32> PRIVATE $<$:gcov> - Threads::Threads) + Threads::Threads + $<$:vroom>) + set_target_properties(valhalla PROPERTIES VERSION "${VERSION}" diff --git a/src/thor/CMakeLists.txt b/src/thor/CMakeLists.txt index d5de3d7026..0a5be17aaa 100644 --- a/src/thor/CMakeLists.txt +++ b/src/thor/CMakeLists.txt @@ -13,6 +13,7 @@ set(sources timedistancematrix.cc triplegbuilder.cc unidirectional_astar.cc + vehicle_routing_problem.cc worker.cc) set(sources_with_warnings diff --git a/src/thor/vehicle_routing_problem.cc b/src/thor/vehicle_routing_problem.cc new file mode 100644 index 0000000000..c254101a50 --- /dev/null +++ b/src/thor/vehicle_routing_problem.cc @@ -0,0 +1,117 @@ +#include +#include +#include "valhalla/thor/vehicle_routing_problem.h" + +#ifdef VROOM_FOUND +#include +#endif + +namespace valhalla { +namespace thor { + +VehicleRoutingSolution solve_vehicle_routing_problem(const VehicleRoutingRequest& request) { + VehicleRoutingSolution solution; + + +#ifdef VROOM_FOUND + // Create a VROOM problem instance + vroom::Input problem; + + // Add vehicles from the request + for (const auto& vehicle : request.vehicles) { + problem.add_vehicle(vroom::Vehicle(vehicle.id, vehicle.start_location, vehicle.end_location)); + } + + // Add jobs from the request + for (const auto& job : request.jobs) { + problem.add_job(vroom::Job(job.id, job.location, job.service_time)); + } + + // Set the distance matrix + problem.set_matrix(request.distance_matrix); + + // Solve the problem + vroom::Solution vroom_solution = problem.solve(); + + // Convert VROOM solution to our format + solution.total_cost = vroom_solution.summary.cost; + solution.total_service_time = vroom_solution.summary.service; + solution.total_duration = vroom_solution.summary.duration; + solution.computing_time_ms = vroom_solution.summary.computing_times.solving; + + // Convert routes + for (const auto& route : vroom_solution.routes) { + Route route_info; + route_info.vehicle_id = route.vehicle; + route_info.cost = route.cost; + route_info.duration = route.duration; + route_info.service_time = route.service; + + // Convert steps + for (const auto& step : route.steps) { + RouteStep step_info; + step_info.type = static_cast(step.type); + step_info.location = step.location; + step_info.job_id = step.job; + route_info.steps.push_back(step_info); + } + + solution.routes.push_back(route_info); + } + + // Convert unassigned jobs + for (const auto& job : vroom_solution.unassigned) { + solution.unassigned_jobs.push_back(job.id); + } +#else + // VROOM not available - return empty solution + solution.total_cost = 0; + solution.total_service_time = 0; + solution.total_duration = 0; + solution.computing_time_ms = 0; +#endif + + return solution; +} + +// Example function that demonstrates basic VRP usage +VehicleRoutingSolution solve_basic_vrp_example() { + VehicleRoutingRequest request; + + // Add one vehicle starting and ending at location 0 + Vehicle vehicle; + vehicle.id = 1; + vehicle.start_location = 0; + vehicle.end_location = 0; + request.vehicles.push_back(vehicle); + + // Add three jobs + Job job1, job2, job3; + job1.id = 1; + job1.location = 1; + job1.service_time = 300; // 5 minutes + + job2.id = 2; + job2.location = 2; + job2.service_time = 300; + + job3.id = 3; + job3.location = 3; + job3.service_time = 300; + + request.jobs = {job1, job2, job3}; + + // Define distance matrix (4x4 symmetric matrix) + // Locations: 0 (depot), 1, 2, 3 + request.distance_matrix = { + {0, 10, 15, 20}, // from depot to locations + {10, 0, 35, 25}, // from location 1 + {15, 35, 0, 30}, // from location 2 + {20, 25, 30, 0} // from location 3 + }; + + return solve_vehicle_routing_problem(request); +} + +} // namespace thor +} // namespace valhalla diff --git a/valhalla/thor/vehicle_routing_problem.h b/valhalla/thor/vehicle_routing_problem.h new file mode 100644 index 0000000000..371b646b66 --- /dev/null +++ b/valhalla/thor/vehicle_routing_problem.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include + +namespace valhalla { +namespace thor { + +// Forward declaration to avoid including VROOM headers in public interface +struct VehicleRoutingSolution; + +// Data structures for vehicle routing problem +struct Vehicle { + uint32_t id; + uint32_t start_location; + uint32_t end_location; +}; + +struct Job { + uint32_t id; + uint32_t location; + uint32_t service_time; // in seconds +}; + +struct RouteStep { + enum class StepType { + START = 0, + JOB = 1, + END = 2 + }; + + StepType type; + uint32_t location; + uint32_t job_id; +}; + +struct Route { + uint32_t vehicle_id; + uint32_t cost; + uint32_t duration; + uint32_t service_time; + std::vector steps; +}; + +struct VehicleRoutingRequest { + std::vector vehicles; + std::vector jobs; + std::vector> distance_matrix; +}; + +struct VehicleRoutingSolution { + uint32_t total_cost; + uint32_t total_service_time; + uint32_t total_duration; + uint32_t computing_time_ms; + std::vector routes; + std::vector unassigned_jobs; +}; + +/** + * Solve a vehicle routing problem using VROOM + * @param request The vehicle routing problem request + * @return The solution containing optimal routes + */ +VehicleRoutingSolution solve_vehicle_routing_problem(const VehicleRoutingRequest& request); + +/** + * Example function that demonstrates basic VRP usage + * Creates a simple problem with 1 vehicle and 3 jobs + * @return The solution for the example problem + */ +VehicleRoutingSolution solve_basic_vrp_example(); + +} // namespace thor +} // namespace valhalla