From 6f06b10388aca0aa12f2bc27d70cd690b295d1e0 Mon Sep 17 00:00:00 2001 From: svxf Date: Wed, 14 Nov 2018 19:57:35 +0400 Subject: [PATCH] max distance is now weighted by hours --- Pipfile | 1 + Pipfile.lock | 10 +++- run.sh | 12 ---- src/optimizer/process/solver.py | 87 ++++++++++++++-------------- src/optimizer/templates/problem.html | 2 + src/rzhdweb/settings.py | 2 +- update.sh | 9 +++ 7 files changed, 67 insertions(+), 56 deletions(-) delete mode 100755 run.sh create mode 100755 update.sh diff --git a/Pipfile b/Pipfile index 16cdd77..29c2acf 100644 --- a/Pipfile +++ b/Pipfile @@ -10,6 +10,7 @@ numpy = "*" pulp = "*" pandas = "*" xlsxwriter = "*" +xlrd = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 1e2e889..71360eb 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "707c3088da92d8c5a3d4d4ace89682526e43dfa8f0104d4709bd0a80453c41cc" + "sha256": "07c3eee4c958d61e36cca97fe6439457f2a852af45d00c03c21ef593b27fb406" }, "pipfile-spec": 6, "requires": { @@ -148,6 +148,14 @@ ], "version": "==1.11.0" }, + "xlrd": { + "hashes": [ + "sha256:83a1d2f1091078fb3f65876753b5302c5cfb6a41de64b9587b74cefa75157148", + "sha256:8a21885513e6d915fe33a8ee5fdfa675433b61405ba13e2a69e62ee36828d7e2" + ], + "index": "pypi", + "version": "==1.1.0" + }, "xlsxwriter": { "hashes": [ "sha256:7cc07619760641b67112dbe0df938399d4d915d9b9924bb58eb5c17384d29cc6", diff --git a/run.sh b/run.sh deleted file mode 100755 index 5a0d0d1..0000000 --- a/run.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env zsh - -set euxo PIPEFAIL - -export PIPENV_VENV_IN_PROJECT=1 -export PYTHONPATH=src/ - -git pull - -pipenv install - -pipenv run python3.7 src/manage.py runserver 2716 diff --git a/src/optimizer/process/solver.py b/src/optimizer/process/solver.py index 0a9474c..682b732 100644 --- a/src/optimizer/process/solver.py +++ b/src/optimizer/process/solver.py @@ -55,8 +55,8 @@ class LPSolver: [self._distance_name_to_id[t.distance.name] for t in self.tasks], dtype=int) - self._expected_worker_ratio = np.array([w.hours for w in self.workers], dtype=float) - self._expected_worker_ratio /= np.sum(self._expected_worker_ratio) + self._worker_hours = np.array([w.hours for w in self.workers], dtype=float) + self._expected_worker_ratio = self._worker_hours / np.sum(self._worker_hours) self._expected_worker_km = self._expected_worker_ratio * np.sum(self._task_kms) self._expected_worker_sp = self._expected_worker_ratio * np.sum(self._task_sps) @@ -83,75 +83,78 @@ class LPSolver: # Worker x Task binary choice matrix self._worker_task_choices = np.zeros((self.worker_n, self.task_n), dtype=object) - for w_i in range(self.worker_n): - for t_i in range(self.task_n): - self._worker_task_choices[w_i, t_i] = \ - pulp.LpVariable(f'worker_task_choice[{w_i},{t_i}]', None, None, pulp.LpBinary) + for worker_id in range(self.worker_n): + for task_id in range(self.task_n): + self._worker_task_choices[worker_id, task_id] = \ + pulp.LpVariable(f'worker_task_choice[{worker_id},{task_id}]', None, None, pulp.LpBinary) # Worker task counts worker_task_counts = np.zeros(self.worker_n, dtype=object) - for w_i in range(self.worker_n): - worker_task_counts[w_i] = pulp.lpSum(self._worker_task_choices[w_i, :]) + for worker_id in range(self.worker_n): + worker_task_counts[worker_id] = pulp.lpSum(self._worker_task_choices[worker_id, :]) # Restriction: one worker per task - for t_i in range(self.task_n): - self.lp_problem += pulp.lpSum(self._worker_task_choices[:, t_i]) == 1 + for task_id in range(self.task_n): + self.lp_problem += pulp.lpSum(self._worker_task_choices[:, task_id]) == 1 # Worker x Distance task counts worker_distance_task_counts = np.zeros((self.worker_n, self.distance_n), dtype=object) - for w_i in range(self.worker_n): - for t_i in range(self.task_n): - d_i = self._task_distances[t_i] - worker_distance_task_counts[w_i, d_i] += self._worker_task_choices[w_i, t_i] + for worker_id in range(self.worker_n): + for task_id in range(self.task_n): + distance_id = self._task_distances[task_id] + worker_distance_task_counts[worker_id, distance_id] += self._worker_task_choices[worker_id, task_id] # Worker x Distance binary choice matrix worker_distance_choices = np.zeros((self.worker_n, self.distance_n), dtype=object) - for w_i in range(self.worker_n): - for d_i in range(self.distance_n): - worker_distance_choices[w_i, d_i] = \ - pulp.LpVariable(f'DistanceChoice[w{w_i},d{d_i}]', None, None, pulp.LpBinary) + for worker_id in range(self.worker_n): + for distance_id in range(self.distance_n): + worker_distance_choices[worker_id, distance_id] = \ + pulp.LpVariable(f'DistanceChoice[w{worker_id},d{distance_id}]', None, None, pulp.LpBinary) # Restriction: Distance choices are an upper bound on Task choices - for w_i in range(self.worker_n): - for t_i in range(self.task_n): - d_i = self._task_distances[t_i] - self.lp_problem += worker_distance_choices[w_i, d_i] >= self._worker_task_choices[w_i, t_i] + for worker_id in range(self.worker_n): + for task_id in range(self.task_n): + distance_id = self._task_distances[task_id] + self.lp_problem += worker_distance_choices[worker_id, distance_id] >= self._worker_task_choices[ + worker_id, task_id] # Restriction: km, sp and agg diffs are in specified intervals - for w_i in range(self.worker_n): - worker_km = pulp.lpDot(self._worker_task_choices[w_i, :], self._task_kms) - self.lp_problem += worker_km >= self._expected_worker_km[w_i] - max_km_diff - self.lp_problem += worker_km <= self._expected_worker_km[w_i] + max_km_diff + for worker_id in range(self.worker_n): + worker_km = pulp.lpDot(self._worker_task_choices[worker_id, :], self._task_kms) + self.lp_problem += worker_km >= self._expected_worker_km[worker_id] - max_km_diff + self.lp_problem += worker_km <= self._expected_worker_km[worker_id] + max_km_diff - worker_sp = pulp.lpDot(self._worker_task_choices[w_i, :], self._task_sps) - self.lp_problem += worker_sp >= self._expected_worker_sp[w_i] - max_sp_diff - self.lp_problem += worker_sp <= self._expected_worker_sp[w_i] + max_sp_diff + worker_sp = pulp.lpDot(self._worker_task_choices[worker_id, :], self._task_sps) + self.lp_problem += worker_sp >= self._expected_worker_sp[worker_id] - max_sp_diff + self.lp_problem += worker_sp <= self._expected_worker_sp[worker_id] + max_sp_diff - worker_agg = pulp.lpDot(self._worker_task_choices[w_i, :], self._task_aggs) - self.lp_problem += worker_agg >= self._expected_worker_agg[w_i] - max_agg_diff - self.lp_problem += worker_agg <= self._expected_worker_agg[w_i] + max_agg_diff + worker_agg = pulp.lpDot(self._worker_task_choices[worker_id, :], self._task_aggs) + self.lp_problem += worker_agg >= self._expected_worker_agg[worker_id] - max_agg_diff + self.lp_problem += worker_agg <= self._expected_worker_agg[worker_id] + max_agg_diff # Restriction: distance counts are below max worker_distance_counts = np.zeros(self.worker_n, dtype=object) - for w_i in range(self.worker_n): - worker_distance_counts[w_i] = pulp.lpSum(worker_distance_choices[w_i, :]) - self.lp_problem += worker_distance_counts[w_i] <= max_distance_count + worker_distance_count_weight = self._worker_hours / np.max(self._worker_hours) + for worker_id in range(self.worker_n): + worker_distance_counts[worker_id] = pulp.lpSum(worker_distance_choices[worker_id, :]) + worker_max_distance_count = max_distance_count * worker_distance_count_weight[worker_id] + self.lp_problem += worker_distance_counts[worker_id] <= worker_max_distance_count # Restriction: avg distance count is below max too worker_avg_dist_count = pulp.lpSum(worker_distance_counts) / self.worker_n self.lp_problem += worker_avg_dist_count <= avg_distance_count # Restriction: task counts are in specified intervals - for w_i in range(self.worker_n): - self.lp_problem += worker_task_counts[w_i] <= max_task_count + for worker_id in range(self.worker_n): + self.lp_problem += worker_task_counts[worker_id] <= max_task_count # Restriction: critical distances - for w_i in range(self.worker_n): - for cd_i in range(self.critical_distances_n): - d_i = self._critical_distances[cd_i] - bound = self._critical_distance_bounds[cd_i] + for worker_id in range(self.worker_n): + for critical_distance_id in range(self.critical_distances_n): + distance_id = self._critical_distances[critical_distance_id] + bound = self._critical_distance_bounds[critical_distance_id] - self.lp_problem += worker_distance_task_counts[w_i, d_i] <= bound + self.lp_problem += worker_distance_task_counts[worker_id, distance_id] <= bound # Restrictions: params self.lp_problem += max_km_diff <= self.param_set.restriction_max_km_diff.value diff --git a/src/optimizer/templates/problem.html b/src/optimizer/templates/problem.html index ca2afe3..d06bcd8 100644 --- a/src/optimizer/templates/problem.html +++ b/src/optimizer/templates/problem.html @@ -84,6 +84,8 @@ method="post"> {% csrf_token %} + +