diff --git a/cpp/src/routing/adapters/assignment_adapter.cuh b/cpp/src/routing/adapters/assignment_adapter.cuh index d2f5f103f7..02b1c66c82 100644 --- a/cpp/src/routing/adapters/assignment_adapter.cuh +++ b/cpp/src/routing/adapters/assignment_adapter.cuh @@ -98,11 +98,14 @@ assignment_t ges_solver_t::get_ges_assignment( std::vector departure_forward_h(node_infos_h.size(), 0.); std::vector actual_arrival_h(node_infos_h.size(), 0.); std::vector earliest_arrival_backward_h(node_infos_h.size(), 0.); + std::vector latest_arrival_forward_h(node_infos_h.size(), 0.); if (problem.dimensions_info.has_dimension(detail::dim_t::TIME)) { departure_forward_h = cuopt::host_copy(route.dimensions.time_dim.departure_forward); actual_arrival_h = cuopt::host_copy(route.dimensions.time_dim.actual_arrival); earliest_arrival_backward_h = cuopt::host_copy(route.dimensions.time_dim.earliest_arrival_backward); + latest_arrival_forward_h = + cuopt::host_copy(route.dimensions.time_dim.latest_arrival_forward); } i_t drop_return_trip = sol.problem_ptr->drop_return_trip_h[vehicle_id]; @@ -128,7 +131,8 @@ assignment_t ges_solver_t::get_ges_assignment( if (sol_status == solution_status_t::SUCCESS) { if (sol.problem_ptr->dimensions_info.time_dim.should_compute_travel_time()) { cuopt_assert(abs(actual_arrival_h[i] - - max(earliest_arrival_backward_h[i], departure_forward_h[i])) < 0.0001f, + max(min(earliest_arrival_backward_h[i], latest_arrival_forward_h[i]), + departure_forward_h[i])) < 0.0001f, "Feasible time mismatch!"); } else { cuopt_assert(abs(actual_arrival_h[i] - departure_forward_h[i]) < 0.0001f, diff --git a/cpp/src/routing/solution/solution.cuh b/cpp/src/routing/solution/solution.cuh index 9c0ff8da31..e130c11748 100644 --- a/cpp/src/routing/solution/solution.cuh +++ b/cpp/src/routing/solution/solution.cuh @@ -243,10 +243,12 @@ DI node_t create_depot_node(const typename problem_t::max_capacity_dim>([&](auto i) { if (i < node.capacity_dim.n_capacity_dimensions) { node.capacity_dim.demand[i] = 0; } @@ -277,10 +279,12 @@ constexpr node_t create_depot_node(const problem_t* : min(problem->order_info_h.latest_time[DEPOT], problem->fleet_info_h.latest_time[vehicle_id]); - node.time_dim.window_start = earliest; - node.time_dim.window_end = latest; - node.time_dim.departure_forward = node.time_dim.window_start; - node.time_dim.departure_backward = node.time_dim.window_end; + node.time_dim.window_start = earliest; + node.time_dim.window_end = latest; + node.time_dim.departure_forward = node.time_dim.window_start; + node.time_dim.departure_backward = node.time_dim.window_end; + node.time_dim.latest_arrival_forward = latest; + node.time_dim.earliest_arrival_backward = earliest; constexpr_for::max_capacity_dim>([&](auto i) { if (i < node.capacity_dim.n_capacity_dimensions) { node.capacity_dim.demand[i] = 0; } diff --git a/cpp/tests/routing/CMakeLists.txt b/cpp/tests/routing/CMakeLists.txt index fd3583fd9c..273fa0420c 100644 --- a/cpp/tests/routing/CMakeLists.txt +++ b/cpp/tests/routing/CMakeLists.txt @@ -16,7 +16,6 @@ ConfigureTest(ROUTING_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_routing_test.cu) ConfigureTest(ROUTING_GES_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_ges_test.cu) -# ConfigureTest(SCROSS_GES_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_scross_test.cu) ConfigureTest(VEHICLE_ORDER_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_vehicle_order_match.cu) ConfigureTest(VEHICLE_TYPES_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_vehicle_types_test.cu) ConfigureTest(OBJECTIVE_FUNCTION_TEST ${CMAKE_CURRENT_SOURCE_DIR}/level0/l0_objective_function_test.cu) @@ -28,11 +27,6 @@ ConfigureTest(RETAIL_L1TEST ${CMAKE_CURRENT_SOURCE_DIR}/level1/l1_retail_test.cu # ################################################################################################## # - L1 tests for quick regression check -------------------------------------------------------------------------- ConfigureTest(ROUTING_L1TEST ${CMAKE_CURRENT_SOURCE_DIR}/level1/l1_routing_test.cu) -ConfigureTest(CYCLE_FINDER_L1TEST ${CMAKE_CURRENT_SOURCE_DIR}/level1/l1_cycle_finder.cu) - -# ################################################################################################## -# - L2 tests for full regression check -------------------------------------------------------------------------- -ConfigureTest(ROUTING_L2TEST ${CMAKE_CURRENT_SOURCE_DIR}/l2_routing_test.cu) # ##################################################################################################### # # - ${CMAKE_CURRENT_SOURCE_DIR} unit tests ---------------------------------------------------------------------------- ConfigureTest(ROUTING_UNIT_TEST diff --git a/cpp/tests/routing/l2_routing_test.cu b/cpp/tests/routing/l2_routing_test.cu deleted file mode 100644 index fd1bf06c5e..0000000000 --- a/cpp/tests/routing/l2_routing_test.cu +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION & AFFILIATES. All rights - * reserved. SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "routing_test.cuh" - -namespace cuopt { -namespace routing { -namespace test { - -TEST_P(regression_routing_test_cvrp_t, CVRP) { test_cvrp(); } -TEST_P(regression_routing_test_25_t, CVRPTW_25) { test_cvrptw(); } -TEST_P(regression_routing_test_50_t, CVRPTW_50) { test_cvrptw(); } -TEST_P(regression_routing_test_100_t, CVRPTW_100) { test_cvrptw(); } -TEST_P(float_regression_test_t, CVRPTW) { test_cvrptw(); } -TEST_P(float_pickup_regression_test_t, CVRPTW) { test_cvrptw(); } - -INSTANTIATE_TEST_SUITE_P( - l2_cvrp, - regression_routing_test_cvrp_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/cvrp.txt")))); -INSTANTIATE_TEST_SUITE_P( - l2_25, - regression_routing_test_25_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/solomon_25.txt")))); -INSTANTIATE_TEST_SUITE_P( - l2_50, - regression_routing_test_50_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/solomon_50.txt")))); -INSTANTIATE_TEST_SUITE_P( - l2_100, - regression_routing_test_100_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/solomon_100.txt")))); -INSTANTIATE_TEST_SUITE_P( - l2_homberger, - float_regression_test_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/homberger.txt")))); -INSTANTIATE_TEST_SUITE_P( - l2_pdptw, - float_pickup_regression_test_t, - ::testing::ValuesIn(parse_tests(cuopt::test::read_tests("datasets/ref/l2_pickup.txt")))); -CUOPT_TEST_PROGRAM_MAIN() - -} // namespace test -} // namespace routing -} // namespace cuopt diff --git a/cpp/tests/routing/level1/l1_cycle_finder.cu b/cpp/tests/routing/level1/l1_cycle_finder.cu deleted file mode 100644 index bd57bc25ce..0000000000 --- a/cpp/tests/routing/level1/l1_cycle_finder.cu +++ /dev/null @@ -1,180 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights - * reserved. SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -namespace cuopt { -namespace routing { -namespace test { - -constexpr int n_sols = 1; - -template -class cycle_finder_test_t : public routing_test_t, - public ::testing::TestWithParam { - public: - cycle_finder_test_t() {} - void SetUp() override - { - auto param = GetParam(); - auto input = load_routing_file(param.routing_file, 10001); - - this->n_locations = input.n_locations; - this->n_vehicles = input.n_vehicles; - this->n_orders = this->n_locations; - this->x_h = input.x_h; - this->y_h = input.y_h; - this->demand_h = input.demand_h; - this->capacity_h = input.capacity_h; - this->earliest_time_h = input.earliest_time_h; - this->latest_time_h = input.latest_time_h; - this->service_time_h = input.service_time_h; - this->pickup_indices_h = input.pickup_indices_h; - this->delivery_indices_h = input.delivery_indices_h; - this->vehicle_types_h.assign(this->n_vehicles, 0); - this->populate_device_vectors(); - raft::copy(this->pickup_indices_d.data(), - this->pickup_indices_h.data(), - this->pickup_indices_h.size(), - this->stream_view_); - raft::copy(this->delivery_indices_d.data(), - this->delivery_indices_h.data(), - this->delivery_indices_h.size(), - this->stream_view_); - } - - bool check_cycle(detail::graph_t& graph, detail::ret_cycles_t& ret) - { - auto h_graph = graph.to_host(); - auto h_cycles = ret.to_host(); - if (!h_cycles.n_cycles) return true; - f_t cost = 0; - auto start = h_cycles.offsets[h_cycles.n_cycles - 1]; - auto end = h_cycles.offsets[h_cycles.n_cycles]; - std::deque tmp_cycle_path(h_cycles.paths.data() + start, h_cycles.paths.data() + end); - tmp_cycle_path.push_front(tmp_cycle_path.back()); - - for (size_t i = tmp_cycle_path.size() - 1; i > 0; --i) { - auto node = tmp_cycle_path[i]; - bool is_cycle = false; - auto row_id = h_graph.row_ids[node]; - auto start = h_graph.rows[row_id]; - auto end = h_graph.rows[row_id + 1]; - for (int col = start; col < end; ++col) { - int dst = h_graph.indices[col]; - f_t weight = h_graph.weights[col]; - if (dst == tmp_cycle_path[i - 1]) { - cost += weight; - is_cycle = true; - } - } - if (!is_cycle) return false; - } - return cost < -detail::EPSILON; - } - - void solve(data_model_view_t const& data_model, - ges_solver_t& ges_solver, - detail::local_search_t& local_search, - detail::solution_t& sol) - { - ges_solver.pool_allocator.sync_all_streams(); - this->hr_timer_.start("Local search"); - local_search.max_iterations = 1; - local_search.set_active_weights(detail::default_weights, 0.); - local_search.run_best_local_search(sol, false, false, true); - ges_solver.pool_allocator.sync_all_streams(); - this->handle_.sync_stream(); - this->hr_timer_.stop(); - auto routing_solution = ges_solver.get_ges_assignment(sol); - ASSERT_EQ(routing_solution.get_status(), cuopt::routing::solution_status_t::SUCCESS); - std::cout << "VN: " << routing_solution.get_vehicle_count() - << ", Cost: " << routing_solution.get_total_objective() << "\n"; - - // FIXME: With new intra operator we don't necessarily execute the cycle finder - // ASSERT_TRUE( - // check_cycle(local_search.move_candidates.graph, local_search.move_candidates.cycles)); - host_assignment_t h_routing_solution(routing_solution); - check_route(data_model, h_routing_solution); - this->check_time_windows(h_routing_solution, false); - this->check_capacity(h_routing_solution, this->demand_h, this->capacity_h, this->demand_d); - } - - void test_pdptw() - { - cuopt::routing::data_model_view_t data_model( - &this->handle_, this->n_locations, this->n_vehicles, this->n_orders); - data_model.add_cost_matrix(this->cost_matrix_d.data()); - if constexpr (REQUEST == request_t::PDP) { - data_model.set_pickup_delivery_pairs(this->pickup_indices_d.data(), - this->delivery_indices_d.data()); - } - data_model.add_capacity_dimension("weight", this->demand_d.data(), this->capacity_d.data()); - data_model.set_order_time_windows(this->earliest_time_d.data(), this->latest_time_d.data()); - data_model.set_order_service_times(this->service_time_d.data()); - - auto time_limit = 15.f; - - cuopt::routing::solver_settings_t solver_settings; - solver_settings.set_time_limit(time_limit); - - this->handle_.sync_stream(); - this->hr_timer_.start("Solve"); - ges_solver_t ges_solver(data_model, solver_settings, n_sols, time_limit); - auto [resource, index] = ges_solver.pool_allocator.resource_pool->acquire(); - const auto start_time = std::chrono::steady_clock::now(); - detail::solution_t sol{ - ges_solver.problem, 0, ges_solver.pool_allocator.sol_handles[0].get()}; - resource.ges.set_solution_ptr(&sol); - resource.ges.start_timer(start_time, time_limit); - resource.ges.route_minimizer_loop(); - sol.compute_cost(); - this->handle_.sync_stream(); - this->hr_timer_.stop(); - std::cout << "Cost before LS: " << sol.get_total_cost(detail::default_weights) << "\n"; - solve(data_model, ges_solver, resource.ls, sol); - ges_solver.pool_allocator.resource_pool->release(index); - this->hr_timer_.display(std::cout); - } -}; - -typedef cycle_finder_test_t float_cycle_finder_test_pdp; -typedef cycle_finder_test_t float_cycle_finder_test_vrp; -TEST_P(float_cycle_finder_test_pdp, CYCLE_FINDER_FLOAT_PDP) { test_pdptw(); } -INSTANTIATE_TEST_SUITE_P(float_test, - float_cycle_finder_test_pdp, - ::testing::Values(file_params("pdptw/LR2_10_2.pdptw"))); -TEST_P(float_cycle_finder_test_vrp, CYCLE_FINDER_FLOAT_VRP) { test_pdptw(); } -INSTANTIATE_TEST_SUITE_P(float_test, - float_cycle_finder_test_vrp, - ::testing::Values(file_params("cvrptw/R2_10_2.TXT"))); - -} // namespace test -} // namespace routing -} // namespace cuopt diff --git a/cpp/tests/routing/utilities/mg_utilities.hpp b/cpp/tests/routing/utilities/mg_utilities.hpp deleted file mode 100644 index e6fbb79de7..0000000000 --- a/cpp/tests/routing/utilities/mg_utilities.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION & AFFILIATES. All rights - * reserved. SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#pragma once - -#include -#include - -namespace cuopt { -namespace routing { -namespace test { - -template -input_t host_reduce_scalar(raft::comms::comms_t const& comm, - input_t local_val, - raft::comms::op_t op, - int root, - cudaStream_t stream) -{ - rmm::device_scalar local_scalar(local_val, stream); - rmm::device_scalar aggregate_scalar(0, stream); - comm.reduce(local_scalar.data(), aggregate_scalar.data(), 1, op, root, stream); - return aggregate_scalar.value(stream); -} - -} // namespace test -} // namespace routing -} // namespace cuopt