From be8aed1dd3fe97768399a020409ad6672cd6538b Mon Sep 17 00:00:00 2001 From: halilsen Date: Thu, 16 Apr 2020 15:13:02 +0200 Subject: [PATCH 1/9] Log: infeasible service count --- wrappers/wrapper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wrappers/wrapper.rb b/wrappers/wrapper.rb index e1c1b8037..658c31943 100644 --- a/wrappers/wrapper.rb +++ b/wrappers/wrapper.rb @@ -730,6 +730,8 @@ def check_distances(vrp, unfeasible) log "Following services marked as infeasible:\n#{unfeasible.group_by{ |u| u[:reason] }.collect{ |g, set| "#{(set.size < 20) ? set.collect{ |s| s[:service_id] }.join(', ') : "#{set.size} services"}\n with reason '#{g}'" }.join("\n")}", level: :debug unless unfeasible.empty? + log "#{unfeasible.size} services marked as infeasible with the following reasons: #{unfeasible.collect{ |u| u[:reason] }.uniq.join(', ')}", level: :info unless unfeasible.empty? + unfeasible end From 69d7f4182b82a0fda68d68006bf17258f749808b Mon Sep 17 00:00:00 2001 From: halilsen Date: Tue, 21 Apr 2020 16:11:04 +0200 Subject: [PATCH 2/9] Fix: sentry due to empty json --- api/v01/vrp.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/v01/vrp.rb b/api/v01/vrp.rb index e6ddd7be7..cb11eda33 100644 --- a/api/v01/vrp.rb +++ b/api/v01/vrp.rb @@ -528,6 +528,8 @@ def self.vrp_request_schedule(this) optional(:configuration, type: Hash, documentation: { hidden: true, desc: 'Describe the limitations of the solve in term of computation' }, coerce_with: ->(c) { c.has_key?('filename') ? JSON.parse(c.tempfile.read) : c }) do Vrp.vrp_request_configuration(self) end + + exactly_one_of :vrp, :vehicles # either it is a json (and :vrp is required) or it is a csv (and :vehicles is required) } post do begin From a05c95b12f589dce650615aa2b2e11e236eeac4e Mon Sep 17 00:00:00 2001 From: halilsen Date: Thu, 23 Apr 2020 21:34:11 +0200 Subject: [PATCH 3/9] Fix: sentry due to negative timelimit --- lib/interpreters/compute_several_solutions.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/interpreters/compute_several_solutions.rb b/lib/interpreters/compute_several_solutions.rb index 4d45b649f..30a9a33b6 100644 --- a/lib/interpreters/compute_several_solutions.rb +++ b/lib/interpreters/compute_several_solutions.rb @@ -162,7 +162,8 @@ def self.find_best_heuristic(service_vrp) if custom_heuristics.size > 1 log '---> find_best_heuristic' tic = Time.now - total_time_allocated_for_heuristic_selection = service_vrp[:vrp].resolution_duration.to_f * 0.30 # spend at most 30% of the total time for heuristic selection + percent_allocated_to_heur_selection = 0.3 # spend at most 30% of the total time for heuristic selection + total_time_allocated_for_heuristic_selection = service_vrp[:vrp].resolution_duration.to_f * percent_allocated_to_heur_selection batched_service_vrps = batch_heuristic([service_vrp], custom_heuristics).flatten(1) times = [] first_results = batched_service_vrps.collect{ |s_vrp| @@ -202,7 +203,7 @@ def self.find_best_heuristic(service_vrp) vrp.resolution_batch_heuristic = nil vrp.preprocessing_first_solution_strategy = [best_heuristic] vrp.preprocessing_heuristic_synthesis = synthesis - vrp.resolution_duration = vrp.resolution_duration ? (vrp.resolution_duration - times.sum).floor : nil + vrp.resolution_duration = vrp.resolution_duration ? [(vrp.resolution_duration.to_f * (1 - percent_allocated_to_heur_selection)).round, 1000].max : nil log "<--- find_best_heuristic elapsed: #{Time.now - tic}sec selected heuristic: #{best_heuristic}" else vrp.preprocessing_first_solution_strategy = custom_heuristics From 2228097746d599845eca6fb5540b12add35c7ec1 Mon Sep 17 00:00:00 2001 From: halilsen Date: Thu, 18 Jun 2020 16:49:37 +0200 Subject: [PATCH 4/9] Logger: add getter and fix nil error --- util/logger.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/logger.rb b/util/logger.rb index 4849a602c..d8b8ea265 100644 --- a/util/logger.rb +++ b/util/logger.rb @@ -42,7 +42,7 @@ class OptimizerLogger @@logger.formatter = proc do |severity, datetime, progname, msg| datetime = OptimizerLogger.with_datetime ? "[#{datetime}]" : nil job_id = OptimizerWrapper::Job.current_job_id ? "#{OptimizerWrapper::Job.current_job_id} -" : nil - progname = progname.empty? ? nil : "- #{progname}" + progname = progname&.empty? ? nil : "- #{progname}" [datetime, job_id, severity, progname].compact.join(' ') + ": #{msg}\n" end @@ -104,6 +104,10 @@ def self.log_device=(logdev) @@logger.reopen logdev end + def self.logger + @@logger + end + def self.formatter=(formatter) @@logger.formatter = formatter end From e3a0fd541e76f38462dd124494cb1327142626ac Mon Sep 17 00:00:00 2001 From: halilsen Date: Mon, 22 Jun 2020 16:42:20 +0200 Subject: [PATCH 5/9] Travis: correct time limit --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 896ef701d..26a03d291 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,25 +13,25 @@ jobs: - stage: "Tests" install: skip env: TEST_SUITE='basis' - script: bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='dicho' install: skip - script: travis_wait 60 bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='scheduling' install: skip - script: bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='real_scheduling' install: skip - script: travis_wait 60 bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='real_scheduling_solver' install: skip - script: travis_wait 60 bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='split_clustering' install: skip - script: bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - env: TEST_SUITE='real' install: skip - script: bash ci-utils/tests.sh ${TEST_SUITE} + script: travis_wait 50 bash ci-utils/tests.sh ${TEST_SUITE} - stage: deploy name: "Deploy" install: skip From b0bd00bb7528cefe15341a5341bcbfa974f0ce56 Mon Sep 17 00:00:00 2001 From: halilsen Date: Tue, 23 Jun 2020 10:51:52 +0200 Subject: [PATCH 6/9] Test: fix broken test due to ortools fist_soln_st --- .../minimum_duration_lapse_shipments.dump | Bin 59103 -> 59095 bytes .../minimum_duration_lapse_shipments.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/minimum_duration_lapse_shipments.dump b/test/fixtures/minimum_duration_lapse_shipments.dump index 2660a35195157a30167b47d7b4dc6e705995aa1f..bc1b22c6889826f1a36e5a4c2a848feba9761b03 100644 GIT binary patch delta 18539 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 delta 18616 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 diff --git a/test/fixtures/minimum_duration_lapse_shipments.json b/test/fixtures/minimum_duration_lapse_shipments.json index 8c0aae5cb..b29dfb4b6 100644 --- a/test/fixtures/minimum_duration_lapse_shipments.json +++ b/test/fixtures/minimum_duration_lapse_shipments.json @@ -889,7 +889,7 @@ "resolution": { "vehicle_limit": 6, "minimum_duration": null, - "duration": 6000 + "duration": 15000 } }, "name": null From f88103bb4d23a002d67dc014767b3050f27afb2c Mon Sep 17 00:00:00 2001 From: halilsen Date: Tue, 23 Jun 2020 18:06:42 +0200 Subject: [PATCH 7/9] Fix: ortools version output --- wrappers/ortools.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/ortools.rb b/wrappers/ortools.rb index d93d84a1a..fb21d5c6d 100644 --- a/wrappers/ortools.rb +++ b/wrappers/ortools.rb @@ -819,7 +819,7 @@ def run_ortools(problem, vrp, services, points, matrix_indices, thread_proc = ni s && (cost = Float(s[1])) t = /Time : ([0-9.eE+]+)/.match(line) t && (time = t[1].to_f) - log line.strip, level: (/Final Iteration :/.match(line) || /First solution strategy :/.match(line) || /Using initial solution provided./.match(line) || /OR-Tools v[0-9]+\.[0-9]+\.[0-9]+\n/.match(line)) ? :info : (r || s || t) ? :debug : :error + log line.strip, level: (/Final Iteration :/.match(line) || /First solution strategy :/.match(line) || /Using initial solution provided./.match(line) || /OR-Tools v[0-9]+\.[0-9]+\n/.match(line)) ? :info : (r || s || t) ? :debug : :error out += line next unless r && t # if there is no iteration and time then there is nothing to do From 1fe69866df654612e9e3f03578d658fa349566a6 Mon Sep 17 00:00:00 2001 From: halilsen Date: Tue, 23 Jun 2020 19:12:47 +0200 Subject: [PATCH 8/9] Test: filtered infeasible service in initial route --- test/wrapper_test.rb | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/wrapper_test.rb b/test/wrapper_test.rb index 11272bb66..5ff075783 100644 --- a/test/wrapper_test.rb +++ b/test/wrapper_test.rb @@ -3046,4 +3046,28 @@ def test_detecting_unfeasible_services_can_not_take_too_long assert_operator total_time, :<=, 14.0 end + + def test_initial_route_with_infeasible_service + # service_1 is eliminated due to + # "Incompatibility between service skills and sticky vehicles" + # but it is referenced inside an initial route which should not cause an issue + problem = VRP.basic + + problem[:vehicles] += [{ + id: 'vehicle_1', + matrix_id: 'matrix_0', + start_point_id: 'point_0', + skills: [['vehicle_1']] + }] + + problem[:services][0][:skills] = ['vehicle_1'] + problem[:services][0][:sticky_vehicle_ids] = ['vehicle_0'] + + problem[:routes] = [{ + vehicle_id: 'vehicle_0', + mission_ids: ['service_1', 'service_2', 'service_3'] + }] + + assert OptimizerWrapper.wrapper_vrp('demo', { services: { vrp: [:ortools] }}, TestHelper.create(problem), nil) + end end From 69f9baf39d70610509564eb19ec579e72b2b70f5 Mon Sep 17 00:00:00 2001 From: Braktar Date: Tue, 23 Jun 2020 17:25:14 +0200 Subject: [PATCH 9/9] Travis PR --- .travis.yml | 3 ++- ci-utils/version.sh | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100755 ci-utils/version.sh diff --git a/.travis.yml b/.travis.yml index 26a03d291..c24ab892a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ services: before_install: - export REGISTRY=${REGISTRY:-registry.mapotempo.com/} - - docker build --build-arg VROOM_VERSION=${VROOM_VERSION:-v1.2.0} --build-arg OPTIMIZER_ORTOOLS_VERSION=${OPTIMIZER_ORTOOLS_VERSION:-v1.3.0} -f docker/Dockerfile -t registry.test.com/mapotempo/optimizer-api:latest . + - source ci-utils/version.sh + - docker build --build-arg VROOM_VERSION=${VROOM_VERSION:-v1.2.0} --build-arg OPTIMIZER_ORTOOLS_VERSION=$OPTIMIZER_ORTOOLS_VERSION -f docker/Dockerfile -t registry.test.com/mapotempo/optimizer-api:latest . - docker swarm init - mkdir -p ./redis - docker stack deploy -c ./docker/docker-compose.yml optimizer diff --git a/ci-utils/version.sh b/ci-utils/version.sh new file mode 100755 index 000000000..2ab6aed85 --- /dev/null +++ b/ci-utils/version.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [[ $TRAVIS_BRANCH == "master" ]] || [[ $TRAVIS_TAG != "" ]]; then + export OPTIMIZER_ORTOOLS_VERSION="v1.3.0"; +else + export OPTIMIZER_ORTOOLS_VERSION=${OPTIMIZER_ORTOOLS_VERSION:-Mapotempo}; +fi