HUANG1993 commited on
Commit
af152d7
1 Parent(s): c2ac027
Files changed (1) hide show
  1. README.md +401 -45
README.md CHANGED
@@ -13,7 +13,17 @@ tags:
13
 
14
  # ✊‍GreedRL
15
 
16
- # Introduction
 
 
 
 
 
 
 
 
 
 
17
 
18
 
19
  ## Architecture design
@@ -46,43 +56,29 @@ The neural network adopts the Seq2Seq architecture commonly used in Natural Lang
46
 
47
  ## Modeling examples
48
 
49
- ### VRP with Time Windows(VRPTW)
 
50
  <details>
51
- <summary>VRPTW</summary>
52
 
53
  ```python
54
- from greedrl import Problem, Solution, Solver
55
  from greedrl.feature import *
56
  from greedrl.variable import *
57
  from greedrl.function import *
58
- from greedrl.model import runner
59
- from greedrl.myenv import VrptwEnv
60
 
61
- features = [continuous_feature('worker_weight_limit'),
62
- continuous_feature('worker_ready_time'),
63
- continuous_feature('worker_due_time'),
64
- continuous_feature('worker_basic_cost'),
65
- continuous_feature('worker_distance_cost'),
66
- continuous_feature('task_demand'),
67
- continuous_feature('task_weight'),
68
- continuous_feature('task_ready_time'),
69
- continuous_feature('task_due_time'),
70
- continuous_feature('task_service_time'),
71
- continuous_feature('distance_matrix')]
72
 
73
  variables = [task_demand_now('task_demand_now', feature='task_demand'),
74
  task_demand_now('task_demand_this', feature='task_demand', only_this=True),
75
  feature_variable('task_weight'),
76
- feature_variable('task_due_time'),
77
- feature_variable('task_ready_time'),
78
- feature_variable('task_service_time'),
79
  worker_variable('worker_weight_limit'),
80
- worker_variable('worker_due_time'),
81
- worker_variable('worker_basic_cost'),
82
- worker_variable('worker_distance_cost'),
83
  worker_used_resource('worker_used_weight', task_require='task_weight'),
84
- worker_used_resource('worker_used_time', 'distance_matrix', 'task_service_time', 'task_ready_time',
85
- 'worker_ready_time'),
86
  edge_variable('distance_last_to_this', feature='distance_matrix', last_to_this=True),
87
  edge_variable('distance_this_to_task', feature='distance_matrix', this_to_task=True),
88
  edge_variable('distance_task_to_end', feature='distance_matrix', task_to_end=True)]
@@ -99,15 +95,6 @@ class Constraint:
99
  # 车辆容量限制
100
  worker_weight_limit = self.worker_weight_limit - self.worker_used_weight
101
  mask |= self.task_demand_now * self.task_weight > worker_weight_limit[:, None]
102
-
103
- worker_used_time = self.worker_used_time[:, None] + self.distance_this_to_task
104
- mask |= worker_used_time > self.task_due_time
105
-
106
- worker_used_time = torch.max(worker_used_time, self.task_ready_time)
107
- worker_used_time += self.task_service_time
108
- worker_used_time += self.distance_task_to_end
109
- mask |= worker_used_time > self.worker_due_time[:, None]
110
-
111
  return mask
112
 
113
  def finished(self):
@@ -116,14 +103,11 @@ class Constraint:
116
 
117
  class Objective:
118
 
119
- def step_worker_start(self):
120
- return self.worker_basic_cost
121
-
122
  def step_worker_end(self):
123
- return self.distance_last_to_this * self.worker_distance_cost
124
 
125
  def step_task(self):
126
- return self.distance_last_to_this * self.worker_distance_cost
127
  ```
128
 
129
  </details>
@@ -208,10 +192,382 @@ class Objective:
208
 
209
  </details>
210
 
211
- ## 🏆Award
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
- # 🤠GreedRL-VRP-pretrained model
215
 
216
  ## Model description
217
 
@@ -236,13 +592,13 @@ You need to compile first and add the resulting library `greedrl_c` to the `PYTH
236
  ```aidl
237
  python setup.py build
238
 
239
- export PYTHONPATH={root_path}/greedrl/build/lib.linux-x86_64-cpython-38/
240
  ```
241
 
242
 
243
  ### Training
244
 
245
- We provide examples of Capacitated VRP(CVRP) for training and inference.
246
 
247
  1. Training data
248
 
@@ -253,7 +609,7 @@ For the CVRP, we assume that the demand of each node is a discrete number in {1,
253
 
254
  2. Start training
255
  ```python
256
- cd example/cvrp
257
 
258
  python train.py --model_filename cvrp_5000.pt --problem_size 5000
259
  ```
@@ -263,7 +619,7 @@ python train.py --model_filename cvrp_5000.pt --problem_size 5000
263
  We provide some pretrained models for different CVRP problem sizes, such as `cvrp_100`, `cvrp_1000`, `cvrp_2000` and `cvrp_5000`, that you can directly use for inference.
264
 
265
  ```python
266
- cd example/cvrp
267
 
268
  python solve.py --device cuda --model_name cvrp_5000.pt --problem_size 5000
269
  ```
 
13
 
14
  # ✊‍GreedRL
15
 
16
+ ## 🏆Award
17
+
18
+
19
+ ## Introduction
20
+
21
+ * **GENERAL**
22
+
23
+
24
+ * **HIGH-PERFORMANCE**
25
+
26
+ * **USER-FRIENDLY**
27
 
28
 
29
  ## Architecture design
 
56
 
57
  ## Modeling examples
58
 
59
+
60
+ ### Capacitated Vehicle Routing Problem (CVRP)
61
  <details>
62
+ <summary>CVRP</summary>
63
 
64
  ```python
 
65
  from greedrl.feature import *
66
  from greedrl.variable import *
67
  from greedrl.function import *
68
+ from greedrl import Problem, Solution, Solver
69
+ from greedrl import runner
70
 
71
+ features = [continuous_feature('task_demand'),
72
+ continuous_feature('worker_weight_limit'),
73
+ continuous_feature('distance_matrix'),
74
+ variable_feature('distance_this_to_task'),
75
+ variable_feature('distance_task_to_end')]
 
 
 
 
 
 
76
 
77
  variables = [task_demand_now('task_demand_now', feature='task_demand'),
78
  task_demand_now('task_demand_this', feature='task_demand', only_this=True),
79
  feature_variable('task_weight'),
 
 
 
80
  worker_variable('worker_weight_limit'),
 
 
 
81
  worker_used_resource('worker_used_weight', task_require='task_weight'),
 
 
82
  edge_variable('distance_last_to_this', feature='distance_matrix', last_to_this=True),
83
  edge_variable('distance_this_to_task', feature='distance_matrix', this_to_task=True),
84
  edge_variable('distance_task_to_end', feature='distance_matrix', task_to_end=True)]
 
95
  # 车辆容量限制
96
  worker_weight_limit = self.worker_weight_limit - self.worker_used_weight
97
  mask |= self.task_demand_now * self.task_weight > worker_weight_limit[:, None]
 
 
 
 
 
 
 
 
 
98
  return mask
99
 
100
  def finished(self):
 
103
 
104
  class Objective:
105
 
 
 
 
106
  def step_worker_end(self):
107
+ return self.distance_last_to_this
108
 
109
  def step_task(self):
110
+ return self.distance_last_to_this
111
  ```
112
 
113
  </details>
 
192
 
193
  </details>
194
 
 
195
 
196
+ ### VRP with Time Windows(VRPTW)
197
+ <details>
198
+ <summary>VRPTW</summary>
199
+
200
+ ```python
201
+ from greedrl import Problem, Solution, Solver
202
+ from greedrl.feature import *
203
+ from greedrl.variable import *
204
+ from greedrl.function import *
205
+ from greedrl.model import runner
206
+ from greedrl.myenv import VrptwEnv
207
+
208
+ features = [continuous_feature('worker_weight_limit'),
209
+ continuous_feature('worker_ready_time'),
210
+ continuous_feature('worker_due_time'),
211
+ continuous_feature('worker_basic_cost'),
212
+ continuous_feature('worker_distance_cost'),
213
+ continuous_feature('task_demand'),
214
+ continuous_feature('task_weight'),
215
+ continuous_feature('task_ready_time'),
216
+ continuous_feature('task_due_time'),
217
+ continuous_feature('task_service_time'),
218
+ continuous_feature('distance_matrix')]
219
+
220
+ variables = [task_demand_now('task_demand_now', feature='task_demand'),
221
+ task_demand_now('task_demand_this', feature='task_demand', only_this=True),
222
+ feature_variable('task_weight'),
223
+ feature_variable('task_due_time'),
224
+ feature_variable('task_ready_time'),
225
+ feature_variable('task_service_time'),
226
+ worker_variable('worker_weight_limit'),
227
+ worker_variable('worker_due_time'),
228
+ worker_variable('worker_basic_cost'),
229
+ worker_variable('worker_distance_cost'),
230
+ worker_used_resource('worker_used_weight', task_require='task_weight'),
231
+ worker_used_resource('worker_used_time', 'distance_matrix', 'task_service_time', 'task_ready_time',
232
+ 'worker_ready_time'),
233
+ edge_variable('distance_last_to_this', feature='distance_matrix', last_to_this=True),
234
+ edge_variable('distance_this_to_task', feature='distance_matrix', this_to_task=True),
235
+ edge_variable('distance_task_to_end', feature='distance_matrix', task_to_end=True)]
236
+
237
+
238
+ class Constraint:
239
+
240
+ def do_task(self):
241
+ return self.task_demand_this
242
+
243
+ def mask_task(self):
244
+ # 已经完成的任务
245
+ mask = self.task_demand_now <= 0
246
+ # 车辆容量限制
247
+ worker_weight_limit = self.worker_weight_limit - self.worker_used_weight
248
+ mask |= self.task_demand_now * self.task_weight > worker_weight_limit[:, None]
249
+
250
+ worker_used_time = self.worker_used_time[:, None] + self.distance_this_to_task
251
+ mask |= worker_used_time > self.task_due_time
252
+
253
+ worker_used_time = torch.max(worker_used_time, self.task_ready_time)
254
+ worker_used_time += self.task_service_time
255
+ worker_used_time += self.distance_task_to_end
256
+ mask |= worker_used_time > self.worker_due_time[:, None]
257
+
258
+ return mask
259
+
260
+ def finished(self):
261
+ return torch.all(self.task_demand_now <= 0, 1)
262
+
263
+
264
+ class Objective:
265
+
266
+ def step_worker_start(self):
267
+ return self.worker_basic_cost
268
+
269
+ def step_worker_end(self):
270
+ return self.distance_last_to_this * self.worker_distance_cost
271
+
272
+ def step_task(self):
273
+ return self.distance_last_to_this * self.worker_distance_cost
274
+ ```
275
+
276
+ </details>
277
+
278
+ ### Travelling Salesman Problem(TSP)
279
+ <details>
280
+ <summary>TSP</summary>
281
+
282
+ ```python
283
+ from greedrl.feature import *
284
+ from greedrl.variable import *
285
+ from greedrl import Problem
286
+ from greedrl import runner
287
+
288
+ features = [continuous_feature('task_location'),
289
+ variable_feature('distance_this_to_task'),
290
+ variable_feature('distance_task_to_end')]
291
+
292
+ variables = [task_demand_now('task_demand_now', feature='task_demand'),
293
+ task_demand_now('task_demand_this', feature='task_demand', only_this=True),
294
+ edge_variable('distance_last_to_this', feature='distance_matrix', last_to_this=True),
295
+ edge_variable('distance_this_to_task', feature='distance_matrix', this_to_task=True),
296
+ edge_variable('distance_task_to_end', feature='distance_matrix', task_to_end=True),
297
+ edge_variable('distance_last_to_loop', feature='distance_matrix', last_to_loop=True)]
298
+
299
+
300
+ class Constraint:
301
+
302
+ def do_task(self):
303
+ return self.task_demand_this
304
+
305
+ def mask_task(self):
306
+ mask = self.task_demand_now <= 0
307
+ return mask
308
+
309
+ def mask_worker_end(self):
310
+ return torch.any(self.task_demand_now > 0, 1)
311
+
312
+ def finished(self):
313
+ return torch.all(self.task_demand_now <= 0, 1)
314
+
315
+
316
+ class Objective:
317
+
318
+ def step_worker_end(self):
319
+ return self.distance_last_to_loop
320
+
321
+ def step_task(self):
322
+ return self.distance_last_to_this
323
+ ```
324
+
325
+ </details>
326
+
327
+ ### Split Delivery Vehicle Routing Problem(SDVRP)
328
+ <details>
329
+ <summary>SDVRP</summary>
330
+
331
+ ```python
332
+ from greedrl.feature import *
333
+ from greedrl.variable import *
334
+ from greedrl import Problem
335
+ from greedrl import runner
336
+
337
+ features = [continuous_feature('task_demand'),
338
+ continuous_feature('worker_weight_limit'),
339
+ continuous_feature('distance_matrix'),
340
+ variable_feature('distance_this_to_task'),
341
+ variable_feature('distance_task_to_end')]
342
+
343
+ variables = [task_demand_now('task_demand'),
344
+ task_demand_now('task_demand_this', feature='task_demand', only_this=True),
345
+ feature_variable('task_weight'),
346
+ task_variable('task_weight_this', feature='task_weight'),
347
+ worker_variable('worker_weight_limit'),
348
+ worker_used_resource('worker_used_weight', task_require='task_weight'),
349
+ edge_variable('distance_last_to_this', feature='distance_matrix', last_to_this=True)]
350
+
351
+
352
+ class Constraint:
353
+
354
+ def do_task(self):
355
+ worker_weight_limit = self.worker_weight_limit - self.worker_used_weight
356
+ return torch.min(self.task_demand_this, worker_weight_limit // self.task_weight_this)
357
+
358
+ def mask_task(self):
359
+ mask = self.task_demand <= 0
360
+ worker_weight_limit = self.worker_weight_limit - self.worker_used_weight
361
+ mask |= self.task_weight > worker_weight_limit[:, None]
362
+ return mask
363
+
364
+ def finished(self):
365
+ return torch.all(self.task_demand <= 0, 1)
366
+
367
+
368
+ class Objective:
369
+
370
+ def step_worker_end(self):
371
+ return self.distance_last_to_this
372
+
373
+ def step_task(self):
374
+ return self.distance_last_to_this
375
+ ```
376
+
377
+ </details>
378
+
379
+ ### Realistic Business Scenario
380
+ <details>
381
+ <summary>real-time Dynamic Pickup and Delivery Problem(DPDP)</summary>
382
+
383
+ ```python
384
+ from greedrl.feature import *
385
+ from greedrl.variable import *
386
+ from greedrl.function import *
387
+ from greedrl import Problem
388
+ from greedrl import runner
389
+
390
+ features = [local_category('task_order'),
391
+ global_category('task_type', 2),
392
+ global_category('task_new_order', 2),
393
+ variable_feature('time_this_to_task'),
394
+ continuous_feature('x_time_matrix'),
395
+ continuous_feature('task_due_time_x'),
396
+ continuous_feature('worker_task_mask')]
397
+
398
+ variables = [task_demand_now('task_demand_now', feature='task_demand'),
399
+ task_demand_now('task_demand_this', feature='task_demand', only_this=True),
400
+ task_variable('task_pickup_this', feature='task_pickup'),
401
+ task_variable('task_due_time_this', feature='task_due_time'),
402
+ feature_variable('task_order', feature='task_order'),
403
+ feature_variable('task_type', feature='task_type'),
404
+ feature_variable('task_new_pickup', feature='task_new_pickup'),
405
+ feature_variable('worker_task_mask', feature='worker_task_mask'),
406
+ worker_count_now('worker_count_now', feature='worker_count'),
407
+ worker_variable('worker_min_old_task_this', feature='worker_min_old_task'),
408
+ worker_variable('worker_max_new_order_this', feature='worker_max_new_order'),
409
+ worker_variable('worker_task_mask_this', feature='worker_task_mask'),
410
+ worker_used_resource('worker_used_old_task', task_require='task_old'),
411
+ worker_used_resource('worker_used_new_order', task_require='task_new_pickup'),
412
+ worker_used_resource('worker_used_time', edge_require='time_matrix'),
413
+ edge_variable('time_this_to_task', feature='x_time_matrix', this_to_task=True)]
414
+
415
+
416
+ class Constraint:
417
+
418
+ def do_task(self):
419
+ return self.task_demand_this
420
+
421
+ def mask_worker_start(self):
422
+ mask = self.worker_count_now <= 0
423
+
424
+ finished = self.task_demand_now <= 0
425
+ worker_task_mask = self.worker_task_mask | finished[:, None, :]
426
+ mask |= torch.all(worker_task_mask, 2)
427
+
428
+ return mask
429
+
430
+ def mask_worker_end(self):
431
+ mask = self.worker_used_old_task < self.worker_min_old_task_this
432
+ mask |= task_group_split(self.task_order, self.task_demand_now <= 0)
433
+ return mask
434
+
435
+ def mask_task(self):
436
+ mask = self.task_demand_now <= 0
437
+
438
+ mask |= task_group_priority(self.task_order, self.task_type, mask)
439
+
440
+ worker_max_new_order = self.worker_max_new_order_this - self.worker_used_new_order
441
+ mask |= self.task_new_pickup > worker_max_new_order[:, None]
442
+
443
+ mask |= self.worker_task_mask_this
444
+
445
+ return mask
446
+
447
+ def finished(self):
448
+ worker_mask = self.worker_count_now <= 0
449
+ task_mask = self.task_demand_now <= 0
450
+ worker_task_mask = worker_mask[:, :, None] | task_mask[:, None, :]
451
+
452
+ worker_task_mask |= self.worker_task_mask
453
+ batch_size = worker_task_mask.size(0)
454
+ worker_task_mask = worker_task_mask.view(batch_size, -1)
455
+ return worker_task_mask.all(1)
456
+
457
+
458
+ class Objective:
459
+
460
+ def step_task(self):
461
+ over_time = (self.worker_used_time - self.task_due_time_this).clamp(min=0)
462
+ pickup_time = self.worker_used_time * self.task_pickup_this
463
+ return self.worker_used_time + over_time + pickup_time
464
+
465
+ def step_finish(self):
466
+ return self.task_demand_now.sum(1) * 1000
467
+ ```
468
+
469
+ </details>
470
+
471
+ ### Order Batching Problem
472
+ <details>
473
+ <summary>Batching</summary>
474
+
475
+ ```python
476
+ from greedrl import Problem, Solver
477
+ from greedrl.feature import *
478
+ from greedrl.variable import *
479
+ from greedrl import runner
480
+
481
+
482
+ features = [local_feature('task_area'),
483
+ local_feature('task_roadway'),
484
+ local_feature('task_area_group'),
485
+ sparse_local_feature('task_item_id', 'task_item_num'),
486
+ sparse_local_feature('task_item_owner_id', 'task_item_num'),
487
+ variable_feature('worker_task_item'),
488
+ variable_feature('worker_used_roadway'),
489
+ variable_feature('worker_used_area')]
490
+
491
+ variables = [task_demand_now('task_demand_now', feature='task_demand'),
492
+ task_demand_now('task_demand_this', feature='task_demand', only_this=True),
493
+ feature_variable('task_item_id'),
494
+ feature_variable('task_item_num'),
495
+ feature_variable('task_item_owner_id'),
496
+ feature_variable('task_area'),
497
+ feature_variable('task_area_group'),
498
+ feature_variable('task_load'),
499
+ feature_variable('task_group'),
500
+ worker_variable('worker_load_limit'),
501
+ worker_variable('worker_area_limit'),
502
+ worker_variable('worker_area_group_limit'),
503
+ worker_task_item('worker_task_item', item_id='task_item_id', item_num='task_item_num'),
504
+ worker_task_item('worker_task_item_owner', item_id='task_item_owner_id', item_num='task_item_num'),
505
+ worker_used_resource('worker_used_load', task_require='task_load'),
506
+ worker_used_resource('worker_used_area', task_require='task_area'),
507
+ worker_used_resource('worker_used_roadway', task_require='task_roadway'),
508
+ worker_used_resource('worker_used_area_group', task_require='task_area_group')]
509
+
510
+
511
+ class Constraint:
512
+
513
+ def do_task(self):
514
+ return self.task_demand_this
515
+
516
+ def mask_worker_end(self):
517
+ return self.worker_used_load < self.worker_load_limit
518
+
519
+ def mask_task(self):
520
+ # completed tasks
521
+ mask = self.task_demand_now <= 0
522
+ # mask |= task_group_priority(self.task_group, self.task_out_stock_time, mask)
523
+
524
+ NT = self.task_item_id.size(1)
525
+ worker_task_item = self.worker_task_item[:, None, :]
526
+ worker_task_item = worker_task_item.expand(-1, NT, -1)
527
+ task_item_in_worker = worker_task_item.gather(2, self.task_item_id.long())
528
+ task_item_in_worker = (task_item_in_worker > 0) & (self.task_item_num > 0)
529
+
530
+ worker_task_item_owner = self.worker_task_item_owner[:, None, :]
531
+ worker_task_item_owner = worker_task_item_owner.expand(-1, NT, -1)
532
+ task_item_owner_in_worker = worker_task_item_owner.gather(2, self.task_item_owner_id.long())
533
+ task_item_owner_in_worker = (task_item_owner_in_worker > 0) & (self.task_item_num > 0)
534
+
535
+ #
536
+ mask |= torch.any(task_item_in_worker & ~task_item_owner_in_worker, 2)
537
+
538
+ worker_load_limit = self.worker_load_limit - self.worker_used_load
539
+ mask |= (self.task_load > worker_load_limit[:, None])
540
+
541
+ task_area = self.task_area + self.worker_used_area[:, None, :]
542
+ task_area_num = task_area.clamp(0, 1).sum(2, dtype=torch.int32)
543
+ mask |= (task_area_num > self.worker_area_limit[:, None])
544
+
545
+ tak_area_group = self.task_area_group + self.worker_used_area_group[:, None, :]
546
+ tak_area_group_num = tak_area_group.clamp(0, 1).sum(2, dtype=torch.int32)
547
+ mask |= (tak_area_group_num > self.worker_area_group_limit[:, None])
548
+
549
+ return mask
550
+
551
+ def finished(self):
552
+ return torch.all(self.task_demand_now <= 0, 1)
553
+
554
+
555
+ class Objective:
556
+
557
+ def step_worker_end(self):
558
+ area_num = self.worker_used_area.clamp(0, 1).sum(1)
559
+ roadway_num = self.worker_used_roadway.clamp(0, 1).sum(1)
560
+ item_num = self.worker_task_item.clamp(0, 1).sum(1)
561
+ penalty = (self.worker_load_limit - self.worker_used_load) * 10
562
+ return area_num * 100 + roadway_num * 10 + item_num + penalty
563
+ ```
564
+
565
+ </details>
566
+
567
+ #
568
+
569
+ # 🤠GreedRL-CVRP-pretrained model
570
 
 
571
 
572
  ## Model description
573
 
 
592
  ```aidl
593
  python setup.py build
594
 
595
+ export PYTHONPATH={root_path}/greedrl/build/lib.linux-x86_64-cpython-38/:$PYTHONPATH
596
  ```
597
 
598
 
599
  ### Training
600
 
601
+ We provide example of Capacitated VRP(CVRP) for training and inference.
602
 
603
  1. Training data
604
 
 
609
 
610
  2. Start training
611
  ```python
612
+ cd examples/cvrp
613
 
614
  python train.py --model_filename cvrp_5000.pt --problem_size 5000
615
  ```
 
619
  We provide some pretrained models for different CVRP problem sizes, such as `cvrp_100`, `cvrp_1000`, `cvrp_2000` and `cvrp_5000`, that you can directly use for inference.
620
 
621
  ```python
622
+ cd examples/cvrp
623
 
624
  python solve.py --device cuda --model_name cvrp_5000.pt --problem_size 5000
625
  ```