diff --git a/.env b/.env new file mode 100644 index 00000000..2ae96b2a --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +ARCHITECTURE=arm64v8/ +RUBY_VERSION=2.6 +ORTOOLS_VERSION=v7.8 # select from https://github.com/google/or-tools/releases diff --git a/.github/actions/build.sh b/.github/actions/build.sh index a51a4c67..4fa4437c 100755 --- a/.github/actions/build.sh +++ b/.github/actions/build.sh @@ -24,14 +24,20 @@ case $ORTOOLS_VERSION in export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.5/or-tools_debian-10_v7.5.7466.tar.gz" ;; 'v7.8') - export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.8/or-tools_debian-10_v7.8.7959.tar.gz" + export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.8/or-tools_debian-10_v7.8.7959.tar.gz" + ;; + 'v9.0') + export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v9.0/or-tools_debian-10_v9.0.9048.tar.gz" + ;; + 'v9.3') + export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v9.3/or-tools_amd64_debian-11_v9.3.10497.tar.gz" ;; *) echo "Unknown OR-Tools version" esac echo "Download asset at ${ORTOOLS_URL}" -docker build --build-arg ORTOOLS_URL=${ORTOOLS_URL} -f ./Dockerfile -t "${IMAGE_NAME}" . +docker build --build-arg RUBY_VERSION="2.6" --build-arg ORTOOLS_URL=${ORTOOLS_URL} -f ./Dockerfile -t "${IMAGE_NAME}" . docker run -d --name optimizer -t "${IMAGE_NAME}" docker exec -i optimizer bash -c "LD_LIBRARY_PATH=/srv/or-tools/lib/ /srv/optimizer-ortools/tsp_simple -time_limit_in_ms 500 -intermediate_solutions -instance_file '/srv/optimizer-ortools/data/test_ortools_single_route_with_route_order' -solution_file '/tmp/optimize-or-tools-output'" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 104d951c..f0ad753e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: types: [opened, synchronize, reopened] env: - ORTOOLS_VERSION: v7.8 + ORTOOLS_VERSION: v9.3 REGISTRY: ${{ secrets.REGISTRY }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }} diff --git a/Dockerfile b/Dockerfile index 7a00957a..7d74e2a8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,7 @@ -# 1.0.13 is the latest version containing bundler 2 required for optimizer-api -FROM phusion/passenger-ruby25:1.0.13 +ARG RUBY_VERSION +ARG ARCHITECTURE + +FROM ${ARCHITECTURE}ruby:${RUBY_VERSION} ARG ORTOOLS_URL=${ORTOOLS_URL} @@ -7,19 +9,6 @@ LABEL maintainer="Mapotempo " WORKDIR /srv/ -# Trick to install passenger-docker on Ruby 2.5. Othwerwise `apt-get update` fails with a -# certificate error. See following links for explanantion: -# https://issueexplorer.com/issue/phusion/passenger-docker/325 -# and -# https://issueexplorer.com/issue/phusion/passenger-docker/322 -# Basically, DST Root CA X3 certificates are expired on Setember 2021 and apt-get cannot validate -# with the old certificates and the certification correction is only done for Ruby 2.6+ on the -# passenger-docker repo because Ruby 2.5 is EOL. -RUN mv /etc/apt/sources.list.d /etc/apt/sources.list.d.bak -RUN apt update && apt install -y ca-certificates -RUN mv /etc/apt/sources.list.d.bak /etc/apt/sources.list.d -# The above trick can be removed after Ruby version is increased. - RUN apt-get update > /dev/null && \ apt-get -y install git wget pkg-config build-essential cmake autoconf libtool zlib1g-dev lsb-release > /dev/null diff --git a/Makefile b/Makefile index 658f31b8..db7b8531 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ OR_TOOLS_TOP=../or-tools -TUTORIAL=resources +TUTORIAL=./resources # -isystem prevents most of the warnings rooted in or-tools library appearing in our compilation -CFLAGS := -std=c++14 -isystem$(OR_TOOLS_TOP)/include +CFLAGS := -std=c++17 -isystem $(OR_TOOLS_TOP)/include # During development uncomment the next line to have debug checks and other verifications # DEVELOPMENT = true ifeq ($(DEVELOPMENT), true) CFLAGS := $(CFLAGS) -O0 -DDEBUG -ggdb3 -fsanitize=address -fkeep-inline-functions -fno-inline-small-functions + # CXX := ../callcatcher/build/scripts-3.6/callcatcher $(CXX) # comment out to check uncalled functions CXX := LSAN_OPTION=verbosity=1:log_threads=1 $(CXX) # adress sanitizer works only if the executable launched without gdb else CFLAGS := $(CFLAGS) -O3 -DNDEBUG @@ -44,11 +45,11 @@ tsp_simple.o: tsp_simple.cc ortools_vrp.pb.h \ tsptw_data_dt.h \ limits.h \ values.h - $(CXX) $(CFLAGS) -I $(TUTORIAL) -c ./tsp_simple.cc -o tsp_simple.o + $(CXX) $(CFLAGS) -isystem$(TUTORIAL) -c ./tsp_simple.cc -o tsp_simple.o tsp_simple: $(ROUTING_DEPS) tsp_simple.o ortools_vrp.pb.o ortools_result.pb.o $(OR_TOOLS_TOP)/lib/libortools.so - $(CXX) $(CFLAGS) -fwhole-program tsp_simple.o ortools_vrp.pb.o ortools_result.pb.o $(OR_TOOLS_LD_FLAGS) \ - -L $(OR_TOOLS_TOP)/lib -Wl,-rpath $(OR_TOOLS_TOP)/lib -lortools -lprotobuf -lglog -lgflags -labsl_raw_hash_set -labsl_time -labsl_time_zone \ + $(CXX) $(CFLAGS) -g tsp_simple.o ortools_vrp.pb.o ortools_result.pb.o $(OR_TOOLS_LD_FLAGS) \ + -L $(OR_TOOLS_TOP)/lib -Wl,-rpath $(OR_TOOLS_TOP)/lib -lortools \ -o tsp_simple local_clean: diff --git a/README.md b/README.md index 22ff134a..7d1d42a4 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ optimizer-ortools Compute an optimized solution to the Vehicle Routing Problem with Time Windows and various constraints using OR-Tools. This wrapper is designed to be called through [Optimizer-API](https://github.com/Mapotempo/optimizer-api) and has been tested on Ubuntu 17.10, 18.04; Linux Mint 18; Debian 8, 10. -The current implementation has been tested with the version 7.8 of OR-Tools +The current implementation has been tested with the version 9.3 of OR-Tools Installation ============ @@ -14,9 +14,9 @@ Installation Require OR-Tools for the C++ part. Fetch source code at [https://github.com/google/or-tools](https://github.com/google/or-tools). -Download OR-Tools here : https://github.com/google/or-tools/releases/tag/v7.8 +Download OR-Tools here : https://github.com/google/or-tools/releases/tag/v9.3 -- Recommended Asset : [or-tools_debian-10_v7.8.7959.tar.gz](https://github.com/google/or-tools/releases/download/v7.8/or-tools_debian-10_v7.8.7959.tar.gz) +- Recommended Asset : [or-tools_debian-10_v9.0.9048.tar.gz](https://github.com/google/or-tools/releases/download/v9.3/or-tools_debian-10_v9.0.9048.tar.gz) More details on [Google Optimization Tools Documentation](https://developers.google.com/optimization/introduction/installing) diff --git a/ci-utils/README.md b/ci-utils/README.md index 00601ca5..a655ac19 100644 --- a/ci-utils/README.md +++ b/ci-utils/README.md @@ -11,7 +11,7 @@ Optimizer requires the two following images that must be manually built. ### Ortools ``` -export ORTOOLS_VERSION=v7.8 +export ORTOOLS_VERSION=v9.3 cd ./docker/ortools docker build --build-arg ORTOOLS_VERSION=${ORTOOLS_VERSION} \ -f ./Dockerfile -t ${REGISTRY}mapotempo/ortools:${ORTOOLS_VERSION} . @@ -19,8 +19,8 @@ docker build --build-arg ORTOOLS_VERSION=${ORTOOLS_VERSION} \ ## Build ``` -export ORTOOLS_VERSION=v7.8 +export ORTOOLS_VERSION=v9.3 export BRANCH=${BRANCH:-ce} docker build --build-arg ORTOOLS_VERSION=${ORTOOLS_VERSION} \ -f ./Dockerfile -t ${REGISTRY}mapotempo-${BRANCH}/optimizer-ortools:latest . -``` \ No newline at end of file +``` diff --git a/ci-utils/ortools/asset_url.sh b/ci-utils/ortools/asset_url.sh deleted file mode 100755 index e8a27959..00000000 --- a/ci-utils/ortools/asset_url.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -case $ORTOOLS_VERSION in - 'v7.1') - export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.1/or-tools_debian-9_v7.1.6720.tar.gz" - ;; - 'v7.4') - export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.4/or-tools_debian-9_v7.4.7247.tar.gz" - ;; - 'v7.5') - export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.5/or-tools_debian-10_v7.5.7466.tar.gz" - ;; - 'v7.8') - export ORTOOLS_URL="https://github.com/google/or-tools/releases/download/v7.8/or-tools_debian-10_v7.8.7959.tar.gz" - ;; - *) - echo "Unknown OR-Tools version" -esac - diff --git a/data/test_ortools_single_route_with_route_order b/data/test_ortools_single_route_with_route_order index 2d7596c0..6a027c90 100644 Binary files a/data/test_ortools_single_route_with_route_order and b/data/test_ortools_single_route_with_route_order differ diff --git a/data/test_with_cluster b/data/test_with_cluster new file mode 100644 index 00000000..792ec4a4 Binary files /dev/null and b/data/test_with_cluster differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..2b16737a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3.7' +x-app-args: &app-args + ARCHITECTURE: ${ARCHITECTURE} + RUBY_VERSION: ${RUBY_VERSION} + ORTOOLS_VERSION: ${ORTOOLS_VERSION} + +x-app: &default-app + volumes: + - ./:/srv/app/ + env_file: + - ./.env + +services: + main: + <<: *default-app + build: + args: + <<: *app-args + context: . + dockerfile: Dockerfile + image: dev.example.com/mapotempo/optimizer-ortools + tty: true diff --git a/limits.h b/limits.h index 31a56487..70a1f442 100644 --- a/limits.h +++ b/limits.h @@ -19,32 +19,32 @@ #include "ortools/constraint_solver/constraint_solver.h" -DEFINE_int64(time_limit_in_ms, 0, "Time limit in ms, no option means no limit."); -DEFINE_int64(no_solution_improvement_limit, -1, "Iterations whitout improvement"); -DEFINE_int64(minimum_duration, -1, "Initial time whitout improvement in ms"); -DEFINE_int64(init_duration, -1, "Maximum duration to find a first solution"); -DEFINE_int64(time_out_multiplier, 2, "Multiplier for the nexts time out"); -DEFINE_int64(vehicle_limit, 0, "Define the maximum number of vehicle"); -DEFINE_int64(solver_parameter, -1, "Force a particular behavior"); -DEFINE_bool(only_first_solution, false, "Compute only the first solution"); -DEFINE_bool(verification_only, false, "Only verify the suplied initial solution"); -DEFINE_bool(balance, false, "Route balancing"); -DEFINE_bool(nearby, false, "Short segment priority"); +ABSL_FLAG(int64_t, time_limit_in_ms, 0, "Time limit in ms, no option means no limit."); +ABSL_FLAG(int64_t, no_solution_improvement_limit, -1, "Iterations whitout improvement"); +ABSL_FLAG(int64_t, minimum_duration, -1, "Initial time whitout improvement in ms"); +ABSL_FLAG(int64_t, init_duration, -1, "Maximum duration to find a first solution"); +ABSL_FLAG(int64_t, time_out_multiplier, 2, "Multiplier for the nexts time out"); +ABSL_FLAG(int64_t, vehicle_limit, 0, "Define the maximum number of vehicle"); +ABSL_FLAG(int64_t, solver_parameter, -1, "Force a particular behavior"); +ABSL_FLAG(bool, only_first_solution, false, "Compute only the first solution"); +ABSL_FLAG(bool, verification_only, false, "Only verify the suplied initial solution"); +ABSL_FLAG(bool, balance, false, "Route balancing"); +ABSL_FLAG(bool, nearby, false, "Short segment priority"); #ifdef DEBUG -DEFINE_bool(debug, true, "debug display"); +ABSL_FLAG(bool, debug, true, "debug display"); #else -DEFINE_bool(debug, false, "debug display"); +ABSL_FLAG(bool, debug, false, "debug display"); #endif -DEFINE_bool(intermediate_solutions, false, "display intermediate solutions"); -DEFINE_string(routing_search_parameters, - "", /* An example of how we can override the default settings */ - // "first_solution_strategy:ALL_UNPERFORMED" - // "local_search_operators {" - // " use_path_lns:BOOL_TRUE" - // " use_inactive_lns:BOOL_TRUE" - // "}", - "Text proto RoutingSearchParameters (possibly partial) that will " - "override the DefaultRoutingSearchParameters()"); +ABSL_FLAG(bool, intermediate_solutions, false, "display intermediate solutions"); +ABSL_FLAG(std::string, routing_search_parameters, + "", /* An example of how we can override the default settings */ + // "first_solution_strategy:ALL_UNPERFORMED" + // "local_search_operators {" + // " use_path_lns:BOOL_TRUE" + // " use_inactive_lns:BOOL_TRUE" + // "}", + "Text proto RoutingSearchParameters (possibly partial) that will " + "override the DefaultRoutingSearchParameters()"); const char* kDistance = "distance"; const char* kDistanceBalance = "distance_balance"; @@ -69,8 +69,9 @@ namespace { class NoImprovementLimit : public SearchLimit { public: NoImprovementLimit(Solver* const solver, IntVar* const objective_var, - int64 solution_nbr_tolerance, double time_out, int64 time_out_coef, - int64 init_duration, const bool minimize = true) + int64_t solution_nbr_tolerance, double time_out, + int64_t time_out_coef, int64_t init_duration, + const bool minimize = true) : SearchLimit(solver) , solver_(solver) , start_time_(absl::GetCurrentTimeNanos()) @@ -173,17 +174,17 @@ class NoImprovementLimit : public SearchLimit { private: Solver* const solver_; - int64 best_result_; + int64_t best_result_; double start_time_; - int64 solution_nbr_tolerance_; + int64_t solution_nbr_tolerance_; bool minimize_; bool limit_reached_; bool first_solution_; double initial_time_out_; double time_out_; - int64 time_out_coef_; - int64 init_duration_; - int64 nbr_solutions_with_no_better_obj_; + int64_t time_out_coef_; + int64_t init_duration_; + int64_t nbr_solutions_with_no_better_obj_; std::unique_ptr prototype_; }; @@ -191,8 +192,8 @@ class NoImprovementLimit : public SearchLimit { NoImprovementLimit* MakeNoImprovementLimit(Solver* const solver, IntVar* const objective_var, - const int64 solution_nbr_tolerance, const double time_out, - const int64 time_out_coef, const int64 init_duration, + const int64_t solution_nbr_tolerance, const double time_out, + const int64_t time_out_coef, const int64_t init_duration, const bool minimize = true) { return solver->RevAlloc(new NoImprovementLimit(solver, objective_var, solution_nbr_tolerance, time_out, @@ -205,7 +206,7 @@ namespace { class LoggerMonitor : public SearchMonitor { public: LoggerMonitor(const TSPTWDataDT& data, RoutingModel* routing, - RoutingIndexManager* manager, int64 min_start, int64 size_matrix, + RoutingIndexManager* manager, int64_t size_matrix, bool debug, bool intermediate, ortools_result::Result* result, std::vector> stored_rests, std::string filename, const bool minimize = true) @@ -215,7 +216,6 @@ class LoggerMonitor : public SearchMonitor { , manager_(manager) , solver_(routing->solver()) , start_time_(absl::GetCurrentTimeNanos()) - , min_start_(min_start) , size_matrix_(size_matrix) , minimize_(minimize) , limit_reached_(false) @@ -278,11 +278,11 @@ class LoggerMonitor : public SearchMonitor { const std::string& dimension_name) const { if (routing_->GetMutableDimension(dimension_name) == nullptr) return 0; - int64 start_time = + int64_t start_time = routing_->GetMutableDimension(dimension_name)->CumulVar(index)->Min(); - int64 upper_bound = + int64_t upper_bound = routing_->GetMutableDimension(dimension_name)->GetCumulVarSoftUpperBound(index); - int64 excess = std::max(start_time - upper_bound, (int64)0); + int64_t excess = std::max(start_time - upper_bound, (int64_t)0); return (double)excess * routing_->GetMutableDimension(dimension_name) ->GetCumulVarSoftUpperBoundCoefficient(index) / @@ -315,15 +315,16 @@ class LoggerMonitor : public SearchMonitor { std::vector rests = stored_rests_[route_nbr]; ortools_result::Route* route = result_->add_routes(); int previous_index = -1; - int64 previous_start_time = 0; - int64 lateness_cost = 0; - int64 overload_cost = 0; + int64_t previous_start_time = 0; + int64_t lateness_cost = 0; + int64_t overload_cost = 0; bool vehicle_used = false; - for (int64 index = routing_->Start(route_nbr); !routing_->IsEnd(index); - index = routing_->NextVar(index)->Value()) { + int64_t earliest_start = data_.EarliestStart(); + for (int64_t index = routing_->Start(route_nbr); !routing_->IsEnd(index); + index = routing_->NextVar(index)->Value()) { for (std::vector::iterator it = rests.begin(); it != rests.end();) { - const int64 rest_start_time = (*it)->StartMin(); + const int64_t rest_start_time = (*it)->StartMin(); if ((*it)->StartMin() == (*it)->StartMax() && previous_index != -1 && rest_start_time >= previous_start_time && rest_start_time <= @@ -338,7 +339,7 @@ class LoggerMonitor : public SearchMonitor { ortools_result::Activity* rest = route->add_activities(); rest->set_type("break"); rest->set_id(parsed_name[1]); - rest->set_start_time(rest_start_time); + rest->set_start_time(rest_start_time + earliest_start); it = rests.erase(it); } else { ++it; @@ -348,12 +349,12 @@ class LoggerMonitor : public SearchMonitor { ortools_result::Activity* activity = route->add_activities(); RoutingIndexManager::NodeIndex nodeIndex = manager_->IndexToNode(index); activity->set_index(data_.ProblemIndex(nodeIndex)); - const int64 start_time = + const int64_t start_time = routing_->GetMutableDimension(kTime)->CumulVar(index)->Min(); - activity->set_start_time(start_time); - const int64 upper_bound = + activity->set_start_time(start_time + earliest_start); + const int64_t upper_bound = routing_->GetMutableDimension(kTime)->GetCumulVarSoftUpperBound(index); - const int64 lateness = std::max(start_time - upper_bound, 0); + const int64_t lateness = std::max(start_time - upper_bound, 0); activity->set_lateness(lateness); lateness_cost += GetUpperBoundCostForDimension(index, kTime); activity->set_current_distance( @@ -384,7 +385,7 @@ class LoggerMonitor : public SearchMonitor { for (std::vector::iterator it = rests.begin(); it != rests.end(); ++it) { - const int64 rest_start_time = (*it)->StartMin(); + const int64_t rest_start_time = (*it)->StartMin(); if ((*it)->StartMin() == (*it)->StartMax()) { ortools_result::Activity* rest = route->add_activities(); std::stringstream ss((*it)->name()); @@ -402,15 +403,15 @@ class LoggerMonitor : public SearchMonitor { ortools_result::Activity* end_activity = route->add_activities(); RoutingIndexManager::NodeIndex nodeIndex = manager_->IndexToNode(routing_->End(route_nbr)); - const int64 end_index = routing_->End(route_nbr); + const int64_t end_index = routing_->End(route_nbr); end_activity->set_index(data_.ProblemIndex(nodeIndex)); - const int64 start_time = + const int64_t start_time = routing_->GetMutableDimension(kTime)->CumulVar(end_index)->Min(); - end_activity->set_start_time(start_time); - const int64 upper_bound = + end_activity->set_start_time(start_time + earliest_start); + const int64_t upper_bound = routing_->GetMutableDimension(kTime)->GetCumulVarSoftUpperBound(end_index); - const int64 lateness = std::max(start_time - upper_bound, 0); + const int64_t lateness = std::max(start_time - upper_bound, 0); end_activity->set_lateness(lateness); lateness_cost += GetUpperBoundCostForDimension(end_index, kTime); end_activity->set_current_distance(routing_->GetMutableDimension(kDistance) @@ -559,9 +560,8 @@ class LoggerMonitor : public SearchMonitor { } if (debug_ && new_best) { - std::cout << "min start : " << min_start_ << std::endl; for (RoutingIndexManager::NodeIndex i(0); i < data_.SizeMatrix() - 1; ++i) { - const int64 index = manager_->NodeToIndex(i); + const int64_t index = manager_->NodeToIndex(i); const IntVar* cumul_var = routing_->GetMutableDimension(kTime)->CumulVar(index); const IntVar* transit_var = routing_->GetMutableDimension(kTime)->TransitVar(index); @@ -571,8 +571,8 @@ class LoggerMonitor : public SearchMonitor { slack_var->Bound()) { std::cout << "Node " << i << " index " << index << " [" << vehicle_var->Value() << "] |"; - std::cout << (cumul_var->Value() - min_start_) << " + " << transit_var->Value() - << " -> " << slack_var->Value() << std::endl; + std::cout << (cumul_var->Value()) << " + " << transit_var->Value() << " -> " + << slack_var->Value() << std::endl; } } std::cout << "-----------" << std::endl; @@ -613,9 +613,9 @@ class LoggerMonitor : public SearchMonitor { // Allocates a clone of the limit virtual SearchMonitor* MakeClone() const { // we don't to copy the variables - return solver_->RevAlloc( - new LoggerMonitor(data_, routing_, manager_, min_start_, size_matrix_, debug_, - intermediate_, result_, stored_rests_, filename_, minimize_)); + return solver_->RevAlloc(new LoggerMonitor(data_, routing_, manager_, size_matrix_, + debug_, intermediate_, result_, + stored_rests_, filename_, minimize_)); } virtual std::string DebugString() const { @@ -639,17 +639,16 @@ class LoggerMonitor : public SearchMonitor { RoutingModel* routing_; RoutingIndexManager* manager_; Solver* const solver_; - int64 best_result_; + int64_t best_result_; double cleaned_cost_; double start_time_; - int64 min_start_; - int64 size_matrix_; + int64_t size_matrix_; bool minimize_; bool limit_reached_; bool debug_; bool intermediate_; - int64 pow_; - int64 iteration_counter_; + int64_t pow_; + int64_t iteration_counter_; std::unique_ptr prototype_; std::string filename_; ortools_result::Result* result_; @@ -659,14 +658,14 @@ class LoggerMonitor : public SearchMonitor { } // namespace LoggerMonitor* MakeLoggerMonitor(const TSPTWDataDT& data, RoutingModel* routing, - RoutingIndexManager* manager, int64 min_start, - int64 size_matrix, bool debug, bool intermediate, + RoutingIndexManager* manager, int64_t size_matrix, + bool debug, bool intermediate, ortools_result::Result* result, std::vector> stored_rests, std::string filename, const bool minimize = true) { return routing->solver()->RevAlloc( - new LoggerMonitor(data, routing, manager, min_start, size_matrix, debug, - intermediate, result, stored_rests, filename, minimize)); + new LoggerMonitor(data, routing, manager, size_matrix, debug, intermediate, result, + stored_rests, filename, minimize)); } } // namespace operations_research diff --git a/ortools_vrp.proto b/ortools_vrp.proto index 1432f53c..576f6e2e 100644 --- a/ortools_vrp.proto +++ b/ortools_vrp.proto @@ -4,6 +4,7 @@ package ortools_vrp; option optimize_for = SPEED; message Matrix { + uint32 size = 1; repeated float time = 2 [ packed = true ]; repeated float distance = 3 [ packed = true ]; repeated float value = 4 [ packed = true ]; @@ -30,6 +31,8 @@ message Service { float exclusion_cost = 13; repeated bool refill_quantities = 14; uint32 problem_index = 15; + string point_id = 16; + uint32 alternative_index = 17; } message Rest { @@ -75,6 +78,7 @@ message Vehicle { uint32 additional_setup = 26; bool free_approach = 27; bool free_return = 28; + string start_point_id = 29; } message Relation { diff --git a/ortools_vrp_pb.rb b/ortools_vrp_pb.rb index ad69e8e8..9dc83a64 100644 --- a/ortools_vrp_pb.rb +++ b/ortools_vrp_pb.rb @@ -6,6 +6,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do add_file("ortools_vrp.proto", :syntax => :proto3) do add_message "ortools_vrp.Matrix" do + optional :size, :uint32, 1 repeated :time, :float, 2 repeated :distance, :float, 3 repeated :value, :float, 4 @@ -30,6 +31,8 @@ optional :exclusion_cost, :float, 13 repeated :refill_quantities, :bool, 14 optional :problem_index, :uint32, 15 + optional :point_id, :string, 16 + optional :alternative_index, :uint32, 17 end add_message "ortools_vrp.Rest" do optional :time_window, :message, 1, "ortools_vrp.TimeWindow" @@ -72,6 +75,7 @@ optional :additional_setup, :uint32, 26 optional :free_approach, :bool, 27 optional :free_return, :bool, 28 + optional :start_point_id, :string, 29 end add_message "ortools_vrp.Relation" do optional :type, :string, 1 diff --git a/resources/common/constants.h b/resources/common/constants.h index 108b02b8..4b829a4a 100644 --- a/resources/common/constants.h +++ b/resources/common/constants.h @@ -19,9 +19,9 @@ namespace operations_research { -const static int64 kPostiveInfinityInt64 = std::numeric_limits::max(); +const static int64_t kPostiveInfinityInt64 = std::numeric_limits::max(); + - } // namespace operations_research #endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_CONSTANTS_H \ No newline at end of file diff --git a/resources/routing_common/routing_common.h b/resources/routing_common/routing_common.h index e7688bf8..df1a91b3 100644 --- a/resources/routing_common/routing_common.h +++ b/resources/routing_common/routing_common.h @@ -23,7 +23,6 @@ #include #include -#include "ortools/base/random.h" #include "ortools/constraint_solver/routing.h" #include "routing_common/routing_common_flags.h" @@ -51,18 +50,18 @@ struct Point { // Distances/costs can be symetric or not. class CompleteGraphArcCost { public: - explicit CompleteGraphArcCost(int32 size = 0): size_(size), is_created_(false), is_instanciated_(false), is_symmetric_(false), + explicit CompleteGraphArcCost(int32_t size = 0): size_(size), is_created_(false), is_instanciated_(false), is_symmetric_(false), min_cost_(kPostiveInfinityInt64), max_cost_(-1) { if (size_ > 0) { CreateMatrix(size_); } } - int32 Size() const { + int32_t Size() const { return size_; } - void Create(int32 size) { + void Create(int32_t size) { CHECK(!IsCreated()) << "Matrix already created!"; size_ = size; CreateMatrix(size); @@ -83,22 +82,22 @@ class CompleteGraphArcCost { ComputeIsSymmetric(); } - int64 Cost(RoutingIndexManager::NodeIndex from, + int64_t Cost(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const { return matrix_.get()[MatrixIndex(from, to)]; } - int64& Cost(RoutingIndexManager::NodeIndex from, + int64_t& Cost(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) { return matrix_.get()[MatrixIndex(from, to)]; } - int64 MaxCost() const { + int64_t MaxCost() const { CHECK(IsInstanciated()) << "Instance is not instanciated!"; return max_cost_; } - int64 MinCost() const { + int64_t MinCost() const { CHECK(IsInstanciated()) << "Instance is not instanciated!"; return min_cost_; } @@ -112,16 +111,16 @@ class CompleteGraphArcCost { void Print(std::ostream & out, const bool label = false, const int width = absl::GetFlag(FLAGS_width_size)) const; private: - int64 MatrixIndex(RoutingIndexManager::NodeIndex from, + int64_t MatrixIndex(RoutingIndexManager::NodeIndex from, RoutingIndexManager::NodeIndex to) const { return (from * size_ + to).value(); } void CreateMatrix(const int size) { CHECK_GT(size, 2) << "Size for matrix non consistent."; - int64 * p_array = nullptr; + int64_t * p_array = nullptr; try { - p_array = new int64 [size_ * size_]; + p_array = new int64_t [size_ * size_]; } catch (std::bad_alloc & e) { p_array = nullptr; LOG(FATAL) << "Problems allocating ressource. Try with a smaller size."; @@ -131,7 +130,7 @@ class CompleteGraphArcCost { is_created_ = true; } - void UpdateExtremeDistance(int64 dist) { + void UpdateExtremeDistance(int64_t dist) { if (min_cost_ > dist) { min_cost_ = dist;} if (max_cost_ < dist) { max_cost_ = dist;} } @@ -161,17 +160,17 @@ class CompleteGraphArcCost { return true; } - int32 size_; - //scoped_array matrix_; - std::shared_ptr matrix_; + int32_t size_; + //scoped_array matrix_; + std::shared_ptr matrix_; bool is_created_; bool is_instanciated_; bool is_symmetric_; - int64 min_cost_; - int64 max_cost_; + int64_t min_cost_; + int64_t max_cost_; }; void CompleteGraphArcCost::Print(std::ostream& out, const bool label, const int width) const { @@ -230,4 +229,4 @@ struct BoundingBox { } // namespace operations_research -#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H \ No newline at end of file +#endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_H diff --git a/resources/routing_common/routing_common_flags.h b/resources/routing_common/routing_common_flags.h index 17100fdc..dc1371b6 100644 --- a/resources/routing_common/routing_common_flags.h +++ b/resources/routing_common/routing_common_flags.h @@ -21,38 +21,38 @@ #include "common/constants.h" -DEFINE_int32(instance_size, 10, "Number of nodes, including the depot."); -DEFINE_string(instance_name, "Dummy instance", "Instance name."); +ABSL_FLAG(int, instance_size, 10, "Number of nodes, including the depot."); +ABSL_FLAG(std::string, instance_name, "Dummy instance", "Instance name."); -DEFINE_int32(instance_depot, 0, "Depot for instance."); +ABSL_FLAG(int, instance_depot, 0, "Depot for instance."); -DEFINE_string(instance_file, "", "TSPLIB instance file."); -DEFINE_string(solution_file, "", "TSPLIB solution file."); +ABSL_FLAG(std::string, instance_file, "", "TSPLIB instance file."); +ABSL_FLAG(std::string, solution_file, "", "TSPLIB solution file."); -DEFINE_string(distance_file, "", "TSP matrix distance file."); +ABSL_FLAG(std::string, distance_file, "", "TSP matrix distance file."); -DEFINE_int32(edge_min, 1, "Minimum edge value."); -DEFINE_int32(edge_max, 100, "Maximum edge value."); +ABSL_FLAG(int, edge_min, 1, "Minimum edge value."); +ABSL_FLAG(int, edge_max, 100, "Maximum edge value."); -DEFINE_int32(instance_edges_percent, 20, "Percent of edges in the graph."); +ABSL_FLAG(int, instance_edges_percent, 20, "Percent of edges in the graph."); -DEFINE_int32(x_max, 100, "Maximum x coordinate."); -DEFINE_int32(y_max, 100, "Maximum y coordinate."); +ABSL_FLAG(int, x_max, 100, "Maximum x coordinate."); +ABSL_FLAG(int, y_max, 100, "Maximum y coordinate."); -DEFINE_int32(width_size, 6, "Width size of fields in output."); +ABSL_FLAG(int, width_size, 6, "Width size of fields in output."); -DEFINE_int32(epix_width, 10, "Width of the pictures in cm."); -DEFINE_int32(epix_height, 10, "Height of the pictures in cm."); +ABSL_FLAG(int, epix_width, 10, "Width of the pictures in cm."); +ABSL_FLAG(int, epix_height, 10, "Height of the pictures in cm."); -DEFINE_double(epix_radius, 0.3, "Radius of circles."); +ABSL_FLAG(double, epix_radius, 0.3, "Radius of circles."); -DEFINE_bool(epix_node_labels, false, "Print node labels?"); +ABSL_FLAG(bool, epix_node_labels, false, "Print node labels?"); -DEFINE_int32(percentage_forbidden_arcs_max, 94, "Maximum percentage of arcs to forbid."); -DEFINE_int64(M, operations_research::kPostiveInfinityInt64, "Big m value to represent infinity."); +ABSL_FLAG(int, percentage_forbidden_arcs_max, 94, "Maximum percentage of arcs to forbid."); +ABSL_FLAG(int64_t, M, operations_research::kPostiveInfinityInt64, "Big m value to represent infinity."); #endif // OR_TOOLS_TUTORIALS_CPLUSPLUS_ROUTING_COMMON_FLAGS_H \ No newline at end of file diff --git a/tsp_simple.cc b/tsp_simple.cc index 90e893c7..e798ba40 100644 --- a/tsp_simple.cc +++ b/tsp_simple.cc @@ -41,7 +41,7 @@ namespace operations_research { -bool CheckOverflow(const int64 a, const int64 b) { +bool CheckOverflow(const int64_t a, const int64_t b) { if (a > std::pow(2, 52) / b) return true; return false; @@ -67,11 +67,11 @@ double GetUpperBoundCostForDimension(const RoutingModel& routing, const std::string& dimension_name) { if (routing.GetMutableDimension(dimension_name) == nullptr) return 0; - const int64 start_time = + const int64_t start_time = solution->Min(routing.GetMutableDimension(dimension_name)->CumulVar(index)); - const int64 upper_bound = + const int64_t upper_bound = routing.GetMutableDimension(dimension_name)->GetCumulVarSoftUpperBound(index); - const int64 excess = std::max(start_time - upper_bound, (int64)0); + const int64_t excess = std::max(start_time - upper_bound, (int64_t)0); return excess * routing.GetMutableDimension(dimension_name) ->GetCumulVarSoftUpperBoundCoefficient(index) / @@ -80,55 +80,67 @@ double GetUpperBoundCostForDimension(const RoutingModel& routing, void MissionsBuilder(const TSPTWDataDT& data, RoutingModel& routing, RoutingValues& routing_values, RoutingIndexManager& manager, - Assignment* assignment, const int64 size, const int64 min_start) { + Assignment* assignment, const int64_t size, + const bool free_approach_return) { + Solver* solver = routing.solver(); const int size_vehicles = data.Vehicles().size(); // const int size_matrix = data.SizeMatrix(); const int size_problem = data.SizeProblem(); - const int64 max_time = - (2 * data.MaxTime() + data.MaxServiceTime() + 1) * data.MaxTimeCost(); - const int64 max_distance = (2 * data.MaxDistance() + 1) * data.MaxDistanceCost(); - const int64 max_value = (2 * data.MaxValue() + 1) * data.MaxValueCost(); + const int64_t max_time = + (2 * data.MaxTime() + data.MaxServiceTime()) * data.MaxTimeCost(); + const int64_t max_distance = 2 * data.MaxDistance() * data.MaxDistanceCost(); + const int64_t max_value = 2 * data.MaxValue() * data.MaxValueCost(); bool overflow_danger = CheckOverflow(max_time + max_distance + max_value, size_vehicles); - int64 data_verif = (max_time + max_distance + max_value) * size_vehicles; + int64_t data_verif = (max_time + max_distance + max_value) * size_vehicles; overflow_danger = overflow_danger || CheckOverflow(data_verif, std::pow(2, 4) * size); data_verif = data_verif * std::pow(2, 4) * size; RoutingIndexManager::NodeIndex i(0); - uint32 tw_index = 0; - int64 disjunction_cost = + int tw_index = 0; + int64_t disjunction_cost = !overflow_danger && !CheckOverflow(data_verif, size) ? data_verif : std::pow(2, 52); - std::vector all_vehicle_indices; + std::vector all_vehicle_indices; for (int v = 0; v < size_vehicles; ++v) all_vehicle_indices.push_back(v); for (int activity = 0; activity <= size_problem; ++activity) { - std::vector* vect = new std::vector(); + std::vector* vect = new std::vector(); - const int64 priority = data.Priority(i); - const int64 exclusion_cost = data.ExclusionCost(i); + const int64_t priority = data.Priority(i); + const int64_t exclusion_cost = data.ExclusionCost(i); for (int alternative = 0; alternative < data.AlternativeSize(activity); ++alternative) { vect->push_back(manager.NodeToIndex(i)); - const int64 index = manager.NodeToIndex(i); - const std::vector& ready = data.ReadyTime(i); - const std::vector& due = data.DueTime(i); - const std::vector& maximum_lateness = data.MaximumLateness(i); - const int64 initial_value = routing_values.NodeValues(i).initial_time_value; - - IntVar* cumul_var = routing.GetMutableDimension(kTime)->CumulVar(index); - const int64 late_multiplier = data.LateMultiplier(i); + const int64_t index = manager.NodeToIndex(i); + const std::vector& ready = data.ReadyTime(i); + const std::vector& due = data.DueTime(i); + const std::vector& maximum_lateness = data.MaximumLateness(i); + const int64_t initial_value = routing_values.NodeValues(i).initial_time_value; + + // Timewindows should apply both on kTime and kFakeTime Dimensions.kTime both + // compute the true timings of activities and the time cost kFakeTime allows to + // compute the time cost of the route when there is an free_approach or free_return + // dimension. But it requires true timings to consider correctly waiting times. + // Lateness could only apply on true timings, which means these contraints should + // only be applied on kTime dimension. Dimensions kNoWait and kFakeNoWait doesn't + // need time windows because it expects no waiting times + IntVar* cumul_var = routing.GetMutableDimension(kTime)->CumulVar(index); + if (free_approach_return) + solver->AddConstraint(solver->MakeEquality( + routing.GetMutableDimension(kFakeTime)->CumulVar(index), cumul_var)); + + const int64_t late_multiplier = data.LateMultiplier(i); std::string service_id = data.ServiceId(i); if (ready.size() > 0 && (ready[0] > -CUSTOM_MAX_INT || due.back() < CUSTOM_MAX_INT)) { if (absl::GetFlag(FLAGS_debug)) { - std::cout << "Node " << i << " index " << index << " [" - << (ready[0] - min_start) << " : " << (due.back() - min_start) - << "]:" << data.ServiceTime(i) << std::endl; + std::cout << "Node " << i << " index " << index << " [" << (ready[0]) << " : " + << (due.back()) << "]:" << data.ServiceTime(i) << std::endl; } if (ready[0] > -CUSTOM_MAX_INT) { cumul_var->SetMin(ready[0]); @@ -160,20 +172,20 @@ void MissionsBuilder(const TSPTWDataDT& data, RoutingModel& routing, } // remove the "invalid" intervals between TWs - for (tw_index = 0; tw_index < due.size() - 1; ++tw_index) { + for (tw_index = 0; tw_index < (int)due.size() - 1; ++tw_index) { cumul_var->RemoveInterval(due[tw_index], ready[tw_index + 1] - 1); } } } - std::vector incompatible_vehicle_indices; - std::vector compatible_vehicles = data.VehicleIndices(i); + std::vector incompatible_vehicle_indices; + std::vector compatible_vehicles = data.VehicleIndices(i); std::set_difference(all_vehicle_indices.begin(), all_vehicle_indices.end(), compatible_vehicles.begin(), compatible_vehicles.end(), std::back_inserter(incompatible_vehicle_indices)); - for (int64 remove : incompatible_vehicle_indices) + for (int64_t remove : incompatible_vehicle_indices) routing.VehicleVar(index)->RemoveValue(remove); const std::vector& refill_quantities = data.RefillQuantities(i); @@ -208,11 +220,11 @@ void MissionsBuilder(const TSPTWDataDT& data, RoutingModel& routing, bool RouteBuilder(const TSPTWDataDT& data, RoutingModel& routing, RoutingIndexManager& manager, Assignment* assignment) { const int size_vehicles = data.Vehicles().size(); - std::vector> routes(size_vehicles); + std::vector> routes(size_vehicles); for (const TSPTWDataDT::Route& route : data.Routes()) { - int64 current_index; + int64_t current_index; IntVar* previous_var = NULL; - std::vector route_variable_indicies; + std::vector route_variable_indicies; if (route.vehicle_index >= 0) { previous_var = routing.NextVar(routing.Start(route.vehicle_index)); @@ -235,16 +247,19 @@ bool RouteBuilder(const TSPTWDataDT& data, RoutingModel& routing, if (previous_var != NULL) { assignment->SetValue(previous_var, routing.End(route.vehicle_index)); } - std::vector& actual_route = routes[route.vehicle_index]; + std::vector& actual_route = routes[route.vehicle_index]; actual_route.insert(actual_route.end(), route_variable_indicies.begin(), route_variable_indicies.end()); } } - return routing.RoutesToAssignment(routes, true, false, assignment); + + assignment = routing.ReadAssignmentFromRoutes(routes, true); + + return assignment == nullptr ? false : true; } std::vector> -RestBuilder(const TSPTWDataDT& data, RoutingModel& routing, const int64 horizon) { +RestBuilder(const TSPTWDataDT& data, RoutingModel& routing, const int64_t horizon) { Solver* solver = routing.solver(); const int size_vehicles = data.Vehicles().size(); std::vector> stored_rests; @@ -272,8 +287,8 @@ RestBuilder(const TSPTWDataDT& data, RoutingModel& routing, const int64 horizon) const TSPTWDataDT::Vehicle& vehicle = data.Vehicles(vehicle_index); for (const TSPTWDataDT::Rest& rest : vehicle.Rests()) { IntervalVar* const rest_interval = solver->MakeFixedDurationIntervalVar( - std::max(rest.ready_time, vehicle.time_start), - std::min(rest.due_time, vehicle.time_end - rest.duration), + std::max(rest.ready_time, vehicle.time_start), + std::min(rest.due_time, vehicle.time_end - rest.duration), rest.duration, // Currently only one timewindow false, absl::StrCat("Rest/", rest.rest_id, "/", vehicle_index)); rest_array.push_back(rest_interval); @@ -303,36 +318,32 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, Solver* solver = routing.solver(); // const int size_vehicles = data.Vehicles().size(); - Solver::IndexEvaluator1 vehicle_evaluator = [&data](int64 index) { + Solver::IndexEvaluator1 vehicle_evaluator = [&data](int64_t index) { return data.VehicleDay(index); }; - Solver::IndexEvaluator1 day_to_vehicle_evaluator = [&data](int64 index) { + Solver::IndexEvaluator1 day_to_vehicle_evaluator = [&data](int64_t index) { return data.DayIndexToVehicleIndex(index); }; - // Solver::IndexEvaluator1 alternative_vehicle_evaluator = [&data](int64 index) { - // return data.VehicleDayAlt(index); - // }; - std::vector next_vars; for (int i = 0; i < data.SizeMissions(); ++i) { next_vars.push_back(routing.NextVar(i)); } for (const TSPTWDataDT::Relation& relation : data.Relations()) { - int64 previous_index; - int64 current_index; - std::vector previous_indices; + int64_t previous_index; + int64_t current_index; + std::vector previous_indices; std::vector> pairs; - std::vector intermediate_values; - std::vector values; + std::vector intermediate_values; + std::vector values; - int32 alternative_size; + int32_t alternative_size; RoutingModel::DisjunctionIndex previous_disjunction_index; RoutingModel::DisjunctionIndex current_disjunction_index; - std::vector previous_vehicle_index_set; - std::vector current_vehicle_index_set; + std::vector previous_vehicle_index_set; + std::vector current_vehicle_index_set; std::vector previous_active_var_set; std::vector current_active_var_set; std::vector current_active_index_set; @@ -347,7 +358,7 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, case Sequence: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = + int32_t service_index = data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); alternative_size = data.AlternativeSize(service_index); @@ -356,7 +367,7 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, current_vehicle_var_set.clear(); current_active_next_var_set.clear(); current_active_index_set.clear(); - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { IntVar* const active_node = routing.ActiveVar(alternative_index); current_vehicle_var_set.push_back( @@ -426,7 +437,7 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, case Order: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = + int32_t service_index = data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); alternative_size = data.AlternativeSize(service_index); @@ -434,7 +445,7 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, current_vehicle_var_set.clear(); current_active_cumul_var_set.clear(); - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { IntVar* active_node = routing.ActiveVar(alternative_index); current_active_var_set.push_back(active_node); @@ -483,13 +494,13 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, case SameRoute: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = + int32_t service_index = data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); alternative_size = data.AlternativeSize(service_index); current_active_var_set.clear(); current_vehicle_var_set.clear(); - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { IntVar* const active_node = routing.ActiveVar(alternative_index); current_active_var_set.push_back(active_node); @@ -592,13 +603,13 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { current_index = data.IdIndex(relation.linked_ids[link_index]); current_disjunction_index = routing.GetDisjunctionIndices(current_index)[0]; - int32 service_index = + int32_t service_index = data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); alternative_size = data.AlternativeSize(service_index); current_active_cumul_var_set.clear(); current_vehicle_var_set.clear(); - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { current_vehicle_var_set.push_back(routing.VehicleVar(alternative_index)); IntVar* const active_node = routing.ActiveVar(alternative_index); @@ -710,16 +721,19 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, break; case NeverFirst: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { - current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = - data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); - alternative_size = data.AlternativeSize(service_index); - - for (int64 alternative_index = current_index; + current_index = data.AlternativeActivityIndex(relation.linked_ids[link_index]); + if (current_index >= 0) { + alternative_size = + data.AlternativeActivitySize(relation.linked_ids[link_index]); + } else { + current_index = data.IdIndex(relation.linked_ids[link_index]); + alternative_size = data.AlternativeSize(current_index); + } + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { for (std::size_t v = 0; v < data.Vehicles().size(); ++v) { - int64 start_index = routing.Start(v); - // int64 end_index = routing.End(v); + int64_t start_index = routing.Start(v); + // int64_t end_index = routing.End(v); IntVar* const next_var = routing.NextVar(start_index); next_var->RemoveValue(alternative_index); } @@ -732,16 +746,20 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, } for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { - current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = - data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); - alternative_size = data.AlternativeSize(service_index); + current_index = data.AlternativeActivityIndex(relation.linked_ids[link_index]); + if (current_index >= 0) { + alternative_size = + data.AlternativeActivitySize(relation.linked_ids[link_index]); + } else { + current_index = data.IdIndex(relation.linked_ids[link_index]); + alternative_size = data.AlternativeSize(current_index); + } - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { intermediate_values.push_back(alternative_index); - std::vector::iterator it = + std::vector::iterator it = std::find(values.begin(), values.end(), alternative_index); values.erase(it); } @@ -754,16 +772,20 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, break; case NeverLast: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { - current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = - data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); - alternative_size = data.AlternativeSize(service_index); + current_index = data.AlternativeActivityIndex(relation.linked_ids[link_index]); + if (current_index >= 0) { + alternative_size = + data.AlternativeActivitySize(relation.linked_ids[link_index]); + } else { + current_index = data.IdIndex(relation.linked_ids[link_index]); + alternative_size = data.AlternativeSize(current_index); + } - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { IntVar* const next_var = routing.NextVar(alternative_index); for (std::size_t v = 0; v < data.Vehicles().size(); ++v) { - int64 end_index = routing.End(v); + int64_t end_index = routing.End(v); next_var->RemoveValue(end_index); } } @@ -771,19 +793,23 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, break; case ForceLast: for (int link_index = 0; link_index < relation.linked_ids.size(); ++link_index) { - current_index = data.IdIndex(relation.linked_ids[link_index]); - int32 service_index = - data.ProblemIndex(RoutingIndexManager::NodeIndex(current_index)); - alternative_size = data.AlternativeSize(service_index); + current_index = data.AlternativeActivityIndex(relation.linked_ids[link_index]); + if (current_index >= 0) { + alternative_size = + data.AlternativeActivitySize(relation.linked_ids[link_index]); + } else { + current_index = data.IdIndex(relation.linked_ids[link_index]); + alternative_size = data.AlternativeSize(current_index); + } - for (int64 alternative_index = current_index; + for (int64_t alternative_index = current_index; alternative_index < current_index + alternative_size; ++alternative_index) { values.push_back(alternative_index); } } intermediate_values.insert(intermediate_values.end(), values.begin(), values.end()); for (std::size_t v = 0; v < data.Vehicles().size(); ++v) { - int64 end_index = routing.End(v); + int64_t end_index = routing.End(v); intermediate_values.push_back(end_index); } for (int index : values) { @@ -799,8 +825,8 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, ++link_index) { current_index = data.VehicleIdIndex(relation.linked_vehicle_ids[link_index]); - int64 start_index = routing.Start(current_index); - int64 end_index = routing.End(current_index); + int64_t start_index = routing.Start(current_index); + int64_t end_index = routing.End(current_index); IntVar* const cumul_var = routing.GetMutableDimension(kTime)->CumulVar(start_index); IntVar* const end_cumul_var = @@ -821,8 +847,8 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, ++link_index) { current_vehicle_index = data.VehicleIdIndex(relation.linked_vehicle_ids[link_index]); - int64 current_start_index = routing.Start(current_vehicle_index); - int64 previous_end_index = routing.End(previous_vehicle_index); + int64_t current_start_index = routing.Start(current_vehicle_index); + int64_t previous_end_index = routing.End(previous_vehicle_index); IntVar* const current_cumul_var = routing.GetMutableDimension(kTime)->CumulVar(current_start_index); IntVar* const previous_end_cumul_var = @@ -841,8 +867,8 @@ void RelationBuilder(const TSPTWDataDT& data, RoutingModel& routing, ++link_index) { int vehicle_index = data.VehicleIdIndex(relation.linked_vehicle_ids[link_index]); - int64 start_index = routing.Start(vehicle_index); - int64 end_index = routing.End(vehicle_index); + int64_t start_index = routing.Start(vehicle_index); + int64_t end_index = routing.End(vehicle_index); IntVar* const is_vehicle_used = solver ->MakeConditionalExpression( @@ -878,8 +904,8 @@ void AddBalanceDimensions(const TSPTWDataDT& data, RoutingModel& routing, const operations_research::RoutingDimension& distance_dimension = routing.GetDimensionOrDie(kDistance); - const int64 start_index = routing.Start(v); - const int64 end_index = routing.End(v); + const int64_t start_index = routing.Start(v); + const int64_t end_index = routing.End(v); IntVar* const time_cumul_var = time_dimension.CumulVar(start_index); IntVar* const time_cumul_var_end = time_dimension.CumulVar(end_index); @@ -898,12 +924,13 @@ void AddBalanceDimensions(const TSPTWDataDT& data, RoutingModel& routing, int v = 0; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { routing.GetMutableDimension(kTimeBalance) - ->SetSpanCostCoefficientForVehicle((int64)vehicle.cost_time_multiplier, v); + ->SetSpanCostCoefficientForVehicle((int64_t)vehicle.cost_time_multiplier, v); routing.GetMutableDimension(kDistanceBalance) - ->SetSpanCostCoefficientForVehicle((int64)vehicle.cost_distance_multiplier, v); + ->SetSpanCostCoefficientForVehicle((int64_t)vehicle.cost_distance_multiplier, + v); - const int64 start_index = routing.Start(v); - const int64 end_index = routing.End(v); + const int64_t start_index = routing.Start(v); + const int64_t end_index = routing.End(v); IntVar* const start_time_cumul_var = routing.GetMutableDimension(kTimeBalance)->CumulVar(start_index); @@ -932,9 +959,9 @@ void AddCapacityDimensions(const TSPTWDataDT& data, RoutingModel& routing, RoutingIndexManager& manager) { for (std::size_t unit_i = 0; unit_i < data.Vehicles(0).capacity.size(); ++unit_i) { const std::string kQuantity = ("quantity" + std::to_string(unit_i)).c_str(); - std::vector capacities; + std::vector capacities; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { - const int64 coef = vehicle.overload_multiplier[unit_i]; + const int64_t coef = vehicle.overload_multiplier[unit_i]; if (coef == 0 && vehicle.capacity[unit_i] >= 0) { capacities.push_back(vehicle.capacity[unit_i]); } else { @@ -942,7 +969,7 @@ void AddCapacityDimensions(const TSPTWDataDT& data, RoutingModel& routing, } } operations_research::RoutingTransitCallback2 quantity_evaluator = - [&data, &manager, unit_i](const int64 from, const int64 to) { + [&data, &manager, unit_i](const int64_t from, const int64_t to) { return data.Quantity(unit_i, manager.IndexToNode(from), manager.IndexToNode(to)); }; @@ -952,7 +979,7 @@ void AddCapacityDimensions(const TSPTWDataDT& data, RoutingModel& routing, int v = 0; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { - const int64 start_index = routing.Start(v); + const int64_t start_index = routing.Start(v); const operations_research::RoutingDimension& unit_dimension = routing.GetDimensionOrDie(kQuantity); IntVar* const start_unit_slack_var = unit_dimension.SlackVar(start_index); @@ -967,7 +994,7 @@ void AddCapacityDimensions(const TSPTWDataDT& data, RoutingModel& routing, void AddDistanceDimensions(const TSPTWDataDT& data, RoutingModel& routing, RoutingIndexManager& manager, - const int64 maximum_route_distance, + const int64_t maximum_route_distance, const bool free_approach_return) { std::vector distance_evaluators; std::vector fake_distance_evaluators; @@ -975,18 +1002,18 @@ void AddDistanceDimensions(const TSPTWDataDT& data, RoutingModel& routing, for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { distance_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.Distance(manager.IndexToNode(i), manager.IndexToNode(j)); })); if (free_approach_return == true) { fake_distance_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.FakeDistance(manager.IndexToNode(i), manager.IndexToNode(j)); })); } if (absl::GetFlag(FLAGS_nearby)) { distance_order_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.DistanceOrder(manager.IndexToNode(i), manager.IndexToNode(j)); })); } @@ -1022,7 +1049,7 @@ void AddDistanceDimensions(const TSPTWDataDT& data, RoutingModel& routing, } void AddTimeDimensions(const TSPTWDataDT& data, RoutingModel& routing, - RoutingIndexManager& manager, const int64 horizon, + RoutingIndexManager& manager, const int64_t horizon, const bool free_approach_return) { std::vector time_evaluators; std::vector fake_time_evaluators; @@ -1030,21 +1057,21 @@ void AddTimeDimensions(const TSPTWDataDT& data, RoutingModel& routing, for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { time_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.TimePlusServiceTime(manager.IndexToNode(i), manager.IndexToNode(j)); })); if (free_approach_return == true) { fake_time_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.FakeTimePlusServiceTime(manager.IndexToNode(i), manager.IndexToNode(j)); })); } if (absl::GetFlag(FLAGS_nearby)) { time_order_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { + [&vehicle, &manager](const int64_t i, const int64_t j) { return vehicle.TimeOrder(manager.IndexToNode(i), manager.IndexToNode(j)); })); } @@ -1080,19 +1107,19 @@ void AddTimeDimensions(const TSPTWDataDT& data, RoutingModel& routing, } } - const int64 without_wait_cost = + const int64_t without_wait_cost = vehicle.cost_time_multiplier - vehicle.cost_waiting_time_multiplier; // Vehicle costs if (vehicle.free_approach == true || vehicle.free_return == true) { routing.GetMutableDimension(kFakeTime)->SetSpanCostCoefficientForVehicle( vehicle.cost_waiting_time_multiplier, v); routing.GetMutableDimension(kFakeTimeNoWait) - ->SetSpanCostCoefficientForVehicle(std::max(without_wait_cost, 0), v); + ->SetSpanCostCoefficientForVehicle(std::max(without_wait_cost, 0), v); } else { routing.GetMutableDimension(kTime)->SetSpanCostCoefficientForVehicle( vehicle.cost_waiting_time_multiplier, v); routing.GetMutableDimension(kTimeNoWait) - ->SetSpanCostCoefficientForVehicle(std::max(without_wait_cost, 0), v); + ->SetSpanCostCoefficientForVehicle(std::max(without_wait_cost, 0), v); } if (absl::GetFlag(FLAGS_nearby)) { routing.GetMutableDimension(kTimeOrder) @@ -1106,11 +1133,18 @@ void AddValueDimensions(const TSPTWDataDT& data, RoutingModel& routing, RoutingIndexManager& manager) { std::vector value_evaluators; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { - value_evaluators.push_back(routing.RegisterTransitCallback( - [&vehicle, &manager](const int64 i, const int64 j) { - return vehicle.ValuePlusServiceValue(manager.IndexToNode(i), - manager.IndexToNode(j)); - })); + if (vehicle.value_matrix->value().empty()) { + value_evaluators.push_back( + routing.RegisterTransitCallback([&data, &manager](const int64_t i, const int64_t) { + return data.ServiceValue(manager.IndexToNode(i)); + })); + } else { + value_evaluators.push_back(routing.RegisterTransitCallback( + [&vehicle, &data, &manager](const int64_t i, const int64_t j) { + return vehicle.Value(manager.IndexToNode(i), manager.IndexToNode(j)) + + data.ServiceValue(manager.IndexToNode(i)); + })); + } } routing.AddDimensionWithVehicleTransits(value_evaluators, 0, LLONG_MAX, true, kValue); int v = 0; @@ -1129,8 +1163,9 @@ void AddVehicleTimeConstraints(const TSPTWDataDT& data, RoutingModel& routing, const operations_research::RoutingDimension& time_dimension = routing.GetDimensionOrDie(kTime); - const int64 start_index = routing.Start(v); - const int64 end_index = routing.End(v); + const int size_tws = data.TWsCounter(); + const int64_t start_index = routing.Start(v); + const int64_t end_index = routing.End(v); IntVar* const time_cumul_var = time_dimension.CumulVar(start_index); IntVar* const time_cumul_var_end = time_dimension.CumulVar(end_index); @@ -1143,8 +1178,8 @@ void AddVehicleTimeConstraints(const TSPTWDataDT& data, RoutingModel& routing, if (vehicle.shift_preference == ForceStart) { routing.GetMutableDimension(kTime)->SetCumulVarSoftUpperBound( start_index, vehicle.time_start, - std::max((int64)vehicle.cost_time_multiplier, - (int64)vehicle.cost_distance_multiplier) * + std::max((int64_t)vehicle.cost_time_multiplier, + (int64_t)vehicle.cost_distance_multiplier) * 100); IntVar* const slack_var = routing.GetMutableDimension(kTime)->SlackVar(start_index); @@ -1152,11 +1187,11 @@ void AddVehicleTimeConstraints(const TSPTWDataDT& data, RoutingModel& routing, } } - const int64 end_value(routing_values.RouteEndValues(v).initial_time_value); - const int64 start_value(routing_values.RouteStartValues(v).initial_time_value); + const int64_t end_value(routing_values.RouteEndValues(v).initial_time_value); + const int64_t start_value(routing_values.RouteStartValues(v).initial_time_value); if (vehicle.time_end < CUSTOM_MAX_INT) { - const int64 coef = vehicle.late_multiplier; + const int64_t coef = vehicle.late_multiplier; if (end_value >= 0) { assignment->Add(time_cumul_var_end); DLOG(INFO) << "time_cumul_var_end:" << time_cumul_var_end @@ -1204,6 +1239,11 @@ void AddVehicleTimeConstraints(const TSPTWDataDT& data, RoutingModel& routing, routing.AddVariableMinimizedByFinalizer(time_cumul_var_end); } + // Discriminate equivalent solutions to start at the earliest + if (size_tws == 0 && vehicle.shift_preference != ForceEnd) { + routing.GetMutableDimension(kTime)->SetCumulVarSoftUpperBound(start_index, vehicle.time_start, 1); + } + if (vehicle.shift_preference == ForceStart) routing.AddVariableMinimizedByFinalizer(time_cumul_var); else @@ -1219,11 +1259,9 @@ void AddVehicleDistanceConstraints(const TSPTWDataDT& data, RoutingModel& routin routing.GetDimensionOrDie(kDistance); for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { if (vehicle.distance > 0) { - const int64 end_index = routing.End(v); // Vehicle maximum distance - IntVar* const dist_end_cumul_var = distance_dimension.CumulVar(end_index); - solver->AddConstraint( - solver->MakeLessOrEqual(dist_end_cumul_var, vehicle.distance)); + solver->AddConstraint(solver->MakeLessOrEqual( + distance_dimension.CumulVar(routing.End(v)), vehicle.distance)); } ++v; } @@ -1232,9 +1270,9 @@ void AddVehicleDistanceConstraints(const TSPTWDataDT& data, RoutingModel& routin void AddVehicleCapacityConstraints(const TSPTWDataDT& data, RoutingModel& routing) { int v = 0; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { - int64 end_index = routing.End(v); + int64_t end_index = routing.End(v); for (std::size_t i = 0; i < vehicle.capacity.size(); ++i) { - const int64 coef = vehicle.overload_multiplier[i]; + const int64_t coef = vehicle.overload_multiplier[i]; // Capacity is already limited by the dimension horizon if (vehicle.capacity[i] >= 0 && coef > 0) { const std::string kQuantity = ("quantity" + std::to_string(i)).c_str(); @@ -1320,6 +1358,8 @@ void ParseSolutionIntoResult(const Assignment* const solution, std::vector>& stored_rests) { result->clear_routes(); + const int64_t earliest_start = data.EarliestStart(); + double total_time_order_cost(0.0), total_distance_order_cost(0.0), total_rest_position_cost(0.0); @@ -1331,12 +1371,12 @@ void ParseSolutionIntoResult(const Assignment* const solution, float lateness_cost = 0; float overload_cost = 0; bool vehicle_used = false; - for (int64 index = routing.Start(route_nbr); !routing.IsEnd(index); - index = solution->Value(routing.NextVar(index))) { - const int64 start_time = + for (int64_t index = routing.Start(route_nbr); !routing.IsEnd(index); + index = solution->Value(routing.NextVar(index))) { + const int64_t start_time = solution->Min(routing.GetMutableDimension(kTime)->CumulVar(index)); for (std::vector::iterator it = rests.begin(); it != rests.end();) { - const int64 rest_start_time = solution->StartValue(*it); + const int64_t rest_start_time = solution->StartValue(*it); if (solution->PerformedValue(*it) && previous_index != -1 && rest_start_time >= previous_start_time && rest_start_time < start_time) { std::stringstream ss((*it)->name()); @@ -1349,7 +1389,7 @@ void ParseSolutionIntoResult(const Assignment* const solution, ortools_result::Activity* rest = route->add_activities(); rest->set_type("break"); rest->set_id(parsed_name[1]); - rest->set_start_time(rest_start_time); + rest->set_start_time(rest_start_time + earliest_start); it = rests.erase(it); } else { ++it; @@ -1359,10 +1399,10 @@ void ParseSolutionIntoResult(const Assignment* const solution, ortools_result::Activity* activity = route->add_activities(); RoutingIndexManager::NodeIndex nodeIndex = manager.IndexToNode(index); activity->set_index(data.ProblemIndex(nodeIndex)); - activity->set_start_time(start_time); - const int64 upper_bound = + activity->set_start_time(start_time + earliest_start); + const int64_t upper_bound = routing.GetMutableDimension(kTime)->GetCumulVarSoftUpperBound(index); - const int64 lateness = std::max(start_time - upper_bound, 0); + const int64_t lateness = std::max(start_time - upper_bound, 0); activity->set_lateness(lateness); lateness_cost += GetUpperBoundCostForDimension(routing, solution, index, kTime); activity->set_current_distance( @@ -1371,7 +1411,8 @@ void ParseSolutionIntoResult(const Assignment* const solution, activity->set_type("start"); DLOG(INFO) << "RouteStartValues:" << route_nbr << "\t start_time: " << start_time << std::endl; - routing_values.RouteStartValues(route_nbr).initial_time_value = start_time; + routing_values.RouteStartValues(route_nbr).initial_time_value = + start_time + earliest_start; } else { vehicle_used = true; activity->set_type("service"); @@ -1379,7 +1420,8 @@ void ParseSolutionIntoResult(const Assignment* const solution, activity->set_alternative(data.AlternativeIndex(nodeIndex)); DLOG(INFO) << "nodeIndex:" << nodeIndex << "\t start_time: " << start_time << std::endl; - routing_values.NodeValues(nodeIndex).initial_time_value = start_time; + routing_values.NodeValues(nodeIndex).initial_time_value = + start_time + earliest_start; } for (std::size_t q = 0; q < data.Quantities(RoutingIndexManager::NodeIndex(0)).size(); ++q) { @@ -1398,7 +1440,7 @@ void ParseSolutionIntoResult(const Assignment* const solution, for (std::vector::iterator it = rests.begin(); it != rests.end(); ++it) { - const int64 rest_start_time = solution->StartValue(*it); + const int64_t rest_start_time = solution->StartValue(*it); if (solution->PerformedValue(*it)) { ortools_result::Activity* rest = route->add_activities(); std::stringstream ss((*it)->name()); @@ -1409,22 +1451,22 @@ void ParseSolutionIntoResult(const Assignment* const solution, } rest->set_type("break"); rest->set_id(parsed_name[1]); - rest->set_start_time(rest_start_time); + rest->set_start_time(rest_start_time + earliest_start); } } ortools_result::Activity* end_activity = route->add_activities(); RoutingIndexManager::NodeIndex nodeIndex = manager.IndexToNode(routing.End(route_nbr)); - const int64 end_index = routing.End(route_nbr); + const int64_t end_index = routing.End(route_nbr); end_activity->set_index(data.ProblemIndex(nodeIndex)); - const int64 start_time = + const int64_t start_time = solution->Min(routing.GetMutableDimension(kTime)->CumulVar(end_index)); - end_activity->set_start_time(start_time); - const int64 upper_bound = + end_activity->set_start_time(start_time + earliest_start); + const int64_t upper_bound = routing.GetMutableDimension(kTime)->GetCumulVarSoftUpperBound(end_index); - const int64 lateness = std::max(start_time - upper_bound, 0); + const int64_t lateness = std::max(start_time - upper_bound, 0); end_activity->set_lateness(lateness); lateness_cost += GetUpperBoundCostForDimension(routing, solution, end_index, kTime); end_activity->set_current_distance(solution->Min( @@ -1487,7 +1529,10 @@ void ParseSolutionIntoResult(const Assignment* const solution, const double time_without_wait_cost = GetSpanCostForVehicleForDimension(routing, solution, route_nbr, kTimeNoWait); - route_costs->set_time_without_wait(time_without_wait_cost); + const double fake_time_without_wait_cost = GetSpanCostForVehicleForDimension( + routing, solution, route_nbr, kFakeTimeNoWait); + route_costs->set_time_without_wait(time_without_wait_cost + + fake_time_without_wait_cost); const double value_cost = GetSpanCostForVehicleForDimension(routing, solution, route_nbr, kValue); @@ -1537,8 +1582,8 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, RoutingIndexManager manager(size, size_vehicles, *start_ends); RoutingModel routing(manager); - int64 maximum_route_distance = 0; - int64 v = 0; + int64_t maximum_route_distance = 0; + int64_t v = 0; while ((maximum_route_distance != INT_MAX) && (v < size_vehicles)) { if (data.Vehicles(v).distance <= 0) maximum_route_distance = INT_MAX; @@ -1549,7 +1594,7 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, } // Dimensions - const int64 horizon = + const int64_t horizon = data.Horizon() * (has_lateness && !CheckOverflow(data.Horizon(), 2) ? 2 : 1); DLOG(INFO) << "horizon=" << horizon; @@ -1568,20 +1613,18 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, AddVehicleDistanceConstraints(data, routing); AddVehicleCapacityConstraints(data, routing); - v = 0; - int64 min_start = CUSTOM_MAX_INT; + v = 0; for (const TSPTWDataDT::Vehicle& vehicle : data.Vehicles()) { routing.SetFixedCostOfVehicle(vehicle.cost_fixed, v); - min_start = std::min(min_start, vehicle.time_start); ++v; } std::vector used_vehicles; if (absl::GetFlag(FLAGS_vehicle_limit) > 0) { for (int vehicle = 0; vehicle < size_vehicles; ++vehicle) { - int64 start_index = routing.Start(vehicle); - int64 end_index = routing.End(vehicle); + int64_t start_index = routing.Start(vehicle); + int64_t end_index = routing.End(vehicle); IntVar* const is_vehicle_used = solver ->MakeConditionalExpression( @@ -1592,15 +1635,15 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, } solver->AddConstraint(solver->MakeLessOrEqual( - solver->MakeSum(used_vehicles), (int64)absl::GetFlag(FLAGS_vehicle_limit))); + solver->MakeSum(used_vehicles), (int64_t)absl::GetFlag(FLAGS_vehicle_limit))); } // Setting solve parameters indicators - int64 previous_distance_depot_start = -1; - int64 previous_distance_depot_end = -1; - ShiftPref shift_preference = MinimizeSpan; - bool loop_route = true; - bool unique_configuration = true; + int64_t previous_distance_depot_start = -1; + int64_t previous_distance_depot_end = -1; + ShiftPref shift_preference = MinimizeSpan; + bool loop_route = true; + bool unique_configuration = true; RoutingIndexManager::NodeIndex compareNodeIndex = manager.IndexToNode(rand() % (data.SizeMatrix() - 2)); const TSPTWDataDT::Vehicle* previous_vehicle = nullptr; @@ -1611,14 +1654,15 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, RoutingIndexManager::NodeIndex nodeIndexEnd = manager.IndexToNode(routing.End(route_nbr)); - int64 distance_depot_start = + int64_t distance_depot_start = std::max(vehicle->Time(nodeIndexStart, compareNodeIndex), vehicle->Distance(nodeIndexStart, compareNodeIndex)); - int64 distance_depot_end = + int64_t distance_depot_end = std::max(vehicle->Time(compareNodeIndex, nodeIndexEnd), vehicle->Distance(compareNodeIndex, nodeIndexEnd)); - int64 distance_start_end = std::max(vehicle->Time(nodeIndexStart, nodeIndexEnd), - vehicle->Distance(nodeIndexStart, nodeIndexEnd)); + int64_t distance_start_end = + std::max(vehicle->Time(nodeIndexStart, nodeIndexEnd), + vehicle->Distance(nodeIndexStart, nodeIndexEnd)); if (previous_vehicle != nullptr) { if (previous_distance_depot_start != distance_depot_start || @@ -1638,7 +1682,7 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, // Setting visit time windows MissionsBuilder(data, routing, routing_values, manager, assignment, size - 2, - min_start); + free_approach_return); std::vector> stored_rests = RestBuilder(data, routing, horizon); RelationBuilder(data, routing, has_overall_duration); @@ -1681,7 +1725,7 @@ const ortools_result::Result* TSPTWSolver(const TSPTWDataDT& data, const bool build_route = RouteBuilder(data, routing, manager, assignment); LoggerMonitor* const logger = MakeLoggerMonitor( - data, &routing, &manager, min_start, size_matrix, absl::GetFlag(FLAGS_debug), + data, &routing, &manager, size_matrix, absl::GetFlag(FLAGS_debug), absl::GetFlag(FLAGS_intermediate_solutions), result, stored_rests, filename, true); routing.AddSearchMonitor(logger); @@ -1757,7 +1801,7 @@ int main(int argc, char** argv) { << operations_research::OrToolsMinorVersion() << std::endl; GOOGLE_PROTOBUF_VERIFY_VERSION; - gflags::ParseCommandLineFlags(&argc, &argv, true); + absl::ParseCommandLine(argc, argv); if (absl::GetFlag(FLAGS_time_limit_in_ms) <= 0 && absl::GetFlag(FLAGS_no_solution_improvement_limit) <= 0 && diff --git a/tsptw_data_dt.h b/tsptw_data_dt.h index 9a5c5dfd..b92ff349 100644 --- a/tsptw_data_dt.h +++ b/tsptw_data_dt.h @@ -15,12 +15,19 @@ #include "ortools/constraint_solver/routing_index_manager.h" -#define CUSTOM_MAX_INT (int64) std::pow(2, 30) +#define CUSTOM_MAX_INT (int64_t) std::pow(2, 30) #define CUSTOM_BIGNUM_COST 1e6 #define CUSTOM_BIGNUM_QUANTITY 1e3 // Needs to stay smaller than CUSTOM_BIGNUM_COST +static bool compare_less_than_custom_max_int(const float& value1, const float& value2) { + if (value2 < CUSTOM_MAX_INT && value1 < value2) + return true; + else + return false; +} + enum RelationType { MinimumDurationLapse = 15, VehicleGroupNumber = 14, @@ -54,6 +61,7 @@ class TSPTWDataDT { , size_alternative_relations_(0) , deliveries_counter_(0) , horizon_(0) + , earliest_start_(CUSTOM_MAX_INT) , max_distance_(0) , max_distance_cost_(0) , max_rest_(0) @@ -72,116 +80,52 @@ class TSPTWDataDT { void LoadInstance(const std::string& filename); - // Helper function - int64& SetDistMatrix(const int i, const int j) { - return distances_matrices_.back().Cost(RoutingIndexManager::NodeIndex(i), - RoutingIndexManager::NodeIndex(j)); - } - - int64& SetTimeMatrix(const int i, const int j) { - return times_matrices_.back().Cost(RoutingIndexManager::NodeIndex(i), - RoutingIndexManager::NodeIndex(j)); - } - - int64& SetValueMatrix(const int i, const int j) { - return values_matrices_.back().Cost(RoutingIndexManager::NodeIndex(i), - RoutingIndexManager::NodeIndex(j)); - } - - int64 BuildTimeMatrix(const ortools_vrp::Matrix& matrix) { - int64 max_time = 0; - const int32 size_matrix = sqrt(matrix.time_size()); - for (int64 i = 0; i < size_matrix; ++i) { - for (int64 j = 0; j < size_matrix; ++j) { - const int64 time = matrix.time(i * size_matrix + j) + 0.5; - if (time < CUSTOM_MAX_INT) - max_time = std::max(max_time, time); - SetTimeMatrix(i, j) = time; - } - // std::cout << std::endl; - } - - return max_time; - } - - int64 BuildDistanceMatrix(const ortools_vrp::Matrix& matrix) { - int64 max_distance = 0; - const int32 size_matrix = sqrt(matrix.distance_size()); - for (int64 i = 0; i < size_matrix; ++i) { - for (int64 j = 0; j < size_matrix; ++j) { - const int64 distance = matrix.distance(i * size_matrix + j); - if (distance < CUSTOM_MAX_INT) - max_distance = std::max(max_distance, distance); - SetDistMatrix(i, j) = distance; - } - } - return max_distance; - } - - int64 BuildValueMatrix(const ortools_vrp::Matrix& matrix) { - int64 max_value = 0; - const int32 size_matrix = sqrt(matrix.value_size()); - for (int64 i = 0; i < size_matrix; ++i) { - for (int64 j = 0; j < size_matrix; ++j) { - const int64 value = matrix.value(i * size_matrix + j); - if (value < CUSTOM_MAX_INT) - max_value = std::max(max_value, value); - SetValueMatrix(i, j) = value; - } - } - return max_value; - } + int64_t Horizon() const { return horizon_; } - int64 Horizon() const { return horizon_; } + int64_t EarliestStart() const { return earliest_start_; } - int64 MatrixIndex(const RoutingIndexManager::NodeIndex i) const { - return tsptw_clients_[i.value()].matrix_index; - } - - int64 MaxTime() const { return max_time_; } + int64_t MaxTime() const { return max_time_; } - int64 MaxDistance() const { return max_distance_; } + int64_t MaxDistance() const { return max_distance_; } - int64 MaxValue() const { return max_value_; } + int64_t MaxValue() const { return max_value_; } - int64 MaxServiceTime() const { return max_service_; } + int64_t MaxServiceTime() const { return max_service_; } - int64 MaxTimeCost() const { return max_time_cost_; } + int64_t MaxTimeCost() const { return max_time_cost_; } - int64 MaxDistanceCost() const { return max_distance_cost_; } + int64_t MaxDistanceCost() const { return max_distance_cost_; } - int64 MaxValueCost() const { return max_value_cost_; } + int64_t MaxValueCost() const { return max_value_cost_; } - int64 TWsCounter() const { return tws_counter_; } + int64_t TwiceTWsCounter() const { return multiple_tws_counter_; } - int64 TwiceTWsCounter() const { return multiple_tws_counter_; } + int64_t DeliveriesCounter() const { return deliveries_counter_; } - int64 DeliveriesCounter() const { return deliveries_counter_; } - - int64 IdIndex(const std::string& id) const { - std::map::const_iterator it = ids_map_.find(id); + int64_t IdIndex(const std::string& id) const { + std::map::const_iterator it = ids_map_.find(id); if (it != ids_map_.end()) return it->second; else return -1; } - int64 VehicleIdIndex(const std::string& id) const { - std::map::const_iterator it = vehicle_ids_map_.find(id); + int64_t VehicleIdIndex(const std::string& id) const { + std::map::const_iterator it = vehicle_ids_map_.find(id); if (it != vehicle_ids_map_.end()) return it->second; else return -1; } - int64 DayIndexToVehicleIndex(const int64 day_index) const { + int64_t DayIndexToVehicleIndex(const int64_t day_index) const { if (day_index_to_vehicle_index_.count(day_index)) { return day_index_to_vehicle_index_.at(day_index); } return CUSTOM_MAX_INT; } - int32 AlternativeSize(const int32 problem_index) const { + int32_t AlternativeSize(const int32_t problem_index) const { if (alternative_size_map_.count(problem_index)) return alternative_size_map_.at(problem_index); return -1; @@ -191,19 +135,37 @@ class TSPTWDataDT { return tsptw_clients_[i.value()].customer_id; } - int32 ProblemIndex(const RoutingIndexManager::NodeIndex i) const { + std::string PointId(const RoutingIndexManager::NodeIndex i) const { + return tsptw_clients_[i.value()].point_id; + } + + int32_t ProblemIndex(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].problem_index; } - int32 AlternativeIndex(const RoutingIndexManager::NodeIndex i) const { + int32_t AlternativeIndex(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].alternative_index; } - const std::vector& ReadyTime(const RoutingIndexManager::NodeIndex i) const { + int32_t AlternativeActivityIndex(const std::string id) const { + if (alternative_activity_ids_map_.find(id) != alternative_activity_ids_map_.end()) { + return alternative_activity_ids_map_.at(id); + } + return -1; + } + + int32_t AlternativeActivitySize(const std::string id) const { + if (alternative_activity_size_map_.find(id) != alternative_activity_size_map_.end()) { + return alternative_activity_size_map_.at(id); + } + return 0; + } + + const std::vector& ReadyTime(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].ready_time; } - const std::vector& DueTime(const RoutingIndexManager::NodeIndex i) const { + const std::vector& DueTime(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].due_time; } @@ -215,65 +177,64 @@ class TSPTWDataDT { return true; } - const std::vector& + const std::vector& MaximumLateness(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].maximum_lateness; } - int64 LateMultiplier(const RoutingIndexManager::NodeIndex i) const { + int64_t LateMultiplier(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].late_multiplier; } - int64 ServiceTime(const RoutingIndexManager::NodeIndex i) const { + int64_t ServiceTime(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].service_time; } - const std::vector& ServiceTimes() const { return service_times_; } + const std::vector& ServiceTimes() const { return service_times_; } - int64 ServiceValue(const RoutingIndexManager::NodeIndex i) const { + int64_t ServiceValue(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].service_value; } - int64 SetupTime(const RoutingIndexManager::NodeIndex i) const { + int64_t SetupTime(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].setup_time; } - int64 Priority(const RoutingIndexManager::NodeIndex i) const { + int64_t Priority(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].priority; } - int64 ExclusionCost(const RoutingIndexManager::NodeIndex i) const { + int64_t ExclusionCost(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].exclusion_cost; } - const std::vector& VehicleIndices(const RoutingIndexManager::NodeIndex i) const { + const std::vector& + VehicleIndices(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].vehicle_indices; } - int32 TimeWindowsSize(const int i) const { return tws_size_[i]; } - - int32 Size() const { return size_; } + int32_t Size() const { return size_; } - int32 SizeMissions() const { return size_missions_; } + int32_t SizeMissions() const { return size_missions_; } - int32 SizeMatrix() const { return size_matrix_; } + int32_t SizeMatrix() const { return size_matrix_; } - int32 SizeProblem() const { return size_problem_; } + int32_t SizeProblem() const { return size_problem_; } - int32 SizeRest() const { return size_rest_; } + int32_t SizeRest() const { return size_rest_; } - int32 SizeAlternativeRelations() const { return size_alternative_relations_; } + int32_t SizeAlternativeRelations() const { return size_alternative_relations_; } const std::vector& RefillQuantities(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].refill_quantities; } - int64 Quantity(const std::size_t unit_i, const RoutingIndexManager::NodeIndex from, - const RoutingIndexManager::NodeIndex to) const { + int64_t Quantity(const std::size_t unit_i, const RoutingIndexManager::NodeIndex from, + const RoutingIndexManager::NodeIndex to) const { // CheckNodeIsValid(from); // CheckNodeIsValid(to); - const int64 index = from.value(); + const int64_t index = from.value(); if (unit_i < tsptw_clients_[index].quantities.size()) { if (tsptw_vehicles_[0].counting[unit_i]) { if (tsptw_vehicles_[0].stop == to || tsptw_vehicles_[0].Distance(from, to) > 0 || @@ -289,20 +250,19 @@ class TSPTWDataDT { } } - const std::vector& Quantities(const RoutingIndexManager::NodeIndex i) const { + const std::vector& Quantities(const RoutingIndexManager::NodeIndex i) const { return tsptw_clients_[i.value()].quantities; } - std::vector MaxTimes(const ortools_vrp::Matrix& matrix) const { - int64 max_row; - int32 size_matrix = sqrt(matrix.time_size()); - std::vector max_times; - for (int32 i = 0; i < size_matrix; i++) { - max_row = 0; - for (int32 j = 0; j < size_matrix; j++) { - int64 cell = matrix.time(i * size_matrix + j); + std::vector MaxTimes(const ortools_vrp::Matrix& matrix) const { + const int32_t matrix_size = matrix.size(); + std::vector max_times; + for (int32_t i = 0; i < matrix_size; i++) { + int64_t max_row = 0; + for (int32_t j = 0; j < matrix_size; j++) { + int64_t cell = matrix.time(i * matrix_size + j); if (cell + 0.5 < CUSTOM_MAX_INT) - max_row = std::max(max_row, (int64)(cell + 0.5)); + max_row = std::max(max_row, (int64_t)(cell + 0.5)); } max_times.push_back(max_row); } @@ -310,24 +270,26 @@ class TSPTWDataDT { } struct Rest { - Rest(std::string id, int64 ready_t, int64 due_t, int64 dur) + Rest(std::string id, int64_t ready_t, int64_t due_t, int64_t dur) : rest_id(id) , ready_time(std::max(0L, ready_t)) , due_time(std::min(CUSTOM_MAX_INT, due_t)) , duration(dur) {} std::string rest_id; - int64 ready_time; - int64 due_time; - int64 duration; + int64_t ready_time; + int64_t due_time; + int64_t duration; }; struct Vehicle { - Vehicle(TSPTWDataDT* data_, int32 size_) + Vehicle(TSPTWDataDT* data_, int32_t size_, const ortools_vrp::Matrix& matrix_, + const ortools_vrp::Matrix& value_matrix_) : data(data_) , size(size_) - , problem_matrix_index(0) - , value_matrix_index(0) - , vehicle_indices(0) + , matrix(&matrix_) + , value_matrix(&value_matrix_) + , start_point_id("") + , matrix_indices(0) , initial_capacity(0) , initial_load(0) , capacity(0) @@ -338,135 +300,106 @@ class TSPTWDataDT { , time_maximum_lateness(CUSTOM_MAX_INT) , late_multiplier(0) {} - int32 SizeMatrix() const { return size_matrix; } - - int32 SizeRest() const { return size_rest; } - void SetStart(const RoutingIndexManager::NodeIndex s) { - CHECK_LT(s, size); + DCHECK_LT(s, size); start = s; } void SetStop(const RoutingIndexManager::NodeIndex s) { - CHECK_LT(s, size); + DCHECK_LT(s, size); stop = s; } - int64 ReturnZero(const RoutingIndexManager::NodeIndex, - const RoutingIndexManager::NodeIndex) const { - return 0; + inline int64_t MatrixIndex(const RoutingIndexManager::NodeIndex i, + const RoutingIndexManager::NodeIndex j, + const size_t matrix_size) const { + CheckNodeIsValid(i); + CheckNodeIsValid(j); + const auto i_matrix_index = matrix_indices[i.value()]; + const auto j_matrix_index = matrix_indices[j.value()]; + + if (i_matrix_index == -1 || j_matrix_index == -1) + return -1; + + DCHECK_LT(i_matrix_index, matrix_size); + DCHECK_LT(j_matrix_index, matrix_size); + + return i_matrix_index * matrix_size + j_matrix_index; } - int64 Distance(const RoutingIndexManager::NodeIndex i, + int64_t Distance(const RoutingIndexManager::NodeIndex i, const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1) + const auto index = MatrixIndex(i, j, matrix->size()); + if (index == -1) return 0; - if (i != Start() && j != Stop() && max_ride_distance_ > 0 && - data->distances_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])) > - max_ride_distance_) + + const auto dist = matrix->distance(index); + + if (max_ride_distance_ > 0 && i != Start() && j != Stop() && + dist > max_ride_distance_) return CUSTOM_MAX_INT; - return data->distances_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])); + + return dist; } - int64 FakeDistance(const RoutingIndexManager::NodeIndex i, - const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1 || - (i == Start() && free_approach) || (j == Stop() && free_return)) + int64_t Time(const RoutingIndexManager::NodeIndex i, + const RoutingIndexManager::NodeIndex j) const { + const auto index = MatrixIndex(i, j, matrix->size()); + if (index == -1) return 0; - if (i != Start() && j != Stop() && max_ride_distance_ > 0 && - data->distances_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])) > - max_ride_distance_) + + const auto time = matrix->time(index); + + if (max_ride_time_ > 0 && i != Start() && j != Stop() && time > max_ride_time_) return CUSTOM_MAX_INT; - return data->distances_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])); + + return time; } - int64 Time(const RoutingIndexManager::NodeIndex i, - const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1) + int64 Value(const RoutingIndexManager::NodeIndex i, + const RoutingIndexManager::NodeIndex j) const { + const auto index = MatrixIndex(i, j, value_matrix->size()); + if (index == -1) return 0; - if (i != Start() && j != Stop() && max_ride_time_ > 0 && - data->times_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])) > - max_ride_time_) - return CUSTOM_MAX_INT; - return data->times_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])); + + return value_matrix->value(index); } - int64 FakeTime(const RoutingIndexManager::NodeIndex i, + int64_t FakeTime(const RoutingIndexManager::NodeIndex i, const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1 || - (i == Start() && free_approach) || (j == Stop() && free_return)) + if ((i == Start() && free_approach) || (j == Stop() && free_return)) return 0; - if (i != Start() && j != Stop() && max_ride_time_ > 0 && - data->times_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])) > - max_ride_time_) - return CUSTOM_MAX_INT; - return data->times_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])); + + return Time(i, j); } - int64 Value(const RoutingIndexManager::NodeIndex i, - const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1) + int64_t FakeDistance(const RoutingIndexManager::NodeIndex i, + const RoutingIndexManager::NodeIndex j) const { + if ((i == Start() && free_approach) || (j == Stop() && free_return)) return 0; - return data->values_matrices_[value_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()])); + + return Distance(i, j); } - int64 TimeOrder(const RoutingIndexManager::NodeIndex i, + int64_t TimeOrder(const RoutingIndexManager::NodeIndex i, const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1) - return 0; - return 10 * std::sqrt(data->times_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()]))); + return 10 * std::sqrt(Time(i, j)); } - int64 DistanceOrder(const RoutingIndexManager::NodeIndex i, + int64_t DistanceOrder(const RoutingIndexManager::NodeIndex i, const RoutingIndexManager::NodeIndex j) const { - CheckNodeIsValid(i); - CheckNodeIsValid(j); - if (vehicle_indices[i.value()] == -1 || vehicle_indices[j.value()] == -1) - return 0; - return 100 * std::sqrt(data->distances_matrices_[problem_matrix_index].Cost( - RoutingIndexManager::NodeIndex(vehicle_indices[i.value()]), - RoutingIndexManager::NodeIndex(vehicle_indices[j.value()]))); + return 100 * std::sqrt(Distance(i, j)); } // Transit quantity at a node "from" // This is the quantity added after visiting node "from" - int64 TimePlusServiceTime(const RoutingIndexManager::NodeIndex from, + int64_t TimePlusServiceTime(const RoutingIndexManager::NodeIndex from, const RoutingIndexManager::NodeIndex to) const { - int64 current_time = Time(from, to) + coef_service * data->ServiceTime(from) + + std::string from_id = + from.value() > data->SizeMissions() ? start_point_id : data->PointId(from); + int64_t current_time = Time(from, to) + coef_service * data->ServiceTime(from) + additional_service + - (vehicle_indices[from.value()] != vehicle_indices[to.value()] + (from_id != data->PointId(to) ? coef_setup * data->SetupTime(to) + (data->SetupTime(to) > 0 ? additional_setup : 0) : 0); @@ -475,7 +408,8 @@ class TSPTWDataDT { // will violate relations as the cumul_var will be the same. // Moreover with sequence+shipment lead or-tools to try only // invalid order of nodes - if (current_time == 0 && data->SizeAlternativeRelations() > 0) { + if (current_time == 0 && data->SizeAlternativeRelations() > 0 && + to.value() < data->SizeMissions()) { ++current_time; } @@ -488,26 +422,18 @@ class TSPTWDataDT { // called data->SetupTime(from, to) } - int64 FakeTimePlusServiceTime(const RoutingIndexManager::NodeIndex from, + int64_t FakeTimePlusServiceTime(const RoutingIndexManager::NodeIndex from, const RoutingIndexManager::NodeIndex to) const { + std::string from_id = + from.value() > data->SizeMissions() ? start_point_id : data->PointId(from); return FakeTime(from, to) + coef_service * data->ServiceTime(from) + additional_service + - (vehicle_indices[from.value()] != vehicle_indices[to.value()] + (from_id != data->PointId(to) ? coef_setup * data->SetupTime(to) + (data->SetupTime(to) > 0 ? additional_setup : 0) : 0); } - int64 ValuePlusServiceValue(const RoutingIndexManager::NodeIndex from, - const RoutingIndexManager::NodeIndex to) const { - return Time(from, to) + data->ServiceValue(from); - } - - int64 TimePlus(const RoutingIndexManager::NodeIndex from, - const RoutingIndexManager::NodeIndex to) const { - return Time(from, to); - } - RoutingIndexManager::NodeIndex Start() const { return start; } RoutingIndexManager::NodeIndex Stop() const { return stop; } @@ -523,50 +449,51 @@ class TSPTWDataDT { const TSPTWDataDT* const data; std::string id; - int64 vehicle_index; - int32 size; - int32 size_matrix; - int32 size_rest; + int64_t vehicle_index; + int32_t size; + const ortools_vrp::Matrix* const matrix; + const ortools_vrp::Matrix* const value_matrix; + int32_t size_matrix; + int32_t size_rest; RoutingIndexManager::NodeIndex start; RoutingIndexManager::NodeIndex stop; - int64 problem_matrix_index; - int64 value_matrix_index; - std::vector vehicle_indices; - std::vector initial_capacity; - std::vector initial_load; - std::vector capacity; + std::string start_point_id; + std::vector matrix_indices; + std::vector initial_capacity; + std::vector initial_load; + std::vector capacity; std::vector counting; - std::vector overload_multiplier; + std::vector overload_multiplier; std::vector rests; - int32 break_size; - int64 time_start; - int64 time_end; - int64 time_maximum_lateness; - int64 late_multiplier; - int64 cost_fixed; - int64 cost_distance_multiplier; - int64 cost_time_multiplier; - int64 cost_waiting_time_multiplier; - int64 cost_value_multiplier; + int32_t break_size; + int64_t time_start; + int64_t time_end; + int64_t time_maximum_lateness; + int64_t late_multiplier; + int64_t cost_fixed; + int64_t cost_distance_multiplier; + int64_t cost_time_multiplier; + int64_t cost_waiting_time_multiplier; + int64_t cost_value_multiplier; float coef_service; - int64 additional_service; + int64_t additional_service; float coef_setup; - int64 additional_setup; - int64 duration; - int64 distance; + int64_t additional_setup; + int64_t duration; + int64_t distance; ShiftPref shift_preference; - int32 day_index; - int64 max_ride_time_; - int64 max_ride_distance_; + int32_t day_index; + int64_t max_ride_time_; + int64_t max_ride_distance_; bool free_approach; bool free_return; }; const std::vector& Vehicles() const { return tsptw_vehicles_; } - const Vehicle& Vehicles(const int64 index) const { return tsptw_vehicles_[index]; } + const Vehicle& Vehicles(const int64_t index) const { return tsptw_vehicles_[index]; } - bool VehicleHasEnd(const int64 index) const { + bool VehicleHasEnd(const int64_t index) const { return tsptw_vehicles_[index].time_end < CUSTOM_MAX_INT; } @@ -607,7 +534,7 @@ class TSPTWDataDT { , lapse(-1) {} Relation(int relation_no, RelationType t, const google::protobuf::RepeatedPtrField& l_i, - const google::protobuf::RepeatedPtrField& l_v_i, int32 l) + const google::protobuf::RepeatedPtrField& l_v_i, int32_t l) : relation_number(relation_no) , type(t) , linked_ids(l_i) @@ -618,34 +545,28 @@ class TSPTWDataDT { RelationType type; const google::protobuf::RepeatedPtrField linked_ids; const google::protobuf::RepeatedPtrField linked_vehicle_ids; - int32 lapse; + int32_t lapse; }; const std::vector& Relations() const { return tsptw_relations_; } - const std::vector& VehiclesDay() const { return vehicles_day_; } - - int VehicleDay(const int64 index) const { + int VehicleDay(const int64_t index) const { if (index < 0) { return -1; } return vehicles_day_[index]; } - int VehicleDayAlt(const int64 index) const { - if (index < 0) { - return CUSTOM_MAX_INT; - } - return vehicles_day_[index]; - } - private: + ortools_vrp::Problem problem; + void ProcessNewLine(char* const line); struct TSPTWClient { // Depot definition - TSPTWClient(std::string cust_id, int32 m_i, int32 p_i) + TSPTWClient(std::string cust_id, std::string p_id, int32_t m_i, int32_t p_i) : customer_id(cust_id) + , point_id(p_id) , matrix_index(m_i) , problem_index(p_i) , alternative_index(0) @@ -659,12 +580,13 @@ class TSPTWDataDT { , late_multiplier(0) , is_break(false) {} // Mission definition - TSPTWClient(std::string cust_id, int32 m_i, int32 p_i, int32 a_i, - std::vector r_t, std::vector d_t, - std::vector& max_lateness, double s_t, double s_v, double st_t, - int32 p_t, double l_m, std::vector& v_i, std::vector& q, - std::vector& s_q, int64 e_c, std::vector& r_q) + TSPTWClient(std::string cust_id, std::string p_id, int32_t m_i, int32_t p_i, int32_t a_i, + std::vector r_t, std::vector d_t, + std::vector& max_lateness, double s_t, double s_v, double st_t, + int32_t p_t, double l_m, std::vector& v_i, std::vector& q, + std::vector& s_q, int64_t e_c, std::vector& r_q) : customer_id(cust_id) + , point_id(p_id) , matrix_index(m_i) , problem_index(p_i) , alternative_index(a_i) @@ -683,68 +605,68 @@ class TSPTWDataDT { , refill_quantities(r_q) , is_break(false) {} std::string customer_id; - int32 matrix_index; - int32 problem_index; - int32 alternative_index; - std::vector ready_time; - std::vector due_time; - std::vector maximum_lateness; - int64 service_time; - int64 service_value; - int64 setup_time; - int64 priority; - int64 late_multiplier; - std::vector vehicle_indices; - std::vector quantities; - std::vector setup_quantities; - int64 exclusion_cost; + std::string point_id; + int32_t matrix_index; + int32_t problem_index; + int32_t alternative_index; + int32_t alternative_activity_index; + std::vector ready_time; + std::vector due_time; + std::vector maximum_lateness; + int64_t service_time; + int64_t service_value; + int64_t setup_time; + int64_t priority; + int64_t late_multiplier; + std::vector vehicle_indices; + std::vector quantities; + std::vector setup_quantities; + int64_t exclusion_cost; std::vector refill_quantities; bool is_break; }; - uint32 size_problem_; - int32 size_; - int32 size_matrix_; - int32 size_missions_; - int32 size_rest_; - int32 size_alternative_relations_; - int64 deliveries_counter_; - int64 horizon_; - int64 max_distance_; - int64 max_distance_cost_; - int64 max_rest_; - int64 max_service_; - int64 max_time_; - int64 max_time_cost_; - int64 max_value_; - int64 max_value_cost_; - int64 multiple_tws_counter_; - int64 sum_max_time_; - int64 tws_counter_; + int32_t size_problem_; + int32_t size_; + int32_t size_matrix_; + int32_t size_missions_; + int32_t size_rest_; + int32_t size_alternative_relations_; + int64_t deliveries_counter_; + int64_t horizon_; + int64_t earliest_start_; + int64_t max_distance_; + int64_t max_distance_cost_; + int64_t max_rest_; + int64_t max_service_; + int64_t max_time_; + int64_t max_time_cost_; + int64_t max_value_; + int64_t max_value_cost_; + int64_t multiple_tws_counter_; + int64_t sum_max_time_; + int64_t tws_counter_; float max_coef_service_; float max_coef_setup_; - std::vector tws_size_; + std::vector tws_size_; std::vector tsptw_vehicles_; std::vector tsptw_relations_; std::vector tsptw_clients_; - std::map alternative_size_map_; + std::map alternative_size_map_; + std::map alternative_activity_size_map_; + std::map alternative_activity_ids_map_; std::vector tsptw_routes_; - std::vector distances_matrices_; - std::vector times_matrices_; - std::vector values_matrices_; std::vector vehicles_day_; - std::vector service_times_; + std::vector service_times_; std::string details_; - std::map ids_map_; - std::map vehicle_ids_map_; - std::map day_index_to_vehicle_index_; + std::map ids_map_; + std::map vehicle_ids_map_; + std::map day_index_to_vehicle_index_; }; void TSPTWDataDT::LoadInstance(const std::string& filename) { GOOGLE_PROTOBUF_VERIFY_VERSION; - ortools_vrp::Problem problem; - { std::fstream input(filename, std::ios::in | std::ios::binary); if (!problem.ParseFromIstream(&input)) { @@ -752,27 +674,33 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { } } - int32 node_index = 0; - int32 matrix_index = 0; - std::vector matrix_indices; + // compute earliest start first + for (const ortools_vrp::Vehicle& vehicle : problem.vehicles()) { + earliest_start_ = std::min((int64_t) vehicle.time_window().start(), earliest_start_); + } + + int32_t node_index = 0; + int32_t matrix_index = 0; + int32_t previous_matrix_size = 0; + std::vector service_matrix_indices; for (const ortools_vrp::Service& service : problem.services()) { if (!alternative_size_map_.count(service.problem_index())) alternative_size_map_[service.problem_index()] = 0; - const int32 tws_size = service.time_windows_size(); + const int32_t tws_size = service.time_windows_size(); tws_size_.push_back(tws_size); std::vector timewindows; - for (int32 tw = 0; tw < tws_size; ++tw) { + for (int32_t tw = 0; tw < tws_size; ++tw) { timewindows.push_back(&service.time_windows().Get(tw)); } - std::vector q; + std::vector q; for (const float& quantity : service.quantities()) { if (quantity < 0) ++deliveries_counter_; q.push_back(std::round(quantity * CUSTOM_BIGNUM_QUANTITY)); } - std::vector s_q; + std::vector s_q; for (const float& setup_quantity : service.setup_quantities()) { s_q.push_back(std::round(setup_quantity * CUSTOM_BIGNUM_QUANTITY)); } @@ -782,8 +710,8 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { r_q.push_back(refill); } - std::vector v_i; - for (const int64& index : service.vehicle_indices()) { + std::vector v_i; + for (const int64_t& index : service.vehicle_indices()) { v_i.push_back(index); } @@ -796,73 +724,98 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { if (service.late_multiplier() > 0) { do { - matrix_indices.push_back(service.matrix_index()); - std::vector start; - if (timewindows.size() > 0 && - timewindows[timewindow_index]->start() > -CUSTOM_MAX_INT) - start.push_back(timewindows[timewindow_index]->start()); - else - start.push_back(-CUSTOM_MAX_INT); - - std::vector end; - if (timewindows.size() > 0 && - timewindows[timewindow_index]->end() < CUSTOM_MAX_INT) - end.push_back(timewindows[timewindow_index]->end()); - else - end.push_back(CUSTOM_MAX_INT); - - std::vector max_lateness; - if (timewindows.size() > 0 && - timewindows[timewindow_index]->maximum_lateness() < CUSTOM_MAX_INT) - max_lateness.push_back(timewindows[timewindow_index]->maximum_lateness()); - else - max_lateness.push_back(CUSTOM_MAX_INT); - - size_problem_ = std::max(size_problem_, service.problem_index()); - tsptw_clients_.push_back(TSPTWClient( - (std::string)service.id(), matrix_index, service.problem_index(), - alternative_size_map_[service.problem_index()], start, end, max_lateness, - service.duration(), service.additional_value(), service.setup_duration(), - service.priority(), - timewindows.size() > 0 - ? (int64)(service.late_multiplier() * CUSTOM_BIGNUM_COST) - : 0, - v_i, q, s_q, - service.exclusion_cost() > 0 ? service.exclusion_cost() * CUSTOM_BIGNUM_COST - : -1, - r_q)); - - service_times_.push_back(service.duration()); - alternative_size_map_[service.problem_index()] += 1; - if (ids_map_.find((std::string)service.id()) == ids_map_.end()) - ids_map_[(std::string)service.id()] = node_index; - node_index++; + if (timewindows.size() == 0 || + (earliest_start_ < timewindows[timewindow_index]->end() + + timewindows[timewindow_index]->maximum_lateness())) { + service_matrix_indices.push_back(service.matrix_index()); + std::vector start; + if (timewindows.size() > 0 && + (timewindows[timewindow_index]->start() - earliest_start_) > 0) + start.push_back(timewindows[timewindow_index]->start() - earliest_start_); + else + start.push_back(0); + + std::vector end; + if (timewindows.size() > 0 && + (timewindows[timewindow_index]->end() - earliest_start_) < CUSTOM_MAX_INT) + end.push_back(timewindows[timewindow_index]->end() - earliest_start_); + else + end.push_back(CUSTOM_MAX_INT); + + std::vector max_lateness; + if (timewindows.size() > 0 && + timewindows[timewindow_index]->maximum_lateness() < CUSTOM_MAX_INT) + max_lateness.push_back(timewindows[timewindow_index]->maximum_lateness()); + else + max_lateness.push_back(CUSTOM_MAX_INT); + + size_problem_ = std::max(size_problem_, (int32_t)service.problem_index()); + tsptw_clients_.push_back(TSPTWClient( + (std::string)service.id(), (std::string)service.point_id(), matrix_index, + service.problem_index(), alternative_size_map_[service.problem_index()], + start, end, max_lateness, service.duration(), service.additional_value(), + service.setup_duration(), service.priority(), + timewindows.size() > 0 + ? (int64_t)(service.late_multiplier() * CUSTOM_BIGNUM_COST) + : 0, + v_i, q, s_q, + service.exclusion_cost() > 0 ? service.exclusion_cost() * CUSTOM_BIGNUM_COST + : -1, + r_q)); + + service_times_.push_back(service.duration()); + alternative_size_map_[service.problem_index()] += 1; + if (ids_map_.find((std::string)service.id()) == ids_map_.end()) + ids_map_[(std::string)service.id()] = node_index; + + if (alternative_activity_ids_map_.find( + (std::string)service.id() + "#" + + std::to_string(service.alternative_index())) == + alternative_activity_ids_map_.end()) { + alternative_activity_ids_map_[service.id() + "#" + + std::to_string(service.alternative_index())] = + node_index; + alternative_activity_size_map_[service.id() + "#" + + std::to_string(service.alternative_index())] = + 1; + } else { + alternative_activity_size_map_[service.id() + "#" + + std::to_string(service.alternative_index())] += + 1; + } + + node_index++; + } ++timewindow_index; } while (timewindow_index < service.time_windows_size()); } else { - std::vector ready_time; - std::vector due_time; - std::vector max_lateness; + std::vector ready_time; + std::vector due_time; + std::vector max_lateness; for (const ortools_vrp::TimeWindow* timewindow : timewindows) { - timewindow->start() > -CUSTOM_MAX_INT ? ready_time.push_back(timewindow->start()) - : ready_time.push_back(-CUSTOM_MAX_INT); - timewindow->end() < CUSTOM_MAX_INT ? due_time.push_back(timewindow->end()) - : due_time.push_back(CUSTOM_MAX_INT); - timewindow->maximum_lateness() < CUSTOM_MAX_INT - ? max_lateness.push_back(timewindow->maximum_lateness()) - : max_lateness.push_back(CUSTOM_MAX_INT); + if (earliest_start_ < timewindow->end()) { + (timewindow->start() - earliest_start_) > 0 + ? ready_time.push_back(timewindow->start() - earliest_start_) + : ready_time.push_back(0); + (timewindow->end() - earliest_start_) < CUSTOM_MAX_INT + ? due_time.push_back(timewindow->end() - earliest_start_) + : due_time.push_back(CUSTOM_MAX_INT); + timewindow->maximum_lateness() < CUSTOM_MAX_INT + ? max_lateness.push_back(timewindow->maximum_lateness()) + : max_lateness.push_back(CUSTOM_MAX_INT); + } } - matrix_indices.push_back(service.matrix_index()); - size_problem_ = std::max(size_problem_, service.problem_index()); + service_matrix_indices.push_back(service.matrix_index()); + size_problem_ = std::max(size_problem_, (int32_t)service.problem_index()); tsptw_clients_.push_back(TSPTWClient( - (std::string)service.id(), matrix_index, service.problem_index(), - alternative_size_map_[service.problem_index()], ready_time, due_time, - max_lateness, service.duration(), service.additional_value(), - service.setup_duration(), service.priority(), - timewindows.size() > 0 ? (int64)(service.late_multiplier() * CUSTOM_BIGNUM_COST) - : 0, + (std::string)service.id(), (std::string)service.point_id(), matrix_index, + service.problem_index(), alternative_size_map_[service.problem_index()], + ready_time, due_time, max_lateness, service.duration(), + service.additional_value(), service.setup_duration(), service.priority(), + ready_time.size() > 0 ? (int64_t)(service.late_multiplier() * CUSTOM_BIGNUM_COST) + : 0, v_i, q, s_q, service.exclusion_cost() > 0 ? service.exclusion_cost() * CUSTOM_BIGNUM_COST : -1, @@ -871,8 +824,27 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { alternative_size_map_[service.problem_index()] += 1; if (ids_map_.find((std::string)service.id()) == ids_map_.end()) ids_map_[(std::string)service.id()] = node_index; + + if (alternative_activity_ids_map_.find( + (std::string)service.id() + "#" + + std::to_string(service.alternative_index())) == + alternative_activity_ids_map_.end()) { + alternative_activity_ids_map_[service.id() + "#" + + std::to_string(service.alternative_index())] = + node_index; + alternative_activity_size_map_[service.id() + "#" + + std::to_string(service.alternative_index())] = 1; + } else { + alternative_activity_size_map_[service.id() + "#" + + std::to_string(service.alternative_index())] += 1; + } node_index++; } + if (previous_matrix_size == (int32)service_matrix_indices.size()) { + throw std::invalid_argument( + "A Service transmitted should always lead to at least one Node"); + } + previous_matrix_size = service_matrix_indices.size(); ++matrix_index; } @@ -887,62 +859,59 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { size_ = node_index + 2; for (const ortools_vrp::Matrix& matrix : problem.matrices()) { - // + 2 In case vehicles have no depots - int32 problem_size = - std::max(std::max(sqrt(matrix.distance_size()), sqrt(matrix.time_size())), - sqrt(matrix.value_size())) + - 2 + (size_rest_ > 0 ? 1 : 0); - - distances_matrices_.emplace_back(std::max(problem_size, 3)); - times_matrices_.emplace_back(std::max(problem_size, 3)); - values_matrices_.emplace_back(std::max(problem_size, 3)); - - // Matrix default values - for (int64 i = 0; i < std::max(problem_size, 3); ++i) { - for (int64 j = 0; j < std::max(problem_size, 3); ++j) { - SetTimeMatrix(i, j) = 0; - SetDistMatrix(i, j) = 0; - SetValueMatrix(i, j) = 0; - } - } + // Estimate necessary horizon due to time matrix + std::vector max_times(MaxTimes(matrix)); + int64_t matrix_sum_time = 0; + if (matrix.size() > 0) { + const int64_t max_time = std::round(*std::max_element( + max_times.begin(), max_times.end(), compare_less_than_custom_max_int)); - if (matrix.time_size() > 0) { - max_time_ = std::max(max_time_, BuildTimeMatrix(matrix)); - } + if (max_time < CUSTOM_MAX_INT) + max_time_ = std::max(max_time_, max_time); - // Estimate necessary horizon due to time matrix - std::vector max_times(MaxTimes(matrix)); - int64 matrix_sum_time = 0; - if (sqrt(matrix.time_size()) > 0) { - for (std::size_t i = 0; i < matrix_indices.size(); i++) { - matrix_sum_time += max_times.at(matrix_indices[i]); + for (std::size_t i = 0; i < service_matrix_indices.size(); i++) { + matrix_sum_time += max_times.at(service_matrix_indices[i]); } } sum_max_time_ = std::max(sum_max_time_, matrix_sum_time); if (matrix.distance_size() > 0) { - max_distance_ = std::max(max_distance_, BuildDistanceMatrix(matrix)); + const int64 max_distance = + std::round(*std::max_element(matrix.distance().begin(), matrix.distance().end(), + compare_less_than_custom_max_int)); + if (max_distance < CUSTOM_MAX_INT) + max_distance_ = std::max(max_distance_, max_distance); } if (matrix.value_size() > 0) { - max_value_ = std::max(max_value_, BuildValueMatrix(matrix)); + const int64 max_value = + std::round(*std::max_element(matrix.value().begin(), matrix.value().end(), + compare_less_than_custom_max_int)); + if (max_value < CUSTOM_MAX_INT) + max_value_ = std::max(max_value_, max_value); } } // Approximate depot time need sum_max_time_ += 2 * max_time_; - int64 current_day_index = 0; + int64_t current_day_index = 0; int v_idx = 0; day_index_to_vehicle_index_[0] = v_idx; for (const ortools_vrp::Vehicle& vehicle : problem.vehicles()) { - tsptw_vehicles_.emplace_back(this, size_); + if (!vehicle.has_time_window()) { + throw std::invalid_argument( + "A vehicle should always have an initialized timewindow"); + } + + tsptw_vehicles_.emplace_back(this, size_, problem.matrices(vehicle.matrix_index()), + problem.matrices(vehicle.value_matrix_index())); auto v = tsptw_vehicles_.rbegin(); // Every vehicle has its own matrix definition - std::vector vehicle_indices(matrix_indices); - vehicle_indices.push_back(vehicle.start_index()); - vehicle_indices.push_back(vehicle.end_index()); + std::vector matrix_indices(service_matrix_indices); + matrix_indices.push_back(vehicle.start_index()); + matrix_indices.push_back(vehicle.end_index()); for (const ortools_vrp::Capacity& capacity : vehicle.capacities()) { v->capacity.push_back(std::round(capacity.limit() * CUSTOM_BIGNUM_QUANTITY)); @@ -958,31 +927,30 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { v->counting.push_back(capacity.counting()); } - v->id = vehicle.id(); - v->vehicle_index = v_idx; - v->break_size = vehicle.rests().size(); - v->problem_matrix_index = vehicle.matrix_index(); - v->value_matrix_index = vehicle.value_matrix_index(); - v->vehicle_indices = vehicle_indices; - v->time_start = vehicle.time_window().start() > -CUSTOM_MAX_INT - ? vehicle.time_window().start() - : -CUSTOM_MAX_INT; - v->time_end = vehicle.time_window().end() < CUSTOM_MAX_INT - ? vehicle.time_window().end() + v->id = vehicle.id(); + v->vehicle_index = v_idx; + v->break_size = vehicle.rests().size(); + v->start_point_id = vehicle.start_point_id(); + v->matrix_indices = matrix_indices; + v->time_start = (vehicle.time_window().start() - earliest_start_) > 0 + ? vehicle.time_window().start() - earliest_start_ + : 0; + v->time_end = (vehicle.time_window().end() - earliest_start_) < CUSTOM_MAX_INT + ? vehicle.time_window().end() - earliest_start_ : CUSTOM_MAX_INT; v->time_maximum_lateness = vehicle.time_window().maximum_lateness() < CUSTOM_MAX_INT ? vehicle.time_window().maximum_lateness() : CUSTOM_MAX_INT; - v->late_multiplier = (int64)(vehicle.cost_late_multiplier() * CUSTOM_BIGNUM_COST); - v->cost_fixed = (int64)(vehicle.cost_fixed() * CUSTOM_BIGNUM_COST); + v->late_multiplier = (int64_t)(vehicle.cost_late_multiplier() * CUSTOM_BIGNUM_COST); + v->cost_fixed = (int64_t)(vehicle.cost_fixed() * CUSTOM_BIGNUM_COST); v->cost_distance_multiplier = - (int64)(vehicle.cost_distance_multiplier() * CUSTOM_BIGNUM_COST); + (int64_t)(vehicle.cost_distance_multiplier() * CUSTOM_BIGNUM_COST); v->cost_time_multiplier = - (int64)(vehicle.cost_time_multiplier() * CUSTOM_BIGNUM_COST); + (int64_t)(vehicle.cost_time_multiplier() * CUSTOM_BIGNUM_COST); v->cost_waiting_time_multiplier = - (int64)(vehicle.cost_waiting_time_multiplier() * CUSTOM_BIGNUM_COST); + (int64_t)(vehicle.cost_waiting_time_multiplier() * CUSTOM_BIGNUM_COST); v->cost_value_multiplier = - (int64)(vehicle.cost_value_multiplier() * CUSTOM_BIGNUM_COST); + (int64_t)(vehicle.cost_value_multiplier() * CUSTOM_BIGNUM_COST); v->coef_service = vehicle.coef_service(); max_coef_service_ = std::max(max_coef_service_, v->coef_service); @@ -991,7 +959,7 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { max_coef_setup_ = std::max(max_coef_setup_, v->coef_setup); v->additional_setup = vehicle.additional_setup(); - v->duration = (int64)(vehicle.duration()); + v->duration = (int64_t)(vehicle.duration()); v->distance = vehicle.distance(); v->free_approach = vehicle.free_approach(); v->free_return = vehicle.free_return(); @@ -1020,8 +988,9 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { // Add vehicle rests for (const ortools_vrp::Rest& rest : vehicle.rests()) { - v->rests.emplace_back((std::string)rest.id(), rest.time_window().start(), - rest.time_window().end(), rest.duration()); + v->rests.emplace_back((std::string)rest.id(), + rest.time_window().start() - earliest_start_, + rest.time_window().end() - earliest_start_, rest.duration()); } v_idx++; @@ -1039,13 +1008,14 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { tsptw_routes_.push_back(r); } - int re_index = 0; - int64 sum_lapse = 0; + int re_index = 0; + int64_t sum_lapse = 0; // Setting start for (Vehicle& v : tsptw_vehicles_) { v.start = RoutingIndexManager::NodeIndex(node_index); } - tsptw_clients_.push_back(TSPTWClient("vehicles_start", matrix_index, node_index)); + tsptw_clients_.push_back( + TSPTWClient("vehicles_start", "vehicles_start", matrix_index, node_index)); service_times_.push_back(0); node_index++; @@ -1054,7 +1024,8 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { v.stop = RoutingIndexManager::NodeIndex(node_index); } // node_index++; - tsptw_clients_.push_back(TSPTWClient("vehicles_end", ++matrix_index, node_index)); + tsptw_clients_.push_back( + TSPTWClient("vehicles_end", "vehicles_end", ++matrix_index, node_index)); service_times_.push_back(0); for (const ortools_vrp::Relation& relation : problem.relations()) { @@ -1101,7 +1072,7 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { else if (relation.type() == "minimum_duration_lapse") relType = MinimumDurationLapse; else - throw "Unknown relation type"; + throw std::invalid_argument("Unknown relation type"); sum_lapse += relation.lapse(); tsptw_relations_.emplace_back(re_index, relType, relation.linked_ids(), @@ -1110,7 +1081,7 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { } // Compute horizon - int64 rest_duration; + int64_t rest_duration; for (std::size_t v = 0; v < tsptw_vehicles_.size(); v++) { rest_duration = 0; for (std::size_t r = 0; r < tsptw_vehicles_[v].Rests().size(); r++) { @@ -1130,15 +1101,15 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { } for (std::size_t v = 0; v < tsptw_vehicles_.size(); v++) { for (std::size_t r = 0; r < tsptw_vehicles_[v].Rests().size(); r++) { - horizon_ = std::max(horizon_, tsptw_vehicles_[v].Rests()[r].due_time); + horizon_ = std::max(horizon_, tsptw_vehicles_[v].Rests()[r].due_time); } } } else { - int64 latest_start = 0; - int64 latest_rest_end = 0; - int64 sum_service = 0; - int64 sum_setup = 0; - for (int32 i = 0; i < size_missions_; ++i) { + int64_t latest_start = 0; + int64_t latest_rest_end = 0; + int64_t sum_service = 0; + int64_t sum_setup = 0; + for (int32_t i = 0; i < size_missions_; ++i) { sum_service += tsptw_clients_[i].service_time; sum_setup += tsptw_clients_[i].setup_time; if (tsptw_clients_[i].ready_time.size() > 0) { @@ -1150,7 +1121,7 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { for (std::size_t r = 0; r < tsptw_vehicles_[v].Rests().size(); r++) { latest_rest_end = - std::max(latest_rest_end, tsptw_vehicles_[v].Rests()[r].due_time); + std::max(latest_rest_end, tsptw_vehicles_[v].Rests()[r].due_time); } } horizon_ = std::max(latest_start, latest_rest_end) + sum_service * max_coef_service_ + @@ -1160,7 +1131,7 @@ void TSPTWDataDT::LoadInstance(const std::string& filename) { if (size_alternative_relations_ > 0) horizon_ += size_missions_; - for (int32 i = 0; i < size_missions_; ++i) { + for (int32_t i = 0; i < size_missions_; ++i) { max_service_ = std::max(max_service_, tsptw_clients_[i].service_time); } } diff --git a/values.h b/values.h index 4ff8e888..116435e9 100644 --- a/values.h +++ b/values.h @@ -9,7 +9,7 @@ class RoutingValues { struct NodeValue { NodeValue() : initial_time_value(-1) {} - int64 initial_time_value; + int64_t initial_time_value; }; std::vector& NodeValues() { return node_values; }