max distance is now weighted by hours

This commit is contained in:
2018-11-14 19:57:35 +04:00
parent d288cf4f9e
commit 6f06b10388
7 changed files with 67 additions and 56 deletions

View File

@@ -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

View File

@@ -84,6 +84,8 @@
method="post">
{% csrf_token %}
<input class="btn btn-primary" type="submit" value="Cоздать">
<div class="card">
<div class="card-header">
<a class="card-link" data-toggle="collapse" href="#params-table-collapse">