File size: 7,347 Bytes
db26c81 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
import json
from greedrl.feature import *
from greedrl.variable import *
from greedrl.function import *
from greedrl import Problem
features = [local_category('task_order'),
global_category('task_type', 2),
global_category('task_new_order', 2),
variable_feature('time_this_to_task'),
continuous_feature('x_time_matrix'),
continuous_feature('task_due_time_x'),
continuous_feature('worker_task_mask')]
variables = [task_demand_now('task_demand_now', feature='task_demand'),
task_demand_now('task_demand_this', feature='task_demand', only_this=True),
task_variable('task_pickup_this', feature='task_pickup'),
task_variable('task_due_time_this', feature='task_due_time'),
feature_variable('task_order', feature='task_order'),
feature_variable('task_type', feature='task_type'),
feature_variable('task_new_pickup', feature='task_new_pickup'),
feature_variable('worker_task_mask', feature='worker_task_mask'),
worker_count_now('worker_count_now', feature='worker_count'),
worker_variable('worker_min_old_task_this', feature='worker_min_old_task'),
worker_variable('worker_max_new_order_this', feature='worker_max_new_order'),
worker_variable('worker_task_mask_this', feature='worker_task_mask'),
worker_used_resource('worker_used_old_task', task_require='task_old'),
worker_used_resource('worker_used_new_order', task_require='task_new_pickup'),
worker_used_resource('worker_used_time', edge_require='time_matrix'),
edge_variable('time_this_to_task', feature='x_time_matrix', this_to_task=True)]
class Constraint:
def do_task(self):
return self.task_demand_this
def mask_worker_start(self):
mask = self.worker_count_now <= 0
finished = self.task_demand_now <= 0
worker_task_mask = self.worker_task_mask | finished[:, None, :]
mask |= torch.all(worker_task_mask, 2)
return mask
def mask_worker_end(self):
mask = self.worker_used_old_task < self.worker_min_old_task_this
mask |= task_group_split(self.task_order, self.task_demand_now <= 0)
return mask
def mask_task(self):
mask = self.task_demand_now <= 0
mask |= task_group_priority(self.task_order, self.task_type, mask)
worker_max_new_order = self.worker_max_new_order_this - self.worker_used_new_order
mask |= self.task_new_pickup > worker_max_new_order[:, None]
mask |= self.worker_task_mask_this
return mask
def finished(self):
worker_mask = self.worker_count_now <= 0
task_mask = self.task_demand_now <= 0
worker_task_mask = worker_mask[:, :, None] | task_mask[:, None, :]
worker_task_mask |= self.worker_task_mask
batch_size = worker_task_mask.size(0)
worker_task_mask = worker_task_mask.view(batch_size, -1)
return worker_task_mask.all(1)
class Objective:
def step_task(self):
over_time = (self.worker_used_time - self.task_due_time_this).clamp(min=0)
pickup_time = self.worker_used_time * self.task_pickup_this
return self.worker_used_time + over_time + pickup_time
def step_finish(self):
return self.task_demand_now.sum(1) * 1000
def preprocess(problem):
NW, NT = problem.worker_task_mask.size()
worker_task_old = torch.ones(NW, NT, dtype=torch.int32)
new_task_mask = problem.task_new_order[None, :].expand(NW, NT)
worker_task_old[new_task_mask] = 0
worker_task_old[problem.worker_task_mask] = 0
assert torch.all(worker_task_old.sum(0) <= 1)
problem.worker_min_old_task = worker_task_old.sum(1)
problem.worker_count = torch.ones(NW, dtype=torch.int32)
problem.task_demand = torch.ones(NT, dtype=torch.int32)
problem.task_pickup = (problem.task_type == 0).to(torch.int32)
task_old = torch.ones(NT, dtype=torch.int32)
task_old[problem.task_new_order] = 0
problem.task_old = task_old
task_new_pickup = torch.ones(NT, dtype=torch.int32)
task_new_pickup[problem.task_type >= 1] = 0
task_new_pickup[~problem.task_new_order] = 0
problem.task_new_pickup = task_new_pickup
problem.task_due_time_x = problem.task_due_time.float() / 900
problem.x_time_matrix = problem.time_matrix.float() / 900
problem.features = features
problem.variables = variables
problem.constraint = Constraint
problem.objective = Objective
return problem
def make_problem_from_json(data):
data = json.loads(data)
problem = Problem()
problem.id = data['id']
problem.task_order = torch.tensor(data['task_order'], dtype=torch.int32)
problem.task_type = torch.tensor(data['task_type'], dtype=torch.int32)
problem.task_new_order = torch.tensor(data['task_new_order'], dtype=torch.bool)
problem.task_due_time = torch.tensor(data['task_due_time'], dtype=torch.int32)
problem.worker_max_new_order = torch.tensor(data['worker_max_new_order'], dtype=torch.int32)
problem.worker_task_mask = torch.tensor(data['worker_task_mask'], dtype=torch.bool)
problem.time_matrix = torch.tensor(data['time_matrix'], dtype=torch.int32)
NW, NT = problem.worker_task_mask.size()
assert problem.task_order.size() == (NT,), "task_order size error"
assert problem.task_type.size() == (NT,), "task_type size error"
assert problem.task_new_order.size() == (NT,), "task_new_order size error"
assert problem.task_due_time.size() == (NT,), "task_due_time size error"
assert problem.worker_max_new_order.size() == (NW,), "worker_max_new_order size error"
assert problem.time_matrix.size() == (NW + NT, NW + NT), "time_matrix size error"
return preprocess(problem)
def make_problem(batch_count, batch_size=1, task_count=100):
assert batch_size == 1
assert task_count == 100
NW = 100
NT = task_count
NO = NT // 2 # 订单数, 一个订单有pickup, delivery两个任务
problem_list = []
for i in range(batch_count):
problem = Problem()
# user-provided data
problem.worker_max_new_order = torch.full((NW,), 2, dtype=torch.int32)
task_order = torch.arange(NO, dtype=torch.int32)
problem.task_order = torch.cat([task_order, task_order], 0)
task_type = torch.zeros(NO, dtype=torch.int32)
problem.task_type = torch.cat([task_type, task_type + 1], 0)
problem.task_new_order = torch.ones(NT, dtype=torch.bool)
task_due_time = torch.randint(1000, 1800, (NO,), dtype=torch.int32)
problem.task_due_time = torch.cat([task_due_time, task_due_time + 1800], 0)
worker_task_mask = torch.rand(NW, NO) < 0.9
problem.worker_task_mask = torch.cat([worker_task_mask, worker_task_mask], 1)
loc = torch.rand(NW + NT, 2, dtype=torch.float32)
time_matrix = torch.norm(loc[:, None, :] - loc[None, :, :], dim=2) * 1000
problem.time_matrix = time_matrix.to(torch.int32)
problem_list.append(preprocess(problem))
return problem_list
if __name__ == '__main__':
import sys
import os.path as osp
sys.path.append(osp.join(osp.dirname(__file__), '../'))
import runner
runner.run(make_problem)
|