diff --git a/examples/notebook/algorithms/knapsack.ipynb b/examples/notebook/algorithms/knapsack.ipynb
index d0909076d1..9d430ded3b 100644
--- a/examples/notebook/algorithms/knapsack.ipynb
+++ b/examples/notebook/algorithms/knapsack.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/algorithms/simple_knapsack_program.ipynb b/examples/notebook/algorithms/simple_knapsack_program.ipynb
index eefae5c088..2db82375a3 100644
--- a/examples/notebook/algorithms/simple_knapsack_program.ipynb
+++ b/examples/notebook/algorithms/simple_knapsack_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb b/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb
index eccca4c830..bbddc10de8 100644
--- a/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb
+++ b/examples/notebook/constraint_solver/cp_is_fun_cp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/cvrp_reload.ipynb b/examples/notebook/constraint_solver/cvrp_reload.ipynb
index b318cfbb69..f90b37dbd9 100644
--- a/examples/notebook/constraint_solver/cvrp_reload.ipynb
+++ b/examples/notebook/constraint_solver/cvrp_reload.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/cvrptw_break.ipynb b/examples/notebook/constraint_solver/cvrptw_break.ipynb
index c037cccd8c..f4b6ecef83 100644
--- a/examples/notebook/constraint_solver/cvrptw_break.ipynb
+++ b/examples/notebook/constraint_solver/cvrptw_break.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/nqueens_cp.ipynb b/examples/notebook/constraint_solver/nqueens_cp.ipynb
index 49b80d9f05..52e67137ae 100644
--- a/examples/notebook/constraint_solver/nqueens_cp.ipynb
+++ b/examples/notebook/constraint_solver/nqueens_cp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/simple_cp_program.ipynb b/examples/notebook/constraint_solver/simple_cp_program.ipynb
index 93ab4f5c14..e57f62343f 100644
--- a/examples/notebook/constraint_solver/simple_cp_program.ipynb
+++ b/examples/notebook/constraint_solver/simple_cp_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/simple_routing_program.ipynb b/examples/notebook/constraint_solver/simple_routing_program.ipynb
index 3364e5d764..57ebd7a1e8 100644
--- a/examples/notebook/constraint_solver/simple_routing_program.ipynb
+++ b/examples/notebook/constraint_solver/simple_routing_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/tsp.ipynb b/examples/notebook/constraint_solver/tsp.ipynb
index 53687bdf71..326c9f83a9 100644
--- a/examples/notebook/constraint_solver/tsp.ipynb
+++ b/examples/notebook/constraint_solver/tsp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/tsp_circuit_board.ipynb b/examples/notebook/constraint_solver/tsp_circuit_board.ipynb
index 0f70f7e4cc..76e86f1d79 100644
--- a/examples/notebook/constraint_solver/tsp_circuit_board.ipynb
+++ b/examples/notebook/constraint_solver/tsp_circuit_board.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/tsp_cities.ipynb b/examples/notebook/constraint_solver/tsp_cities.ipynb
index 8aee9a21ea..c759d138b8 100644
--- a/examples/notebook/constraint_solver/tsp_cities.ipynb
+++ b/examples/notebook/constraint_solver/tsp_cities.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb b/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb
index 1dc0c99fbe..0a32bfc5f8 100644
--- a/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb
+++ b/examples/notebook/constraint_solver/tsp_distance_matrix.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp.ipynb b/examples/notebook/constraint_solver/vrp.ipynb
index 602ee59995..6512432a1d 100644
--- a/examples/notebook/constraint_solver/vrp.ipynb
+++ b/examples/notebook/constraint_solver/vrp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_breaks.ipynb b/examples/notebook/constraint_solver/vrp_breaks.ipynb
index 82f30a29b7..ae15252c87 100644
--- a/examples/notebook/constraint_solver/vrp_breaks.ipynb
+++ b/examples/notebook/constraint_solver/vrp_breaks.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb b/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb
index 82119980d1..855235963a 100644
--- a/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb
+++ b/examples/notebook/constraint_solver/vrp_breaks_from_start.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_capacity.ipynb b/examples/notebook/constraint_solver/vrp_capacity.ipynb
index e0b7e7d827..2e4465fa3d 100644
--- a/examples/notebook/constraint_solver/vrp_capacity.ipynb
+++ b/examples/notebook/constraint_solver/vrp_capacity.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb b/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb
index 73e72be25b..459e2fed81 100644
--- a/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb
+++ b/examples/notebook/constraint_solver/vrp_drop_nodes.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_global_span.ipynb b/examples/notebook/constraint_solver/vrp_global_span.ipynb
index a62cfe957e..b9278678ec 100644
--- a/examples/notebook/constraint_solver/vrp_global_span.ipynb
+++ b/examples/notebook/constraint_solver/vrp_global_span.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_initial_routes.ipynb b/examples/notebook/constraint_solver/vrp_initial_routes.ipynb
index 5051d3f932..bfe860c563 100644
--- a/examples/notebook/constraint_solver/vrp_initial_routes.ipynb
+++ b/examples/notebook/constraint_solver/vrp_initial_routes.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_items_to_deliver.ipynb b/examples/notebook/constraint_solver/vrp_items_to_deliver.ipynb
index a7a0ca637f..e860236575 100644
--- a/examples/notebook/constraint_solver/vrp_items_to_deliver.ipynb
+++ b/examples/notebook/constraint_solver/vrp_items_to_deliver.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_node_max.ipynb b/examples/notebook/constraint_solver/vrp_node_max.ipynb
index aff7fe46df..bcd9e8c958 100644
--- a/examples/notebook/constraint_solver/vrp_node_max.ipynb
+++ b/examples/notebook/constraint_solver/vrp_node_max.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb b/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb
index fd58b697c6..9e93d6ea8c 100644
--- a/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb
+++ b/examples/notebook/constraint_solver/vrp_nodes_indices.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb
index c0a36bb5b7..1f6aa3be6c 100644
--- a/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb
+++ b/examples/notebook/constraint_solver/vrp_pickup_delivery.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb
index 624902ef79..6a4154e113 100644
--- a/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb
+++ b/examples/notebook/constraint_solver/vrp_pickup_delivery_fifo.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb b/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb
index ab1ceadbd0..369b896a12 100644
--- a/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb
+++ b/examples/notebook/constraint_solver/vrp_pickup_delivery_lifo.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_resources.ipynb b/examples/notebook/constraint_solver/vrp_resources.ipynb
index 527bd11da9..026cc370da 100644
--- a/examples/notebook/constraint_solver/vrp_resources.ipynb
+++ b/examples/notebook/constraint_solver/vrp_resources.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_solution_callback.ipynb b/examples/notebook/constraint_solver/vrp_solution_callback.ipynb
index 443b3e7449..571575c57f 100644
--- a/examples/notebook/constraint_solver/vrp_solution_callback.ipynb
+++ b/examples/notebook/constraint_solver/vrp_solution_callback.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_starts_ends.ipynb b/examples/notebook/constraint_solver/vrp_starts_ends.ipynb
index 950cde4d9f..de86e7addd 100644
--- a/examples/notebook/constraint_solver/vrp_starts_ends.ipynb
+++ b/examples/notebook/constraint_solver/vrp_starts_ends.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_time_windows.ipynb b/examples/notebook/constraint_solver/vrp_time_windows.ipynb
index d23624b613..1796e779b8 100644
--- a/examples/notebook/constraint_solver/vrp_time_windows.ipynb
+++ b/examples/notebook/constraint_solver/vrp_time_windows.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb b/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb
index 7d54cffabe..f0326c598b 100644
--- a/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb
+++ b/examples/notebook/constraint_solver/vrp_time_windows_per_vehicles.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_tokens.ipynb b/examples/notebook/constraint_solver/vrp_tokens.ipynb
index 1f15db2f8c..773461b26e 100644
--- a/examples/notebook/constraint_solver/vrp_tokens.ipynb
+++ b/examples/notebook/constraint_solver/vrp_tokens.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb b/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb
index 94a86a864f..870e8efc7a 100644
--- a/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb
+++ b/examples/notebook/constraint_solver/vrp_with_time_limit.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb b/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb
index aa88a63202..41e60a55a1 100644
--- a/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb
+++ b/examples/notebook/constraint_solver/vrptw_store_solution_data.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/3_jugs_mip.ipynb b/examples/notebook/contrib/3_jugs_mip.ipynb
index ee8a8251b8..bc0c4ce243 100644
--- a/examples/notebook/contrib/3_jugs_mip.ipynb
+++ b/examples/notebook/contrib/3_jugs_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/3_jugs_regular.ipynb b/examples/notebook/contrib/3_jugs_regular.ipynb
index d09dc39bfc..4b5cdeeba0 100644
--- a/examples/notebook/contrib/3_jugs_regular.ipynb
+++ b/examples/notebook/contrib/3_jugs_regular.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/a_round_of_golf.ipynb b/examples/notebook/contrib/a_round_of_golf.ipynb
index f661c46724..53e4401a64 100644
--- a/examples/notebook/contrib/a_round_of_golf.ipynb
+++ b/examples/notebook/contrib/a_round_of_golf.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/all_interval.ipynb b/examples/notebook/contrib/all_interval.ipynb
index 6238de5ca9..54070f3662 100644
--- a/examples/notebook/contrib/all_interval.ipynb
+++ b/examples/notebook/contrib/all_interval.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/alldifferent_except_0.ipynb b/examples/notebook/contrib/alldifferent_except_0.ipynb
index 287ca64cd1..a4b7f0ef4f 100644
--- a/examples/notebook/contrib/alldifferent_except_0.ipynb
+++ b/examples/notebook/contrib/alldifferent_except_0.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/alphametic.ipynb b/examples/notebook/contrib/alphametic.ipynb
index d6184c59a8..da69bc36e7 100644
--- a/examples/notebook/contrib/alphametic.ipynb
+++ b/examples/notebook/contrib/alphametic.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/assignment.ipynb b/examples/notebook/contrib/assignment.ipynb
index 8bc379abec..5c6c316bf7 100644
--- a/examples/notebook/contrib/assignment.ipynb
+++ b/examples/notebook/contrib/assignment.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/assignment6_mip.ipynb b/examples/notebook/contrib/assignment6_mip.ipynb
index 1fbb2d5243..81b7a831cf 100644
--- a/examples/notebook/contrib/assignment6_mip.ipynb
+++ b/examples/notebook/contrib/assignment6_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/bacp.ipynb b/examples/notebook/contrib/bacp.ipynb
index 82ff8d3542..f7e01f2a3d 100644
--- a/examples/notebook/contrib/bacp.ipynb
+++ b/examples/notebook/contrib/bacp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/blending.ipynb b/examples/notebook/contrib/blending.ipynb
index 4be44edc8b..8f999b1e98 100644
--- a/examples/notebook/contrib/blending.ipynb
+++ b/examples/notebook/contrib/blending.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/broken_weights.ipynb b/examples/notebook/contrib/broken_weights.ipynb
index 8c3e1f4460..641f2dbbac 100644
--- a/examples/notebook/contrib/broken_weights.ipynb
+++ b/examples/notebook/contrib/broken_weights.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/bus_schedule.ipynb b/examples/notebook/contrib/bus_schedule.ipynb
index eb98ba762a..d10280c607 100644
--- a/examples/notebook/contrib/bus_schedule.ipynb
+++ b/examples/notebook/contrib/bus_schedule.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/car.ipynb b/examples/notebook/contrib/car.ipynb
index 7933e3f9de..f2582c5aaf 100644
--- a/examples/notebook/contrib/car.ipynb
+++ b/examples/notebook/contrib/car.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/check_dependencies.ipynb b/examples/notebook/contrib/check_dependencies.ipynb
index e5c203bb29..e7460d693f 100644
--- a/examples/notebook/contrib/check_dependencies.ipynb
+++ b/examples/notebook/contrib/check_dependencies.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/circuit.ipynb b/examples/notebook/contrib/circuit.ipynb
index 4dc7eec26a..5c0d3b996d 100644
--- a/examples/notebook/contrib/circuit.ipynb
+++ b/examples/notebook/contrib/circuit.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/coins3.ipynb b/examples/notebook/contrib/coins3.ipynb
index f22afa819a..2acc61bf25 100644
--- a/examples/notebook/contrib/coins3.ipynb
+++ b/examples/notebook/contrib/coins3.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/coins_grid.ipynb b/examples/notebook/contrib/coins_grid.ipynb
index 9d5286172f..25ac1f2ef8 100644
--- a/examples/notebook/contrib/coins_grid.ipynb
+++ b/examples/notebook/contrib/coins_grid.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/coins_grid_mip.ipynb b/examples/notebook/contrib/coins_grid_mip.ipynb
index f0a146e73d..89be73fe5f 100644
--- a/examples/notebook/contrib/coins_grid_mip.ipynb
+++ b/examples/notebook/contrib/coins_grid_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/coloring_ip.ipynb b/examples/notebook/contrib/coloring_ip.ipynb
index bebf939dca..0c4733271b 100644
--- a/examples/notebook/contrib/coloring_ip.ipynb
+++ b/examples/notebook/contrib/coloring_ip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/combinatorial_auction2.ipynb b/examples/notebook/contrib/combinatorial_auction2.ipynb
index 3513d029b5..fde253c500 100644
--- a/examples/notebook/contrib/combinatorial_auction2.ipynb
+++ b/examples/notebook/contrib/combinatorial_auction2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/contiguity_regular.ipynb b/examples/notebook/contrib/contiguity_regular.ipynb
index 0ba85444d2..33011747c6 100644
--- a/examples/notebook/contrib/contiguity_regular.ipynb
+++ b/examples/notebook/contrib/contiguity_regular.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/costas_array.ipynb b/examples/notebook/contrib/costas_array.ipynb
index 71ee63633d..a14993b9c9 100644
--- a/examples/notebook/contrib/costas_array.ipynb
+++ b/examples/notebook/contrib/costas_array.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/covering_opl.ipynb b/examples/notebook/contrib/covering_opl.ipynb
index 26dd09df98..45024be9d3 100644
--- a/examples/notebook/contrib/covering_opl.ipynb
+++ b/examples/notebook/contrib/covering_opl.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/crew.ipynb b/examples/notebook/contrib/crew.ipynb
index a9434f07e4..cff12bc40e 100644
--- a/examples/notebook/contrib/crew.ipynb
+++ b/examples/notebook/contrib/crew.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/crossword2.ipynb b/examples/notebook/contrib/crossword2.ipynb
index 9b1d5bec3d..3bced776ea 100644
--- a/examples/notebook/contrib/crossword2.ipynb
+++ b/examples/notebook/contrib/crossword2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/crypta.ipynb b/examples/notebook/contrib/crypta.ipynb
index ab01f2af06..7c659f09bd 100644
--- a/examples/notebook/contrib/crypta.ipynb
+++ b/examples/notebook/contrib/crypta.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/crypto.ipynb b/examples/notebook/contrib/crypto.ipynb
index 1fb774b8a7..8a4c505b75 100644
--- a/examples/notebook/contrib/crypto.ipynb
+++ b/examples/notebook/contrib/crypto.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/curious_set_of_integers.ipynb b/examples/notebook/contrib/curious_set_of_integers.ipynb
index 9e3549413e..882151fc2e 100644
--- a/examples/notebook/contrib/curious_set_of_integers.ipynb
+++ b/examples/notebook/contrib/curious_set_of_integers.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/debruijn_binary.ipynb b/examples/notebook/contrib/debruijn_binary.ipynb
index 55b7012b6a..820c777dba 100644
--- a/examples/notebook/contrib/debruijn_binary.ipynb
+++ b/examples/notebook/contrib/debruijn_binary.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/diet1.ipynb b/examples/notebook/contrib/diet1.ipynb
index 583e600895..948da29917 100644
--- a/examples/notebook/contrib/diet1.ipynb
+++ b/examples/notebook/contrib/diet1.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/diet1_b.ipynb b/examples/notebook/contrib/diet1_b.ipynb
index 398efbbbd1..b0c692160b 100644
--- a/examples/notebook/contrib/diet1_b.ipynb
+++ b/examples/notebook/contrib/diet1_b.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/diet1_mip.ipynb b/examples/notebook/contrib/diet1_mip.ipynb
index a272b6741e..ba426559fd 100644
--- a/examples/notebook/contrib/diet1_mip.ipynb
+++ b/examples/notebook/contrib/diet1_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/discrete_tomography.ipynb b/examples/notebook/contrib/discrete_tomography.ipynb
index 702065109b..551757a260 100644
--- a/examples/notebook/contrib/discrete_tomography.ipynb
+++ b/examples/notebook/contrib/discrete_tomography.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/divisible_by_9_through_1.ipynb b/examples/notebook/contrib/divisible_by_9_through_1.ipynb
index 5c3fa505a4..e4df8c6810 100644
--- a/examples/notebook/contrib/divisible_by_9_through_1.ipynb
+++ b/examples/notebook/contrib/divisible_by_9_through_1.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/dudeney.ipynb b/examples/notebook/contrib/dudeney.ipynb
index a06fa46c92..841542197d 100644
--- a/examples/notebook/contrib/dudeney.ipynb
+++ b/examples/notebook/contrib/dudeney.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/einav_puzzle.ipynb b/examples/notebook/contrib/einav_puzzle.ipynb
index 1e561ba719..fb10e72c6f 100644
--- a/examples/notebook/contrib/einav_puzzle.ipynb
+++ b/examples/notebook/contrib/einav_puzzle.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/einav_puzzle2.ipynb b/examples/notebook/contrib/einav_puzzle2.ipynb
index cf73b64ec7..1c14453eb2 100644
--- a/examples/notebook/contrib/einav_puzzle2.ipynb
+++ b/examples/notebook/contrib/einav_puzzle2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/eq10.ipynb b/examples/notebook/contrib/eq10.ipynb
index 8d73138164..59bab8f057 100644
--- a/examples/notebook/contrib/eq10.ipynb
+++ b/examples/notebook/contrib/eq10.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/eq20.ipynb b/examples/notebook/contrib/eq20.ipynb
index 14d4315247..c9fc2dabd6 100644
--- a/examples/notebook/contrib/eq20.ipynb
+++ b/examples/notebook/contrib/eq20.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/fill_a_pix.ipynb b/examples/notebook/contrib/fill_a_pix.ipynb
index 91a8780ac6..88f31c747b 100644
--- a/examples/notebook/contrib/fill_a_pix.ipynb
+++ b/examples/notebook/contrib/fill_a_pix.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/furniture_moving.ipynb b/examples/notebook/contrib/furniture_moving.ipynb
index 71ff8a961a..eb3b35036e 100644
--- a/examples/notebook/contrib/furniture_moving.ipynb
+++ b/examples/notebook/contrib/furniture_moving.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/futoshiki.ipynb b/examples/notebook/contrib/futoshiki.ipynb
index 00719e963b..9789b29bee 100644
--- a/examples/notebook/contrib/futoshiki.ipynb
+++ b/examples/notebook/contrib/futoshiki.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/game_theory_taha.ipynb b/examples/notebook/contrib/game_theory_taha.ipynb
index d24c0a2f3a..3de60774aa 100644
--- a/examples/notebook/contrib/game_theory_taha.ipynb
+++ b/examples/notebook/contrib/game_theory_taha.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/grocery.ipynb b/examples/notebook/contrib/grocery.ipynb
index 7c342809f0..2fdfbb61d1 100644
--- a/examples/notebook/contrib/grocery.ipynb
+++ b/examples/notebook/contrib/grocery.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/hidato.ipynb b/examples/notebook/contrib/hidato.ipynb
index 7443716a85..942aa78428 100644
--- a/examples/notebook/contrib/hidato.ipynb
+++ b/examples/notebook/contrib/hidato.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/just_forgotten.ipynb b/examples/notebook/contrib/just_forgotten.ipynb
index d21153566d..888f3163f2 100644
--- a/examples/notebook/contrib/just_forgotten.ipynb
+++ b/examples/notebook/contrib/just_forgotten.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/kakuro.ipynb b/examples/notebook/contrib/kakuro.ipynb
index 7d2ee5b163..fa524843b3 100644
--- a/examples/notebook/contrib/kakuro.ipynb
+++ b/examples/notebook/contrib/kakuro.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/kenken2.ipynb b/examples/notebook/contrib/kenken2.ipynb
index 156c4628d0..eace922e2e 100644
--- a/examples/notebook/contrib/kenken2.ipynb
+++ b/examples/notebook/contrib/kenken2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/killer_sudoku.ipynb b/examples/notebook/contrib/killer_sudoku.ipynb
index d4b450e100..7b8e84e06d 100644
--- a/examples/notebook/contrib/killer_sudoku.ipynb
+++ b/examples/notebook/contrib/killer_sudoku.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/knapsack_cp.ipynb b/examples/notebook/contrib/knapsack_cp.ipynb
index 79c306fce8..f4c10df6c2 100644
--- a/examples/notebook/contrib/knapsack_cp.ipynb
+++ b/examples/notebook/contrib/knapsack_cp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/knapsack_mip.ipynb b/examples/notebook/contrib/knapsack_mip.ipynb
index ee9d0c12ef..7e3531fb97 100644
--- a/examples/notebook/contrib/knapsack_mip.ipynb
+++ b/examples/notebook/contrib/knapsack_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/labeled_dice.ipynb b/examples/notebook/contrib/labeled_dice.ipynb
index e7db02b0a7..b1c3345a49 100644
--- a/examples/notebook/contrib/labeled_dice.ipynb
+++ b/examples/notebook/contrib/labeled_dice.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/langford.ipynb b/examples/notebook/contrib/langford.ipynb
index 6ac7a6083a..1ce419ecd2 100644
--- a/examples/notebook/contrib/langford.ipynb
+++ b/examples/notebook/contrib/langford.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/least_diff.ipynb b/examples/notebook/contrib/least_diff.ipynb
index e41126ba4e..34ac0ff016 100644
--- a/examples/notebook/contrib/least_diff.ipynb
+++ b/examples/notebook/contrib/least_diff.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/least_square.ipynb b/examples/notebook/contrib/least_square.ipynb
index e9d11d9d01..469d07772d 100644
--- a/examples/notebook/contrib/least_square.ipynb
+++ b/examples/notebook/contrib/least_square.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/lectures.ipynb b/examples/notebook/contrib/lectures.ipynb
index a17cfbb0c0..dc7c4c4354 100644
--- a/examples/notebook/contrib/lectures.ipynb
+++ b/examples/notebook/contrib/lectures.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/magic_sequence_sat.ipynb b/examples/notebook/contrib/magic_sequence_sat.ipynb
index d082364a40..1093abee03 100644
--- a/examples/notebook/contrib/magic_sequence_sat.ipynb
+++ b/examples/notebook/contrib/magic_sequence_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/magic_square.ipynb b/examples/notebook/contrib/magic_square.ipynb
index 8d4cf7bb09..e33cf54121 100644
--- a/examples/notebook/contrib/magic_square.ipynb
+++ b/examples/notebook/contrib/magic_square.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/magic_square_and_cards.ipynb b/examples/notebook/contrib/magic_square_and_cards.ipynb
index 6bc65edccc..feb9bee0df 100644
--- a/examples/notebook/contrib/magic_square_and_cards.ipynb
+++ b/examples/notebook/contrib/magic_square_and_cards.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/magic_square_mip.ipynb b/examples/notebook/contrib/magic_square_mip.ipynb
index 3b4ada6779..7dd7edd998 100644
--- a/examples/notebook/contrib/magic_square_mip.ipynb
+++ b/examples/notebook/contrib/magic_square_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/map.ipynb b/examples/notebook/contrib/map.ipynb
index df84f637ef..6f383791cf 100644
--- a/examples/notebook/contrib/map.ipynb
+++ b/examples/notebook/contrib/map.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/marathon2.ipynb b/examples/notebook/contrib/marathon2.ipynb
index 6d35184652..d3581cd2f9 100644
--- a/examples/notebook/contrib/marathon2.ipynb
+++ b/examples/notebook/contrib/marathon2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/max_flow_taha.ipynb b/examples/notebook/contrib/max_flow_taha.ipynb
index d52cf2acec..7913958490 100644
--- a/examples/notebook/contrib/max_flow_taha.ipynb
+++ b/examples/notebook/contrib/max_flow_taha.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/max_flow_winston1.ipynb b/examples/notebook/contrib/max_flow_winston1.ipynb
index 4eb9f3dea2..462d0999f3 100644
--- a/examples/notebook/contrib/max_flow_winston1.ipynb
+++ b/examples/notebook/contrib/max_flow_winston1.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/minesweeper.ipynb b/examples/notebook/contrib/minesweeper.ipynb
index 0e008b1c07..236b8cbc8c 100644
--- a/examples/notebook/contrib/minesweeper.ipynb
+++ b/examples/notebook/contrib/minesweeper.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/mr_smith.ipynb b/examples/notebook/contrib/mr_smith.ipynb
index 76f57a97cb..0767bedb00 100644
--- a/examples/notebook/contrib/mr_smith.ipynb
+++ b/examples/notebook/contrib/mr_smith.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nonogram_default_search.ipynb b/examples/notebook/contrib/nonogram_default_search.ipynb
index c9a0abf4c8..17665e777a 100644
--- a/examples/notebook/contrib/nonogram_default_search.ipynb
+++ b/examples/notebook/contrib/nonogram_default_search.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nonogram_regular.ipynb b/examples/notebook/contrib/nonogram_regular.ipynb
index 12b3bc9ece..01edff0a1e 100644
--- a/examples/notebook/contrib/nonogram_regular.ipynb
+++ b/examples/notebook/contrib/nonogram_regular.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nonogram_table.ipynb b/examples/notebook/contrib/nonogram_table.ipynb
index aba767b93e..0de937699c 100644
--- a/examples/notebook/contrib/nonogram_table.ipynb
+++ b/examples/notebook/contrib/nonogram_table.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nonogram_table2.ipynb b/examples/notebook/contrib/nonogram_table2.ipynb
index ad25175beb..d7dfa8fb54 100644
--- a/examples/notebook/contrib/nonogram_table2.ipynb
+++ b/examples/notebook/contrib/nonogram_table2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nontransitive_dice.ipynb b/examples/notebook/contrib/nontransitive_dice.ipynb
index d5fa172d43..da3cd48537 100644
--- a/examples/notebook/contrib/nontransitive_dice.ipynb
+++ b/examples/notebook/contrib/nontransitive_dice.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nqueens.ipynb b/examples/notebook/contrib/nqueens.ipynb
index b5ca63c2cf..437a3de407 100644
--- a/examples/notebook/contrib/nqueens.ipynb
+++ b/examples/notebook/contrib/nqueens.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nqueens2.ipynb b/examples/notebook/contrib/nqueens2.ipynb
index 43ebd96434..492c898c8c 100644
--- a/examples/notebook/contrib/nqueens2.ipynb
+++ b/examples/notebook/contrib/nqueens2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nqueens3.ipynb b/examples/notebook/contrib/nqueens3.ipynb
index 373dbc126e..d5b310fc08 100644
--- a/examples/notebook/contrib/nqueens3.ipynb
+++ b/examples/notebook/contrib/nqueens3.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nurse_rostering.ipynb b/examples/notebook/contrib/nurse_rostering.ipynb
index 3a0490f896..ca1f438aff 100644
--- a/examples/notebook/contrib/nurse_rostering.ipynb
+++ b/examples/notebook/contrib/nurse_rostering.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/nurses_cp.ipynb b/examples/notebook/contrib/nurses_cp.ipynb
index 036eb4d3ab..4247c3b9b3 100644
--- a/examples/notebook/contrib/nurses_cp.ipynb
+++ b/examples/notebook/contrib/nurses_cp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/olympic.ipynb b/examples/notebook/contrib/olympic.ipynb
index fc438a146d..4c7675c3f1 100644
--- a/examples/notebook/contrib/olympic.ipynb
+++ b/examples/notebook/contrib/olympic.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/organize_day.ipynb b/examples/notebook/contrib/organize_day.ipynb
index 1cfd0e775d..7888444751 100644
--- a/examples/notebook/contrib/organize_day.ipynb
+++ b/examples/notebook/contrib/organize_day.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/p_median.ipynb b/examples/notebook/contrib/p_median.ipynb
index 14a71c3b9f..937e78c03d 100644
--- a/examples/notebook/contrib/p_median.ipynb
+++ b/examples/notebook/contrib/p_median.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/pandigital_numbers.ipynb b/examples/notebook/contrib/pandigital_numbers.ipynb
index 3a2391e8cd..bf4746b3e5 100644
--- a/examples/notebook/contrib/pandigital_numbers.ipynb
+++ b/examples/notebook/contrib/pandigital_numbers.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/photo_problem.ipynb b/examples/notebook/contrib/photo_problem.ipynb
index 3c926c0d9e..9a75a3413f 100644
--- a/examples/notebook/contrib/photo_problem.ipynb
+++ b/examples/notebook/contrib/photo_problem.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/place_number_puzzle.ipynb b/examples/notebook/contrib/place_number_puzzle.ipynb
index f0e9472e4a..8fc2cd1ba8 100644
--- a/examples/notebook/contrib/place_number_puzzle.ipynb
+++ b/examples/notebook/contrib/place_number_puzzle.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/post_office_problem2.ipynb b/examples/notebook/contrib/post_office_problem2.ipynb
index 7e4b3f90dd..7271628b0a 100644
--- a/examples/notebook/contrib/post_office_problem2.ipynb
+++ b/examples/notebook/contrib/post_office_problem2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/production.ipynb b/examples/notebook/contrib/production.ipynb
index 90a4ce1409..f450e58575 100644
--- a/examples/notebook/contrib/production.ipynb
+++ b/examples/notebook/contrib/production.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/project_scheduling_sat.ipynb b/examples/notebook/contrib/project_scheduling_sat.ipynb
index 1705b4dc4f..328bbdc134 100644
--- a/examples/notebook/contrib/project_scheduling_sat.ipynb
+++ b/examples/notebook/contrib/project_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/pyls_api.ipynb b/examples/notebook/contrib/pyls_api.ipynb
index f58f9c01dd..f0d5503213 100644
--- a/examples/notebook/contrib/pyls_api.ipynb
+++ b/examples/notebook/contrib/pyls_api.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/quasigroup_completion.ipynb b/examples/notebook/contrib/quasigroup_completion.ipynb
index c7e5a1c2e3..3a89729599 100644
--- a/examples/notebook/contrib/quasigroup_completion.ipynb
+++ b/examples/notebook/contrib/quasigroup_completion.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/regular.ipynb b/examples/notebook/contrib/regular.ipynb
index db879beecc..1f53a18eb5 100644
--- a/examples/notebook/contrib/regular.ipynb
+++ b/examples/notebook/contrib/regular.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/regular_table.ipynb b/examples/notebook/contrib/regular_table.ipynb
index 9f671a3945..bad77bc5fa 100644
--- a/examples/notebook/contrib/regular_table.ipynb
+++ b/examples/notebook/contrib/regular_table.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/regular_table2.ipynb b/examples/notebook/contrib/regular_table2.ipynb
index 5df0798cad..73b7fe76ee 100644
--- a/examples/notebook/contrib/regular_table2.ipynb
+++ b/examples/notebook/contrib/regular_table2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/rogo2.ipynb b/examples/notebook/contrib/rogo2.ipynb
index 2acf87de4c..9bae765dc5 100644
--- a/examples/notebook/contrib/rogo2.ipynb
+++ b/examples/notebook/contrib/rogo2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/rostering_with_travel.ipynb b/examples/notebook/contrib/rostering_with_travel.ipynb
index 794bc3e8a3..a5545bbf53 100644
--- a/examples/notebook/contrib/rostering_with_travel.ipynb
+++ b/examples/notebook/contrib/rostering_with_travel.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/safe_cracking.ipynb b/examples/notebook/contrib/safe_cracking.ipynb
index 8c2184de87..4baaa5c125 100644
--- a/examples/notebook/contrib/safe_cracking.ipynb
+++ b/examples/notebook/contrib/safe_cracking.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/scheduling_speakers.ipynb b/examples/notebook/contrib/scheduling_speakers.ipynb
index 29ec70d428..8f3de34267 100644
--- a/examples/notebook/contrib/scheduling_speakers.ipynb
+++ b/examples/notebook/contrib/scheduling_speakers.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb b/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb
index 16275fec82..b67470ee1d 100644
--- a/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb
+++ b/examples/notebook/contrib/scheduling_with_transitions_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/school_scheduling_sat.ipynb b/examples/notebook/contrib/school_scheduling_sat.ipynb
index bf5507e2c2..423ff950f0 100644
--- a/examples/notebook/contrib/school_scheduling_sat.ipynb
+++ b/examples/notebook/contrib/school_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/secret_santa.ipynb b/examples/notebook/contrib/secret_santa.ipynb
index 789a388412..1997541e8a 100644
--- a/examples/notebook/contrib/secret_santa.ipynb
+++ b/examples/notebook/contrib/secret_santa.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/secret_santa2.ipynb b/examples/notebook/contrib/secret_santa2.ipynb
index 63b73e3827..24314c8a4d 100644
--- a/examples/notebook/contrib/secret_santa2.ipynb
+++ b/examples/notebook/contrib/secret_santa2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/send_more_money_any_base.ipynb b/examples/notebook/contrib/send_more_money_any_base.ipynb
index 18ad26402d..a3039842df 100644
--- a/examples/notebook/contrib/send_more_money_any_base.ipynb
+++ b/examples/notebook/contrib/send_more_money_any_base.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/send_most_money.ipynb b/examples/notebook/contrib/send_most_money.ipynb
index 3cfc024843..418e7dd237 100644
--- a/examples/notebook/contrib/send_most_money.ipynb
+++ b/examples/notebook/contrib/send_most_money.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/seseman.ipynb b/examples/notebook/contrib/seseman.ipynb
index e4ba7742e7..4b6d7a9151 100644
--- a/examples/notebook/contrib/seseman.ipynb
+++ b/examples/notebook/contrib/seseman.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/seseman_b.ipynb b/examples/notebook/contrib/seseman_b.ipynb
index 35bddea7f3..5d91bb53f8 100644
--- a/examples/notebook/contrib/seseman_b.ipynb
+++ b/examples/notebook/contrib/seseman_b.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering.ipynb b/examples/notebook/contrib/set_covering.ipynb
index 31123d37e7..8881614419 100644
--- a/examples/notebook/contrib/set_covering.ipynb
+++ b/examples/notebook/contrib/set_covering.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering2.ipynb b/examples/notebook/contrib/set_covering2.ipynb
index ee0af37f97..f68a156379 100644
--- a/examples/notebook/contrib/set_covering2.ipynb
+++ b/examples/notebook/contrib/set_covering2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering3.ipynb b/examples/notebook/contrib/set_covering3.ipynb
index 99d5ce7481..2464fc62f5 100644
--- a/examples/notebook/contrib/set_covering3.ipynb
+++ b/examples/notebook/contrib/set_covering3.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering4.ipynb b/examples/notebook/contrib/set_covering4.ipynb
index aedf1099b5..30632d5cce 100644
--- a/examples/notebook/contrib/set_covering4.ipynb
+++ b/examples/notebook/contrib/set_covering4.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering_deployment.ipynb b/examples/notebook/contrib/set_covering_deployment.ipynb
index 779bc0b556..bd6e6fed72 100644
--- a/examples/notebook/contrib/set_covering_deployment.ipynb
+++ b/examples/notebook/contrib/set_covering_deployment.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_covering_skiena.ipynb b/examples/notebook/contrib/set_covering_skiena.ipynb
index 2e9c36e3fb..0105739449 100644
--- a/examples/notebook/contrib/set_covering_skiena.ipynb
+++ b/examples/notebook/contrib/set_covering_skiena.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/set_partition.ipynb b/examples/notebook/contrib/set_partition.ipynb
index 41e415e1ed..d151380bc1 100644
--- a/examples/notebook/contrib/set_partition.ipynb
+++ b/examples/notebook/contrib/set_partition.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/sicherman_dice.ipynb b/examples/notebook/contrib/sicherman_dice.ipynb
index 11f1f6c91b..41531e4954 100644
--- a/examples/notebook/contrib/sicherman_dice.ipynb
+++ b/examples/notebook/contrib/sicherman_dice.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/ski_assignment.ipynb b/examples/notebook/contrib/ski_assignment.ipynb
index 0fd19263f6..cfa236c191 100644
--- a/examples/notebook/contrib/ski_assignment.ipynb
+++ b/examples/notebook/contrib/ski_assignment.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/slitherlink.ipynb b/examples/notebook/contrib/slitherlink.ipynb
index afae049f1f..4ce404c391 100644
--- a/examples/notebook/contrib/slitherlink.ipynb
+++ b/examples/notebook/contrib/slitherlink.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/sports_schedule_sat.ipynb b/examples/notebook/contrib/sports_schedule_sat.ipynb
index a8d95bfe38..1425f40d41 100644
--- a/examples/notebook/contrib/sports_schedule_sat.ipynb
+++ b/examples/notebook/contrib/sports_schedule_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/stable_marriage.ipynb b/examples/notebook/contrib/stable_marriage.ipynb
index 1209a47734..7d9c87ddb1 100644
--- a/examples/notebook/contrib/stable_marriage.ipynb
+++ b/examples/notebook/contrib/stable_marriage.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/stable_marriage_sat.ipynb b/examples/notebook/contrib/stable_marriage_sat.ipynb
index 6db6211940..5cd6df5856 100644
--- a/examples/notebook/contrib/stable_marriage_sat.ipynb
+++ b/examples/notebook/contrib/stable_marriage_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/steel.ipynb b/examples/notebook/contrib/steel.ipynb
index 895afb030f..73ebdf511a 100644
--- a/examples/notebook/contrib/steel.ipynb
+++ b/examples/notebook/contrib/steel.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/steel_lns.ipynb b/examples/notebook/contrib/steel_lns.ipynb
index c8f1937bbe..df75ee18df 100644
--- a/examples/notebook/contrib/steel_lns.ipynb
+++ b/examples/notebook/contrib/steel_lns.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/stigler_contrib.ipynb b/examples/notebook/contrib/stigler_contrib.ipynb
index 2e8e24bb6a..a9f73e4444 100644
--- a/examples/notebook/contrib/stigler_contrib.ipynb
+++ b/examples/notebook/contrib/stigler_contrib.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/strimko2.ipynb b/examples/notebook/contrib/strimko2.ipynb
index 0255610cc0..49411e6dc2 100644
--- a/examples/notebook/contrib/strimko2.ipynb
+++ b/examples/notebook/contrib/strimko2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/subset_sum.ipynb b/examples/notebook/contrib/subset_sum.ipynb
index 8825f23e14..17f716fc71 100644
--- a/examples/notebook/contrib/subset_sum.ipynb
+++ b/examples/notebook/contrib/subset_sum.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/survo_puzzle.ipynb b/examples/notebook/contrib/survo_puzzle.ipynb
index 76a96d52fb..217186c4e6 100644
--- a/examples/notebook/contrib/survo_puzzle.ipynb
+++ b/examples/notebook/contrib/survo_puzzle.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/toNum.ipynb b/examples/notebook/contrib/toNum.ipynb
index cf9efddccb..86392c650b 100644
--- a/examples/notebook/contrib/toNum.ipynb
+++ b/examples/notebook/contrib/toNum.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/traffic_lights.ipynb b/examples/notebook/contrib/traffic_lights.ipynb
index 2f1a2b379c..9e695c55cc 100644
--- a/examples/notebook/contrib/traffic_lights.ipynb
+++ b/examples/notebook/contrib/traffic_lights.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/vendor_scheduling.ipynb b/examples/notebook/contrib/vendor_scheduling.ipynb
index 15808dcbd1..e819b7a59b 100644
--- a/examples/notebook/contrib/vendor_scheduling.ipynb
+++ b/examples/notebook/contrib/vendor_scheduling.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/volsay.ipynb b/examples/notebook/contrib/volsay.ipynb
index 54d4905352..d344e95c0f 100644
--- a/examples/notebook/contrib/volsay.ipynb
+++ b/examples/notebook/contrib/volsay.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/volsay2.ipynb b/examples/notebook/contrib/volsay2.ipynb
index baadaa11b7..c8d6e89129 100644
--- a/examples/notebook/contrib/volsay2.ipynb
+++ b/examples/notebook/contrib/volsay2.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/volsay3.ipynb b/examples/notebook/contrib/volsay3.ipynb
index b15b62ff29..9b64f26d0c 100644
--- a/examples/notebook/contrib/volsay3.ipynb
+++ b/examples/notebook/contrib/volsay3.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/wedding_optimal_chart.ipynb b/examples/notebook/contrib/wedding_optimal_chart.ipynb
index 49f26a266b..2d25a22f9e 100644
--- a/examples/notebook/contrib/wedding_optimal_chart.ipynb
+++ b/examples/notebook/contrib/wedding_optimal_chart.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/who_killed_agatha.ipynb b/examples/notebook/contrib/who_killed_agatha.ipynb
index da0b53b75c..b35d1a6313 100644
--- a/examples/notebook/contrib/who_killed_agatha.ipynb
+++ b/examples/notebook/contrib/who_killed_agatha.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/xkcd.ipynb b/examples/notebook/contrib/xkcd.ipynb
index 363385a51d..87e1a351f9 100644
--- a/examples/notebook/contrib/xkcd.ipynb
+++ b/examples/notebook/contrib/xkcd.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/contrib/young_tableaux.ipynb b/examples/notebook/contrib/young_tableaux.ipynb
index 86ca0ee19e..a5aa3cbdc3 100644
--- a/examples/notebook/contrib/young_tableaux.ipynb
+++ b/examples/notebook/contrib/young_tableaux.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/appointments.ipynb b/examples/notebook/examples/appointments.ipynb
index 3976bab8ac..e9473305c3 100644
--- a/examples/notebook/examples/appointments.ipynb
+++ b/examples/notebook/examples/appointments.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb
index 66eb9fbcd0..59374a1958 100644
--- a/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb
+++ b/examples/notebook/examples/arc_flow_cutting_stock_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -93,7 +93,6 @@
"from ortools.linear_solver.python import model_builder as mb\n",
"from ortools.sat.python import cp_model\n",
"\n",
- "FLAGS = flags.FLAGS\n",
"\n",
"_OUTPUT_PROTO = flags.define_string(\n",
" \"output_proto\", \"\", \"Output file to write the cp_model proto to.\"\n",
@@ -107,17 +106,143 @@
"\n",
"\n",
"DESIRED_LENGTHS = [\n",
- " 2490, 3980, 2490, 3980, 2391, 2391, 2391, 596, 596, 596, 2456, 2456, 3018,\n",
- " 938, 3018, 938, 943, 3018, 943, 3018, 2490, 3980, 2490, 3980, 2391, 2391,\n",
- " 2391, 596, 596, 596, 2456, 2456, 3018, 938, 3018, 938, 943, 3018, 943,\n",
- " 3018, 2890, 3980, 2890, 3980, 2391, 2391, 2391, 596, 596, 596, 2856, 2856,\n",
- " 3018, 938, 3018, 938, 943, 3018, 943, 3018, 3290, 3980, 3290, 3980, 2391,\n",
- " 2391, 2391, 596, 596, 596, 3256, 3256, 3018, 938, 3018, 938, 943, 3018,\n",
- " 943, 3018, 3690, 3980, 3690, 3980, 2391, 2391, 2391, 596, 596, 596, 3656,\n",
- " 3656, 3018, 938, 3018, 938, 943, 3018, 943, 3018, 2790, 3980, 2790, 3980,\n",
- " 2391, 2391, 2391, 596, 596, 596, 2756, 2756, 3018, 938, 3018, 938, 943,\n",
- " 3018, 943, 3018, 2790, 3980, 2790, 3980, 2391, 2391, 2391, 596, 596, 596,\n",
- " 2756, 2756, 3018, 938, 3018, 938, 943\n",
+ " 2490,\n",
+ " 3980,\n",
+ " 2490,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 2456,\n",
+ " 2456,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 2490,\n",
+ " 3980,\n",
+ " 2490,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 2456,\n",
+ " 2456,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 2890,\n",
+ " 3980,\n",
+ " 2890,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 2856,\n",
+ " 2856,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 3290,\n",
+ " 3980,\n",
+ " 3290,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 3256,\n",
+ " 3256,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 3690,\n",
+ " 3980,\n",
+ " 3690,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 3656,\n",
+ " 3656,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 2790,\n",
+ " 3980,\n",
+ " 2790,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 2756,\n",
+ " 2756,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 943,\n",
+ " 3018,\n",
+ " 2790,\n",
+ " 3980,\n",
+ " 2790,\n",
+ " 3980,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 2391,\n",
+ " 596,\n",
+ " 596,\n",
+ " 596,\n",
+ " 2756,\n",
+ " 2756,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 3018,\n",
+ " 938,\n",
+ " 943,\n",
"]\n",
"POSSIBLE_CAPACITIES = [4000, 5000, 6000, 7000, 8000]\n",
"\n",
@@ -167,7 +292,6 @@
" new_state = current_state + size * (card + 1)\n",
" if new_state > max_capacity:\n",
" break\n",
- " new_state_index = -1\n",
" if new_state in state_to_index:\n",
" new_state_index = state_to_index[new_state]\n",
" else:\n",
diff --git a/examples/notebook/examples/assignment_with_constraints_sat.ipynb b/examples/notebook/examples/assignment_with_constraints_sat.ipynb
index 7f4bd7437a..4faf8406e8 100644
--- a/examples/notebook/examples/assignment_with_constraints_sat.ipynb
+++ b/examples/notebook/examples/assignment_with_constraints_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -110,24 +110,24 @@
" [0, 1, 0, 1], # Workers 1, 3\n",
" [0, 1, 1, 0], # Workers 1, 2\n",
" [1, 1, 0, 0], # Workers 0, 1\n",
- " [1, 0, 1, 0],\n",
- " ] # Workers 0, 2\n",
+ " [1, 0, 1, 0], # Workers 0, 2\n",
+ " ]\n",
"\n",
" group2 = [\n",
" [0, 0, 1, 1], # Workers 6, 7\n",
" [0, 1, 0, 1], # Workers 5, 7\n",
" [0, 1, 1, 0], # Workers 5, 6\n",
" [1, 1, 0, 0], # Workers 4, 5\n",
- " [1, 0, 0, 1],\n",
- " ] # Workers 4, 7\n",
+ " [1, 0, 0, 1], # Workers 4, 7\n",
+ " ]\n",
"\n",
" group3 = [\n",
" [0, 0, 1, 1], # Workers 10, 11\n",
" [0, 1, 0, 1], # Workers 9, 11\n",
" [0, 1, 1, 0], # Workers 9, 10\n",
" [1, 0, 1, 0], # Workers 8, 10\n",
- " [1, 0, 0, 1],\n",
- " ] # Workers 8, 11\n",
+ " [1, 0, 0, 1], # Workers 8, 11\n",
+ " ]\n",
"\n",
" sizes = [10, 7, 3, 12, 15, 4, 11, 5]\n",
" total_size_max = 15\n",
@@ -141,10 +141,9 @@
" model = cp_model.CpModel()\n",
" # Variables\n",
" selected = [\n",
- " [model.new_bool_var(\"x[%i,%i]\" % (i, j)) for j in all_tasks]\n",
- " for i in all_workers\n",
+ " [model.new_bool_var(f\"x[{i},{j}]\") for j in all_tasks] for i in all_workers\n",
" ]\n",
- " works = [model.new_bool_var(\"works[%i]\" % i) for i in all_workers]\n",
+ " works = [model.new_bool_var(f\"works[{i}]\") for i in all_workers]\n",
"\n",
" # Constraints\n",
"\n",
@@ -175,21 +174,16 @@
" status = solver.solve(model)\n",
"\n",
" if status == cp_model.OPTIMAL:\n",
- " print(\"Total cost = %i\" % solver.objective_value)\n",
+ " print(f\"Total cost = {solver.objective_value}\")\n",
" print()\n",
" for i in all_workers:\n",
" for j in all_tasks:\n",
" if solver.boolean_value(selected[i][j]):\n",
- " print(\n",
- " \"Worker \", i, \" assigned to task \", j, \" Cost = \", cost[i][j]\n",
- " )\n",
+ " print(f\"Worker {i} assigned to task {j} with Cost = {cost[i][j]}\")\n",
"\n",
" print()\n",
"\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"def main(argv: Sequence[str]) -> None:\n",
diff --git a/examples/notebook/examples/balance_group_sat.ipynb b/examples/notebook/examples/balance_group_sat.ipynb
index 61b74bf4a4..2e966e0e28 100644
--- a/examples/notebook/examples/balance_group_sat.ipynb
+++ b/examples/notebook/examples/balance_group_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -88,7 +88,8 @@
"metadata": {},
"outputs": [],
"source": [
- "from typing import Sequence\n",
+ "from typing import Dict, Sequence\n",
+ "\n",
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
@@ -106,10 +107,10 @@
" self.__item_in_group = item_in_group\n",
"\n",
" def on_solution_callback(self):\n",
- " print(\"Solution %i\" % self.__solution_count)\n",
+ " print(f\"Solution {self.__solution_count}\")\n",
" self.__solution_count += 1\n",
"\n",
- " print(\" objective value = %i\" % self.objective_value)\n",
+ " print(f\" objective value = {self.objective_value}\")\n",
" groups = {}\n",
" sums = {}\n",
" for g in self.__all_groups:\n",
@@ -122,11 +123,11 @@
"\n",
" for g in self.__all_groups:\n",
" group = groups[g]\n",
- " print(\"group %i: sum = %0.2f [\" % (g, sums[g]), end=\"\")\n",
+ " print(f\"group {g}: sum = {sums[g]:0.2f} [\", end=\"\")\n",
" for item in group:\n",
" value = self.__values[item]\n",
" color = self.__colors[item]\n",
- " print(\" (%i, %i, %i)\" % (item, value, color), end=\"\")\n",
+ " print(f\" ({item}, {value}, {color})\", end=\"\")\n",
" print(\"]\")\n",
"\n",
"\n",
@@ -156,18 +157,17 @@
" num_items_per_group = num_items // num_groups\n",
"\n",
" # Collect all items in a given color.\n",
- " items_per_color = {}\n",
- " for c in all_colors:\n",
- " items_per_color[c] = []\n",
+ " items_per_color: Dict[int, list[int]] = {}\n",
+ " for color in all_colors:\n",
+ " items_per_color[color] = []\n",
" for i in all_items:\n",
- " if colors[i] == c:\n",
- " items_per_color[c].append(i)\n",
+ " if colors[i] == color:\n",
+ " items_per_color[color].append(i)\n",
"\n",
" print(\n",
- " \"Model has %i items, %i groups, and %i colors\"\n",
- " % (num_items, num_groups, num_colors)\n",
+ " f\"Model has {num_items} items, {num_groups} groups, and\" f\" {num_colors} colors\"\n",
" )\n",
- " print(\" average sum per group = %i\" % average_sum_per_group)\n",
+ " print(f\" average sum per group = {average_sum_per_group}\")\n",
"\n",
" # Model.\n",
"\n",
@@ -176,7 +176,7 @@
" item_in_group = {}\n",
" for i in all_items:\n",
" for g in all_groups:\n",
- " item_in_group[(i, g)] = model.new_bool_var(\"item %d in group %d\" % (i, g))\n",
+ " item_in_group[(i, g)] = model.new_bool_var(f\"item {i} in group {g}\")\n",
"\n",
" # Each group must have the same size.\n",
" for g in all_groups:\n",
@@ -204,9 +204,7 @@
" color_in_group = {}\n",
" for g in all_groups:\n",
" for c in all_colors:\n",
- " color_in_group[(c, g)] = model.new_bool_var(\n",
- " \"color %d is in group %d\" % (c, g)\n",
- " )\n",
+ " color_in_group[(c, g)] = model.new_bool_var(f\"color {c} is in group {g}\")\n",
"\n",
" # Item is in a group implies its color is in that group.\n",
" for i in all_items:\n",
@@ -243,11 +241,8 @@
" status = solver.solve(model, solution_printer)\n",
"\n",
" if status == cp_model.OPTIMAL:\n",
- " print(\"Optimal epsilon: %i\" % solver.objective_value)\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(f\"Optimal epsilon: {solver.objective_value}\")\n",
+ " print(solver.response_stats())\n",
" else:\n",
" print(\"No solution found\")\n",
"\n",
diff --git a/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb b/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb
index 3f4b5cd2fd..59a3162001 100644
--- a/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb
+++ b/examples/notebook/examples/bus_driver_scheduling_flow_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -99,14 +99,13 @@
"from ortools.sat.python import cp_model\n",
"\n",
"PARSER = argparse.ArgumentParser()\n",
+ "PARSER.add_argument(\"--instance\", default=1, type=int, help=\"Instance number (1..3).\")\n",
"PARSER.add_argument(\n",
- " '--instance', default=1, type=int, help='Instance number (1..3).')\n",
- "PARSER.add_argument(\n",
- " '--output_proto_file',\n",
+ " \"--output_proto_file\",\n",
" default=\"\",\n",
- " help='Output file to write the cp_model'\n",
- " 'proto to.')\n",
- "PARSER.add_argument('--params', default=\"\", help='Sat solver parameters.')\n",
+ " help=\"Output file to write the cp_model\" \"proto to.\",\n",
+ ")\n",
+ "PARSER.add_argument(\"--params\", default=\"\", help=\"Sat solver parameters.\")\n",
"\n",
"SAMPLE_SHIFTS_SMALL = [\n",
" #\n",
@@ -118,1618 +117,1618 @@
" # - shift end minute\n",
" # - shift duration in minutes\n",
" #\n",
- " [0, '05:18', '06:00', 318, 360, 42],\n",
- " [1, '05:26', '06:08', 326, 368, 42],\n",
- " [2, '05:40', '05:56', 340, 356, 16],\n",
- " [3, '06:06', '06:51', 366, 411, 45],\n",
- " [4, '06:40', '07:52', 400, 472, 72],\n",
- " [5, '06:42', '07:13', 402, 433, 31],\n",
- " [6, '06:48', '08:15', 408, 495, 87],\n",
- " [7, '06:59', '08:07', 419, 487, 68],\n",
- " [8, '07:20', '07:36', 440, 456, 16],\n",
- " [9, '07:35', '08:22', 455, 502, 47],\n",
- " [10, '07:50', '08:55', 470, 535, 65],\n",
- " [11, '08:00', '09:05', 480, 545, 65],\n",
- " [12, '08:00', '08:35', 480, 515, 35],\n",
- " [13, '08:11', '09:41', 491, 581, 90],\n",
- " [14, '08:28', '08:50', 508, 530, 22],\n",
- " [15, '08:35', '08:45', 515, 525, 10],\n",
- " [16, '08:40', '08:50', 520, 530, 10],\n",
- " [17, '09:03', '10:28', 543, 628, 85],\n",
- " [18, '09:23', '09:49', 563, 589, 26],\n",
- " [19, '09:30', '09:40', 570, 580, 10],\n",
- " [20, '09:57', '10:20', 597, 620, 23],\n",
- " [21, '10:09', '11:03', 609, 663, 54],\n",
- " [22, '10:20', '10:30', 620, 630, 10],\n",
- " [23, '11:00', '11:10', 660, 670, 10],\n",
- " [24, '11:45', '12:24', 705, 744, 39],\n",
- " [25, '12:18', '13:00', 738, 780, 42],\n",
- " [26, '13:18', '14:44', 798, 884, 86],\n",
- " [27, '13:53', '14:49', 833, 889, 56],\n",
- " [28, '14:03', '14:50', 843, 890, 47],\n",
- " [29, '14:28', '15:15', 868, 915, 47],\n",
- " [30, '14:30', '15:41', 870, 941, 71],\n",
- " [31, '14:48', '15:35', 888, 935, 47],\n",
- " [32, '15:03', '15:50', 903, 950, 47],\n",
- " [33, '15:28', '16:54', 928, 1014, 86],\n",
- " [34, '15:38', '16:25', 938, 985, 47],\n",
- " [35, '15:40', '15:56', 940, 956, 16],\n",
- " [36, '15:58', '16:45', 958, 1005, 47],\n",
- " [37, '16:04', '17:30', 964, 1050, 86],\n",
- " [38, '16:28', '17:15', 988, 1035, 47],\n",
- " [39, '16:36', '17:21', 996, 1041, 45],\n",
- " [40, '16:50', '17:00', 1010, 1020, 10],\n",
- " [41, '16:54', '18:20', 1014, 1100, 86],\n",
- " [42, '17:01', '17:13', 1021, 1033, 12],\n",
- " [43, '17:19', '18:31', 1039, 1111, 72],\n",
- " [44, '17:23', '18:10', 1043, 1090, 47],\n",
- " [45, '17:34', '18:15', 1054, 1095, 41],\n",
- " [46, '18:04', '19:29', 1084, 1169, 85],\n",
- " [47, '18:34', '19:58', 1114, 1198, 84],\n",
- " [48, '19:56', '20:34', 1196, 1234, 38],\n",
- " [49, '20:05', '20:48', 1205, 1248, 43]\n",
+ " [0, \"05:18\", \"06:00\", 318, 360, 42],\n",
+ " [1, \"05:26\", \"06:08\", 326, 368, 42],\n",
+ " [2, \"05:40\", \"05:56\", 340, 356, 16],\n",
+ " [3, \"06:06\", \"06:51\", 366, 411, 45],\n",
+ " [4, \"06:40\", \"07:52\", 400, 472, 72],\n",
+ " [5, \"06:42\", \"07:13\", 402, 433, 31],\n",
+ " [6, \"06:48\", \"08:15\", 408, 495, 87],\n",
+ " [7, \"06:59\", \"08:07\", 419, 487, 68],\n",
+ " [8, \"07:20\", \"07:36\", 440, 456, 16],\n",
+ " [9, \"07:35\", \"08:22\", 455, 502, 47],\n",
+ " [10, \"07:50\", \"08:55\", 470, 535, 65],\n",
+ " [11, \"08:00\", \"09:05\", 480, 545, 65],\n",
+ " [12, \"08:00\", \"08:35\", 480, 515, 35],\n",
+ " [13, \"08:11\", \"09:41\", 491, 581, 90],\n",
+ " [14, \"08:28\", \"08:50\", 508, 530, 22],\n",
+ " [15, \"08:35\", \"08:45\", 515, 525, 10],\n",
+ " [16, \"08:40\", \"08:50\", 520, 530, 10],\n",
+ " [17, \"09:03\", \"10:28\", 543, 628, 85],\n",
+ " [18, \"09:23\", \"09:49\", 563, 589, 26],\n",
+ " [19, \"09:30\", \"09:40\", 570, 580, 10],\n",
+ " [20, \"09:57\", \"10:20\", 597, 620, 23],\n",
+ " [21, \"10:09\", \"11:03\", 609, 663, 54],\n",
+ " [22, \"10:20\", \"10:30\", 620, 630, 10],\n",
+ " [23, \"11:00\", \"11:10\", 660, 670, 10],\n",
+ " [24, \"11:45\", \"12:24\", 705, 744, 39],\n",
+ " [25, \"12:18\", \"13:00\", 738, 780, 42],\n",
+ " [26, \"13:18\", \"14:44\", 798, 884, 86],\n",
+ " [27, \"13:53\", \"14:49\", 833, 889, 56],\n",
+ " [28, \"14:03\", \"14:50\", 843, 890, 47],\n",
+ " [29, \"14:28\", \"15:15\", 868, 915, 47],\n",
+ " [30, \"14:30\", \"15:41\", 870, 941, 71],\n",
+ " [31, \"14:48\", \"15:35\", 888, 935, 47],\n",
+ " [32, \"15:03\", \"15:50\", 903, 950, 47],\n",
+ " [33, \"15:28\", \"16:54\", 928, 1014, 86],\n",
+ " [34, \"15:38\", \"16:25\", 938, 985, 47],\n",
+ " [35, \"15:40\", \"15:56\", 940, 956, 16],\n",
+ " [36, \"15:58\", \"16:45\", 958, 1005, 47],\n",
+ " [37, \"16:04\", \"17:30\", 964, 1050, 86],\n",
+ " [38, \"16:28\", \"17:15\", 988, 1035, 47],\n",
+ " [39, \"16:36\", \"17:21\", 996, 1041, 45],\n",
+ " [40, \"16:50\", \"17:00\", 1010, 1020, 10],\n",
+ " [41, \"16:54\", \"18:20\", 1014, 1100, 86],\n",
+ " [42, \"17:01\", \"17:13\", 1021, 1033, 12],\n",
+ " [43, \"17:19\", \"18:31\", 1039, 1111, 72],\n",
+ " [44, \"17:23\", \"18:10\", 1043, 1090, 47],\n",
+ " [45, \"17:34\", \"18:15\", 1054, 1095, 41],\n",
+ " [46, \"18:04\", \"19:29\", 1084, 1169, 85],\n",
+ " [47, \"18:34\", \"19:58\", 1114, 1198, 84],\n",
+ " [48, \"19:56\", \"20:34\", 1196, 1234, 38],\n",
+ " [49, \"20:05\", \"20:48\", 1205, 1248, 43],\n",
"] # yapf:disable\n",
"\n",
"SAMPLE_SHIFTS_MEDIUM = [\n",
- " [0, '04:30', '04:53', 270, 293, 23],\n",
- " [1, '04:46', '04:56', 286, 296, 10],\n",
- " [2, '04:52', '05:56', 292, 356, 64],\n",
- " [3, '04:53', '05:23', 293, 323, 30],\n",
- " [4, '05:07', '05:44', 307, 344, 37],\n",
- " [5, '05:10', '06:06', 310, 366, 56],\n",
- " [6, '05:18', '06:03', 318, 363, 45],\n",
- " [7, '05:30', '05:40', 330, 340, 10],\n",
- " [8, '05:30', '05:40', 330, 340, 10],\n",
- " [9, '05:33', '06:15', 333, 375, 42],\n",
- " [10, '05:40', '05:50', 340, 350, 10],\n",
- " [11, '05:43', '06:08', 343, 368, 25],\n",
- " [12, '05:54', '07:20', 354, 440, 86],\n",
- " [13, '06:04', '06:37', 364, 397, 33],\n",
- " [14, '06:13', '06:58', 373, 418, 45],\n",
- " [15, '06:14', '07:40', 374, 460, 86],\n",
- " [16, '06:15', '07:15', 375, 435, 60],\n",
- " [17, '06:16', '06:26', 376, 386, 10],\n",
- " [18, '06:17', '06:34', 377, 394, 17],\n",
- " [19, '06:20', '06:36', 380, 396, 16],\n",
- " [20, '06:22', '07:06', 382, 426, 44],\n",
- " [21, '06:24', '07:50', 384, 470, 86],\n",
- " [22, '06:27', '06:44', 387, 404, 17],\n",
- " [23, '06:30', '06:40', 390, 400, 10],\n",
- " [24, '06:31', '06:43', 391, 403, 12],\n",
- " [25, '06:33', '07:53', 393, 473, 80],\n",
- " [26, '06:34', '07:09', 394, 429, 35],\n",
- " [27, '06:40', '06:56', 400, 416, 16],\n",
- " [28, '06:44', '07:17', 404, 437, 33],\n",
- " [29, '06:46', '06:58', 406, 418, 12],\n",
- " [30, '06:49', '07:43', 409, 463, 54],\n",
- " [31, '06:50', '07:05', 410, 425, 15],\n",
- " [32, '06:52', '07:36', 412, 456, 44],\n",
- " [33, '06:54', '07:27', 414, 447, 33],\n",
- " [34, '06:56', '08:23', 416, 503, 87],\n",
- " [35, '07:04', '07:44', 424, 464, 40],\n",
- " [36, '07:11', '08:36', 431, 516, 85],\n",
- " [37, '07:17', '07:35', 437, 455, 18],\n",
- " [38, '07:22', '08:06', 442, 486, 44],\n",
- " [39, '07:27', '08:15', 447, 495, 48],\n",
- " [40, '07:35', '07:45', 455, 465, 10],\n",
- " [41, '07:43', '08:08', 463, 488, 25],\n",
- " [42, '07:50', '08:37', 470, 517, 47],\n",
- " [43, '07:58', '08:45', 478, 525, 47],\n",
- " [44, '08:00', '08:35', 480, 515, 35],\n",
- " [45, '08:06', '08:51', 486, 531, 45],\n",
- " [46, '08:10', '08:45', 490, 525, 35],\n",
- " [47, '08:15', '08:30', 495, 510, 15],\n",
- " [48, '08:16', '09:00', 496, 540, 44],\n",
- " [49, '08:18', '09:16', 498, 556, 58],\n",
- " [50, '08:20', '08:36', 500, 516, 16],\n",
- " [51, '08:27', '09:07', 507, 547, 40],\n",
- " [52, '08:30', '08:45', 510, 525, 15],\n",
- " [53, '08:35', '09:15', 515, 555, 40],\n",
- " [54, '08:46', '09:30', 526, 570, 44],\n",
- " [55, '08:51', '09:17', 531, 557, 26],\n",
- " [56, '08:55', '09:15', 535, 555, 20],\n",
- " [57, '08:58', '09:38', 538, 578, 40],\n",
- " [58, '09:00', '09:35', 540, 575, 35],\n",
- " [59, '09:00', '09:16', 540, 556, 16],\n",
- " [60, '09:20', '09:36', 560, 576, 16],\n",
- " [61, '09:31', '09:43', 571, 583, 12],\n",
- " [62, '09:33', '10:15', 573, 615, 42],\n",
- " [63, '09:54', '10:05', 594, 605, 11],\n",
- " [64, '10:11', '10:38', 611, 638, 27],\n",
- " [65, '10:18', '11:00', 618, 660, 42],\n",
- " [66, '10:21', '10:47', 621, 647, 26],\n",
- " [67, '10:25', '11:04', 625, 664, 39],\n",
- " [68, '10:26', '11:08', 626, 668, 42],\n",
- " [69, '10:44', '12:11', 644, 731, 87],\n",
- " [70, '11:00', '11:16', 660, 676, 16],\n",
- " [71, '11:15', '11:54', 675, 714, 39],\n",
- " [72, '11:16', '11:28', 676, 688, 12],\n",
- " [73, '11:20', '11:30', 680, 690, 10],\n",
- " [74, '11:21', '11:47', 681, 707, 26],\n",
- " [75, '11:25', '12:04', 685, 724, 39],\n",
- " [76, '11:34', '11:45', 694, 705, 11],\n",
- " [77, '11:35', '12:14', 695, 734, 39],\n",
- " [78, '11:41', '12:23', 701, 743, 42],\n",
- " [79, '11:44', '12:35', 704, 755, 51],\n",
- " [80, '11:46', '11:58', 706, 718, 12],\n",
- " [81, '12:00', '12:10', 720, 730, 10],\n",
- " [82, '12:04', '12:15', 724, 735, 11],\n",
- " [83, '12:04', '13:04', 724, 784, 60],\n",
- " [84, '12:11', '12:38', 731, 758, 27],\n",
- " [85, '12:15', '12:54', 735, 774, 39],\n",
- " [86, '12:25', '13:10', 745, 790, 45],\n",
- " [87, '12:30', '12:40', 750, 760, 10],\n",
- " [88, '12:34', '13:58', 754, 838, 84],\n",
- " [89, '12:38', '13:25', 758, 805, 47],\n",
- " [90, '12:48', '13:35', 768, 815, 47],\n",
- " [91, '13:00', '13:16', 780, 796, 16],\n",
- " [92, '13:05', '13:44', 785, 824, 39],\n",
- " [93, '13:08', '13:55', 788, 835, 47],\n",
- " [94, '13:14', '14:38', 794, 878, 84],\n",
- " [95, '13:23', '13:49', 803, 829, 26],\n",
- " [96, '13:25', '14:04', 805, 844, 39],\n",
- " [97, '13:28', '14:54', 808, 894, 86],\n",
- " [98, '13:31', '13:43', 811, 823, 12],\n",
- " [99, '13:34', '14:58', 814, 898, 84],\n",
- " [100, '13:38', '14:25', 818, 865, 47],\n",
- " [101, '13:38', '15:04', 818, 904, 86],\n",
- " [102, '13:39', '14:33', 819, 873, 54],\n",
- " [103, '13:40', '13:50', 820, 830, 10],\n",
- " [104, '13:43', '14:10', 823, 850, 27],\n",
- " [105, '13:48', '14:35', 828, 875, 47],\n",
- " [106, '13:48', '14:35', 828, 875, 47],\n",
- " [107, '13:53', '14:40', 833, 880, 47],\n",
- " [108, '13:58', '15:24', 838, 924, 86],\n",
- " [109, '13:58', '14:25', 838, 865, 27],\n",
- " [110, '14:00', '14:16', 840, 856, 16],\n",
- " [111, '14:13', '15:00', 853, 900, 47],\n",
- " [112, '14:20', '15:31', 860, 931, 71],\n",
- " [113, '14:25', '15:02', 865, 902, 37],\n",
- " [114, '14:34', '14:45', 874, 885, 11],\n",
- " [115, '14:40', '15:51', 880, 951, 71],\n",
- " [116, '14:40', '14:56', 880, 896, 16],\n",
- " [117, '14:46', '14:58', 886, 898, 12],\n",
- " [118, '14:49', '15:43', 889, 943, 54],\n",
- " [119, '14:52', '15:21', 892, 921, 29],\n",
- " [120, '14:58', '16:24', 898, 984, 86],\n",
- " [121, '14:59', '15:53', 899, 953, 54],\n",
- " [122, '15:00', '15:10', 900, 910, 10],\n",
- " [123, '15:00', '15:35', 900, 935, 35],\n",
- " [124, '15:08', '15:45', 908, 945, 37],\n",
- " [125, '15:12', '15:36', 912, 936, 24],\n",
- " [126, '15:18', '16:05', 918, 965, 47],\n",
- " [127, '15:24', '16:05', 924, 965, 41],\n",
- " [128, '15:31', '15:43', 931, 943, 12],\n",
- " [129, '15:35', '15:54', 935, 954, 19],\n",
- " [130, '15:36', '16:21', 936, 981, 45],\n",
- " [131, '15:39', '16:33', 939, 993, 54],\n",
- " [132, '15:48', '16:35', 948, 995, 47],\n",
- " [133, '15:50', '17:01', 950, 1021, 71],\n",
- " [134, '16:03', '16:50', 963, 1010, 47],\n",
- " [135, '16:18', '17:44', 978, 1064, 86],\n",
- " [136, '16:24', '17:05', 984, 1025, 41],\n",
- " [137, '16:28', '17:15', 988, 1035, 47],\n",
- " [138, '16:34', '17:15', 994, 1035, 41],\n",
- " [139, '16:38', '17:25', 998, 1045, 47],\n",
- " [140, '16:40', '16:56', 1000, 1016, 16],\n",
- " [141, '16:45', '17:04', 1005, 1024, 19],\n",
- " [142, '16:52', '17:36', 1012, 1056, 44],\n",
- " [143, '16:58', '17:45', 1018, 1065, 47],\n",
- " [144, '17:04', '18:30', 1024, 1110, 86],\n",
- " [145, '17:04', '17:45', 1024, 1065, 41],\n",
- " [146, '17:09', '18:03', 1029, 1083, 54],\n",
- " [147, '17:18', '18:44', 1038, 1124, 86],\n",
- " [148, '17:28', '18:15', 1048, 1095, 47],\n",
- " [149, '17:29', '18:41', 1049, 1121, 72],\n",
- " [150, '17:36', '18:21', 1056, 1101, 45],\n",
- " [151, '17:38', '18:25', 1058, 1105, 47],\n",
- " [152, '17:40', '17:56', 1060, 1076, 16],\n",
- " [153, '17:45', '18:04', 1065, 1084, 19],\n",
- " [154, '17:46', '17:58', 1066, 1078, 12],\n",
- " [155, '17:48', '18:35', 1068, 1115, 47],\n",
- " [156, '17:49', '18:43', 1069, 1123, 54],\n",
- " [157, '17:55', '18:14', 1075, 1094, 19],\n",
- " [158, '17:58', '18:45', 1078, 1125, 47],\n",
- " [159, '18:00', '19:11', 1080, 1151, 71],\n",
- " [160, '18:04', '18:45', 1084, 1125, 41],\n",
- " [161, '18:09', '19:03', 1089, 1143, 54],\n",
- " [162, '18:13', '19:00', 1093, 1140, 47],\n",
- " [163, '18:13', '18:40', 1093, 1120, 27],\n",
- " [164, '18:19', '19:13', 1099, 1153, 54],\n",
- " [165, '18:28', '19:25', 1108, 1165, 57],\n",
- " [166, '18:48', '19:28', 1128, 1168, 40],\n",
- " [167, '19:03', '19:45', 1143, 1185, 42],\n",
- " [168, '19:20', '19:36', 1160, 1176, 16],\n",
- " [169, '19:21', '19:31', 1161, 1171, 10],\n",
- " [170, '19:25', '20:04', 1165, 1204, 39],\n",
- " [171, '19:26', '20:08', 1166, 1208, 42],\n",
- " [172, '19:30', '19:40', 1170, 1180, 10],\n",
- " [173, '19:44', '20:33', 1184, 1233, 49],\n",
- " [174, '19:48', '21:09', 1188, 1269, 81],\n",
- " [175, '19:53', '21:02', 1193, 1262, 69],\n",
- " [176, '20:04', '20:29', 1204, 1229, 25],\n",
- " [177, '20:17', '21:03', 1217, 1263, 46],\n",
- " [178, '20:20', '20:57', 1220, 1257, 37],\n",
- " [179, '20:29', '21:18', 1229, 1278, 49],\n",
- " [180, '20:35', '21:54', 1235, 1314, 79],\n",
- " [181, '20:40', '20:50', 1240, 1250, 10],\n",
- " [182, '20:47', '21:42', 1247, 1302, 55],\n",
- " [183, '21:00', '21:10', 1260, 1270, 10],\n",
- " [184, '21:07', '21:44', 1267, 1304, 37],\n",
- " [185, '21:14', '22:03', 1274, 1323, 49],\n",
- " [186, '21:39', '21:55', 1299, 1315, 16],\n",
- " [187, '21:40', '22:17', 1300, 1337, 37],\n",
- " [188, '21:40', '21:50', 1300, 1310, 10],\n",
- " [189, '21:48', '22:03', 1308, 1323, 15],\n",
- " [190, '22:17', '23:03', 1337, 1383, 46],\n",
- " [191, '22:43', '23:08', 1363, 1388, 25],\n",
- " [192, '23:35', '01:05', 1415, 1505, 90],\n",
- " [193, '23:46', '00:01', 1426, 1441, 15],\n",
- " [194, '23:47', '00:33', 1427, 1473, 46],\n",
- " [195, '23:52', '00:24', 1432, 1464, 32],\n",
- " [196, '23:58', '00:38', 1438, 1478, 40],\n",
- " [197, '00:02', '00:12', 1442, 1452, 10],\n",
- " [198, '00:07', '00:39', 1447, 1479, 32],\n",
- " [199, '00:25', '01:12', 1465, 1512, 47]\n",
+ " [0, \"04:30\", \"04:53\", 270, 293, 23],\n",
+ " [1, \"04:46\", \"04:56\", 286, 296, 10],\n",
+ " [2, \"04:52\", \"05:56\", 292, 356, 64],\n",
+ " [3, \"04:53\", \"05:23\", 293, 323, 30],\n",
+ " [4, \"05:07\", \"05:44\", 307, 344, 37],\n",
+ " [5, \"05:10\", \"06:06\", 310, 366, 56],\n",
+ " [6, \"05:18\", \"06:03\", 318, 363, 45],\n",
+ " [7, \"05:30\", \"05:40\", 330, 340, 10],\n",
+ " [8, \"05:30\", \"05:40\", 330, 340, 10],\n",
+ " [9, \"05:33\", \"06:15\", 333, 375, 42],\n",
+ " [10, \"05:40\", \"05:50\", 340, 350, 10],\n",
+ " [11, \"05:43\", \"06:08\", 343, 368, 25],\n",
+ " [12, \"05:54\", \"07:20\", 354, 440, 86],\n",
+ " [13, \"06:04\", \"06:37\", 364, 397, 33],\n",
+ " [14, \"06:13\", \"06:58\", 373, 418, 45],\n",
+ " [15, \"06:14\", \"07:40\", 374, 460, 86],\n",
+ " [16, \"06:15\", \"07:15\", 375, 435, 60],\n",
+ " [17, \"06:16\", \"06:26\", 376, 386, 10],\n",
+ " [18, \"06:17\", \"06:34\", 377, 394, 17],\n",
+ " [19, \"06:20\", \"06:36\", 380, 396, 16],\n",
+ " [20, \"06:22\", \"07:06\", 382, 426, 44],\n",
+ " [21, \"06:24\", \"07:50\", 384, 470, 86],\n",
+ " [22, \"06:27\", \"06:44\", 387, 404, 17],\n",
+ " [23, \"06:30\", \"06:40\", 390, 400, 10],\n",
+ " [24, \"06:31\", \"06:43\", 391, 403, 12],\n",
+ " [25, \"06:33\", \"07:53\", 393, 473, 80],\n",
+ " [26, \"06:34\", \"07:09\", 394, 429, 35],\n",
+ " [27, \"06:40\", \"06:56\", 400, 416, 16],\n",
+ " [28, \"06:44\", \"07:17\", 404, 437, 33],\n",
+ " [29, \"06:46\", \"06:58\", 406, 418, 12],\n",
+ " [30, \"06:49\", \"07:43\", 409, 463, 54],\n",
+ " [31, \"06:50\", \"07:05\", 410, 425, 15],\n",
+ " [32, \"06:52\", \"07:36\", 412, 456, 44],\n",
+ " [33, \"06:54\", \"07:27\", 414, 447, 33],\n",
+ " [34, \"06:56\", \"08:23\", 416, 503, 87],\n",
+ " [35, \"07:04\", \"07:44\", 424, 464, 40],\n",
+ " [36, \"07:11\", \"08:36\", 431, 516, 85],\n",
+ " [37, \"07:17\", \"07:35\", 437, 455, 18],\n",
+ " [38, \"07:22\", \"08:06\", 442, 486, 44],\n",
+ " [39, \"07:27\", \"08:15\", 447, 495, 48],\n",
+ " [40, \"07:35\", \"07:45\", 455, 465, 10],\n",
+ " [41, \"07:43\", \"08:08\", 463, 488, 25],\n",
+ " [42, \"07:50\", \"08:37\", 470, 517, 47],\n",
+ " [43, \"07:58\", \"08:45\", 478, 525, 47],\n",
+ " [44, \"08:00\", \"08:35\", 480, 515, 35],\n",
+ " [45, \"08:06\", \"08:51\", 486, 531, 45],\n",
+ " [46, \"08:10\", \"08:45\", 490, 525, 35],\n",
+ " [47, \"08:15\", \"08:30\", 495, 510, 15],\n",
+ " [48, \"08:16\", \"09:00\", 496, 540, 44],\n",
+ " [49, \"08:18\", \"09:16\", 498, 556, 58],\n",
+ " [50, \"08:20\", \"08:36\", 500, 516, 16],\n",
+ " [51, \"08:27\", \"09:07\", 507, 547, 40],\n",
+ " [52, \"08:30\", \"08:45\", 510, 525, 15],\n",
+ " [53, \"08:35\", \"09:15\", 515, 555, 40],\n",
+ " [54, \"08:46\", \"09:30\", 526, 570, 44],\n",
+ " [55, \"08:51\", \"09:17\", 531, 557, 26],\n",
+ " [56, \"08:55\", \"09:15\", 535, 555, 20],\n",
+ " [57, \"08:58\", \"09:38\", 538, 578, 40],\n",
+ " [58, \"09:00\", \"09:35\", 540, 575, 35],\n",
+ " [59, \"09:00\", \"09:16\", 540, 556, 16],\n",
+ " [60, \"09:20\", \"09:36\", 560, 576, 16],\n",
+ " [61, \"09:31\", \"09:43\", 571, 583, 12],\n",
+ " [62, \"09:33\", \"10:15\", 573, 615, 42],\n",
+ " [63, \"09:54\", \"10:05\", 594, 605, 11],\n",
+ " [64, \"10:11\", \"10:38\", 611, 638, 27],\n",
+ " [65, \"10:18\", \"11:00\", 618, 660, 42],\n",
+ " [66, \"10:21\", \"10:47\", 621, 647, 26],\n",
+ " [67, \"10:25\", \"11:04\", 625, 664, 39],\n",
+ " [68, \"10:26\", \"11:08\", 626, 668, 42],\n",
+ " [69, \"10:44\", \"12:11\", 644, 731, 87],\n",
+ " [70, \"11:00\", \"11:16\", 660, 676, 16],\n",
+ " [71, \"11:15\", \"11:54\", 675, 714, 39],\n",
+ " [72, \"11:16\", \"11:28\", 676, 688, 12],\n",
+ " [73, \"11:20\", \"11:30\", 680, 690, 10],\n",
+ " [74, \"11:21\", \"11:47\", 681, 707, 26],\n",
+ " [75, \"11:25\", \"12:04\", 685, 724, 39],\n",
+ " [76, \"11:34\", \"11:45\", 694, 705, 11],\n",
+ " [77, \"11:35\", \"12:14\", 695, 734, 39],\n",
+ " [78, \"11:41\", \"12:23\", 701, 743, 42],\n",
+ " [79, \"11:44\", \"12:35\", 704, 755, 51],\n",
+ " [80, \"11:46\", \"11:58\", 706, 718, 12],\n",
+ " [81, \"12:00\", \"12:10\", 720, 730, 10],\n",
+ " [82, \"12:04\", \"12:15\", 724, 735, 11],\n",
+ " [83, \"12:04\", \"13:04\", 724, 784, 60],\n",
+ " [84, \"12:11\", \"12:38\", 731, 758, 27],\n",
+ " [85, \"12:15\", \"12:54\", 735, 774, 39],\n",
+ " [86, \"12:25\", \"13:10\", 745, 790, 45],\n",
+ " [87, \"12:30\", \"12:40\", 750, 760, 10],\n",
+ " [88, \"12:34\", \"13:58\", 754, 838, 84],\n",
+ " [89, \"12:38\", \"13:25\", 758, 805, 47],\n",
+ " [90, \"12:48\", \"13:35\", 768, 815, 47],\n",
+ " [91, \"13:00\", \"13:16\", 780, 796, 16],\n",
+ " [92, \"13:05\", \"13:44\", 785, 824, 39],\n",
+ " [93, \"13:08\", \"13:55\", 788, 835, 47],\n",
+ " [94, \"13:14\", \"14:38\", 794, 878, 84],\n",
+ " [95, \"13:23\", \"13:49\", 803, 829, 26],\n",
+ " [96, \"13:25\", \"14:04\", 805, 844, 39],\n",
+ " [97, \"13:28\", \"14:54\", 808, 894, 86],\n",
+ " [98, \"13:31\", \"13:43\", 811, 823, 12],\n",
+ " [99, \"13:34\", \"14:58\", 814, 898, 84],\n",
+ " [100, \"13:38\", \"14:25\", 818, 865, 47],\n",
+ " [101, \"13:38\", \"15:04\", 818, 904, 86],\n",
+ " [102, \"13:39\", \"14:33\", 819, 873, 54],\n",
+ " [103, \"13:40\", \"13:50\", 820, 830, 10],\n",
+ " [104, \"13:43\", \"14:10\", 823, 850, 27],\n",
+ " [105, \"13:48\", \"14:35\", 828, 875, 47],\n",
+ " [106, \"13:48\", \"14:35\", 828, 875, 47],\n",
+ " [107, \"13:53\", \"14:40\", 833, 880, 47],\n",
+ " [108, \"13:58\", \"15:24\", 838, 924, 86],\n",
+ " [109, \"13:58\", \"14:25\", 838, 865, 27],\n",
+ " [110, \"14:00\", \"14:16\", 840, 856, 16],\n",
+ " [111, \"14:13\", \"15:00\", 853, 900, 47],\n",
+ " [112, \"14:20\", \"15:31\", 860, 931, 71],\n",
+ " [113, \"14:25\", \"15:02\", 865, 902, 37],\n",
+ " [114, \"14:34\", \"14:45\", 874, 885, 11],\n",
+ " [115, \"14:40\", \"15:51\", 880, 951, 71],\n",
+ " [116, \"14:40\", \"14:56\", 880, 896, 16],\n",
+ " [117, \"14:46\", \"14:58\", 886, 898, 12],\n",
+ " [118, \"14:49\", \"15:43\", 889, 943, 54],\n",
+ " [119, \"14:52\", \"15:21\", 892, 921, 29],\n",
+ " [120, \"14:58\", \"16:24\", 898, 984, 86],\n",
+ " [121, \"14:59\", \"15:53\", 899, 953, 54],\n",
+ " [122, \"15:00\", \"15:10\", 900, 910, 10],\n",
+ " [123, \"15:00\", \"15:35\", 900, 935, 35],\n",
+ " [124, \"15:08\", \"15:45\", 908, 945, 37],\n",
+ " [125, \"15:12\", \"15:36\", 912, 936, 24],\n",
+ " [126, \"15:18\", \"16:05\", 918, 965, 47],\n",
+ " [127, \"15:24\", \"16:05\", 924, 965, 41],\n",
+ " [128, \"15:31\", \"15:43\", 931, 943, 12],\n",
+ " [129, \"15:35\", \"15:54\", 935, 954, 19],\n",
+ " [130, \"15:36\", \"16:21\", 936, 981, 45],\n",
+ " [131, \"15:39\", \"16:33\", 939, 993, 54],\n",
+ " [132, \"15:48\", \"16:35\", 948, 995, 47],\n",
+ " [133, \"15:50\", \"17:01\", 950, 1021, 71],\n",
+ " [134, \"16:03\", \"16:50\", 963, 1010, 47],\n",
+ " [135, \"16:18\", \"17:44\", 978, 1064, 86],\n",
+ " [136, \"16:24\", \"17:05\", 984, 1025, 41],\n",
+ " [137, \"16:28\", \"17:15\", 988, 1035, 47],\n",
+ " [138, \"16:34\", \"17:15\", 994, 1035, 41],\n",
+ " [139, \"16:38\", \"17:25\", 998, 1045, 47],\n",
+ " [140, \"16:40\", \"16:56\", 1000, 1016, 16],\n",
+ " [141, \"16:45\", \"17:04\", 1005, 1024, 19],\n",
+ " [142, \"16:52\", \"17:36\", 1012, 1056, 44],\n",
+ " [143, \"16:58\", \"17:45\", 1018, 1065, 47],\n",
+ " [144, \"17:04\", \"18:30\", 1024, 1110, 86],\n",
+ " [145, \"17:04\", \"17:45\", 1024, 1065, 41],\n",
+ " [146, \"17:09\", \"18:03\", 1029, 1083, 54],\n",
+ " [147, \"17:18\", \"18:44\", 1038, 1124, 86],\n",
+ " [148, \"17:28\", \"18:15\", 1048, 1095, 47],\n",
+ " [149, \"17:29\", \"18:41\", 1049, 1121, 72],\n",
+ " [150, \"17:36\", \"18:21\", 1056, 1101, 45],\n",
+ " [151, \"17:38\", \"18:25\", 1058, 1105, 47],\n",
+ " [152, \"17:40\", \"17:56\", 1060, 1076, 16],\n",
+ " [153, \"17:45\", \"18:04\", 1065, 1084, 19],\n",
+ " [154, \"17:46\", \"17:58\", 1066, 1078, 12],\n",
+ " [155, \"17:48\", \"18:35\", 1068, 1115, 47],\n",
+ " [156, \"17:49\", \"18:43\", 1069, 1123, 54],\n",
+ " [157, \"17:55\", \"18:14\", 1075, 1094, 19],\n",
+ " [158, \"17:58\", \"18:45\", 1078, 1125, 47],\n",
+ " [159, \"18:00\", \"19:11\", 1080, 1151, 71],\n",
+ " [160, \"18:04\", \"18:45\", 1084, 1125, 41],\n",
+ " [161, \"18:09\", \"19:03\", 1089, 1143, 54],\n",
+ " [162, \"18:13\", \"19:00\", 1093, 1140, 47],\n",
+ " [163, \"18:13\", \"18:40\", 1093, 1120, 27],\n",
+ " [164, \"18:19\", \"19:13\", 1099, 1153, 54],\n",
+ " [165, \"18:28\", \"19:25\", 1108, 1165, 57],\n",
+ " [166, \"18:48\", \"19:28\", 1128, 1168, 40],\n",
+ " [167, \"19:03\", \"19:45\", 1143, 1185, 42],\n",
+ " [168, \"19:20\", \"19:36\", 1160, 1176, 16],\n",
+ " [169, \"19:21\", \"19:31\", 1161, 1171, 10],\n",
+ " [170, \"19:25\", \"20:04\", 1165, 1204, 39],\n",
+ " [171, \"19:26\", \"20:08\", 1166, 1208, 42],\n",
+ " [172, \"19:30\", \"19:40\", 1170, 1180, 10],\n",
+ " [173, \"19:44\", \"20:33\", 1184, 1233, 49],\n",
+ " [174, \"19:48\", \"21:09\", 1188, 1269, 81],\n",
+ " [175, \"19:53\", \"21:02\", 1193, 1262, 69],\n",
+ " [176, \"20:04\", \"20:29\", 1204, 1229, 25],\n",
+ " [177, \"20:17\", \"21:03\", 1217, 1263, 46],\n",
+ " [178, \"20:20\", \"20:57\", 1220, 1257, 37],\n",
+ " [179, \"20:29\", \"21:18\", 1229, 1278, 49],\n",
+ " [180, \"20:35\", \"21:54\", 1235, 1314, 79],\n",
+ " [181, \"20:40\", \"20:50\", 1240, 1250, 10],\n",
+ " [182, \"20:47\", \"21:42\", 1247, 1302, 55],\n",
+ " [183, \"21:00\", \"21:10\", 1260, 1270, 10],\n",
+ " [184, \"21:07\", \"21:44\", 1267, 1304, 37],\n",
+ " [185, \"21:14\", \"22:03\", 1274, 1323, 49],\n",
+ " [186, \"21:39\", \"21:55\", 1299, 1315, 16],\n",
+ " [187, \"21:40\", \"22:17\", 1300, 1337, 37],\n",
+ " [188, \"21:40\", \"21:50\", 1300, 1310, 10],\n",
+ " [189, \"21:48\", \"22:03\", 1308, 1323, 15],\n",
+ " [190, \"22:17\", \"23:03\", 1337, 1383, 46],\n",
+ " [191, \"22:43\", \"23:08\", 1363, 1388, 25],\n",
+ " [192, \"23:35\", \"01:05\", 1415, 1505, 90],\n",
+ " [193, \"23:46\", \"00:01\", 1426, 1441, 15],\n",
+ " [194, \"23:47\", \"00:33\", 1427, 1473, 46],\n",
+ " [195, \"23:52\", \"00:24\", 1432, 1464, 32],\n",
+ " [196, \"23:58\", \"00:38\", 1438, 1478, 40],\n",
+ " [197, \"00:02\", \"00:12\", 1442, 1452, 10],\n",
+ " [198, \"00:07\", \"00:39\", 1447, 1479, 32],\n",
+ " [199, \"00:25\", \"01:12\", 1465, 1512, 47],\n",
"] # yapf:disable\n",
"\n",
"SAMPLE_SHIFTS_LARGE = [\n",
- " [0, '04:18', '05:00', 258, 300, 42],\n",
- " [1, '04:27', '05:08', 267, 308, 41],\n",
- " [2, '04:29', '05:26', 269, 326, 57],\n",
- " [3, '04:29', '04:55', 269, 295, 26],\n",
- " [4, '04:30', '04:53', 270, 293, 23],\n",
- " [5, '04:30', '04:51', 270, 291, 21],\n",
- " [6, '04:31', '04:53', 271, 293, 22],\n",
- " [7, '04:33', '05:15', 273, 315, 42],\n",
- " [8, '04:34', '04:44', 274, 284, 10],\n",
- " [9, '04:34', '05:03', 274, 303, 29],\n",
- " [10, '04:35', '04:50', 275, 290, 15],\n",
- " [11, '04:36', '04:46', 276, 286, 10],\n",
- " [12, '04:37', '05:18', 277, 318, 41],\n",
- " [13, '04:41', '05:13', 281, 313, 32],\n",
- " [14, '04:42', '05:23', 282, 323, 41],\n",
- " [15, '04:43', '04:53', 283, 293, 10],\n",
- " [16, '04:44', '05:45', 284, 345, 61],\n",
- " [17, '04:45', '05:11', 285, 311, 26],\n",
- " [18, '04:46', '05:01', 286, 301, 15],\n",
- " [19, '04:46', '04:56', 286, 296, 10],\n",
- " [20, '04:47', '05:14', 287, 314, 27],\n",
- " [21, '04:48', '05:30', 288, 330, 42],\n",
- " [22, '04:49', '05:41', 289, 341, 52],\n",
- " [23, '04:49', '05:18', 289, 318, 29],\n",
- " [24, '04:50', '05:33', 290, 333, 43],\n",
- " [25, '04:52', '05:56', 292, 356, 64],\n",
- " [26, '04:52', '05:07', 292, 307, 15],\n",
- " [27, '04:53', '05:19', 293, 319, 26],\n",
- " [28, '04:53', '05:23', 293, 323, 30],\n",
- " [29, '04:55', '05:27', 295, 327, 32],\n",
- " [30, '04:57', '05:38', 297, 338, 41],\n",
- " [31, '05:00', '06:00', 300, 360, 60],\n",
- " [32, '05:00', '05:54', 300, 354, 54],\n",
- " [33, '05:01', '05:33', 301, 333, 32],\n",
- " [34, '05:01', '05:26', 301, 326, 25],\n",
- " [35, '05:02', '05:29', 302, 329, 27],\n",
- " [36, '05:02', '05:12', 302, 312, 10],\n",
- " [37, '05:03', '05:45', 303, 345, 42],\n",
- " [38, '05:03', '05:18', 303, 318, 15],\n",
- " [39, '05:03', '06:28', 303, 388, 85],\n",
- " [40, '05:03', '05:13', 303, 313, 10],\n",
- " [41, '05:04', '06:24', 304, 384, 80],\n",
- " [42, '05:07', '05:44', 307, 344, 37],\n",
- " [43, '05:08', '05:48', 308, 348, 40],\n",
- " [44, '05:10', '06:06', 310, 366, 56],\n",
- " [45, '05:11', '05:37', 311, 337, 26],\n",
- " [46, '05:11', '05:53', 311, 353, 42],\n",
- " [47, '05:13', '06:15', 313, 375, 62],\n",
- " [48, '05:13', '05:38', 313, 338, 25],\n",
- " [49, '05:16', '05:44', 316, 344, 28],\n",
- " [50, '05:17', '05:27', 317, 327, 10],\n",
- " [51, '05:18', '06:40', 318, 400, 82],\n",
- " [52, '05:18', '06:03', 318, 363, 45],\n",
- " [53, '05:18', '06:11', 318, 371, 53],\n",
- " [54, '05:18', '06:00', 318, 360, 42],\n",
- " [55, '05:19', '06:34', 319, 394, 75],\n",
- " [56, '05:20', '06:17', 320, 377, 57],\n",
- " [57, '05:22', '05:59', 322, 359, 37],\n",
- " [58, '05:24', '05:48', 324, 348, 24],\n",
- " [59, '05:25', '05:40', 325, 340, 15],\n",
- " [60, '05:26', '06:08', 326, 368, 42],\n",
- " [61, '05:27', '06:30', 327, 390, 63],\n",
- " [62, '05:27', '05:54', 327, 354, 27],\n",
- " [63, '05:28', '05:53', 328, 353, 25],\n",
- " [64, '05:29', '05:44', 329, 344, 15],\n",
- " [65, '05:30', '05:40', 330, 340, 10],\n",
- " [66, '05:30', '05:40', 330, 340, 10],\n",
- " [67, '05:30', '05:40', 330, 340, 10],\n",
- " [68, '05:32', '06:53', 332, 413, 81],\n",
- " [69, '05:33', '07:00', 333, 420, 87],\n",
- " [70, '05:33', '06:15', 333, 375, 42],\n",
- " [71, '05:33', '05:47', 333, 347, 14],\n",
- " [72, '05:37', '06:13', 337, 373, 36],\n",
- " [73, '05:37', '06:05', 337, 365, 28],\n",
- " [74, '05:38', '06:33', 338, 393, 55],\n",
- " [75, '05:38', '06:04', 338, 364, 26],\n",
- " [76, '05:38', '06:18', 338, 378, 40],\n",
- " [77, '05:39', '05:54', 339, 354, 15],\n",
- " [78, '05:40', '05:56', 340, 356, 16],\n",
- " [79, '05:40', '06:41', 340, 401, 61],\n",
- " [80, '05:40', '05:50', 340, 350, 10],\n",
- " [81, '05:41', '06:23', 341, 383, 42],\n",
- " [82, '05:41', '06:01', 341, 361, 20],\n",
- " [83, '05:43', '06:08', 343, 368, 25],\n",
- " [84, '05:44', '07:10', 344, 430, 86],\n",
- " [85, '05:44', '05:55', 344, 355, 11],\n",
- " [86, '05:45', '06:44', 345, 404, 59],\n",
- " [87, '05:47', '06:17', 347, 377, 30],\n",
- " [88, '05:48', '07:08', 348, 428, 80],\n",
- " [89, '05:48', '06:30', 348, 390, 42],\n",
- " [90, '05:50', '06:50', 350, 410, 60],\n",
- " [91, '05:50', '06:00', 350, 360, 10],\n",
- " [92, '05:50', '06:00', 350, 360, 10],\n",
- " [93, '05:50', '06:51', 350, 411, 61],\n",
- " [94, '05:52', '06:33', 352, 393, 41],\n",
- " [95, '05:52', '06:36', 352, 396, 44],\n",
- " [96, '05:52', '06:23', 352, 383, 31],\n",
- " [97, '05:54', '06:14', 354, 374, 20],\n",
- " [98, '05:54', '07:20', 354, 440, 86],\n",
- " [99, '05:55', '06:40', 355, 400, 45],\n",
- " [100, '05:55', '06:27', 355, 387, 32],\n",
- " [101, '05:56', '06:35', 356, 395, 39],\n",
- " [102, '05:56', '06:06', 356, 366, 10],\n",
- " [103, '05:57', '06:21', 357, 381, 24],\n",
- " [104, '05:58', '07:23', 358, 443, 85],\n",
- " [105, '05:58', '06:23', 358, 383, 25],\n",
- " [106, '05:58', '06:08', 358, 368, 10],\n",
- " [107, '05:58', '06:43', 358, 403, 45],\n",
- " [108, '06:00', '06:10', 360, 370, 10],\n",
- " [109, '06:00', '06:16', 360, 376, 16],\n",
- " [110, '06:00', '07:01', 360, 421, 61],\n",
- " [111, '06:01', '07:00', 361, 420, 59],\n",
- " [112, '06:01', '06:13', 361, 373, 12],\n",
- " [113, '06:01', '06:45', 361, 405, 44],\n",
- " [114, '06:03', '06:50', 363, 410, 47],\n",
- " [115, '06:04', '06:37', 364, 397, 33],\n",
- " [116, '06:04', '07:30', 364, 450, 86],\n",
- " [117, '06:05', '06:24', 365, 384, 19],\n",
- " [118, '06:06', '06:51', 366, 411, 45],\n",
- " [119, '06:07', '06:43', 367, 403, 36],\n",
- " [120, '06:08', '07:30', 368, 450, 82],\n",
- " [121, '06:10', '06:20', 370, 380, 10],\n",
- " [122, '06:10', '07:17', 370, 437, 67],\n",
- " [123, '06:11', '06:54', 371, 414, 43],\n",
- " [124, '06:11', '06:21', 371, 381, 10],\n",
- " [125, '06:13', '06:38', 373, 398, 25],\n",
- " [126, '06:13', '06:58', 373, 418, 45],\n",
- " [127, '06:13', '06:53', 373, 413, 40],\n",
- " [128, '06:14', '07:03', 374, 423, 49],\n",
- " [129, '06:14', '06:47', 374, 407, 33],\n",
- " [130, '06:14', '07:40', 374, 460, 86],\n",
- " [131, '06:15', '07:15', 375, 435, 60],\n",
- " [132, '06:16', '06:28', 376, 388, 12],\n",
- " [133, '06:16', '06:26', 376, 386, 10],\n",
- " [134, '06:17', '06:34', 377, 394, 17],\n",
- " [135, '06:18', '07:06', 378, 426, 48],\n",
- " [136, '06:18', '07:38', 378, 458, 80],\n",
- " [137, '06:18', '07:02', 378, 422, 44],\n",
- " [138, '06:19', '06:53', 379, 413, 34],\n",
- " [139, '06:20', '07:25', 380, 445, 65],\n",
- " [140, '06:20', '06:36', 380, 396, 16],\n",
- " [141, '06:20', '06:30', 380, 390, 10],\n",
- " [142, '06:20', '06:30', 380, 390, 10],\n",
- " [143, '06:21', '06:49', 381, 409, 28],\n",
- " [144, '06:22', '07:06', 382, 426, 44],\n",
- " [145, '06:24', '07:50', 384, 470, 86],\n",
- " [146, '06:24', '06:57', 384, 417, 33],\n",
- " [147, '06:26', '07:45', 386, 465, 79],\n",
- " [148, '06:26', '07:10', 386, 430, 44],\n",
- " [149, '06:27', '06:44', 387, 404, 17],\n",
- " [150, '06:28', '06:53', 388, 413, 25],\n",
- " [151, '06:28', '07:14', 388, 434, 46],\n",
- " [152, '06:29', '07:03', 389, 423, 34],\n",
- " [153, '06:30', '06:40', 390, 400, 10],\n",
- " [154, '06:30', '07:37', 390, 457, 67],\n",
- " [155, '06:31', '06:43', 391, 403, 12],\n",
- " [156, '06:33', '07:14', 393, 434, 41],\n",
- " [157, '06:33', '07:53', 393, 473, 80],\n",
- " [158, '06:34', '08:16', 394, 496, 102],\n",
- " [159, '06:34', '07:09', 394, 429, 35],\n",
- " [160, '06:34', '07:07', 394, 427, 33],\n",
- " [161, '06:36', '07:21', 396, 441, 45],\n",
- " [162, '06:37', '07:22', 397, 442, 45],\n",
- " [163, '06:37', '06:54', 397, 414, 17],\n",
- " [164, '06:38', '07:30', 398, 450, 52],\n",
- " [165, '06:38', '07:18', 398, 438, 40],\n",
- " [166, '06:39', '07:33', 399, 453, 54],\n",
- " [167, '06:40', '07:52', 400, 472, 72],\n",
- " [168, '06:40', '06:50', 400, 410, 10],\n",
- " [169, '06:40', '07:22', 400, 442, 42],\n",
- " [170, '06:40', '06:56', 400, 416, 16],\n",
- " [171, '06:41', '08:00', 401, 480, 79],\n",
- " [172, '06:42', '07:26', 402, 446, 44],\n",
- " [173, '06:42', '07:13', 402, 433, 31],\n",
- " [174, '06:43', '07:08', 403, 428, 25],\n",
- " [175, '06:43', '07:30', 403, 450, 47],\n",
- " [176, '06:43', '07:23', 403, 443, 40],\n",
- " [177, '06:44', '07:17', 404, 437, 33],\n",
- " [178, '06:44', '08:13', 404, 493, 89],\n",
- " [179, '06:46', '07:01', 406, 421, 15],\n",
- " [180, '06:46', '06:58', 406, 418, 12],\n",
- " [181, '06:47', '07:04', 407, 424, 17],\n",
- " [182, '06:48', '08:15', 408, 495, 87],\n",
- " [183, '06:48', '07:34', 408, 454, 46],\n",
- " [184, '06:48', '07:37', 408, 457, 49],\n",
- " [185, '06:49', '07:43', 409, 463, 54],\n",
- " [186, '06:50', '08:00', 410, 480, 70],\n",
- " [187, '06:50', '07:00', 410, 420, 10],\n",
- " [188, '06:50', '07:05', 410, 425, 15],\n",
- " [189, '06:51', '07:18', 411, 438, 27],\n",
- " [190, '06:52', '07:36', 412, 456, 44],\n",
- " [191, '06:53', '07:37', 413, 457, 44],\n",
- " [192, '06:54', '08:20', 414, 500, 86],\n",
- " [193, '06:54', '07:27', 414, 447, 33],\n",
- " [194, '06:54', '07:20', 414, 440, 26],\n",
- " [195, '06:56', '08:23', 416, 503, 87],\n",
- " [196, '06:57', '07:12', 417, 432, 15],\n",
- " [197, '06:57', '07:58', 417, 478, 61],\n",
- " [198, '06:57', '07:45', 417, 465, 48],\n",
- " [199, '06:57', '07:40', 417, 460, 43],\n",
- " [200, '06:58', '07:23', 418, 443, 25],\n",
- " [201, '06:59', '07:53', 419, 473, 54],\n",
- " [202, '06:59', '08:07', 419, 487, 68],\n",
- " [203, '07:00', '07:10', 420, 430, 10],\n",
- " [204, '07:00', '07:16', 420, 436, 16],\n",
- " [205, '07:01', '08:30', 421, 510, 89],\n",
- " [206, '07:01', '07:13', 421, 433, 12],\n",
- " [207, '07:01', '07:43', 421, 463, 42],\n",
- " [208, '07:03', '08:30', 423, 510, 87],\n",
- " [209, '07:04', '07:37', 424, 457, 33],\n",
- " [210, '07:04', '07:44', 424, 464, 40],\n",
- " [211, '07:05', '07:52', 425, 472, 47],\n",
- " [212, '07:05', '08:05', 425, 485, 60],\n",
- " [213, '07:05', '07:46', 425, 466, 41],\n",
- " [214, '07:06', '07:51', 426, 471, 45],\n",
- " [215, '07:07', '08:08', 427, 488, 61],\n",
- " [216, '07:07', '07:52', 427, 472, 45],\n",
- " [217, '07:07', '08:16', 427, 496, 69],\n",
- " [218, '07:07', '07:27', 427, 447, 20],\n",
- " [219, '07:09', '07:50', 429, 470, 41],\n",
- " [220, '07:09', '08:40', 429, 520, 91],\n",
- " [221, '07:09', '08:03', 429, 483, 54],\n",
- " [222, '07:10', '07:20', 430, 440, 10],\n",
- " [223, '07:11', '08:36', 431, 516, 85],\n",
- " [224, '07:12', '08:00', 432, 480, 48],\n",
- " [225, '07:12', '07:47', 432, 467, 35],\n",
- " [226, '07:13', '07:54', 433, 474, 41],\n",
- " [227, '07:13', '07:38', 433, 458, 25],\n",
- " [228, '07:14', '07:59', 434, 479, 45],\n",
- " [229, '07:16', '08:50', 436, 530, 94],\n",
- " [230, '07:16', '07:28', 436, 448, 12],\n",
- " [231, '07:17', '07:35', 437, 455, 18],\n",
- " [232, '07:17', '07:58', 437, 478, 41],\n",
- " [233, '07:18', '08:06', 438, 486, 48],\n",
- " [234, '07:18', '08:44', 438, 524, 86],\n",
- " [235, '07:19', '08:13', 439, 493, 54],\n",
- " [236, '07:20', '08:02', 440, 482, 42],\n",
- " [237, '07:20', '08:07', 440, 487, 47],\n",
- " [238, '07:20', '07:30', 440, 450, 10],\n",
- " [239, '07:20', '07:57', 440, 477, 37],\n",
- " [240, '07:20', '07:36', 440, 456, 16],\n",
- " [241, '07:21', '07:48', 441, 468, 27],\n",
- " [242, '07:22', '08:06', 442, 486, 44],\n",
- " [243, '07:22', '08:25', 442, 505, 63],\n",
- " [244, '07:24', '08:27', 444, 507, 63],\n",
- " [245, '07:24', '08:05', 444, 485, 41],\n",
- " [246, '07:26', '08:23', 446, 503, 57],\n",
- " [247, '07:26', '08:52', 446, 532, 86],\n",
- " [248, '07:27', '08:07', 447, 487, 40],\n",
- " [249, '07:27', '07:42', 447, 462, 15],\n",
- " [250, '07:27', '08:15', 447, 495, 48],\n",
- " [251, '07:28', '07:53', 448, 473, 25],\n",
- " [252, '07:28', '08:09', 448, 489, 41],\n",
- " [253, '07:28', '07:38', 448, 458, 10],\n",
- " [254, '07:30', '08:35', 450, 515, 65],\n",
- " [255, '07:31', '07:43', 451, 463, 12],\n",
- " [256, '07:32', '08:13', 452, 493, 41],\n",
- " [257, '07:34', '09:00', 454, 540, 86],\n",
- " [258, '07:34', '08:33', 454, 513, 59],\n",
- " [259, '07:34', '09:04', 454, 544, 90],\n",
- " [260, '07:35', '08:22', 455, 502, 47],\n",
- " [261, '07:35', '07:45', 455, 465, 10],\n",
- " [262, '07:35', '08:16', 455, 496, 41],\n",
- " [263, '07:36', '08:17', 456, 497, 41],\n",
- " [264, '07:36', '08:36', 456, 516, 60],\n",
- " [265, '07:37', '07:50', 457, 470, 13],\n",
- " [266, '07:40', '07:56', 460, 476, 16],\n",
- " [267, '07:40', '08:20', 460, 500, 40],\n",
- " [268, '07:40', '08:45', 460, 525, 65],\n",
- " [269, '07:41', '08:39', 461, 519, 58],\n",
- " [270, '07:41', '07:51', 461, 471, 10],\n",
- " [271, '07:42', '08:30', 462, 510, 48],\n",
- " [272, '07:42', '08:21', 462, 501, 39],\n",
- " [273, '07:43', '08:08', 463, 488, 25],\n",
- " [274, '07:43', '08:24', 463, 504, 41],\n",
- " [275, '07:44', '09:10', 464, 550, 86],\n",
- " [276, '07:44', '08:43', 464, 523, 59],\n",
- " [277, '07:46', '08:28', 466, 508, 42],\n",
- " [278, '07:46', '07:58', 466, 478, 12],\n",
- " [279, '07:47', '08:00', 467, 480, 13],\n",
- " [280, '07:48', '09:14', 468, 554, 86],\n",
- " [281, '07:49', '08:32', 469, 512, 43],\n",
- " [282, '07:50', '08:55', 470, 535, 65],\n",
- " [283, '07:50', '08:00', 470, 480, 10],\n",
- " [284, '07:50', '08:37', 470, 517, 47],\n",
- " [285, '07:50', '08:26', 470, 506, 36],\n",
- " [286, '07:51', '08:18', 471, 498, 27],\n",
- " [287, '07:52', '08:21', 472, 501, 29],\n",
- " [288, '07:53', '08:35', 473, 515, 42],\n",
- " [289, '07:54', '09:19', 474, 559, 85],\n",
- " [290, '07:55', '08:53', 475, 533, 58],\n",
- " [291, '07:56', '08:54', 476, 534, 58],\n",
- " [292, '07:57', '08:39', 477, 519, 42],\n",
- " [293, '07:57', '08:10', 477, 490, 13],\n",
- " [294, '07:58', '08:45', 478, 525, 47],\n",
- " [295, '07:58', '08:23', 478, 503, 25],\n",
- " [296, '08:00', '08:10', 480, 490, 10],\n",
- " [297, '08:00', '09:05', 480, 545, 65],\n",
- " [298, '08:00', '08:16', 480, 496, 16],\n",
- " [299, '08:00', '08:35', 480, 515, 35],\n",
- " [300, '08:01', '08:13', 481, 493, 12],\n",
- " [301, '08:01', '08:43', 481, 523, 42],\n",
- " [302, '08:03', '09:26', 483, 566, 83],\n",
- " [303, '08:04', '09:29', 484, 569, 85],\n",
- " [304, '08:05', '08:21', 485, 501, 16],\n",
- " [305, '08:05', '08:47', 485, 527, 42],\n",
- " [306, '08:06', '08:51', 486, 531, 45],\n",
- " [307, '08:06', '09:03', 486, 543, 57],\n",
- " [308, '08:07', '08:20', 487, 500, 13],\n",
- " [309, '08:08', '08:55', 488, 535, 47],\n",
- " [310, '08:08', '08:50', 488, 530, 42],\n",
- " [311, '08:10', '08:45', 490, 525, 35],\n",
- " [312, '08:10', '09:15', 490, 555, 65],\n",
- " [313, '08:10', '08:20', 490, 500, 10],\n",
- " [314, '08:11', '09:41', 491, 581, 90],\n",
- " [315, '08:12', '08:55', 492, 535, 43],\n",
- " [316, '08:13', '08:38', 493, 518, 25],\n",
- " [317, '08:14', '09:38', 494, 578, 84],\n",
- " [318, '08:15', '08:30', 495, 510, 15],\n",
- " [319, '08:16', '08:30', 496, 510, 14],\n",
- " [320, '08:16', '08:28', 496, 508, 12],\n",
- " [321, '08:16', '09:00', 496, 540, 44],\n",
- " [322, '08:17', '09:13', 497, 553, 56],\n",
- " [323, '08:18', '09:16', 498, 556, 58],\n",
- " [324, '08:18', '09:05', 498, 545, 47],\n",
- " [325, '08:20', '08:36', 500, 516, 16],\n",
- " [326, '08:20', '08:55', 500, 535, 35],\n",
- " [327, '08:20', '09:05', 500, 545, 45],\n",
- " [328, '08:20', '08:30', 500, 510, 10],\n",
- " [329, '08:20', '09:25', 500, 565, 65],\n",
- " [330, '08:21', '08:38', 501, 518, 17],\n",
- " [331, '08:21', '08:47', 501, 527, 26],\n",
- " [332, '08:22', '08:45', 502, 525, 23],\n",
- " [333, '08:23', '09:10', 503, 550, 47],\n",
- " [334, '08:24', '09:48', 504, 588, 84],\n",
- " [335, '08:26', '08:46', 506, 526, 20],\n",
- " [336, '08:27', '09:07', 507, 547, 40],\n",
- " [337, '08:28', '08:50', 508, 530, 22],\n",
- " [338, '08:28', '09:56', 508, 596, 88],\n",
- " [339, '08:28', '09:23', 508, 563, 55],\n",
- " [340, '08:29', '09:20', 509, 560, 51],\n",
- " [341, '08:30', '09:05', 510, 545, 35],\n",
- " [342, '08:30', '08:45', 510, 525, 15],\n",
- " [343, '08:30', '08:40', 510, 520, 10],\n",
- " [344, '08:30', '09:35', 510, 575, 65],\n",
- " [345, '08:31', '08:43', 511, 523, 12],\n",
- " [346, '08:31', '09:13', 511, 553, 42],\n",
- " [347, '08:34', '09:58', 514, 598, 84],\n",
- " [348, '08:35', '08:55', 515, 535, 20],\n",
- " [349, '08:35', '09:15', 515, 555, 40],\n",
- " [350, '08:35', '08:45', 515, 525, 10],\n",
- " [351, '08:36', '08:46', 516, 526, 10],\n",
- " [352, '08:36', '09:00', 516, 540, 24],\n",
- " [353, '08:38', '09:20', 518, 560, 42],\n",
- " [354, '08:38', '09:35', 518, 575, 57],\n",
- " [355, '08:38', '09:14', 518, 554, 36],\n",
- " [356, '08:39', '09:33', 519, 573, 54],\n",
- " [357, '08:40', '09:45', 520, 585, 65],\n",
- " [358, '08:40', '08:50', 520, 530, 10],\n",
- " [359, '08:40', '08:56', 520, 536, 16],\n",
- " [360, '08:42', '09:25', 522, 565, 43],\n",
- " [361, '08:43', '09:08', 523, 548, 25],\n",
- " [362, '08:44', '09:35', 524, 575, 51],\n",
- " [363, '08:45', '09:00', 525, 540, 15],\n",
- " [364, '08:45', '09:05', 525, 545, 20],\n",
- " [365, '08:46', '09:24', 526, 564, 38],\n",
- " [366, '08:46', '08:58', 526, 538, 12],\n",
- " [367, '08:46', '09:30', 526, 570, 44],\n",
- " [368, '08:48', '10:11', 528, 611, 83],\n",
- " [369, '08:48', '10:13', 528, 613, 85],\n",
- " [370, '08:49', '09:43', 529, 583, 54],\n",
- " [371, '08:50', '09:30', 530, 570, 40],\n",
- " [372, '08:50', '10:00', 530, 600, 70],\n",
- " [373, '08:50', '09:00', 530, 540, 10],\n",
- " [374, '08:51', '09:17', 531, 557, 26],\n",
- " [375, '08:53', '09:20', 533, 560, 27],\n",
- " [376, '08:53', '09:35', 533, 575, 42],\n",
- " [377, '08:55', '09:34', 535, 574, 39],\n",
- " [378, '08:55', '09:15', 535, 555, 20],\n",
- " [379, '08:58', '09:38', 538, 578, 40],\n",
- " [380, '08:58', '10:26', 538, 626, 88],\n",
- " [381, '08:59', '09:53', 539, 593, 54],\n",
- " [382, '08:59', '09:50', 539, 590, 51],\n",
- " [383, '09:00', '09:35', 540, 575, 35],\n",
- " [384, '09:00', '09:16', 540, 556, 16],\n",
- " [385, '09:00', '09:10', 540, 550, 10],\n",
- " [386, '09:00', '09:16', 540, 556, 16],\n",
- " [387, '09:01', '09:13', 541, 553, 12],\n",
- " [388, '09:03', '09:45', 543, 585, 42],\n",
- " [389, '09:03', '10:28', 543, 628, 85],\n",
- " [390, '09:05', '09:44', 545, 584, 39],\n",
- " [391, '09:05', '09:25', 545, 565, 20],\n",
- " [392, '09:08', '09:53', 548, 593, 45],\n",
- " [393, '09:08', '10:04', 548, 604, 56],\n",
- " [394, '09:09', '10:03', 549, 603, 54],\n",
- " [395, '09:10', '10:15', 550, 615, 65],\n",
- " [396, '09:10', '09:20', 550, 560, 10],\n",
- " [397, '09:11', '09:38', 551, 578, 27],\n",
- " [398, '09:13', '10:00', 553, 600, 47],\n",
- " [399, '09:14', '09:39', 554, 579, 25],\n",
- " [400, '09:14', '10:05', 554, 605, 51],\n",
- " [401, '09:15', '09:54', 555, 594, 39],\n",
- " [402, '09:16', '09:28', 556, 568, 12],\n",
- " [403, '09:18', '10:43', 558, 643, 85],\n",
- " [404, '09:18', '10:41', 558, 641, 83],\n",
- " [405, '09:18', '09:58', 558, 598, 40],\n",
- " [406, '09:19', '10:13', 559, 613, 54],\n",
- " [407, '09:20', '09:30', 560, 570, 10],\n",
- " [408, '09:20', '09:36', 560, 576, 16],\n",
- " [409, '09:21', '09:47', 561, 587, 26],\n",
- " [410, '09:23', '10:30', 563, 630, 67],\n",
- " [411, '09:23', '10:05', 563, 605, 42],\n",
- " [412, '09:23', '09:49', 563, 589, 26],\n",
- " [413, '09:24', '09:35', 564, 575, 11],\n",
- " [414, '09:25', '09:35', 565, 575, 10],\n",
- " [415, '09:25', '10:04', 565, 604, 39],\n",
- " [416, '09:28', '10:08', 568, 608, 40],\n",
- " [417, '09:29', '09:45', 569, 585, 16],\n",
- " [418, '09:29', '10:20', 569, 620, 51],\n",
- " [419, '09:29', '10:56', 569, 656, 87],\n",
- " [420, '09:29', '10:23', 569, 623, 54],\n",
- " [421, '09:30', '09:40', 570, 580, 10],\n",
- " [422, '09:31', '09:43', 571, 583, 12],\n",
- " [423, '09:33', '10:58', 573, 658, 85],\n",
- " [424, '09:33', '10:15', 573, 615, 42],\n",
- " [425, '09:34', '09:45', 574, 585, 11],\n",
- " [426, '09:35', '10:14', 575, 614, 39],\n",
- " [427, '09:38', '10:45', 578, 645, 67],\n",
- " [428, '09:39', '10:33', 579, 633, 54],\n",
- " [429, '09:40', '09:56', 580, 596, 16],\n",
- " [430, '09:40', '09:50', 580, 590, 10],\n",
- " [431, '09:41', '10:08', 581, 608, 27],\n",
- " [432, '09:41', '10:23', 581, 623, 42],\n",
- " [433, '09:44', '10:35', 584, 635, 51],\n",
- " [434, '09:44', '11:11', 584, 671, 87],\n",
- " [435, '09:44', '09:55', 584, 595, 11],\n",
- " [436, '09:45', '10:24', 585, 624, 39],\n",
- " [437, '09:46', '09:58', 586, 598, 12],\n",
- " [438, '09:48', '10:30', 588, 630, 42],\n",
- " [439, '09:48', '11:13', 588, 673, 85],\n",
- " [440, '09:48', '10:04', 588, 604, 16],\n",
- " [441, '09:49', '10:43', 589, 643, 54],\n",
- " [442, '09:50', '10:00', 590, 600, 10],\n",
- " [443, '09:51', '10:17', 591, 617, 26],\n",
- " [444, '09:53', '10:49', 593, 649, 56],\n",
- " [445, '09:53', '11:00', 593, 660, 67],\n",
- " [446, '09:54', '10:05', 594, 605, 11],\n",
- " [447, '09:55', '10:34', 595, 634, 39],\n",
- " [448, '09:56', '10:38', 596, 638, 42],\n",
- " [449, '09:57', '10:20', 597, 620, 23],\n",
- " [450, '09:59', '11:26', 599, 686, 87],\n",
- " [451, '09:59', '10:50', 599, 650, 51],\n",
- " [452, '09:59', '10:53', 599, 653, 54],\n",
- " [453, '10:00', '10:16', 600, 616, 16],\n",
- " [454, '10:00', '10:10', 600, 610, 10],\n",
- " [455, '10:01', '10:13', 601, 613, 12],\n",
- " [456, '10:03', '11:28', 603, 688, 85],\n",
- " [457, '10:03', '10:45', 603, 645, 42],\n",
- " [458, '10:04', '10:15', 604, 615, 11],\n",
- " [459, '10:05', '10:44', 605, 644, 39],\n",
- " [460, '10:08', '11:15', 608, 675, 67],\n",
- " [461, '10:09', '11:03', 609, 663, 54],\n",
- " [462, '10:10', '10:20', 610, 620, 10],\n",
- " [463, '10:11', '10:38', 611, 638, 27],\n",
- " [464, '10:11', '10:53', 611, 653, 42],\n",
- " [465, '10:14', '11:05', 614, 665, 51],\n",
- " [466, '10:14', '11:41', 614, 701, 87],\n",
- " [467, '10:14', '10:25', 614, 625, 11],\n",
- " [468, '10:15', '10:54', 615, 654, 39],\n",
- " [469, '10:16', '10:28', 616, 628, 12],\n",
- " [470, '10:18', '11:43', 618, 703, 85],\n",
- " [471, '10:18', '11:00', 618, 660, 42],\n",
- " [472, '10:19', '11:13', 619, 673, 54],\n",
- " [473, '10:20', '10:30', 620, 630, 10],\n",
- " [474, '10:20', '10:36', 620, 636, 16],\n",
- " [475, '10:21', '10:47', 621, 647, 26],\n",
- " [476, '10:23', '11:30', 623, 690, 67],\n",
- " [477, '10:23', '10:45', 623, 645, 22],\n",
- " [478, '10:24', '10:35', 624, 635, 11],\n",
- " [479, '10:25', '11:04', 625, 664, 39],\n",
- " [480, '10:26', '11:08', 626, 668, 42],\n",
- " [481, '10:29', '11:20', 629, 680, 51],\n",
- " [482, '10:29', '11:23', 629, 683, 54],\n",
- " [483, '10:29', '11:56', 629, 716, 87],\n",
- " [484, '10:30', '10:40', 630, 640, 10],\n",
- " [485, '10:31', '10:43', 631, 643, 12],\n",
- " [486, '10:33', '11:15', 633, 675, 42],\n",
- " [487, '10:33', '11:58', 633, 718, 85],\n",
- " [488, '10:34', '10:45', 634, 645, 11],\n",
- " [489, '10:35', '11:14', 635, 674, 39],\n",
- " [490, '10:38', '11:45', 638, 705, 67],\n",
- " [491, '10:39', '11:33', 639, 693, 54],\n",
- " [492, '10:40', '10:50', 640, 650, 10],\n",
- " [493, '10:40', '10:56', 640, 656, 16],\n",
- " [494, '10:41', '11:23', 641, 683, 42],\n",
- " [495, '10:41', '11:08', 641, 668, 27],\n",
- " [496, '10:44', '12:11', 644, 731, 87],\n",
- " [497, '10:44', '11:35', 644, 695, 51],\n",
- " [498, '10:44', '10:55', 644, 655, 11],\n",
- " [499, '10:45', '11:24', 645, 684, 39],\n",
- " [500, '10:46', '10:58', 646, 658, 12],\n",
- " [501, '10:48', '12:13', 648, 733, 85],\n",
- " [502, '10:48', '11:30', 648, 690, 42],\n",
- " [503, '10:49', '11:43', 649, 703, 54],\n",
- " [504, '10:50', '11:00', 650, 660, 10],\n",
- " [505, '10:51', '11:17', 651, 677, 26],\n",
- " [506, '10:53', '12:00', 653, 720, 67],\n",
- " [507, '10:53', '11:20', 653, 680, 27],\n",
- " [508, '10:54', '11:05', 654, 665, 11],\n",
- " [509, '10:55', '11:34', 655, 694, 39],\n",
- " [510, '10:56', '11:38', 656, 698, 42],\n",
- " [511, '10:59', '11:14', 659, 674, 15],\n",
- " [512, '10:59', '12:26', 659, 746, 87],\n",
- " [513, '10:59', '11:53', 659, 713, 54],\n",
- " [514, '10:59', '11:50', 659, 710, 51],\n",
- " [515, '11:00', '11:16', 660, 676, 16],\n",
- " [516, '11:00', '11:10', 660, 670, 10],\n",
- " [517, '11:01', '11:13', 661, 673, 12],\n",
- " [518, '11:03', '11:45', 663, 705, 42],\n",
- " [519, '11:03', '12:28', 663, 748, 85],\n",
- " [520, '11:04', '11:15', 664, 675, 11],\n",
- " [521, '11:05', '11:44', 665, 704, 39],\n",
- " [522, '11:08', '12:15', 668, 735, 67],\n",
- " [523, '11:09', '12:03', 669, 723, 54],\n",
- " [524, '11:10', '11:20', 670, 680, 10],\n",
- " [525, '11:11', '11:38', 671, 698, 27],\n",
- " [526, '11:11', '11:53', 671, 713, 42],\n",
- " [527, '11:14', '11:25', 674, 685, 11],\n",
- " [528, '11:14', '12:05', 674, 725, 51],\n",
- " [529, '11:14', '12:38', 674, 758, 84],\n",
- " [530, '11:14', '12:41', 674, 761, 87],\n",
- " [531, '11:15', '11:54', 675, 714, 39],\n",
- " [532, '11:16', '11:28', 676, 688, 12],\n",
- " [533, '11:18', '12:00', 678, 720, 42],\n",
- " [534, '11:19', '12:13', 679, 733, 54],\n",
- " [535, '11:20', '11:30', 680, 690, 10],\n",
- " [536, '11:20', '11:36', 680, 696, 16],\n",
- " [537, '11:21', '11:47', 681, 707, 26],\n",
- " [538, '11:23', '12:30', 683, 750, 67],\n",
- " [539, '11:23', '11:49', 683, 709, 26],\n",
- " [540, '11:24', '12:48', 684, 768, 84],\n",
- " [541, '11:24', '11:35', 684, 695, 11],\n",
- " [542, '11:25', '12:04', 685, 724, 39],\n",
- " [543, '11:26', '12:08', 686, 728, 42],\n",
- " [544, '11:29', '11:44', 689, 704, 15],\n",
- " [545, '11:29', '12:23', 689, 743, 54],\n",
- " [546, '11:29', '12:20', 689, 740, 51],\n",
- " [547, '11:29', '12:54', 689, 774, 85],\n",
- " [548, '11:30', '11:40', 690, 700, 10],\n",
- " [549, '11:31', '11:43', 691, 703, 12],\n",
- " [550, '11:33', '12:15', 693, 735, 42],\n",
- " [551, '11:34', '12:58', 694, 778, 84],\n",
- " [552, '11:34', '11:45', 694, 705, 11],\n",
- " [553, '11:35', '12:14', 695, 734, 39],\n",
- " [554, '11:38', '12:45', 698, 765, 67],\n",
- " [555, '11:39', '12:33', 699, 753, 54],\n",
- " [556, '11:40', '11:56', 700, 716, 16],\n",
- " [557, '11:40', '11:50', 700, 710, 10],\n",
- " [558, '11:41', '12:08', 701, 728, 27],\n",
- " [559, '11:41', '12:23', 701, 743, 42],\n",
- " [560, '11:44', '11:55', 704, 715, 11],\n",
- " [561, '11:44', '13:14', 704, 794, 90],\n",
- " [562, '11:44', '13:08', 704, 788, 84],\n",
- " [563, '11:44', '12:35', 704, 755, 51],\n",
- " [564, '11:45', '12:24', 705, 744, 39],\n",
- " [565, '11:46', '11:58', 706, 718, 12],\n",
- " [566, '11:48', '12:30', 708, 750, 42],\n",
- " [567, '11:49', '12:43', 709, 763, 54],\n",
- " [568, '11:50', '12:00', 710, 720, 10],\n",
- " [569, '11:51', '12:17', 711, 737, 26],\n",
- " [570, '11:53', '12:49', 713, 769, 56],\n",
- " [571, '11:53', '13:00', 713, 780, 67],\n",
- " [572, '11:54', '13:18', 714, 798, 84],\n",
- " [573, '11:54', '12:05', 714, 725, 11],\n",
- " [574, '11:55', '12:40', 715, 760, 45],\n",
- " [575, '11:55', '12:34', 715, 754, 39],\n",
- " [576, '11:56', '12:35', 716, 755, 39],\n",
- " [577, '11:57', '12:20', 717, 740, 23],\n",
- " [578, '11:58', '12:29', 718, 749, 31],\n",
- " [579, '11:59', '12:50', 719, 770, 51],\n",
- " [580, '11:59', '12:53', 719, 773, 54],\n",
- " [581, '11:59', '13:24', 719, 804, 85],\n",
- " [582, '11:59', '12:14', 719, 734, 15],\n",
- " [583, '12:00', '12:16', 720, 736, 16],\n",
- " [584, '12:00', '12:10', 720, 730, 10],\n",
- " [585, '12:01', '12:45', 721, 765, 44],\n",
- " [586, '12:01', '12:13', 721, 733, 12],\n",
- " [587, '12:03', '12:50', 723, 770, 47],\n",
- " [588, '12:04', '12:15', 724, 735, 11],\n",
- " [589, '12:04', '13:04', 724, 784, 60],\n",
- " [590, '12:04', '13:28', 724, 808, 84],\n",
- " [591, '12:05', '12:44', 725, 764, 39],\n",
- " [592, '12:08', '13:11', 728, 791, 63],\n",
- " [593, '12:08', '12:39', 728, 759, 31],\n",
- " [594, '12:09', '13:03', 729, 783, 54],\n",
- " [595, '12:10', '12:20', 730, 740, 10],\n",
- " [596, '12:11', '12:55', 731, 775, 44],\n",
- " [597, '12:11', '12:38', 731, 758, 27],\n",
- " [598, '12:14', '13:05', 734, 785, 51],\n",
- " [599, '12:14', '12:25', 734, 745, 11],\n",
- " [600, '12:14', '13:44', 734, 824, 90],\n",
- " [601, '12:14', '13:38', 734, 818, 84],\n",
- " [602, '12:15', '12:54', 735, 774, 39],\n",
- " [603, '12:16', '12:28', 736, 748, 12],\n",
- " [604, '12:18', '13:00', 738, 780, 42],\n",
- " [605, '12:19', '13:13', 739, 793, 54],\n",
- " [606, '12:20', '12:30', 740, 750, 10],\n",
- " [607, '12:20', '13:31', 740, 811, 71],\n",
- " [608, '12:20', '12:30', 740, 750, 10],\n",
- " [609, '12:20', '12:36', 740, 756, 16],\n",
- " [610, '12:21', '12:47', 741, 767, 26],\n",
- " [611, '12:23', '12:45', 743, 765, 22],\n",
- " [612, '12:24', '12:35', 744, 755, 11],\n",
- " [613, '12:24', '13:48', 744, 828, 84],\n",
- " [614, '12:25', '13:10', 745, 790, 45],\n",
- " [615, '12:25', '13:04', 745, 784, 39],\n",
- " [616, '12:26', '13:05', 746, 785, 39],\n",
- " [617, '12:28', '13:54', 748, 834, 86],\n",
- " [618, '12:28', '12:38', 748, 758, 10],\n",
- " [619, '12:28', '13:15', 748, 795, 47],\n",
- " [620, '12:29', '13:23', 749, 803, 54],\n",
- " [621, '12:30', '13:41', 750, 821, 71],\n",
- " [622, '12:30', '12:40', 750, 760, 10],\n",
- " [623, '12:31', '13:15', 751, 795, 44],\n",
- " [624, '12:31', '12:43', 751, 763, 12],\n",
- " [625, '12:33', '12:48', 753, 768, 15],\n",
- " [626, '12:33', '13:20', 753, 800, 47],\n",
- " [627, '12:34', '13:58', 754, 838, 84],\n",
- " [628, '12:34', '13:34', 754, 814, 60],\n",
- " [629, '12:34', '12:45', 754, 765, 11],\n",
- " [630, '12:35', '13:14', 755, 794, 39],\n",
- " [631, '12:38', '13:25', 758, 805, 47],\n",
- " [632, '12:38', '13:25', 758, 805, 47],\n",
- " [633, '12:38', '14:04', 758, 844, 86],\n",
- " [634, '12:39', '13:33', 759, 813, 54],\n",
- " [635, '12:40', '13:51', 760, 831, 71],\n",
- " [636, '12:40', '12:50', 760, 770, 10],\n",
- " [637, '12:40', '12:56', 760, 776, 16],\n",
- " [638, '12:41', '13:08', 761, 788, 27],\n",
- " [639, '12:43', '13:30', 763, 810, 47],\n",
- " [640, '12:44', '12:55', 764, 775, 11],\n",
- " [641, '12:44', '14:08', 764, 848, 84],\n",
- " [642, '12:45', '13:24', 765, 804, 39],\n",
- " [643, '12:46', '12:58', 766, 778, 12],\n",
- " [644, '12:46', '13:21', 766, 801, 35],\n",
- " [645, '12:48', '14:14', 768, 854, 86],\n",
- " [646, '12:48', '13:35', 768, 815, 47],\n",
- " [647, '12:48', '12:58', 768, 778, 10],\n",
- " [648, '12:48', '13:35', 768, 815, 47],\n",
- " [649, '12:49', '13:43', 769, 823, 54],\n",
- " [650, '12:50', '14:01', 770, 841, 71],\n",
- " [651, '12:50', '13:00', 770, 780, 10],\n",
- " [652, '12:50', '13:00', 770, 780, 10],\n",
- " [653, '12:51', '13:17', 771, 797, 26],\n",
- " [654, '12:53', '13:20', 773, 800, 27],\n",
- " [655, '12:53', '13:24', 773, 804, 31],\n",
- " [656, '12:53', '13:40', 773, 820, 47],\n",
- " [657, '12:54', '14:18', 774, 858, 84],\n",
- " [658, '12:54', '13:05', 774, 785, 11],\n",
- " [659, '12:55', '13:34', 775, 814, 39],\n",
- " [660, '12:58', '14:24', 778, 864, 86],\n",
- " [661, '12:58', '13:25', 778, 805, 27],\n",
- " [662, '12:58', '13:45', 778, 825, 47],\n",
- " [663, '12:58', '13:45', 778, 825, 47],\n",
- " [664, '12:59', '13:53', 779, 833, 54],\n",
- " [665, '13:00', '13:10', 780, 790, 10],\n",
- " [666, '13:00', '13:16', 780, 796, 16],\n",
- " [667, '13:00', '14:11', 780, 851, 71],\n",
- " [668, '13:01', '13:13', 781, 793, 12],\n",
- " [669, '13:03', '13:34', 783, 814, 31],\n",
- " [670, '13:03', '13:50', 783, 830, 47],\n",
- " [671, '13:04', '13:15', 784, 795, 11],\n",
- " [672, '13:04', '14:28', 784, 868, 84],\n",
- " [673, '13:05', '13:44', 785, 824, 39],\n",
- " [674, '13:08', '13:55', 788, 835, 47],\n",
- " [675, '13:08', '14:34', 788, 874, 86],\n",
- " [676, '13:08', '13:55', 788, 835, 47],\n",
- " [677, '13:09', '14:03', 789, 843, 54],\n",
- " [678, '13:10', '13:20', 790, 800, 10],\n",
- " [679, '13:10', '14:21', 790, 861, 71],\n",
- " [680, '13:13', '14:00', 793, 840, 47],\n",
- " [681, '13:13', '13:40', 793, 820, 27],\n",
- " [682, '13:14', '14:38', 794, 878, 84],\n",
- " [683, '13:14', '13:25', 794, 805, 11],\n",
- " [684, '13:15', '13:54', 795, 834, 39],\n",
- " [685, '13:16', '13:28', 796, 808, 12],\n",
- " [686, '13:18', '14:05', 798, 845, 47],\n",
- " [687, '13:18', '14:44', 798, 884, 86],\n",
- " [688, '13:18', '14:05', 798, 845, 47],\n",
- " [689, '13:19', '14:13', 799, 853, 54],\n",
- " [690, '13:20', '13:36', 800, 816, 16],\n",
- " [691, '13:20', '14:31', 800, 871, 71],\n",
- " [692, '13:20', '13:30', 800, 810, 10],\n",
- " [693, '13:21', '13:47', 801, 827, 26],\n",
- " [694, '13:23', '14:10', 803, 850, 47],\n",
- " [695, '13:23', '13:49', 803, 829, 26],\n",
- " [696, '13:24', '14:48', 804, 888, 84],\n",
- " [697, '13:24', '13:35', 804, 815, 11],\n",
- " [698, '13:25', '14:04', 805, 844, 39],\n",
- " [699, '13:28', '14:15', 808, 855, 47],\n",
- " [700, '13:28', '14:54', 808, 894, 86],\n",
- " [701, '13:28', '13:55', 808, 835, 27],\n",
- " [702, '13:28', '14:15', 808, 855, 47],\n",
- " [703, '13:29', '14:23', 809, 863, 54],\n",
- " [704, '13:30', '13:40', 810, 820, 10],\n",
- " [705, '13:30', '14:41', 810, 881, 71],\n",
- " [706, '13:31', '13:43', 811, 823, 12],\n",
- " [707, '13:33', '14:20', 813, 860, 47],\n",
- " [708, '13:34', '14:58', 814, 898, 84],\n",
- " [709, '13:34', '13:45', 814, 825, 11],\n",
- " [710, '13:35', '14:14', 815, 854, 39],\n",
- " [711, '13:38', '14:25', 818, 865, 47],\n",
- " [712, '13:38', '14:25', 818, 865, 47],\n",
- " [713, '13:38', '15:04', 818, 904, 86],\n",
- " [714, '13:39', '14:33', 819, 873, 54],\n",
- " [715, '13:40', '13:50', 820, 830, 10],\n",
- " [716, '13:40', '13:56', 820, 836, 16],\n",
- " [717, '13:40', '14:51', 820, 891, 71],\n",
- " [718, '13:43', '14:30', 823, 870, 47],\n",
- " [719, '13:43', '14:10', 823, 850, 27],\n",
- " [720, '13:44', '15:09', 824, 909, 85],\n",
- " [721, '13:44', '13:55', 824, 835, 11],\n",
- " [722, '13:45', '14:24', 825, 864, 39],\n",
- " [723, '13:46', '13:58', 826, 838, 12],\n",
- " [724, '13:48', '14:35', 828, 875, 47],\n",
- " [725, '13:48', '15:14', 828, 914, 86],\n",
- " [726, '13:48', '14:35', 828, 875, 47],\n",
- " [727, '13:49', '14:43', 829, 883, 54],\n",
- " [728, '13:50', '14:00', 830, 840, 10],\n",
- " [729, '13:50', '15:01', 830, 901, 71],\n",
- " [730, '13:51', '14:17', 831, 857, 26],\n",
- " [731, '13:53', '14:40', 833, 880, 47],\n",
- " [732, '13:53', '14:49', 833, 889, 56],\n",
- " [733, '13:54', '14:05', 834, 845, 11],\n",
- " [734, '13:54', '15:19', 834, 919, 85],\n",
- " [735, '13:55', '14:34', 835, 874, 39],\n",
- " [736, '13:57', '14:20', 837, 860, 23],\n",
- " [737, '13:58', '15:24', 838, 924, 86],\n",
- " [738, '13:58', '14:45', 838, 885, 47],\n",
- " [739, '13:58', '14:45', 838, 885, 47],\n",
- " [740, '13:58', '14:25', 838, 865, 27],\n",
- " [741, '13:59', '14:53', 839, 893, 54],\n",
- " [742, '14:00', '14:16', 840, 856, 16],\n",
- " [743, '14:00', '14:10', 840, 850, 10],\n",
- " [744, '14:00', '15:11', 840, 911, 71],\n",
- " [745, '14:01', '14:13', 841, 853, 12],\n",
- " [746, '14:03', '14:50', 843, 890, 47],\n",
- " [747, '14:04', '14:15', 844, 855, 11],\n",
- " [748, '14:04', '15:29', 844, 929, 85],\n",
- " [749, '14:05', '14:44', 845, 884, 39],\n",
- " [750, '14:08', '14:55', 848, 895, 47],\n",
- " [751, '14:08', '14:55', 848, 895, 47],\n",
- " [752, '14:08', '15:34', 848, 934, 86],\n",
- " [753, '14:09', '15:03', 849, 903, 54],\n",
- " [754, '14:10', '15:21', 850, 921, 71],\n",
- " [755, '14:10', '14:20', 850, 860, 10],\n",
- " [756, '14:13', '15:00', 853, 900, 47],\n",
- " [757, '14:13', '14:40', 853, 880, 27],\n",
- " [758, '14:14', '15:40', 854, 940, 86],\n",
- " [759, '14:14', '14:25', 854, 865, 11],\n",
- " [760, '14:15', '14:54', 855, 894, 39],\n",
- " [761, '14:16', '14:28', 856, 868, 12],\n",
- " [762, '14:18', '15:05', 858, 905, 47],\n",
- " [763, '14:18', '15:44', 858, 944, 86],\n",
- " [764, '14:18', '15:05', 858, 905, 47],\n",
- " [765, '14:19', '15:13', 859, 913, 54],\n",
- " [766, '14:20', '15:31', 860, 931, 71],\n",
- " [767, '14:20', '14:30', 860, 870, 10],\n",
- " [768, '14:20', '14:36', 860, 876, 16],\n",
- " [769, '14:21', '14:47', 861, 887, 26],\n",
- " [770, '14:23', '15:10', 863, 910, 47],\n",
- " [771, '14:23', '14:45', 863, 885, 22],\n",
- " [772, '14:24', '15:50', 864, 950, 86],\n",
- " [773, '14:24', '14:35', 864, 875, 11],\n",
- " [774, '14:25', '15:02', 865, 902, 37],\n",
- " [775, '14:26', '14:52', 866, 892, 26],\n",
- " [776, '14:28', '15:15', 868, 915, 47],\n",
- " [777, '14:28', '14:55', 868, 895, 27],\n",
- " [778, '14:28', '15:54', 868, 954, 86],\n",
- " [779, '14:28', '15:15', 868, 915, 47],\n",
- " [780, '14:29', '15:23', 869, 923, 54],\n",
- " [781, '14:30', '15:41', 870, 941, 71],\n",
- " [782, '14:30', '14:40', 870, 880, 10],\n",
- " [783, '14:31', '14:43', 871, 883, 12],\n",
- " [784, '14:33', '15:20', 873, 920, 47],\n",
- " [785, '14:34', '16:00', 874, 960, 86],\n",
- " [786, '14:34', '14:45', 874, 885, 11],\n",
- " [787, '14:35', '15:11', 875, 911, 36],\n",
- " [788, '14:38', '15:25', 878, 925, 47],\n",
- " [789, '14:38', '15:25', 878, 925, 47],\n",
- " [790, '14:38', '16:04', 878, 964, 86],\n",
- " [791, '14:39', '15:33', 879, 933, 54],\n",
- " [792, '14:40', '14:50', 880, 890, 10],\n",
- " [793, '14:40', '15:51', 880, 951, 71],\n",
- " [794, '14:40', '14:56', 880, 896, 16],\n",
- " [795, '14:43', '15:30', 883, 930, 47],\n",
- " [796, '14:43', '15:10', 883, 910, 27],\n",
- " [797, '14:44', '15:00', 884, 900, 16],\n",
- " [798, '14:44', '16:10', 884, 970, 86],\n",
- " [799, '14:45', '15:19', 885, 919, 34],\n",
- " [800, '14:46', '14:58', 886, 898, 12],\n",
- " [801, '14:48', '15:35', 888, 935, 47],\n",
- " [802, '14:48', '15:35', 888, 935, 47],\n",
- " [803, '14:48', '17:04', 888, 1024, 136],\n",
- " [804, '14:49', '15:43', 889, 943, 54],\n",
- " [805, '14:50', '16:01', 890, 961, 71],\n",
- " [806, '14:50', '15:00', 890, 900, 10],\n",
- " [807, '14:51', '15:17', 891, 917, 26],\n",
- " [808, '14:52', '15:27', 892, 927, 35],\n",
- " [809, '14:52', '15:21', 892, 921, 29],\n",
- " [810, '14:53', '15:40', 893, 940, 47],\n",
- " [811, '14:54', '15:08', 894, 908, 14],\n",
- " [812, '14:54', '16:20', 894, 980, 86],\n",
- " [813, '14:58', '16:24', 898, 984, 86],\n",
- " [814, '14:58', '15:45', 898, 945, 47],\n",
- " [815, '14:58', '15:25', 898, 925, 27],\n",
- " [816, '14:58', '15:45', 898, 945, 47],\n",
- " [817, '14:59', '15:53', 899, 953, 54],\n",
- " [818, '15:00', '15:10', 900, 910, 10],\n",
- " [819, '15:00', '15:35', 900, 935, 35],\n",
- " [820, '15:00', '16:11', 900, 971, 71],\n",
- " [821, '15:00', '15:16', 900, 916, 16],\n",
- " [822, '15:01', '15:13', 901, 913, 12],\n",
- " [823, '15:02', '15:16', 902, 916, 14],\n",
- " [824, '15:03', '15:50', 903, 950, 47],\n",
- " [825, '15:04', '16:30', 904, 990, 86],\n",
- " [826, '15:08', '16:34', 908, 994, 86],\n",
- " [827, '15:08', '15:55', 908, 955, 47],\n",
- " [828, '15:08', '15:55', 908, 955, 47],\n",
- " [829, '15:08', '15:45', 908, 945, 37],\n",
- " [830, '15:09', '16:14', 909, 974, 65],\n",
- " [831, '15:09', '16:03', 909, 963, 54],\n",
- " [832, '15:10', '16:21', 910, 981, 71],\n",
- " [833, '15:10', '15:20', 910, 920, 10],\n",
- " [834, '15:11', '15:24', 911, 924, 13],\n",
- " [835, '15:12', '15:36', 912, 936, 24],\n",
- " [836, '15:13', '16:00', 913, 960, 47],\n",
- " [837, '15:13', '15:40', 913, 940, 27],\n",
- " [838, '15:14', '16:40', 914, 1000, 86],\n",
- " [839, '15:16', '15:28', 916, 928, 12],\n",
- " [840, '15:16', '15:55', 916, 955, 39],\n",
- " [841, '15:18', '16:05', 918, 965, 47],\n",
- " [842, '15:18', '16:44', 918, 1004, 86],\n",
- " [843, '15:18', '16:05', 918, 965, 47],\n",
- " [844, '15:19', '16:13', 919, 973, 54],\n",
- " [845, '15:19', '15:34', 919, 934, 15],\n",
- " [846, '15:20', '15:30', 920, 930, 10],\n",
- " [847, '15:20', '16:31', 920, 991, 71],\n",
- " [848, '15:20', '15:36', 920, 936, 16],\n",
- " [849, '15:21', '15:47', 921, 947, 26],\n",
- " [850, '15:21', '16:06', 921, 966, 45],\n",
- " [851, '15:23', '16:10', 923, 970, 47],\n",
- " [852, '15:24', '16:50', 924, 1010, 86],\n",
- " [853, '15:24', '16:05', 924, 965, 41],\n",
- " [854, '15:27', '15:51', 927, 951, 24],\n",
- " [855, '15:27', '15:44', 927, 944, 17],\n",
- " [856, '15:28', '16:15', 928, 975, 47],\n",
- " [857, '15:28', '16:54', 928, 1014, 86],\n",
- " [858, '15:28', '16:15', 928, 975, 47],\n",
- " [859, '15:28', '15:55', 928, 955, 27],\n",
- " [860, '15:29', '16:23', 929, 983, 54],\n",
- " [861, '15:30', '16:41', 930, 1001, 71],\n",
- " [862, '15:30', '15:40', 930, 940, 10],\n",
- " [863, '15:31', '15:43', 931, 943, 12],\n",
- " [864, '15:33', '16:20', 933, 980, 47],\n",
- " [865, '15:34', '17:00', 934, 1020, 86],\n",
- " [866, '15:34', '16:15', 934, 975, 41],\n",
- " [867, '15:35', '15:54', 935, 954, 19],\n",
- " [868, '15:36', '16:21', 936, 981, 45],\n",
- " [869, '15:38', '16:25', 938, 985, 47],\n",
- " [870, '15:38', '16:25', 938, 985, 47],\n",
- " [871, '15:38', '16:39', 938, 999, 61],\n",
- " [872, '15:39', '16:33', 939, 993, 54],\n",
- " [873, '15:40', '15:50', 940, 950, 10],\n",
- " [874, '15:40', '16:51', 940, 1011, 71],\n",
- " [875, '15:40', '15:56', 940, 956, 16],\n",
- " [876, '15:43', '16:10', 943, 970, 27],\n",
- " [877, '15:43', '16:30', 943, 990, 47],\n",
- " [878, '15:44', '17:10', 944, 1030, 86],\n",
- " [879, '15:44', '16:25', 944, 985, 41],\n",
- " [880, '15:45', '16:04', 945, 964, 19],\n",
- " [881, '15:46', '15:58', 946, 958, 12],\n",
- " [882, '15:48', '16:35', 948, 995, 47],\n",
- " [883, '15:48', '16:35', 948, 995, 47],\n",
- " [884, '15:48', '17:14', 948, 1034, 86],\n",
- " [885, '15:49', '16:43', 949, 1003, 54],\n",
- " [886, '15:50', '16:00', 950, 960, 10],\n",
- " [887, '15:50', '17:01', 950, 1021, 71],\n",
- " [888, '15:51', '16:18', 951, 978, 27],\n",
- " [889, '15:52', '16:36', 952, 996, 44],\n",
- " [890, '15:53', '16:40', 953, 1000, 47],\n",
- " [891, '15:54', '17:20', 954, 1040, 86],\n",
- " [892, '15:54', '16:35', 954, 995, 41],\n",
- " [893, '15:55', '16:14', 955, 974, 19],\n",
- " [894, '15:58', '16:25', 958, 985, 27],\n",
- " [895, '15:58', '16:45', 958, 1005, 47],\n",
- " [896, '15:58', '16:45', 958, 1005, 47],\n",
- " [897, '15:58', '17:24', 958, 1044, 86],\n",
- " [898, '15:59', '17:11', 959, 1031, 72],\n",
- " [899, '15:59', '16:53', 959, 1013, 54],\n",
- " [900, '16:00', '16:10', 960, 970, 10],\n",
- " [901, '16:00', '16:16', 960, 976, 16],\n",
- " [902, '16:01', '16:13', 961, 973, 12],\n",
- " [903, '16:03', '16:50', 963, 1010, 47],\n",
- " [904, '16:04', '17:30', 964, 1050, 86],\n",
- " [905, '16:04', '16:45', 964, 1005, 41],\n",
- " [906, '16:05', '16:24', 965, 984, 19],\n",
- " [907, '16:06', '16:51', 966, 1011, 45],\n",
- " [908, '16:08', '16:55', 968, 1015, 47],\n",
- " [909, '16:08', '17:34', 968, 1054, 86],\n",
- " [910, '16:08', '16:55', 968, 1015, 47],\n",
- " [911, '16:09', '17:03', 969, 1023, 54],\n",
- " [912, '16:09', '17:21', 969, 1041, 72],\n",
- " [913, '16:10', '16:20', 970, 980, 10],\n",
- " [914, '16:13', '16:40', 973, 1000, 27],\n",
- " [915, '16:13', '17:00', 973, 1020, 47],\n",
- " [916, '16:14', '16:55', 974, 1015, 41],\n",
- " [917, '16:14', '17:40', 974, 1060, 86],\n",
- " [918, '16:15', '16:34', 975, 994, 19],\n",
- " [919, '16:16', '16:28', 976, 988, 12],\n",
- " [920, '16:18', '17:05', 978, 1025, 47],\n",
- " [921, '16:18', '17:05', 978, 1025, 47],\n",
- " [922, '16:18', '17:44', 978, 1064, 86],\n",
- " [923, '16:19', '17:31', 979, 1051, 72],\n",
- " [924, '16:19', '17:13', 979, 1033, 54],\n",
- " [925, '16:20', '16:30', 980, 990, 10],\n",
- " [926, '16:20', '16:36', 980, 996, 16],\n",
- " [927, '16:21', '16:48', 981, 1008, 27],\n",
- " [928, '16:22', '17:06', 982, 1026, 44],\n",
- " [929, '16:23', '17:10', 983, 1030, 47],\n",
- " [930, '16:24', '17:05', 984, 1025, 41],\n",
- " [931, '16:24', '17:50', 984, 1070, 86],\n",
- " [932, '16:25', '16:44', 985, 1004, 19],\n",
- " [933, '16:28', '17:15', 988, 1035, 47],\n",
- " [934, '16:28', '17:15', 988, 1035, 47],\n",
- " [935, '16:28', '16:55', 988, 1015, 27],\n",
- " [936, '16:28', '17:54', 988, 1074, 86],\n",
- " [937, '16:29', '17:23', 989, 1043, 54],\n",
- " [938, '16:29', '17:41', 989, 1061, 72],\n",
- " [939, '16:30', '16:40', 990, 1000, 10],\n",
- " [940, '16:31', '16:43', 991, 1003, 12],\n",
- " [941, '16:33', '17:20', 993, 1040, 47],\n",
- " [942, '16:34', '17:15', 994, 1035, 41],\n",
- " [943, '16:34', '18:00', 994, 1080, 86],\n",
- " [944, '16:35', '16:54', 995, 1014, 19],\n",
- " [945, '16:36', '17:21', 996, 1041, 45],\n",
- " [946, '16:38', '17:25', 998, 1045, 47],\n",
- " [947, '16:38', '17:25', 998, 1045, 47],\n",
- " [948, '16:38', '18:04', 998, 1084, 86],\n",
- " [949, '16:39', '17:33', 999, 1053, 54],\n",
- " [950, '16:39', '17:51', 999, 1071, 72],\n",
- " [951, '16:40', '16:56', 1000, 1016, 16],\n",
- " [952, '16:40', '16:50', 1000, 1010, 10],\n",
- " [953, '16:43', '17:10', 1003, 1030, 27],\n",
- " [954, '16:43', '17:30', 1003, 1050, 47],\n",
- " [955, '16:44', '17:25', 1004, 1045, 41],\n",
- " [956, '16:44', '18:10', 1004, 1090, 86],\n",
- " [957, '16:45', '17:04', 1005, 1024, 19],\n",
- " [958, '16:46', '16:58', 1006, 1018, 12],\n",
- " [959, '16:48', '18:14', 1008, 1094, 86],\n",
- " [960, '16:48', '17:35', 1008, 1055, 47],\n",
- " [961, '16:48', '17:35', 1008, 1055, 47],\n",
- " [962, '16:49', '18:01', 1009, 1081, 72],\n",
- " [963, '16:49', '17:43', 1009, 1063, 54],\n",
- " [964, '16:50', '17:00', 1010, 1020, 10],\n",
- " [965, '16:51', '17:18', 1011, 1038, 27],\n",
- " [966, '16:52', '17:36', 1012, 1056, 44],\n",
- " [967, '16:53', '17:40', 1013, 1060, 47],\n",
- " [968, '16:54', '18:20', 1014, 1100, 86],\n",
- " [969, '16:54', '17:35', 1014, 1055, 41],\n",
- " [970, '16:55', '17:14', 1015, 1034, 19],\n",
- " [971, '16:58', '17:25', 1018, 1045, 27],\n",
- " [972, '16:58', '17:45', 1018, 1065, 47],\n",
- " [973, '16:58', '17:45', 1018, 1065, 47],\n",
- " [974, '16:58', '18:24', 1018, 1104, 86],\n",
- " [975, '16:59', '18:11', 1019, 1091, 72],\n",
- " [976, '16:59', '17:53', 1019, 1073, 54],\n",
- " [977, '17:00', '17:16', 1020, 1036, 16],\n",
- " [978, '17:00', '17:10', 1020, 1030, 10],\n",
- " [979, '17:01', '17:13', 1021, 1033, 12],\n",
- " [980, '17:03', '17:50', 1023, 1070, 47],\n",
- " [981, '17:04', '18:30', 1024, 1110, 86],\n",
- " [982, '17:04', '17:45', 1024, 1065, 41],\n",
- " [983, '17:05', '17:24', 1025, 1044, 19],\n",
- " [984, '17:06', '17:51', 1026, 1071, 45],\n",
- " [985, '17:08', '17:55', 1028, 1075, 47],\n",
- " [986, '17:08', '17:55', 1028, 1075, 47],\n",
- " [987, '17:08', '18:34', 1028, 1114, 86],\n",
- " [988, '17:09', '18:03', 1029, 1083, 54],\n",
- " [989, '17:09', '18:21', 1029, 1101, 72],\n",
- " [990, '17:10', '17:20', 1030, 1040, 10],\n",
- " [991, '17:13', '17:40', 1033, 1060, 27],\n",
- " [992, '17:13', '18:00', 1033, 1080, 47],\n",
- " [993, '17:14', '17:55', 1034, 1075, 41],\n",
- " [994, '17:14', '18:40', 1034, 1120, 86],\n",
- " [995, '17:15', '17:34', 1035, 1054, 19],\n",
- " [996, '17:16', '17:28', 1036, 1048, 12],\n",
- " [997, '17:18', '18:05', 1038, 1085, 47],\n",
- " [998, '17:18', '18:05', 1038, 1085, 47],\n",
- " [999, '17:18', '18:44', 1038, 1124, 86],\n",
- " [1000, '17:19', '18:31', 1039, 1111, 72],\n",
- " [1001, '17:19', '18:13', 1039, 1093, 54],\n",
- " [1002, '17:20', '17:36', 1040, 1056, 16],\n",
- " [1003, '17:20', '17:30', 1040, 1050, 10],\n",
- " [1004, '17:21', '17:47', 1041, 1067, 26],\n",
- " [1005, '17:22', '18:06', 1042, 1086, 44],\n",
- " [1006, '17:23', '18:10', 1043, 1090, 47],\n",
- " [1007, '17:24', '18:50', 1044, 1130, 86],\n",
- " [1008, '17:24', '18:05', 1044, 1085, 41],\n",
- " [1009, '17:25', '17:44', 1045, 1064, 19],\n",
- " [1010, '17:28', '17:55', 1048, 1075, 27],\n",
- " [1011, '17:28', '18:15', 1048, 1095, 47],\n",
- " [1012, '17:28', '18:15', 1048, 1095, 47],\n",
- " [1013, '17:28', '18:54', 1048, 1134, 86],\n",
- " [1014, '17:29', '18:41', 1049, 1121, 72],\n",
- " [1015, '17:29', '18:23', 1049, 1103, 54],\n",
- " [1016, '17:30', '17:40', 1050, 1060, 10],\n",
- " [1017, '17:31', '17:43', 1051, 1063, 12],\n",
- " [1018, '17:33', '18:20', 1053, 1100, 47],\n",
- " [1019, '17:34', '18:15', 1054, 1095, 41],\n",
- " [1020, '17:34', '19:00', 1054, 1140, 86],\n",
- " [1021, '17:35', '17:54', 1055, 1074, 19],\n",
- " [1022, '17:36', '18:21', 1056, 1101, 45],\n",
- " [1023, '17:38', '18:25', 1058, 1105, 47],\n",
- " [1024, '17:38', '19:04', 1058, 1144, 86],\n",
- " [1025, '17:38', '18:25', 1058, 1105, 47],\n",
- " [1026, '17:39', '18:51', 1059, 1131, 72],\n",
- " [1027, '17:39', '18:33', 1059, 1113, 54],\n",
- " [1028, '17:40', '17:56', 1060, 1076, 16],\n",
- " [1029, '17:40', '17:50', 1060, 1070, 10],\n",
- " [1030, '17:43', '18:10', 1063, 1090, 27],\n",
- " [1031, '17:43', '18:30', 1063, 1110, 47],\n",
- " [1032, '17:44', '18:25', 1064, 1105, 41],\n",
- " [1033, '17:44', '19:14', 1064, 1154, 90],\n",
- " [1034, '17:45', '18:04', 1065, 1084, 19],\n",
- " [1035, '17:46', '17:58', 1066, 1078, 12],\n",
- " [1036, '17:48', '18:35', 1068, 1115, 47],\n",
- " [1037, '17:48', '18:35', 1068, 1115, 47],\n",
- " [1038, '17:48', '19:14', 1068, 1154, 86],\n",
- " [1039, '17:49', '19:01', 1069, 1141, 72],\n",
- " [1040, '17:49', '18:43', 1069, 1123, 54],\n",
- " [1041, '17:50', '18:00', 1070, 1080, 10],\n",
- " [1042, '17:51', '18:17', 1071, 1097, 26],\n",
- " [1043, '17:52', '18:36', 1072, 1116, 44],\n",
- " [1044, '17:53', '18:40', 1073, 1120, 47],\n",
- " [1045, '17:54', '18:35', 1074, 1115, 41],\n",
- " [1046, '17:54', '18:57', 1074, 1137, 63],\n",
- " [1047, '17:55', '18:14', 1075, 1094, 19],\n",
- " [1048, '17:58', '18:45', 1078, 1125, 47],\n",
- " [1049, '17:58', '18:45', 1078, 1125, 47],\n",
- " [1050, '17:58', '18:25', 1078, 1105, 27],\n",
- " [1051, '17:58', '19:26', 1078, 1166, 88],\n",
- " [1052, '17:59', '18:53', 1079, 1133, 54],\n",
- " [1053, '18:00', '19:11', 1080, 1151, 71],\n",
- " [1054, '18:00', '18:10', 1080, 1090, 10],\n",
- " [1055, '18:00', '18:16', 1080, 1096, 16],\n",
- " [1056, '18:01', '18:13', 1081, 1093, 12],\n",
- " [1057, '18:03', '18:50', 1083, 1130, 47],\n",
- " [1058, '18:04', '18:45', 1084, 1125, 41],\n",
- " [1059, '18:04', '19:29', 1084, 1169, 85],\n",
- " [1060, '18:05', '18:24', 1085, 1104, 19],\n",
- " [1061, '18:06', '18:51', 1086, 1131, 45],\n",
- " [1062, '18:08', '18:55', 1088, 1135, 47],\n",
- " [1063, '18:08', '19:06', 1088, 1146, 58],\n",
- " [1064, '18:08', '18:55', 1088, 1135, 47],\n",
- " [1065, '18:09', '19:03', 1089, 1143, 54],\n",
- " [1066, '18:10', '18:20', 1090, 1100, 10],\n",
- " [1067, '18:10', '19:21', 1090, 1161, 71],\n",
- " [1068, '18:13', '19:00', 1093, 1140, 47],\n",
- " [1069, '18:13', '18:40', 1093, 1120, 27],\n",
- " [1070, '18:14', '19:43', 1094, 1183, 89],\n",
- " [1071, '18:14', '18:55', 1094, 1135, 41],\n",
- " [1072, '18:15', '18:34', 1095, 1114, 19],\n",
- " [1073, '18:16', '18:28', 1096, 1108, 12],\n",
- " [1074, '18:17', '18:27', 1097, 1107, 10],\n",
- " [1075, '18:18', '19:41', 1098, 1181, 83],\n",
- " [1076, '18:18', '18:58', 1098, 1138, 40],\n",
- " [1077, '18:18', '19:05', 1098, 1145, 47],\n",
- " [1078, '18:19', '19:13', 1099, 1153, 54],\n",
- " [1079, '18:20', '19:31', 1100, 1171, 71],\n",
- " [1080, '18:20', '18:36', 1100, 1116, 16],\n",
- " [1081, '18:20', '18:30', 1100, 1110, 10],\n",
- " [1082, '18:22', '19:05', 1102, 1145, 43],\n",
- " [1083, '18:23', '19:05', 1103, 1145, 42],\n",
- " [1084, '18:24', '19:27', 1104, 1167, 63],\n",
- " [1085, '18:24', '19:05', 1104, 1145, 41],\n",
- " [1086, '18:25', '18:44', 1105, 1124, 19],\n",
- " [1087, '18:28', '19:25', 1108, 1165, 57],\n",
- " [1088, '18:28', '18:55', 1108, 1135, 27],\n",
- " [1089, '18:28', '19:08', 1108, 1148, 40],\n",
- " [1090, '18:28', '19:15', 1108, 1155, 47],\n",
- " [1091, '18:29', '19:23', 1109, 1163, 54],\n",
- " [1092, '18:30', '19:05', 1110, 1145, 35],\n",
- " [1093, '18:30', '18:40', 1110, 1120, 10],\n",
- " [1094, '18:31', '18:43', 1111, 1123, 12],\n",
- " [1095, '18:33', '19:15', 1113, 1155, 42],\n",
- " [1096, '18:34', '19:58', 1114, 1198, 84],\n",
- " [1097, '18:34', '19:14', 1114, 1154, 40],\n",
- " [1098, '18:35', '18:55', 1115, 1135, 20],\n",
- " [1099, '18:36', '19:20', 1116, 1160, 44],\n",
- " [1100, '18:38', '19:25', 1118, 1165, 47],\n",
- " [1101, '18:38', '19:23', 1118, 1163, 45],\n",
- " [1102, '18:38', '19:56', 1118, 1196, 78],\n",
- " [1103, '18:39', '19:33', 1119, 1173, 54],\n",
- " [1104, '18:40', '18:50', 1120, 1130, 10],\n",
- " [1105, '18:40', '19:45', 1120, 1185, 65],\n",
- " [1106, '18:40', '18:56', 1120, 1136, 16],\n",
- " [1107, '18:43', '19:10', 1123, 1150, 27],\n",
- " [1108, '18:43', '19:30', 1123, 1170, 47],\n",
- " [1109, '18:44', '19:24', 1124, 1164, 40],\n",
- " [1110, '18:45', '19:05', 1125, 1145, 20],\n",
- " [1111, '18:46', '18:58', 1126, 1138, 12],\n",
- " [1112, '18:48', '19:35', 1128, 1175, 47],\n",
- " [1113, '18:48', '20:12', 1128, 1212, 84],\n",
- " [1114, '18:48', '20:11', 1128, 1211, 83],\n",
- " [1115, '18:48', '19:28', 1128, 1168, 40],\n",
- " [1116, '18:49', '19:43', 1129, 1183, 54],\n",
- " [1117, '18:50', '19:00', 1130, 1140, 10],\n",
- " [1118, '18:51', '19:01', 1131, 1141, 10],\n",
- " [1119, '18:53', '19:35', 1133, 1175, 42],\n",
- " [1120, '18:53', '19:15', 1133, 1155, 22],\n",
- " [1121, '18:53', '20:00', 1133, 1200, 67],\n",
- " [1122, '18:55', '19:15', 1135, 1155, 20],\n",
- " [1123, '18:55', '19:34', 1135, 1174, 39],\n",
- " [1124, '18:58', '19:38', 1138, 1178, 40],\n",
- " [1125, '18:59', '19:53', 1139, 1193, 54],\n",
- " [1126, '18:59', '19:50', 1139, 1190, 51],\n",
- " [1127, '18:59', '19:53', 1139, 1193, 54],\n",
- " [1128, '19:00', '19:16', 1140, 1156, 16],\n",
- " [1129, '19:00', '19:10', 1140, 1150, 10],\n",
- " [1130, '19:00', '19:16', 1140, 1156, 16],\n",
- " [1131, '19:01', '19:13', 1141, 1153, 12],\n",
- " [1132, '19:03', '20:26', 1143, 1226, 83],\n",
- " [1133, '19:03', '19:45', 1143, 1185, 42],\n",
- " [1134, '19:05', '19:44', 1145, 1184, 39],\n",
- " [1135, '19:05', '19:25', 1145, 1165, 20],\n",
- " [1136, '19:08', '20:15', 1148, 1215, 67],\n",
- " [1137, '19:08', '19:35', 1148, 1175, 27],\n",
- " [1138, '19:09', '19:49', 1149, 1189, 40],\n",
- " [1139, '19:09', '20:03', 1149, 1203, 54],\n",
- " [1140, '19:10', '19:20', 1150, 1160, 10],\n",
- " [1141, '19:10', '19:20', 1150, 1160, 10],\n",
- " [1142, '19:11', '19:53', 1151, 1193, 42],\n",
- " [1143, '19:14', '20:26', 1154, 1226, 72],\n",
- " [1144, '19:14', '19:35', 1154, 1175, 21],\n",
- " [1145, '19:14', '19:24', 1154, 1164, 10],\n",
- " [1146, '19:14', '20:05', 1154, 1205, 51],\n",
- " [1147, '19:15', '19:30', 1155, 1170, 15],\n",
- " [1148, '19:15', '19:54', 1155, 1194, 39],\n",
- " [1149, '19:18', '20:39', 1158, 1239, 81],\n",
- " [1150, '19:18', '20:00', 1158, 1200, 42],\n",
- " [1151, '19:19', '20:14', 1159, 1214, 55],\n",
- " [1152, '19:20', '19:30', 1160, 1170, 10],\n",
- " [1153, '19:20', '19:36', 1160, 1176, 16],\n",
- " [1154, '19:21', '19:31', 1161, 1171, 10],\n",
- " [1155, '19:23', '20:30', 1163, 1230, 67],\n",
- " [1156, '19:23', '19:35', 1163, 1175, 12],\n",
- " [1157, '19:24', '19:45', 1164, 1185, 21],\n",
- " [1158, '19:24', '19:45', 1164, 1185, 21],\n",
- " [1159, '19:25', '20:04', 1165, 1204, 39],\n",
- " [1160, '19:26', '20:08', 1166, 1208, 42],\n",
- " [1161, '19:29', '20:02', 1169, 1202, 33],\n",
- " [1162, '19:29', '20:18', 1169, 1218, 49],\n",
- " [1163, '19:29', '20:41', 1169, 1241, 72],\n",
- " [1164, '19:30', '19:40', 1170, 1180, 10],\n",
- " [1165, '19:33', '20:54', 1173, 1254, 81],\n",
- " [1166, '19:33', '20:17', 1173, 1217, 44],\n",
- " [1167, '19:34', '19:55', 1174, 1195, 21],\n",
- " [1168, '19:35', '20:14', 1175, 1214, 39],\n",
- " [1169, '19:38', '20:05', 1178, 1205, 27],\n",
- " [1170, '19:38', '20:45', 1178, 1245, 67],\n",
- " [1171, '19:39', '20:12', 1179, 1212, 33],\n",
- " [1172, '19:40', '19:50', 1180, 1190, 10],\n",
- " [1173, '19:40', '19:56', 1180, 1196, 16],\n",
- " [1174, '19:41', '20:27', 1181, 1227, 46],\n",
- " [1175, '19:43', '19:55', 1183, 1195, 12],\n",
- " [1176, '19:44', '20:05', 1184, 1205, 21],\n",
- " [1177, '19:44', '20:33', 1184, 1233, 49],\n",
- " [1178, '19:44', '21:00', 1184, 1260, 76],\n",
- " [1179, '19:45', '20:24', 1185, 1224, 39],\n",
- " [1180, '19:48', '20:37', 1188, 1237, 49],\n",
- " [1181, '19:48', '21:09', 1188, 1269, 81],\n",
- " [1182, '19:50', '20:00', 1190, 1200, 10],\n",
- " [1183, '19:52', '20:29', 1192, 1229, 37],\n",
- " [1184, '19:53', '20:08', 1193, 1208, 15],\n",
- " [1185, '19:53', '21:02', 1193, 1262, 69],\n",
- " [1186, '19:53', '20:20', 1193, 1220, 27],\n",
- " [1187, '19:54', '20:19', 1194, 1219, 25],\n",
- " [1188, '19:55', '20:34', 1195, 1234, 39],\n",
- " [1189, '19:56', '20:34', 1196, 1234, 38],\n",
- " [1190, '19:59', '20:48', 1199, 1248, 49],\n",
- " [1191, '19:59', '21:20', 1199, 1280, 81],\n",
- " [1192, '20:00', '20:16', 1200, 1216, 16],\n",
- " [1193, '20:00', '20:10', 1200, 1210, 10],\n",
- " [1194, '20:03', '20:42', 1203, 1242, 39],\n",
- " [1195, '20:03', '21:24', 1203, 1284, 81],\n",
- " [1196, '20:04', '20:29', 1204, 1229, 25],\n",
- " [1197, '20:05', '20:48', 1205, 1248, 43],\n",
- " [1198, '20:07', '20:44', 1207, 1244, 37],\n",
- " [1199, '20:08', '20:40', 1208, 1240, 32],\n",
- " [1200, '20:08', '20:35', 1208, 1235, 27],\n",
- " [1201, '20:10', '20:20', 1210, 1220, 10],\n",
- " [1202, '20:10', '20:22', 1210, 1222, 12],\n",
- " [1203, '20:11', '20:47', 1211, 1247, 36],\n",
- " [1204, '20:14', '21:04', 1214, 1264, 50],\n",
- " [1205, '20:14', '21:03', 1214, 1263, 49],\n",
- " [1206, '20:17', '21:03', 1217, 1263, 46],\n",
- " [1207, '20:18', '21:39', 1218, 1299, 81],\n",
- " [1208, '20:20', '20:30', 1220, 1230, 10],\n",
- " [1209, '20:20', '20:57', 1220, 1257, 37],\n",
- " [1210, '20:20', '20:36', 1220, 1236, 16],\n",
- " [1211, '20:22', '20:59', 1222, 1259, 37],\n",
- " [1212, '20:22', '20:42', 1222, 1242, 20],\n",
- " [1213, '20:24', '20:49', 1224, 1249, 25],\n",
- " [1214, '20:27', '21:22', 1227, 1282, 55],\n",
- " [1215, '20:29', '21:18', 1229, 1278, 49],\n",
- " [1216, '20:30', '21:07', 1230, 1267, 37],\n",
- " [1217, '20:30', '20:40', 1230, 1240, 10],\n",
- " [1218, '20:30', '20:40', 1230, 1240, 10],\n",
- " [1219, '20:30', '21:40', 1230, 1300, 70],\n",
- " [1220, '20:32', '21:18', 1232, 1278, 46],\n",
- " [1221, '20:35', '21:54', 1235, 1314, 79],\n",
- " [1222, '20:37', '21:14', 1237, 1274, 37],\n",
- " [1223, '20:38', '21:08', 1238, 1268, 30],\n",
- " [1224, '20:40', '20:50', 1240, 1250, 10],\n",
- " [1225, '20:40', '21:17', 1240, 1277, 37],\n",
- " [1226, '20:40', '20:56', 1240, 1256, 16],\n",
- " [1227, '20:44', '21:33', 1244, 1293, 49],\n",
- " [1228, '20:47', '21:33', 1247, 1293, 46],\n",
- " [1229, '20:47', '21:42', 1247, 1302, 55],\n",
- " [1230, '20:50', '21:00', 1250, 1260, 10],\n",
- " [1231, '20:50', '22:00', 1250, 1320, 70],\n",
- " [1232, '20:50', '22:09', 1250, 1329, 79],\n",
- " [1233, '20:50', '21:27', 1250, 1287, 37],\n",
- " [1234, '20:52', '21:29', 1252, 1289, 37],\n",
- " [1235, '20:53', '21:20', 1253, 1280, 27],\n",
- " [1236, '20:56', '21:11', 1256, 1271, 15],\n",
- " [1237, '20:59', '21:48', 1259, 1308, 49],\n",
- " [1238, '21:00', '21:10', 1260, 1270, 10],\n",
- " [1239, '21:00', '21:37', 1260, 1297, 37],\n",
- " [1240, '21:02', '21:48', 1262, 1308, 46],\n",
- " [1241, '21:05', '22:24', 1265, 1344, 79],\n",
- " [1242, '21:07', '21:44', 1267, 1304, 37],\n",
- " [1243, '21:07', '22:02', 1267, 1322, 55],\n",
- " [1244, '21:08', '21:38', 1268, 1298, 30],\n",
- " [1245, '21:10', '22:25', 1270, 1345, 75],\n",
- " [1246, '21:10', '21:20', 1270, 1280, 10],\n",
- " [1247, '21:10', '21:47', 1270, 1307, 37],\n",
- " [1248, '21:14', '22:03', 1274, 1323, 49],\n",
- " [1249, '21:17', '22:03', 1277, 1323, 46],\n",
- " [1250, '21:20', '22:18', 1280, 1338, 58],\n",
- " [1251, '21:20', '21:57', 1280, 1317, 37],\n",
- " [1252, '21:20', '21:30', 1280, 1290, 10],\n",
- " [1253, '21:22', '21:59', 1282, 1319, 37],\n",
- " [1254, '21:24', '21:49', 1284, 1309, 25],\n",
- " [1255, '21:27', '22:21', 1287, 1341, 54],\n",
- " [1256, '21:30', '22:07', 1290, 1327, 37],\n",
- " [1257, '21:30', '22:20', 1290, 1340, 50],\n",
- " [1258, '21:30', '21:40', 1290, 1300, 10],\n",
- " [1259, '21:32', '22:18', 1292, 1338, 46],\n",
- " [1260, '21:32', '22:01', 1292, 1321, 29],\n",
- " [1261, '21:35', '22:54', 1295, 1374, 79],\n",
- " [1262, '21:37', '22:14', 1297, 1334, 37],\n",
- " [1263, '21:39', '21:55', 1299, 1315, 16],\n",
- " [1264, '21:40', '22:17', 1300, 1337, 37],\n",
- " [1265, '21:40', '21:50', 1300, 1310, 10],\n",
- " [1266, '21:41', '22:08', 1301, 1328, 27],\n",
- " [1267, '21:47', '22:16', 1307, 1336, 29],\n",
- " [1268, '21:47', '22:51', 1307, 1371, 64],\n",
- " [1269, '21:47', '22:33', 1307, 1353, 46],\n",
- " [1270, '21:48', '22:03', 1308, 1323, 15],\n",
- " [1271, '21:50', '22:55', 1310, 1375, 65],\n",
- " [1272, '21:50', '22:27', 1310, 1347, 37],\n",
- " [1273, '21:50', '22:00', 1310, 1320, 10],\n",
- " [1274, '21:52', '22:29', 1312, 1349, 37],\n",
- " [1275, '21:53', '22:19', 1313, 1339, 26],\n",
- " [1276, '22:00', '22:38', 1320, 1358, 38],\n",
- " [1277, '22:00', '22:10', 1320, 1330, 10],\n",
- " [1278, '22:02', '22:12', 1322, 1332, 10],\n",
- " [1279, '22:02', '22:48', 1322, 1368, 46],\n",
- " [1280, '22:04', '22:31', 1324, 1351, 27],\n",
- " [1281, '22:05', '23:24', 1325, 1404, 79],\n",
- " [1282, '22:07', '22:44', 1327, 1364, 37],\n",
- " [1283, '22:07', '22:39', 1327, 1359, 32],\n",
- " [1284, '22:09', '22:25', 1329, 1345, 16],\n",
- " [1285, '22:10', '23:25', 1330, 1405, 75],\n",
- " [1286, '22:13', '22:38', 1333, 1358, 25],\n",
- " [1287, '22:13', '22:53', 1333, 1373, 40],\n",
- " [1288, '22:17', '22:27', 1337, 1347, 10],\n",
- " [1289, '22:17', '23:03', 1337, 1383, 46],\n",
- " [1290, '22:19', '22:46', 1339, 1366, 27],\n",
- " [1291, '22:22', '22:59', 1342, 1379, 37],\n",
- " [1292, '22:24', '22:48', 1344, 1368, 24],\n",
- " [1293, '22:27', '22:52', 1347, 1372, 25],\n",
- " [1294, '22:27', '23:21', 1347, 1401, 54],\n",
- " [1295, '22:28', '23:08', 1348, 1388, 40],\n",
- " [1296, '22:30', '23:17', 1350, 1397, 47],\n",
- " [1297, '22:32', '22:42', 1352, 1362, 10],\n",
- " [1298, '22:32', '23:11', 1352, 1391, 39],\n",
- " [1299, '22:34', '23:01', 1354, 1381, 27],\n",
- " [1300, '22:35', '23:54', 1355, 1434, 79],\n",
- " [1301, '22:37', '23:14', 1357, 1394, 37],\n",
- " [1302, '22:43', '23:23', 1363, 1403, 40],\n",
- " [1303, '22:43', '23:08', 1363, 1388, 25],\n",
- " [1304, '22:47', '23:33', 1367, 1413, 46],\n",
- " [1305, '22:47', '22:57', 1367, 1377, 10],\n",
- " [1306, '22:49', '23:16', 1369, 1396, 27],\n",
- " [1307, '22:52', '23:29', 1372, 1409, 37],\n",
- " [1308, '22:53', '23:15', 1373, 1395, 22],\n",
- " [1309, '22:55', '23:55', 1375, 1435, 60],\n",
- " [1310, '22:57', '23:51', 1377, 1431, 54],\n",
- " [1311, '22:58', '23:38', 1378, 1418, 40],\n",
- " [1312, '23:02', '23:41', 1382, 1421, 39],\n",
- " [1313, '23:02', '23:12', 1382, 1392, 10],\n",
- " [1314, '23:04', '23:31', 1384, 1411, 27],\n",
- " [1315, '23:05', '00:24', 1385, 1464, 79],\n",
- " [1316, '23:07', '23:44', 1387, 1424, 37],\n",
- " [1317, '23:13', '23:53', 1393, 1433, 40],\n",
- " [1318, '23:13', '23:38', 1393, 1418, 25],\n",
- " [1319, '23:17', '00:03', 1397, 1443, 46],\n",
- " [1320, '23:17', '23:27', 1397, 1407, 10],\n",
- " [1321, '23:19', '23:46', 1399, 1426, 27],\n",
- " [1322, '23:22', '23:59', 1402, 1439, 37],\n",
- " [1323, '23:25', '00:25', 1405, 1465, 60],\n",
- " [1324, '23:27', '00:21', 1407, 1461, 54],\n",
- " [1325, '23:28', '00:08', 1408, 1448, 40],\n",
- " [1326, '23:32', '23:42', 1412, 1422, 10],\n",
- " [1327, '23:34', '00:01', 1414, 1441, 27],\n",
- " [1328, '23:35', '01:05', 1415, 1505, 90],\n",
- " [1329, '23:37', '00:09', 1417, 1449, 32],\n",
- " [1330, '23:43', '00:23', 1423, 1463, 40],\n",
- " [1331, '23:43', '00:08', 1423, 1448, 25],\n",
- " [1332, '23:46', '00:01', 1426, 1441, 15],\n",
- " [1333, '23:47', '23:57', 1427, 1437, 10],\n",
- " [1334, '23:47', '00:33', 1427, 1473, 46],\n",
- " [1335, '23:52', '00:24', 1432, 1464, 32],\n",
- " [1336, '23:55', '00:49', 1435, 1489, 54],\n",
- " [1337, '23:57', '00:57', 1437, 1497, 60],\n",
- " [1338, '23:58', '00:38', 1438, 1478, 40],\n",
- " [1339, '00:02', '00:12', 1442, 1452, 10],\n",
- " [1340, '00:07', '00:39', 1447, 1479, 32],\n",
- " [1341, '00:13', '00:38', 1453, 1478, 25],\n",
- " [1342, '00:13', '00:51', 1453, 1491, 38],\n",
- " [1343, '00:15', '01:14', 1455, 1514, 59],\n",
- " [1344, '00:17', '01:23', 1457, 1523, 66],\n",
- " [1345, '00:23', '00:33', 1463, 1473, 10],\n",
- " [1346, '00:24', '00:40', 1464, 1480, 16],\n",
- " [1347, '00:25', '01:12', 1465, 1512, 47],\n",
- " [1348, '00:28', '01:07', 1468, 1507, 39],\n",
- " [1349, '00:33', '01:05', 1473, 1505, 32],\n",
- " [1350, '00:43', '01:21', 1483, 1521, 38],\n",
- " [1351, '00:44', '00:54', 1484, 1494, 10],\n",
- " [1352, '00:47', '01:09', 1487, 1509, 22],\n",
- " [1353, '00:47', '01:26', 1487, 1526, 39],\n",
- " [1354, '00:54', '01:04', 1494, 1504, 10],\n",
- " [1355, '00:57', '01:07', 1497, 1507, 10]\n",
+ " [0, \"04:18\", \"05:00\", 258, 300, 42],\n",
+ " [1, \"04:27\", \"05:08\", 267, 308, 41],\n",
+ " [2, \"04:29\", \"05:26\", 269, 326, 57],\n",
+ " [3, \"04:29\", \"04:55\", 269, 295, 26],\n",
+ " [4, \"04:30\", \"04:53\", 270, 293, 23],\n",
+ " [5, \"04:30\", \"04:51\", 270, 291, 21],\n",
+ " [6, \"04:31\", \"04:53\", 271, 293, 22],\n",
+ " [7, \"04:33\", \"05:15\", 273, 315, 42],\n",
+ " [8, \"04:34\", \"04:44\", 274, 284, 10],\n",
+ " [9, \"04:34\", \"05:03\", 274, 303, 29],\n",
+ " [10, \"04:35\", \"04:50\", 275, 290, 15],\n",
+ " [11, \"04:36\", \"04:46\", 276, 286, 10],\n",
+ " [12, \"04:37\", \"05:18\", 277, 318, 41],\n",
+ " [13, \"04:41\", \"05:13\", 281, 313, 32],\n",
+ " [14, \"04:42\", \"05:23\", 282, 323, 41],\n",
+ " [15, \"04:43\", \"04:53\", 283, 293, 10],\n",
+ " [16, \"04:44\", \"05:45\", 284, 345, 61],\n",
+ " [17, \"04:45\", \"05:11\", 285, 311, 26],\n",
+ " [18, \"04:46\", \"05:01\", 286, 301, 15],\n",
+ " [19, \"04:46\", \"04:56\", 286, 296, 10],\n",
+ " [20, \"04:47\", \"05:14\", 287, 314, 27],\n",
+ " [21, \"04:48\", \"05:30\", 288, 330, 42],\n",
+ " [22, \"04:49\", \"05:41\", 289, 341, 52],\n",
+ " [23, \"04:49\", \"05:18\", 289, 318, 29],\n",
+ " [24, \"04:50\", \"05:33\", 290, 333, 43],\n",
+ " [25, \"04:52\", \"05:56\", 292, 356, 64],\n",
+ " [26, \"04:52\", \"05:07\", 292, 307, 15],\n",
+ " [27, \"04:53\", \"05:19\", 293, 319, 26],\n",
+ " [28, \"04:53\", \"05:23\", 293, 323, 30],\n",
+ " [29, \"04:55\", \"05:27\", 295, 327, 32],\n",
+ " [30, \"04:57\", \"05:38\", 297, 338, 41],\n",
+ " [31, \"05:00\", \"06:00\", 300, 360, 60],\n",
+ " [32, \"05:00\", \"05:54\", 300, 354, 54],\n",
+ " [33, \"05:01\", \"05:33\", 301, 333, 32],\n",
+ " [34, \"05:01\", \"05:26\", 301, 326, 25],\n",
+ " [35, \"05:02\", \"05:29\", 302, 329, 27],\n",
+ " [36, \"05:02\", \"05:12\", 302, 312, 10],\n",
+ " [37, \"05:03\", \"05:45\", 303, 345, 42],\n",
+ " [38, \"05:03\", \"05:18\", 303, 318, 15],\n",
+ " [39, \"05:03\", \"06:28\", 303, 388, 85],\n",
+ " [40, \"05:03\", \"05:13\", 303, 313, 10],\n",
+ " [41, \"05:04\", \"06:24\", 304, 384, 80],\n",
+ " [42, \"05:07\", \"05:44\", 307, 344, 37],\n",
+ " [43, \"05:08\", \"05:48\", 308, 348, 40],\n",
+ " [44, \"05:10\", \"06:06\", 310, 366, 56],\n",
+ " [45, \"05:11\", \"05:37\", 311, 337, 26],\n",
+ " [46, \"05:11\", \"05:53\", 311, 353, 42],\n",
+ " [47, \"05:13\", \"06:15\", 313, 375, 62],\n",
+ " [48, \"05:13\", \"05:38\", 313, 338, 25],\n",
+ " [49, \"05:16\", \"05:44\", 316, 344, 28],\n",
+ " [50, \"05:17\", \"05:27\", 317, 327, 10],\n",
+ " [51, \"05:18\", \"06:40\", 318, 400, 82],\n",
+ " [52, \"05:18\", \"06:03\", 318, 363, 45],\n",
+ " [53, \"05:18\", \"06:11\", 318, 371, 53],\n",
+ " [54, \"05:18\", \"06:00\", 318, 360, 42],\n",
+ " [55, \"05:19\", \"06:34\", 319, 394, 75],\n",
+ " [56, \"05:20\", \"06:17\", 320, 377, 57],\n",
+ " [57, \"05:22\", \"05:59\", 322, 359, 37],\n",
+ " [58, \"05:24\", \"05:48\", 324, 348, 24],\n",
+ " [59, \"05:25\", \"05:40\", 325, 340, 15],\n",
+ " [60, \"05:26\", \"06:08\", 326, 368, 42],\n",
+ " [61, \"05:27\", \"06:30\", 327, 390, 63],\n",
+ " [62, \"05:27\", \"05:54\", 327, 354, 27],\n",
+ " [63, \"05:28\", \"05:53\", 328, 353, 25],\n",
+ " [64, \"05:29\", \"05:44\", 329, 344, 15],\n",
+ " [65, \"05:30\", \"05:40\", 330, 340, 10],\n",
+ " [66, \"05:30\", \"05:40\", 330, 340, 10],\n",
+ " [67, \"05:30\", \"05:40\", 330, 340, 10],\n",
+ " [68, \"05:32\", \"06:53\", 332, 413, 81],\n",
+ " [69, \"05:33\", \"07:00\", 333, 420, 87],\n",
+ " [70, \"05:33\", \"06:15\", 333, 375, 42],\n",
+ " [71, \"05:33\", \"05:47\", 333, 347, 14],\n",
+ " [72, \"05:37\", \"06:13\", 337, 373, 36],\n",
+ " [73, \"05:37\", \"06:05\", 337, 365, 28],\n",
+ " [74, \"05:38\", \"06:33\", 338, 393, 55],\n",
+ " [75, \"05:38\", \"06:04\", 338, 364, 26],\n",
+ " [76, \"05:38\", \"06:18\", 338, 378, 40],\n",
+ " [77, \"05:39\", \"05:54\", 339, 354, 15],\n",
+ " [78, \"05:40\", \"05:56\", 340, 356, 16],\n",
+ " [79, \"05:40\", \"06:41\", 340, 401, 61],\n",
+ " [80, \"05:40\", \"05:50\", 340, 350, 10],\n",
+ " [81, \"05:41\", \"06:23\", 341, 383, 42],\n",
+ " [82, \"05:41\", \"06:01\", 341, 361, 20],\n",
+ " [83, \"05:43\", \"06:08\", 343, 368, 25],\n",
+ " [84, \"05:44\", \"07:10\", 344, 430, 86],\n",
+ " [85, \"05:44\", \"05:55\", 344, 355, 11],\n",
+ " [86, \"05:45\", \"06:44\", 345, 404, 59],\n",
+ " [87, \"05:47\", \"06:17\", 347, 377, 30],\n",
+ " [88, \"05:48\", \"07:08\", 348, 428, 80],\n",
+ " [89, \"05:48\", \"06:30\", 348, 390, 42],\n",
+ " [90, \"05:50\", \"06:50\", 350, 410, 60],\n",
+ " [91, \"05:50\", \"06:00\", 350, 360, 10],\n",
+ " [92, \"05:50\", \"06:00\", 350, 360, 10],\n",
+ " [93, \"05:50\", \"06:51\", 350, 411, 61],\n",
+ " [94, \"05:52\", \"06:33\", 352, 393, 41],\n",
+ " [95, \"05:52\", \"06:36\", 352, 396, 44],\n",
+ " [96, \"05:52\", \"06:23\", 352, 383, 31],\n",
+ " [97, \"05:54\", \"06:14\", 354, 374, 20],\n",
+ " [98, \"05:54\", \"07:20\", 354, 440, 86],\n",
+ " [99, \"05:55\", \"06:40\", 355, 400, 45],\n",
+ " [100, \"05:55\", \"06:27\", 355, 387, 32],\n",
+ " [101, \"05:56\", \"06:35\", 356, 395, 39],\n",
+ " [102, \"05:56\", \"06:06\", 356, 366, 10],\n",
+ " [103, \"05:57\", \"06:21\", 357, 381, 24],\n",
+ " [104, \"05:58\", \"07:23\", 358, 443, 85],\n",
+ " [105, \"05:58\", \"06:23\", 358, 383, 25],\n",
+ " [106, \"05:58\", \"06:08\", 358, 368, 10],\n",
+ " [107, \"05:58\", \"06:43\", 358, 403, 45],\n",
+ " [108, \"06:00\", \"06:10\", 360, 370, 10],\n",
+ " [109, \"06:00\", \"06:16\", 360, 376, 16],\n",
+ " [110, \"06:00\", \"07:01\", 360, 421, 61],\n",
+ " [111, \"06:01\", \"07:00\", 361, 420, 59],\n",
+ " [112, \"06:01\", \"06:13\", 361, 373, 12],\n",
+ " [113, \"06:01\", \"06:45\", 361, 405, 44],\n",
+ " [114, \"06:03\", \"06:50\", 363, 410, 47],\n",
+ " [115, \"06:04\", \"06:37\", 364, 397, 33],\n",
+ " [116, \"06:04\", \"07:30\", 364, 450, 86],\n",
+ " [117, \"06:05\", \"06:24\", 365, 384, 19],\n",
+ " [118, \"06:06\", \"06:51\", 366, 411, 45],\n",
+ " [119, \"06:07\", \"06:43\", 367, 403, 36],\n",
+ " [120, \"06:08\", \"07:30\", 368, 450, 82],\n",
+ " [121, \"06:10\", \"06:20\", 370, 380, 10],\n",
+ " [122, \"06:10\", \"07:17\", 370, 437, 67],\n",
+ " [123, \"06:11\", \"06:54\", 371, 414, 43],\n",
+ " [124, \"06:11\", \"06:21\", 371, 381, 10],\n",
+ " [125, \"06:13\", \"06:38\", 373, 398, 25],\n",
+ " [126, \"06:13\", \"06:58\", 373, 418, 45],\n",
+ " [127, \"06:13\", \"06:53\", 373, 413, 40],\n",
+ " [128, \"06:14\", \"07:03\", 374, 423, 49],\n",
+ " [129, \"06:14\", \"06:47\", 374, 407, 33],\n",
+ " [130, \"06:14\", \"07:40\", 374, 460, 86],\n",
+ " [131, \"06:15\", \"07:15\", 375, 435, 60],\n",
+ " [132, \"06:16\", \"06:28\", 376, 388, 12],\n",
+ " [133, \"06:16\", \"06:26\", 376, 386, 10],\n",
+ " [134, \"06:17\", \"06:34\", 377, 394, 17],\n",
+ " [135, \"06:18\", \"07:06\", 378, 426, 48],\n",
+ " [136, \"06:18\", \"07:38\", 378, 458, 80],\n",
+ " [137, \"06:18\", \"07:02\", 378, 422, 44],\n",
+ " [138, \"06:19\", \"06:53\", 379, 413, 34],\n",
+ " [139, \"06:20\", \"07:25\", 380, 445, 65],\n",
+ " [140, \"06:20\", \"06:36\", 380, 396, 16],\n",
+ " [141, \"06:20\", \"06:30\", 380, 390, 10],\n",
+ " [142, \"06:20\", \"06:30\", 380, 390, 10],\n",
+ " [143, \"06:21\", \"06:49\", 381, 409, 28],\n",
+ " [144, \"06:22\", \"07:06\", 382, 426, 44],\n",
+ " [145, \"06:24\", \"07:50\", 384, 470, 86],\n",
+ " [146, \"06:24\", \"06:57\", 384, 417, 33],\n",
+ " [147, \"06:26\", \"07:45\", 386, 465, 79],\n",
+ " [148, \"06:26\", \"07:10\", 386, 430, 44],\n",
+ " [149, \"06:27\", \"06:44\", 387, 404, 17],\n",
+ " [150, \"06:28\", \"06:53\", 388, 413, 25],\n",
+ " [151, \"06:28\", \"07:14\", 388, 434, 46],\n",
+ " [152, \"06:29\", \"07:03\", 389, 423, 34],\n",
+ " [153, \"06:30\", \"06:40\", 390, 400, 10],\n",
+ " [154, \"06:30\", \"07:37\", 390, 457, 67],\n",
+ " [155, \"06:31\", \"06:43\", 391, 403, 12],\n",
+ " [156, \"06:33\", \"07:14\", 393, 434, 41],\n",
+ " [157, \"06:33\", \"07:53\", 393, 473, 80],\n",
+ " [158, \"06:34\", \"08:16\", 394, 496, 102],\n",
+ " [159, \"06:34\", \"07:09\", 394, 429, 35],\n",
+ " [160, \"06:34\", \"07:07\", 394, 427, 33],\n",
+ " [161, \"06:36\", \"07:21\", 396, 441, 45],\n",
+ " [162, \"06:37\", \"07:22\", 397, 442, 45],\n",
+ " [163, \"06:37\", \"06:54\", 397, 414, 17],\n",
+ " [164, \"06:38\", \"07:30\", 398, 450, 52],\n",
+ " [165, \"06:38\", \"07:18\", 398, 438, 40],\n",
+ " [166, \"06:39\", \"07:33\", 399, 453, 54],\n",
+ " [167, \"06:40\", \"07:52\", 400, 472, 72],\n",
+ " [168, \"06:40\", \"06:50\", 400, 410, 10],\n",
+ " [169, \"06:40\", \"07:22\", 400, 442, 42],\n",
+ " [170, \"06:40\", \"06:56\", 400, 416, 16],\n",
+ " [171, \"06:41\", \"08:00\", 401, 480, 79],\n",
+ " [172, \"06:42\", \"07:26\", 402, 446, 44],\n",
+ " [173, \"06:42\", \"07:13\", 402, 433, 31],\n",
+ " [174, \"06:43\", \"07:08\", 403, 428, 25],\n",
+ " [175, \"06:43\", \"07:30\", 403, 450, 47],\n",
+ " [176, \"06:43\", \"07:23\", 403, 443, 40],\n",
+ " [177, \"06:44\", \"07:17\", 404, 437, 33],\n",
+ " [178, \"06:44\", \"08:13\", 404, 493, 89],\n",
+ " [179, \"06:46\", \"07:01\", 406, 421, 15],\n",
+ " [180, \"06:46\", \"06:58\", 406, 418, 12],\n",
+ " [181, \"06:47\", \"07:04\", 407, 424, 17],\n",
+ " [182, \"06:48\", \"08:15\", 408, 495, 87],\n",
+ " [183, \"06:48\", \"07:34\", 408, 454, 46],\n",
+ " [184, \"06:48\", \"07:37\", 408, 457, 49],\n",
+ " [185, \"06:49\", \"07:43\", 409, 463, 54],\n",
+ " [186, \"06:50\", \"08:00\", 410, 480, 70],\n",
+ " [187, \"06:50\", \"07:00\", 410, 420, 10],\n",
+ " [188, \"06:50\", \"07:05\", 410, 425, 15],\n",
+ " [189, \"06:51\", \"07:18\", 411, 438, 27],\n",
+ " [190, \"06:52\", \"07:36\", 412, 456, 44],\n",
+ " [191, \"06:53\", \"07:37\", 413, 457, 44],\n",
+ " [192, \"06:54\", \"08:20\", 414, 500, 86],\n",
+ " [193, \"06:54\", \"07:27\", 414, 447, 33],\n",
+ " [194, \"06:54\", \"07:20\", 414, 440, 26],\n",
+ " [195, \"06:56\", \"08:23\", 416, 503, 87],\n",
+ " [196, \"06:57\", \"07:12\", 417, 432, 15],\n",
+ " [197, \"06:57\", \"07:58\", 417, 478, 61],\n",
+ " [198, \"06:57\", \"07:45\", 417, 465, 48],\n",
+ " [199, \"06:57\", \"07:40\", 417, 460, 43],\n",
+ " [200, \"06:58\", \"07:23\", 418, 443, 25],\n",
+ " [201, \"06:59\", \"07:53\", 419, 473, 54],\n",
+ " [202, \"06:59\", \"08:07\", 419, 487, 68],\n",
+ " [203, \"07:00\", \"07:10\", 420, 430, 10],\n",
+ " [204, \"07:00\", \"07:16\", 420, 436, 16],\n",
+ " [205, \"07:01\", \"08:30\", 421, 510, 89],\n",
+ " [206, \"07:01\", \"07:13\", 421, 433, 12],\n",
+ " [207, \"07:01\", \"07:43\", 421, 463, 42],\n",
+ " [208, \"07:03\", \"08:30\", 423, 510, 87],\n",
+ " [209, \"07:04\", \"07:37\", 424, 457, 33],\n",
+ " [210, \"07:04\", \"07:44\", 424, 464, 40],\n",
+ " [211, \"07:05\", \"07:52\", 425, 472, 47],\n",
+ " [212, \"07:05\", \"08:05\", 425, 485, 60],\n",
+ " [213, \"07:05\", \"07:46\", 425, 466, 41],\n",
+ " [214, \"07:06\", \"07:51\", 426, 471, 45],\n",
+ " [215, \"07:07\", \"08:08\", 427, 488, 61],\n",
+ " [216, \"07:07\", \"07:52\", 427, 472, 45],\n",
+ " [217, \"07:07\", \"08:16\", 427, 496, 69],\n",
+ " [218, \"07:07\", \"07:27\", 427, 447, 20],\n",
+ " [219, \"07:09\", \"07:50\", 429, 470, 41],\n",
+ " [220, \"07:09\", \"08:40\", 429, 520, 91],\n",
+ " [221, \"07:09\", \"08:03\", 429, 483, 54],\n",
+ " [222, \"07:10\", \"07:20\", 430, 440, 10],\n",
+ " [223, \"07:11\", \"08:36\", 431, 516, 85],\n",
+ " [224, \"07:12\", \"08:00\", 432, 480, 48],\n",
+ " [225, \"07:12\", \"07:47\", 432, 467, 35],\n",
+ " [226, \"07:13\", \"07:54\", 433, 474, 41],\n",
+ " [227, \"07:13\", \"07:38\", 433, 458, 25],\n",
+ " [228, \"07:14\", \"07:59\", 434, 479, 45],\n",
+ " [229, \"07:16\", \"08:50\", 436, 530, 94],\n",
+ " [230, \"07:16\", \"07:28\", 436, 448, 12],\n",
+ " [231, \"07:17\", \"07:35\", 437, 455, 18],\n",
+ " [232, \"07:17\", \"07:58\", 437, 478, 41],\n",
+ " [233, \"07:18\", \"08:06\", 438, 486, 48],\n",
+ " [234, \"07:18\", \"08:44\", 438, 524, 86],\n",
+ " [235, \"07:19\", \"08:13\", 439, 493, 54],\n",
+ " [236, \"07:20\", \"08:02\", 440, 482, 42],\n",
+ " [237, \"07:20\", \"08:07\", 440, 487, 47],\n",
+ " [238, \"07:20\", \"07:30\", 440, 450, 10],\n",
+ " [239, \"07:20\", \"07:57\", 440, 477, 37],\n",
+ " [240, \"07:20\", \"07:36\", 440, 456, 16],\n",
+ " [241, \"07:21\", \"07:48\", 441, 468, 27],\n",
+ " [242, \"07:22\", \"08:06\", 442, 486, 44],\n",
+ " [243, \"07:22\", \"08:25\", 442, 505, 63],\n",
+ " [244, \"07:24\", \"08:27\", 444, 507, 63],\n",
+ " [245, \"07:24\", \"08:05\", 444, 485, 41],\n",
+ " [246, \"07:26\", \"08:23\", 446, 503, 57],\n",
+ " [247, \"07:26\", \"08:52\", 446, 532, 86],\n",
+ " [248, \"07:27\", \"08:07\", 447, 487, 40],\n",
+ " [249, \"07:27\", \"07:42\", 447, 462, 15],\n",
+ " [250, \"07:27\", \"08:15\", 447, 495, 48],\n",
+ " [251, \"07:28\", \"07:53\", 448, 473, 25],\n",
+ " [252, \"07:28\", \"08:09\", 448, 489, 41],\n",
+ " [253, \"07:28\", \"07:38\", 448, 458, 10],\n",
+ " [254, \"07:30\", \"08:35\", 450, 515, 65],\n",
+ " [255, \"07:31\", \"07:43\", 451, 463, 12],\n",
+ " [256, \"07:32\", \"08:13\", 452, 493, 41],\n",
+ " [257, \"07:34\", \"09:00\", 454, 540, 86],\n",
+ " [258, \"07:34\", \"08:33\", 454, 513, 59],\n",
+ " [259, \"07:34\", \"09:04\", 454, 544, 90],\n",
+ " [260, \"07:35\", \"08:22\", 455, 502, 47],\n",
+ " [261, \"07:35\", \"07:45\", 455, 465, 10],\n",
+ " [262, \"07:35\", \"08:16\", 455, 496, 41],\n",
+ " [263, \"07:36\", \"08:17\", 456, 497, 41],\n",
+ " [264, \"07:36\", \"08:36\", 456, 516, 60],\n",
+ " [265, \"07:37\", \"07:50\", 457, 470, 13],\n",
+ " [266, \"07:40\", \"07:56\", 460, 476, 16],\n",
+ " [267, \"07:40\", \"08:20\", 460, 500, 40],\n",
+ " [268, \"07:40\", \"08:45\", 460, 525, 65],\n",
+ " [269, \"07:41\", \"08:39\", 461, 519, 58],\n",
+ " [270, \"07:41\", \"07:51\", 461, 471, 10],\n",
+ " [271, \"07:42\", \"08:30\", 462, 510, 48],\n",
+ " [272, \"07:42\", \"08:21\", 462, 501, 39],\n",
+ " [273, \"07:43\", \"08:08\", 463, 488, 25],\n",
+ " [274, \"07:43\", \"08:24\", 463, 504, 41],\n",
+ " [275, \"07:44\", \"09:10\", 464, 550, 86],\n",
+ " [276, \"07:44\", \"08:43\", 464, 523, 59],\n",
+ " [277, \"07:46\", \"08:28\", 466, 508, 42],\n",
+ " [278, \"07:46\", \"07:58\", 466, 478, 12],\n",
+ " [279, \"07:47\", \"08:00\", 467, 480, 13],\n",
+ " [280, \"07:48\", \"09:14\", 468, 554, 86],\n",
+ " [281, \"07:49\", \"08:32\", 469, 512, 43],\n",
+ " [282, \"07:50\", \"08:55\", 470, 535, 65],\n",
+ " [283, \"07:50\", \"08:00\", 470, 480, 10],\n",
+ " [284, \"07:50\", \"08:37\", 470, 517, 47],\n",
+ " [285, \"07:50\", \"08:26\", 470, 506, 36],\n",
+ " [286, \"07:51\", \"08:18\", 471, 498, 27],\n",
+ " [287, \"07:52\", \"08:21\", 472, 501, 29],\n",
+ " [288, \"07:53\", \"08:35\", 473, 515, 42],\n",
+ " [289, \"07:54\", \"09:19\", 474, 559, 85],\n",
+ " [290, \"07:55\", \"08:53\", 475, 533, 58],\n",
+ " [291, \"07:56\", \"08:54\", 476, 534, 58],\n",
+ " [292, \"07:57\", \"08:39\", 477, 519, 42],\n",
+ " [293, \"07:57\", \"08:10\", 477, 490, 13],\n",
+ " [294, \"07:58\", \"08:45\", 478, 525, 47],\n",
+ " [295, \"07:58\", \"08:23\", 478, 503, 25],\n",
+ " [296, \"08:00\", \"08:10\", 480, 490, 10],\n",
+ " [297, \"08:00\", \"09:05\", 480, 545, 65],\n",
+ " [298, \"08:00\", \"08:16\", 480, 496, 16],\n",
+ " [299, \"08:00\", \"08:35\", 480, 515, 35],\n",
+ " [300, \"08:01\", \"08:13\", 481, 493, 12],\n",
+ " [301, \"08:01\", \"08:43\", 481, 523, 42],\n",
+ " [302, \"08:03\", \"09:26\", 483, 566, 83],\n",
+ " [303, \"08:04\", \"09:29\", 484, 569, 85],\n",
+ " [304, \"08:05\", \"08:21\", 485, 501, 16],\n",
+ " [305, \"08:05\", \"08:47\", 485, 527, 42],\n",
+ " [306, \"08:06\", \"08:51\", 486, 531, 45],\n",
+ " [307, \"08:06\", \"09:03\", 486, 543, 57],\n",
+ " [308, \"08:07\", \"08:20\", 487, 500, 13],\n",
+ " [309, \"08:08\", \"08:55\", 488, 535, 47],\n",
+ " [310, \"08:08\", \"08:50\", 488, 530, 42],\n",
+ " [311, \"08:10\", \"08:45\", 490, 525, 35],\n",
+ " [312, \"08:10\", \"09:15\", 490, 555, 65],\n",
+ " [313, \"08:10\", \"08:20\", 490, 500, 10],\n",
+ " [314, \"08:11\", \"09:41\", 491, 581, 90],\n",
+ " [315, \"08:12\", \"08:55\", 492, 535, 43],\n",
+ " [316, \"08:13\", \"08:38\", 493, 518, 25],\n",
+ " [317, \"08:14\", \"09:38\", 494, 578, 84],\n",
+ " [318, \"08:15\", \"08:30\", 495, 510, 15],\n",
+ " [319, \"08:16\", \"08:30\", 496, 510, 14],\n",
+ " [320, \"08:16\", \"08:28\", 496, 508, 12],\n",
+ " [321, \"08:16\", \"09:00\", 496, 540, 44],\n",
+ " [322, \"08:17\", \"09:13\", 497, 553, 56],\n",
+ " [323, \"08:18\", \"09:16\", 498, 556, 58],\n",
+ " [324, \"08:18\", \"09:05\", 498, 545, 47],\n",
+ " [325, \"08:20\", \"08:36\", 500, 516, 16],\n",
+ " [326, \"08:20\", \"08:55\", 500, 535, 35],\n",
+ " [327, \"08:20\", \"09:05\", 500, 545, 45],\n",
+ " [328, \"08:20\", \"08:30\", 500, 510, 10],\n",
+ " [329, \"08:20\", \"09:25\", 500, 565, 65],\n",
+ " [330, \"08:21\", \"08:38\", 501, 518, 17],\n",
+ " [331, \"08:21\", \"08:47\", 501, 527, 26],\n",
+ " [332, \"08:22\", \"08:45\", 502, 525, 23],\n",
+ " [333, \"08:23\", \"09:10\", 503, 550, 47],\n",
+ " [334, \"08:24\", \"09:48\", 504, 588, 84],\n",
+ " [335, \"08:26\", \"08:46\", 506, 526, 20],\n",
+ " [336, \"08:27\", \"09:07\", 507, 547, 40],\n",
+ " [337, \"08:28\", \"08:50\", 508, 530, 22],\n",
+ " [338, \"08:28\", \"09:56\", 508, 596, 88],\n",
+ " [339, \"08:28\", \"09:23\", 508, 563, 55],\n",
+ " [340, \"08:29\", \"09:20\", 509, 560, 51],\n",
+ " [341, \"08:30\", \"09:05\", 510, 545, 35],\n",
+ " [342, \"08:30\", \"08:45\", 510, 525, 15],\n",
+ " [343, \"08:30\", \"08:40\", 510, 520, 10],\n",
+ " [344, \"08:30\", \"09:35\", 510, 575, 65],\n",
+ " [345, \"08:31\", \"08:43\", 511, 523, 12],\n",
+ " [346, \"08:31\", \"09:13\", 511, 553, 42],\n",
+ " [347, \"08:34\", \"09:58\", 514, 598, 84],\n",
+ " [348, \"08:35\", \"08:55\", 515, 535, 20],\n",
+ " [349, \"08:35\", \"09:15\", 515, 555, 40],\n",
+ " [350, \"08:35\", \"08:45\", 515, 525, 10],\n",
+ " [351, \"08:36\", \"08:46\", 516, 526, 10],\n",
+ " [352, \"08:36\", \"09:00\", 516, 540, 24],\n",
+ " [353, \"08:38\", \"09:20\", 518, 560, 42],\n",
+ " [354, \"08:38\", \"09:35\", 518, 575, 57],\n",
+ " [355, \"08:38\", \"09:14\", 518, 554, 36],\n",
+ " [356, \"08:39\", \"09:33\", 519, 573, 54],\n",
+ " [357, \"08:40\", \"09:45\", 520, 585, 65],\n",
+ " [358, \"08:40\", \"08:50\", 520, 530, 10],\n",
+ " [359, \"08:40\", \"08:56\", 520, 536, 16],\n",
+ " [360, \"08:42\", \"09:25\", 522, 565, 43],\n",
+ " [361, \"08:43\", \"09:08\", 523, 548, 25],\n",
+ " [362, \"08:44\", \"09:35\", 524, 575, 51],\n",
+ " [363, \"08:45\", \"09:00\", 525, 540, 15],\n",
+ " [364, \"08:45\", \"09:05\", 525, 545, 20],\n",
+ " [365, \"08:46\", \"09:24\", 526, 564, 38],\n",
+ " [366, \"08:46\", \"08:58\", 526, 538, 12],\n",
+ " [367, \"08:46\", \"09:30\", 526, 570, 44],\n",
+ " [368, \"08:48\", \"10:11\", 528, 611, 83],\n",
+ " [369, \"08:48\", \"10:13\", 528, 613, 85],\n",
+ " [370, \"08:49\", \"09:43\", 529, 583, 54],\n",
+ " [371, \"08:50\", \"09:30\", 530, 570, 40],\n",
+ " [372, \"08:50\", \"10:00\", 530, 600, 70],\n",
+ " [373, \"08:50\", \"09:00\", 530, 540, 10],\n",
+ " [374, \"08:51\", \"09:17\", 531, 557, 26],\n",
+ " [375, \"08:53\", \"09:20\", 533, 560, 27],\n",
+ " [376, \"08:53\", \"09:35\", 533, 575, 42],\n",
+ " [377, \"08:55\", \"09:34\", 535, 574, 39],\n",
+ " [378, \"08:55\", \"09:15\", 535, 555, 20],\n",
+ " [379, \"08:58\", \"09:38\", 538, 578, 40],\n",
+ " [380, \"08:58\", \"10:26\", 538, 626, 88],\n",
+ " [381, \"08:59\", \"09:53\", 539, 593, 54],\n",
+ " [382, \"08:59\", \"09:50\", 539, 590, 51],\n",
+ " [383, \"09:00\", \"09:35\", 540, 575, 35],\n",
+ " [384, \"09:00\", \"09:16\", 540, 556, 16],\n",
+ " [385, \"09:00\", \"09:10\", 540, 550, 10],\n",
+ " [386, \"09:00\", \"09:16\", 540, 556, 16],\n",
+ " [387, \"09:01\", \"09:13\", 541, 553, 12],\n",
+ " [388, \"09:03\", \"09:45\", 543, 585, 42],\n",
+ " [389, \"09:03\", \"10:28\", 543, 628, 85],\n",
+ " [390, \"09:05\", \"09:44\", 545, 584, 39],\n",
+ " [391, \"09:05\", \"09:25\", 545, 565, 20],\n",
+ " [392, \"09:08\", \"09:53\", 548, 593, 45],\n",
+ " [393, \"09:08\", \"10:04\", 548, 604, 56],\n",
+ " [394, \"09:09\", \"10:03\", 549, 603, 54],\n",
+ " [395, \"09:10\", \"10:15\", 550, 615, 65],\n",
+ " [396, \"09:10\", \"09:20\", 550, 560, 10],\n",
+ " [397, \"09:11\", \"09:38\", 551, 578, 27],\n",
+ " [398, \"09:13\", \"10:00\", 553, 600, 47],\n",
+ " [399, \"09:14\", \"09:39\", 554, 579, 25],\n",
+ " [400, \"09:14\", \"10:05\", 554, 605, 51],\n",
+ " [401, \"09:15\", \"09:54\", 555, 594, 39],\n",
+ " [402, \"09:16\", \"09:28\", 556, 568, 12],\n",
+ " [403, \"09:18\", \"10:43\", 558, 643, 85],\n",
+ " [404, \"09:18\", \"10:41\", 558, 641, 83],\n",
+ " [405, \"09:18\", \"09:58\", 558, 598, 40],\n",
+ " [406, \"09:19\", \"10:13\", 559, 613, 54],\n",
+ " [407, \"09:20\", \"09:30\", 560, 570, 10],\n",
+ " [408, \"09:20\", \"09:36\", 560, 576, 16],\n",
+ " [409, \"09:21\", \"09:47\", 561, 587, 26],\n",
+ " [410, \"09:23\", \"10:30\", 563, 630, 67],\n",
+ " [411, \"09:23\", \"10:05\", 563, 605, 42],\n",
+ " [412, \"09:23\", \"09:49\", 563, 589, 26],\n",
+ " [413, \"09:24\", \"09:35\", 564, 575, 11],\n",
+ " [414, \"09:25\", \"09:35\", 565, 575, 10],\n",
+ " [415, \"09:25\", \"10:04\", 565, 604, 39],\n",
+ " [416, \"09:28\", \"10:08\", 568, 608, 40],\n",
+ " [417, \"09:29\", \"09:45\", 569, 585, 16],\n",
+ " [418, \"09:29\", \"10:20\", 569, 620, 51],\n",
+ " [419, \"09:29\", \"10:56\", 569, 656, 87],\n",
+ " [420, \"09:29\", \"10:23\", 569, 623, 54],\n",
+ " [421, \"09:30\", \"09:40\", 570, 580, 10],\n",
+ " [422, \"09:31\", \"09:43\", 571, 583, 12],\n",
+ " [423, \"09:33\", \"10:58\", 573, 658, 85],\n",
+ " [424, \"09:33\", \"10:15\", 573, 615, 42],\n",
+ " [425, \"09:34\", \"09:45\", 574, 585, 11],\n",
+ " [426, \"09:35\", \"10:14\", 575, 614, 39],\n",
+ " [427, \"09:38\", \"10:45\", 578, 645, 67],\n",
+ " [428, \"09:39\", \"10:33\", 579, 633, 54],\n",
+ " [429, \"09:40\", \"09:56\", 580, 596, 16],\n",
+ " [430, \"09:40\", \"09:50\", 580, 590, 10],\n",
+ " [431, \"09:41\", \"10:08\", 581, 608, 27],\n",
+ " [432, \"09:41\", \"10:23\", 581, 623, 42],\n",
+ " [433, \"09:44\", \"10:35\", 584, 635, 51],\n",
+ " [434, \"09:44\", \"11:11\", 584, 671, 87],\n",
+ " [435, \"09:44\", \"09:55\", 584, 595, 11],\n",
+ " [436, \"09:45\", \"10:24\", 585, 624, 39],\n",
+ " [437, \"09:46\", \"09:58\", 586, 598, 12],\n",
+ " [438, \"09:48\", \"10:30\", 588, 630, 42],\n",
+ " [439, \"09:48\", \"11:13\", 588, 673, 85],\n",
+ " [440, \"09:48\", \"10:04\", 588, 604, 16],\n",
+ " [441, \"09:49\", \"10:43\", 589, 643, 54],\n",
+ " [442, \"09:50\", \"10:00\", 590, 600, 10],\n",
+ " [443, \"09:51\", \"10:17\", 591, 617, 26],\n",
+ " [444, \"09:53\", \"10:49\", 593, 649, 56],\n",
+ " [445, \"09:53\", \"11:00\", 593, 660, 67],\n",
+ " [446, \"09:54\", \"10:05\", 594, 605, 11],\n",
+ " [447, \"09:55\", \"10:34\", 595, 634, 39],\n",
+ " [448, \"09:56\", \"10:38\", 596, 638, 42],\n",
+ " [449, \"09:57\", \"10:20\", 597, 620, 23],\n",
+ " [450, \"09:59\", \"11:26\", 599, 686, 87],\n",
+ " [451, \"09:59\", \"10:50\", 599, 650, 51],\n",
+ " [452, \"09:59\", \"10:53\", 599, 653, 54],\n",
+ " [453, \"10:00\", \"10:16\", 600, 616, 16],\n",
+ " [454, \"10:00\", \"10:10\", 600, 610, 10],\n",
+ " [455, \"10:01\", \"10:13\", 601, 613, 12],\n",
+ " [456, \"10:03\", \"11:28\", 603, 688, 85],\n",
+ " [457, \"10:03\", \"10:45\", 603, 645, 42],\n",
+ " [458, \"10:04\", \"10:15\", 604, 615, 11],\n",
+ " [459, \"10:05\", \"10:44\", 605, 644, 39],\n",
+ " [460, \"10:08\", \"11:15\", 608, 675, 67],\n",
+ " [461, \"10:09\", \"11:03\", 609, 663, 54],\n",
+ " [462, \"10:10\", \"10:20\", 610, 620, 10],\n",
+ " [463, \"10:11\", \"10:38\", 611, 638, 27],\n",
+ " [464, \"10:11\", \"10:53\", 611, 653, 42],\n",
+ " [465, \"10:14\", \"11:05\", 614, 665, 51],\n",
+ " [466, \"10:14\", \"11:41\", 614, 701, 87],\n",
+ " [467, \"10:14\", \"10:25\", 614, 625, 11],\n",
+ " [468, \"10:15\", \"10:54\", 615, 654, 39],\n",
+ " [469, \"10:16\", \"10:28\", 616, 628, 12],\n",
+ " [470, \"10:18\", \"11:43\", 618, 703, 85],\n",
+ " [471, \"10:18\", \"11:00\", 618, 660, 42],\n",
+ " [472, \"10:19\", \"11:13\", 619, 673, 54],\n",
+ " [473, \"10:20\", \"10:30\", 620, 630, 10],\n",
+ " [474, \"10:20\", \"10:36\", 620, 636, 16],\n",
+ " [475, \"10:21\", \"10:47\", 621, 647, 26],\n",
+ " [476, \"10:23\", \"11:30\", 623, 690, 67],\n",
+ " [477, \"10:23\", \"10:45\", 623, 645, 22],\n",
+ " [478, \"10:24\", \"10:35\", 624, 635, 11],\n",
+ " [479, \"10:25\", \"11:04\", 625, 664, 39],\n",
+ " [480, \"10:26\", \"11:08\", 626, 668, 42],\n",
+ " [481, \"10:29\", \"11:20\", 629, 680, 51],\n",
+ " [482, \"10:29\", \"11:23\", 629, 683, 54],\n",
+ " [483, \"10:29\", \"11:56\", 629, 716, 87],\n",
+ " [484, \"10:30\", \"10:40\", 630, 640, 10],\n",
+ " [485, \"10:31\", \"10:43\", 631, 643, 12],\n",
+ " [486, \"10:33\", \"11:15\", 633, 675, 42],\n",
+ " [487, \"10:33\", \"11:58\", 633, 718, 85],\n",
+ " [488, \"10:34\", \"10:45\", 634, 645, 11],\n",
+ " [489, \"10:35\", \"11:14\", 635, 674, 39],\n",
+ " [490, \"10:38\", \"11:45\", 638, 705, 67],\n",
+ " [491, \"10:39\", \"11:33\", 639, 693, 54],\n",
+ " [492, \"10:40\", \"10:50\", 640, 650, 10],\n",
+ " [493, \"10:40\", \"10:56\", 640, 656, 16],\n",
+ " [494, \"10:41\", \"11:23\", 641, 683, 42],\n",
+ " [495, \"10:41\", \"11:08\", 641, 668, 27],\n",
+ " [496, \"10:44\", \"12:11\", 644, 731, 87],\n",
+ " [497, \"10:44\", \"11:35\", 644, 695, 51],\n",
+ " [498, \"10:44\", \"10:55\", 644, 655, 11],\n",
+ " [499, \"10:45\", \"11:24\", 645, 684, 39],\n",
+ " [500, \"10:46\", \"10:58\", 646, 658, 12],\n",
+ " [501, \"10:48\", \"12:13\", 648, 733, 85],\n",
+ " [502, \"10:48\", \"11:30\", 648, 690, 42],\n",
+ " [503, \"10:49\", \"11:43\", 649, 703, 54],\n",
+ " [504, \"10:50\", \"11:00\", 650, 660, 10],\n",
+ " [505, \"10:51\", \"11:17\", 651, 677, 26],\n",
+ " [506, \"10:53\", \"12:00\", 653, 720, 67],\n",
+ " [507, \"10:53\", \"11:20\", 653, 680, 27],\n",
+ " [508, \"10:54\", \"11:05\", 654, 665, 11],\n",
+ " [509, \"10:55\", \"11:34\", 655, 694, 39],\n",
+ " [510, \"10:56\", \"11:38\", 656, 698, 42],\n",
+ " [511, \"10:59\", \"11:14\", 659, 674, 15],\n",
+ " [512, \"10:59\", \"12:26\", 659, 746, 87],\n",
+ " [513, \"10:59\", \"11:53\", 659, 713, 54],\n",
+ " [514, \"10:59\", \"11:50\", 659, 710, 51],\n",
+ " [515, \"11:00\", \"11:16\", 660, 676, 16],\n",
+ " [516, \"11:00\", \"11:10\", 660, 670, 10],\n",
+ " [517, \"11:01\", \"11:13\", 661, 673, 12],\n",
+ " [518, \"11:03\", \"11:45\", 663, 705, 42],\n",
+ " [519, \"11:03\", \"12:28\", 663, 748, 85],\n",
+ " [520, \"11:04\", \"11:15\", 664, 675, 11],\n",
+ " [521, \"11:05\", \"11:44\", 665, 704, 39],\n",
+ " [522, \"11:08\", \"12:15\", 668, 735, 67],\n",
+ " [523, \"11:09\", \"12:03\", 669, 723, 54],\n",
+ " [524, \"11:10\", \"11:20\", 670, 680, 10],\n",
+ " [525, \"11:11\", \"11:38\", 671, 698, 27],\n",
+ " [526, \"11:11\", \"11:53\", 671, 713, 42],\n",
+ " [527, \"11:14\", \"11:25\", 674, 685, 11],\n",
+ " [528, \"11:14\", \"12:05\", 674, 725, 51],\n",
+ " [529, \"11:14\", \"12:38\", 674, 758, 84],\n",
+ " [530, \"11:14\", \"12:41\", 674, 761, 87],\n",
+ " [531, \"11:15\", \"11:54\", 675, 714, 39],\n",
+ " [532, \"11:16\", \"11:28\", 676, 688, 12],\n",
+ " [533, \"11:18\", \"12:00\", 678, 720, 42],\n",
+ " [534, \"11:19\", \"12:13\", 679, 733, 54],\n",
+ " [535, \"11:20\", \"11:30\", 680, 690, 10],\n",
+ " [536, \"11:20\", \"11:36\", 680, 696, 16],\n",
+ " [537, \"11:21\", \"11:47\", 681, 707, 26],\n",
+ " [538, \"11:23\", \"12:30\", 683, 750, 67],\n",
+ " [539, \"11:23\", \"11:49\", 683, 709, 26],\n",
+ " [540, \"11:24\", \"12:48\", 684, 768, 84],\n",
+ " [541, \"11:24\", \"11:35\", 684, 695, 11],\n",
+ " [542, \"11:25\", \"12:04\", 685, 724, 39],\n",
+ " [543, \"11:26\", \"12:08\", 686, 728, 42],\n",
+ " [544, \"11:29\", \"11:44\", 689, 704, 15],\n",
+ " [545, \"11:29\", \"12:23\", 689, 743, 54],\n",
+ " [546, \"11:29\", \"12:20\", 689, 740, 51],\n",
+ " [547, \"11:29\", \"12:54\", 689, 774, 85],\n",
+ " [548, \"11:30\", \"11:40\", 690, 700, 10],\n",
+ " [549, \"11:31\", \"11:43\", 691, 703, 12],\n",
+ " [550, \"11:33\", \"12:15\", 693, 735, 42],\n",
+ " [551, \"11:34\", \"12:58\", 694, 778, 84],\n",
+ " [552, \"11:34\", \"11:45\", 694, 705, 11],\n",
+ " [553, \"11:35\", \"12:14\", 695, 734, 39],\n",
+ " [554, \"11:38\", \"12:45\", 698, 765, 67],\n",
+ " [555, \"11:39\", \"12:33\", 699, 753, 54],\n",
+ " [556, \"11:40\", \"11:56\", 700, 716, 16],\n",
+ " [557, \"11:40\", \"11:50\", 700, 710, 10],\n",
+ " [558, \"11:41\", \"12:08\", 701, 728, 27],\n",
+ " [559, \"11:41\", \"12:23\", 701, 743, 42],\n",
+ " [560, \"11:44\", \"11:55\", 704, 715, 11],\n",
+ " [561, \"11:44\", \"13:14\", 704, 794, 90],\n",
+ " [562, \"11:44\", \"13:08\", 704, 788, 84],\n",
+ " [563, \"11:44\", \"12:35\", 704, 755, 51],\n",
+ " [564, \"11:45\", \"12:24\", 705, 744, 39],\n",
+ " [565, \"11:46\", \"11:58\", 706, 718, 12],\n",
+ " [566, \"11:48\", \"12:30\", 708, 750, 42],\n",
+ " [567, \"11:49\", \"12:43\", 709, 763, 54],\n",
+ " [568, \"11:50\", \"12:00\", 710, 720, 10],\n",
+ " [569, \"11:51\", \"12:17\", 711, 737, 26],\n",
+ " [570, \"11:53\", \"12:49\", 713, 769, 56],\n",
+ " [571, \"11:53\", \"13:00\", 713, 780, 67],\n",
+ " [572, \"11:54\", \"13:18\", 714, 798, 84],\n",
+ " [573, \"11:54\", \"12:05\", 714, 725, 11],\n",
+ " [574, \"11:55\", \"12:40\", 715, 760, 45],\n",
+ " [575, \"11:55\", \"12:34\", 715, 754, 39],\n",
+ " [576, \"11:56\", \"12:35\", 716, 755, 39],\n",
+ " [577, \"11:57\", \"12:20\", 717, 740, 23],\n",
+ " [578, \"11:58\", \"12:29\", 718, 749, 31],\n",
+ " [579, \"11:59\", \"12:50\", 719, 770, 51],\n",
+ " [580, \"11:59\", \"12:53\", 719, 773, 54],\n",
+ " [581, \"11:59\", \"13:24\", 719, 804, 85],\n",
+ " [582, \"11:59\", \"12:14\", 719, 734, 15],\n",
+ " [583, \"12:00\", \"12:16\", 720, 736, 16],\n",
+ " [584, \"12:00\", \"12:10\", 720, 730, 10],\n",
+ " [585, \"12:01\", \"12:45\", 721, 765, 44],\n",
+ " [586, \"12:01\", \"12:13\", 721, 733, 12],\n",
+ " [587, \"12:03\", \"12:50\", 723, 770, 47],\n",
+ " [588, \"12:04\", \"12:15\", 724, 735, 11],\n",
+ " [589, \"12:04\", \"13:04\", 724, 784, 60],\n",
+ " [590, \"12:04\", \"13:28\", 724, 808, 84],\n",
+ " [591, \"12:05\", \"12:44\", 725, 764, 39],\n",
+ " [592, \"12:08\", \"13:11\", 728, 791, 63],\n",
+ " [593, \"12:08\", \"12:39\", 728, 759, 31],\n",
+ " [594, \"12:09\", \"13:03\", 729, 783, 54],\n",
+ " [595, \"12:10\", \"12:20\", 730, 740, 10],\n",
+ " [596, \"12:11\", \"12:55\", 731, 775, 44],\n",
+ " [597, \"12:11\", \"12:38\", 731, 758, 27],\n",
+ " [598, \"12:14\", \"13:05\", 734, 785, 51],\n",
+ " [599, \"12:14\", \"12:25\", 734, 745, 11],\n",
+ " [600, \"12:14\", \"13:44\", 734, 824, 90],\n",
+ " [601, \"12:14\", \"13:38\", 734, 818, 84],\n",
+ " [602, \"12:15\", \"12:54\", 735, 774, 39],\n",
+ " [603, \"12:16\", \"12:28\", 736, 748, 12],\n",
+ " [604, \"12:18\", \"13:00\", 738, 780, 42],\n",
+ " [605, \"12:19\", \"13:13\", 739, 793, 54],\n",
+ " [606, \"12:20\", \"12:30\", 740, 750, 10],\n",
+ " [607, \"12:20\", \"13:31\", 740, 811, 71],\n",
+ " [608, \"12:20\", \"12:30\", 740, 750, 10],\n",
+ " [609, \"12:20\", \"12:36\", 740, 756, 16],\n",
+ " [610, \"12:21\", \"12:47\", 741, 767, 26],\n",
+ " [611, \"12:23\", \"12:45\", 743, 765, 22],\n",
+ " [612, \"12:24\", \"12:35\", 744, 755, 11],\n",
+ " [613, \"12:24\", \"13:48\", 744, 828, 84],\n",
+ " [614, \"12:25\", \"13:10\", 745, 790, 45],\n",
+ " [615, \"12:25\", \"13:04\", 745, 784, 39],\n",
+ " [616, \"12:26\", \"13:05\", 746, 785, 39],\n",
+ " [617, \"12:28\", \"13:54\", 748, 834, 86],\n",
+ " [618, \"12:28\", \"12:38\", 748, 758, 10],\n",
+ " [619, \"12:28\", \"13:15\", 748, 795, 47],\n",
+ " [620, \"12:29\", \"13:23\", 749, 803, 54],\n",
+ " [621, \"12:30\", \"13:41\", 750, 821, 71],\n",
+ " [622, \"12:30\", \"12:40\", 750, 760, 10],\n",
+ " [623, \"12:31\", \"13:15\", 751, 795, 44],\n",
+ " [624, \"12:31\", \"12:43\", 751, 763, 12],\n",
+ " [625, \"12:33\", \"12:48\", 753, 768, 15],\n",
+ " [626, \"12:33\", \"13:20\", 753, 800, 47],\n",
+ " [627, \"12:34\", \"13:58\", 754, 838, 84],\n",
+ " [628, \"12:34\", \"13:34\", 754, 814, 60],\n",
+ " [629, \"12:34\", \"12:45\", 754, 765, 11],\n",
+ " [630, \"12:35\", \"13:14\", 755, 794, 39],\n",
+ " [631, \"12:38\", \"13:25\", 758, 805, 47],\n",
+ " [632, \"12:38\", \"13:25\", 758, 805, 47],\n",
+ " [633, \"12:38\", \"14:04\", 758, 844, 86],\n",
+ " [634, \"12:39\", \"13:33\", 759, 813, 54],\n",
+ " [635, \"12:40\", \"13:51\", 760, 831, 71],\n",
+ " [636, \"12:40\", \"12:50\", 760, 770, 10],\n",
+ " [637, \"12:40\", \"12:56\", 760, 776, 16],\n",
+ " [638, \"12:41\", \"13:08\", 761, 788, 27],\n",
+ " [639, \"12:43\", \"13:30\", 763, 810, 47],\n",
+ " [640, \"12:44\", \"12:55\", 764, 775, 11],\n",
+ " [641, \"12:44\", \"14:08\", 764, 848, 84],\n",
+ " [642, \"12:45\", \"13:24\", 765, 804, 39],\n",
+ " [643, \"12:46\", \"12:58\", 766, 778, 12],\n",
+ " [644, \"12:46\", \"13:21\", 766, 801, 35],\n",
+ " [645, \"12:48\", \"14:14\", 768, 854, 86],\n",
+ " [646, \"12:48\", \"13:35\", 768, 815, 47],\n",
+ " [647, \"12:48\", \"12:58\", 768, 778, 10],\n",
+ " [648, \"12:48\", \"13:35\", 768, 815, 47],\n",
+ " [649, \"12:49\", \"13:43\", 769, 823, 54],\n",
+ " [650, \"12:50\", \"14:01\", 770, 841, 71],\n",
+ " [651, \"12:50\", \"13:00\", 770, 780, 10],\n",
+ " [652, \"12:50\", \"13:00\", 770, 780, 10],\n",
+ " [653, \"12:51\", \"13:17\", 771, 797, 26],\n",
+ " [654, \"12:53\", \"13:20\", 773, 800, 27],\n",
+ " [655, \"12:53\", \"13:24\", 773, 804, 31],\n",
+ " [656, \"12:53\", \"13:40\", 773, 820, 47],\n",
+ " [657, \"12:54\", \"14:18\", 774, 858, 84],\n",
+ " [658, \"12:54\", \"13:05\", 774, 785, 11],\n",
+ " [659, \"12:55\", \"13:34\", 775, 814, 39],\n",
+ " [660, \"12:58\", \"14:24\", 778, 864, 86],\n",
+ " [661, \"12:58\", \"13:25\", 778, 805, 27],\n",
+ " [662, \"12:58\", \"13:45\", 778, 825, 47],\n",
+ " [663, \"12:58\", \"13:45\", 778, 825, 47],\n",
+ " [664, \"12:59\", \"13:53\", 779, 833, 54],\n",
+ " [665, \"13:00\", \"13:10\", 780, 790, 10],\n",
+ " [666, \"13:00\", \"13:16\", 780, 796, 16],\n",
+ " [667, \"13:00\", \"14:11\", 780, 851, 71],\n",
+ " [668, \"13:01\", \"13:13\", 781, 793, 12],\n",
+ " [669, \"13:03\", \"13:34\", 783, 814, 31],\n",
+ " [670, \"13:03\", \"13:50\", 783, 830, 47],\n",
+ " [671, \"13:04\", \"13:15\", 784, 795, 11],\n",
+ " [672, \"13:04\", \"14:28\", 784, 868, 84],\n",
+ " [673, \"13:05\", \"13:44\", 785, 824, 39],\n",
+ " [674, \"13:08\", \"13:55\", 788, 835, 47],\n",
+ " [675, \"13:08\", \"14:34\", 788, 874, 86],\n",
+ " [676, \"13:08\", \"13:55\", 788, 835, 47],\n",
+ " [677, \"13:09\", \"14:03\", 789, 843, 54],\n",
+ " [678, \"13:10\", \"13:20\", 790, 800, 10],\n",
+ " [679, \"13:10\", \"14:21\", 790, 861, 71],\n",
+ " [680, \"13:13\", \"14:00\", 793, 840, 47],\n",
+ " [681, \"13:13\", \"13:40\", 793, 820, 27],\n",
+ " [682, \"13:14\", \"14:38\", 794, 878, 84],\n",
+ " [683, \"13:14\", \"13:25\", 794, 805, 11],\n",
+ " [684, \"13:15\", \"13:54\", 795, 834, 39],\n",
+ " [685, \"13:16\", \"13:28\", 796, 808, 12],\n",
+ " [686, \"13:18\", \"14:05\", 798, 845, 47],\n",
+ " [687, \"13:18\", \"14:44\", 798, 884, 86],\n",
+ " [688, \"13:18\", \"14:05\", 798, 845, 47],\n",
+ " [689, \"13:19\", \"14:13\", 799, 853, 54],\n",
+ " [690, \"13:20\", \"13:36\", 800, 816, 16],\n",
+ " [691, \"13:20\", \"14:31\", 800, 871, 71],\n",
+ " [692, \"13:20\", \"13:30\", 800, 810, 10],\n",
+ " [693, \"13:21\", \"13:47\", 801, 827, 26],\n",
+ " [694, \"13:23\", \"14:10\", 803, 850, 47],\n",
+ " [695, \"13:23\", \"13:49\", 803, 829, 26],\n",
+ " [696, \"13:24\", \"14:48\", 804, 888, 84],\n",
+ " [697, \"13:24\", \"13:35\", 804, 815, 11],\n",
+ " [698, \"13:25\", \"14:04\", 805, 844, 39],\n",
+ " [699, \"13:28\", \"14:15\", 808, 855, 47],\n",
+ " [700, \"13:28\", \"14:54\", 808, 894, 86],\n",
+ " [701, \"13:28\", \"13:55\", 808, 835, 27],\n",
+ " [702, \"13:28\", \"14:15\", 808, 855, 47],\n",
+ " [703, \"13:29\", \"14:23\", 809, 863, 54],\n",
+ " [704, \"13:30\", \"13:40\", 810, 820, 10],\n",
+ " [705, \"13:30\", \"14:41\", 810, 881, 71],\n",
+ " [706, \"13:31\", \"13:43\", 811, 823, 12],\n",
+ " [707, \"13:33\", \"14:20\", 813, 860, 47],\n",
+ " [708, \"13:34\", \"14:58\", 814, 898, 84],\n",
+ " [709, \"13:34\", \"13:45\", 814, 825, 11],\n",
+ " [710, \"13:35\", \"14:14\", 815, 854, 39],\n",
+ " [711, \"13:38\", \"14:25\", 818, 865, 47],\n",
+ " [712, \"13:38\", \"14:25\", 818, 865, 47],\n",
+ " [713, \"13:38\", \"15:04\", 818, 904, 86],\n",
+ " [714, \"13:39\", \"14:33\", 819, 873, 54],\n",
+ " [715, \"13:40\", \"13:50\", 820, 830, 10],\n",
+ " [716, \"13:40\", \"13:56\", 820, 836, 16],\n",
+ " [717, \"13:40\", \"14:51\", 820, 891, 71],\n",
+ " [718, \"13:43\", \"14:30\", 823, 870, 47],\n",
+ " [719, \"13:43\", \"14:10\", 823, 850, 27],\n",
+ " [720, \"13:44\", \"15:09\", 824, 909, 85],\n",
+ " [721, \"13:44\", \"13:55\", 824, 835, 11],\n",
+ " [722, \"13:45\", \"14:24\", 825, 864, 39],\n",
+ " [723, \"13:46\", \"13:58\", 826, 838, 12],\n",
+ " [724, \"13:48\", \"14:35\", 828, 875, 47],\n",
+ " [725, \"13:48\", \"15:14\", 828, 914, 86],\n",
+ " [726, \"13:48\", \"14:35\", 828, 875, 47],\n",
+ " [727, \"13:49\", \"14:43\", 829, 883, 54],\n",
+ " [728, \"13:50\", \"14:00\", 830, 840, 10],\n",
+ " [729, \"13:50\", \"15:01\", 830, 901, 71],\n",
+ " [730, \"13:51\", \"14:17\", 831, 857, 26],\n",
+ " [731, \"13:53\", \"14:40\", 833, 880, 47],\n",
+ " [732, \"13:53\", \"14:49\", 833, 889, 56],\n",
+ " [733, \"13:54\", \"14:05\", 834, 845, 11],\n",
+ " [734, \"13:54\", \"15:19\", 834, 919, 85],\n",
+ " [735, \"13:55\", \"14:34\", 835, 874, 39],\n",
+ " [736, \"13:57\", \"14:20\", 837, 860, 23],\n",
+ " [737, \"13:58\", \"15:24\", 838, 924, 86],\n",
+ " [738, \"13:58\", \"14:45\", 838, 885, 47],\n",
+ " [739, \"13:58\", \"14:45\", 838, 885, 47],\n",
+ " [740, \"13:58\", \"14:25\", 838, 865, 27],\n",
+ " [741, \"13:59\", \"14:53\", 839, 893, 54],\n",
+ " [742, \"14:00\", \"14:16\", 840, 856, 16],\n",
+ " [743, \"14:00\", \"14:10\", 840, 850, 10],\n",
+ " [744, \"14:00\", \"15:11\", 840, 911, 71],\n",
+ " [745, \"14:01\", \"14:13\", 841, 853, 12],\n",
+ " [746, \"14:03\", \"14:50\", 843, 890, 47],\n",
+ " [747, \"14:04\", \"14:15\", 844, 855, 11],\n",
+ " [748, \"14:04\", \"15:29\", 844, 929, 85],\n",
+ " [749, \"14:05\", \"14:44\", 845, 884, 39],\n",
+ " [750, \"14:08\", \"14:55\", 848, 895, 47],\n",
+ " [751, \"14:08\", \"14:55\", 848, 895, 47],\n",
+ " [752, \"14:08\", \"15:34\", 848, 934, 86],\n",
+ " [753, \"14:09\", \"15:03\", 849, 903, 54],\n",
+ " [754, \"14:10\", \"15:21\", 850, 921, 71],\n",
+ " [755, \"14:10\", \"14:20\", 850, 860, 10],\n",
+ " [756, \"14:13\", \"15:00\", 853, 900, 47],\n",
+ " [757, \"14:13\", \"14:40\", 853, 880, 27],\n",
+ " [758, \"14:14\", \"15:40\", 854, 940, 86],\n",
+ " [759, \"14:14\", \"14:25\", 854, 865, 11],\n",
+ " [760, \"14:15\", \"14:54\", 855, 894, 39],\n",
+ " [761, \"14:16\", \"14:28\", 856, 868, 12],\n",
+ " [762, \"14:18\", \"15:05\", 858, 905, 47],\n",
+ " [763, \"14:18\", \"15:44\", 858, 944, 86],\n",
+ " [764, \"14:18\", \"15:05\", 858, 905, 47],\n",
+ " [765, \"14:19\", \"15:13\", 859, 913, 54],\n",
+ " [766, \"14:20\", \"15:31\", 860, 931, 71],\n",
+ " [767, \"14:20\", \"14:30\", 860, 870, 10],\n",
+ " [768, \"14:20\", \"14:36\", 860, 876, 16],\n",
+ " [769, \"14:21\", \"14:47\", 861, 887, 26],\n",
+ " [770, \"14:23\", \"15:10\", 863, 910, 47],\n",
+ " [771, \"14:23\", \"14:45\", 863, 885, 22],\n",
+ " [772, \"14:24\", \"15:50\", 864, 950, 86],\n",
+ " [773, \"14:24\", \"14:35\", 864, 875, 11],\n",
+ " [774, \"14:25\", \"15:02\", 865, 902, 37],\n",
+ " [775, \"14:26\", \"14:52\", 866, 892, 26],\n",
+ " [776, \"14:28\", \"15:15\", 868, 915, 47],\n",
+ " [777, \"14:28\", \"14:55\", 868, 895, 27],\n",
+ " [778, \"14:28\", \"15:54\", 868, 954, 86],\n",
+ " [779, \"14:28\", \"15:15\", 868, 915, 47],\n",
+ " [780, \"14:29\", \"15:23\", 869, 923, 54],\n",
+ " [781, \"14:30\", \"15:41\", 870, 941, 71],\n",
+ " [782, \"14:30\", \"14:40\", 870, 880, 10],\n",
+ " [783, \"14:31\", \"14:43\", 871, 883, 12],\n",
+ " [784, \"14:33\", \"15:20\", 873, 920, 47],\n",
+ " [785, \"14:34\", \"16:00\", 874, 960, 86],\n",
+ " [786, \"14:34\", \"14:45\", 874, 885, 11],\n",
+ " [787, \"14:35\", \"15:11\", 875, 911, 36],\n",
+ " [788, \"14:38\", \"15:25\", 878, 925, 47],\n",
+ " [789, \"14:38\", \"15:25\", 878, 925, 47],\n",
+ " [790, \"14:38\", \"16:04\", 878, 964, 86],\n",
+ " [791, \"14:39\", \"15:33\", 879, 933, 54],\n",
+ " [792, \"14:40\", \"14:50\", 880, 890, 10],\n",
+ " [793, \"14:40\", \"15:51\", 880, 951, 71],\n",
+ " [794, \"14:40\", \"14:56\", 880, 896, 16],\n",
+ " [795, \"14:43\", \"15:30\", 883, 930, 47],\n",
+ " [796, \"14:43\", \"15:10\", 883, 910, 27],\n",
+ " [797, \"14:44\", \"15:00\", 884, 900, 16],\n",
+ " [798, \"14:44\", \"16:10\", 884, 970, 86],\n",
+ " [799, \"14:45\", \"15:19\", 885, 919, 34],\n",
+ " [800, \"14:46\", \"14:58\", 886, 898, 12],\n",
+ " [801, \"14:48\", \"15:35\", 888, 935, 47],\n",
+ " [802, \"14:48\", \"15:35\", 888, 935, 47],\n",
+ " [803, \"14:48\", \"17:04\", 888, 1024, 136],\n",
+ " [804, \"14:49\", \"15:43\", 889, 943, 54],\n",
+ " [805, \"14:50\", \"16:01\", 890, 961, 71],\n",
+ " [806, \"14:50\", \"15:00\", 890, 900, 10],\n",
+ " [807, \"14:51\", \"15:17\", 891, 917, 26],\n",
+ " [808, \"14:52\", \"15:27\", 892, 927, 35],\n",
+ " [809, \"14:52\", \"15:21\", 892, 921, 29],\n",
+ " [810, \"14:53\", \"15:40\", 893, 940, 47],\n",
+ " [811, \"14:54\", \"15:08\", 894, 908, 14],\n",
+ " [812, \"14:54\", \"16:20\", 894, 980, 86],\n",
+ " [813, \"14:58\", \"16:24\", 898, 984, 86],\n",
+ " [814, \"14:58\", \"15:45\", 898, 945, 47],\n",
+ " [815, \"14:58\", \"15:25\", 898, 925, 27],\n",
+ " [816, \"14:58\", \"15:45\", 898, 945, 47],\n",
+ " [817, \"14:59\", \"15:53\", 899, 953, 54],\n",
+ " [818, \"15:00\", \"15:10\", 900, 910, 10],\n",
+ " [819, \"15:00\", \"15:35\", 900, 935, 35],\n",
+ " [820, \"15:00\", \"16:11\", 900, 971, 71],\n",
+ " [821, \"15:00\", \"15:16\", 900, 916, 16],\n",
+ " [822, \"15:01\", \"15:13\", 901, 913, 12],\n",
+ " [823, \"15:02\", \"15:16\", 902, 916, 14],\n",
+ " [824, \"15:03\", \"15:50\", 903, 950, 47],\n",
+ " [825, \"15:04\", \"16:30\", 904, 990, 86],\n",
+ " [826, \"15:08\", \"16:34\", 908, 994, 86],\n",
+ " [827, \"15:08\", \"15:55\", 908, 955, 47],\n",
+ " [828, \"15:08\", \"15:55\", 908, 955, 47],\n",
+ " [829, \"15:08\", \"15:45\", 908, 945, 37],\n",
+ " [830, \"15:09\", \"16:14\", 909, 974, 65],\n",
+ " [831, \"15:09\", \"16:03\", 909, 963, 54],\n",
+ " [832, \"15:10\", \"16:21\", 910, 981, 71],\n",
+ " [833, \"15:10\", \"15:20\", 910, 920, 10],\n",
+ " [834, \"15:11\", \"15:24\", 911, 924, 13],\n",
+ " [835, \"15:12\", \"15:36\", 912, 936, 24],\n",
+ " [836, \"15:13\", \"16:00\", 913, 960, 47],\n",
+ " [837, \"15:13\", \"15:40\", 913, 940, 27],\n",
+ " [838, \"15:14\", \"16:40\", 914, 1000, 86],\n",
+ " [839, \"15:16\", \"15:28\", 916, 928, 12],\n",
+ " [840, \"15:16\", \"15:55\", 916, 955, 39],\n",
+ " [841, \"15:18\", \"16:05\", 918, 965, 47],\n",
+ " [842, \"15:18\", \"16:44\", 918, 1004, 86],\n",
+ " [843, \"15:18\", \"16:05\", 918, 965, 47],\n",
+ " [844, \"15:19\", \"16:13\", 919, 973, 54],\n",
+ " [845, \"15:19\", \"15:34\", 919, 934, 15],\n",
+ " [846, \"15:20\", \"15:30\", 920, 930, 10],\n",
+ " [847, \"15:20\", \"16:31\", 920, 991, 71],\n",
+ " [848, \"15:20\", \"15:36\", 920, 936, 16],\n",
+ " [849, \"15:21\", \"15:47\", 921, 947, 26],\n",
+ " [850, \"15:21\", \"16:06\", 921, 966, 45],\n",
+ " [851, \"15:23\", \"16:10\", 923, 970, 47],\n",
+ " [852, \"15:24\", \"16:50\", 924, 1010, 86],\n",
+ " [853, \"15:24\", \"16:05\", 924, 965, 41],\n",
+ " [854, \"15:27\", \"15:51\", 927, 951, 24],\n",
+ " [855, \"15:27\", \"15:44\", 927, 944, 17],\n",
+ " [856, \"15:28\", \"16:15\", 928, 975, 47],\n",
+ " [857, \"15:28\", \"16:54\", 928, 1014, 86],\n",
+ " [858, \"15:28\", \"16:15\", 928, 975, 47],\n",
+ " [859, \"15:28\", \"15:55\", 928, 955, 27],\n",
+ " [860, \"15:29\", \"16:23\", 929, 983, 54],\n",
+ " [861, \"15:30\", \"16:41\", 930, 1001, 71],\n",
+ " [862, \"15:30\", \"15:40\", 930, 940, 10],\n",
+ " [863, \"15:31\", \"15:43\", 931, 943, 12],\n",
+ " [864, \"15:33\", \"16:20\", 933, 980, 47],\n",
+ " [865, \"15:34\", \"17:00\", 934, 1020, 86],\n",
+ " [866, \"15:34\", \"16:15\", 934, 975, 41],\n",
+ " [867, \"15:35\", \"15:54\", 935, 954, 19],\n",
+ " [868, \"15:36\", \"16:21\", 936, 981, 45],\n",
+ " [869, \"15:38\", \"16:25\", 938, 985, 47],\n",
+ " [870, \"15:38\", \"16:25\", 938, 985, 47],\n",
+ " [871, \"15:38\", \"16:39\", 938, 999, 61],\n",
+ " [872, \"15:39\", \"16:33\", 939, 993, 54],\n",
+ " [873, \"15:40\", \"15:50\", 940, 950, 10],\n",
+ " [874, \"15:40\", \"16:51\", 940, 1011, 71],\n",
+ " [875, \"15:40\", \"15:56\", 940, 956, 16],\n",
+ " [876, \"15:43\", \"16:10\", 943, 970, 27],\n",
+ " [877, \"15:43\", \"16:30\", 943, 990, 47],\n",
+ " [878, \"15:44\", \"17:10\", 944, 1030, 86],\n",
+ " [879, \"15:44\", \"16:25\", 944, 985, 41],\n",
+ " [880, \"15:45\", \"16:04\", 945, 964, 19],\n",
+ " [881, \"15:46\", \"15:58\", 946, 958, 12],\n",
+ " [882, \"15:48\", \"16:35\", 948, 995, 47],\n",
+ " [883, \"15:48\", \"16:35\", 948, 995, 47],\n",
+ " [884, \"15:48\", \"17:14\", 948, 1034, 86],\n",
+ " [885, \"15:49\", \"16:43\", 949, 1003, 54],\n",
+ " [886, \"15:50\", \"16:00\", 950, 960, 10],\n",
+ " [887, \"15:50\", \"17:01\", 950, 1021, 71],\n",
+ " [888, \"15:51\", \"16:18\", 951, 978, 27],\n",
+ " [889, \"15:52\", \"16:36\", 952, 996, 44],\n",
+ " [890, \"15:53\", \"16:40\", 953, 1000, 47],\n",
+ " [891, \"15:54\", \"17:20\", 954, 1040, 86],\n",
+ " [892, \"15:54\", \"16:35\", 954, 995, 41],\n",
+ " [893, \"15:55\", \"16:14\", 955, 974, 19],\n",
+ " [894, \"15:58\", \"16:25\", 958, 985, 27],\n",
+ " [895, \"15:58\", \"16:45\", 958, 1005, 47],\n",
+ " [896, \"15:58\", \"16:45\", 958, 1005, 47],\n",
+ " [897, \"15:58\", \"17:24\", 958, 1044, 86],\n",
+ " [898, \"15:59\", \"17:11\", 959, 1031, 72],\n",
+ " [899, \"15:59\", \"16:53\", 959, 1013, 54],\n",
+ " [900, \"16:00\", \"16:10\", 960, 970, 10],\n",
+ " [901, \"16:00\", \"16:16\", 960, 976, 16],\n",
+ " [902, \"16:01\", \"16:13\", 961, 973, 12],\n",
+ " [903, \"16:03\", \"16:50\", 963, 1010, 47],\n",
+ " [904, \"16:04\", \"17:30\", 964, 1050, 86],\n",
+ " [905, \"16:04\", \"16:45\", 964, 1005, 41],\n",
+ " [906, \"16:05\", \"16:24\", 965, 984, 19],\n",
+ " [907, \"16:06\", \"16:51\", 966, 1011, 45],\n",
+ " [908, \"16:08\", \"16:55\", 968, 1015, 47],\n",
+ " [909, \"16:08\", \"17:34\", 968, 1054, 86],\n",
+ " [910, \"16:08\", \"16:55\", 968, 1015, 47],\n",
+ " [911, \"16:09\", \"17:03\", 969, 1023, 54],\n",
+ " [912, \"16:09\", \"17:21\", 969, 1041, 72],\n",
+ " [913, \"16:10\", \"16:20\", 970, 980, 10],\n",
+ " [914, \"16:13\", \"16:40\", 973, 1000, 27],\n",
+ " [915, \"16:13\", \"17:00\", 973, 1020, 47],\n",
+ " [916, \"16:14\", \"16:55\", 974, 1015, 41],\n",
+ " [917, \"16:14\", \"17:40\", 974, 1060, 86],\n",
+ " [918, \"16:15\", \"16:34\", 975, 994, 19],\n",
+ " [919, \"16:16\", \"16:28\", 976, 988, 12],\n",
+ " [920, \"16:18\", \"17:05\", 978, 1025, 47],\n",
+ " [921, \"16:18\", \"17:05\", 978, 1025, 47],\n",
+ " [922, \"16:18\", \"17:44\", 978, 1064, 86],\n",
+ " [923, \"16:19\", \"17:31\", 979, 1051, 72],\n",
+ " [924, \"16:19\", \"17:13\", 979, 1033, 54],\n",
+ " [925, \"16:20\", \"16:30\", 980, 990, 10],\n",
+ " [926, \"16:20\", \"16:36\", 980, 996, 16],\n",
+ " [927, \"16:21\", \"16:48\", 981, 1008, 27],\n",
+ " [928, \"16:22\", \"17:06\", 982, 1026, 44],\n",
+ " [929, \"16:23\", \"17:10\", 983, 1030, 47],\n",
+ " [930, \"16:24\", \"17:05\", 984, 1025, 41],\n",
+ " [931, \"16:24\", \"17:50\", 984, 1070, 86],\n",
+ " [932, \"16:25\", \"16:44\", 985, 1004, 19],\n",
+ " [933, \"16:28\", \"17:15\", 988, 1035, 47],\n",
+ " [934, \"16:28\", \"17:15\", 988, 1035, 47],\n",
+ " [935, \"16:28\", \"16:55\", 988, 1015, 27],\n",
+ " [936, \"16:28\", \"17:54\", 988, 1074, 86],\n",
+ " [937, \"16:29\", \"17:23\", 989, 1043, 54],\n",
+ " [938, \"16:29\", \"17:41\", 989, 1061, 72],\n",
+ " [939, \"16:30\", \"16:40\", 990, 1000, 10],\n",
+ " [940, \"16:31\", \"16:43\", 991, 1003, 12],\n",
+ " [941, \"16:33\", \"17:20\", 993, 1040, 47],\n",
+ " [942, \"16:34\", \"17:15\", 994, 1035, 41],\n",
+ " [943, \"16:34\", \"18:00\", 994, 1080, 86],\n",
+ " [944, \"16:35\", \"16:54\", 995, 1014, 19],\n",
+ " [945, \"16:36\", \"17:21\", 996, 1041, 45],\n",
+ " [946, \"16:38\", \"17:25\", 998, 1045, 47],\n",
+ " [947, \"16:38\", \"17:25\", 998, 1045, 47],\n",
+ " [948, \"16:38\", \"18:04\", 998, 1084, 86],\n",
+ " [949, \"16:39\", \"17:33\", 999, 1053, 54],\n",
+ " [950, \"16:39\", \"17:51\", 999, 1071, 72],\n",
+ " [951, \"16:40\", \"16:56\", 1000, 1016, 16],\n",
+ " [952, \"16:40\", \"16:50\", 1000, 1010, 10],\n",
+ " [953, \"16:43\", \"17:10\", 1003, 1030, 27],\n",
+ " [954, \"16:43\", \"17:30\", 1003, 1050, 47],\n",
+ " [955, \"16:44\", \"17:25\", 1004, 1045, 41],\n",
+ " [956, \"16:44\", \"18:10\", 1004, 1090, 86],\n",
+ " [957, \"16:45\", \"17:04\", 1005, 1024, 19],\n",
+ " [958, \"16:46\", \"16:58\", 1006, 1018, 12],\n",
+ " [959, \"16:48\", \"18:14\", 1008, 1094, 86],\n",
+ " [960, \"16:48\", \"17:35\", 1008, 1055, 47],\n",
+ " [961, \"16:48\", \"17:35\", 1008, 1055, 47],\n",
+ " [962, \"16:49\", \"18:01\", 1009, 1081, 72],\n",
+ " [963, \"16:49\", \"17:43\", 1009, 1063, 54],\n",
+ " [964, \"16:50\", \"17:00\", 1010, 1020, 10],\n",
+ " [965, \"16:51\", \"17:18\", 1011, 1038, 27],\n",
+ " [966, \"16:52\", \"17:36\", 1012, 1056, 44],\n",
+ " [967, \"16:53\", \"17:40\", 1013, 1060, 47],\n",
+ " [968, \"16:54\", \"18:20\", 1014, 1100, 86],\n",
+ " [969, \"16:54\", \"17:35\", 1014, 1055, 41],\n",
+ " [970, \"16:55\", \"17:14\", 1015, 1034, 19],\n",
+ " [971, \"16:58\", \"17:25\", 1018, 1045, 27],\n",
+ " [972, \"16:58\", \"17:45\", 1018, 1065, 47],\n",
+ " [973, \"16:58\", \"17:45\", 1018, 1065, 47],\n",
+ " [974, \"16:58\", \"18:24\", 1018, 1104, 86],\n",
+ " [975, \"16:59\", \"18:11\", 1019, 1091, 72],\n",
+ " [976, \"16:59\", \"17:53\", 1019, 1073, 54],\n",
+ " [977, \"17:00\", \"17:16\", 1020, 1036, 16],\n",
+ " [978, \"17:00\", \"17:10\", 1020, 1030, 10],\n",
+ " [979, \"17:01\", \"17:13\", 1021, 1033, 12],\n",
+ " [980, \"17:03\", \"17:50\", 1023, 1070, 47],\n",
+ " [981, \"17:04\", \"18:30\", 1024, 1110, 86],\n",
+ " [982, \"17:04\", \"17:45\", 1024, 1065, 41],\n",
+ " [983, \"17:05\", \"17:24\", 1025, 1044, 19],\n",
+ " [984, \"17:06\", \"17:51\", 1026, 1071, 45],\n",
+ " [985, \"17:08\", \"17:55\", 1028, 1075, 47],\n",
+ " [986, \"17:08\", \"17:55\", 1028, 1075, 47],\n",
+ " [987, \"17:08\", \"18:34\", 1028, 1114, 86],\n",
+ " [988, \"17:09\", \"18:03\", 1029, 1083, 54],\n",
+ " [989, \"17:09\", \"18:21\", 1029, 1101, 72],\n",
+ " [990, \"17:10\", \"17:20\", 1030, 1040, 10],\n",
+ " [991, \"17:13\", \"17:40\", 1033, 1060, 27],\n",
+ " [992, \"17:13\", \"18:00\", 1033, 1080, 47],\n",
+ " [993, \"17:14\", \"17:55\", 1034, 1075, 41],\n",
+ " [994, \"17:14\", \"18:40\", 1034, 1120, 86],\n",
+ " [995, \"17:15\", \"17:34\", 1035, 1054, 19],\n",
+ " [996, \"17:16\", \"17:28\", 1036, 1048, 12],\n",
+ " [997, \"17:18\", \"18:05\", 1038, 1085, 47],\n",
+ " [998, \"17:18\", \"18:05\", 1038, 1085, 47],\n",
+ " [999, \"17:18\", \"18:44\", 1038, 1124, 86],\n",
+ " [1000, \"17:19\", \"18:31\", 1039, 1111, 72],\n",
+ " [1001, \"17:19\", \"18:13\", 1039, 1093, 54],\n",
+ " [1002, \"17:20\", \"17:36\", 1040, 1056, 16],\n",
+ " [1003, \"17:20\", \"17:30\", 1040, 1050, 10],\n",
+ " [1004, \"17:21\", \"17:47\", 1041, 1067, 26],\n",
+ " [1005, \"17:22\", \"18:06\", 1042, 1086, 44],\n",
+ " [1006, \"17:23\", \"18:10\", 1043, 1090, 47],\n",
+ " [1007, \"17:24\", \"18:50\", 1044, 1130, 86],\n",
+ " [1008, \"17:24\", \"18:05\", 1044, 1085, 41],\n",
+ " [1009, \"17:25\", \"17:44\", 1045, 1064, 19],\n",
+ " [1010, \"17:28\", \"17:55\", 1048, 1075, 27],\n",
+ " [1011, \"17:28\", \"18:15\", 1048, 1095, 47],\n",
+ " [1012, \"17:28\", \"18:15\", 1048, 1095, 47],\n",
+ " [1013, \"17:28\", \"18:54\", 1048, 1134, 86],\n",
+ " [1014, \"17:29\", \"18:41\", 1049, 1121, 72],\n",
+ " [1015, \"17:29\", \"18:23\", 1049, 1103, 54],\n",
+ " [1016, \"17:30\", \"17:40\", 1050, 1060, 10],\n",
+ " [1017, \"17:31\", \"17:43\", 1051, 1063, 12],\n",
+ " [1018, \"17:33\", \"18:20\", 1053, 1100, 47],\n",
+ " [1019, \"17:34\", \"18:15\", 1054, 1095, 41],\n",
+ " [1020, \"17:34\", \"19:00\", 1054, 1140, 86],\n",
+ " [1021, \"17:35\", \"17:54\", 1055, 1074, 19],\n",
+ " [1022, \"17:36\", \"18:21\", 1056, 1101, 45],\n",
+ " [1023, \"17:38\", \"18:25\", 1058, 1105, 47],\n",
+ " [1024, \"17:38\", \"19:04\", 1058, 1144, 86],\n",
+ " [1025, \"17:38\", \"18:25\", 1058, 1105, 47],\n",
+ " [1026, \"17:39\", \"18:51\", 1059, 1131, 72],\n",
+ " [1027, \"17:39\", \"18:33\", 1059, 1113, 54],\n",
+ " [1028, \"17:40\", \"17:56\", 1060, 1076, 16],\n",
+ " [1029, \"17:40\", \"17:50\", 1060, 1070, 10],\n",
+ " [1030, \"17:43\", \"18:10\", 1063, 1090, 27],\n",
+ " [1031, \"17:43\", \"18:30\", 1063, 1110, 47],\n",
+ " [1032, \"17:44\", \"18:25\", 1064, 1105, 41],\n",
+ " [1033, \"17:44\", \"19:14\", 1064, 1154, 90],\n",
+ " [1034, \"17:45\", \"18:04\", 1065, 1084, 19],\n",
+ " [1035, \"17:46\", \"17:58\", 1066, 1078, 12],\n",
+ " [1036, \"17:48\", \"18:35\", 1068, 1115, 47],\n",
+ " [1037, \"17:48\", \"18:35\", 1068, 1115, 47],\n",
+ " [1038, \"17:48\", \"19:14\", 1068, 1154, 86],\n",
+ " [1039, \"17:49\", \"19:01\", 1069, 1141, 72],\n",
+ " [1040, \"17:49\", \"18:43\", 1069, 1123, 54],\n",
+ " [1041, \"17:50\", \"18:00\", 1070, 1080, 10],\n",
+ " [1042, \"17:51\", \"18:17\", 1071, 1097, 26],\n",
+ " [1043, \"17:52\", \"18:36\", 1072, 1116, 44],\n",
+ " [1044, \"17:53\", \"18:40\", 1073, 1120, 47],\n",
+ " [1045, \"17:54\", \"18:35\", 1074, 1115, 41],\n",
+ " [1046, \"17:54\", \"18:57\", 1074, 1137, 63],\n",
+ " [1047, \"17:55\", \"18:14\", 1075, 1094, 19],\n",
+ " [1048, \"17:58\", \"18:45\", 1078, 1125, 47],\n",
+ " [1049, \"17:58\", \"18:45\", 1078, 1125, 47],\n",
+ " [1050, \"17:58\", \"18:25\", 1078, 1105, 27],\n",
+ " [1051, \"17:58\", \"19:26\", 1078, 1166, 88],\n",
+ " [1052, \"17:59\", \"18:53\", 1079, 1133, 54],\n",
+ " [1053, \"18:00\", \"19:11\", 1080, 1151, 71],\n",
+ " [1054, \"18:00\", \"18:10\", 1080, 1090, 10],\n",
+ " [1055, \"18:00\", \"18:16\", 1080, 1096, 16],\n",
+ " [1056, \"18:01\", \"18:13\", 1081, 1093, 12],\n",
+ " [1057, \"18:03\", \"18:50\", 1083, 1130, 47],\n",
+ " [1058, \"18:04\", \"18:45\", 1084, 1125, 41],\n",
+ " [1059, \"18:04\", \"19:29\", 1084, 1169, 85],\n",
+ " [1060, \"18:05\", \"18:24\", 1085, 1104, 19],\n",
+ " [1061, \"18:06\", \"18:51\", 1086, 1131, 45],\n",
+ " [1062, \"18:08\", \"18:55\", 1088, 1135, 47],\n",
+ " [1063, \"18:08\", \"19:06\", 1088, 1146, 58],\n",
+ " [1064, \"18:08\", \"18:55\", 1088, 1135, 47],\n",
+ " [1065, \"18:09\", \"19:03\", 1089, 1143, 54],\n",
+ " [1066, \"18:10\", \"18:20\", 1090, 1100, 10],\n",
+ " [1067, \"18:10\", \"19:21\", 1090, 1161, 71],\n",
+ " [1068, \"18:13\", \"19:00\", 1093, 1140, 47],\n",
+ " [1069, \"18:13\", \"18:40\", 1093, 1120, 27],\n",
+ " [1070, \"18:14\", \"19:43\", 1094, 1183, 89],\n",
+ " [1071, \"18:14\", \"18:55\", 1094, 1135, 41],\n",
+ " [1072, \"18:15\", \"18:34\", 1095, 1114, 19],\n",
+ " [1073, \"18:16\", \"18:28\", 1096, 1108, 12],\n",
+ " [1074, \"18:17\", \"18:27\", 1097, 1107, 10],\n",
+ " [1075, \"18:18\", \"19:41\", 1098, 1181, 83],\n",
+ " [1076, \"18:18\", \"18:58\", 1098, 1138, 40],\n",
+ " [1077, \"18:18\", \"19:05\", 1098, 1145, 47],\n",
+ " [1078, \"18:19\", \"19:13\", 1099, 1153, 54],\n",
+ " [1079, \"18:20\", \"19:31\", 1100, 1171, 71],\n",
+ " [1080, \"18:20\", \"18:36\", 1100, 1116, 16],\n",
+ " [1081, \"18:20\", \"18:30\", 1100, 1110, 10],\n",
+ " [1082, \"18:22\", \"19:05\", 1102, 1145, 43],\n",
+ " [1083, \"18:23\", \"19:05\", 1103, 1145, 42],\n",
+ " [1084, \"18:24\", \"19:27\", 1104, 1167, 63],\n",
+ " [1085, \"18:24\", \"19:05\", 1104, 1145, 41],\n",
+ " [1086, \"18:25\", \"18:44\", 1105, 1124, 19],\n",
+ " [1087, \"18:28\", \"19:25\", 1108, 1165, 57],\n",
+ " [1088, \"18:28\", \"18:55\", 1108, 1135, 27],\n",
+ " [1089, \"18:28\", \"19:08\", 1108, 1148, 40],\n",
+ " [1090, \"18:28\", \"19:15\", 1108, 1155, 47],\n",
+ " [1091, \"18:29\", \"19:23\", 1109, 1163, 54],\n",
+ " [1092, \"18:30\", \"19:05\", 1110, 1145, 35],\n",
+ " [1093, \"18:30\", \"18:40\", 1110, 1120, 10],\n",
+ " [1094, \"18:31\", \"18:43\", 1111, 1123, 12],\n",
+ " [1095, \"18:33\", \"19:15\", 1113, 1155, 42],\n",
+ " [1096, \"18:34\", \"19:58\", 1114, 1198, 84],\n",
+ " [1097, \"18:34\", \"19:14\", 1114, 1154, 40],\n",
+ " [1098, \"18:35\", \"18:55\", 1115, 1135, 20],\n",
+ " [1099, \"18:36\", \"19:20\", 1116, 1160, 44],\n",
+ " [1100, \"18:38\", \"19:25\", 1118, 1165, 47],\n",
+ " [1101, \"18:38\", \"19:23\", 1118, 1163, 45],\n",
+ " [1102, \"18:38\", \"19:56\", 1118, 1196, 78],\n",
+ " [1103, \"18:39\", \"19:33\", 1119, 1173, 54],\n",
+ " [1104, \"18:40\", \"18:50\", 1120, 1130, 10],\n",
+ " [1105, \"18:40\", \"19:45\", 1120, 1185, 65],\n",
+ " [1106, \"18:40\", \"18:56\", 1120, 1136, 16],\n",
+ " [1107, \"18:43\", \"19:10\", 1123, 1150, 27],\n",
+ " [1108, \"18:43\", \"19:30\", 1123, 1170, 47],\n",
+ " [1109, \"18:44\", \"19:24\", 1124, 1164, 40],\n",
+ " [1110, \"18:45\", \"19:05\", 1125, 1145, 20],\n",
+ " [1111, \"18:46\", \"18:58\", 1126, 1138, 12],\n",
+ " [1112, \"18:48\", \"19:35\", 1128, 1175, 47],\n",
+ " [1113, \"18:48\", \"20:12\", 1128, 1212, 84],\n",
+ " [1114, \"18:48\", \"20:11\", 1128, 1211, 83],\n",
+ " [1115, \"18:48\", \"19:28\", 1128, 1168, 40],\n",
+ " [1116, \"18:49\", \"19:43\", 1129, 1183, 54],\n",
+ " [1117, \"18:50\", \"19:00\", 1130, 1140, 10],\n",
+ " [1118, \"18:51\", \"19:01\", 1131, 1141, 10],\n",
+ " [1119, \"18:53\", \"19:35\", 1133, 1175, 42],\n",
+ " [1120, \"18:53\", \"19:15\", 1133, 1155, 22],\n",
+ " [1121, \"18:53\", \"20:00\", 1133, 1200, 67],\n",
+ " [1122, \"18:55\", \"19:15\", 1135, 1155, 20],\n",
+ " [1123, \"18:55\", \"19:34\", 1135, 1174, 39],\n",
+ " [1124, \"18:58\", \"19:38\", 1138, 1178, 40],\n",
+ " [1125, \"18:59\", \"19:53\", 1139, 1193, 54],\n",
+ " [1126, \"18:59\", \"19:50\", 1139, 1190, 51],\n",
+ " [1127, \"18:59\", \"19:53\", 1139, 1193, 54],\n",
+ " [1128, \"19:00\", \"19:16\", 1140, 1156, 16],\n",
+ " [1129, \"19:00\", \"19:10\", 1140, 1150, 10],\n",
+ " [1130, \"19:00\", \"19:16\", 1140, 1156, 16],\n",
+ " [1131, \"19:01\", \"19:13\", 1141, 1153, 12],\n",
+ " [1132, \"19:03\", \"20:26\", 1143, 1226, 83],\n",
+ " [1133, \"19:03\", \"19:45\", 1143, 1185, 42],\n",
+ " [1134, \"19:05\", \"19:44\", 1145, 1184, 39],\n",
+ " [1135, \"19:05\", \"19:25\", 1145, 1165, 20],\n",
+ " [1136, \"19:08\", \"20:15\", 1148, 1215, 67],\n",
+ " [1137, \"19:08\", \"19:35\", 1148, 1175, 27],\n",
+ " [1138, \"19:09\", \"19:49\", 1149, 1189, 40],\n",
+ " [1139, \"19:09\", \"20:03\", 1149, 1203, 54],\n",
+ " [1140, \"19:10\", \"19:20\", 1150, 1160, 10],\n",
+ " [1141, \"19:10\", \"19:20\", 1150, 1160, 10],\n",
+ " [1142, \"19:11\", \"19:53\", 1151, 1193, 42],\n",
+ " [1143, \"19:14\", \"20:26\", 1154, 1226, 72],\n",
+ " [1144, \"19:14\", \"19:35\", 1154, 1175, 21],\n",
+ " [1145, \"19:14\", \"19:24\", 1154, 1164, 10],\n",
+ " [1146, \"19:14\", \"20:05\", 1154, 1205, 51],\n",
+ " [1147, \"19:15\", \"19:30\", 1155, 1170, 15],\n",
+ " [1148, \"19:15\", \"19:54\", 1155, 1194, 39],\n",
+ " [1149, \"19:18\", \"20:39\", 1158, 1239, 81],\n",
+ " [1150, \"19:18\", \"20:00\", 1158, 1200, 42],\n",
+ " [1151, \"19:19\", \"20:14\", 1159, 1214, 55],\n",
+ " [1152, \"19:20\", \"19:30\", 1160, 1170, 10],\n",
+ " [1153, \"19:20\", \"19:36\", 1160, 1176, 16],\n",
+ " [1154, \"19:21\", \"19:31\", 1161, 1171, 10],\n",
+ " [1155, \"19:23\", \"20:30\", 1163, 1230, 67],\n",
+ " [1156, \"19:23\", \"19:35\", 1163, 1175, 12],\n",
+ " [1157, \"19:24\", \"19:45\", 1164, 1185, 21],\n",
+ " [1158, \"19:24\", \"19:45\", 1164, 1185, 21],\n",
+ " [1159, \"19:25\", \"20:04\", 1165, 1204, 39],\n",
+ " [1160, \"19:26\", \"20:08\", 1166, 1208, 42],\n",
+ " [1161, \"19:29\", \"20:02\", 1169, 1202, 33],\n",
+ " [1162, \"19:29\", \"20:18\", 1169, 1218, 49],\n",
+ " [1163, \"19:29\", \"20:41\", 1169, 1241, 72],\n",
+ " [1164, \"19:30\", \"19:40\", 1170, 1180, 10],\n",
+ " [1165, \"19:33\", \"20:54\", 1173, 1254, 81],\n",
+ " [1166, \"19:33\", \"20:17\", 1173, 1217, 44],\n",
+ " [1167, \"19:34\", \"19:55\", 1174, 1195, 21],\n",
+ " [1168, \"19:35\", \"20:14\", 1175, 1214, 39],\n",
+ " [1169, \"19:38\", \"20:05\", 1178, 1205, 27],\n",
+ " [1170, \"19:38\", \"20:45\", 1178, 1245, 67],\n",
+ " [1171, \"19:39\", \"20:12\", 1179, 1212, 33],\n",
+ " [1172, \"19:40\", \"19:50\", 1180, 1190, 10],\n",
+ " [1173, \"19:40\", \"19:56\", 1180, 1196, 16],\n",
+ " [1174, \"19:41\", \"20:27\", 1181, 1227, 46],\n",
+ " [1175, \"19:43\", \"19:55\", 1183, 1195, 12],\n",
+ " [1176, \"19:44\", \"20:05\", 1184, 1205, 21],\n",
+ " [1177, \"19:44\", \"20:33\", 1184, 1233, 49],\n",
+ " [1178, \"19:44\", \"21:00\", 1184, 1260, 76],\n",
+ " [1179, \"19:45\", \"20:24\", 1185, 1224, 39],\n",
+ " [1180, \"19:48\", \"20:37\", 1188, 1237, 49],\n",
+ " [1181, \"19:48\", \"21:09\", 1188, 1269, 81],\n",
+ " [1182, \"19:50\", \"20:00\", 1190, 1200, 10],\n",
+ " [1183, \"19:52\", \"20:29\", 1192, 1229, 37],\n",
+ " [1184, \"19:53\", \"20:08\", 1193, 1208, 15],\n",
+ " [1185, \"19:53\", \"21:02\", 1193, 1262, 69],\n",
+ " [1186, \"19:53\", \"20:20\", 1193, 1220, 27],\n",
+ " [1187, \"19:54\", \"20:19\", 1194, 1219, 25],\n",
+ " [1188, \"19:55\", \"20:34\", 1195, 1234, 39],\n",
+ " [1189, \"19:56\", \"20:34\", 1196, 1234, 38],\n",
+ " [1190, \"19:59\", \"20:48\", 1199, 1248, 49],\n",
+ " [1191, \"19:59\", \"21:20\", 1199, 1280, 81],\n",
+ " [1192, \"20:00\", \"20:16\", 1200, 1216, 16],\n",
+ " [1193, \"20:00\", \"20:10\", 1200, 1210, 10],\n",
+ " [1194, \"20:03\", \"20:42\", 1203, 1242, 39],\n",
+ " [1195, \"20:03\", \"21:24\", 1203, 1284, 81],\n",
+ " [1196, \"20:04\", \"20:29\", 1204, 1229, 25],\n",
+ " [1197, \"20:05\", \"20:48\", 1205, 1248, 43],\n",
+ " [1198, \"20:07\", \"20:44\", 1207, 1244, 37],\n",
+ " [1199, \"20:08\", \"20:40\", 1208, 1240, 32],\n",
+ " [1200, \"20:08\", \"20:35\", 1208, 1235, 27],\n",
+ " [1201, \"20:10\", \"20:20\", 1210, 1220, 10],\n",
+ " [1202, \"20:10\", \"20:22\", 1210, 1222, 12],\n",
+ " [1203, \"20:11\", \"20:47\", 1211, 1247, 36],\n",
+ " [1204, \"20:14\", \"21:04\", 1214, 1264, 50],\n",
+ " [1205, \"20:14\", \"21:03\", 1214, 1263, 49],\n",
+ " [1206, \"20:17\", \"21:03\", 1217, 1263, 46],\n",
+ " [1207, \"20:18\", \"21:39\", 1218, 1299, 81],\n",
+ " [1208, \"20:20\", \"20:30\", 1220, 1230, 10],\n",
+ " [1209, \"20:20\", \"20:57\", 1220, 1257, 37],\n",
+ " [1210, \"20:20\", \"20:36\", 1220, 1236, 16],\n",
+ " [1211, \"20:22\", \"20:59\", 1222, 1259, 37],\n",
+ " [1212, \"20:22\", \"20:42\", 1222, 1242, 20],\n",
+ " [1213, \"20:24\", \"20:49\", 1224, 1249, 25],\n",
+ " [1214, \"20:27\", \"21:22\", 1227, 1282, 55],\n",
+ " [1215, \"20:29\", \"21:18\", 1229, 1278, 49],\n",
+ " [1216, \"20:30\", \"21:07\", 1230, 1267, 37],\n",
+ " [1217, \"20:30\", \"20:40\", 1230, 1240, 10],\n",
+ " [1218, \"20:30\", \"20:40\", 1230, 1240, 10],\n",
+ " [1219, \"20:30\", \"21:40\", 1230, 1300, 70],\n",
+ " [1220, \"20:32\", \"21:18\", 1232, 1278, 46],\n",
+ " [1221, \"20:35\", \"21:54\", 1235, 1314, 79],\n",
+ " [1222, \"20:37\", \"21:14\", 1237, 1274, 37],\n",
+ " [1223, \"20:38\", \"21:08\", 1238, 1268, 30],\n",
+ " [1224, \"20:40\", \"20:50\", 1240, 1250, 10],\n",
+ " [1225, \"20:40\", \"21:17\", 1240, 1277, 37],\n",
+ " [1226, \"20:40\", \"20:56\", 1240, 1256, 16],\n",
+ " [1227, \"20:44\", \"21:33\", 1244, 1293, 49],\n",
+ " [1228, \"20:47\", \"21:33\", 1247, 1293, 46],\n",
+ " [1229, \"20:47\", \"21:42\", 1247, 1302, 55],\n",
+ " [1230, \"20:50\", \"21:00\", 1250, 1260, 10],\n",
+ " [1231, \"20:50\", \"22:00\", 1250, 1320, 70],\n",
+ " [1232, \"20:50\", \"22:09\", 1250, 1329, 79],\n",
+ " [1233, \"20:50\", \"21:27\", 1250, 1287, 37],\n",
+ " [1234, \"20:52\", \"21:29\", 1252, 1289, 37],\n",
+ " [1235, \"20:53\", \"21:20\", 1253, 1280, 27],\n",
+ " [1236, \"20:56\", \"21:11\", 1256, 1271, 15],\n",
+ " [1237, \"20:59\", \"21:48\", 1259, 1308, 49],\n",
+ " [1238, \"21:00\", \"21:10\", 1260, 1270, 10],\n",
+ " [1239, \"21:00\", \"21:37\", 1260, 1297, 37],\n",
+ " [1240, \"21:02\", \"21:48\", 1262, 1308, 46],\n",
+ " [1241, \"21:05\", \"22:24\", 1265, 1344, 79],\n",
+ " [1242, \"21:07\", \"21:44\", 1267, 1304, 37],\n",
+ " [1243, \"21:07\", \"22:02\", 1267, 1322, 55],\n",
+ " [1244, \"21:08\", \"21:38\", 1268, 1298, 30],\n",
+ " [1245, \"21:10\", \"22:25\", 1270, 1345, 75],\n",
+ " [1246, \"21:10\", \"21:20\", 1270, 1280, 10],\n",
+ " [1247, \"21:10\", \"21:47\", 1270, 1307, 37],\n",
+ " [1248, \"21:14\", \"22:03\", 1274, 1323, 49],\n",
+ " [1249, \"21:17\", \"22:03\", 1277, 1323, 46],\n",
+ " [1250, \"21:20\", \"22:18\", 1280, 1338, 58],\n",
+ " [1251, \"21:20\", \"21:57\", 1280, 1317, 37],\n",
+ " [1252, \"21:20\", \"21:30\", 1280, 1290, 10],\n",
+ " [1253, \"21:22\", \"21:59\", 1282, 1319, 37],\n",
+ " [1254, \"21:24\", \"21:49\", 1284, 1309, 25],\n",
+ " [1255, \"21:27\", \"22:21\", 1287, 1341, 54],\n",
+ " [1256, \"21:30\", \"22:07\", 1290, 1327, 37],\n",
+ " [1257, \"21:30\", \"22:20\", 1290, 1340, 50],\n",
+ " [1258, \"21:30\", \"21:40\", 1290, 1300, 10],\n",
+ " [1259, \"21:32\", \"22:18\", 1292, 1338, 46],\n",
+ " [1260, \"21:32\", \"22:01\", 1292, 1321, 29],\n",
+ " [1261, \"21:35\", \"22:54\", 1295, 1374, 79],\n",
+ " [1262, \"21:37\", \"22:14\", 1297, 1334, 37],\n",
+ " [1263, \"21:39\", \"21:55\", 1299, 1315, 16],\n",
+ " [1264, \"21:40\", \"22:17\", 1300, 1337, 37],\n",
+ " [1265, \"21:40\", \"21:50\", 1300, 1310, 10],\n",
+ " [1266, \"21:41\", \"22:08\", 1301, 1328, 27],\n",
+ " [1267, \"21:47\", \"22:16\", 1307, 1336, 29],\n",
+ " [1268, \"21:47\", \"22:51\", 1307, 1371, 64],\n",
+ " [1269, \"21:47\", \"22:33\", 1307, 1353, 46],\n",
+ " [1270, \"21:48\", \"22:03\", 1308, 1323, 15],\n",
+ " [1271, \"21:50\", \"22:55\", 1310, 1375, 65],\n",
+ " [1272, \"21:50\", \"22:27\", 1310, 1347, 37],\n",
+ " [1273, \"21:50\", \"22:00\", 1310, 1320, 10],\n",
+ " [1274, \"21:52\", \"22:29\", 1312, 1349, 37],\n",
+ " [1275, \"21:53\", \"22:19\", 1313, 1339, 26],\n",
+ " [1276, \"22:00\", \"22:38\", 1320, 1358, 38],\n",
+ " [1277, \"22:00\", \"22:10\", 1320, 1330, 10],\n",
+ " [1278, \"22:02\", \"22:12\", 1322, 1332, 10],\n",
+ " [1279, \"22:02\", \"22:48\", 1322, 1368, 46],\n",
+ " [1280, \"22:04\", \"22:31\", 1324, 1351, 27],\n",
+ " [1281, \"22:05\", \"23:24\", 1325, 1404, 79],\n",
+ " [1282, \"22:07\", \"22:44\", 1327, 1364, 37],\n",
+ " [1283, \"22:07\", \"22:39\", 1327, 1359, 32],\n",
+ " [1284, \"22:09\", \"22:25\", 1329, 1345, 16],\n",
+ " [1285, \"22:10\", \"23:25\", 1330, 1405, 75],\n",
+ " [1286, \"22:13\", \"22:38\", 1333, 1358, 25],\n",
+ " [1287, \"22:13\", \"22:53\", 1333, 1373, 40],\n",
+ " [1288, \"22:17\", \"22:27\", 1337, 1347, 10],\n",
+ " [1289, \"22:17\", \"23:03\", 1337, 1383, 46],\n",
+ " [1290, \"22:19\", \"22:46\", 1339, 1366, 27],\n",
+ " [1291, \"22:22\", \"22:59\", 1342, 1379, 37],\n",
+ " [1292, \"22:24\", \"22:48\", 1344, 1368, 24],\n",
+ " [1293, \"22:27\", \"22:52\", 1347, 1372, 25],\n",
+ " [1294, \"22:27\", \"23:21\", 1347, 1401, 54],\n",
+ " [1295, \"22:28\", \"23:08\", 1348, 1388, 40],\n",
+ " [1296, \"22:30\", \"23:17\", 1350, 1397, 47],\n",
+ " [1297, \"22:32\", \"22:42\", 1352, 1362, 10],\n",
+ " [1298, \"22:32\", \"23:11\", 1352, 1391, 39],\n",
+ " [1299, \"22:34\", \"23:01\", 1354, 1381, 27],\n",
+ " [1300, \"22:35\", \"23:54\", 1355, 1434, 79],\n",
+ " [1301, \"22:37\", \"23:14\", 1357, 1394, 37],\n",
+ " [1302, \"22:43\", \"23:23\", 1363, 1403, 40],\n",
+ " [1303, \"22:43\", \"23:08\", 1363, 1388, 25],\n",
+ " [1304, \"22:47\", \"23:33\", 1367, 1413, 46],\n",
+ " [1305, \"22:47\", \"22:57\", 1367, 1377, 10],\n",
+ " [1306, \"22:49\", \"23:16\", 1369, 1396, 27],\n",
+ " [1307, \"22:52\", \"23:29\", 1372, 1409, 37],\n",
+ " [1308, \"22:53\", \"23:15\", 1373, 1395, 22],\n",
+ " [1309, \"22:55\", \"23:55\", 1375, 1435, 60],\n",
+ " [1310, \"22:57\", \"23:51\", 1377, 1431, 54],\n",
+ " [1311, \"22:58\", \"23:38\", 1378, 1418, 40],\n",
+ " [1312, \"23:02\", \"23:41\", 1382, 1421, 39],\n",
+ " [1313, \"23:02\", \"23:12\", 1382, 1392, 10],\n",
+ " [1314, \"23:04\", \"23:31\", 1384, 1411, 27],\n",
+ " [1315, \"23:05\", \"00:24\", 1385, 1464, 79],\n",
+ " [1316, \"23:07\", \"23:44\", 1387, 1424, 37],\n",
+ " [1317, \"23:13\", \"23:53\", 1393, 1433, 40],\n",
+ " [1318, \"23:13\", \"23:38\", 1393, 1418, 25],\n",
+ " [1319, \"23:17\", \"00:03\", 1397, 1443, 46],\n",
+ " [1320, \"23:17\", \"23:27\", 1397, 1407, 10],\n",
+ " [1321, \"23:19\", \"23:46\", 1399, 1426, 27],\n",
+ " [1322, \"23:22\", \"23:59\", 1402, 1439, 37],\n",
+ " [1323, \"23:25\", \"00:25\", 1405, 1465, 60],\n",
+ " [1324, \"23:27\", \"00:21\", 1407, 1461, 54],\n",
+ " [1325, \"23:28\", \"00:08\", 1408, 1448, 40],\n",
+ " [1326, \"23:32\", \"23:42\", 1412, 1422, 10],\n",
+ " [1327, \"23:34\", \"00:01\", 1414, 1441, 27],\n",
+ " [1328, \"23:35\", \"01:05\", 1415, 1505, 90],\n",
+ " [1329, \"23:37\", \"00:09\", 1417, 1449, 32],\n",
+ " [1330, \"23:43\", \"00:23\", 1423, 1463, 40],\n",
+ " [1331, \"23:43\", \"00:08\", 1423, 1448, 25],\n",
+ " [1332, \"23:46\", \"00:01\", 1426, 1441, 15],\n",
+ " [1333, \"23:47\", \"23:57\", 1427, 1437, 10],\n",
+ " [1334, \"23:47\", \"00:33\", 1427, 1473, 46],\n",
+ " [1335, \"23:52\", \"00:24\", 1432, 1464, 32],\n",
+ " [1336, \"23:55\", \"00:49\", 1435, 1489, 54],\n",
+ " [1337, \"23:57\", \"00:57\", 1437, 1497, 60],\n",
+ " [1338, \"23:58\", \"00:38\", 1438, 1478, 40],\n",
+ " [1339, \"00:02\", \"00:12\", 1442, 1452, 10],\n",
+ " [1340, \"00:07\", \"00:39\", 1447, 1479, 32],\n",
+ " [1341, \"00:13\", \"00:38\", 1453, 1478, 25],\n",
+ " [1342, \"00:13\", \"00:51\", 1453, 1491, 38],\n",
+ " [1343, \"00:15\", \"01:14\", 1455, 1514, 59],\n",
+ " [1344, \"00:17\", \"01:23\", 1457, 1523, 66],\n",
+ " [1345, \"00:23\", \"00:33\", 1463, 1473, 10],\n",
+ " [1346, \"00:24\", \"00:40\", 1464, 1480, 16],\n",
+ " [1347, \"00:25\", \"01:12\", 1465, 1512, 47],\n",
+ " [1348, \"00:28\", \"01:07\", 1468, 1507, 39],\n",
+ " [1349, \"00:33\", \"01:05\", 1473, 1505, 32],\n",
+ " [1350, \"00:43\", \"01:21\", 1483, 1521, 38],\n",
+ " [1351, \"00:44\", \"00:54\", 1484, 1494, 10],\n",
+ " [1352, \"00:47\", \"01:09\", 1487, 1509, 22],\n",
+ " [1353, \"00:47\", \"01:26\", 1487, 1526, 39],\n",
+ " [1354, \"00:54\", \"01:04\", 1494, 1504, 10],\n",
+ " [1355, \"00:57\", \"01:07\", 1497, 1507, 10],\n",
"] # yapf:disable\n",
"\n",
"\n",
@@ -1750,17 +1749,16 @@
"\n",
" # Computed data.\n",
" total_driving_time = sum(shift[5] for shift in shifts)\n",
- " min_num_drivers = int(\n",
- " math.ceil(total_driving_time * 1.0 / max_driving_time))\n",
+ " min_num_drivers = int(math.ceil(total_driving_time * 1.0 / max_driving_time))\n",
" min_start_time = min(shift[3] for shift in shifts)\n",
" max_end_time = max(shift[4] for shift in shifts)\n",
"\n",
- " print('Bus driver scheduling')\n",
- " print(' num shifts =', num_shifts)\n",
- " print(' total driving time =', total_driving_time, 'minutes')\n",
- " print(' min num drivers =', min_num_drivers)\n",
- " print(' min start time =', min_start_time)\n",
- " print(' max end time =', max_end_time)\n",
+ " print(\"Bus driver scheduling\")\n",
+ " print(\" num shifts =\", num_shifts)\n",
+ " print(\" total driving time =\", total_driving_time, \"minutes\")\n",
+ " print(\" min num drivers =\", min_num_drivers)\n",
+ " print(\" min start time =\", min_start_time)\n",
+ " print(\" max end time =\", max_end_time)\n",
"\n",
" # We are going to build a flow from a the start of the day to the end\n",
" # of the day.\n",
@@ -1785,11 +1783,11 @@
" # Create all the shift variables before iterating on the transitions\n",
" # between these shifts.\n",
" for shift in range(num_shifts):\n",
- " driving_time[shift] = model.NewIntVar(0, max_driving_time, 'dt_%i' % shift)\n",
+ " driving_time[shift] = model.NewIntVar(0, max_driving_time, \"dt_%i\" % shift)\n",
" no_break_driving_time[shift] = model.NewIntVar(\n",
- " 0, max_driving_time_without_pauses, 'nbdt_%i' % shift)\n",
- " working_time[shift] = model.NewIntVar(\n",
- " 0, max_working_time, 'wt_%i' % shift)\n",
+ " 0, max_driving_time_without_pauses, \"nbdt_%i\" % shift\n",
+ " )\n",
+ " working_time[shift] = model.NewIntVar(0, max_working_time, \"wt_%i\" % shift)\n",
"\n",
" for shift in range(num_shifts):\n",
" duration = shifts[shift][5]\n",
@@ -1797,19 +1795,19 @@
" # Arc from source to shift.\n",
" # - set the working time of the driver\n",
" # - increase driving time and driving time since the last break\n",
- " source_lit = model.NewBoolVar('from source to %i' % shift)\n",
+ " source_lit = model.NewBoolVar(\"from source to %i\" % shift)\n",
" all_literals.append(source_lit)\n",
" outgoing_source_literals.append(source_lit)\n",
" incoming_literals[shift].append(source_lit)\n",
" model.Add(driving_time[shift] == duration).OnlyEnforceIf(source_lit)\n",
- " model.Add(no_break_driving_time[shift] == duration).OnlyEnforceIf(\n",
- " source_lit)\n",
+ " model.Add(no_break_driving_time[shift] == duration).OnlyEnforceIf(source_lit)\n",
" model.Add(working_time[shift] == duration + extra_time).OnlyEnforceIf(\n",
- " source_lit)\n",
+ " source_lit\n",
+ " )\n",
"\n",
" # Arc from shift to sink\n",
" # - checks that working time is greater than min_working_time\n",
- " sink_lit = model.NewBoolVar('from %i to sink' % shift)\n",
+ " sink_lit = model.NewBoolVar(\"from %i to sink\" % shift)\n",
" all_literals.append(sink_lit)\n",
" outgoing_literals[shift].append(sink_lit)\n",
" incoming_sink_literals.append(sink_lit)\n",
@@ -1822,25 +1820,29 @@
" if delay > max_break:\n",
" break # Assumes start times are sorted.\n",
" other_duration = shifts[other][5]\n",
- " lit = model.NewBoolVar('from %i to %i' % (shift, other))\n",
+ " lit = model.NewBoolVar(\"from %i to %i\" % (shift, other))\n",
" all_literals.append(lit)\n",
"\n",
" # Increase driving time\n",
- " model.Add(driving_time[other] ==\n",
- " driving_time[shift] + other_duration).OnlyEnforceIf(lit)\n",
+ " model.Add(\n",
+ " driving_time[other] == driving_time[shift] + other_duration\n",
+ " ).OnlyEnforceIf(lit)\n",
"\n",
" # Increase no_break_driving or reset it to 0 depending on the delay\n",
" if delay >= min_pause_after_4h:\n",
- " model.Add(no_break_driving_time[other] ==\n",
- " other_duration).OnlyEnforceIf(lit)\n",
+ " model.Add(no_break_driving_time[other] == other_duration).OnlyEnforceIf(\n",
+ " lit\n",
+ " )\n",
" else:\n",
" model.Add(\n",
- " no_break_driving_time[other] ==\n",
- " no_break_driving_time[shift] + other_duration).OnlyEnforceIf(lit)\n",
+ " no_break_driving_time[other]\n",
+ " == no_break_driving_time[shift] + other_duration\n",
+ " ).OnlyEnforceIf(lit)\n",
"\n",
" # Increase working time\n",
- " model.Add(working_time[other] == working_time[shift] + delay +\n",
- " other_duration).OnlyEnforceIf(lit)\n",
+ " model.Add(\n",
+ " working_time[other] == working_time[shift] + delay + other_duration\n",
+ " ).OnlyEnforceIf(lit)\n",
"\n",
" # Add arc\n",
" outgoing_literals[shift].append(lit)\n",
@@ -1852,16 +1854,16 @@
" model.Add(sum(incoming_literals[shift]) == 1)\n",
"\n",
" # Num drivers\n",
- " num_drivers = model.NewIntVar(min_num_drivers, min_num_drivers * 3, 'num_drivers')\n",
+ " num_drivers = model.NewIntVar(min_num_drivers, min_num_drivers * 3, \"num_drivers\")\n",
" model.Add(sum(incoming_sink_literals) == num_drivers)\n",
" model.Add(sum(outgoing_source_literals) == num_drivers)\n",
"\n",
- " model.Minimize(num_drivers) \n",
+ " model.Minimize(num_drivers)\n",
"\n",
" # Solve model.\n",
" solver = cp_model.CpSolver()\n",
" solver.parameters.log_search_progress = True\n",
- " #solver.parameters.num_search_workers = 16\n",
+ " # solver.parameters.num_search_workers = 16\n",
" # solver.parameters.boolean_encoding_level = 0\n",
" # solver.parameters.lns_focus_on_decision_variables = True\n",
" status = solver.Solve(model)\n",
@@ -1871,13 +1873,13 @@
"\n",
" # Display solution\n",
" optimal_num_drivers = int(solver.ObjectiveValue())\n",
- " print('minimal number of drivers =', optimal_num_drivers)\n",
+ " print(\"minimal number of drivers =\", optimal_num_drivers)\n",
" return optimal_num_drivers\n",
"\n",
"\n",
"def main(args):\n",
" \"\"\"Optimize the bus driver allocation in two passes.\"\"\"\n",
- " print('----------- first pass: minimize the number of drivers')\n",
+ " print(\"----------- first pass: minimize the number of drivers\")\n",
" shifts = []\n",
" if args.instance == 1:\n",
" shifts = SAMPLE_SHIFTS_SMALL\n",
@@ -1887,8 +1889,8 @@
" shifts = SAMPLE_SHIFTS_LARGE\n",
" num_drivers = find_minimum_number_of_drivers(shifts, args.params)\n",
"\n",
- " print('----------- second pass: minimize the sum of working times')\n",
- " #bus_driver_scheduling(False, num_drivers)\n",
+ " print(\"----------- second pass: minimize the sum of working times\")\n",
+ " # bus_driver_scheduling(False, num_drivers)\n",
"\n",
"\n",
"main(PARSER.parse_args())\n",
diff --git a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb
index 8031e8d40e..bb04ad260c 100644
--- a/examples/notebook/examples/bus_driver_scheduling_sat.ipynb
+++ b/examples/notebook/examples/bus_driver_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/chemical_balance_lp.ipynb b/examples/notebook/examples/chemical_balance_lp.ipynb
index 61cf55e97d..2e0538ecbe 100644
--- a/examples/notebook/examples/chemical_balance_lp.ipynb
+++ b/examples/notebook/examples/chemical_balance_lp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/chemical_balance_sat.ipynb b/examples/notebook/examples/chemical_balance_sat.ipynb
index f456b3b679..4cc19e2a37 100644
--- a/examples/notebook/examples/chemical_balance_sat.ipynb
+++ b/examples/notebook/examples/chemical_balance_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -157,24 +157,24 @@
" # Creates a solver and solves.\n",
" solver = cp_model.CpSolver()\n",
" status = solver.solve(model)\n",
- " print(f\"Status = {solver.status_name(status)}\")\n",
- " # The objective value of the solution.\n",
- " print(f\"Optimal objective value = {solver.objective_value / 10000.0}\")\n",
+ " if status == cp_model.OPTIMAL:\n",
+ " # The objective value of the solution.\n",
+ " print(f\"Optimal objective value = {solver.objective_value / 10000.0}\")\n",
"\n",
- " for s in all_sets:\n",
- " print(\n",
- " f\" {chemical_set[s][0]} = {solver.value(set_vars[s]) / 1000.0}\",\n",
- " end=\" \",\n",
- " )\n",
- " print()\n",
- " for p in all_products:\n",
- " name = max_quantities[p][0]\n",
- " max_quantity = max_quantities[p][1]\n",
- " quantity = sum(\n",
- " solver.value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]\n",
- " for s in all_sets\n",
- " )\n",
- " print(f\"{name}: {quantity} out of {max_quantity}\")\n",
+ " for s in all_sets:\n",
+ " print(\n",
+ " f\" {chemical_set[s][0]} = {solver.value(set_vars[s]) / 1000.0}\",\n",
+ " end=\" \",\n",
+ " )\n",
+ " print()\n",
+ " for p in all_products:\n",
+ " name = max_quantities[p][0]\n",
+ " max_quantity = max_quantities[p][1]\n",
+ " quantity = sum(\n",
+ " solver.value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]\n",
+ " for s in all_sets\n",
+ " )\n",
+ " print(f\"{name}: {quantity:.3f} out of {max_quantity}\")\n",
"\n",
"\n",
"def main(argv: Sequence[str]) -> None:\n",
diff --git a/examples/notebook/examples/clustering_sat.ipynb b/examples/notebook/examples/clustering_sat.ipynb
index d355ed1387..18636b3f4f 100644
--- a/examples/notebook/examples/clustering_sat.ipynb
+++ b/examples/notebook/examples/clustering_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -133,7 +133,7 @@
"]\n",
"\n",
"\n",
- "def clustering_sat():\n",
+ "def clustering_sat() -> None:\n",
" \"\"\"Entry point of the program.\"\"\"\n",
" num_nodes = len(distance_matrix)\n",
" print(\"Num nodes =\", num_nodes)\n",
diff --git a/examples/notebook/examples/cover_rectangle_sat.ipynb b/examples/notebook/examples/cover_rectangle_sat.ipynb
index 2893b2a866..e98d7890b5 100644
--- a/examples/notebook/examples/cover_rectangle_sat.ipynb
+++ b/examples/notebook/examples/cover_rectangle_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/cryptarithm_sat.ipynb b/examples/notebook/examples/cryptarithm_sat.ipynb
index c217a0c410..a448898767 100644
--- a/examples/notebook/examples/cryptarithm_sat.ipynb
+++ b/examples/notebook/examples/cryptarithm_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -87,7 +87,7 @@
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
- "def send_more_money():\n",
+ "def send_more_money() -> None:\n",
" \"\"\"solve the cryptarithmic puzzle SEND+MORE=MONEY.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
@@ -142,7 +142,7 @@
" print(\"y:\", solver.value(y))\n",
"\n",
"\n",
- "def main(_):\n",
+ "def main(_) -> None:\n",
" send_more_money()\n",
"\n",
"\n",
diff --git a/examples/notebook/examples/cvrptw_plot.ipynb b/examples/notebook/examples/cvrptw_plot.ipynb
index 1ef4eec93b..4c4599c99f 100644
--- a/examples/notebook/examples/cvrptw_plot.ipynb
+++ b/examples/notebook/examples/cvrptw_plot.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/flexible_job_shop_sat.ipynb b/examples/notebook/examples/flexible_job_shop_sat.ipynb
index 5388b1facb..d76f41b56e 100644
--- a/examples/notebook/examples/flexible_job_shop_sat.ipynb
+++ b/examples/notebook/examples/flexible_job_shop_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -101,20 +101,20 @@
"class SolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
- " def __init__(self):\n",
+ " def __init__(self) -> None:\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
"\n",
- " def on_solution_callback(self):\n",
+ " def on_solution_callback(self) -> None:\n",
" \"\"\"Called at each new solution.\"\"\"\n",
" print(\n",
- " \"Solution %i, time = %f s, objective = %i\"\n",
- " % (self.__solution_count, self.wall_time, self.objective_value)\n",
+ " f\"Solution {self.__solution_count}, time = {self.wall_time} s,\"\n",
+ " f\" objective = {self.objective_value}\"\n",
" )\n",
" self.__solution_count += 1\n",
"\n",
"\n",
- "def flexible_jobshop():\n",
+ "def flexible_jobshop() -> None:\n",
" \"\"\"solve a small flexible jobshop problem.\"\"\"\n",
" # Data part.\n",
" jobs = [ # task = (processing_time, machine_id)\n",
@@ -152,13 +152,13 @@
" max_task_duration = max(max_task_duration, alternative[0])\n",
" horizon += max_task_duration\n",
"\n",
- " print(\"Horizon = %i\" % horizon)\n",
+ " print(f\"Horizon = {horizon}\")\n",
"\n",
" # Global storage of variables.\n",
" intervals_per_resources = collections.defaultdict(list)\n",
" starts = {} # indexed by (job_id, task_id).\n",
" presences = {} # indexed by (job_id, task_id, alt_id).\n",
- " job_ends = []\n",
+ " job_ends: list[cp_model.IntVar] = []\n",
"\n",
" # Scan the jobs and create the relevant variables and intervals.\n",
" for job_id in all_jobs:\n",
@@ -180,7 +180,7 @@
" max_duration = max(max_duration, alt_duration)\n",
"\n",
" # Create main interval for the task.\n",
- " suffix_name = \"_j%i_t%i\" % (job_id, task_id)\n",
+ " suffix_name = f\"_j{job_id}_t{task_id}\"\n",
" start = model.new_int_var(0, horizon, \"start\" + suffix_name)\n",
" duration = model.new_int_var(\n",
" min_duration, max_duration, \"duration\" + suffix_name\n",
@@ -202,7 +202,7 @@
" if num_alternatives > 1:\n",
" l_presences = []\n",
" for alt_id in all_alternatives:\n",
- " alt_suffix = \"_j%i_t%i_a%i\" % (job_id, task_id, alt_id)\n",
+ " alt_suffix = f\"_j{job_id}_t{task_id}_a{alt_id}\"\n",
" l_presence = model.new_bool_var(\"presence\" + alt_suffix)\n",
" l_start = model.new_int_var(0, horizon, \"start\" + alt_suffix)\n",
" l_duration = task[alt_id][0]\n",
@@ -229,7 +229,8 @@
" intervals_per_resources[task[0][1]].append(interval)\n",
" presences[(job_id, task_id, 0)] = model.new_constant(1)\n",
"\n",
- " job_ends.append(previous_end)\n",
+ " if previous_end is not None:\n",
+ " job_ends.append(previous_end)\n",
"\n",
" # Create machines constraints.\n",
" for machine_id in all_machines:\n",
@@ -248,29 +249,25 @@
" status = solver.solve(model, solution_printer)\n",
"\n",
" # Print final solution.\n",
- " for job_id in all_jobs:\n",
- " print(\"Job %i:\" % job_id)\n",
- " for task_id in range(len(jobs[job_id])):\n",
- " start_value = solver.value(starts[(job_id, task_id)])\n",
- " machine = -1\n",
- " duration = -1\n",
- " selected = -1\n",
- " for alt_id in range(len(jobs[job_id][task_id])):\n",
- " if solver.value(presences[(job_id, task_id, alt_id)]):\n",
- " duration = jobs[job_id][task_id][alt_id][0]\n",
- " machine = jobs[job_id][task_id][alt_id][1]\n",
- " selected = alt_id\n",
- " print(\n",
- " \" task_%i_%i starts at %i (alt %i, machine %i, duration %i)\"\n",
- " % (job_id, task_id, start_value, selected, machine, duration)\n",
- " )\n",
+ " if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
+ " print(f\"Optimal objective value: {solver.objective_value}\")\n",
+ " for job_id in all_jobs:\n",
+ " print(f\"Job {job_id}\")\n",
+ " for task_id, task in enumerate(jobs[job_id]):\n",
+ " start_value = solver.value(starts[(job_id, task_id)])\n",
+ " machine: int = -1\n",
+ " task_duration: int = -1\n",
+ " selected: int = -1\n",
+ " for alt_id, alt in enumerate(task):\n",
+ " if solver.boolean_value(presences[(job_id, task_id, alt_id)]):\n",
+ " task_duration, machine = alt\n",
+ " selected = alt_id\n",
+ " print(\n",
+ " f\" task_{job_id}_{task_id} starts at {start_value} (alt\"\n",
+ " f\" {selected}, machine {machine}, duration {task_duration})\"\n",
+ " )\n",
"\n",
- " print(\"solve status: %s\" % solver.status_name(status))\n",
- " print(\"Optimal objective value: %i\" % solver.objective_value)\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"flexible_jobshop()\n",
diff --git a/examples/notebook/examples/gate_scheduling_sat.ipynb b/examples/notebook/examples/gate_scheduling_sat.ipynb
index 44792eab75..985b8f9c6b 100644
--- a/examples/notebook/examples/gate_scheduling_sat.ipynb
+++ b/examples/notebook/examples/gate_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -96,7 +96,7 @@
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
- "def main(_):\n",
+ "def main(_) -> None:\n",
" \"\"\"Solves the gate scheduling problem.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
@@ -134,34 +134,34 @@
"\n",
" for i in all_jobs:\n",
" # Create main interval.\n",
- " start = model.new_int_var(0, horizon, \"start_%i\" % i)\n",
+ " start = model.new_int_var(0, horizon, f\"start_{i}\")\n",
" duration = jobs[i][0]\n",
- " end = model.new_int_var(0, horizon, \"end_%i\" % i)\n",
- " interval = model.new_interval_var(start, duration, end, \"interval_%i\" % i)\n",
+ " end = model.new_int_var(0, horizon, f\"end_{i}\")\n",
+ " interval = model.new_interval_var(start, duration, end, f\"interval_{i}\")\n",
" starts.append(start)\n",
" intervals.append(interval)\n",
" ends.append(end)\n",
" demands.append(jobs[i][1])\n",
"\n",
" # Create an optional copy of interval to be executed on machine 0.\n",
- " performed_on_m0 = model.new_bool_var(\"perform_%i_on_m0\" % i)\n",
+ " performed_on_m0 = model.new_bool_var(f\"perform_{i}_on_m0\")\n",
" performed.append(performed_on_m0)\n",
- " start0 = model.new_int_var(0, horizon, \"start_%i_on_m0\" % i)\n",
- " end0 = model.new_int_var(0, horizon, \"end_%i_on_m0\" % i)\n",
+ " start0 = model.new_int_var(0, horizon, f\"start_{i}_on_m0\")\n",
+ " end0 = model.new_int_var(0, horizon, f\"end_{i}_on_m0\")\n",
" interval0 = model.new_optional_interval_var(\n",
- " start0, duration, end0, performed_on_m0, \"interval_%i_on_m0\" % i\n",
+ " start0, duration, end0, performed_on_m0, f\"interval_{i}_on_m0\"\n",
" )\n",
" intervals0.append(interval0)\n",
"\n",
" # Create an optional copy of interval to be executed on machine 1.\n",
- " start1 = model.new_int_var(0, horizon, \"start_%i_on_m1\" % i)\n",
- " end1 = model.new_int_var(0, horizon, \"end_%i_on_m1\" % i)\n",
+ " start1 = model.new_int_var(0, horizon, f\"start_{i}_on_m1\")\n",
+ " end1 = model.new_int_var(0, horizon, f\"end_{i}_on_m1\")\n",
" interval1 = model.new_optional_interval_var(\n",
" start1,\n",
" duration,\n",
" end1,\n",
" ~performed_on_m0,\n",
- " \"interval_%i_on_m1\" % i,\n",
+ " f\"interval_{i}_on_m1\",\n",
" )\n",
" intervals1.append(interval1)\n",
"\n",
@@ -191,18 +191,24 @@
" # Output solution.\n",
" if visualization.RunFromIPython():\n",
" output = visualization.SvgWrapper(solver.objective_value, max_width, 40.0)\n",
- " output.AddTitle(\"Makespan = %i\" % solver.objective_value)\n",
+ " output.AddTitle(f\"Makespan = {solver.objective_value}\")\n",
" color_manager = visualization.ColorManager()\n",
" color_manager.SeedRandomColor(0)\n",
"\n",
" for i in all_jobs:\n",
" performed_machine = 1 - solver.value(performed[i])\n",
- " start = solver.value(starts[i])\n",
+ " start_of_task = solver.value(starts[i])\n",
" d_x = jobs[i][0]\n",
" d_y = jobs[i][1]\n",
" s_y = performed_machine * (max_width - d_y)\n",
" output.AddRectangle(\n",
- " start, s_y, d_x, d_y, color_manager.RandomColor(), \"black\", \"j%i\" % i\n",
+ " start_of_task,\n",
+ " s_y,\n",
+ " d_x,\n",
+ " d_y,\n",
+ " color_manager.RandomColor(),\n",
+ " \"black\",\n",
+ " f\"j{i}\",\n",
" )\n",
"\n",
" output.AddXScale()\n",
@@ -210,17 +216,15 @@
" output.Display()\n",
" else:\n",
" print(\"Solution\")\n",
- " print(\" - makespan = %i\" % solver.objective_value)\n",
+ " print(f\" - makespan = {solver.objective_value}\")\n",
" for i in all_jobs:\n",
" performed_machine = 1 - solver.value(performed[i])\n",
- " start = solver.value(starts[i])\n",
+ " start_of_task = solver.value(starts[i])\n",
" print(\n",
- " \" - Job %i starts at %i on machine %i\" % (i, start, performed_machine)\n",
+ " f\" - Job {i} starts at {start_of_task} on machine\"\n",
+ " f\" {performed_machine}\"\n",
" )\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"main()\n",
diff --git a/examples/notebook/examples/golomb8.ipynb b/examples/notebook/examples/golomb8.ipynb
index 6d05000633..0414ee36c5 100644
--- a/examples/notebook/examples/golomb8.ipynb
+++ b/examples/notebook/examples/golomb8.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -91,17 +91,14 @@
"metadata": {},
"outputs": [],
"source": [
- "from ortools.sat.colab import flags\n",
"from ortools.constraint_solver import pywrapcp\n",
"\n",
- "FLAGS = flags.FLAGS\n",
- "\n",
"# We disable the following warning because it is a false positive on constraints\n",
"# like: solver.Add(x == 0)\n",
"# pylint: disable=g-explicit-bool-comparison\n",
"\n",
"\n",
- "def main(_):\n",
+ "def main(_) -> None:\n",
" # Create the solver.\n",
" solver = pywrapcp.Solver(\"golomb ruler\")\n",
"\n",
diff --git a/examples/notebook/examples/golomb_sat.ipynb b/examples/notebook/examples/golomb_sat.ipynb
index d9d6c36f6c..cdd120961f 100644
--- a/examples/notebook/examples/golomb_sat.ipynb
+++ b/examples/notebook/examples/golomb_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -105,7 +105,7 @@
")\n",
"\n",
"\n",
- "def solve_golomb_ruler(order: int, params: str):\n",
+ "def solve_golomb_ruler(order: int, params: str) -> None:\n",
" \"\"\"Solve the Golomb ruler problem.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
@@ -143,18 +143,13 @@
" status = solver.solve(model, solution_printer)\n",
"\n",
" # Print solution.\n",
- " print(f\"status: {solver.status_name(status)}\")\n",
" if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" for idx, var in enumerate(marks):\n",
" print(f\"mark[{idx}]: {solver.value(var)}\")\n",
" intervals = [solver.value(diff) for diff in diffs]\n",
" intervals.sort()\n",
" print(f\"intervals: {intervals}\")\n",
- "\n",
- " print(\"Statistics:\")\n",
- " print(f\"- conflicts: {solver.num_conflicts}\")\n",
- " print(f\"- branches : {solver.num_branches}\")\n",
- " print(f\"- wall time: {solver.wall_time}s\\n\")\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"def main(argv: Sequence[str]) -> None:\n",
diff --git a/examples/notebook/examples/hidato_sat.ipynb b/examples/notebook/examples/hidato_sat.ipynb
index 70434bacb5..49640e66c3 100644
--- a/examples/notebook/examples/hidato_sat.ipynb
+++ b/examples/notebook/examples/hidato_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -142,7 +142,7 @@
" if game[i][j] == 0:\n",
" line += \" .\"\n",
" else:\n",
- " line += \"% 3s\" % game[i][j]\n",
+ " line += f\"{game[i][j]:3}\"\n",
" print(line)\n",
"\n",
"\n",
@@ -170,7 +170,7 @@
"\n",
" elif problem == 3:\n",
" # Problems from the book:\n",
- " # Gyora Bededek: \"Hidato: 2000 Pure Logic Puzzles\"\n",
+ " # Gyora Bededek: 'Hidato: 2000 Pure Logic Puzzles'\n",
" # Problem 1 (Practice)\n",
" puzzle = [\n",
" [0, 0, 20, 0, 0],\n",
@@ -215,7 +215,7 @@
" return puzzle\n",
"\n",
"\n",
- "def solve_hidato(puzzle: list[list[int]], index: int):\n",
+ "def solve_hidato(puzzle: list[list[int]], index: int) -> None:\n",
" \"\"\"solve the given hidato table.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
@@ -224,15 +224,15 @@
" c = len(puzzle[0])\n",
" if not visualization.RunFromIPython():\n",
" print(\"\")\n",
- " print(\"----- Solving problem %i -----\" % index)\n",
+ " print(f\"----- Solving problem {index} -----\")\n",
" print(\"\")\n",
- " print((\"Initial game (%i x %i)\" % (r, c)))\n",
+ " print(f\"Initial game ({r} x {c})\")\n",
" print_matrix(puzzle)\n",
"\n",
" #\n",
" # Declare variables.\n",
" #\n",
- " positions = [model.new_int_var(0, r * c - 1, \"p[%i]\" % i) for i in range(r * c)]\n",
+ " positions = [model.new_int_var(0, r * c - 1, f\"p[{i}]\") for i in range(r * c)]\n",
"\n",
" #\n",
" # Constraints.\n",
@@ -270,7 +270,7 @@
" color = \"white\" if puzzle[y][x] == 0 else \"lightgreen\"\n",
" output.AddRectangle(x, r - y - 1, 1, 1, color, \"black\", str(i + 1))\n",
"\n",
- " output.AddTitle(\"Puzzle %i solved in %f s\" % (index, solver.wall_time))\n",
+ " output.AddTitle(f\"Puzzle {index} solved in {solver.wall_time:.2f} s\")\n",
" output.Display()\n",
" else:\n",
" print_solution(\n",
@@ -278,10 +278,7 @@
" r,\n",
" c,\n",
" )\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"def main(_):\n",
diff --git a/examples/notebook/examples/integer_programming.ipynb b/examples/notebook/examples/integer_programming.ipynb
index c8519d2a82..3dd97a4aae 100644
--- a/examples/notebook/examples/integer_programming.ipynb
+++ b/examples/notebook/examples/integer_programming.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb b/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb
index 277650be7f..dc5ee45b5b 100644
--- a/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb
+++ b/examples/notebook/examples/jobshop_ft06_distance_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -105,7 +105,7 @@
" return abs(x - y)\n",
"\n",
"\n",
- "def jobshop_ft06_distance():\n",
+ "def jobshop_ft06_distance() -> None:\n",
" \"\"\"Solves the ft06 jobshop with distances between tasks.\"\"\"\n",
" # Creates the model.\n",
" model = cp_model.CpModel()\n",
@@ -142,11 +142,11 @@
" all_tasks = {}\n",
" for i in all_jobs:\n",
" for j in all_machines:\n",
- " start_var = model.new_int_var(0, horizon, \"start_%i_%i\" % (i, j))\n",
+ " start_var = model.new_int_var(0, horizon, f\"start_{i}_{j}\")\n",
" duration = durations[i][j]\n",
- " end_var = model.new_int_var(0, horizon, \"end_%i_%i\" % (i, j))\n",
+ " end_var = model.new_int_var(0, horizon, f\"end_{i}_{j}\")\n",
" interval_var = model.new_interval_var(\n",
- " start_var, duration, end_var, \"interval_%i_%i\" % (i, j)\n",
+ " start_var, duration, end_var, f\"interval_{i}_{j}\"\n",
" )\n",
" all_tasks[(i, j)] = task_type(\n",
" start=start_var, end=end_var, interval=interval_var\n",
@@ -170,16 +170,16 @@
" arcs = []\n",
" for j1 in range(len(job_intervals)):\n",
" # Initial arc from the dummy node (0) to a task.\n",
- " start_lit = model.new_bool_var(\"%i is first job\" % j1)\n",
+ " start_lit = model.new_bool_var(f\"{j1} is first job\")\n",
" arcs.append((0, j1 + 1, start_lit))\n",
" # Final arc from an arc to the dummy node.\n",
- " arcs.append((j1 + 1, 0, model.new_bool_var(\"%i is last job\" % j1)))\n",
+ " arcs.append((j1 + 1, 0, model.new_bool_var(f\"{j1} is last job\")))\n",
"\n",
" for j2 in range(len(job_intervals)):\n",
" if j1 == j2:\n",
" continue\n",
"\n",
- " lit = model.new_bool_var(\"%i follows %i\" % (j2, j1))\n",
+ " lit = model.new_bool_var(f\"{j2} follows {j1}\")\n",
" arcs.append((j1 + 1, j2 + 1, lit))\n",
"\n",
" # We add the reified precedence to link the literal with the\n",
@@ -209,7 +209,8 @@
"\n",
" # Output solution.\n",
" if status == cp_model.OPTIMAL:\n",
- " print(\"Optimal makespan: %i\" % solver.objective_value)\n",
+ " print(f\"Optimal makespan: {solver.objective_value}\")\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"jobshop_ft06_distance()\n",
diff --git a/examples/notebook/examples/jobshop_ft06_sat.ipynb b/examples/notebook/examples/jobshop_ft06_sat.ipynb
index ae6fc8fa35..792fd66ff5 100644
--- a/examples/notebook/examples/jobshop_ft06_sat.ipynb
+++ b/examples/notebook/examples/jobshop_ft06_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -135,11 +135,11 @@
" all_tasks = {}\n",
" for i in all_jobs:\n",
" for j in all_machines:\n",
- " start_var = model.new_int_var(0, horizon, \"start_%i_%i\" % (i, j))\n",
+ " start_var = model.new_int_var(0, horizon, f\"start_{i}_{j}\")\n",
" duration = durations[i][j]\n",
- " end_var = model.new_int_var(0, horizon, \"end_%i_%i\" % (i, j))\n",
+ " end_var = model.new_int_var(0, horizon, f\"end_{i}_{j}\")\n",
" interval_var = model.new_interval_var(\n",
- " start_var, duration, end_var, \"interval_%i_%i\" % (i, j)\n",
+ " start_var, duration, end_var, f\"interval_{i}_{j}\"\n",
" )\n",
" all_tasks[(i, j)] = task_type(\n",
" start=start_var, end=end_var, interval=interval_var\n",
@@ -182,7 +182,7 @@
" ]\n",
" visualization.DisplayJobshop(starts, durations, machines, \"FT06\")\n",
" else:\n",
- " print(\"Optimal makespan: %i\" % solver.objective_value)\n",
+ " print(f\"Optimal makespan: {solver.objective_value}\")\n",
"\n",
"\n",
"jobshop_ft06()\n",
diff --git a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb
index 7410dc9bbf..a40167ca52 100644
--- a/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb
+++ b/examples/notebook/examples/jobshop_with_maintenance_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -91,20 +91,20 @@
"class SolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
- " def __init__(self):\n",
+ " def __init__(self) -> None:\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
"\n",
- " def on_solution_callback(self):\n",
+ " def on_solution_callback(self) -> None:\n",
" \"\"\"Called at each new solution.\"\"\"\n",
" print(\n",
- " \"Solution %i, time = %f s, objective = %i\"\n",
- " % (self.__solution_count, self.wall_time, self.objective_value)\n",
+ " f\"Solution {self.__solution_count}, time = {self.wall_time} s,\"\n",
+ " f\" objective = {self.objective_value}\"\n",
" )\n",
" self.__solution_count += 1\n",
"\n",
"\n",
- "def jobshop_with_maintenance():\n",
+ "def jobshop_with_maintenance() -> None:\n",
" \"\"\"Solves a jobshop with maintenance on one machine.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
@@ -122,7 +122,7 @@
" horizon = sum(task[1] for job in jobs_data for task in job)\n",
"\n",
" # Named tuple to store information about created variables.\n",
- " task_type = collections.namedtuple(\"Task\", \"start end interval\")\n",
+ " task_type = collections.namedtuple(\"task_type\", \"start end interval\")\n",
" # Named tuple to manipulate solution information.\n",
" assigned_task_type = collections.namedtuple(\n",
" \"assigned_task_type\", \"start job index duration\"\n",
@@ -135,9 +135,8 @@
" for job_id, job in enumerate(jobs_data):\n",
" for entry in enumerate(job):\n",
" task_id, task = entry\n",
- " machine = task[0]\n",
- " duration = task[1]\n",
- " suffix = \"_%i_%i\" % (job_id, task_id)\n",
+ " machine, duration = task\n",
+ " suffix = f\"_{job_id}_{task_id}\"\n",
" start_var = model.new_int_var(0, horizon, \"start\" + suffix)\n",
" end_var = model.new_int_var(0, horizon, \"end\" + suffix)\n",
" interval_var = model.new_interval_var(\n",
@@ -200,15 +199,15 @@
" sol_line = \" \"\n",
"\n",
" for assigned_task in assigned_jobs[machine]:\n",
- " name = \"job_%i_%i\" % (assigned_task.job, assigned_task.index)\n",
+ " name = f\"job_{assigned_task.job}_{assigned_task.index}\"\n",
" # add spaces to output to align columns.\n",
- " sol_line_tasks += \"%-10s\" % name\n",
+ " sol_line_tasks += f\"{name:>10}\"\n",
" start = assigned_task.start\n",
" duration = assigned_task.duration\n",
"\n",
- " sol_tmp = \"[%i,%i]\" % (start, start + duration)\n",
+ " sol_tmp = f\"[{start}, {start + duration}]\"\n",
" # add spaces to output to align columns.\n",
- " sol_line += \"%-10s\" % sol_tmp\n",
+ " sol_line += f\"{sol_tmp:>10}\"\n",
"\n",
" sol_line += \"\\n\"\n",
" sol_line_tasks += \"\\n\"\n",
@@ -216,12 +215,9 @@
" output += sol_line\n",
"\n",
" # Finally print the solution found.\n",
- " print(\"Optimal Schedule Length: %i\" % solver.objective_value)\n",
+ " print(f\"Optimal Schedule Length: {solver.objective_value}\")\n",
" print(output)\n",
- " print(\"Statistics\")\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"def main(argv: Sequence[str]) -> None:\n",
diff --git a/examples/notebook/examples/knapsack_2d_sat.ipynb b/examples/notebook/examples/knapsack_2d_sat.ipynb
index b05a748ef8..09efe31498 100644
--- a/examples/notebook/examples/knapsack_2d_sat.ipynb
+++ b/examples/notebook/examples/knapsack_2d_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -139,7 +139,9 @@
" return (data, max_height, max_width)\n",
"\n",
"\n",
- "def solve_with_duplicate_items(data: pd.Series, max_height: int, max_width: int):\n",
+ "def solve_with_duplicate_items(\n",
+ " data: pd.Series, max_height: int, max_width: int\n",
+ ") -> None:\n",
" \"\"\"solve the problem by building 2 items (rotated or not) for each item.\"\"\"\n",
" # Derived data (expanded to individual items).\n",
" data_widths = data[\"width\"].to_numpy()\n",
@@ -230,7 +232,7 @@
" status = solver.solve(model)\n",
"\n",
" # Report solution.\n",
- " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n",
+ " if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" used = {i for i in range(num_items) if solver.boolean_value(is_used[i])}\n",
" data = pd.DataFrame(\n",
" {\n",
@@ -332,7 +334,7 @@
" status = solver.solve(model)\n",
"\n",
" # Report solution.\n",
- " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n",
+ " if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" used = {i for i in range(num_items) if solver.boolean_value(is_used[i])}\n",
" data = pd.DataFrame(\n",
" {\n",
@@ -453,7 +455,7 @@
" status = solver.solve(model)\n",
"\n",
" # Report solution.\n",
- " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n",
+ " if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" used = {i for i in range(num_items) if solver.boolean_value(is_used[i])}\n",
" data = pd.DataFrame(\n",
" {\n",
diff --git a/examples/notebook/examples/line_balancing_sat.ipynb b/examples/notebook/examples/line_balancing_sat.ipynb
index 07adcde4c2..07c2c82ab9 100644
--- a/examples/notebook/examples/line_balancing_sat.ipynb
+++ b/examples/notebook/examples/line_balancing_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -98,7 +98,7 @@
"source": [
"import collections\n",
"import re\n",
- "from typing import Sequence\n",
+ "from typing import Dict, Sequence\n",
"\n",
"from ortools.sat.colab import flags\n",
"from google.protobuf import text_format\n",
@@ -115,8 +115,8 @@
")\n",
"\n",
"\n",
- "class SectionInfo(object):\n",
- " \"\"\"Store model information for each section of the input file.\"\"\"\n",
+ "class SectionInfo:\n",
+ " \"\"\"Store problem information for each section of the input file.\"\"\"\n",
"\n",
" def __init__(self):\n",
" self.value = None\n",
@@ -134,44 +134,43 @@
" return \"SectionInfo()\"\n",
"\n",
"\n",
- "def read_model(filename):\n",
- " \"\"\"Reads a .alb file and returns the model.\"\"\"\n",
+ "def read_problem(filename: str) -> Dict[str, SectionInfo]:\n",
+ " \"\"\"Reads a .alb file and returns the problem.\"\"\"\n",
"\n",
" current_info = SectionInfo()\n",
"\n",
- " model = {}\n",
+ " problem: Dict[str, SectionInfo] = {}\n",
" with open(filename, \"r\") as input_file:\n",
- " print(f\"Reading model from '{filename}'\")\n",
- " section_name = \"\"\n",
+ " print(f\"Reading problem from '{filename}'\")\n",
"\n",
" for line in input_file:\n",
" stripped_line = line.strip()\n",
" if not stripped_line:\n",
" continue\n",
"\n",
- " match_section_def = re.match(r\"<([\\w\\s]+)>\", stripped_line)\n",
+ " match_section_def = re.fullmatch(r\"<([\\w\\s]+)>\", stripped_line)\n",
" if match_section_def:\n",
" section_name = match_section_def.group(1)\n",
" if section_name == \"end\":\n",
" continue\n",
"\n",
" current_info = SectionInfo()\n",
- " model[section_name] = current_info\n",
+ " problem[section_name] = current_info\n",
" continue\n",
"\n",
- " match_single_number = re.match(r\"^([0-9]+)$\", stripped_line)\n",
+ " match_single_number = re.fullmatch(r\"^([0-9]+)$\", stripped_line)\n",
" if match_single_number:\n",
" current_info.value = int(match_single_number.group(1))\n",
" continue\n",
"\n",
- " match_key_value = re.match(r\"^([0-9]+)\\s+([0-9]+)$\", stripped_line)\n",
+ " match_key_value = re.fullmatch(r\"^([0-9]+)\\s+([0-9]+)$\", stripped_line)\n",
" if match_key_value:\n",
" key = int(match_key_value.group(1))\n",
" value = int(match_key_value.group(2))\n",
" current_info.index_map[key] = value\n",
" continue\n",
"\n",
- " match_pair = re.match(r\"^([0-9]+),([0-9]+)$\", stripped_line)\n",
+ " match_pair = re.fullmatch(r\"^([0-9]+),([0-9]+)$\", stripped_line)\n",
" if match_pair:\n",
" left = int(match_pair.group(1))\n",
" right = int(match_pair.group(2))\n",
@@ -180,24 +179,26 @@
"\n",
" print(f\"Unrecognized line '{stripped_line}'\")\n",
"\n",
- " return model\n",
+ " return problem\n",
"\n",
"\n",
- "def print_stats(model):\n",
- " print(\"Model Statistics\")\n",
- " for key, value in model.items():\n",
+ "def print_stats(problem: Dict[str, SectionInfo]) -> None:\n",
+ " print(\"Problem Statistics\")\n",
+ " for key, value in problem.items():\n",
" print(f\" - {key}: {value}\")\n",
"\n",
"\n",
- "def solve_model_greedily(model):\n",
+ "def solve_problem_greedily(problem: Dict[str, SectionInfo]) -> Dict[int, int]:\n",
" \"\"\"Compute a greedy solution.\"\"\"\n",
" print(\"Solving using a Greedy heuristics\")\n",
"\n",
- " num_tasks = model[\"number of tasks\"].value\n",
+ " num_tasks = problem[\"number of tasks\"].value\n",
+ " if num_tasks is None:\n",
+ " return {}\n",
" all_tasks = range(1, num_tasks + 1) # Tasks are 1 based in the data.\n",
- " precedences = model[\"precedence relations\"].set_of_pairs\n",
- " durations = model[\"task times\"].index_map\n",
- " cycle_time = model[\"cycle time\"].value\n",
+ " precedences = problem[\"precedence relations\"].set_of_pairs\n",
+ " durations = problem[\"task times\"].index_map\n",
+ " cycle_time = problem[\"cycle time\"].value\n",
"\n",
" weights = collections.defaultdict(int)\n",
" successors = collections.defaultdict(list)\n",
@@ -210,7 +211,7 @@
" if after in candidates:\n",
" candidates.remove(after)\n",
"\n",
- " assignment = {}\n",
+ " assignment: Dict[int, int] = {}\n",
" current_pod = 0\n",
" residual_capacity = cycle_time\n",
"\n",
@@ -251,16 +252,20 @@
" return assignment\n",
"\n",
"\n",
- "def solve_boolean_model(model, hint):\n",
- " \"\"\"solve the given model.\"\"\"\n",
+ "def solve_problem_with_boolean_model(\n",
+ " problem: Dict[str, SectionInfo], hint: Dict[int, int]\n",
+ ") -> None:\n",
+ " \"\"\"solve the given problem.\"\"\"\n",
"\n",
" print(\"Solving using the Boolean model\")\n",
- " # Model data\n",
- " num_tasks = model[\"number of tasks\"].value\n",
- " all_tasks = range(1, num_tasks + 1) # Tasks are 1 based in the model.\n",
- " durations = model[\"task times\"].index_map\n",
- " precedences = model[\"precedence relations\"].set_of_pairs\n",
- " cycle_time = model[\"cycle time\"].value\n",
+ " # problem data\n",
+ " num_tasks = problem[\"number of tasks\"].value\n",
+ " if num_tasks is None:\n",
+ " return\n",
+ " all_tasks = range(1, num_tasks + 1) # Tasks are 1 based in the problem.\n",
+ " durations = problem[\"task times\"].index_map\n",
+ " precedences = problem[\"precedence relations\"].set_of_pairs\n",
+ " cycle_time = problem[\"cycle time\"].value\n",
"\n",
" num_pods = max(p for _, p in hint.items()) + 1 if hint else num_tasks - 1\n",
" all_pods = range(num_pods)\n",
@@ -340,16 +345,20 @@
" solver.solve(model)\n",
"\n",
"\n",
- "def solve_scheduling_model(model, hint):\n",
- " \"\"\"solve the given model using a cumutive model.\"\"\"\n",
+ "def solve_problem_with_scheduling_model(\n",
+ " problem: Dict[str, SectionInfo], hint: Dict[int, int]\n",
+ ") -> None:\n",
+ " \"\"\"solve the given problem using a cumulative model.\"\"\"\n",
"\n",
" print(\"Solving using the scheduling model\")\n",
- " # Model data\n",
- " num_tasks = model[\"number of tasks\"].value\n",
+ " # Problem data\n",
+ " num_tasks = problem[\"number of tasks\"].value\n",
+ " if num_tasks is None:\n",
+ " return\n",
" all_tasks = range(1, num_tasks + 1) # Tasks are 1 based in the data.\n",
- " durations = model[\"task times\"].index_map\n",
- " precedences = model[\"precedence relations\"].set_of_pairs\n",
- " cycle_time = model[\"cycle time\"].value\n",
+ " durations = problem[\"task times\"].index_map\n",
+ " precedences = problem[\"precedence relations\"].set_of_pairs\n",
+ " cycle_time = problem[\"cycle time\"].value\n",
"\n",
" num_pods = max(p for _, p in hint.items()) + 1 if hint else num_tasks\n",
"\n",
@@ -407,14 +416,14 @@
" if len(argv) > 1:\n",
" raise app.UsageError(\"Too many command-line arguments.\")\n",
"\n",
- " model = read_model(_INPUT.value)\n",
- " print_stats(model)\n",
- " greedy_solution = solve_model_greedily(model)\n",
+ " problem = read_problem(_INPUT.value)\n",
+ " print_stats(problem)\n",
+ " greedy_solution = solve_problem_greedily(problem)\n",
"\n",
" if _MODEL.value == \"boolean\":\n",
- " solve_boolean_model(model, greedy_solution)\n",
+ " solve_problem_with_boolean_model(problem, greedy_solution)\n",
" elif _MODEL.value == \"scheduling\":\n",
- " solve_scheduling_model(model, greedy_solution)\n",
+ " solve_problem_with_scheduling_model(problem, greedy_solution)\n",
"\n",
"\n",
"main()\n",
diff --git a/examples/notebook/examples/linear_assignment_api.ipynb b/examples/notebook/examples/linear_assignment_api.ipynb
index 55c1d39baa..093c87cf6f 100644
--- a/examples/notebook/examples/linear_assignment_api.ipynb
+++ b/examples/notebook/examples/linear_assignment_api.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/linear_programming.ipynb b/examples/notebook/examples/linear_programming.ipynb
index 553507ec07..ea83ff3c89 100644
--- a/examples/notebook/examples/linear_programming.ipynb
+++ b/examples/notebook/examples/linear_programming.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/magic_sequence_distribute.ipynb b/examples/notebook/examples/magic_sequence_distribute.ipynb
index ed8cd1d909..d3ec65460f 100644
--- a/examples/notebook/examples/magic_sequence_distribute.ipynb
+++ b/examples/notebook/examples/magic_sequence_distribute.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/maximize_combinations_sat.ipynb b/examples/notebook/examples/maximize_combinations_sat.ipynb
new file mode 100644
index 0000000000..a30e3d7166
--- /dev/null
+++ b/examples/notebook/examples/maximize_combinations_sat.ipynb
@@ -0,0 +1,149 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "google",
+ "metadata": {},
+ "source": [
+ "##### Copyright 2024 Google LLC."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "apache",
+ "metadata": {},
+ "source": [
+ "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ "you may not use this file except in compliance with the License.\n",
+ "You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ "Unless required by applicable law or agreed to in writing, software\n",
+ "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ "See the License for the specific language governing permissions and\n",
+ "limitations under the License.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "basename",
+ "metadata": {},
+ "source": [
+ "# maximize_combinations_sat"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "link",
+ "metadata": {},
+ "source": [
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "doc",
+ "metadata": {},
+ "source": [
+ "First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "install",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install ortools"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "description",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Maximize the number of valid combinations of Boolean variables.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "code",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from typing import Sequence\n",
+ "from ortools.sat.python import cp_model\n",
+ "\n",
+ "\n",
+ "def maximize_combinations_sat() -> None:\n",
+ " \"\"\"Maximize the number of valid combinations of Boolean variables.\"\"\"\n",
+ " model = cp_model.CpModel()\n",
+ " cards: list[cp_model.IntVar] = [\n",
+ " model.new_bool_var(\"card1\"),\n",
+ " model.new_bool_var(\"card2\"),\n",
+ " model.new_bool_var(\"card3\"),\n",
+ " model.new_bool_var(\"card4\"),\n",
+ " ]\n",
+ "\n",
+ " combos: list[list[cp_model.IntVar]] = [\n",
+ " [cards[0], cards[1]],\n",
+ " [cards[0], cards[2]],\n",
+ " [cards[1], cards[3]],\n",
+ " [cards[0], cards[2], cards[3]],\n",
+ " ]\n",
+ "\n",
+ " deck_size: int = 3\n",
+ " model.add(sum(cards) == deck_size)\n",
+ "\n",
+ " valid_combos: list[cp_model.IntVar] = []\n",
+ " for combination in combos:\n",
+ " is_valid = model.new_bool_var(\"\")\n",
+ "\n",
+ " # All true implies is_valid.\n",
+ " model.add_bool_and(is_valid).only_enforce_if(combination)\n",
+ "\n",
+ " # is_valid implies all true.\n",
+ " for literal in combination:\n",
+ " model.add_implication(is_valid, literal)\n",
+ " valid_combos.append(is_valid)\n",
+ "\n",
+ " model.maximize(sum(valid_combos))\n",
+ "\n",
+ " solver = cp_model.CpSolver()\n",
+ " solver.parameters.log_search_progress = True\n",
+ " status = solver.solve(model)\n",
+ "\n",
+ " if status == cp_model.OPTIMAL:\n",
+ " print(\n",
+ " \"chosen cards:\",\n",
+ " [card.name for card in cards if solver.boolean_value(card)],\n",
+ " )\n",
+ "\n",
+ "\n",
+ "def main(argv: Sequence[str]) -> None:\n",
+ " if len(argv) > 1:\n",
+ " raise app.UsageError(\"Too many command-line arguments.\")\n",
+ " maximize_combinations_sat()\n",
+ "\n",
+ "\n",
+ "main()\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/notebook/examples/maze_escape_sat.ipynb b/examples/notebook/examples/maze_escape_sat.ipynb
index cebacf631b..2ff03b9f05 100644
--- a/examples/notebook/examples/maze_escape_sat.ipynb
+++ b/examples/notebook/examples/maze_escape_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -89,7 +89,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from typing import Sequence\n",
+ "from typing import Dict, Sequence, Tuple\n",
"\n",
"from ortools.sat.colab import flags\n",
"from google.protobuf import text_format\n",
@@ -99,11 +99,25 @@
" \"output_proto\", \"\", \"Output file to write the cp_model proto to.\"\n",
")\n",
"_PARAMS = flags.define_string(\n",
- " \"params\", \"num_search_workers:8,log_search_progress:true\", \"Sat solver parameters.\"\n",
+ " \"params\",\n",
+ " \"num_search_workers:8,log_search_progress:true\",\n",
+ " \"Sat solver parameters.\",\n",
")\n",
"\n",
"\n",
- "def add_neighbor(size, x, y, z, dx, dy, dz, model, index_map, position_to_rank, arcs):\n",
+ "def add_neighbor(\n",
+ " size: int,\n",
+ " x: int,\n",
+ " y: int,\n",
+ " z: int,\n",
+ " dx: int,\n",
+ " dy: int,\n",
+ " dz: int,\n",
+ " model: cp_model.CpModel,\n",
+ " index_map: Dict[Tuple[int, int, int], int],\n",
+ " position_to_rank: Dict[Tuple[int, int, int], cp_model.IntVar],\n",
+ " arcs: list[Tuple[int, int, cp_model.LiteralT]],\n",
+ ") -> None:\n",
" \"\"\"Checks if the neighbor is valid, and adds it to the model.\"\"\"\n",
" if (\n",
" x + dx < 0\n",
@@ -123,7 +137,7 @@
" arcs.append((before_index, after_index, move_literal))\n",
"\n",
"\n",
- "def escape_the_maze(params, output_proto):\n",
+ "def escape_the_maze(params: str, output_proto: str) -> None:\n",
" \"\"\"Escapes the maze.\"\"\"\n",
" size = 4\n",
" boxes = [(0, 1, 0), (2, 0, 1), (1, 3, 1), (3, 1, 3)]\n",
@@ -157,7 +171,7 @@
"\n",
" # Circuit constraint: visit all blocks exactly once, and maintains the rank\n",
" # of each block.\n",
- " arcs = []\n",
+ " arcs: list[Tuple[int, int, cp_model.LiteralT]] = []\n",
" for x in range(size):\n",
" for y in range(size):\n",
" for z in range(size):\n",
@@ -211,8 +225,8 @@
" elif position == end:\n",
" msg += \" [end]\"\n",
" else:\n",
- " for b in range(len(boxes)):\n",
- " if position == boxes[b]:\n",
+ " for b, box in enumerate(boxes):\n",
+ " if position == box:\n",
" msg += f\" [boxes {b}]\"\n",
" path[rank] = msg\n",
" print(path)\n",
diff --git a/examples/notebook/examples/memory_layout_and_infeasibility_sat.ipynb b/examples/notebook/examples/memory_layout_and_infeasibility_sat.ipynb
index 8819fc4290..5512d91f34 100644
--- a/examples/notebook/examples/memory_layout_and_infeasibility_sat.ipynb
+++ b/examples/notebook/examples/memory_layout_and_infeasibility_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -121,8 +121,10 @@
" y_starts: List[cp_model.IntVar] = []\n",
" y_intervals: List[cp_model.IntervalVar] = []\n",
"\n",
- " for start, end, demand, unused_alignment in DEMANDS:\n",
- " x_interval = model.new_fixed_size_interval_var(start, end - start + 1, \"\")\n",
+ " for start_time, end_time, demand, _ in DEMANDS:\n",
+ " x_interval = model.new_fixed_size_interval_var(\n",
+ " start_time, end_time - start_time + 1, \"\"\n",
+ " )\n",
" y_start = model.new_int_var(0, CAPACITY - demand, \"\")\n",
" y_interval = model.new_fixed_size_interval_var(y_start, demand, \"\")\n",
"\n",
@@ -141,9 +143,9 @@
" status = solver.solve(model)\n",
" print(solver.response_stats())\n",
"\n",
- " if status == cp_model.FEASIBLE or status == cp_model.OPTIMAL:\n",
- " for index, start in enumerate(y_starts):\n",
- " print(f\"task {index} buffer starts at {solver.value(start)}\")\n",
+ " if status in (cp_model.FEASIBLE, cp_model.OPTIMAL):\n",
+ " for index, start_var in enumerate(y_starts):\n",
+ " print(f\"task {index} buffer starts at {solver.value(start_var)}\")\n",
"\n",
" return status != cp_model.INFEASIBLE\n",
"\n",
diff --git a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb
index 442eb1f8e1..e82657ba4a 100644
--- a/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb
+++ b/examples/notebook/examples/no_wait_baking_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -90,16 +90,16 @@
"outputs": [],
"source": [
"import collections\n",
- "from typing import Sequence\n",
+ "from typing import List, Sequence, Tuple\n",
+ "\n",
"from ortools.sat.colab import flags\n",
"from google.protobuf import text_format\n",
"from ortools.sat.python import cp_model\n",
"\n",
"_PARAMS = flags.define_string(\n",
- " \"params\", \"num_search_workers:16, max_time_in_seconds:30\", \"Sat solver parameters.\"\n",
- ")\n",
- "_PROTO_FILE = flags.define_string(\n",
- " \"proto_file\", \"\", \"If not empty, output the proto to this file.\"\n",
+ " \"params\",\n",
+ " \"num_search_workers:16, max_time_in_seconds:30\",\n",
+ " \"Sat solver parameters.\",\n",
")\n",
"\n",
"# Recipes\n",
@@ -117,7 +117,7 @@
"DISPLAY = \"display\"\n",
"\n",
"\n",
- "class Task(object):\n",
+ "class Task:\n",
" \"\"\"A unit baking task.\n",
"\n",
" - Simple baking tasks have a fixed duration. They are performed by workers.\n",
@@ -131,7 +131,7 @@
" self.max_duration = max_duration\n",
"\n",
"\n",
- "class Skill(object):\n",
+ "class Skill:\n",
" \"\"\"The skill of a worker or the capability of a machine.\"\"\"\n",
"\n",
" def __init__(self, name, efficiency):\n",
@@ -140,19 +140,21 @@
" self.efficiency = efficiency\n",
"\n",
"\n",
- "class Recipe(object):\n",
+ "class Recipe:\n",
" \"\"\"A recipe is a sequence of cooking tasks.\"\"\"\n",
"\n",
" def __init__(self, name):\n",
" self.name = name\n",
" self.tasks = []\n",
"\n",
- " def add_task(self, resource_name, min_duration, max_duration):\n",
+ " def add_task(\n",
+ " self, resource_name: str, min_duration: int, max_duration: int\n",
+ " ) -> \"Recipe\":\n",
" self.tasks.append(Task(resource_name, min_duration, max_duration))\n",
" return self\n",
"\n",
"\n",
- "class Resource(object):\n",
+ "class Resource:\n",
" \"\"\"A resource is a worker, a machine, or just some space for cakes to rest.\n",
"\n",
" - Workers have a capacity of 1 and can have variable efficiency.\n",
@@ -168,12 +170,12 @@
" self.capacity = capacity\n",
" self.skills = []\n",
"\n",
- " def add_skill(self, skill_name, efficiency):\n",
+ " def add_skill(self, skill_name: str, efficiency: float) -> \"Resource\":\n",
" self.skills.append(Skill(skill_name, efficiency))\n",
" return self\n",
"\n",
"\n",
- "class Order(object):\n",
+ "class Order:\n",
" \"\"\"An order is a recipe that should be delivered at a given due date.\"\"\"\n",
"\n",
" def __init__(self, unique_id, recipe_name, due_date, quantity):\n",
@@ -191,7 +193,7 @@
" self.quantity = quantity\n",
"\n",
"\n",
- "def set_up_data():\n",
+ "def set_up_data() -> Tuple[List[Recipe], List[Resource], List[Order]]:\n",
" \"\"\"Set up the bakery problem data.\"\"\"\n",
"\n",
" # Recipes.\n",
@@ -260,7 +262,9 @@
" return recipes, resources, orders\n",
"\n",
"\n",
- "def solve_with_cp_sat(recipes, resources, orders):\n",
+ "def solve_with_cp_sat(\n",
+ " recipes: List[Recipe], resources: List[Resource], orders: List[Order]\n",
+ ") -> None:\n",
" \"\"\"Build the optimization model, and solve the problem.\"\"\"\n",
"\n",
" model = cp_model.CpModel()\n",
@@ -297,7 +301,6 @@
" skill_name = task.name\n",
" suffix = f\"_{order.unique_id}_batch{batch}_{skill_name}\"\n",
"\n",
- " start = None\n",
" if previous_end is None:\n",
" start = model.new_int_var(start_work, horizon, f\"start{suffix}\")\n",
" orders_sequence_of_events[order_id].append(\n",
@@ -309,7 +312,6 @@
" size = model.new_int_var(\n",
" task.min_duration, task.max_duration, f\"size{suffix}\"\n",
" )\n",
- " end = None\n",
" if task == recipe.tasks[-1]:\n",
" # The order must end after the due_date. Ideally, exactly at the\n",
" # due_date.\n",
diff --git a/examples/notebook/examples/nqueens_sat.ipynb b/examples/notebook/examples/nqueens_sat.ipynb
index c235565da3..391be2abc6 100644
--- a/examples/notebook/examples/nqueens_sat.ipynb
+++ b/examples/notebook/examples/nqueens_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -96,26 +96,26 @@
"\n",
" def __init__(self, queens: list[cp_model.IntVar]):\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
- " self.__queens = queens\n",
- " self.__solution_count = 0\n",
- " self.__start_time = time.time()\n",
+ " self._queens = queens\n",
+ " self._solution_count = 0\n",
+ " self._start_time = time.time()\n",
"\n",
" @property\n",
" def solution_count(self) -> int:\n",
- " return self.__solution_count\n",
+ " return self._solution_count\n",
"\n",
" def on_solution_callback(self) -> None:\n",
" current_time = time.time()\n",
" print(\n",
- " \"Solution %i, time = %f s\"\n",
- " % (self.__solution_count, current_time - self.__start_time)\n",
+ " f\"Solution{self._solution_count}, time =\"\n",
+ " f\" {current_time - self._start_time} s\"\n",
" )\n",
- " self.__solution_count += 1\n",
+ " self._solution_count += 1\n",
"\n",
- " all_queens = range(len(self.__queens))\n",
+ " all_queens = range(len(self._queens))\n",
" for i in all_queens:\n",
" for j in all_queens:\n",
- " if self.value(self.__queens[j]) == i:\n",
+ " if self.value(self._queens[j]) == i:\n",
" # There is a queen in column j, row i.\n",
" print(\"Q\", end=\" \")\n",
" else:\n",
diff --git a/examples/notebook/examples/pell_equation_sat.ipynb b/examples/notebook/examples/pell_equation_sat.ipynb
new file mode 100644
index 0000000000..d136340121
--- /dev/null
+++ b/examples/notebook/examples/pell_equation_sat.ipynb
@@ -0,0 +1,141 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "google",
+ "metadata": {},
+ "source": [
+ "##### Copyright 2024 Google LLC."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "apache",
+ "metadata": {},
+ "source": [
+ "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ "you may not use this file except in compliance with the License.\n",
+ "You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ "Unless required by applicable law or agreed to in writing, software\n",
+ "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ "See the License for the specific language governing permissions and\n",
+ "limitations under the License.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "basename",
+ "metadata": {},
+ "source": [
+ "# pell_equation_sat"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "link",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "doc",
+ "metadata": {},
+ "source": [
+ "First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "install",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install ortools"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "description",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Solves Pell's equation x^2 - coeff * y^2 = 1.\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "code",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from collections.abc import Sequence\n",
+ "\n",
+ "from ortools.sat.colab import flags\n",
+ "from ortools.sat.python import cp_model\n",
+ "\n",
+ "\n",
+ "_COEFF = flags.define_integer(\"coeff\", 1, \"The Pell equation coefficient.\")\n",
+ "_MAX_VALUE = flags.define_integer(\"max_value\", 5000_000, \"The maximum value.\")\n",
+ "\n",
+ "\n",
+ "def solve_pell(coeff: int, max_value: int) -> None:\n",
+ " \"\"\"Solves Pell's equation x^2 - coeff * y^2 = 1.\"\"\"\n",
+ " model = cp_model.CpModel()\n",
+ "\n",
+ " x = model.new_int_var(1, max_value, \"x\")\n",
+ " y = model.new_int_var(1, max_value, \"y\")\n",
+ "\n",
+ " # Pell's equation:\n",
+ " x_square = model.new_int_var(1, max_value * max_value, \"x_square\")\n",
+ " y_square = model.new_int_var(1, max_value * max_value, \"y_square\")\n",
+ " model.add_multiplication_equality(x_square, x, x)\n",
+ " model.add_multiplication_equality(y_square, y, y)\n",
+ " model.add(x_square - coeff * y_square == 1)\n",
+ "\n",
+ " model.add_decision_strategy(\n",
+ " [x, y], cp_model.CHOOSE_MIN_DOMAIN_SIZE, cp_model.SELECT_MIN_VALUE\n",
+ " )\n",
+ "\n",
+ " solver = cp_model.CpSolver()\n",
+ " solver.parameters.num_workers = 12\n",
+ " solver.parameters.log_search_progress = True\n",
+ " solver.parameters.cp_model_presolve = True\n",
+ " solver.parameters.cp_model_probing_level = 0\n",
+ "\n",
+ " result = solver.solve(model)\n",
+ " if result == cp_model.OPTIMAL:\n",
+ " print(f\"x={solver.value(x)} y={solver.value(y)} coeff={coeff}\")\n",
+ " if solver.value(x) ** 2 - coeff * (solver.value(y) ** 2) != 1:\n",
+ " raise ValueError(\"Pell equation not satisfied.\")\n",
+ "\n",
+ "\n",
+ "def main(argv: Sequence[str]) -> None:\n",
+ " if len(argv) > 1:\n",
+ " raise app.UsageError(\"Too many command-line arguments.\")\n",
+ " solve_pell(_COEFF.value, _MAX_VALUE.value)\n",
+ "\n",
+ "\n",
+ "main()\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/notebook/examples/pentominoes_sat.ipynb b/examples/notebook/examples/pentominoes_sat.ipynb
index e3d2a01a18..8f47a9623c 100644
--- a/examples/notebook/examples/pentominoes_sat.ipynb
+++ b/examples/notebook/examples/pentominoes_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -81,6 +81,9 @@
"\n",
"This problem comes from the game Katamino:\n",
"http://boardgamegeek.com/boardgame/6931/katamino\n",
+ "\n",
+ "This example also includes suggestions from\n",
+ "https://web.ma.utexas.edu/users/smmg/archive/1997/radin.html\n",
"\n"
]
},
@@ -109,6 +112,8 @@
" \"pieces\", \"FILNPTUVWXYZ\", \"The subset of pieces to consider.\"\n",
")\n",
"\n",
+ "_HEIGHT = flags.define_integer(\"height\", 5, \"The height of the box.\")\n",
+ "\n",
"\n",
"def is_one(mask: List[List[int]], x: int, y: int, orientation: int) -> bool:\n",
" \"\"\"Returns true if the oriented piece is 1 at position [i][j].\n",
@@ -171,8 +176,9 @@
"\n",
"def generate_and_solve_problem(pieces: Dict[str, List[List[int]]]) -> None:\n",
" \"\"\"Solves the pentominoes problem.\"\"\"\n",
- " box_width = len(pieces)\n",
- " box_height = 5\n",
+ " box_height = _HEIGHT.value\n",
+ " box_width = 5 * len(pieces) // box_height\n",
+ " print(f\"Box has dimension {box_height} * {box_width}\")\n",
"\n",
" model = cp_model.CpModel()\n",
" position_to_variables: List[List[List[cp_model.IntVar]]] = [\n",
@@ -209,8 +215,8 @@
" status = solver.solve(model)\n",
"\n",
" print(\n",
- " f\"Problem {_PIECES.value} solved in {solver.wall_time}s with status\"\n",
- " f\" {solver.status_name(status)}\"\n",
+ " f\"Problem {_PIECES.value} box {box_height}*{box_width} solved in\"\n",
+ " f\" {solver.wall_time}s with status {solver.status_name(status)}\"\n",
" )\n",
"\n",
" # Print the solution.\n",
@@ -250,6 +256,16 @@
" print(f\"Piece {p} not found in the list of pieces\")\n",
" return\n",
" selected_pieces[p] = pieces[p]\n",
+ " if (len(selected_pieces) * 5) % _HEIGHT.value != 0:\n",
+ " print(\n",
+ " f\"The height {_HEIGHT.value} does not divide the total area\"\n",
+ " f\" {5 * len(selected_pieces)}\"\n",
+ " )\n",
+ " return\n",
+ " if _HEIGHT.value < 3 or 5 * len(selected_pieces) // _HEIGHT.value < 3:\n",
+ " print(f\"The height {_HEIGHT.value} is not compatible with the pieces.\")\n",
+ " return\n",
+ "\n",
" generate_and_solve_problem(selected_pieces)\n",
"\n",
"\n",
diff --git a/examples/notebook/examples/prize_collecting_tsp.ipynb b/examples/notebook/examples/prize_collecting_tsp.ipynb
index 0a22c80eef..c18f94325e 100644
--- a/examples/notebook/examples/prize_collecting_tsp.ipynb
+++ b/examples/notebook/examples/prize_collecting_tsp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb
index 953b755e2a..df2d25e7c1 100644
--- a/examples/notebook/examples/prize_collecting_tsp_sat.ipynb
+++ b/examples/notebook/examples/prize_collecting_tsp_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/prize_collecting_vrp.ipynb b/examples/notebook/examples/prize_collecting_vrp.ipynb
index 9d2199ef03..59f667c073 100644
--- a/examples/notebook/examples/prize_collecting_vrp.ipynb
+++ b/examples/notebook/examples/prize_collecting_vrp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb
index ece91f2ba5..e0565da839 100644
--- a/examples/notebook/examples/prize_collecting_vrp_sat.ipynb
+++ b/examples/notebook/examples/prize_collecting_vrp_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/proto_solve.ipynb b/examples/notebook/examples/proto_solve.ipynb
index 58708fa2ed..8ef8b466e2 100644
--- a/examples/notebook/examples/proto_solve.ipynb
+++ b/examples/notebook/examples/proto_solve.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/pyflow_example.ipynb b/examples/notebook/examples/pyflow_example.ipynb
index 920b6a6e6e..d90c8fc992 100644
--- a/examples/notebook/examples/pyflow_example.ipynb
+++ b/examples/notebook/examples/pyflow_example.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/qubo_sat.ipynb b/examples/notebook/examples/qubo_sat.ipynb
index d3273c3bb4..2372041466 100644
--- a/examples/notebook/examples/qubo_sat.ipynb
+++ b/examples/notebook/examples/qubo_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/random_tsp.ipynb b/examples/notebook/examples/random_tsp.ipynb
index 42c6be3776..179aad7477 100644
--- a/examples/notebook/examples/random_tsp.ipynb
+++ b/examples/notebook/examples/random_tsp.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/rcpsp_sat.ipynb b/examples/notebook/examples/rcpsp_sat.ipynb
index da67fe4fc5..ee96bdd88b 100644
--- a/examples/notebook/examples/rcpsp_sat.ipynb
+++ b/examples/notebook/examples/rcpsp_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/reallocate_sat.ipynb b/examples/notebook/examples/reallocate_sat.ipynb
index cf54de8209..3a1aa56091 100644
--- a/examples/notebook/examples/reallocate_sat.ipynb
+++ b/examples/notebook/examples/reallocate_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -89,7 +89,6 @@
"\n",
"\n",
"def main():\n",
- "\n",
" # Data\n",
" data_0 = [\n",
" [107, 107, 107, 0, 0], # pr1\n",
@@ -105,7 +104,7 @@
" [298836792, 0, 0, 0],\n",
" [3713428, 4118530, 4107277, 3072018],\n",
" [6477273, 7183884, 5358471, 0],\n",
- " [1485371, 1647412, 1642911, 1228807]\n",
+ " [1485371, 1647412, 1642911, 1228807],\n",
" ]\n",
"\n",
" data_2 = [\n",
@@ -115,7 +114,7 @@
" [2988367, 0, 0, 0],\n",
" [37134, 41185, 41072, 30720],\n",
" [64772, 71838, 53584, 0],\n",
- " [14853, 16474, 16429, 12288]\n",
+ " [14853, 16474, 16429, 12288],\n",
" ]\n",
"\n",
" pr = data_0\n",
@@ -129,7 +128,7 @@
" model = cp_model.CpModel()\n",
"\n",
" # Variables\n",
- " delta = model.NewIntVar(0, total, 'delta')\n",
+ " delta = model.NewIntVar(0, total, \"delta\")\n",
"\n",
" contributions_per_years = collections.defaultdict(list)\n",
" contributions_per_prs = collections.defaultdict(list)\n",
@@ -138,14 +137,12 @@
" for p, inner_l in enumerate(pr):\n",
" for y, item in enumerate(inner_l):\n",
" if item != 0:\n",
- " contrib = model.NewIntVar(0, total, 'r%d c%d' % (p, y))\n",
+ " contrib = model.NewIntVar(0, total, \"r%d c%d\" % (p, y))\n",
" contributions_per_years[y].append(contrib)\n",
" contributions_per_prs[p].append(contrib)\n",
" all_contribs[p, y] = contrib\n",
"\n",
- " year_var = [\n",
- " model.NewIntVar(0, total, 'y[%i]' % i) for i in range(num_years)\n",
- " ]\n",
+ " year_var = [model.NewIntVar(0, total, \"y[%i]\" % i) for i in range(num_years)]\n",
"\n",
" # Constraints\n",
"\n",
@@ -173,32 +170,32 @@
"\n",
" # Output solution.\n",
" if status == cp_model.OPTIMAL:\n",
- " print('Data')\n",
- " print(' - total = ', total)\n",
- " print(' - year_average = ', avg)\n",
- " print(' - number of projects = ', num_pr)\n",
- " print(' - number of years = ', num_years)\n",
+ " print(\"Data\")\n",
+ " print(\" - total = \", total)\n",
+ " print(\" - year_average = \", avg)\n",
+ " print(\" - number of projects = \", num_pr)\n",
+ " print(\" - number of years = \", num_years)\n",
"\n",
- " print(' - input production')\n",
+ " print(\" - input production\")\n",
" for p in range(num_pr):\n",
" for y in range(num_years):\n",
" if pr[p][y] == 0:\n",
- " print(' ', end='')\n",
+ " print(\" \", end=\"\")\n",
" else:\n",
- " print('%10i' % pr[p][y], end='')\n",
+ " print(\"%10i\" % pr[p][y], end=\"\")\n",
" print()\n",
"\n",
- " print('Solution')\n",
+ " print(\"Solution\")\n",
" for p in range(num_pr):\n",
" for y in range(num_years):\n",
" if pr[p][y] == 0:\n",
- " print(' ', end='')\n",
+ " print(\" \", end=\"\")\n",
" else:\n",
- " print('%10i' % solver.Value(all_contribs[p, y]), end='')\n",
+ " print(\"%10i\" % solver.Value(all_contribs[p, y]), end=\"\")\n",
" print()\n",
"\n",
" for y in range(num_years):\n",
- " print('%10i' % solver.Value(year_var[y]), end='')\n",
+ " print(\"%10i\" % solver.Value(year_var[y]), end=\"\")\n",
" print()\n",
"\n",
"\n",
diff --git a/examples/notebook/examples/shift_scheduling_sat.ipynb b/examples/notebook/examples/shift_scheduling_sat.ipynb
index 5b4a551d6c..68ae241e11 100644
--- a/examples/notebook/examples/shift_scheduling_sat.ipynb
+++ b/examples/notebook/examples/shift_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -177,7 +177,7 @@
" for length in range(hard_min, soft_min):\n",
" for start in range(len(works) - length + 1):\n",
" span = negated_bounded_span(works, start, length)\n",
- " name = \": under_span(start=%i, length=%i)\" % (start, length)\n",
+ " name = f\": under_span(start={start}, length={length})\"\n",
" lit = model.new_bool_var(prefix + name)\n",
" span.append(lit)\n",
" model.add_bool_or(span)\n",
@@ -191,7 +191,7 @@
" for length in range(soft_max + 1, hard_max + 1):\n",
" for start in range(len(works) - length + 1):\n",
" span = negated_bounded_span(works, start, length)\n",
- " name = \": over_span(start=%i, length=%i)\" % (start, length)\n",
+ " name = f\": over_span(start={start}, length={length})\"\n",
" lit = model.new_bool_var(prefix + name)\n",
" span.append(lit)\n",
" model.add_bool_or(span)\n",
@@ -366,7 +366,7 @@
" for e in range(num_employees):\n",
" for s in range(num_shifts):\n",
" for d in range(num_days):\n",
- " work[e, s, d] = model.new_bool_var(\"work%i_%i_%i\" % (e, s, d))\n",
+ " work[e, s, d] = model.new_bool_var(f\"work{e}_{s}_{d}\")\n",
"\n",
" # Linear terms of the objective in a minimization context.\n",
" obj_int_vars: list[cp_model.IntVar] = []\n",
@@ -402,7 +402,7 @@
" soft_max,\n",
" hard_max,\n",
" max_cost,\n",
- " \"shift_constraint(employee %i, shift %i)\" % (e, shift),\n",
+ " f\"shift_constraint(employee {e}, shift {shift})\",\n",
" )\n",
" obj_bool_vars.extend(variables)\n",
" obj_bool_coeffs.extend(coeffs)\n",
@@ -422,8 +422,7 @@
" soft_max,\n",
" hard_max,\n",
" max_cost,\n",
- " \"weekly_sum_constraint(employee %i, shift %i, week %i)\"\n",
- " % (e, shift, w),\n",
+ " f\"weekly_sum_constraint(employee {e}, shift {shift}, week {w})\",\n",
" )\n",
" obj_int_vars.extend(variables)\n",
" obj_int_coeffs.extend(coeffs)\n",
@@ -440,7 +439,7 @@
" model.add_bool_or(transition)\n",
" else:\n",
" trans_var = model.new_bool_var(\n",
- " \"transition (employee=%i, day=%i)\" % (e, d)\n",
+ " f\"transition (employee={e}, day={d})\"\n",
" )\n",
" transition.append(trans_var)\n",
" model.add_bool_or(transition)\n",
@@ -458,7 +457,7 @@
" model.add(worked == sum(works))\n",
" over_penalty = excess_cover_penalties[s - 1]\n",
" if over_penalty > 0:\n",
- " name = \"excess_demand(shift=%i, week=%i, day=%i)\" % (s, w, d)\n",
+ " name = f\"excess_demand(shift={s}, week={w}, day={d})\"\n",
" excess = model.new_int_var(0, num_employees - min_demand, name)\n",
" model.add(excess == worked - min_demand)\n",
" obj_int_vars.append(excess)\n",
@@ -471,7 +470,7 @@
" )\n",
"\n",
" if output_proto:\n",
- " print(\"Writing proto to %s\" % output_proto)\n",
+ " print(f\"Writing proto to {output_proto}\")\n",
" with open(output_proto, \"w\") as text_file:\n",
" text_file.write(str(model))\n",
"\n",
@@ -495,7 +494,7 @@
" for s in range(num_shifts):\n",
" if solver.boolean_value(work[e, s, d]):\n",
" schedule += shifts[s] + \" \"\n",
- " print(\"worker %i: %s\" % (e, schedule))\n",
+ " print(f\"worker {e}: {schedule}\")\n",
" print()\n",
" print(\"Penalties:\")\n",
" for i, var in enumerate(obj_bool_vars):\n",
@@ -509,16 +508,12 @@
" for i, var in enumerate(obj_int_vars):\n",
" if solver.value(var) > 0:\n",
" print(\n",
- " \" %s violated by %i, linear penalty=%i\"\n",
- " % (var.name, solver.value(var), obj_int_coeffs[i])\n",
+ " f\" {var.name} violated by {solver.value(var)}, linear\"\n",
+ " f\" penalty={obj_int_coeffs[i]}\"\n",
" )\n",
"\n",
" print()\n",
- " print(\"Statistics\")\n",
- " print(\" - status : %s\" % solver.status_name(status))\n",
- " print(\" - conflicts : %i\" % solver.num_conflicts)\n",
- " print(\" - branches : %i\" % solver.num_branches)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " print(solver.response_stats())\n",
"\n",
"\n",
"def main(_):\n",
diff --git a/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb b/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb
index db433d3080..b8f6fede11 100644
--- a/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb
+++ b/examples/notebook/examples/single_machine_scheduling_with_setup_release_due_dates_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -95,7 +95,7 @@
")\n",
"_PARAMS = flags.define_string(\n",
" \"params\",\n",
- " \"num_search_workers:16,log_search_progress:false,max_time_in_seconds:45\",\n",
+ " \"num_search_workers:16,log_search_progress:true,max_time_in_seconds:45\",\n",
" \"Sat solver parameters.\",\n",
")\n",
"_PREPROCESS = flags.define_bool(\n",
@@ -108,17 +108,16 @@
"class SolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
- " def __init__(self):\n",
+ " def __init__(self) -> None:\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__solution_count = 0\n",
"\n",
- " def on_solution_callback(self):\n",
- " \"\"\"Called after each new solution found.\"\"\"\n",
+ " def on_solution_callback(self) -> None:\n",
+ " \"\"\"Called at each new solution.\"\"\"\n",
" print(\n",
- " \"Solution %i, time = %f s, objective = %i\"\n",
- " % (self.__solution_count, self.wall_time, self.objective_value)\n",
+ " f\"Solution {self.__solution_count}, time = {self.wall_time} s,\"\n",
+ " f\" objective = {self.objective_value}\"\n",
" )\n",
- " self.__solution_count += 1\n",
"\n",
"\n",
"def single_machine_scheduling():\n",
@@ -461,9 +460,7 @@
" if min_incoming_setup == 0:\n",
" continue\n",
"\n",
- " print(\n",
- " \"job %i has a min incoming setup of %i\" % (job_id, min_incoming_setup)\n",
- " )\n",
+ " print(f\"job {job_id} has a min incoming setup of {min_incoming_setup}\")\n",
" # We can transfer some setup times to the duration of the job.\n",
" job_durations[job_id] += min_incoming_setup\n",
" # Decrease corresponding incoming setup times.\n",
@@ -482,7 +479,7 @@
" horizon = sum(job_durations) + sum(\n",
" max(setup_times[i][j] for i in range(num_jobs + 1)) for j in range(num_jobs)\n",
" )\n",
- " print(\"Greedy horizon =\", horizon)\n",
+ " print(f\"Greedy horizon = {horizon}\")\n",
"\n",
" # ----------------------------------------------------------------------------\n",
" # Global storage of variables.\n",
@@ -497,10 +494,10 @@
" release_date = release_dates[job_id]\n",
" due_date = due_dates[job_id] if due_dates[job_id] != -1 else horizon\n",
" print(\n",
- " \"job %2i: start = %5i, duration = %4i, end = %6i\"\n",
- " % (job_id, release_date, duration, due_date)\n",
+ " f\"job {job_id:2}: start = {release_date:5}, duration = {duration:4},\"\n",
+ " f\" end = {due_date:6}\"\n",
" )\n",
- " name_suffix = \"_%i\" % job_id\n",
+ " name_suffix = f\"_{job_id}\"\n",
" start = model.new_int_var(release_date, due_date, \"s\" + name_suffix)\n",
" end = model.new_int_var(release_date, due_date, \"e\" + name_suffix)\n",
" interval = model.new_interval_var(start, duration, end, \"i\" + name_suffix)\n",
@@ -528,7 +525,7 @@
" if i == j:\n",
" continue\n",
"\n",
- " lit = model.new_bool_var(\"%i follows %i\" % (j, i))\n",
+ " lit = model.new_bool_var(f\"{j} follows {i}\")\n",
" arcs.append((i + 1, j + 1, lit))\n",
"\n",
" # We add the reified precedence to link the literal with the times of the\n",
@@ -549,7 +546,7 @@
" # ----------------------------------------------------------------------------\n",
" # Precedences.\n",
" for before, after in precedences:\n",
- " print(\"job %i is after job %i\" % (after, before))\n",
+ " print(f\"job {after} is after job {before}\")\n",
" model.add(ends[before] <= starts[after])\n",
"\n",
" # ----------------------------------------------------------------------------\n",
@@ -561,7 +558,7 @@
" # ----------------------------------------------------------------------------\n",
" # Write problem to file.\n",
" if output_proto_file:\n",
- " print(\"Writing proto to %s\" % output_proto_file)\n",
+ " print(f\"Writing proto to {output_proto_file}\")\n",
" with open(output_proto_file, \"w\") as text_file:\n",
" text_file.write(str(model))\n",
"\n",
@@ -571,12 +568,12 @@
" if parameters:\n",
" text_format.Parse(parameters, solver.parameters)\n",
" solution_printer = SolutionPrinter()\n",
- " solver.best_bound_callback = lambda a : print(f\"New objective lower bound: {a}\")\n",
+ " solver.best_bound_callback = lambda a: print(f\"New objective lower bound: {a}\")\n",
" solver.solve(model, solution_printer)\n",
" for job_id in all_jobs:\n",
" print(\n",
- " \"job %i starts at %i end ends at %i\"\n",
- " % (job_id, solver.value(starts[job_id]), solver.value(ends[job_id]))\n",
+ " f\"job {job_id} starts at {solver.value(starts[job_id])} end ends at\"\n",
+ " f\" {solver.value(ends[job_id])}\"\n",
" )\n",
"\n",
"\n",
diff --git a/examples/notebook/examples/spread_robots_sat.ipynb b/examples/notebook/examples/spread_robots_sat.ipynb
index 0108997abd..f59067cf5d 100644
--- a/examples/notebook/examples/spread_robots_sat.ipynb
+++ b/examples/notebook/examples/spread_robots_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -100,7 +100,7 @@
")\n",
"\n",
"\n",
- "def spread_robots(num_robots: int, room_size: int, params: str):\n",
+ "def spread_robots(num_robots: int, room_size: int, params: str) -> None:\n",
" \"\"\"Optimize robots placement.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
diff --git a/examples/notebook/examples/steel_mill_slab_sat.ipynb b/examples/notebook/examples/steel_mill_slab_sat.ipynb
index f41ba73058..effe92258d 100644
--- a/examples/notebook/examples/steel_mill_slab_sat.ipynb
+++ b/examples/notebook/examples/steel_mill_slab_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -106,13 +106,10 @@
")\n",
"\n",
"\n",
- "def build_problem(problem_id):\n",
+ "def build_problem(\n",
+ " problem_id: int,\n",
+ ") -> tuple[int, list[int], int, list[tuple[int, int]]]:\n",
" \"\"\"Build problem data.\"\"\"\n",
- " capacities = None\n",
- " num_colors = None\n",
- " num_slabs = None\n",
- " orders = None\n",
- "\n",
" if problem_id == 0:\n",
" capacities = [\n",
" # fmt:off\n",
@@ -167,15 +164,22 @@
" # fmt:on\n",
" ]\n",
"\n",
- " elif problem_id == 3:\n",
+ " else: # problem_id == 3, default problem.\n",
" capacities = [0, 17, 44]\n",
" num_colors = 8\n",
" num_slabs = 10\n",
" orders = [ # (size, color)\n",
- " # fmt:off\n",
- " (4, 1), (22, 2), (9, 3), (5, 4), (8, 5), (3, 6), (3, 4), (4, 7),\n",
- " (7, 4), (7, 8), (3, 6),\n",
- " # fmt:on\n",
+ " (4, 1),\n",
+ " (22, 2),\n",
+ " (9, 3),\n",
+ " (5, 4),\n",
+ " (8, 5),\n",
+ " (3, 6),\n",
+ " (3, 4),\n",
+ " (4, 7),\n",
+ " (7, 4),\n",
+ " (7, 8),\n",
+ " (3, 6),\n",
" ]\n",
"\n",
" return (num_slabs, capacities, num_colors, orders)\n",
@@ -184,7 +188,7 @@
"class SteelMillSlabSolutionPrinter(cp_model.CpSolverSolutionCallback):\n",
" \"\"\"Print intermediate solutions.\"\"\"\n",
"\n",
- " def __init__(self, orders, assign, load, loss):\n",
+ " def __init__(self, orders, assign, load, loss) -> None:\n",
" cp_model.CpSolverSolutionCallback.__init__(self)\n",
" self.__orders = orders\n",
" self.__assign = assign\n",
@@ -195,13 +199,13 @@
" self.__all_slabs = range(len(assign[0]))\n",
" self.__start_time = time.time()\n",
"\n",
- " def on_solution_callback(self):\n",
+ " def on_solution_callback(self) -> None:\n",
" \"\"\"Called on each new solution.\"\"\"\n",
" current_time = time.time()\n",
" objective = sum(self.value(l) for l in self.__loss)\n",
" print(\n",
- " \"Solution %i, time = %f s, objective = %i\"\n",
- " % (self.__solution_count, current_time - self.__start_time, objective)\n",
+ " f\"Solution {self.__solution_count}, time =\"\n",
+ " f\" {current_time - self.__start_time} s, objective = {objective}\"\n",
" )\n",
" self.__solution_count += 1\n",
" orders_in_slab = [\n",
@@ -210,25 +214,20 @@
" ]\n",
" for s in self.__all_slabs:\n",
" if orders_in_slab[s]:\n",
- " line = \" - slab %i, load = %i, loss = %i, orders = [\" % (\n",
- " s,\n",
- " self.value(self.__load[s]),\n",
- " self.value(self.__loss[s]),\n",
+ " line = (\n",
+ " f\" - slab {s}, load = {self.value(self.__load[s])}, loss =\"\n",
+ " f\" {self.value(self.__loss[s])}, orders = [\"\n",
" )\n",
" for o in orders_in_slab[s]:\n",
- " line += \"#%i(w%i, c%i) \" % (\n",
- " o,\n",
- " self.__orders[o][0],\n",
- " self.__orders[o][1],\n",
- " )\n",
+ " line += f\"#{o}(w{self.__orders[o][0]}, c{self.__orders[o][1]})\"\n",
" line += \"]\"\n",
" print(line)\n",
"\n",
"\n",
- "def steel_mill_slab(problem, break_symmetries):\n",
+ "def steel_mill_slab(problem_id: int, break_symmetries: bool) -> None:\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
- " (num_slabs, capacities, num_colors, orders) = build_problem(problem)\n",
+ " num_slabs, capacities, num_colors, orders = build_problem(problem_id)\n",
"\n",
" num_orders = len(orders)\n",
" num_capacities = len(capacities)\n",
@@ -236,8 +235,8 @@
" all_colors = range(num_colors)\n",
" all_orders = range(len(orders))\n",
" print(\n",
- " \"Solving steel mill with %i orders, %i slabs, and %i capacities\"\n",
- " % (num_orders, num_slabs, num_capacities - 1)\n",
+ " f\"Solving steel mill with {num_orders} orders, {num_slabs} slabs, and\"\n",
+ " f\" {num_capacities - 1} capacities\"\n",
" )\n",
"\n",
" # Compute auxiliary data.\n",
@@ -260,14 +259,12 @@
" # Create the model and the decision variables.\n",
" model = cp_model.CpModel()\n",
" assign = [\n",
- " [model.new_bool_var(\"assign_%i_to_slab_%i\" % (o, s)) for s in all_slabs]\n",
+ " [model.new_bool_var(f\"assign_{o}_to_slab_{s}\") for s in all_slabs]\n",
" for o in all_orders\n",
" ]\n",
- " loads = [\n",
- " model.new_int_var(0, max_capacity, \"load_of_slab_%i\" % s) for s in all_slabs\n",
- " ]\n",
+ " loads = [model.new_int_var(0, max_capacity, f\"load_of_slab_{s}\") for s in all_slabs]\n",
" color_is_in_slab = [\n",
- " [model.new_bool_var(\"color_%i_in_slab_%i\" % (c + 1, s)) for c in all_colors]\n",
+ " [model.new_bool_var(f\"color_{c + 1}_in_slab_{s}\") for c in all_colors]\n",
" for s in all_slabs\n",
" ]\n",
"\n",
@@ -334,19 +331,19 @@
" # Create position variables if there are symmetries to be broken.\n",
" if break_symmetries and ordered_equivalent_orders:\n",
" print(\n",
- " \" - creating %i symmetry breaking constraints\"\n",
- " % len(ordered_equivalent_orders)\n",
+ " f\" - creating {len(ordered_equivalent_orders)} symmetry breaking\"\n",
+ " \" constraints\"\n",
" )\n",
" positions = {}\n",
" for p in ordered_equivalent_orders:\n",
" if p[0] not in positions:\n",
" positions[p[0]] = model.new_int_var(\n",
- " 0, num_slabs - 1, \"position_of_slab_%i\" % p[0]\n",
+ " 0, num_slabs - 1, f\"position_of_slab_{p[0]}\"\n",
" )\n",
" model.add_map_domain(positions[p[0]], assign[p[0]])\n",
" if p[1] not in positions:\n",
" positions[p[1]] = model.new_int_var(\n",
- " 0, num_slabs - 1, \"position_of_slab_%i\" % p[1]\n",
+ " 0, num_slabs - 1, f\"position_of_slab_{p[1]}\"\n",
" )\n",
" model.add_map_domain(positions[p[1]], assign[p[1]])\n",
" # Finally add the symmetry breaking constraint.\n",
@@ -354,7 +351,7 @@
"\n",
" # Objective.\n",
" obj = model.new_int_var(0, num_slabs * max_loss, \"obj\")\n",
- " losses = [model.new_int_var(0, max_loss, \"loss_%i\" % s) for s in all_slabs]\n",
+ " losses = [model.new_int_var(0, max_loss, f\"loss_{s}\") for s in all_slabs]\n",
" for s in all_slabs:\n",
" model.add_element(loads[s], loss_array, losses[s])\n",
" model.add(obj == sum(losses))\n",
@@ -370,14 +367,19 @@
" ### Output the solution.\n",
" if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" print(\n",
- " \"Loss = %i, time = %f s, %i conflicts\"\n",
- " % (solver.objective_value, solver.wall_time, solver.num_conflicts)\n",
+ " f\"Loss = {solver.objective_value}, time = {solver.wall_time} s,\"\n",
+ " f\" {solver.num_conflicts} conflicts\"\n",
" )\n",
" else:\n",
" print(\"No solution\")\n",
"\n",
"\n",
- "def collect_valid_slabs_dp(capacities, colors, widths, loss_array):\n",
+ "def collect_valid_slabs_dp(\n",
+ " capacities: list[int],\n",
+ " colors: list[int],\n",
+ " widths: list[int],\n",
+ " loss_array: list[int],\n",
+ ") -> list[list[int]]:\n",
" \"\"\"Collect valid columns (assign, loss) for one slab.\"\"\"\n",
" start_time = time.time()\n",
"\n",
@@ -406,8 +408,8 @@
" all_valid_assignments.extend(new_assignments)\n",
"\n",
" print(\n",
- " \"%i assignments created in %.2f s\"\n",
- " % (len(all_valid_assignments), time.time() - start_time)\n",
+ " f\"{len(all_valid_assignments)} assignments created in\"\n",
+ " f\" {time.time() - start_time:2f} s\"\n",
" )\n",
" tuples = []\n",
" for assignment in all_valid_assignments:\n",
@@ -421,10 +423,10 @@
" return tuples\n",
"\n",
"\n",
- "def steel_mill_slab_with_valid_slabs(problem, break_symmetries):\n",
+ "def steel_mill_slab_with_valid_slabs(problem_id: int, break_symmetries: bool) -> None:\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
- " (num_slabs, capacities, num_colors, orders) = build_problem(problem)\n",
+ " (num_slabs, capacities, num_colors, orders) = build_problem(problem_id)\n",
"\n",
" num_orders = len(orders)\n",
" num_capacities = len(capacities)\n",
@@ -432,8 +434,8 @@
" all_colors = range(num_colors)\n",
" all_orders = range(len(orders))\n",
" print(\n",
- " \"Solving steel mill with %i orders, %i slabs, and %i capacities\"\n",
- " % (num_orders, num_slabs, num_capacities - 1)\n",
+ " f\"Solving steel mill with {num_orders} orders, {num_slabs} slabs, and\"\n",
+ " f\" {num_capacities - 1} capacities\"\n",
" )\n",
"\n",
" # Compute auxiliary data.\n",
@@ -450,11 +452,11 @@
" # Create the model and the decision variables.\n",
" model = cp_model.CpModel()\n",
" assign = [\n",
- " [model.new_bool_var(\"assign_%i_to_slab_%i\" % (o, s)) for s in all_slabs]\n",
+ " [model.new_bool_var(r\"assign_{o}_to_slab_{s}\") for s in all_slabs]\n",
" for o in all_orders\n",
" ]\n",
- " loads = [model.new_int_var(0, max_capacity, \"load_%i\" % s) for s in all_slabs]\n",
- " losses = [model.new_int_var(0, max_loss, \"loss_%i\" % s) for s in all_slabs]\n",
+ " loads = [model.new_int_var(0, max_capacity, f\"load_{s}\") for s in all_slabs]\n",
+ " losses = [model.new_int_var(0, max_loss, f\"loss_{s}\") for s in all_slabs]\n",
"\n",
" unsorted_valid_slabs = collect_valid_slabs_dp(\n",
" capacities, colors, widths, loss_array\n",
@@ -516,19 +518,19 @@
" # Create position variables if there are symmetries to be broken.\n",
" if ordered_equivalent_orders:\n",
" print(\n",
- " \" - creating %i symmetry breaking constraints\"\n",
- " % len(ordered_equivalent_orders)\n",
+ " f\" - creating {len(ordered_equivalent_orders)} symmetry breaking\"\n",
+ " \" constraints\"\n",
" )\n",
" positions = {}\n",
" for p in ordered_equivalent_orders:\n",
" if p[0] not in positions:\n",
" positions[p[0]] = model.new_int_var(\n",
- " 0, num_slabs - 1, \"position_of_slab_%i\" % p[0]\n",
+ " 0, num_slabs - 1, f\"position_of_slab_{p[0]}\"\n",
" )\n",
" model.add_map_domain(positions[p[0]], assign[p[0]])\n",
" if p[1] not in positions:\n",
" positions[p[1]] = model.new_int_var(\n",
- " 0, num_slabs - 1, \"position_of_slab_%i\" % p[1]\n",
+ " 0, num_slabs - 1, f\"position_of_slab_{p[1]}\"\n",
" )\n",
" model.add_map_domain(positions[p[1]], assign[p[1]])\n",
" # Finally add the symmetry breaking constraint.\n",
@@ -550,24 +552,24 @@
" ### Output the solution.\n",
" if status == cp_model.OPTIMAL:\n",
" print(\n",
- " \"Loss = %i, time = %.2f s, %i conflicts\"\n",
- " % (solver.objective_value, solver.wall_time, solver.num_conflicts)\n",
+ " f\"Loss = {solver.objective_value}, time = {solver.wall_time:2f} s,\"\n",
+ " f\" {solver.num_conflicts} conflicts\"\n",
" )\n",
" else:\n",
" print(\"No solution\")\n",
"\n",
"\n",
- "def steel_mill_slab_with_column_generation(problem):\n",
+ "def steel_mill_slab_with_column_generation(problem_id: int) -> None:\n",
" \"\"\"Solves the Steel Mill Slab Problem.\"\"\"\n",
" ### Load problem.\n",
- " (num_slabs, capacities, _, orders) = build_problem(problem)\n",
+ " (num_slabs, capacities, _, orders) = build_problem(problem_id)\n",
"\n",
" num_orders = len(orders)\n",
" num_capacities = len(capacities)\n",
" all_orders = range(len(orders))\n",
" print(\n",
- " \"Solving steel mill with %i orders, %i slabs, and %i capacities\"\n",
- " % (num_orders, num_slabs, num_capacities - 1)\n",
+ " f\"Solving steel mill with {num_orders} orders, {num_slabs} slabs, and\"\n",
+ " f\" {num_capacities - 1} capacities\"\n",
" )\n",
"\n",
" # Compute auxiliary data.\n",
@@ -591,7 +593,7 @@
"\n",
" # create model and decision variables.\n",
" model = cp_model.CpModel()\n",
- " selected = [model.new_bool_var(\"selected_%i\" % i) for i in all_valid_slabs]\n",
+ " selected = [model.new_bool_var(f\"selected_{i}\") for i in all_valid_slabs]\n",
"\n",
" for order_id in all_orders:\n",
" model.add(\n",
@@ -619,8 +621,8 @@
" ### Output the solution.\n",
" if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):\n",
" print(\n",
- " \"Loss = %i, time = %.2f s, %i conflicts\"\n",
- " % (solver.objective_value, solver.wall_time, solver.num_conflicts)\n",
+ " f\"Loss = {solver.objective_value}, time = {solver.wall_time:2f} s,\"\n",
+ " f\" {solver.num_conflicts} conflicts\"\n",
" )\n",
" else:\n",
" print(\"No solution\")\n",
diff --git a/examples/notebook/examples/sudoku_sat.ipynb b/examples/notebook/examples/sudoku_sat.ipynb
index bf099994ae..85bf780cb1 100644
--- a/examples/notebook/examples/sudoku_sat.ipynb
+++ b/examples/notebook/examples/sudoku_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -86,7 +86,7 @@
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
- "def solve_sudoku():\n",
+ "def solve_sudoku() -> None:\n",
" \"\"\"Solves the sudoku problem with the CP-SAT solver.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
diff --git a/examples/notebook/examples/task_allocation_sat.ipynb b/examples/notebook/examples/task_allocation_sat.ipynb
index 41e056b698..ab7e77752d 100644
--- a/examples/notebook/examples/task_allocation_sat.ipynb
+++ b/examples/notebook/examples/task_allocation_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -91,7 +91,7 @@
"from ortools.sat.python import cp_model\n",
"\n",
"\n",
- "def task_allocation_sat():\n",
+ "def task_allocation_sat() -> None:\n",
" \"\"\"Solves the task allocation problem.\"\"\"\n",
" # Availability matrix.\n",
" available = [\n",
@@ -314,9 +314,9 @@
" assign = {}\n",
" for task in all_tasks:\n",
" for slot in all_slots:\n",
- " assign[(task, slot)] = model.new_bool_var(\"x[%i][%i]\" % (task, slot))\n",
+ " assign[(task, slot)] = model.new_bool_var(f\"x[{task}][{slot}]\")\n",
" count = model.new_int_var(0, nslots, \"count\")\n",
- " slot_used = [model.new_bool_var(\"slot_used[%i]\" % s) for s in all_slots]\n",
+ " slot_used = [model.new_bool_var(f\"slot_used[{s}]\") for s in all_slots]\n",
"\n",
" for task in all_tasks:\n",
" model.add(\n",
@@ -353,12 +353,7 @@
" # Uses the portfolion of heuristics.\n",
" solver.parameters.log_search_progress = True\n",
" solver.parameters.num_search_workers = 16\n",
- " status = solver.solve(model)\n",
- "\n",
- " print(\"Statistics\")\n",
- " print(\" - status =\", solver.status_name(status))\n",
- " print(\" - optimal solution =\", solver.objective_value)\n",
- " print(\" - wall time : %f s\" % solver.wall_time)\n",
+ " solver.solve(model)\n",
"\n",
"\n",
"def main(argv: Sequence[str]) -> None:\n",
diff --git a/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb b/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb
index b436483c2e..2bfdd2250f 100644
--- a/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb
+++ b/examples/notebook/examples/tasks_and_workers_assignment_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -102,7 +102,7 @@
" self.__solution_count += 1\n",
"\n",
"\n",
- "def tasks_and_workers_assignment_sat():\n",
+ "def tasks_and_workers_assignment_sat() -> None:\n",
" \"\"\"solve the assignment problem.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
diff --git a/examples/notebook/examples/test_scheduling_sat.ipynb b/examples/notebook/examples/test_scheduling_sat.ipynb
new file mode 100644
index 0000000000..fd94dc99cd
--- /dev/null
+++ b/examples/notebook/examples/test_scheduling_sat.ipynb
@@ -0,0 +1,251 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "google",
+ "metadata": {},
+ "source": [
+ "##### Copyright 2024 Google LLC."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "apache",
+ "metadata": {},
+ "source": [
+ "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+ "you may not use this file except in compliance with the License.\n",
+ "You may obtain a copy of the License at\n",
+ "\n",
+ " http://www.apache.org/licenses/LICENSE-2.0\n",
+ "\n",
+ "Unless required by applicable law or agreed to in writing, software\n",
+ "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+ "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+ "See the License for the specific language governing permissions and\n",
+ "limitations under the License.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "basename",
+ "metadata": {},
+ "source": [
+ "# test_scheduling_sat"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "link",
+ "metadata": {},
+ "source": [
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "doc",
+ "metadata": {},
+ "source": [
+ "First, you must install [ortools](https://pypi.org/project/ortools/) package in this colab."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "install",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%pip install ortools"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "description",
+ "metadata": {},
+ "source": [
+ "\n",
+ "Solves a test scheduling problem.\n",
+ "\n",
+ "Tests must be run by an operator. Tests have a duration and a power consumption.\n",
+ "\n",
+ "Operators draw power from power supplies. The mapping between operators and\n",
+ "power supplies is given.\n",
+ "\n",
+ "Power supplies have a maximum power they can deliver.\n",
+ "\n",
+ "Can we schedule the tests so that the power consumption of each power supply is\n",
+ "always below its maximum power, and the total makespan is minimized?\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "code",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from collections.abc import Sequence\n",
+ "import io\n",
+ "from typing import Dict, Tuple\n",
+ "\n",
+ "from ortools.sat.colab import flags\n",
+ "import pandas as pd\n",
+ "\n",
+ "from google.protobuf import text_format\n",
+ "from ortools.sat.python import cp_model\n",
+ "\n",
+ "\n",
+ "_PARAMS = flags.define_string(\n",
+ " \"params\",\n",
+ " \"num_search_workers:16,log_search_progress:true,max_time_in_seconds:45\",\n",
+ " \"Sat solver parameters.\",\n",
+ ")\n",
+ "\n",
+ "\n",
+ "def build_data() -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:\n",
+ " \"\"\"Build the data frame.\"\"\"\n",
+ " tests_str = \"\"\"\n",
+ " Name Operator TestTime AveragePower\n",
+ " T1 O1 300 200\n",
+ " T2 O1 150 40\n",
+ " T3 O2 100 65\n",
+ " T4 O2 250 150\n",
+ " T5 O3 210 140\n",
+ " \"\"\"\n",
+ "\n",
+ " operators_str = \"\"\"\n",
+ " Operator Supply\n",
+ " O1 S1\n",
+ " O2 S2\n",
+ " O3 S2\n",
+ " \"\"\"\n",
+ "\n",
+ " supplies_str = \"\"\"\n",
+ " Supply MaxAllowedPower\n",
+ " S1 230\n",
+ " S2 210\n",
+ " \"\"\"\n",
+ "\n",
+ " tests_data = pd.read_table(io.StringIO(tests_str), sep=r\"\\s+\")\n",
+ " operators_data = pd.read_table(io.StringIO(operators_str), sep=r\"\\s+\")\n",
+ " supplies_data = pd.read_table(io.StringIO(supplies_str), sep=r\"\\s+\")\n",
+ "\n",
+ " return (tests_data, operators_data, supplies_data)\n",
+ "\n",
+ "\n",
+ "def solve(\n",
+ " tests_data: pd.DataFrame,\n",
+ " operator_data: pd.DataFrame,\n",
+ " supplies_data: pd.DataFrame,\n",
+ ") -> None:\n",
+ " \"\"\"Solve the scheduling of tests problem.\"\"\"\n",
+ "\n",
+ " # Parses data.\n",
+ " operator_to_supply: Dict[str, str] = {}\n",
+ " for _, row in operator_data.iterrows():\n",
+ " operator_to_supply[row[\"Operator\"]] = row[\"Supply\"]\n",
+ "\n",
+ " supply_to_max_power: Dict[str, int] = {}\n",
+ " for _, row in supplies_data.iterrows():\n",
+ " supply_to_max_power[row[\"Supply\"]] = row[\"MaxAllowedPower\"]\n",
+ "\n",
+ " horizon = tests_data[\"TestTime\"].sum()\n",
+ "\n",
+ " # OR-Tools model.\n",
+ " model = cp_model.CpModel()\n",
+ "\n",
+ " # Create containers.\n",
+ " tests_per_supply: Dict[str, Tuple[list[cp_model.IntervalVar], list[int]]] = {}\n",
+ " test_supply: Dict[str, str] = {}\n",
+ " test_starts: Dict[str, cp_model.IntVar] = {}\n",
+ " test_durations: Dict[str, int] = {}\n",
+ " test_powers: Dict[str, int] = {}\n",
+ " all_ends = []\n",
+ "\n",
+ " # Creates intervals.\n",
+ " for _, row in tests_data.iterrows():\n",
+ " name: str = row[\"Name\"]\n",
+ " operator: str = row[\"Operator\"]\n",
+ " test_time: int = row[\"TestTime\"]\n",
+ " average_power: int = row[\"AveragePower\"]\n",
+ " supply: str = operator_to_supply[operator]\n",
+ "\n",
+ " start = model.new_int_var(0, horizon - test_time, f\"start_{name}\")\n",
+ " interval = model.new_fixed_size_interval_var(\n",
+ " start, test_time, f\"interval_{name}\"\n",
+ " )\n",
+ "\n",
+ " # Bookkeeping.\n",
+ " test_starts[name] = start\n",
+ " test_durations[name] = test_time\n",
+ " test_powers[name] = average_power\n",
+ " test_supply[name] = supply\n",
+ " if supply not in tests_per_supply.keys():\n",
+ " tests_per_supply[supply] = ([], [])\n",
+ " tests_per_supply[supply][0].append(interval)\n",
+ " tests_per_supply[supply][1].append(average_power)\n",
+ " all_ends.append(start + test_time)\n",
+ "\n",
+ " # Create supply cumulative constraints.\n",
+ " for supply, (intervals, demands) in tests_per_supply.items():\n",
+ " model.add_cumulative(intervals, demands, supply_to_max_power[supply])\n",
+ "\n",
+ " # Objective.\n",
+ " makespan = model.new_int_var(0, horizon, \"makespan\")\n",
+ " for end in all_ends:\n",
+ " model.add(makespan >= end)\n",
+ " model.minimize(makespan)\n",
+ "\n",
+ " # Solve model.\n",
+ " solver = cp_model.CpSolver()\n",
+ " if _PARAMS.value:\n",
+ " text_format.Parse(_PARAMS.value, solver.parameters)\n",
+ " status = solver.solve(model)\n",
+ "\n",
+ " # Report solution.\n",
+ " if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:\n",
+ " print(f\"Makespan = {solver.value(makespan)}\")\n",
+ " for name, start in test_starts.items():\n",
+ " print(\n",
+ " f\"{name}: start:{solver.value(start)} duration:{test_durations[name]}\"\n",
+ " f\" power:{test_powers[name]} on supply {test_supply[name]}\"\n",
+ " )\n",
+ "\n",
+ "\n",
+ "def main(argv: Sequence[str]) -> None:\n",
+ " \"\"\"Builds the data and solve the scheduling problem.\"\"\"\n",
+ " if len(argv) > 1:\n",
+ " raise app.UsageError(\"Too many command-line arguments.\")\n",
+ "\n",
+ " tests_data, operators_data, supplies_data = build_data()\n",
+ " print(\"Tests data\")\n",
+ " print(tests_data)\n",
+ " print()\n",
+ " print(\"Operators data\")\n",
+ " print(operators_data)\n",
+ " print()\n",
+ " print(\"Supplies data\")\n",
+ " print(supplies_data)\n",
+ "\n",
+ " solve(tests_data, operators_data, supplies_data)\n",
+ "\n",
+ "\n",
+ "main()\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/notebook/examples/transit_time.ipynb b/examples/notebook/examples/transit_time.ipynb
index bcd5687089..073c4d9aa7 100644
--- a/examples/notebook/examples/transit_time.ipynb
+++ b/examples/notebook/examples/transit_time.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/tsp_sat.ipynb b/examples/notebook/examples/tsp_sat.ipynb
index 3917b3e864..8704e02160 100644
--- a/examples/notebook/examples/tsp_sat.ipynb
+++ b/examples/notebook/examples/tsp_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/examples/vendor_scheduling_sat.ipynb b/examples/notebook/examples/vendor_scheduling_sat.ipynb
index 8c71c011a3..f23d5dc94b 100644
--- a/examples/notebook/examples/vendor_scheduling_sat.ipynb
+++ b/examples/notebook/examples/vendor_scheduling_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -131,7 +131,7 @@
" return self.__solution_count\n",
"\n",
"\n",
- "def vendor_scheduling_sat():\n",
+ "def vendor_scheduling_sat() -> None:\n",
" \"\"\"Create the shift scheduling model and solve it.\"\"\"\n",
" # Create the model.\n",
" model = cp_model.CpModel()\n",
diff --git a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb
index 06abd55693..c27f1c2c78 100644
--- a/examples/notebook/examples/wedding_optimal_chart_sat.ipynb
+++ b/examples/notebook/examples/wedding_optimal_chart_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -198,7 +198,7 @@
" return num_tables, table_capacity, min_known_neighbors, connections, names\n",
"\n",
"\n",
- "def solve_with_discrete_model():\n",
+ "def solve_with_discrete_model() -> None:\n",
" \"\"\"Discrete approach.\"\"\"\n",
" num_tables, table_capacity, min_known_neighbors, connections, names = build_data()\n",
"\n",
diff --git a/examples/notebook/examples/weighted_latency_problem_sat.ipynb b/examples/notebook/examples/weighted_latency_problem_sat.ipynb
index 270789e36e..5267fe8663 100644
--- a/examples/notebook/examples/weighted_latency_problem_sat.ipynb
+++ b/examples/notebook/examples/weighted_latency_problem_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
@@ -122,7 +122,7 @@
" return x, y, profits\n",
"\n",
"\n",
- "def solve_with_cp_sat(x, y, profits):\n",
+ "def solve_with_cp_sat(x, y, profits) -> None:\n",
" \"\"\"Solves the problem with the CP-SAT solver.\"\"\"\n",
" model = cp_model.CpModel()\n",
"\n",
diff --git a/examples/notebook/examples/zebra_sat.ipynb b/examples/notebook/examples/zebra_sat.ipynb
index acc02dcddc..3b78497478 100644
--- a/examples/notebook/examples/zebra_sat.ipynb
+++ b/examples/notebook/examples/zebra_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/graph/assignment_linear_sum_assignment.ipynb b/examples/notebook/graph/assignment_linear_sum_assignment.ipynb
index 4d9fcd7645..c0edfe8444 100644
--- a/examples/notebook/graph/assignment_linear_sum_assignment.ipynb
+++ b/examples/notebook/graph/assignment_linear_sum_assignment.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/graph/assignment_min_flow.ipynb b/examples/notebook/graph/assignment_min_flow.ipynb
index 65b5fe8066..e8a998a10d 100644
--- a/examples/notebook/graph/assignment_min_flow.ipynb
+++ b/examples/notebook/graph/assignment_min_flow.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/graph/balance_min_flow.ipynb b/examples/notebook/graph/balance_min_flow.ipynb
index 4f4610d7a1..b1c9d3fbd9 100644
--- a/examples/notebook/graph/balance_min_flow.ipynb
+++ b/examples/notebook/graph/balance_min_flow.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/graph/simple_max_flow_program.ipynb b/examples/notebook/graph/simple_max_flow_program.ipynb
index 7fd3732f68..565b87b392 100644
--- a/examples/notebook/graph/simple_max_flow_program.ipynb
+++ b/examples/notebook/graph/simple_max_flow_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/graph/simple_min_cost_flow_program.ipynb b/examples/notebook/graph/simple_min_cost_flow_program.ipynb
index ab10714e41..0f754965ee 100644
--- a/examples/notebook/graph/simple_min_cost_flow_program.ipynb
+++ b/examples/notebook/graph/simple_min_cost_flow_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/assignment_groups_mip.ipynb b/examples/notebook/linear_solver/assignment_groups_mip.ipynb
index cf4e28298f..e2c72d3bd5 100644
--- a/examples/notebook/linear_solver/assignment_groups_mip.ipynb
+++ b/examples/notebook/linear_solver/assignment_groups_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/assignment_mb.ipynb b/examples/notebook/linear_solver/assignment_mb.ipynb
index 34b7ac0a9d..a6808aeacd 100644
--- a/examples/notebook/linear_solver/assignment_mb.ipynb
+++ b/examples/notebook/linear_solver/assignment_mb.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/assignment_mip.ipynb b/examples/notebook/linear_solver/assignment_mip.ipynb
index 6540ed8f04..f814693fa9 100644
--- a/examples/notebook/linear_solver/assignment_mip.ipynb
+++ b/examples/notebook/linear_solver/assignment_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb b/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb
index 2b1f0b69f0..3bfb3141f4 100644
--- a/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb
+++ b/examples/notebook/linear_solver/assignment_task_sizes_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/assignment_teams_mip.ipynb b/examples/notebook/linear_solver/assignment_teams_mip.ipynb
index 75911a8447..5726a5d5ef 100644
--- a/examples/notebook/linear_solver/assignment_teams_mip.ipynb
+++ b/examples/notebook/linear_solver/assignment_teams_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/basic_example.ipynb b/examples/notebook/linear_solver/basic_example.ipynb
index 5d9f00fd07..536f091e80 100644
--- a/examples/notebook/linear_solver/basic_example.ipynb
+++ b/examples/notebook/linear_solver/basic_example.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/bin_packing_mb.ipynb b/examples/notebook/linear_solver/bin_packing_mb.ipynb
index 1f28e0fa63..e848fa7fe9 100644
--- a/examples/notebook/linear_solver/bin_packing_mb.ipynb
+++ b/examples/notebook/linear_solver/bin_packing_mb.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/bin_packing_mip.ipynb b/examples/notebook/linear_solver/bin_packing_mip.ipynb
index 1b43da8711..58fc818c3d 100644
--- a/examples/notebook/linear_solver/bin_packing_mip.ipynb
+++ b/examples/notebook/linear_solver/bin_packing_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/clone_model_mb.ipynb b/examples/notebook/linear_solver/clone_model_mb.ipynb
index 17478cf4ab..350ecc4c4b 100644
--- a/examples/notebook/linear_solver/clone_model_mb.ipynb
+++ b/examples/notebook/linear_solver/clone_model_mb.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/integer_programming_example.ipynb b/examples/notebook/linear_solver/integer_programming_example.ipynb
index 8db2b7c336..7dd5b31fdb 100644
--- a/examples/notebook/linear_solver/integer_programming_example.ipynb
+++ b/examples/notebook/linear_solver/integer_programming_example.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/linear_programming_example.ipynb b/examples/notebook/linear_solver/linear_programming_example.ipynb
index 00cb97c3b8..7ee26107cd 100644
--- a/examples/notebook/linear_solver/linear_programming_example.ipynb
+++ b/examples/notebook/linear_solver/linear_programming_example.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/mip_var_array.ipynb b/examples/notebook/linear_solver/mip_var_array.ipynb
index 4f1d743c2d..f0f8664fdd 100644
--- a/examples/notebook/linear_solver/mip_var_array.ipynb
+++ b/examples/notebook/linear_solver/mip_var_array.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb b/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb
index e5fc31b7d7..8e8125b9af 100644
--- a/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb
+++ b/examples/notebook/linear_solver/multiple_knapsack_mip.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/simple_lp_program.ipynb b/examples/notebook/linear_solver/simple_lp_program.ipynb
index 3094e7382e..4775ecdfbd 100644
--- a/examples/notebook/linear_solver/simple_lp_program.ipynb
+++ b/examples/notebook/linear_solver/simple_lp_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/simple_lp_program_mb.ipynb b/examples/notebook/linear_solver/simple_lp_program_mb.ipynb
index 2d434121d8..bee79cf01f 100644
--- a/examples/notebook/linear_solver/simple_lp_program_mb.ipynb
+++ b/examples/notebook/linear_solver/simple_lp_program_mb.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/simple_mip_program.ipynb b/examples/notebook/linear_solver/simple_mip_program.ipynb
index f72fc00803..b3c6b8ad24 100644
--- a/examples/notebook/linear_solver/simple_mip_program.ipynb
+++ b/examples/notebook/linear_solver/simple_mip_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/simple_mip_program_mb.ipynb b/examples/notebook/linear_solver/simple_mip_program_mb.ipynb
index ef4151b636..9fb3f76d99 100644
--- a/examples/notebook/linear_solver/simple_mip_program_mb.ipynb
+++ b/examples/notebook/linear_solver/simple_mip_program_mb.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/linear_solver/stigler_diet.ipynb b/examples/notebook/linear_solver/stigler_diet.ipynb
index 7acaf3b707..d57c2dafa5 100644
--- a/examples/notebook/linear_solver/stigler_diet.ipynb
+++ b/examples/notebook/linear_solver/stigler_diet.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/pdlp/simple_pdlp_program.ipynb b/examples/notebook/pdlp/simple_pdlp_program.ipynb
index 7a0464fed0..4cb305fd49 100644
--- a/examples/notebook/pdlp/simple_pdlp_program.ipynb
+++ b/examples/notebook/pdlp/simple_pdlp_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/all_different_except_zero_sample_sat.ipynb b/examples/notebook/sat/all_different_except_zero_sample_sat.ipynb
index c4a826ec56..deb2a3f1bb 100644
--- a/examples/notebook/sat/all_different_except_zero_sample_sat.ipynb
+++ b/examples/notebook/sat/all_different_except_zero_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/assignment_groups_sat.ipynb b/examples/notebook/sat/assignment_groups_sat.ipynb
index 69798db58a..5bebc34dcf 100644
--- a/examples/notebook/sat/assignment_groups_sat.ipynb
+++ b/examples/notebook/sat/assignment_groups_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/assignment_sat.ipynb b/examples/notebook/sat/assignment_sat.ipynb
index 4bff58240b..012e9219af 100644
--- a/examples/notebook/sat/assignment_sat.ipynb
+++ b/examples/notebook/sat/assignment_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/assignment_task_sizes_sat.ipynb b/examples/notebook/sat/assignment_task_sizes_sat.ipynb
index e7a0ff6d7a..aa2c528af5 100644
--- a/examples/notebook/sat/assignment_task_sizes_sat.ipynb
+++ b/examples/notebook/sat/assignment_task_sizes_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/assignment_teams_sat.ipynb b/examples/notebook/sat/assignment_teams_sat.ipynb
index 63bf3749f1..5e50e35875 100644
--- a/examples/notebook/sat/assignment_teams_sat.ipynb
+++ b/examples/notebook/sat/assignment_teams_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/assumptions_sample_sat.ipynb b/examples/notebook/sat/assumptions_sample_sat.ipynb
index 218b9e1c6c..b76394e579 100644
--- a/examples/notebook/sat/assumptions_sample_sat.ipynb
+++ b/examples/notebook/sat/assumptions_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/bin_packing_sat.ipynb b/examples/notebook/sat/bin_packing_sat.ipynb
index 36edf83669..638ea767a9 100644
--- a/examples/notebook/sat/bin_packing_sat.ipynb
+++ b/examples/notebook/sat/bin_packing_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/binpacking_problem_sat.ipynb b/examples/notebook/sat/binpacking_problem_sat.ipynb
index 7bf8dd8ead..81a5b31467 100644
--- a/examples/notebook/sat/binpacking_problem_sat.ipynb
+++ b/examples/notebook/sat/binpacking_problem_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/bool_and_int_var_product_sample_sat.ipynb b/examples/notebook/sat/bool_and_int_var_product_sample_sat.ipynb
index 48490ea2ba..741e862cde 100644
--- a/examples/notebook/sat/bool_and_int_var_product_sample_sat.ipynb
+++ b/examples/notebook/sat/bool_and_int_var_product_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/bool_or_sample_sat.ipynb b/examples/notebook/sat/bool_or_sample_sat.ipynb
index 49091ac08b..004c570642 100644
--- a/examples/notebook/sat/bool_or_sample_sat.ipynb
+++ b/examples/notebook/sat/bool_or_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/boolean_product_sample_sat.ipynb b/examples/notebook/sat/boolean_product_sample_sat.ipynb
index ba6b49ef5a..206189e2dc 100644
--- a/examples/notebook/sat/boolean_product_sample_sat.ipynb
+++ b/examples/notebook/sat/boolean_product_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/channeling_sample_sat.ipynb b/examples/notebook/sat/channeling_sample_sat.ipynb
index ffc1bdafbd..87c91888ff 100644
--- a/examples/notebook/sat/channeling_sample_sat.ipynb
+++ b/examples/notebook/sat/channeling_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/clone_model_sample_sat.ipynb b/examples/notebook/sat/clone_model_sample_sat.ipynb
index 7eeb63ca17..0f07c81c5c 100644
--- a/examples/notebook/sat/clone_model_sample_sat.ipynb
+++ b/examples/notebook/sat/clone_model_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/cp_is_fun_sat.ipynb b/examples/notebook/sat/cp_is_fun_sat.ipynb
index 511f7678ee..d8c3facd9a 100644
--- a/examples/notebook/sat/cp_is_fun_sat.ipynb
+++ b/examples/notebook/sat/cp_is_fun_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/cp_sat_example.ipynb b/examples/notebook/sat/cp_sat_example.ipynb
index 5becf97322..130032976b 100644
--- a/examples/notebook/sat/cp_sat_example.ipynb
+++ b/examples/notebook/sat/cp_sat_example.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/cumulative_variable_profile_sample_sat.ipynb b/examples/notebook/sat/cumulative_variable_profile_sample_sat.ipynb
index c53482cf68..236fdd83b4 100644
--- a/examples/notebook/sat/cumulative_variable_profile_sample_sat.ipynb
+++ b/examples/notebook/sat/cumulative_variable_profile_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb b/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb
index 1310572d55..3f2d6595c2 100644
--- a/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb
+++ b/examples/notebook/sat/earliness_tardiness_cost_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/index_first_boolvar_true_sample_sat.ipynb b/examples/notebook/sat/index_first_boolvar_true_sample_sat.ipynb
index 39b1147d61..4c6e816d8c 100644
--- a/examples/notebook/sat/index_first_boolvar_true_sample_sat.ipynb
+++ b/examples/notebook/sat/index_first_boolvar_true_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/interval_relations_sample_sat.ipynb b/examples/notebook/sat/interval_relations_sample_sat.ipynb
index 876fce6f48..397249ba5e 100644
--- a/examples/notebook/sat/interval_relations_sample_sat.ipynb
+++ b/examples/notebook/sat/interval_relations_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/interval_sample_sat.ipynb b/examples/notebook/sat/interval_sample_sat.ipynb
index 3e44a96691..493c78ace5 100644
--- a/examples/notebook/sat/interval_sample_sat.ipynb
+++ b/examples/notebook/sat/interval_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/literal_sample_sat.ipynb b/examples/notebook/sat/literal_sample_sat.ipynb
index 0c91794ccb..be8ff9ab74 100644
--- a/examples/notebook/sat/literal_sample_sat.ipynb
+++ b/examples/notebook/sat/literal_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/minimal_jobshop_sat.ipynb b/examples/notebook/sat/minimal_jobshop_sat.ipynb
index dcf4f17a6c..1fc4886873 100644
--- a/examples/notebook/sat/minimal_jobshop_sat.ipynb
+++ b/examples/notebook/sat/minimal_jobshop_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/multiple_knapsack_sat.ipynb b/examples/notebook/sat/multiple_knapsack_sat.ipynb
index 91ed388c2e..95eec40688 100644
--- a/examples/notebook/sat/multiple_knapsack_sat.ipynb
+++ b/examples/notebook/sat/multiple_knapsack_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/no_overlap_sample_sat.ipynb b/examples/notebook/sat/no_overlap_sample_sat.ipynb
index f835517bab..2cdb3ec36c 100644
--- a/examples/notebook/sat/no_overlap_sample_sat.ipynb
+++ b/examples/notebook/sat/no_overlap_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/non_linear_sat.ipynb b/examples/notebook/sat/non_linear_sat.ipynb
index bcfb65d347..6a612e344b 100644
--- a/examples/notebook/sat/non_linear_sat.ipynb
+++ b/examples/notebook/sat/non_linear_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/nqueens_sat.ipynb b/examples/notebook/sat/nqueens_sat.ipynb
index 4b25066bc2..019fb94777 100644
--- a/examples/notebook/sat/nqueens_sat.ipynb
+++ b/examples/notebook/sat/nqueens_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/nurses_sat.ipynb b/examples/notebook/sat/nurses_sat.ipynb
index 705fa28cc6..02cf4d5aa2 100644
--- a/examples/notebook/sat/nurses_sat.ipynb
+++ b/examples/notebook/sat/nurses_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/optional_interval_sample_sat.ipynb b/examples/notebook/sat/optional_interval_sample_sat.ipynb
index 65d1e6a1d8..f356012ecf 100644
--- a/examples/notebook/sat/optional_interval_sample_sat.ipynb
+++ b/examples/notebook/sat/optional_interval_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb b/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb
index 4ce140f031..0eab065320 100644
--- a/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb
+++ b/examples/notebook/sat/overlapping_intervals_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb b/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb
index 0270831e70..63dc2a60b8 100644
--- a/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb
+++ b/examples/notebook/sat/rabbits_and_pheasants_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/ranking_circuit_sample_sat.ipynb b/examples/notebook/sat/ranking_circuit_sample_sat.ipynb
index 5aa71c8688..fb87e45064 100644
--- a/examples/notebook/sat/ranking_circuit_sample_sat.ipynb
+++ b/examples/notebook/sat/ranking_circuit_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/ranking_sample_sat.ipynb b/examples/notebook/sat/ranking_sample_sat.ipynb
index 0f3be41613..8dc5a41d81 100644
--- a/examples/notebook/sat/ranking_sample_sat.ipynb
+++ b/examples/notebook/sat/ranking_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/reified_sample_sat.ipynb b/examples/notebook/sat/reified_sample_sat.ipynb
index 99fa6e00e6..0ad5d78137 100644
--- a/examples/notebook/sat/reified_sample_sat.ipynb
+++ b/examples/notebook/sat/reified_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/schedule_requests_sat.ipynb b/examples/notebook/sat/schedule_requests_sat.ipynb
index b59b80f9ac..42333d160a 100644
--- a/examples/notebook/sat/schedule_requests_sat.ipynb
+++ b/examples/notebook/sat/schedule_requests_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb b/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb
index 9d8d97094c..0ddd27e1e6 100644
--- a/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb
+++ b/examples/notebook/sat/scheduling_with_calendar_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb b/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb
index 4d176acba6..90bb0d27f6 100644
--- a/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb
+++ b/examples/notebook/sat/search_for_all_solutions_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/simple_sat_program.ipynb b/examples/notebook/sat/simple_sat_program.ipynb
index 5af365a37c..fcb5827ea9 100644
--- a/examples/notebook/sat/simple_sat_program.ipynb
+++ b/examples/notebook/sat/simple_sat_program.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/solution_hinting_sample_sat.ipynb b/examples/notebook/sat/solution_hinting_sample_sat.ipynb
index 543e327c8d..a3a5ff8b04 100644
--- a/examples/notebook/sat/solution_hinting_sample_sat.ipynb
+++ b/examples/notebook/sat/solution_hinting_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb b/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb
index 0723487a2b..f3b5e59e2e 100644
--- a/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb
+++ b/examples/notebook/sat/solve_and_print_intermediate_solutions_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb b/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb
index 2893bc443a..1bd9182de2 100644
--- a/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb
+++ b/examples/notebook/sat/solve_with_time_limit_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/step_function_sample_sat.ipynb b/examples/notebook/sat/step_function_sample_sat.ipynb
index 7dde80e322..d0acd538ee 100644
--- a/examples/notebook/sat/step_function_sample_sat.ipynb
+++ b/examples/notebook/sat/step_function_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb b/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb
index 0fd972bc50..091b49d23f 100644
--- a/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb
+++ b/examples/notebook/sat/stop_after_n_solutions_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{
diff --git a/examples/notebook/sat/transitions_in_no_overlap_sample_sat.ipynb b/examples/notebook/sat/transitions_in_no_overlap_sample_sat.ipynb
index 1b618f02fc..77b4f68c4c 100644
--- a/examples/notebook/sat/transitions_in_no_overlap_sample_sat.ipynb
+++ b/examples/notebook/sat/transitions_in_no_overlap_sample_sat.ipynb
@@ -5,7 +5,7 @@
"id": "google",
"metadata": {},
"source": [
- "##### Copyright 2023 Google LLC."
+ "##### Copyright 2024 Google LLC."
]
},
{