Skip to content

Commit

Permalink
Improve support for vehicle routing
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Marte committed May 1, 2021
1 parent 899311d commit 8eee363
Show file tree
Hide file tree
Showing 74 changed files with 2,902 additions and 299 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
* Yuck's approach to problem solving is based in local search.
* Yuck implements Boolean, integer, and integer set variables, see [FlatZinc support](#flatzinc-support).
* Yuck implements many global constraints and their reified counterparts, see [Global constraints](#global-constraints).
* Yuck comes with support for vehicle routing, see [Extending Yuck for Vehicle Routing](https://github.com/informarte/yuck/releases/download/20210501/Extending_Yuck_for_Vehicle_Routing.pdf).
* Yuck features a mechanism to turn Boolean MiniZinc expressions (including applications of global constraints) into soft constraints, see [bool2costs](#bool2costs).
* Yuck supports lexicographic multi-objective optimization, see [goal hierarchies](#goal-hierarchies).
* Yuck supports lexicographic multi-objective optimization, see [Goal hierarchies](#goal-hierarchies).
* Yuck is provided under the terms of the [Mozilla Public License 2.0](https://www.mozilla.org/en-US/MPL/2.0).
* Yuck ranked second among local-search solvers at the [MiniZinc Challenge 2017](http://www.minizinc.org/challenge2017/results2017.html), the [MiniZinc Challenge 2018](http://www.minizinc.org/challenge2018/results2018.html), and the [MiniZinc Challenge 2019](http://www.minizinc.org/challenge2019/results2019.html), and it won a gold medal at the [MiniZinc Challenge 2020](https://www.minizinc.org/challenge2020/results2020.html).

Expand Down
1 change: 1 addition & 0 deletions resources/mzn/lib/verification/yuck/delivery.mzn
1 change: 1 addition & 0 deletions resources/mzn/lib/verification/yuck/domain.mzn
30 changes: 30 additions & 0 deletions resources/mzn/lib/verification/yuck/fzn_delivery.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
predicate fzn_delivery(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime)
=
let {
set of int: Nodes = index_set(succ),
bool: WithServiceTimes = index_set(ServiceTimes) != {},
bool: WithTravelTimes = index_set_1of2(TravelTimes) != {}
}
in forall(i in Nodes diff EndNodes)(
let {
var int: j = succ[i],
var int: st = if WithServiceTimes then ServiceTimes[i] else 0 endif,
var int: tt = if WithTravelTimes then TravelTimes[i, j] else 0 endif,
var int: t = arrivalTimes[i] + st + tt,
var int: u = arrivalTimes[j]
}
in if WithWaiting then u >= t else u = t endif
)
/\
(if WithTravelTimes
then totalTravelTime = sum(i in Nodes diff EndNodes)(TravelTimes[i, succ[i]])
else totalTravelTime = 0
endif);
33 changes: 33 additions & 0 deletions resources/mzn/lib/verification/yuck/fzn_delivery_reif.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
predicate fzn_delivery_reif(
set of int: StartNodes,
set of int: CityNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime,
var bool: satisfied)
=
satisfied
<->
let {
set of int: Nodes = index_set(succ),
bool: WithServiceTimes = index_set(ServiceTimes) != {},
bool: WithTravelTimes = index_set_1of2(TravelTimes) != {}
}
in forall(i in Nodes diff EndNodes)(
let {
var int: j = succ[i],
var int: st = if WithServiceTimes then ServiceTimes[i] else 0 endif,
var int: tt = if WithTravelTimes then TravelTimes[i, j] else 0 endif,
var int: t = arrivalTimes[i] + st + tt,
var int: u = arrivalTimes[j]
}
in if WithWaiting then u >= t else u = t endif
)
/\
(if WithTravelTimes
then totalTravelTime = sum(i in Nodes diff EndNodes)(TravelTimes[i, succ[i]])
else totalTravelTime = 0
endif);
2 changes: 2 additions & 0 deletions resources/mzn/lib/verification/yuck/fzn_domain.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
predicate fzn_domain(array[int] of var int: x, set of int: d) =
forall(i in index_set(x))(x[i] in d);
1 change: 1 addition & 0 deletions resources/mzn/lib/verification/yuck/giant_tour.mzn
84 changes: 84 additions & 0 deletions resources/mzn/lib/yuck/delivery.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
include "fzn_delivery.mzn";
include "fzn_delivery_reif.mzn";
include "giant_tour.mzn";

function bool: delivery_requirements_are_met(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes) :: promise_total
=
let {
set of int: Nodes = index_set(succ)
}
in giant_tour_requirements_are_met(StartNodes, EndNodes, succ)
/\ index_set(arrivalTimes) = Nodes
/\ (index_set(ServiceTimes) = {} \/ index_set(ServiceTimes) = Nodes)
/\ ((index_set_1of2(TravelTimes) = {} /\ index_set_2of2(TravelTimes) = {}) \/
(index_set_1of2(TravelTimes) = Nodes /\ index_set_2of2(TravelTimes) = Nodes));

/**
Helps with solving single-depot vehicle-routing problems with or without
time windows.

Requires the model to be based on the giant-tour representation where,
in addition to the city nodes, there is a pair of start and end nodes
for each vehicle.

Constrains the arrival times to consider the given travel times:

delivery(StartNodes, EndNodes, succ, arrivalTimes, ServiceTimes, TravelTimes, WithWaiting, totalTravelTime)

is equivalent to

let {
set of int: Nodes = index_set(succ)
}
in forall(i in Nodes diff EndNodes)(
let {
var int: j = succ[i],
var int: t = arrivalTimes[i] + ServiceTimes[i] + TravelTimes[i, j],
var int: u = arrivalTimes[j]
}
in if WithWaiting then u >= t else u = t endif
)
/\
totalTravelTime = sum(i in Nodes diff EndNodes)(TravelTimes[i, succ[i]]);
*/
predicate delivery(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime)
=
assert(
delivery_requirements_are_met(StartNodes, EndNodes, succ, arrivalTimes, ServiceTimes, TravelTimes),
"delivery requirements not met",
fzn_delivery(StartNodes, EndNodes, succ, arrivalTimes, ServiceTimes, TravelTimes, WithWaiting, totalTravelTime));

/**
Reified version of delivery
*/
predicate delivery_reif(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime,
var bool: satisfied)
=
assert(
delivery_requirements_are_met(StartNodes, EndNodes, succ, arrivalTimes, ServiceTimes, TravelTimes),
"delivery_reif requirements not met",
fzn_delivery_reif(
StartNodes, EndNodes, succ, arrivalTimes, ServiceTimes, TravelTimes, WithWaiting, totalTravelTime,
satisfied));
4 changes: 4 additions & 0 deletions resources/mzn/lib/yuck/domain.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include "fzn_domain.mzn";

predicate domain(array[int] of var int: x, set of int: d) =
fzn_domain(x, d);
1 change: 0 additions & 1 deletion resources/mzn/lib/yuck/fzn_circuit.mzn
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ include "alldifferent.mzn";
predicate yuck_circuit(array [int] of var int: succ, int: offset);

predicate fzn_circuit(array [int] of var int: succ) =
forall(i in index_set(succ))(succ[i] in index_set(succ) diff {i}) /\
yuck_circuit(succ, min(index_set(succ)));
30 changes: 30 additions & 0 deletions resources/mzn/lib/yuck/fzn_delivery.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
include "yuck.mzn";

predicate yuck_delivery(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
int: offset,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime);

predicate fzn_delivery(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime)
=
let {
int: offset = min(index_set(succ))
}
in yuck_delivery(
StartNodes, EndNodes, succ, offset, arrivalTimes, ServiceTimes, TravelTimes, WithWaiting, totalTravelTime)
:: defines_vars([arrivalTimes[i] | i in index_set(arrivalTimes) diff StartNodes])
:: defines_var(totalTravelTime);
34 changes: 34 additions & 0 deletions resources/mzn/lib/yuck/fzn_delivery_reif.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
include "yuck.mzn";

predicate yuck_delivery_reif(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
int: offset,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime,
var bool: satisfied);

predicate fzn_delivery_reif(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ,
array[int] of var int: arrivalTimes,
array[int] of int: ServiceTimes,
array[int, int] of int: TravelTimes,
bool: WithWaiting,
var int: totalTravelTime,
var bool: satisfied)
=
let {
int: offset = min(index_set(succ))
}
in yuck_delivery_reif(
StartNodes, EndNodes, succ, offset, arrivalTimes, ServiceTimes, TravelTimes, WithWaiting, totalTravelTime,
satisfied)
:: defines_vars([arrivalTimes[i] | i in index_set(arrivalTimes) diff StartNodes])
:: defines_var(totalTravelTime)
:: defines_var(satisfied);
4 changes: 4 additions & 0 deletions resources/mzn/lib/yuck/fzn_domain.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
predicate yuck_int_domain(array[int] of var int: x, set of int: d);

predicate fzn_domain(array[int] of var int: x, set of int: d) =
yuck_int_domain(x, d);
35 changes: 35 additions & 0 deletions resources/mzn/lib/yuck/giant_tour.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
include "circuit.mzn";
include "domain.mzn";

function bool: giant_tour_requirements_are_met(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ) :: promise_total
=
let {
set of int: Nodes = index_set(succ)
}
in StartNodes != {}
/\ card(StartNodes) = card(EndNodes)
/\ max(StartNodes) < min(EndNodes)
/\ StartNodes subset Nodes
/\ EndNodes subset Nodes
/\ dom_array(succ) subset Nodes;

% Hamiltonian circuit where start nodes succeed end nodes
predicate giant_tour(
set of int: StartNodes,
set of int: EndNodes,
array[int] of var int: succ)
=
let {
set of int: Nodes = index_set(succ),
int: K = card(StartNodes)
}
in assert(
giant_tour_requirements_are_met(StartNodes, EndNodes, succ),
"giant tour requirements not met",
circuit(succ)
/\ forall(i in 1..(K - 1))(succ[min(EndNodes) + i - 1] = min(StartNodes) + i)
/\ succ[max(EndNodes)] = min(StartNodes)
/\ domain([succ[i] | i in Nodes diff EndNodes], Nodes diff StartNodes));
47 changes: 47 additions & 0 deletions resources/mzn/tests/front-end-tests/A-n37-k5.dzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
% CVRP instance A-n37-k5 by Augerat et al.

N = 36;
MinK = 5;
Capacity = 100;

TravelTimes = array2d(0..N, 0..N, [|
0, 21, 58, 17, 33, 49, 70, 21, 55, 55, 48, 70, 36, 34, 42, 3, 12, 37, 53, 60, 56, 6, 26, 44, 47, 42, 35, 62, 34, 29, 29, 37, 30, 46, 14, 47, 17 |
21, 0, 37, 19, 45, 41, 54, 30, 47, 42, 29, 56, 16, 26, 22, 23, 17, 18, 67, 39, 37, 16, 22, 27, 35, 47, 51, 52, 52, 50, 43, 56, 49, 45, 34, 59, 38 |
58, 37, 0, 53, 75, 47, 35, 61, 57, 46, 20, 48, 22, 42, 24, 60, 51, 27, 99, 9, 20, 53, 46, 29, 44, 75, 86, 58, 88, 87, 77, 92, 86, 61, 71, 91, 75 |
17, 19, 53, 0, 51, 58, 73, 37, 37, 39, 48, 54, 33, 43, 31, 17, 25, 26, 48, 52, 45, 19, 36, 31, 31, 29, 33, 45, 36, 40, 25, 40, 35, 59, 22, 40, 26 |
33, 45, 75, 51, 0, 41, 70, 15, 88, 86, 57, 101, 55, 34, 67, 34, 28, 63, 78, 80, 81, 32, 29, 72, 79, 74, 59, 95, 53, 38, 57, 56, 48, 27, 39, 74, 38 |
49, 41, 47, 58, 41, 0, 30, 35, 86, 79, 27, 88, 37, 15, 53, 52, 37, 51, 102, 55, 62, 43, 23, 60, 73, 87, 84, 90, 81, 71, 78, 85, 77, 16, 62, 96, 64 |
70, 54, 35, 73, 70, 30, 0, 62, 89, 79, 25, 83, 41, 38, 54, 73, 59, 55, 120, 44, 55, 64, 47, 61, 76, 100, 104, 91, 103, 97, 96, 107, 100, 46, 84, 113, 87 |
21, 30, 61, 37, 15, 35, 62, 0, 74, 72, 45, 86, 41, 24, 53, 23, 14, 48, 71, 66, 66, 18, 16, 57, 64, 63, 52, 81, 49, 37, 49, 52, 44, 26, 31, 67, 32 |
55, 47, 57, 37, 88, 86, 89, 74, 0, 13, 66, 25, 50, 72, 35, 54, 61, 35, 58, 51, 38, 56, 69, 29, 14, 31, 55, 8, 63, 73, 47, 65, 64, 92, 57, 50, 60 |
55, 42, 46, 39, 86, 79, 79, 72, 13, 0, 56, 16, 42, 66, 26, 55, 58, 27, 68, 39, 26, 55, 64, 19, 8, 41, 63, 12, 69, 77, 54, 72, 70, 87, 60, 60, 64 |
48, 29, 20, 48, 57, 27, 25, 45, 66, 56, 0, 63, 16, 23, 30, 50, 38, 30, 96, 28, 35, 41, 29, 37, 52, 75, 80, 68, 81, 76, 72, 84, 77, 41, 62, 88, 65 |
70, 56, 48, 54, 101, 88, 83, 86, 25, 16, 63, 0, 52, 77, 35, 71, 72, 39, 83, 39, 28, 69, 76, 29, 24, 56, 79, 19, 85, 93, 70, 88, 86, 98, 76, 75, 80 |
36, 16, 22, 33, 55, 37, 41, 41, 50, 42, 16, 52, 0, 26, 16, 38, 30, 15, 81, 26, 27, 31, 27, 23, 37, 59, 66, 54, 67, 65, 57, 71, 65, 47, 49, 73, 53 |
34, 26, 42, 43, 34, 15, 38, 24, 72, 66, 23, 77, 26, 0, 42, 37, 22, 39, 87, 49, 53, 28, 9, 48, 60, 72, 69, 77, 67, 59, 63, 71, 63, 21, 48, 81, 50 |
42, 22, 24, 31, 67, 53, 54, 53, 35, 26, 30, 35, 16, 42, 0, 43, 40, 5, 76, 21, 15, 38, 41, 7, 22, 51, 64, 38, 67, 70, 55, 71, 66, 63, 52, 68, 56 |
3, 23, 60, 17, 34, 52, 73, 23, 54, 55, 50, 71, 38, 37, 43, 0, 15, 38, 50, 62, 58, 9, 29, 45, 48, 40, 32, 62, 31, 27, 26, 34, 27, 48, 12, 45, 15 |
12, 17, 51, 25, 28, 37, 59, 14, 61, 58, 38, 72, 30, 22, 40, 15, 0, 35, 65, 55, 54, 6, 14, 44, 51, 53, 47, 67, 45, 38, 41, 49, 41, 34, 26, 59, 29 |
37, 18, 27, 26, 63, 51, 55, 48, 35, 27, 30, 39, 15, 39, 5, 38, 35, 0, 72, 26, 20, 34, 38, 9, 22, 48, 59, 39, 63, 64, 50, 66, 61, 60, 47, 64, 51 |
53, 67, 99, 48, 78, 102, 120, 71, 58, 68, 96, 83, 81, 87, 76, 50, 65, 72, 0, 97, 87, 59, 79, 73, 63, 27, 19, 65, 25, 42, 24, 23, 30, 98, 40, 8, 40 |
60, 39, 9, 52, 80, 55, 44, 66, 51, 39, 28, 39, 26, 49, 21, 62, 55, 26, 97, 0, 13, 56, 52, 24, 38, 71, 85, 51, 88, 89, 76, 92, 87, 69, 72, 89, 76 |
56, 37, 20, 45, 81, 62, 55, 66, 38, 26, 35, 28, 27, 53, 15, 58, 54, 20, 87, 13, 0, 53, 54, 14, 26, 61, 77, 38, 81, 84, 68, 84, 80, 73, 66, 79, 71 |
6, 16, 53, 19, 32, 43, 64, 18, 56, 55, 41, 69, 31, 28, 38, 9, 6, 34, 59, 56, 53, 0, 20, 42, 47, 46, 41, 63, 40, 35, 35, 44, 36, 41, 21, 53, 24 |
26, 22, 46, 36, 29, 23, 47, 16, 69, 64, 29, 76, 27, 9, 41, 29, 14, 38, 79, 52, 54, 20, 0, 47, 57, 65, 61, 74, 59, 50, 55, 62, 55, 23, 40, 73, 42 |
44, 27, 29, 31, 72, 60, 61, 57, 29, 19, 37, 29, 23, 48, 7, 45, 44, 9, 73, 24, 14, 42, 47, 0, 15, 47, 63, 31, 67, 71, 53, 70, 66, 69, 53, 65, 57 |
47, 35, 44, 31, 79, 73, 76, 64, 14, 8, 52, 24, 37, 60, 22, 48, 51, 22, 63, 38, 26, 47, 57, 15, 0, 36, 56, 17, 62, 70, 48, 65, 63, 80, 52, 55, 56 |
42, 47, 75, 29, 74, 87, 100, 63, 31, 41, 75, 56, 59, 72, 51, 40, 53, 48, 27, 71, 61, 46, 65, 47, 36, 0, 26, 39, 34, 48, 20, 35, 37, 87, 36, 19, 38 |
35, 51, 86, 33, 59, 84, 104, 52, 55, 63, 80, 79, 66, 69, 64, 32, 47, 59, 19, 85, 77, 41, 61, 63, 56, 26, 0, 63, 9, 25, 9, 9, 13, 79, 21, 16, 21 |
62, 52, 58, 45, 95, 90, 91, 81, 8, 12, 68, 19, 54, 77, 38, 62, 67, 39, 65, 51, 38, 63, 74, 31, 17, 39, 63, 0, 71, 81, 55, 73, 72, 97, 65, 57, 68 |
34, 52, 88, 36, 53, 81, 103, 49, 63, 69, 81, 85, 67, 67, 67, 31, 45, 63, 25, 88, 81, 40, 59, 67, 62, 34, 9, 71, 0, 17, 15, 4, 5, 75, 19, 24, 17 |
29, 50, 87, 40, 38, 71, 97, 37, 73, 77, 76, 93, 65, 59, 70, 27, 38, 64, 42, 89, 84, 35, 50, 71, 70, 48, 25, 81, 17, 0, 28, 19, 12, 62, 18, 41, 14 |
29, 43, 77, 25, 57, 78, 96, 49, 47, 54, 72, 70, 57, 63, 55, 26, 41, 50, 24, 76, 68, 35, 55, 53, 48, 20, 9, 55, 15, 28, 0, 17, 17, 74, 18, 18, 19 |
37, 56, 92, 40, 56, 85, 107, 52, 65, 72, 84, 88, 71, 71, 71, 34, 49, 66, 23, 92, 84, 44, 62, 70, 65, 35, 9, 73, 4, 19, 17, 0, 8, 78, 23, 23, 21 |
30, 49, 86, 35, 48, 77, 100, 44, 64, 70, 77, 86, 65, 63, 66, 27, 41, 61, 30, 87, 80, 36, 55, 66, 63, 37, 13, 72, 5, 12, 17, 8, 0, 70, 16, 29, 13 |
46, 45, 61, 59, 27, 16, 46, 26, 92, 87, 41, 98, 47, 21, 63, 48, 34, 60, 98, 69, 73, 41, 23, 69, 80, 87, 79, 97, 75, 62, 74, 78, 70, 0, 57, 93, 58 |
14, 34, 71, 22, 39, 62, 84, 31, 57, 60, 62, 76, 49, 48, 52, 12, 26, 47, 40, 72, 66, 21, 40, 53, 52, 36, 21, 65, 19, 18, 18, 23, 16, 57, 0, 36, 4 |
47, 59, 91, 40, 74, 96, 113, 67, 50, 60, 88, 75, 73, 81, 68, 45, 59, 64, 8, 89, 79, 53, 73, 65, 55, 19, 16, 57, 24, 41, 18, 23, 29, 93, 36, 0, 36 |
17, 38, 75, 26, 38, 64, 87, 32, 60, 64, 65, 80, 53, 50, 56, 15, 29, 51, 40, 76, 71, 24, 42, 57, 56, 38, 21, 68, 17, 14, 19, 21, 13, 58, 4, 36, 0 |
|]);

Demands = array1d(1..N, [16, 18, 1, 13, 8, 23, 7, 27, 1, 3, 6, 24, 19, 2, 5, 16, 7, 4, 22, 7, 23, 16, 2, 2, 9, 2, 12, 1, 9, 23, 6, 19, 7, 7, 20, 20]);
22 changes: 22 additions & 0 deletions resources/mzn/tests/front-end-tests/cvrp.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
% Capacitated VRP

include "vrp.mzn";

% maximum number of vehicles/ tours
float: MaxKToMinKRatio;
MaxK = min(N, floor(MinK * MaxKToMinKRatio));

% arrival times
constraint forall(i in StartNodes)(arrivalTimes[i] = 0);

% demands
array [CityNodes] of int: Demands;
array[Nodes] of int: GiantTourDemands = [if i in CityNodes then Demands[i] else 0 endif | i in Nodes];

% vehicle capacities and loads
int: Capacity;
set of int: Load = 0..Capacity;
array[Nodes] of var Load: loads;
constraint forall(i in StartNodes)(loads[i] = 0);
predicate track_loads();
constraint track_loads();
17 changes: 17 additions & 0 deletions resources/mzn/tests/front-end-tests/delivery_reif_test.mzn
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include "delivery.mzn";
include "yuck.mzn";

include "tsptw.mzn";
include "n20w20.001.dzn";

predicate track_times() =
bool2costs(
delivery(StartNodes, EndNodes, succ, arrivalTimes, [], GiantTourTravelTimes, true, totalTravelTime),
0);

solve satisfy;

output [
"totalTravelTime = ", show(totalTravelTime), ",\n",
"arrivalTimes = ", show(arrivalTimes), ",\n",
"succ = ", show(succ)];
Loading

0 comments on commit 8eee363

Please sign in to comment.