max distance is now weighted by hours
This commit is contained in:
1
Pipfile
1
Pipfile
@@ -10,6 +10,7 @@ numpy = "*"
|
|||||||
pulp = "*"
|
pulp = "*"
|
||||||
pandas = "*"
|
pandas = "*"
|
||||||
xlsxwriter = "*"
|
xlsxwriter = "*"
|
||||||
|
xlrd = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
|
||||||
|
10
Pipfile.lock
generated
10
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "707c3088da92d8c5a3d4d4ace89682526e43dfa8f0104d4709bd0a80453c41cc"
|
"sha256": "07c3eee4c958d61e36cca97fe6439457f2a852af45d00c03c21ef593b27fb406"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
@@ -148,6 +148,14 @@
|
|||||||
],
|
],
|
||||||
"version": "==1.11.0"
|
"version": "==1.11.0"
|
||||||
},
|
},
|
||||||
|
"xlrd": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:83a1d2f1091078fb3f65876753b5302c5cfb6a41de64b9587b74cefa75157148",
|
||||||
|
"sha256:8a21885513e6d915fe33a8ee5fdfa675433b61405ba13e2a69e62ee36828d7e2"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
"xlsxwriter": {
|
"xlsxwriter": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:7cc07619760641b67112dbe0df938399d4d915d9b9924bb58eb5c17384d29cc6",
|
"sha256:7cc07619760641b67112dbe0df938399d4d915d9b9924bb58eb5c17384d29cc6",
|
||||||
|
12
run.sh
12
run.sh
@@ -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
|
|
@@ -55,8 +55,8 @@ class LPSolver:
|
|||||||
[self._distance_name_to_id[t.distance.name] for t in self.tasks],
|
[self._distance_name_to_id[t.distance.name] for t in self.tasks],
|
||||||
dtype=int)
|
dtype=int)
|
||||||
|
|
||||||
self._expected_worker_ratio = np.array([w.hours for w in self.workers], dtype=float)
|
self._worker_hours = np.array([w.hours for w in self.workers], dtype=float)
|
||||||
self._expected_worker_ratio /= np.sum(self._expected_worker_ratio)
|
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_km = self._expected_worker_ratio * np.sum(self._task_kms)
|
||||||
self._expected_worker_sp = self._expected_worker_ratio * np.sum(self._task_sps)
|
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
|
# Worker x Task binary choice matrix
|
||||||
self._worker_task_choices = np.zeros((self.worker_n, self.task_n), dtype=object)
|
self._worker_task_choices = np.zeros((self.worker_n, self.task_n), dtype=object)
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
for t_i in range(self.task_n):
|
for task_id in range(self.task_n):
|
||||||
self._worker_task_choices[w_i, t_i] = \
|
self._worker_task_choices[worker_id, task_id] = \
|
||||||
pulp.LpVariable(f'worker_task_choice[{w_i},{t_i}]', None, None, pulp.LpBinary)
|
pulp.LpVariable(f'worker_task_choice[{worker_id},{task_id}]', None, None, pulp.LpBinary)
|
||||||
|
|
||||||
# Worker task counts
|
# Worker task counts
|
||||||
worker_task_counts = np.zeros(self.worker_n, dtype=object)
|
worker_task_counts = np.zeros(self.worker_n, dtype=object)
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
worker_task_counts[w_i] = pulp.lpSum(self._worker_task_choices[w_i, :])
|
worker_task_counts[worker_id] = pulp.lpSum(self._worker_task_choices[worker_id, :])
|
||||||
|
|
||||||
# Restriction: one worker per task
|
# Restriction: one worker per task
|
||||||
for t_i in range(self.task_n):
|
for task_id in range(self.task_n):
|
||||||
self.lp_problem += pulp.lpSum(self._worker_task_choices[:, t_i]) == 1
|
self.lp_problem += pulp.lpSum(self._worker_task_choices[:, task_id]) == 1
|
||||||
|
|
||||||
# Worker x Distance task counts
|
# Worker x Distance task counts
|
||||||
worker_distance_task_counts = np.zeros((self.worker_n, self.distance_n), dtype=object)
|
worker_distance_task_counts = np.zeros((self.worker_n, self.distance_n), dtype=object)
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
for t_i in range(self.task_n):
|
for task_id in range(self.task_n):
|
||||||
d_i = self._task_distances[t_i]
|
distance_id = self._task_distances[task_id]
|
||||||
worker_distance_task_counts[w_i, d_i] += self._worker_task_choices[w_i, t_i]
|
worker_distance_task_counts[worker_id, distance_id] += self._worker_task_choices[worker_id, task_id]
|
||||||
|
|
||||||
# Worker x Distance binary choice matrix
|
# Worker x Distance binary choice matrix
|
||||||
worker_distance_choices = np.zeros((self.worker_n, self.distance_n), dtype=object)
|
worker_distance_choices = np.zeros((self.worker_n, self.distance_n), dtype=object)
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
for d_i in range(self.distance_n):
|
for distance_id in range(self.distance_n):
|
||||||
worker_distance_choices[w_i, d_i] = \
|
worker_distance_choices[worker_id, distance_id] = \
|
||||||
pulp.LpVariable(f'DistanceChoice[w{w_i},d{d_i}]', None, None, pulp.LpBinary)
|
pulp.LpVariable(f'DistanceChoice[w{worker_id},d{distance_id}]', None, None, pulp.LpBinary)
|
||||||
|
|
||||||
# Restriction: Distance choices are an upper bound on Task choices
|
# Restriction: Distance choices are an upper bound on Task choices
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
for t_i in range(self.task_n):
|
for task_id in range(self.task_n):
|
||||||
d_i = self._task_distances[t_i]
|
distance_id = self._task_distances[task_id]
|
||||||
self.lp_problem += worker_distance_choices[w_i, d_i] >= self._worker_task_choices[w_i, t_i]
|
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
|
# Restriction: km, sp and agg diffs are in specified intervals
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
worker_km = pulp.lpDot(self._worker_task_choices[w_i, :], self._task_kms)
|
worker_km = pulp.lpDot(self._worker_task_choices[worker_id, :], 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[worker_id] - max_km_diff
|
||||||
self.lp_problem += worker_km <= self._expected_worker_km[w_i] + 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)
|
worker_sp = pulp.lpDot(self._worker_task_choices[worker_id, :], 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[worker_id] - max_sp_diff
|
||||||
self.lp_problem += worker_sp <= self._expected_worker_sp[w_i] + 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)
|
worker_agg = pulp.lpDot(self._worker_task_choices[worker_id, :], 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[worker_id] - max_agg_diff
|
||||||
self.lp_problem += worker_agg <= self._expected_worker_agg[w_i] + max_agg_diff
|
self.lp_problem += worker_agg <= self._expected_worker_agg[worker_id] + max_agg_diff
|
||||||
|
|
||||||
# Restriction: distance counts are below max
|
# Restriction: distance counts are below max
|
||||||
worker_distance_counts = np.zeros(self.worker_n, dtype=object)
|
worker_distance_counts = np.zeros(self.worker_n, dtype=object)
|
||||||
for w_i in range(self.worker_n):
|
worker_distance_count_weight = self._worker_hours / np.max(self._worker_hours)
|
||||||
worker_distance_counts[w_i] = pulp.lpSum(worker_distance_choices[w_i, :])
|
for worker_id in range(self.worker_n):
|
||||||
self.lp_problem += worker_distance_counts[w_i] <= max_distance_count
|
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
|
# Restriction: avg distance count is below max too
|
||||||
worker_avg_dist_count = pulp.lpSum(worker_distance_counts) / self.worker_n
|
worker_avg_dist_count = pulp.lpSum(worker_distance_counts) / self.worker_n
|
||||||
self.lp_problem += worker_avg_dist_count <= avg_distance_count
|
self.lp_problem += worker_avg_dist_count <= avg_distance_count
|
||||||
|
|
||||||
# Restriction: task counts are in specified intervals
|
# Restriction: task counts are in specified intervals
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
self.lp_problem += worker_task_counts[w_i] <= max_task_count
|
self.lp_problem += worker_task_counts[worker_id] <= max_task_count
|
||||||
|
|
||||||
# Restriction: critical distances
|
# Restriction: critical distances
|
||||||
for w_i in range(self.worker_n):
|
for worker_id in range(self.worker_n):
|
||||||
for cd_i in range(self.critical_distances_n):
|
for critical_distance_id in range(self.critical_distances_n):
|
||||||
d_i = self._critical_distances[cd_i]
|
distance_id = self._critical_distances[critical_distance_id]
|
||||||
bound = self._critical_distance_bounds[cd_i]
|
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
|
# Restrictions: params
|
||||||
self.lp_problem += max_km_diff <= self.param_set.restriction_max_km_diff.value
|
self.lp_problem += max_km_diff <= self.param_set.restriction_max_km_diff.value
|
||||||
|
@@ -84,6 +84,8 @@
|
|||||||
method="post">
|
method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<input class="btn btn-primary" type="submit" value="Cоздать">
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<a class="card-link" data-toggle="collapse" href="#params-table-collapse">
|
<a class="card-link" data-toggle="collapse" href="#params-table-collapse">
|
||||||
|
@@ -13,7 +13,7 @@ import datetime
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
|
||||||
|
Reference in New Issue
Block a user