From 72db1d9ef26aa75d6a3d7edfd0a22635e0d56bbb Mon Sep 17 00:00:00 2001 From: Laurent Perron Date: Mon, 11 Jun 2018 11:51:18 +0200 Subject: [PATCH] run pyformat on python examples --- examples/python/3_jugs_mip.py | 81 +- examples/python/3_jugs_regular.py | 33 +- examples/python/a_round_of_golf.py | 21 +- examples/python/all_interval.py | 6 +- examples/python/alldifferent_except_0.py | 16 +- examples/python/alphametic.py | 26 +- examples/python/appointments.py | 60 +- examples/python/assignment.py | 34 +- examples/python/assignment6_mip.py | 18 +- examples/python/assignment_sat.py | 22 +- .../python/assignment_with_constraints.py | 99 +- .../python/assignment_with_constraints_sat.py | 68 +- examples/python/bacp.py | 23 +- examples/python/blending.py | 19 +- examples/python/broken_weights.py | 7 +- examples/python/bus_schedule.py | 11 +- examples/python/car.py | 22 +- examples/python/check_dependencies.py | 150 +-- examples/python/circuit.py | 8 +- examples/python/coins3.py | 4 +- examples/python/coins_grid.py | 13 +- examples/python/coins_grid_mip.py | 10 +- examples/python/coloring_ip.py | 24 +- examples/python/combinatorial_auction2.py | 14 +- examples/python/contiguity_regular.py | 12 +- examples/python/costas_array.py | 19 +- examples/python/covering_opl.py | 42 +- examples/python/cp_is_fun_sat.py | 31 +- examples/python/crew.py | 95 +- examples/python/crossword2.py | 20 +- examples/python/crypta.py | 25 +- examples/python/crypto.py | 4 +- examples/python/curious_set_of_integers.py | 4 +- examples/python/cvrp.py | 371 +++---- examples/python/cvrptw.py | 584 +++++------ examples/python/cvrptw_plot.py | 948 +++++++++--------- examples/python/debruijn_binary.py | 12 +- examples/python/diet1.py | 10 +- examples/python/diet1_b.py | 10 +- examples/python/diet1_mip.py | 13 +- examples/python/discrete_tomography.py | 31 +- examples/python/divisible_by_9_through_1.py | 19 +- examples/python/dudeney.py | 12 +- examples/python/einav_puzzle.py | 85 +- examples/python/einav_puzzle2.py | 78 +- examples/python/eq10.py | 46 +- examples/python/eq20.py | 5 +- examples/python/fill_a_pix.py | 40 +- examples/python/flexible_job_shop_sat.py | 169 ++-- examples/python/furniture_moving.py | 11 +- examples/python/futoshiki.py | 54 +- examples/python/game_theory_taha.py | 12 +- examples/python/gate_scheduling_sat.py | 44 +- examples/python/golomb8.py | 18 +- examples/python/grocery.py | 8 +- examples/python/hidato.py | 108 +- examples/python/hidato_sat.py | 71 +- examples/python/hidato_table.py | 72 +- examples/python/integer_programming.py | 9 +- examples/python/jobshop_ft06.py | 33 +- examples/python/jobshop_ft06_distance.py | 33 +- examples/python/jobshop_ft06_sat.py | 26 +- examples/python/just_forgotten.py | 16 +- examples/python/kakuro.py | 63 +- examples/python/kenken2.py | 33 +- examples/python/killer_sudoku.py | 62 +- examples/python/knapsack.py | 31 +- examples/python/knapsack_cp.py | 5 +- examples/python/knapsack_mip.py | 18 +- examples/python/labeled_dice.py | 38 +- examples/python/langford.py | 5 +- examples/python/least_diff.py | 19 +- examples/python/least_square.py | 19 +- examples/python/lectures.py | 14 +- examples/python/linear_assignment_api.py | 13 +- examples/python/linear_programming.py | 8 +- examples/python/magic_sequence_distribute.py | 8 +- examples/python/magic_square.py | 17 +- examples/python/magic_square_and_cards.py | 6 +- examples/python/magic_square_mip.py | 43 +- examples/python/map.py | 8 +- examples/python/marathon2.py | 9 +- examples/python/max_flow_taha.py | 21 +- examples/python/max_flow_winston1.py | 26 +- examples/python/minesweeper.py | 52 +- examples/python/mr_smith.py | 5 +- examples/python/nonogram_default_search.py | 41 +- examples/python/nonogram_regular.py | 52 +- examples/python/nonogram_table.py | 46 +- examples/python/nonogram_table2.py | 44 +- examples/python/nontransitive_dice.py | 33 +- examples/python/nqueens.py | 13 +- examples/python/nqueens2.py | 14 +- examples/python/nqueens3.py | 8 +- examples/python/nqueens_sat.py | 16 +- examples/python/nurse_rostering.py | 31 +- examples/python/nurses_cp.py | 127 ++- examples/python/nurses_sat.py | 17 +- examples/python/olympic.py | 5 +- examples/python/organize_day.py | 13 +- examples/python/p_median.py | 29 +- examples/python/pandigital_numbers.py | 15 +- examples/python/photo_problem.py | 16 +- examples/python/place_number_puzzle.py | 50 +- examples/python/post_office_problem2.py | 8 +- examples/python/production.py | 35 +- examples/python/pyflow_example.py | 25 +- examples/python/pyls_api.py | 1 + examples/python/quasigroup_completion.py | 20 +- examples/python/rabbit_pheasant.py | 6 +- examples/python/rcpsp_sat.py | 40 +- examples/python/regular.py | 17 +- examples/python/regular_table.py | 13 +- examples/python/regular_table2.py | 14 +- examples/python/rogo2.py | 18 +- examples/python/rostering_with_travel.py | 17 +- examples/python/safe_cracking.py | 5 +- examples/python/scheduling_speakers.py | 15 +- examples/python/school_scheduling_sat.py | 4 +- examples/python/secret_santa.py | 6 +- examples/python/secret_santa2.py | 23 +- examples/python/send_more_money_any_base.py | 14 +- examples/python/send_most_money.py | 13 +- examples/python/sendmore.py | 12 +- examples/python/seseman.py | 13 +- examples/python/seseman_b.py | 9 +- examples/python/set_covering.py | 19 +- examples/python/set_covering2.py | 23 +- examples/python/set_covering3.py | 29 +- examples/python/set_covering4.py | 24 +- examples/python/set_covering_deployment.py | 37 +- examples/python/set_covering_skiena.py | 12 +- examples/python/set_partition.py | 31 +- examples/python/sicherman_dice.py | 8 +- examples/python/simple_meeting.py | 92 +- examples/python/ski_assignment.py | 14 +- examples/python/slitherlink.py | 55 +- examples/python/stable_marriage.py | 89 +- examples/python/steel.py | 58 +- examples/python/steel_lns.py | 93 +- examples/python/steel_mill_slab_sat.py | 104 +- examples/python/stigler.py | 308 +++--- examples/python/strimko2.py | 33 +- examples/python/subset_sum.py | 6 +- examples/python/sudoku.py | 22 +- examples/python/survo_puzzle.py | 17 +- examples/python/toNum.py | 14 +- examples/python/traffic_lights.py | 12 +- examples/python/transit_time.py | 294 +++--- examples/python/tsp.py | 37 +- examples/python/vendor_scheduling.py | 16 +- examples/python/volsay.py | 7 +- examples/python/volsay2.py | 8 +- examples/python/volsay3.py | 16 +- examples/python/vrp.py | 266 ++--- examples/python/vrpgs.py | 293 +++--- examples/python/wedding_optimal_chart.py | 219 ++-- examples/python/wedding_optimal_chart_sat.py | 121 +-- examples/python/who_killed_agatha.py | 6 +- examples/python/word_square.py | 12 +- examples/python/worker_schedule_sat.py | 10 +- examples/python/xkcd.py | 13 +- examples/python/young_tableaux.py | 10 +- examples/python/zebra.py | 29 +- 164 files changed, 3657 insertions(+), 4210 deletions(-) diff --git a/examples/python/3_jugs_mip.py b/examples/python/3_jugs_mip.py index 34d1447e3b..d7ef2616dd 100644 --- a/examples/python/3_jugs_mip.py +++ b/examples/python/3_jugs_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ 3 jugs problem using MIP in Google or-tools. @@ -54,41 +53,42 @@ def main(sol='CBC'): n = 15 start = 0 # start node end = 14 # end node - M = 999 # a large number + M = 999 # a large number - nodes = ['8,0,0', # start - '5,0,3', - '5,3,0', - '2,3,3', - '2,5,1', - '7,0,1', - '7,1,0', - '4,1,3', - '3,5,0', - '3,2,3', - '6,2,0', - '6,0,2', - '1,5,2', - '1,4,3', - '4,4,0' # goal! - ] + nodes = [ + '8,0,0', # start + '5,0,3', + '5,3,0', + '2,3,3', + '2,5,1', + '7,0,1', + '7,1,0', + '4,1,3', + '3,5,0', + '3,2,3', + '6,2,0', + '6,0,2', + '1,5,2', + '1,4,3', + '4,4,0' # goal! + ] # distance - d = [[M, 1, M, M, M, M, M, M, 1, M, M, M, M, M, M], - [M, M, 1, M, M, M, M, M, M, M, M, M, M, M, M], - [M, M, M, 1, M, M, M, M, 1, M, M, M, M, M, M], - [M, M, M, M, 1, M, M, M, M, M, M, M, M, M, M], - [M, M, M, M, M, 1, M, M, 1, M, M, M, M, M, M], - [M, M, M, M, M, M, 1, M, M, M, M, M, M, M, M], - [M, M, M, M, M, M, M, 1, 1, M, M, M, M, M, M], - [M, M, M, M, M, M, M, M, M, M, M, M, M, M, 1], - [M, M, M, M, M, M, M, M, M, 1, M, M, M, M, M], - [M, 1, M, M, M, M, M, M, M, M, 1, M, M, M, M], - [M, M, M, M, M, M, M, M, M, M, M, 1, M, M, M], - [M, 1, M, M, M, M, M, M, M, M, M, M, 1, M, M], - [M, M, M, M, M, M, M, M, M, M, M, M, M, 1, M], - [M, 1, M, M, M, M, M, M, M, M, M, M, M, M, 1], - [M, M, M, M, M, M, M, M, M, M, M, M, M, M, M]] + d = [[M, 1, M, M, M, M, M, M, 1, M, M, M, M, M, + M], [M, M, 1, M, M, M, M, M, M, M, M, M, M, M, + M], [M, M, M, 1, M, M, M, M, 1, M, M, M, M, M, + M], [M, M, M, M, 1, M, M, M, M, M, M, M, M, M, M], + [M, M, M, M, M, 1, M, M, 1, M, M, M, M, M, + M], [M, M, M, M, M, M, 1, M, M, M, M, M, M, M, + M], [M, M, M, M, M, M, M, 1, 1, M, M, M, M, M, M], + [M, M, M, M, M, M, M, M, M, M, M, M, M, M, + 1], [M, M, M, M, M, M, M, M, M, 1, M, M, M, M, + M], [M, 1, M, M, M, M, M, M, M, M, 1, M, M, M, M], + [M, M, M, M, M, M, M, M, M, M, M, 1, M, M, + M], [M, 1, M, M, M, M, M, M, M, M, M, M, 1, M, + M], [M, M, M, M, M, M, M, M, M, M, M, M, M, 1, M], [ + M, 1, M, M, M, M, M, M, M, M, M, M, M, M, 1 + ], [M, M, M, M, M, M, M, M, M, M, M, M, M, M, M]] # # variables @@ -106,9 +106,8 @@ def main(sol='CBC'): in_flow = [solver.IntVar(0, 1, 'in_flow[%i]' % i) for i in range(n)] # length of path, to be minimized - z = solver.Sum([d[i][j] * x[i, j] - for i in range(n) - for j in range(n) if d[i][j] < M]) + z = solver.Sum( + [d[i][j] * x[i, j] for i in range(n) for j in range(n) if d[i][j] < M]) # # constraints @@ -124,15 +123,13 @@ def main(sol='CBC'): # outflow constraint for i in range(n): - solver.Add(out_flow[i] == solver.Sum([x[i, j] - for j in range(n) - if d[i][j] < M])) + solver.Add( + out_flow[i] == solver.Sum([x[i, j] for j in range(n) if d[i][j] < M])) # inflow constraint for j in range(n): - solver.Add(in_flow[j] == solver.Sum([x[i, j] - for i in range(n) - if d[i][j] < M])) + solver.Add( + in_flow[j] == solver.Sum([x[i, j] for i in range(n) if d[i][j] < M])) # inflow = outflow for i in range(n): diff --git a/examples/python/3_jugs_regular.py b/examples/python/3_jugs_regular.py index 114a7e1bad..efb8af45a6 100644 --- a/examples/python/3_jugs_regular.py +++ b/examples/python/3_jugs_regular.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ 3 jugs problem using regular constraint in Google CP Solver. @@ -118,8 +117,8 @@ def regular(x, Q, S, d, q0, F): solver.Add(x[i] <= S) # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] - solver.Add( - a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1))) + solver.Add(a[i + 1] == solver.Element(d2_flatten, ( + (a[i]) * S) + (x[i] - 1))) def main(n): @@ -165,19 +164,19 @@ def main(n): # states = [ [2, 9], # state 1 - [3], # state 2 + [3], # state 2 [4, 9], # state 3 - [5], # state 4 + [5], # state 4 [6, 9], # state 5 - [7], # state 6 + [7], # state 6 [8, 9], # state 7 - [15], # state 8 - [10], # state 9 - [11], # state 10 - [12], # state 11 - [13], # state 12 - [14], # state 13 - [15] # state 14 + [15], # state 8 + [10], # state 9 + [11], # state 10 + [12], # state 11 + [13], # state 12 + [14], # state 13 + [15] # state 14 ] transition_fn = [] @@ -220,15 +219,13 @@ def main(n): # # constraints # - regular(x, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(x, n_states, input_max, transition_fn, initial_state, + accepting_states) # # solution and search # - db = solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/a_round_of_golf.py b/examples/python/a_round_of_golf.py index 07930dfdab..2ec1fdeeb0 100644 --- a/examples/python/a_round_of_golf.py +++ b/examples/python/a_round_of_golf.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ A Round of Golf puzzle (Dell Logic Puzzles) in Google CP Solver. @@ -117,15 +116,15 @@ def main(): solver.Add(Frank != Sands) solver.Add(caddy != Sands) - b3_a_1 = solver.IsEqualVar(solver.Element(score, Sands) + 4, - score[Frank]) - b3_a_2 = solver.IsEqualVar(solver.Element(score, caddy), - solver.Element(score, Sands) + 7) + b3_a_1 = solver.IsEqualVar(solver.Element(score, Sands) + 4, score[Frank]) + b3_a_2 = solver.IsEqualVar( + solver.Element(score, caddy), + solver.Element(score, Sands) + 7) - b3_b_1 = solver.IsEqualVar(solver.Element(score, Sands) + 7, - score[Frank]) - b3_b_2 = solver.IsEqualVar(solver.Element(score, caddy), - solver.Element(score, Sands) + 4) + b3_b_1 = solver.IsEqualVar(solver.Element(score, Sands) + 7, score[Frank]) + b3_b_2 = solver.IsEqualVar( + solver.Element(score, caddy), + solver.Element(score, Sands) + 4) solver.Add((b3_a_1 * b3_a_2) + (b3_b_1 * b3_b_2) == 1) @@ -146,8 +145,7 @@ def main(): solution.Add(job) solution.Add(score) - db = solver.Phase(last_name + job + score, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(last_name + job + score, solver.CHOOSE_FIRST_UNBOUND, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -164,5 +162,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/all_interval.py b/examples/python/all_interval.py index a5f6fb56a8..a4e196013d 100644 --- a/examples/python/all_interval.py +++ b/examples/python/all_interval.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ All interval problem in Google CP Solver. @@ -94,9 +93,7 @@ def main(n=12): solution.Add(x) solution.Add(diffs) - db = solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -111,6 +108,7 @@ def main(n=12): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + n = 12 if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/alldifferent_except_0.py b/examples/python/alldifferent_except_0.py index 07f09759cc..b3817e5981 100644 --- a/examples/python/alldifferent_except_0.py +++ b/examples/python/alldifferent_except_0.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ All different except 0 Google CP Solver. @@ -66,13 +65,17 @@ def alldifferent_except_0(solver, a): for j in range(i): solver.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j])) + # more compact version: def alldifferent_except_0_b(solver, a): n = len(a) - [solver.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j])) - for i in range(n) for j in range(i)] + [ + solver.Add((a[i] != 0) * (a[j] != 0) <= (a[i] != a[j])) + for i in range(n) + for j in range(i) + ] def main(unused_argv): @@ -103,10 +106,9 @@ def main(unused_argv): solution.Add(z) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase([x[i] for i in range(n)], - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND, + solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() for s in range(num_solutions): diff --git a/examples/python/alphametic.py b/examples/python/alphametic.py index 4393090207..b5501eea1b 100644 --- a/examples/python/alphametic.py +++ b/examples/python/alphametic.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Generic alphametic solver in Google CP Solver. @@ -80,7 +79,7 @@ def main(problem_str="SEND+MORE=MONEY", base=10): # the digits x = [solver.IntVar(0, base - 1, "x[%i]" % i) for i in range(n)] # the sums of each number (e.g. the three numbers SEND, MORE, MONEY) - sums = [solver.IntVar(1, 10 ** (lens[i]) - 1) for i in range(p_len)] + sums = [solver.IntVar(1, 10**(lens[i]) - 1) for i in range(p_len)] # # constraints @@ -92,8 +91,9 @@ def main(problem_str="SEND+MORE=MONEY", base=10): this_len = len(prob) # sum all the digits with proper exponents to a number - solver.Add(sums[ix] == solver.Sum( - [(base ** i) * x[lookup[prob[this_len - i - 1]]] for i in range(this_len)[::-1]])) + solver.Add(sums[ix] == solver.Sum([(base**i) * + x[lookup[prob[this_len - i - 1]]] + for i in range(this_len)[::-1]])) # leading digits must be > 0 solver.Add(x[lookup[prob[0]]] > 0) ix += 1 @@ -108,9 +108,7 @@ def main(problem_str="SEND+MORE=MONEY", base=10): solution.Add(x) solution.Add(sums) - db = solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -123,12 +121,12 @@ def main(problem_str="SEND+MORE=MONEY", base=10): print() for prob in problem: for p in prob: - print(p, end=' ') + print(p, end=" ") print() print() for prob in problem: for p in prob: - print(x[lookup[p]].Value(), end=' ') + print(x[lookup[p]].Value(), end=" ") print() print("sums:", [sums[i].Value() for i in range(p_len)]) @@ -142,13 +140,9 @@ def main(problem_str="SEND+MORE=MONEY", base=10): def test_problems(base=10): problems = [ - "SEND+MORE=MONEY", - "SEND+MOST=MONEY", - "VINGT+CINQ+CINQ=TRENTE", - "EIN+EIN+EIN+EIN=VIER", - "DONALD+GERALD=ROBERT", - "SATURN+URANUS+NEPTUNE+PLUTO+PLANETS", - "WRONG+WRONG=RIGHT" + "SEND+MORE=MONEY", "SEND+MOST=MONEY", "VINGT+CINQ+CINQ=TRENTE", + "EIN+EIN+EIN+EIN=VIER", "DONALD+GERALD=ROBERT", + "SATURN+URANUS+NEPTUNE+PLUTO+PLANETS", "WRONG+WRONG=RIGHT" ] for p in problems: diff --git a/examples/python/appointments.py b/examples/python/appointments.py index 0bd4913c39..4199c24b9b 100644 --- a/examples/python/appointments.py +++ b/examples/python/appointments.py @@ -19,14 +19,14 @@ from ortools.constraint_solver import pywrapcp from ortools.linear_solver import pywraplp parser = argparse.ArgumentParser() -parser.add_argument('--load_min', default = 480, type = int, - help = 'Minimum load in minutes') -parser.add_argument('--load_max', default = 540, type = int, - help = 'Maximum load in minutes') -parser.add_argument('--commute_time', default = 30, type = int, - help = 'Commute time in minutes') -parser.add_argument('--num_workers', default = 98, type = int, - help = 'Maximum number of workers.') +parser.add_argument( + '--load_min', default=480, type=int, help='Minimum load in minutes') +parser.add_argument( + '--load_max', default=540, type=int, help='Maximum load in minutes') +parser.add_argument( + '--commute_time', default=30, type=int, help='Commute time in minutes') +parser.add_argument( + '--num_workers', default=98, type=int, help='Maximum number of workers.') def FindCombinations(durations, load_min, load_max, commute_time): @@ -44,13 +44,13 @@ def FindCombinations(durations, load_min, load_max, commute_time): A matrix where each line is a valid combinations of appointments. """ solver = pywrapcp.Solver('FindCombinations') - variables = [solver.IntVar(0, load_max / (i + commute_time)) - for i in durations] + variables = [ + solver.IntVar(0, load_max / (i + commute_time)) for i in durations + ] lengths = [i + commute_time for i in durations] solver.Add(solver.ScalProd(variables, lengths) >= load_min) solver.Add(solver.ScalProd(variables, lengths) <= load_max) - db = solver.Phase(variables, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(variables, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) results = [] solver.NewSearch(db) @@ -71,11 +71,15 @@ def Select(combinations, loads, max_number_of_workers): pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING) num_vars = len(loads) num_combinations = len(combinations) - variables = [solver.IntVar(0, max_number_of_workers, 's[%d]' % i) - for i in range(num_combinations)] - achieved = [solver.IntVar(0, 1000, 'achieved[%d]' % i) - for i in range(num_vars)] - transposed = [[combinations[type][index] for type in range(num_combinations)] + variables = [ + solver.IntVar(0, max_number_of_workers, 's[%d]' % i) + for i in range(num_combinations) + ] + achieved = [ + solver.IntVar(0, 1000, 'achieved[%d]' % i) for i in range(num_vars) + ] + transposed = [[combinations[type][index] + for type in range(num_combinations)] for index in range(num_vars)] # Maintain the achieved variables. @@ -89,8 +93,9 @@ def Select(combinations, loads, max_number_of_workers): # Simple bound. solver.Add(solver.Sum(variables) <= max_number_of_workers) - obj_vars = [solver.IntVar(0, 1000, 'obj_vars[%d]' % i) - for i in range(num_vars)] + obj_vars = [ + solver.IntVar(0, 1000, 'obj_vars[%d]' % i) for i in range(num_vars) + ] for i in range(num_vars): solver.Add(obj_vars[i] >= achieved[i] - loads[i]) solver.Add(obj_vars[i] >= loads[i] - achieved[i]) @@ -102,26 +107,25 @@ def Select(combinations, loads, max_number_of_workers): # The problem has an optimal solution. if result_status == pywraplp.Solver.OPTIMAL: print('Problem solved in %f milliseconds' % solver.WallTime()) - return solver.Objective().Value(), [int(v.SolutionValue()) - for v in variables] + return solver.Objective().Value(), [ + int(v.SolutionValue()) for v in variables + ] return -1, [] def GetOptimalSchedule(demand, args): """Computes the optimal schedule for the appointment selection problem.""" - combinations = FindCombinations([a[2] for a in demand], - args.load_min, - args.load_max, - args.commute_time) + combinations = FindCombinations([a[2] for a in demand], args.load_min, + args.load_max, args.commute_time) print('found %d possible combinations of appointements' % len(combinations)) - cost, selection = Select(combinations, - [a[0] for a in demand], + cost, selection = Select(combinations, [a[0] for a in demand], args.num_workers) output = [(selection[i], [(combinations[i][t], demand[t][1]) for t in range(len(demand)) if combinations[i][t] != 0]) - for i in range(len(selection)) if selection[i] != 0] + for i in range(len(selection)) + if selection[i] != 0] return cost, output diff --git a/examples/python/assignment.py b/examples/python/assignment.py index 69353040da..db994dfa31 100644 --- a/examples/python/assignment.py +++ b/examples/python/assignment.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Assignment problem in Google CP Solver. @@ -58,18 +57,22 @@ def main(cost, rows, cols): # # total_cost - solver.Add( - total_cost == solver.Sum( - [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip( - x, cost)])) + solver.Add(total_cost == solver.Sum( + [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip(x, cost)])) # exacly one assignment per row, all rows must be assigned - [solver.Add(solver.Sum([x[row][j] for j in range(cols)]) == 1) - for row in range(rows)] + [ + solver.Add(solver.Sum([x[row][j] + for j in range(cols)]) == 1) + for row in range(rows) + ] # zero or one assignments per column - [solver.Add(solver.Sum([x[i][col] for i in range(rows)]) <= 1) - for col in range(cols)] + [ + solver.Add(solver.Sum([x[i][col] + for i in range(rows)]) <= 1) + for col in range(cols) + ] objective = solver.Minimize(total_cost, 1) @@ -81,9 +84,7 @@ def main(cost, rows, cols): solution.Add(total_cost) # db: DecisionBuilder - db = solver.Phase(x_flat, - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db, [objective]) num_solutions = 0 @@ -91,12 +92,12 @@ def main(cost, rows, cols): print("total_cost:", total_cost.Value()) for i in range(rows): for j in range(cols): - print(x[i][j].Value(), end=' ') + print(x[i][j].Value(), end=" ") print() print() for i in range(rows): - print("Task:", i, end=' ') + print("Task:", i, end=" ") for j in range(cols): if x[i][j].Value() == 1: print(" is done by ", j) @@ -117,10 +118,7 @@ def main(cost, rows, cols): # interesting rows = 4 cols = 5 -cost = [[14, 5, 8, 7, 15], - [2, 12, 6, 5, 3], - [7, 8, 3, 9, 7], - [2, 4, 6, 10, 1]] +cost = [[14, 5, 8, 7, 15], [2, 12, 6, 5, 3], [7, 8, 3, 9, 7], [2, 4, 6, 10, 1]] if __name__ == "__main__": main(cost, rows, cols) diff --git a/examples/python/assignment6_mip.py b/examples/python/assignment6_mip.py index dd1ac6fb65..d1dc0bad8d 100644 --- a/examples/python/assignment6_mip.py +++ b/examples/python/assignment6_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Assignment problem using MIP in Google or-tools. @@ -82,14 +81,11 @@ def main(sol='CBC'): # # Optimal solution is 76 # """ - c = [[13, 21, 20, 12, 8, 26, 22, 11], - [12, 36, 25, 41, 40, 11, 4, 8], - [35, 32, 13, 36, 26, 21, 13, 37], - [34, 54, 7, 8, 12, 22, 11, 40], - [21, 6, 45, 18, 24, 34, 12, 48], - [42, 19, 39, 15, 14, 16, 28, 46], - [16, 34, 38, 3, 34, 40, 22, 24], - [26, 20, 5, 17, 45, 31, 37, 43]] + c = [[13, 21, 20, 12, 8, 26, 22, 11], [12, 36, 25, 41, 40, 11, 4, 8], + [35, 32, 13, 36, 26, 21, 13, 37], [34, 54, 7, 8, 12, 22, 11, + 40], [21, 6, 45, 18, 24, 34, 12, 48], + [42, 19, 39, 15, 14, 16, 28, 46], [16, 34, 38, 3, 34, 40, 22, + 24], [26, 20, 5, 17, 45, 31, 37, 43]] # # variables @@ -106,9 +102,7 @@ def main(sol='CBC'): x[i, j] = solver.IntVar(0, 1, 'x[%i,%i]' % (i, j)) # total cost, to be minimized - z = solver.Sum([c[i][j] * x[i, j] - for i in I - for j in J]) + z = solver.Sum([c[i][j] * x[i, j] for i in I for j in J]) # # constraints diff --git a/examples/python/assignment_sat.py b/examples/python/assignment_sat.py index b9ac86687d..59df959140 100644 --- a/examples/python/assignment_sat.py +++ b/examples/python/assignment_sat.py @@ -14,19 +14,15 @@ from __future__ import print_function from ortools.sat.python import cp_model + def main(): # Instantiate a cp model. - cost = [[90, 76, 75, 70, 50, 74, 12, 68], - [35, 85, 55, 65, 48, 101, 70, 83], - [125, 95, 90, 105, 59, 120, 36, 73], - [45, 110, 95, 115, 104, 83, 37, 71], - [60, 105, 80, 75, 59, 62, 93, 88], - [45, 65, 110, 95, 47, 31, 81, 34], - [38, 51, 107, 41, 69, 99, 115, 48], - [47, 85, 57, 71, 92, 77, 109, 36], - [39, 63, 97, 49, 118, 56, 92, 61], - [47, 101, 71, 60, 88, 109, 52, 90]] - + cost = [[90, 76, 75, 70, 50, 74, 12, 68], [35, 85, 55, 65, 48, 101, 70, 83], [ + 125, 95, 90, 105, 59, 120, 36, 73 + ], [45, 110, 95, 115, 104, 83, 37, 71], [60, 105, 80, 75, 59, 62, 93, 88], [ + 45, 65, 110, 95, 47, 31, 81, 34 + ], [38, 51, 107, 41, 69, 99, 115, 48], [47, 85, 57, 71, 92, 77, 109, 36], + [39, 63, 97, 49, 118, 56, 92, 61], [47, 101, 71, 60, 88, 109, 52, 90]] sizes = [10, 7, 3, 12, 15, 4, 11, 5] total_size_max = 15 @@ -55,8 +51,8 @@ def main(): model.Add(sum(sizes[j] * x[i][j] for j in all_tasks) <= total_size_max) # Total cost - model.Add(total_cost == - sum(x[i][j] * cost[i][j] for j in all_tasks for i in all_workers)) + model.Add(total_cost == sum( + x[i][j] * cost[i][j] for j in all_tasks for i in all_workers)) model.Minimize(total_cost) solver = cp_model.CpSolver() diff --git a/examples/python/assignment_with_constraints.py b/examples/python/assignment_with_constraints.py index 1915c84d4e..d92159ff77 100644 --- a/examples/python/assignment_with_constraints.py +++ b/examples/python/assignment_with_constraints.py @@ -13,40 +13,42 @@ from __future__ import print_function from ortools.constraint_solver import pywrapcp + def main(): # Instantiate a cp solver. solver = pywrapcp.Solver('transportation_with_sizes') - cost = [[90, 76, 75, 70, 50, 74], - [35, 85, 55, 65, 48, 101], - [125, 95, 90, 105, 59, 120], - [45, 110, 95, 115, 104, 83], - [60, 105, 80, 75, 59, 62], - [45, 65, 110, 95, 47, 31], - [38, 51, 107, 41, 69, 99], - [47, 85, 57, 71, 92, 77], - [39, 63, 97, 49, 118, 56], - [47, 101, 71, 60, 88, 109], - [17, 39, 103, 64, 61, 92], - [101, 45, 83, 59, 92, 27]] + cost = [[90, 76, 75, 70, 50, 74], [35, 85, 55, 65, 48, + 101], [125, 95, 90, 105, 59, 120], + [45, 110, 95, 115, 104, 83], [60, 105, 80, 75, 59, 62], [ + 45, 65, 110, 95, 47, 31 + ], [38, 51, 107, 41, 69, 99], [47, 85, 57, 71, + 92, 77], [39, 63, 97, 49, 118, 56], + [47, 101, 71, 60, 88, 109], [17, 39, 103, 64, 61, + 92], [101, 45, 83, 59, 92, 27]] - group1 = [[0, 0, 1, 1], # Workers 2, 3 - [0, 1, 0, 1], # Workers 1, 3 - [0, 1, 1, 0], # Workers 1, 2 - [1, 1, 0, 0], # Workers 0, 1 - [1, 0, 1, 0]] # Workers 0, 2 + group1 = [ + [0, 0, 1, 1], # Workers 2, 3 + [0, 1, 0, 1], # Workers 1, 3 + [0, 1, 1, 0], # Workers 1, 2 + [1, 1, 0, 0], # Workers 0, 1 + [1, 0, 1, 0] + ] # Workers 0, 2 - group2 = [[0, 0, 1, 1], # Workers 6, 7 - [0, 1, 0, 1], # Workers 5, 7 - [0, 1, 1, 0], # Workers 5, 6 - [1, 1, 0, 0], # Workers 4, 5 - [1, 0, 0, 1]] # Workers 4, 7 - - group3 = [[0, 0, 1, 1], # Workers 10, 11 - [0, 1, 0, 1], # Workers 9, 11 - [0, 1, 1, 0], # Workers 9, 10 - [1, 0, 1, 0], # Workers 8, 10 - [1, 0, 0, 1]] # Workers 8, 11 + group2 = [ + [0, 0, 1, 1], # Workers 6, 7 + [0, 1, 0, 1], # Workers 5, 7 + [0, 1, 1, 0], # Workers 5, 6 + [1, 1, 0, 0], # Workers 4, 5 + [1, 0, 0, 1] + ] # Workers 4, 7 + group3 = [ + [0, 0, 1, 1], # Workers 10, 11 + [0, 1, 0, 1], # Workers 9, 11 + [0, 1, 1, 0], # Workers 9, 10 + [1, 0, 1, 0], # Workers 8, 10 + [1, 0, 0, 1] + ] # Workers 8, 11 sizes = [10, 7, 3, 12, 15, 4, 11, 5] total_size_max = 15 @@ -66,34 +68,40 @@ def main(): solver.Add(solver.MaxEquality(x[i], work)) x_array = [x[i][j] for i in range(num_workers) for j in range(num_tasks)] - - # Constraints # Each task is assigned to at least one worker. - [solver.Add(solver.Sum(x[i][j] for i in range(num_workers)) >= 1) - for j in range(num_tasks)] + [ + solver.Add(solver.Sum(x[i][j] + for i in range(num_workers)) >= 1) + for j in range(num_tasks) + ] # Total task size for each worker is at most total_size_max - [solver.Add(solver.Sum(sizes[j] * x[i][j] for j in range(num_tasks)) <= total_size_max) - for i in range(num_workers)] + [ + solver.Add( + solver.Sum(sizes[j] * x[i][j] + for j in range(num_tasks)) <= total_size_max) + for i in range(num_workers) + ] # Workers forms valid groups. - solver.Add(solver.AllowedAssignments([works[0], works[1], works[2], works[3]], - group1)) - solver.Add(solver.AllowedAssignments([works[4], works[5], works[6], works[7]], - group2)) - solver.Add(solver.AllowedAssignments([works[8], works[9], works[10], works[11]], - group3)) + solver.Add( + solver.AllowedAssignments([works[0], works[1], works[2], works[3]], + group1)) + solver.Add( + solver.AllowedAssignments([works[4], works[5], works[6], works[7]], + group2)) + solver.Add( + solver.AllowedAssignments([works[8], works[9], works[10], works[11]], + group3)) # Total cost - solver.Add( - total_cost == solver.Sum( - [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip(x, cost)])) + solver.Add(total_cost == solver.Sum( + [solver.ScalProd(x_row, cost_row) for (x_row, cost_row) in zip(x, cost)])) objective = solver.Minimize(total_cost, 1) - db = solver.Phase(x_array, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(x_array, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) # Create a solution collector. @@ -123,5 +131,6 @@ def main(): print() print('Time = ', solver.WallTime(), 'milliseconds') + if __name__ == '__main__': main() diff --git a/examples/python/assignment_with_constraints_sat.py b/examples/python/assignment_with_constraints_sat.py index 394f9b5600..c8f6a0bb68 100644 --- a/examples/python/assignment_with_constraints_sat.py +++ b/examples/python/assignment_with_constraints_sat.py @@ -13,39 +13,41 @@ from __future__ import print_function from ortools.sat.python import cp_model + def main(): # Data. - cost = [[90, 76, 75, 70, 50, 74], - [35, 85, 55, 65, 48, 101], - [125, 95, 90, 105, 59, 120], - [45, 110, 95, 115, 104, 83], - [60, 105, 80, 75, 59, 62], - [45, 65, 110, 95, 47, 31], - [38, 51, 107, 41, 69, 99], - [47, 85, 57, 71, 92, 77], - [39, 63, 97, 49, 118, 56], - [47, 101, 71, 60, 88, 109], - [17, 39, 103, 64, 61, 92], - [101, 45, 83, 59, 92, 27]] + cost = [[90, 76, 75, 70, 50, 74], [35, 85, 55, 65, 48, + 101], [125, 95, 90, 105, 59, 120], + [45, 110, 95, 115, 104, 83], [60, 105, 80, 75, 59, 62], [ + 45, 65, 110, 95, 47, 31 + ], [38, 51, 107, 41, 69, 99], [47, 85, 57, 71, + 92, 77], [39, 63, 97, 49, 118, 56], + [47, 101, 71, 60, 88, 109], [17, 39, 103, 64, 61, + 92], [101, 45, 83, 59, 92, 27]] - group1 = [[0, 0, 1, 1], # Workers 2, 3 - [0, 1, 0, 1], # Workers 1, 3 - [0, 1, 1, 0], # Workers 1, 2 - [1, 1, 0, 0], # Workers 0, 1 - [1, 0, 1, 0]] # Workers 0, 2 + group1 = [ + [0, 0, 1, 1], # Workers 2, 3 + [0, 1, 0, 1], # Workers 1, 3 + [0, 1, 1, 0], # Workers 1, 2 + [1, 1, 0, 0], # Workers 0, 1 + [1, 0, 1, 0] + ] # Workers 0, 2 - group2 = [[0, 0, 1, 1], # Workers 6, 7 - [0, 1, 0, 1], # Workers 5, 7 - [0, 1, 1, 0], # Workers 5, 6 - [1, 1, 0, 0], # Workers 4, 5 - [1, 0, 0, 1]] # Workers 4, 7 - - group3 = [[0, 0, 1, 1], # Workers 10, 11 - [0, 1, 0, 1], # Workers 9, 11 - [0, 1, 1, 0], # Workers 9, 10 - [1, 0, 1, 0], # Workers 8, 10 - [1, 0, 0, 1]] # Workers 8, 11 + group2 = [ + [0, 0, 1, 1], # Workers 6, 7 + [0, 1, 0, 1], # Workers 5, 7 + [0, 1, 1, 0], # Workers 5, 6 + [1, 1, 0, 0], # Workers 4, 5 + [1, 0, 0, 1] + ] # Workers 4, 7 + group3 = [ + [0, 0, 1, 1], # Workers 10, 11 + [0, 1, 0, 1], # Workers 9, 11 + [0, 1, 1, 0], # Workers 9, 10 + [1, 0, 1, 0], # Workers 8, 10 + [1, 0, 0, 1] + ] # Workers 8, 11 sizes = [10, 7, 3, 12, 15, 4, 11, 5] total_size_max = 15 @@ -59,7 +61,8 @@ def main(): model = cp_model.CpModel() # Variables total_cost = model.NewIntVar(0, 1000, 'total_cost') - x = [[model.NewBoolVar('x[%i,%i]' % (i, j)) for j in all_tasks] + x = [[model.NewBoolVar('x[%i,%i]' % (i, j)) + for j in all_tasks] for i in all_workers] works = [model.NewBoolVar('works[%i]' % i) for i in all_workers] @@ -80,11 +83,12 @@ def main(): # Group constraints. model.AddAllowedAssignments([works[0], works[1], works[2], works[3]], group1) model.AddAllowedAssignments([works[4], works[5], works[6], works[7]], group2) - model.AddAllowedAssignments([works[8], works[9], works[10], works[11]], group3) + model.AddAllowedAssignments([works[8], works[9], works[10], works[11]], + group3) # Total cost - model.Add(total_cost == - sum(x[i][j] * cost[i][j] for j in all_tasks for i in all_workers)) + model.Add(total_cost == sum( + x[i][j] * cost[i][j] for j in all_tasks for i in all_workers)) model.Minimize(total_cost) # Solve and output solution. diff --git a/examples/python/bacp.py b/examples/python/bacp.py index cdba8150cb..6c000302d8 100644 --- a/examples/python/bacp.py +++ b/examples/python/bacp.py @@ -17,22 +17,23 @@ from ortools.constraint_solver import pywrapcp parser = argparse.ArgumentParser() -parser.add_argument('--data', default = 'examples/data/bacp/bacp12.txt', - help = 'path to data file') +parser.add_argument( + '--data', default='examples/data/bacp/bacp12.txt', help='path to data file') #----------------helper for binpacking posting---------------- def BinPacking(solver, binvars, weights, loadvars): - '''post the load constraint on bins. + """post the load constraint on bins. constraints forall j: loadvars[j] == sum_i (binvars[i] == j) * weights[i]) - ''' + """ pack = solver.Pack(binvars, len(loadvars)) pack.AddWeightedSumEqualVarDimension(weights, loadvars) solver.Add(pack) solver.Add(solver.SumEquality(loadvars, sum(weights))) + #------------------------------data reading------------------- @@ -55,10 +56,13 @@ def main(args): solver = pywrapcp.Solver('Balanced Academic Curriculum Problem') - x = [solver.IntVar(0, nb_periods - 1, 'x' + str(i)) - for i in range(nb_courses)] - load_vars = [solver.IntVar(0, sum(credits), 'load_vars' + str(i)) - for i in range(nb_periods)] + x = [ + solver.IntVar(0, nb_periods - 1, 'x' + str(i)) for i in range(nb_courses) + ] + load_vars = [ + solver.IntVar(0, sum(credits), 'load_vars' + str(i)) + for i in range(nb_periods) + ] #-------------------post of the constraints-------------- @@ -75,8 +79,7 @@ def main(args): #------------start the search and optimization----------- - db = solver.Phase(x, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.INT_VALUE_DEFAULT) search_log = solver.SearchLog(100000, objective_var) diff --git a/examples/python/blending.py b/examples/python/blending.py index ee466fe806..a5ab10320b 100644 --- a/examples/python/blending.py +++ b/examples/python/blending.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Blending problem in Google or-tools. @@ -72,8 +71,10 @@ def main(sol='CBC'): r = [solver.NumVar(0, solver.Infinity(), 'r[%i]' % i) for i in Raws] s = [solver.NumVar(0, solver.Infinity(), 's[%i]' % i) for i in Scraps] ii = [solver.IntVar(0, solver.Infinity(), 'ii[%i]' % i) for i in Ingos] - metal = [solver.NumVar(Low[j] * Alloy, Up[j] * Alloy, 'metal[%i]' % j) - for j in Metals] + metal = [ + solver.NumVar(Low[j] * Alloy, Up[j] * Alloy, 'metal[%i]' % j) + for j in Metals + ] z = solver.NumVar(0, solver.Infinity(), 'z') @@ -81,18 +82,16 @@ def main(sol='CBC'): # constraints # - solver.Add(z == - solver.Sum([CostMetal[i] * p[i] for i in Metals]) + + solver.Add(z == solver.Sum([CostMetal[i] * p[i] for i in Metals]) + solver.Sum([CostRaw[i] * r[i] for i in Raws]) + solver.Sum([CostScrap[i] * s[i] for i in Scraps]) + solver.Sum([CostIngo[i] * ii[i] for i in Ingos])) for j in Metals: - solver.Add( - metal[j] == p[j] + - solver.Sum([PercRaw[j][k] * r[k] for k in Raws]) + - solver.Sum([PercScrap[j][k] * s[k] for k in Scraps]) + - solver.Sum([PercIngo[j][k] * ii[k] for k in Ingos])) + solver.Add(metal[j] == p[j] + + solver.Sum([PercRaw[j][k] * r[k] for k in Raws]) + + solver.Sum([PercScrap[j][k] * s[k] for k in Scraps]) + + solver.Sum([PercIngo[j][k] * ii[k] for k in Ingos])) solver.Add(solver.Sum(metal) == Alloy) diff --git a/examples/python/broken_weights.py b/examples/python/broken_weights.py index 25739e3d6a..367b43373b 100644 --- a/examples/python/broken_weights.py +++ b/examples/python/broken_weights.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Broken weights problem in Google CP Solver. @@ -93,8 +92,7 @@ def main(m=40, n=4): # -1 is the weights on the left and 1 is on the right. # for i in range(m): - solver.Add(i + 1 == solver.Sum([weights[j] * x[i, j] - for j in range(n)])) + solver.Add(i + 1 == solver.Sum([weights[j] * x[i, j] for j in range(n)])) # objective objective = solver.Minimize(weights[n - 1], 1) @@ -102,8 +100,7 @@ def main(m=40, n=4): # # search and result # - db = solver.Phase(weights + x_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(weights + x_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) search_log = solver.SearchLog(1) diff --git a/examples/python/bus_schedule.py b/examples/python/bus_schedule.py index 5fabc9d1eb..42c4102fce 100644 --- a/examples/python/bus_schedule.py +++ b/examples/python/bus_schedule.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Bus scheduling in Google CP Solver. @@ -83,15 +82,14 @@ def main(num_buses_check=0): objective = solver.Minimize(num_buses, 1) cargs.extend([objective]) - solver.Solve(solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - cargs) + solver.Solve( + solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE), + cargs) num_solutions = collector.SolutionCount() num_buses_check_value = 0 for s in range(num_solutions): - print("x:", [collector.Value(s, x[i]) for i in range(len(x))], end=' ') + print("x:", [collector.Value(s, x[i]) for i in range(len(x))], end=" ") num_buses_check_value = collector.Value(s, num_buses) print(" num_buses:", num_buses_check_value) @@ -104,6 +102,7 @@ def main(num_buses_check=0): if num_buses_check == 0: return num_buses_check_value + if __name__ == "__main__": print("Check for minimun number of buses") num_buses_check = main() diff --git a/examples/python/car.py b/examples/python/car.py index feb6a1d4bb..456b9399a0 100644 --- a/examples/python/car.py +++ b/examples/python/car.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Car sequencing in Google CP Solver. @@ -63,16 +62,11 @@ def main(num_sol=3): [0, 0, 1, 0, 0, 0] # option 5 ] - capacity = [ - (1, 2), - (2, 3), - (1, 3), - (2, 5), - (1, 5) - ] + capacity = [(1, 2), (2, 3), (1, 3), (2, 5), (1, 5)] - optionDemand = [sum([demand[j] * option[i][j] for j in Cars]) - for i in Options] + optionDemand = [ + sum([demand[j] * option[i][j] for j in Cars]) for i in Options + ] # # declare variables @@ -111,8 +105,7 @@ def main(num_sol=3): # # search and result # - db = solver.Phase(slot + setup_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(slot + setup_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -121,9 +114,9 @@ def main(num_sol=3): print("slot:%s" % ",".join([str(slot[i].Value()) for i in Slots])) print("setup:") for o in Options: - print("%i/%i:" % (capacity[o][0], capacity[o][1]), end=' ') + print("%i/%i:" % (capacity[o][0], capacity[o][1]), end=" ") for s in Slots: - print(setup[o, s].Value(), end=' ') + print(setup[o, s].Value(), end=" ") print() print() num_solutions += 1 @@ -139,6 +132,7 @@ def main(num_sol=3): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + num_sol = 3 if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/check_dependencies.py b/examples/python/check_dependencies.py index 22ffdccaf7..258f9db7c9 100644 --- a/examples/python/check_dependencies.py +++ b/examples/python/check_dependencies.py @@ -2,97 +2,113 @@ import logging, sys, inspect from os.path import dirname, abspath from optparse import OptionParser + def log_error_and_exit(error_message): - logging.error(error_message) - raise SystemExit + logging.error(error_message) + raise SystemExit + #try to import setuptools try: - from setuptools import setup, Extension - from setuptools.command import easy_install + from setuptools import setup, Extension + from setuptools.command import easy_install except ImportError: - log_error_and_exit("""setuptools is not installed for \"""" + sys.executable + """\" + log_error_and_exit("""setuptools is not installed for \"""" + sys.executable + + """\" Follow this link for installing instructions : https://pypi.python.org/pypi/setuptools make sure you use \"""" + sys.executable + """\" during the installation""") from pkg_resources import parse_version + def notinstalled(modulename): - return modulename + """ could not be imported for \"""" + sys.executable + """\" + return modulename + """ could not be imported for \"""" + sys.executable + """\" Set PYTHONPATH to the output of this command \"make print-OR_TOOLS_PYTHONPATH\" before running the examples""" + def wrong_module(module_file, modulename): - return """ + return """ The python examples are not importing the """ + modulename + """ module from the sources. Remove the site-package that contains \"""" + module_file + """\", either manually or by using pip, and rerun this script again.""" + # Returns the n_th parent of file def n_dirname(n, file): - directory = file - for x in range(0, n): - directory = dirname(directory) - return directory + directory = file + for x in range(0, n): + directory = dirname(directory) + return directory -if __name__ == '__main__': - parser = OptionParser('Log level') - parser.add_option('-l','--log',type='string',help='Available levels are CRITICAL (3), ERROR (2), WARNING (1), INFO (0), DEBUG (-1)',default='INFO') - options,args = parser.parse_args() - - try: - loglevel = getattr(logging,options.log.upper()) - except AttributeError: - loglevel = {3:logging.CRITICAL, - 2:logging.ERROR, - 1:logging.WARNING, - 0:logging.INFO, - -1:logging.DEBUG, - }[int(options.log)] - - logging.basicConfig(format='[%(levelname)s] %(message)s',stream=sys.stdout, level=loglevel) - - logging.info("Python path : " + sys.executable) - logging.info("Python version : " + sys.version) - logging.info("sys.path : " + str(sys.path)) - ortools_project_path = n_dirname(3, abspath(inspect.getfile(inspect.currentframe()))) - #try to import ortools - try: - import ortools - except ImportError: - logging.error (notinstalled("ortools")) - raise SystemExit +if __name__ == "__main__": + parser = OptionParser("Log level") + parser.add_option( + "-l", + "--log", + type="string", + help= + "Available levels are CRITICAL (3), ERROR (2), WARNING (1), INFO (0), DEBUG (-1)", + default="INFO") + options, args = parser.parse_args() - #check if we're using ortools from the sources or it's binded by pypi's module - ortools_module_file = inspect.getfile(ortools) - ortools_module_path = n_dirname(3, ortools_module_file) - if(ortools_module_path == ortools_project_path): - logging.info("Or-tools is imported from : " + ortools_module_file) - else: - log_error_and_exit(wrong_module(ortools_module_file, "ortools")) + try: + loglevel = getattr(logging, options.log.upper()) + except AttributeError: + loglevel = { + 3: logging.CRITICAL, + 2: logging.ERROR, + 1: logging.WARNING, + 0: logging.INFO, + -1: logging.DEBUG, + }[int(options.log)] - # Check if python can load the libraries' modules - # this is useful when the library architecture is not compatbile with the python executable, - # or when the library's dependencies are not available or not compatible. - from ortools.constraint_solver import _pywrapcp - from ortools.linear_solver import _pywraplp - from ortools.algorithms import _pywrapknapsack_solver - from ortools.graph import _pywrapgraph + logging.basicConfig( + format="[%(levelname)s] %(message)s", stream=sys.stdout, level=loglevel) - #try to import protobuf - try: - import google.protobuf - except ImportError: - log_error_and_exit(notinstalled("protobuf")) + logging.info("Python path : " + sys.executable) + logging.info("Python version : " + sys.version) + logging.info("sys.path : " + str(sys.path)) + ortools_project_path = n_dirname( + 3, abspath(inspect.getfile(inspect.currentframe()))) - #check if we're using protobuf from the sources or it's binded by pypi's module - protobuf_module_file = inspect.getfile(google.protobuf) - protobuf_module_path = n_dirname(7, protobuf_module_file) - if(protobuf_module_path == ortools_project_path): - logging.info("Protobuf is imported from : " + protobuf_module_file) - else: - log_error_and_exit(wrong_module(protobuf_module_file, "protobuf")) + #try to import ortools + try: + import ortools + except ImportError: + logging.error(notinstalled("ortools")) + raise SystemExit - #Check if the protobuf modules were successfully generated - from google.protobuf import descriptor as _descriptor - from google.protobuf import descriptor_pb2 \ No newline at end of file + #check if we're using ortools from the sources or it's binded by pypi's module + ortools_module_file = inspect.getfile(ortools) + ortools_module_path = n_dirname(3, ortools_module_file) + if (ortools_module_path == ortools_project_path): + logging.info("Or-tools is imported from : " + ortools_module_file) + else: + log_error_and_exit(wrong_module(ortools_module_file, "ortools")) + + # Check if python can load the libraries' modules + # this is useful when the library architecture is not compatbile with the python executable, + # or when the library's dependencies are not available or not compatible. + from ortools.constraint_solver import _pywrapcp + from ortools.linear_solver import _pywraplp + from ortools.algorithms import _pywrapknapsack_solver + from ortools.graph import _pywrapgraph + + #try to import protobuf + try: + import google.protobuf + except ImportError: + log_error_and_exit(notinstalled("protobuf")) + + #check if we're using protobuf from the sources or it's binded by pypi's module + protobuf_module_file = inspect.getfile(google.protobuf) + protobuf_module_path = n_dirname(7, protobuf_module_file) + if (protobuf_module_path == ortools_project_path): + logging.info("Protobuf is imported from : " + protobuf_module_file) + else: + log_error_and_exit(wrong_module(protobuf_module_file, "protobuf")) + + #Check if the protobuf modules were successfully generated + from google.protobuf import descriptor as _descriptor + from google.protobuf import descriptor_pb2 diff --git a/examples/python/circuit.py b/examples/python/circuit.py index 6456f5e092..6b66df2803 100644 --- a/examples/python/circuit.py +++ b/examples/python/circuit.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Decomposition of the circuit constraint in Google CP Solver. @@ -109,10 +108,9 @@ def main(n=5): collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE), + [collector]) num_solutions = collector.SolutionCount() for s in range(num_solutions): diff --git a/examples/python/coins3.py b/examples/python/coins3.py index 46125f7a13..ab96b5f193 100644 --- a/examples/python/coins3.py +++ b/examples/python/coins3.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Coin application in Google CP Solver. @@ -82,8 +81,7 @@ def main(): solution.Add(num_coins) solution.AddObjective(num_coins) - db = solver.Phase(x, - solver.CHOOSE_MIN_SIZE_LOWEST_MAX, + db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MAX, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db, [objective]) diff --git a/examples/python/coins_grid.py b/examples/python/coins_grid.py index 186fa84b66..768a397a8b 100644 --- a/examples/python/coins_grid.py +++ b/examples/python/coins_grid.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Coins grid problem in Google CP Solver. @@ -81,8 +80,8 @@ def main(unused_argv): solver.Add(solver.SumEquality([x[(j, i)] for j in range(n)], c)) # sum cols # quadratic horizonal distance var - objective_var = solver.Sum([x[(i, j)] * (i - j) * (i - j) - for i in range(n) for j in range(n)]) + objective_var = solver.Sum( + [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)]) # objective objective = solver.Minimize(objective_var, 1) @@ -98,10 +97,10 @@ def main(unused_argv): collector = solver.LastSolutionCollector(solution) search_log = solver.SearchLog(1000000, objective_var) restart = solver.ConstantRestart(300) - solver.Solve(solver.Phase([x[(i, j)] for i in range(n) for j in range(n)], - solver.CHOOSE_RANDOM, - solver.ASSIGN_MAX_VALUE), - [collector, search_log, objective]) + solver.Solve( + solver.Phase([x[(i, j)] for i in range(n) for j in range(n)], + solver.CHOOSE_RANDOM, solver.ASSIGN_MAX_VALUE), + [collector, search_log, objective]) print "objective:", collector.ObjectiveValue(0) for i in range(n): diff --git a/examples/python/coins_grid_mip.py b/examples/python/coins_grid_mip.py index 03c2cc0361..aa5caca258 100644 --- a/examples/python/coins_grid_mip.py +++ b/examples/python/coins_grid_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Coins grid problem in Google CP Solver. @@ -72,15 +71,12 @@ def main(unused_argv): # sum rows/columns == c for i in range(n): - solver.Add(solver.Sum( - [x[(i, j)] for j in range(n)]) == c) # sum rows - solver.Add(solver.Sum( - [x[(j, i)] for j in range(n)]) == c) # sum cols + solver.Add(solver.Sum([x[(i, j)] for j in range(n)]) == c) # sum rows + solver.Add(solver.Sum([x[(j, i)] for j in range(n)]) == c) # sum cols # quadratic horizonal distance var objective_var = solver.Sum( - [x[(i, j)] * (i - j) * (i - j) - for i in range(n) for j in range(n)]) + [x[(i, j)] * (i - j) * (i - j) for i in range(n) for j in range(n)]) # objective objective = solver.Minimize(objective_var) diff --git a/examples/python/coloring_ip.py b/examples/python/coloring_ip.py index c27614ae6f..37849a1404 100644 --- a/examples/python/coloring_ip.py +++ b/examples/python/coloring_ip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Simple coloring problem using MIP in Google CP Solver. @@ -79,26 +78,9 @@ def main(sol='CBC'): # http://mat.gsia.cmu.edu/COLOR/instances.html # # Note: 1-based (adjusted below) - E = [[1, 2], - [1, 4], - [1, 7], - [1, 9], - [2, 3], - [2, 6], - [2, 8], - [3, 5], - [3, 7], - [3, 10], - [4, 5], - [4, 6], - [4, 10], - [5, 8], - [5, 9], - [6, 11], - [7, 11], - [8, 11], - [9, 11], - [10, 11]] + E = [[1, 2], [1, 4], [1, 7], [1, 9], [2, 3], [2, 6], [2, 8], [3, 5], [3, 7], + [3, 10], [4, 5], [4, 6], [4, 10], [5, 8], [5, 9], [6, 11], [7, 11], + [8, 11], [9, 11], [10, 11]] # # declare variables diff --git a/examples/python/combinatorial_auction2.py b/examples/python/combinatorial_auction2.py index 63a09a66de..bf0ddb1890 100644 --- a/examples/python/combinatorial_auction2.py +++ b/examples/python/combinatorial_auction2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Combinatorial auction in Google CP Solver. @@ -49,11 +48,11 @@ def main(): # the items for each bid items = [ - [0, 1], # A,B - [0, 2], # A, C - [1, 3], # B,D + [0, 1], # A,B + [0, 2], # A, C + [1, 3], # B,D [1, 2, 3], # B,C,D - [0] # A + [0] # A ] # collect the bids for each item items_t = defaultdict(list) @@ -88,9 +87,7 @@ def main(): solution.Add(obj) # db: DecisionBuilder - db = solver.Phase(X, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db, [objective]) num_solutions = 0 @@ -108,5 +105,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/contiguity_regular.py b/examples/python/contiguity_regular.py index 05cd9b186d..942e55d9eb 100644 --- a/examples/python/contiguity_regular.py +++ b/examples/python/contiguity_regular.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Global constraint contiguity using regularin Google CP Solver. @@ -109,8 +108,8 @@ def regular(x, Q, S, d, q0, F): solver.Add(x[i] <= S) # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] - solver.Add( - a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1))) + solver.Add(a[i + 1] == solver.Element(d2_flatten, ( + (a[i]) * S) + (x[i] - 1))) def main(): @@ -148,14 +147,13 @@ def main(): # # constraints # - regular(reg_input, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(reg_input, n_states, input_max, transition_fn, initial_state, + accepting_states) # # solution and search # - db = solver.Phase(reg_input, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(reg_input, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/costas_array.py b/examples/python/costas_array.py index 4759811548..edb5797b0a 100644 --- a/examples/python/costas_array.py +++ b/examples/python/costas_array.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Costas array in Google CP Solver. @@ -113,8 +112,8 @@ def main(n=6): # "All entries in a particular row of the difference # triangle must be distint." for i in range(n - 2): - solver.Add(solver.AllDifferent([differences[i, j] - for j in range(n) if j > i])) + solver.Add( + solver.AllDifferent([differences[i, j] for j in range(n) if j > i])) # # "All the following are redundant - only here to speed up search." @@ -129,16 +128,13 @@ def main(n=6): for k in range(2, n): for l in range(2, n): if k < l: - solver.Add(differences[k - 2, l - 1] + - differences[k, l] == - differences[k - 1, l - 1] + - differences[k - 1, l]) + solver.Add(differences[k - 2, l - 1] + differences[k, l] == + differences[k - 1, l - 1] + differences[k - 1, l]) # # search and result # - db = solver.Phase(costas + differences_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(costas + differences_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -150,9 +146,9 @@ def main(n=6): for j in range(n): v = differences[i, j].Value() if v == -n + 1: - print(" ", end=' ') + print(" ", end=" ") else: - print("%2d" % v, end=' ') + print("%2d" % v, end=" ") print() print() num_solutions += 1 @@ -165,6 +161,7 @@ def main(n=6): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + n = 6 if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/covering_opl.py b/examples/python/covering_opl.py index 17fa265b02..097b9a108f 100644 --- a/examples/python/covering_opl.py +++ b/examples/python/covering_opl.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering problem in Google CP Solver. @@ -77,27 +76,22 @@ def main(): # Which worker is qualified for each task. # Note: This is 1-based and will be made 0-base below. - Qualified = [ - [1, 9, 19, 22, 25, 28, 31], - [2, 12, 15, 19, 21, 23, 27, 29, 30, 31, 32], - [3, 10, 19, 24, 26, 30, 32], - [4, 21, 25, 28, 32], - [5, 11, 16, 22, 23, 27, 31], - [6, 20, 24, 26, 30, 32], - [7, 12, 17, 25, 30, 31], - [8, 17, 20, 22, 23], - [9, 13, 14, 26, 29, 30, 31], - [10, 21, 25, 31, 32], - [14, 15, 18, 23, 24, 27, 30, 32], - [18, 19, 22, 24, 26, 29, 31], - [11, 20, 25, 28, 30, 32], - [16, 19, 23, 31], - [9, 18, 26, 28, 31, 32] - ] + Qualified = [[1, 9, 19, 22, 25, 28, + 31], [2, 12, 15, 19, 21, 23, 27, 29, 30, 31, + 32], [3, 10, 19, 24, 26, 30, 32], [4, 21, 25, 28, 32], + [5, 11, 16, 22, 23, 27, 31], [6, 20, 24, 26, + 30, 32], [7, 12, 17, 25, 30, + 31], [8, 17, 20, 22, 23], + [9, 13, 14, 26, 29, 30, + 31], [10, 21, 25, 31, 32], [14, 15, 18, 23, 24, 27, 30, 32], [ + 18, 19, 22, 24, 26, 29, 31 + ], [11, 20, 25, 28, 30, 32], [16, 19, 23, + 31], [9, 18, 26, 28, 31, 32]] Cost = [ - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, - 5, 5, 6, 6, 6, 7, 8, 9] + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, + 5, 6, 6, 6, 7, 8, 9 + ] # # variables @@ -122,9 +116,7 @@ def main(): # # search and result # - db = solver.Phase(Hire, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(Hire, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db, [objective]) @@ -132,10 +124,10 @@ def main(): while solver.NextSolution(): num_solutions += 1 print("Total cost", total_cost.Value()) - print("We should hire these workers: ", end=' ') + print("We should hire these workers: ", end=" ") for w in Workers: if Hire[w].Value() == 1: - print(w, end=' ') + print(w, end=" ") print() print() diff --git a/examples/python/cp_is_fun_sat.py b/examples/python/cp_is_fun_sat.py index 3c6065f0b5..9e7d920c90 100644 --- a/examples/python/cp_is_fun_sat.py +++ b/examples/python/cp_is_fun_sat.py @@ -10,9 +10,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -""" -Cryptarithmetic puzzle +"""Cryptarithmetic puzzle First attempt to solve equation CP + IS + FUN = TRUE where each letter represents a unique digit. @@ -23,6 +21,7 @@ This problem has 72 different solutions in base 10. from __future__ import print_function from ortools.sat.python import cp_model + class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback): """Print intermediate solutions.""" @@ -33,7 +32,7 @@ class VarArraySolutionPrinter(cp_model.CpSolverSolutionCallback): def NewSolution(self): self.__solution_count += 1 for v in self.__variables: - print('%s=%i' % (v, self.Value(v)), end = ' ') + print('%s=%i' % (v, self.Value(v)), end=' ') print() def SolutionCount(self): @@ -47,16 +46,16 @@ def CPIsFun(): # Constraint programming engine model = cp_model.CpModel() - c = model.NewIntVar(1, 9, 'C'); - p = model.NewIntVar(0, 9, 'P'); - i = model.NewIntVar(1, 9, 'I'); - s = model.NewIntVar(0, 9, 'S'); - f = model.NewIntVar(1, 9, 'F'); - u = model.NewIntVar(0, 9, 'U'); - n = model.NewIntVar(0, 9, 'N'); - t = model.NewIntVar(1, 9, 'T'); - r = model.NewIntVar(0, 9, 'R'); - e = model.NewIntVar(0, 9, 'E'); + c = model.NewIntVar(1, 9, 'C') + p = model.NewIntVar(0, 9, 'P') + i = model.NewIntVar(1, 9, 'I') + s = model.NewIntVar(0, 9, 'S') + f = model.NewIntVar(1, 9, 'F') + u = model.NewIntVar(0, 9, 'U') + n = model.NewIntVar(0, 9, 'N') + t = model.NewIntVar(1, 9, 'T') + r = model.NewIntVar(0, 9, 'R') + e = model.NewIntVar(0, 9, 'E') # We need to group variables in a list to use the constraint AllDifferent. letters = [c, p, i, s, f, u, n, t, r, e] @@ -68,8 +67,8 @@ def CPIsFun(): model.AddAllDifferent(letters) # CP + IS + FUN = TRUE - model.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f == - e + kBase * u + kBase * kBase * r + kBase * kBase * kBase * t) + model.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f == e + + kBase * u + kBase * kBase * r + kBase * kBase * kBase * t) solver = cp_model.CpSolver() status = solver.Solve(model) diff --git a/examples/python/crew.py b/examples/python/crew.py index cffde60cdf..b3acc71f11 100644 --- a/examples/python/crew.py +++ b/examples/python/crew.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Crew allocation problem in Google CP Solver. @@ -51,51 +50,36 @@ def main(sols=1): # # data # - names = ["Tom", - "David", - "Jeremy", - "Ron", - "Joe", - "Bill", - "Fred", - "Bob", - "Mario", - "Ed", - "Carol", - "Janet", - "Tracy", - "Marilyn", - "Carolyn", - "Cathy", - "Inez", - "Jean", - "Heather", - "Juliet"] + names = [ + "Tom", "David", "Jeremy", "Ron", "Joe", "Bill", "Fred", "Bob", "Mario", + "Ed", "Carol", "Janet", "Tracy", "Marilyn", "Carolyn", "Cathy", "Inez", + "Jean", "Heather", "Juliet" + ] num_persons = len(names) # number of persons attributes = [ # steward, hostess, french, spanish, german - [1, 0, 0, 0, 1], # Tom = 1 - [1, 0, 0, 0, 0], # David = 2 - [1, 0, 0, 0, 1], # Jeremy = 3 - [1, 0, 0, 0, 0], # Ron = 4 - [1, 0, 0, 1, 0], # Joe = 5 - [1, 0, 1, 1, 0], # Bill = 6 - [1, 0, 0, 1, 0], # Fred = 7 - [1, 0, 0, 0, 0], # Bob = 8 - [1, 0, 0, 1, 1], # Mario = 9 - [1, 0, 0, 0, 0], # Ed = 10 - [0, 1, 0, 0, 0], # Carol = 11 - [0, 1, 0, 0, 0], # Janet = 12 - [0, 1, 0, 0, 0], # Tracy = 13 - [0, 1, 0, 1, 1], # Marilyn = 14 - [0, 1, 0, 0, 0], # Carolyn = 15 - [0, 1, 0, 0, 0], # Cathy = 16 - [0, 1, 1, 1, 1], # Inez = 17 - [0, 1, 1, 0, 0], # Jean = 18 - [0, 1, 0, 1, 1], # Heather = 19 - [0, 1, 1, 0, 0] # Juliet = 20 + [1, 0, 0, 0, 1], # Tom = 1 + [1, 0, 0, 0, 0], # David = 2 + [1, 0, 0, 0, 1], # Jeremy = 3 + [1, 0, 0, 0, 0], # Ron = 4 + [1, 0, 0, 1, 0], # Joe = 5 + [1, 0, 1, 1, 0], # Bill = 6 + [1, 0, 0, 1, 0], # Fred = 7 + [1, 0, 0, 0, 0], # Bob = 8 + [1, 0, 0, 1, 1], # Mario = 9 + [1, 0, 0, 0, 0], # Ed = 10 + [0, 1, 0, 0, 0], # Carol = 11 + [0, 1, 0, 0, 0], # Janet = 12 + [0, 1, 0, 0, 0], # Tracy = 13 + [0, 1, 0, 1, 1], # Marilyn = 14 + [0, 1, 0, 0, 0], # Carolyn = 15 + [0, 1, 0, 0, 0], # Cathy = 16 + [0, 1, 1, 1, 1], # Inez = 17 + [0, 1, 1, 0, 0], # Jean = 18 + [0, 1, 0, 1, 1], # Heather = 19 + [0, 1, 1, 0, 0] # Juliet = 20 ] # The columns are in the following order: @@ -127,8 +111,9 @@ def main(sols=1): for i in range(num_flights): for j in range(num_persons): crew[(i, j)] = solver.IntVar(0, 1, "crew[%i,%i]" % (i, j)) - crew_flat = [crew[(i, j)] for i in range(num_flights) - for j in range(num_persons)] + crew_flat = [ + crew[(i, j)] for i in range(num_flights) for j in range(num_persons) + ] # number of working persons num_working = solver.IntVar(1, num_persons, "num_working") @@ -138,10 +123,12 @@ def main(sols=1): # # number of working persons - solver.Add(num_working == solver.Sum( - [solver.IsGreaterOrEqualCstVar(solver.Sum([crew[(f, p)] - for f in range(num_flights)]), 1) - for p in range(num_persons)])) + solver.Add(num_working == solver.Sum([ + solver.IsGreaterOrEqualCstVar( + solver.Sum([crew[(f, p)] + for f in range(num_flights)]), 1) + for p in range(num_persons) + ])) for f in range(num_flights): # size of crew @@ -169,8 +156,7 @@ def main(sols=1): solution.Add(crew_flat) solution.Add(num_working) - db = solver.Phase(crew_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(crew_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) # @@ -184,25 +170,25 @@ def main(sols=1): print("Number working:", num_working.Value()) for i in range(num_flights): for j in range(num_persons): - print(crew[i, j].Value(), end=' ') + print(crew[i, j].Value(), end=" ") print() print() print("Flights:") for flight in range(num_flights): - print("Flight", flight, "persons:", end=' ') + print("Flight", flight, "persons:", end=" ") for person in range(num_persons): if crew[flight, person].Value() == 1: - print(names[person], end=' ') + print(names[person], end=" ") print() print() print("Crew:") for person in range(num_persons): - print("%-10s flights" % names[person], end=' ') + print("%-10s flights" % names[person], end=" ") for flight in range(num_flights): if crew[flight, person].Value() == 1: - print(flight, end=' ') + print(flight, end=" ") print() print() @@ -216,6 +202,7 @@ def main(sols=1): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + num_solutions_to_show = 1 if __name__ == "__main__": if (len(sys.argv) > 1): diff --git a/examples/python/crossword2.py b/examples/python/crossword2.py index 5c079a3b82..7f9f17a4d7 100644 --- a/examples/python/crossword2.py +++ b/examples/python/crossword2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Crosswords in Google CP Solver. @@ -120,15 +119,12 @@ def main(): overlapping = [ [0, 2, 1, 0], # s [0, 4, 2, 0], # s - [3, 1, 1, 2], # i [3, 2, 4, 0], # k [3, 3, 2, 2], # e - [6, 0, 1, 3], # l [6, 1, 4, 1], # e [6, 2, 2, 3], # e - [7, 0, 5, 1], # l [7, 2, 1, 4], # s [7, 3, 4, 2], # e @@ -161,10 +157,9 @@ def main(): # But we must use Element explicitly solver.Add( - solver.Element( - A_flat, E[overlapping[I][0]] * word_len + overlapping[I][1]) == - solver.Element( - A_flat, E[overlapping[I][2]] * word_len + overlapping[I][3])) + solver.Element(A_flat, E[overlapping[I][0]] * word_len + + overlapping[I][1]) == solver. + Element(A_flat, E[overlapping[I][2]] * word_len + overlapping[I][3])) # # solution and search @@ -173,9 +168,7 @@ def main(): solution.Add(E) # db: DecisionBuilder - db = solver.Phase(E + A_flat, - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(E + A_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -194,8 +187,9 @@ def main(): def print_solution(A, E, alpha, n, word_len): for ee in range(n): - print("%i: (%2i)" % (ee, E[ee].Value()), end=' ') - print("".join(["%s" % (alpha[A[ee, ii].Value()]) for ii in range(word_len)])) + print("%i: (%2i)" % (ee, E[ee].Value()), end=" ") + print("".join( + ["%s" % (alpha[A[ee, ii].Value()]) for ii in range(word_len)])) if __name__ == "__main__": diff --git a/examples/python/crypta.py b/examples/python/crypta.py index 9df9b0eac2..498015966f 100644 --- a/examples/python/crypta.py +++ b/examples/python/crypta.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Cryptarithmetic puzzle in Google CP Solver. @@ -74,24 +73,24 @@ def main(): solver.Add(D >= 1) solver.Add(G >= 1) - solver.Add(A + 10 * E + 100 * J + 1000 * B + 10000 * B + 100000 * E + 1000000 * F + - E + 10 * J + 100 * E + 1000 * F + 10000 * G + 100000 * A + 1000000 * F - == F + 10 * E + 100 * E + 1000 * H + 10000 * I + 100000 * F + 1000000 * B + 10000000 * Sr1) + solver.Add(A + 10 * E + 100 * J + 1000 * B + 10000 * B + 100000 * E + + 1000000 * F + E + 10 * J + 100 * E + 1000 * F + 10000 * G + + 100000 * A + 1000000 * F == F + 10 * E + 100 * E + 1000 * H + + 10000 * I + 100000 * F + 1000000 * B + 10000000 * Sr1) - solver.Add(C + 10 * F + 100 * H + 1000 * A + 10000 * I + 100000 * I + 1000000 * J + - F + 10 * I + 100 * B + 1000 * D + 10000 * I + 100000 * D + 1000000 * C + Sr1 - == J + 10 * F + 100 * A + 1000 * F + 10000 * H + 100000 * D + 1000000 * D + 10000000 * Sr2) + solver.Add(C + 10 * F + 100 * H + 1000 * A + 10000 * I + 100000 * I + + 1000000 * J + F + 10 * I + 100 * B + 1000 * D + 10000 * I + + 100000 * D + 1000000 * C + Sr1 == J + 10 * F + 100 * A + 1000 * F + + 10000 * H + 100000 * D + 1000000 * D + 10000000 * Sr2) - solver.Add(A + 10 * J + 100 * J + 1000 * I + 10000 * A + 100000 * B + - B + 10 * A + 100 * G + 1000 * F + 10000 * H + 100000 * D + Sr2 - == C + 10 * A + 100 * G + 1000 * E + 10000 * J + 100000 * G) + solver.Add(A + 10 * J + 100 * J + 1000 * I + 10000 * A + 100000 * B + B + + 10 * A + 100 * G + 1000 * F + 10000 * H + 100000 * D + Sr2 == C + + 10 * A + 100 * G + 1000 * E + 10000 * J + 100000 * G) # # search and result # - db = solver.Phase(LD, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_SIMPLE) + db = solver.Phase(LD, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) solver.NewSearch(db) diff --git a/examples/python/crypto.py b/examples/python/crypto.py index 885f69c1f8..d1ec075891 100644 --- a/examples/python/crypto.py +++ b/examples/python/crypto.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Crypto problem in Google CP Solver. @@ -112,8 +111,7 @@ def main(): # # search and result # - db = solver.Phase(LD, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(LD, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db) diff --git a/examples/python/curious_set_of_integers.py b/examples/python/curious_set_of_integers.py index a9415e4499..2c09cec33a 100644 --- a/examples/python/curious_set_of_integers.py +++ b/examples/python/curious_set_of_integers.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Crypto problem in Google CP Solver. @@ -105,8 +104,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/cvrp.py b/examples/python/cvrp.py index 1656c8e3de..a575fd9987 100755 --- a/examples/python/cvrp.py +++ b/examples/python/cvrp.py @@ -13,9 +13,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Capacitated Vehicle Routing Problem (CVRP). - This is a sample using the routing library python wrapper to solve a CVRP problem. + + This is a sample using the routing library python wrapper to solve a CVRP + problem. A description of the problem can be found here: http://en.wikipedia.org/wiki/Vehicle_routing_problem. @@ -31,229 +32,243 @@ from six.moves import xrange from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 + ########################### # Problem Data Definition # ########################### class Vehicle(): - """Stores the property of a vehicle""" - def __init__(self): - """Initializes the vehicle properties""" - self._capacity = 15 + """Stores the property of a vehicle""" + + def __init__(self): + """Initializes the vehicle properties""" + self._capacity = 15 + + @property + def capacity(self): + """Gets vehicle capacity""" + return self._capacity - @property - def capacity(self): - """Gets vehicle capacity""" - return self._capacity class CityBlock(): - """City block definition""" - @property - def width(self): - """Gets Block size West to East""" - return 228/2 + """City block definition""" + + @property + def width(self): + """Gets Block size West to East""" + return 228 / 2 + + @property + def height(self): + """Gets Block size North to South""" + return 80 - @property - def height(self): - """Gets Block size North to South""" - return 80 class DataProblem(): - """Stores the data for the problem""" - def __init__(self): - """Initializes the data for the problem""" - self._vehicle = Vehicle() - self._num_vehicles = 4 + """Stores the data for the problem""" - # Locations in block unit - locations = \ - [(4, 4), # depot - (2, 0), (8, 0), # row 0 - (0, 1), (1, 1), - (5, 2), (7, 2), - (3, 3), (6, 3), - (5, 5), (8, 5), - (1, 6), (2, 6), - (3, 7), (6, 7), - (0, 8), (7, 8)] - # locations in meters using the block dimension defined - city_block = CityBlock() - self._locations = [( - loc[0]*city_block.width, - loc[1]*city_block.height) for loc in locations] + def __init__(self): + """Initializes the data for the problem""" + self._vehicle = Vehicle() + self._num_vehicles = 4 - self._depot = 0 + # Locations in block unit + locations = \ + [(4, 4), # depot + (2, 0), (8, 0), # row 0 + (0, 1), (1, 1), + (5, 2), (7, 2), + (3, 3), (6, 3), + (5, 5), (8, 5), + (1, 6), (2, 6), + (3, 7), (6, 7), + (0, 8), (7, 8)] + # locations in meters using the block dimension defined + city_block = CityBlock() + self._locations = [(loc[0] * city_block.width, loc[1] * city_block.height) + for loc in locations] - self._demands = \ - [0, # depot - 1, 1, # row 0 - 2, 4, - 2, 4, - 8, 8, - 1, 2, - 1, 2, - 4, 4, - 8, 8] + self._depot = 0 - @property - def vehicle(self): - """Gets a vehicle""" - return self._vehicle + self._demands = \ + [0, # depot + 1, 1, # row 0 + 2, 4, + 2, 4, + 8, 8, + 1, 2, + 1, 2, + 4, 4, + 8, 8] - @property - def num_vehicles(self): - """Gets number of vehicles""" - return self._num_vehicles + @property + def vehicle(self): + """Gets a vehicle""" + return self._vehicle - @property - def locations(self): - """Gets locations""" - return self._locations + @property + def num_vehicles(self): + """Gets number of vehicles""" + return self._num_vehicles - @property - def num_locations(self): - """Gets number of locations""" - return len(self.locations) + @property + def locations(self): + """Gets locations""" + return self._locations - @property - def depot(self): - """Gets depot location index""" - return self._depot + @property + def num_locations(self): + """Gets number of locations""" + return len(self.locations) + + @property + def depot(self): + """Gets depot location index""" + return self._depot + + @property + def demands(self): + """Gets demands at each location""" + return self._demands - @property - def demands(self): - """Gets demands at each location""" - return self._demands ####################### # Problem Constraints # ####################### def manhattan_distance(position_1, position_2): - """Computes the Manhattan distance between two points""" - return (abs(position_1[0] - position_2[0]) + - abs(position_1[1] - position_2[1])) + """Computes the Manhattan distance between two points""" + return ( + abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1])) -class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to return distance between points.""" - def __init__(self, data): - """Initializes the distance matrix.""" - self._distances = {} - # precompute distance between location to have distance callback in O(1) - for from_node in xrange(data.num_locations): - self._distances[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._distances[from_node][to_node] = 0 - else: - self._distances[from_node][to_node] = ( - manhattan_distance( - data.locations[from_node], - data.locations[to_node])) +class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to return distance between points.""" - def distance_evaluator(self, from_node, to_node): - """Returns the manhattan distance between the two nodes""" - return self._distances[from_node][to_node] + def __init__(self, data): + """Initializes the distance matrix.""" + self._distances = {} -class CreateDemandEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to get demands at each location.""" - def __init__(self, data): - """Initializes the demand array.""" - self._demands = data.demands + # precompute distance between location to have distance callback in O(1) + for from_node in xrange(data.num_locations): + self._distances[from_node] = {} + for to_node in xrange(data.num_locations): + if from_node == to_node: + self._distances[from_node][to_node] = 0 + else: + self._distances[from_node][to_node] = ( + manhattan_distance(data.locations[from_node], + data.locations[to_node])) + + def distance_evaluator(self, from_node, to_node): + """Returns the manhattan distance between the two nodes""" + return self._distances[from_node][to_node] + + +class CreateDemandEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to get demands at each location.""" + + def __init__(self, data): + """Initializes the demand array.""" + self._demands = data.demands + + def demand_evaluator(self, from_node, to_node): + """Returns the demand of the current node""" + del to_node + return self._demands[from_node] - def demand_evaluator(self, from_node, to_node): - """Returns the demand of the current node""" - del to_node - return self._demands[from_node] def add_capacity_constraints(routing, data, demand_evaluator): - """Adds capacity constraint""" - capacity = "Capacity" - routing.AddDimension( - demand_evaluator, - 0, # null capacity slack - data.vehicle.capacity, - True, # start cumul to zero - capacity) + """Adds capacity constraint""" + capacity = 'Capacity' + routing.AddDimension( + demand_evaluator, + 0, # null capacity slack + data.vehicle.capacity, + True, # start cumul to zero + capacity) + ########### # Printer # ########### class ConsolePrinter(): - """Print solution to console""" - def __init__(self, data, routing, assignment): - """Initializes the printer""" - self._data = data - self._routing = routing - self._assignment = assignment + """Print solution to console""" - @property - def data(self): - """Gets problem data""" - return self._data + def __init__(self, data, routing, assignment): + """Initializes the printer""" + self._data = data + self._routing = routing + self._assignment = assignment - @property - def routing(self): - """Gets routing model""" - return self._routing + @property + def data(self): + """Gets problem data""" + return self._data - @property - def assignment(self): - """Gets routing model""" - return self._assignment + @property + def routing(self): + """Gets routing model""" + return self._routing - def print(self): - """Prints assignment on console""" - # Inspect solution. - total_dist = 0 - for vehicle_id in xrange(self.data.num_vehicles): - index = self.routing.Start(vehicle_id) - plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) - route_dist = 0 - route_load = 0 - while not self.routing.IsEnd(index): - node_index = self.routing.IndexToNode(index) - next_node_index = self.routing.IndexToNode( - self.assignment.Value(self.routing.NextVar(index))) - route_dist += manhattan_distance( - self.data.locations[node_index], - self.data.locations[next_node_index]) - route_load += self.data.demands[node_index] - plan_output += ' {0} Load({1}) -> '.format(node_index, route_load) - index = self.assignment.Value(self.routing.NextVar(index)) + @property + def assignment(self): + """Gets routing model""" + return self._assignment + + def print(self): + """Prints assignment on console""" + # Inspect solution. + total_dist = 0 + for vehicle_id in xrange(self.data.num_vehicles): + index = self.routing.Start(vehicle_id) + plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) + route_dist = 0 + route_load = 0 + while not self.routing.IsEnd(index): + node_index = self.routing.IndexToNode(index) + next_node_index = self.routing.IndexToNode( + self.assignment.Value(self.routing.NextVar(index))) + route_dist += manhattan_distance(self.data.locations[node_index], + self.data.locations[next_node_index]) + route_load += self.data.demands[node_index] + plan_output += ' {0} Load({1}) -> '.format(node_index, route_load) + index = self.assignment.Value(self.routing.NextVar(index)) + + node_index = self.routing.IndexToNode(index) + total_dist += route_dist + plan_output += ' {0} Load({1})\n'.format(node_index, route_load) + plan_output += 'Distance of the route: {0}m\n'.format(route_dist) + plan_output += 'Load of the route: {0}\n'.format(route_load) + print(plan_output) + print('Total Distance of all routes: {0}m'.format(total_dist)) - node_index = self.routing.IndexToNode(index) - total_dist += route_dist - plan_output += ' {0} Load({1})\n'.format(node_index, route_load) - plan_output += 'Distance of the route: {0}m\n'.format(route_dist) - plan_output += 'Load of the route: {0}\n'.format(route_load) - print(plan_output) - print('Total Distance of all routes: {0}m'.format(total_dist)) ######## # Main # ######## def main(): - """Entry point of the program""" - # Instantiate the data problem. - data = DataProblem() + """Entry point of the program""" + # Instantiate the data problem. + data = DataProblem() - # Create Routing Model - routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, data.depot) - # Define weight of each edge - distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator - routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) - # Add Capacity constraint - demand_evaluator = CreateDemandEvaluator(data).demand_evaluator - add_capacity_constraints(routing, data, demand_evaluator) + # Create Routing Model + routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, + data.depot) + # Define weight of each edge + distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator + routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) + # Add Capacity constraint + demand_evaluator = CreateDemandEvaluator(data).demand_evaluator + add_capacity_constraints(routing, data, demand_evaluator) + + # Setting first solution heuristic (cheapest addition). + search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # Solve the problem. + assignment = routing.SolveWithParameters(search_parameters) + printer = ConsolePrinter(data, routing, assignment) + printer. print() - # Setting first solution heuristic (cheapest addition). - search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() - search_parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) - # Solve the problem. - assignment = routing.SolveWithParameters(search_parameters) - printer = ConsolePrinter(data, routing, assignment) - printer.print() if __name__ == '__main__': - main() + main() diff --git a/examples/python/cvrptw.py b/examples/python/cvrptw.py index 6598e5b48d..9ce2615d11 100755 --- a/examples/python/cvrptw.py +++ b/examples/python/cvrptw.py @@ -13,9 +13,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Capacitated Vehicle Routing Problem with Time Windows (CVRPTW). - This is a sample using the routing library python wrapper to solve a CVRPTW problem. + + This is a sample using the routing library python wrapper to solve a CVRPTW + problem. A description of the problem can be found here: http://en.wikipedia.org/wiki/Vehicle_routing_problem. @@ -31,349 +32,362 @@ from six.moves import xrange from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 + ########################### # Problem Data Definition # ########################### class Vehicle(): - """Stores the property of a vehicle""" - def __init__(self): - """Initializes the vehicle properties""" - self._capacity = 15 - # Travel speed: 5km/h to convert in m/min - self._speed = 5 * 60 / 3.6 + """Stores the property of a vehicle""" - @property - def capacity(self): - """Gets vehicle capacity""" - return self._capacity + def __init__(self): + """Initializes the vehicle properties""" + self._capacity = 15 + # Travel speed: 5km/h to convert in m/min + self._speed = 5 * 60 / 3.6 + + @property + def capacity(self): + """Gets vehicle capacity""" + return self._capacity + + @property + def speed(self): + """Gets the average travel speed of a vehicle""" + return self._speed - @property - def speed(self): - """Gets the average travel speed of a vehicle""" - return self._speed class CityBlock(): - """City block definition""" - @property - def width(self): - """Gets Block size West to East""" - return 228/2 + """City block definition""" + + @property + def width(self): + """Gets Block size West to East""" + return 228 / 2 + + @property + def height(self): + """Gets Block size North to South""" + return 80 - @property - def height(self): - """Gets Block size North to South""" - return 80 class DataProblem(): - """Stores the data for the problem""" - def __init__(self): - """Initializes the data for the problem""" - self._vehicle = Vehicle() - self._num_vehicles = 4 + """Stores the data for the problem""" - # Locations in block unit - locations = \ - [(4, 4), # depot - (2, 0), (8, 0), # row 0 - (0, 1), (1, 1), - (5, 2), (7, 2), - (3, 3), (6, 3), - (5, 5), (8, 5), - (1, 6), (2, 6), - (3, 7), (6, 7), - (0, 8), (7, 8)] - # locations in meters using the city block dimension - city_block = CityBlock() - self._locations = [( - loc[0]*city_block.width, - loc[1]*city_block.height) for loc in locations] + def __init__(self): + """Initializes the data for the problem""" + self._vehicle = Vehicle() + self._num_vehicles = 4 - self._depot = 0 + # Locations in block unit + locations = \ + [(4, 4), # depot + (2, 0), (8, 0), # row 0 + (0, 1), (1, 1), + (5, 2), (7, 2), + (3, 3), (6, 3), + (5, 5), (8, 5), + (1, 6), (2, 6), + (3, 7), (6, 7), + (0, 8), (7, 8)] + # locations in meters using the city block dimension + city_block = CityBlock() + self._locations = [(loc[0] * city_block.width, loc[1] * city_block.height) + for loc in locations] - self._demands = \ - [0, # depot - 1, 1, # 1, 2 - 2, 4, # 3, 4 - 2, 4, # 5, 6 - 8, 8, # 7, 8 - 1, 2, # 9,10 - 1, 2, # 11,12 - 4, 4, # 13, 14 - 8, 8] # 15, 16 + self._depot = 0 - self._time_windows = \ - [(0, 0), - (75, 85), (75, 85), # 1, 2 - (60, 70), (45, 55), # 3, 4 - (0, 8), (50, 60), # 5, 6 - (0, 10), (10, 20), # 7, 8 - (0, 10), (75, 85), # 9, 10 - (85, 95), (5, 15), # 11, 12 - (15, 25), (10, 20), # 13, 14 - (45, 55), (30, 40)] # 15, 16 + self._demands = \ + [0, # depot + 1, 1, # 1, 2 + 2, 4, # 3, 4 + 2, 4, # 5, 6 + 8, 8, # 7, 8 + 1, 2, # 9,10 + 1, 2, # 11,12 + 4, 4, # 13, 14 + 8, 8] # 15, 16 - @property - def vehicle(self): - """Gets a vehicle""" - return self._vehicle + self._time_windows = \ + [(0, 0), + (75, 85), (75, 85), # 1, 2 + (60, 70), (45, 55), # 3, 4 + (0, 8), (50, 60), # 5, 6 + (0, 10), (10, 20), # 7, 8 + (0, 10), (75, 85), # 9, 10 + (85, 95), (5, 15), # 11, 12 + (15, 25), (10, 20), # 13, 14 + (45, 55), (30, 40)] # 15, 16 - @property - def num_vehicles(self): - """Gets number of vehicles""" - return self._num_vehicles + @property + def vehicle(self): + """Gets a vehicle""" + return self._vehicle - @property - def locations(self): - """Gets locations""" - return self._locations + @property + def num_vehicles(self): + """Gets number of vehicles""" + return self._num_vehicles - @property - def num_locations(self): - """Gets number of locations""" - return len(self.locations) + @property + def locations(self): + """Gets locations""" + return self._locations - @property - def depot(self): - """Gets depot location index""" - return self._depot + @property + def num_locations(self): + """Gets number of locations""" + return len(self.locations) - @property - def demands(self): - """Gets demands at each location""" - return self._demands + @property + def depot(self): + """Gets depot location index""" + return self._depot - @property - def time_per_demand_unit(self): - """Gets the time (in min) to load a demand""" - return 5 # 5 minutes/unit + @property + def demands(self): + """Gets demands at each location""" + return self._demands + + @property + def time_per_demand_unit(self): + """Gets the time (in min) to load a demand""" + return 5 # 5 minutes/unit + + @property + def time_windows(self): + """Gets (start time, end time) for each locations""" + return self._time_windows - @property - def time_windows(self): - """Gets (start time, end time) for each locations""" - return self._time_windows ####################### # Problem Constraints # ####################### def manhattan_distance(position_1, position_2): - """Computes the Manhattan distance between two points""" - return (abs(position_1[0] - position_2[0]) + - abs(position_1[1] - position_2[1])) + """Computes the Manhattan distance between two points""" + return ( + abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1])) -class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to return distance between points.""" - def __init__(self, data): - """Initializes the distance matrix.""" - self._distances = {} - # precompute distance between location to have distance callback in O(1) - for from_node in xrange(data.num_locations): - self._distances[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._distances[from_node][to_node] = 0 - else: - self._distances[from_node][to_node] = ( - manhattan_distance( - data.locations[from_node], - data.locations[to_node])) +class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to return distance between points.""" - def distance_evaluator(self, from_node, to_node): - """Returns the manhattan distance between the two nodes""" - return self._distances[from_node][to_node] + def __init__(self, data): + """Initializes the distance matrix.""" + self._distances = {} -class CreateDemandEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to get demands at each location.""" - def __init__(self, data): - """Initializes the demand array.""" - self._demands = data.demands + # precompute distance between location to have distance callback in O(1) + for from_node in xrange(data.num_locations): + self._distances[from_node] = {} + for to_node in xrange(data.num_locations): + if from_node == to_node: + self._distances[from_node][to_node] = 0 + else: + self._distances[from_node][to_node] = ( + manhattan_distance(data.locations[from_node], + data.locations[to_node])) + + def distance_evaluator(self, from_node, to_node): + """Returns the manhattan distance between the two nodes""" + return self._distances[from_node][to_node] + + +class CreateDemandEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to get demands at each location.""" + + def __init__(self, data): + """Initializes the demand array.""" + self._demands = data.demands + + def demand_evaluator(self, from_node, to_node): + """Returns the demand of the current node""" + del to_node + return self._demands[from_node] - def demand_evaluator(self, from_node, to_node): - """Returns the demand of the current node""" - del to_node - return self._demands[from_node] def add_capacity_constraints(routing, data, demand_evaluator): - """Adds capacity constraint""" - capacity = "Capacity" - routing.AddDimension( - demand_evaluator, - 0, # null capacity slack - data.vehicle.capacity, # vehicle maximum capacity - True, # start cumul to zero - capacity) + """Adds capacity constraint""" + capacity = 'Capacity' + routing.AddDimension( + demand_evaluator, + 0, # null capacity slack + data.vehicle.capacity, # vehicle maximum capacity + True, # start cumul to zero + capacity) + class CreateTimeEvaluator(object): - """Creates callback to get total times between locations.""" - @staticmethod - def service_time(data, node): - """Gets the service time for the specified location.""" - return data.demands[node] * data.time_per_demand_unit + """Creates callback to get total times between locations.""" - @staticmethod - def travel_time(data, from_node, to_node): - """Gets the travel times between two locations.""" + @staticmethod + def service_time(data, node): + """Gets the service time for the specified location.""" + return data.demands[node] * data.time_per_demand_unit + + @staticmethod + def travel_time(data, from_node, to_node): + """Gets the travel times between two locations.""" + if from_node == to_node: + travel_time = 0 + else: + travel_time = manhattan_distance( + data.locations[from_node], + data.locations[to_node]) / data.vehicle.speed + return travel_time + + def __init__(self, data): + """Initializes the total time matrix.""" + self._total_time = {} + # precompute total time to have time callback in O(1) + for from_node in xrange(data.num_locations): + self._total_time[from_node] = {} + for to_node in xrange(data.num_locations): if from_node == to_node: - travel_time = 0 + self._total_time[from_node][to_node] = 0 else: - travel_time = manhattan_distance( - data.locations[from_node], - data.locations[to_node]) / data.vehicle.speed - return travel_time + self._total_time[from_node][to_node] = int( + self.service_time(data, from_node) + + self.travel_time(data, from_node, to_node)) - def __init__(self, data): - """Initializes the total time matrix.""" - self._total_time = {} - # precompute total time to have time callback in O(1) - for from_node in xrange(data.num_locations): - self._total_time[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._total_time[from_node][to_node] = 0 - else: - self._total_time[from_node][to_node] = int( - self.service_time(data, from_node) + - self.travel_time(data, from_node, to_node)) + def time_evaluator(self, from_node, to_node): + """Returns the total time between the two nodes""" + return self._total_time[from_node][to_node] - def time_evaluator(self, from_node, to_node): - """Returns the total time between the two nodes""" - return self._total_time[from_node][to_node] def add_time_window_constraints(routing, data, time_evaluator): - """Add Global Span constraint""" - time = "Time" - horizon = 120 - routing.AddDimension( - time_evaluator, - horizon, # allow waiting time - horizon, # maximum time per vehicle - False, # don't force start cumul to zero since we are giving TW to start nodes - time) - time_dimension = routing.GetDimensionOrDie(time) - # Add time window constraints for each location except depot - # and "copy" the slack var in the solution object (aka Assignment) to print it - for location_idx, time_window in enumerate(data.time_windows): - if location_idx == 0: - continue - index = routing.NodeToIndex(location_idx) - time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1]) - routing.AddToAssignment(time_dimension.SlackVar(index)) - # Add time window constraints for each vehicle start node - # and "copy" the slack var in the solution object (aka Assignment) to print it - for vehicle_id in xrange(data.num_vehicles): - index = routing.Start(vehicle_id) - time_dimension.CumulVar(index).SetRange(data.time_windows[0][0], data.time_windows[0][1]) - routing.AddToAssignment(time_dimension.SlackVar(index)) - # Warning: Slack var is not defined for vehicle's end node - #routing.AddToAssignment(time_dimension.SlackVar(self.routing.End(vehicle_id))) + """Add Global Span constraint""" + time = 'Time' + horizon = 120 + routing.AddDimension( + time_evaluator, + horizon, # allow waiting time + horizon, # maximum time per vehicle + False, # don't force start cumul to zero since we are giving TW to start nodes + time) + time_dimension = routing.GetDimensionOrDie(time) + # Add time window constraints for each location except depot + # and "copy" the slack var in the solution object (aka Assignment) to print it + for location_idx, time_window in enumerate(data.time_windows): + if location_idx == 0: + continue + index = routing.NodeToIndex(location_idx) + time_dimension.CumulVar(index).SetRange(time_window[0], time_window[1]) + routing.AddToAssignment(time_dimension.SlackVar(index)) + # Add time window constraints for each vehicle start node + # and "copy" the slack var in the solution object (aka Assignment) to print it + for vehicle_id in xrange(data.num_vehicles): + index = routing.Start(vehicle_id) + time_dimension.CumulVar(index).SetRange(data.time_windows[0][0], + data.time_windows[0][1]) + routing.AddToAssignment(time_dimension.SlackVar(index)) + # Warning: Slack var is not defined for vehicle's end node + #routing.AddToAssignment(time_dimension.SlackVar(self.routing.End(vehicle_id))) + ########### # Printer # ########### class ConsolePrinter(): - """Print solution to console""" - def __init__(self, data, routing, assignment): - """Initializes the printer""" - self._data = data - self._routing = routing - self._assignment = assignment + """Print solution to console""" - @property - def data(self): - """Gets problem data""" - return self._data + def __init__(self, data, routing, assignment): + """Initializes the printer""" + self._data = data + self._routing = routing + self._assignment = assignment - @property - def routing(self): - """Gets routing model""" - return self._routing + @property + def data(self): + """Gets problem data""" + return self._data - @property - def assignment(self): - """Gets routing model""" - return self._assignment + @property + def routing(self): + """Gets routing model""" + return self._routing - def print(self): - """Prints assignment on console""" - # Inspect solution. - capacity_dimension = self.routing.GetDimensionOrDie('Capacity') - time_dimension = self.routing.GetDimensionOrDie('Time') - total_dist = 0 - total_time = 0 - for vehicle_id in xrange(self.data.num_vehicles): - index = self.routing.Start(vehicle_id) - plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) - route_dist = 0 - while not self.routing.IsEnd(index): - node_index = self.routing.IndexToNode(index) - next_node_index = self.routing.IndexToNode( - self.assignment.Value(self.routing.NextVar(index))) - route_dist += manhattan_distance( - self.data.locations[node_index], - self.data.locations[next_node_index]) - load_var = capacity_dimension.CumulVar(index) - route_load = self.assignment.Value(load_var) - time_var = time_dimension.CumulVar(index) - time_min = self.assignment.Min(time_var) - time_max = self.assignment.Max(time_var) - slack_var = time_dimension.SlackVar(index) - slack_min = self.assignment.Min(slack_var) - slack_max = self.assignment.Max(slack_var) - plan_output += ' {0} Load({1}) Time({2},{3}) Slack({4},{5}) ->'.format( - node_index, - route_load, - time_min, time_max, - slack_min, slack_max) - index = self.assignment.Value(self.routing.NextVar(index)) + @property + def assignment(self): + """Gets routing model""" + return self._assignment + + def print(self): + """Prints assignment on console""" + # Inspect solution. + capacity_dimension = self.routing.GetDimensionOrDie('Capacity') + time_dimension = self.routing.GetDimensionOrDie('Time') + total_dist = 0 + total_time = 0 + for vehicle_id in xrange(self.data.num_vehicles): + index = self.routing.Start(vehicle_id) + plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) + route_dist = 0 + while not self.routing.IsEnd(index): + node_index = self.routing.IndexToNode(index) + next_node_index = self.routing.IndexToNode( + self.assignment.Value(self.routing.NextVar(index))) + route_dist += manhattan_distance(self.data.locations[node_index], + self.data.locations[next_node_index]) + load_var = capacity_dimension.CumulVar(index) + route_load = self.assignment.Value(load_var) + time_var = time_dimension.CumulVar(index) + time_min = self.assignment.Min(time_var) + time_max = self.assignment.Max(time_var) + slack_var = time_dimension.SlackVar(index) + slack_min = self.assignment.Min(slack_var) + slack_max = self.assignment.Max(slack_var) + plan_output += ' {0} Load({1}) Time({2},{3}) Slack({4},{5}) ->'.format( + node_index, route_load, time_min, time_max, slack_min, slack_max) + index = self.assignment.Value(self.routing.NextVar(index)) + + node_index = self.routing.IndexToNode(index) + load_var = capacity_dimension.CumulVar(index) + route_load = self.assignment.Value(load_var) + time_var = time_dimension.CumulVar(index) + route_time = self.assignment.Value(time_var) + time_min = self.assignment.Min(time_var) + time_max = self.assignment.Max(time_var) + total_dist += route_dist + total_time += route_time + plan_output += ' {0} Load({1}) Time({2},{3})\n'.format( + node_index, route_load, time_min, time_max) + plan_output += 'Distance of the route: {0}m\n'.format(route_dist) + plan_output += 'Load of the route: {0}\n'.format(route_load) + plan_output += 'Time of the route: {0}min\n'.format(route_time) + print(plan_output) + print('Total Distance of all routes: {0}m'.format(total_dist)) + print('Total Time of all routes: {0}min'.format(total_time)) - node_index = self.routing.IndexToNode(index) - load_var = capacity_dimension.CumulVar(index) - route_load = self.assignment.Value(load_var) - time_var = time_dimension.CumulVar(index) - route_time = self.assignment.Value(time_var) - time_min = self.assignment.Min(time_var) - time_max = self.assignment.Max(time_var) - total_dist += route_dist - total_time += route_time - plan_output += ' {0} Load({1}) Time({2},{3})\n'.format( - node_index, - route_load, - time_min, time_max) - plan_output += 'Distance of the route: {0}m\n'.format(route_dist) - plan_output += 'Load of the route: {0}\n'.format(route_load) - plan_output += 'Time of the route: {0}min\n'.format(route_time) - print(plan_output) - print('Total Distance of all routes: {0}m'.format(total_dist)) - print('Total Time of all routes: {0}min'.format(total_time)) ######## # Main # ######## def main(): - """Entry point of the program""" - # Instantiate the data problem. - data = DataProblem() + """Entry point of the program""" + # Instantiate the data problem. + data = DataProblem() - # Create Routing Model - routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, data.depot) - # Define weight of each edge - distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator - routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) - # Add Capacity constraint - demand_evaluator = CreateDemandEvaluator(data).demand_evaluator - add_capacity_constraints(routing, data, demand_evaluator) - # Add Time Window constraint - time_evaluator = CreateTimeEvaluator(data).time_evaluator - add_time_window_constraints(routing, data, time_evaluator) + # Create Routing Model + routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, + data.depot) + # Define weight of each edge + distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator + routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) + # Add Capacity constraint + demand_evaluator = CreateDemandEvaluator(data).demand_evaluator + add_capacity_constraints(routing, data, demand_evaluator) + # Add Time Window constraint + time_evaluator = CreateTimeEvaluator(data).time_evaluator + add_time_window_constraints(routing, data, time_evaluator) + + # Setting first solution heuristic (cheapest addition). + search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # Solve the problem. + assignment = routing.SolveWithParameters(search_parameters) + printer = ConsolePrinter(data, routing, assignment) + printer. print() - # Setting first solution heuristic (cheapest addition). - search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() - search_parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) - # Solve the problem. - assignment = routing.SolveWithParameters(search_parameters) - printer = ConsolePrinter(data, routing, assignment) - printer.print() if __name__ == '__main__': - main() + main() diff --git a/examples/python/cvrptw_plot.py b/examples/python/cvrptw_plot.py index a4537d8749..d524bebf58 100644 --- a/examples/python/cvrptw_plot.py +++ b/examples/python/cvrptw_plot.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Capacitated Vehicle Routing Problem with Time Windows (and optional orders). This is a sample using the routing library python wrapper to solve a @@ -45,7 +44,7 @@ from datetime import datetime, timedelta class Customers(): - """ + """ A class that generates and holds customers information. Randomly normally distribute a number of customers and locations within @@ -56,128 +55,122 @@ class Customers(): point (lat, lon), and box_size in km. The default arguments are for a 10 x 10 km square centered in Sheffield). - Args: - extents (Optional[Dict]): A dictionary describing a rectangle in - latitude and longitude with the keys 'llcrnrlat', 'llcrnrlon' & - 'urcrnrlat' & 'urcrnrlat' - - center (Optional(Tuple): A tuple of (latitude, longitude) - describing the centre of the rectangle. - - box_size (Optional float: The length in km of the box's sides. - - num_stops (int): The number of customers, including the depots that - are placed normally distributed in the rectangle. - - min_demand (int): Lower limit on the randomly generated demand at - each customer. - - max_demand (int): Upper limit on the randomly generated demand at - each customer. - + Args: extents (Optional[Dict]): A dictionary describing a rectangle in + latitude and longitude with the keys 'llcrnrlat', 'llcrnrlon' & + 'urcrnrlat' & 'urcrnrlat' center (Optional(Tuple): A tuple of + (latitude, longitude) describing the centre of the rectangle. box_size + (Optional float: The length in km of the box's sides. num_stops (int): + The number of customers, including the depots that are placed normally + distributed in the rectangle. min_demand (int): Lower limit on the + randomly generated demand at each customer. max_demand (int): Upper + limit on the randomly generated demand at each customer. min_tw: shortest random time window for a customer, in hours. - max_tw: longest random time window for a customer, in hours. + Examples: To place 100 customers randomly within 100 km x 100 km + rectangle, centered in the default location, with a random demand of + between 5 and 10 units: >>> customers = Customers(num_stops=100, + box_size=100, ... min_demand=5, max_demand=10) + alternatively, to place 75 customers in the same area with default + arguments for demand: >>> extents = {'urcrnrlon': 0.03403, 'llcrnrlon': + -2.98325, ... 'urcrnrlat': 54.28127, 'llcrnrlat': 52.48150} >>> + customers = Customers(num_stops=75, extents=extents) + """ - Examples: - To place 100 customers randomly within 100 km x 100 km rectangle, - centered in the default location, with a random demand of between 5 - and 10 units: + def __init__(self, + extents=None, + center=(53.381393, -1.474611), + box_size=10, + num_stops=100, + min_demand=0, + max_demand=25, + min_tw=1, + max_tw=5): + self.number = num_stops #: The number of customers and depots + #: Location, a named tuple for locations. + Location = namedtuple('Location', ['lat', 'lon']) + if extents is not None: + self.extents = extents #: The lower left and upper right points + #: Location[lat,lon]: the centre point of the area. + self.center = Location( + extents['urcrnrlat'] - + 0.5 * (extents['urcrnrlat'] - extents['llcrnrlat']), + extents['urcrnrlon'] - + 0.5 * (extents['urcrnrlon'] - extents['llcrnrlon'])) + else: + #: Location[lat,lon]: the centre point of the area. + (clat, clon) = self.center = Location(center[0], center[1]) + rad_earth = 6367 # km + circ_earth = np.pi * rad_earth + #: The lower left and upper right points + self.extents = { + 'llcrnrlon': ( + clon - 180 * box_size / (circ_earth * np.cos(np.deg2rad(clat)))), + 'llcrnrlat': + clat - 180 * box_size / circ_earth, + 'urcrnrlon': ( + clon + 180 * box_size / (circ_earth * np.cos(np.deg2rad(clat)))), + 'urcrnrlat': + clat + 180 * box_size / circ_earth + } + # The 'name' of the stop, indexed from 0 to num_stops-1 + stops = np.array(range(0, num_stops)) + # normaly distributed random distribution of stops within the box + stdv = 6 # the number of standard deviations 99.9% will be within +-3 + lats = ( + self.extents['llcrnrlat'] + np.random.randn(num_stops) * + (self.extents['urcrnrlat'] - self.extents['llcrnrlat']) / stdv) + lons = ( + self.extents['llcrnrlon'] + np.random.randn(num_stops) * + (self.extents['urcrnrlon'] - self.extents['llcrnrlon']) / stdv) + # uniformly distributed integer demands. + demmands = np.random.randint(min_demand, max_demand, num_stops) - >>> customers = Customers(num_stops=100, box_size=100, - ... min_demand=5, max_demand=10) + self.time_horizon = 24 * 60**2 # A 24 hour period. - alternatively, to place 75 customers in the same area with default - arguments for demand: + # The customers demand min_tw to max_tw hour time window for each + # delivery + time_windows = np.random.random_integers(min_tw * 3600, max_tw * 3600, + num_stops) + # The last time a delivery window can start + latest_time = self.time_horizon - time_windows + start_times = [None for o in time_windows] + stop_times = [None for o in time_windows] + # Make random timedeltas, nominaly from the start of the day. + for idx in range(self.number): + stime = int(np.random.random_integers(0, latest_time[idx])) + start_times[idx] = timedelta(seconds=stime) + stop_times[idx] = ( + start_times[idx] + timedelta(seconds=int(time_windows[idx]))) + # A named tuple for the customer + Customer = namedtuple( + 'Customer', + [ + 'index', # the index of the stop + 'demand', # the demand for the stop + 'lat', # the latitude of the stop + 'lon', # the longitude of the stop + 'tw_open', # timedelta window open + 'tw_close' + ]) # timedelta window cls - >>> extents = {'urcrnrlon': 0.03403, 'llcrnrlon': -2.98325, - ... 'urcrnrlat': 54.28127, 'llcrnrlat': 52.48150} - >>> customers = Customers(num_stops=75, extents=extents) + self.customers = [ + Customer(idx, dem, lat, lon, tw_open, tw_close) + for idx, dem, lat, lon, tw_open, tw_close in zip( + stops, demmands, lats, lons, start_times, stop_times) + ] + # The number of seconds needed to 'unload' 1 unit of goods. + self.service_time_per_dem = 300 # seconds + def central_start_node(self, invert=False): """ - def __init__(self, extents=None, center=(53.381393, -1.474611), - box_size=10, num_stops=100, - min_demand=0, max_demand=25, - min_tw=1, max_tw=5): - self.number = num_stops #: The number of customers and depots - #: Location, a named tuple for locations. - Location = namedtuple("Location", ['lat', 'lon']) - if extents is not None: - self.extents = extents #: The lower left and upper right points - #: Location[lat,lon]: the centre point of the area. - self.center = Location(extents['urcrnrlat'] - - 0.5 * (extents['urcrnrlat'] - - extents['llcrnrlat']), - extents['urcrnrlon'] - - 0.5 * (extents['urcrnrlon'] - - extents['llcrnrlon'])) - else: - #: Location[lat,lon]: the centre point of the area. - (clat, clon) = self.center = Location(center[0], center[1]) - rad_earth = 6367 # km - circ_earth = np.pi * rad_earth - #: The lower left and upper right points - self.extents = {'llcrnrlon': (clon - 180 * box_size / - (circ_earth * - np.cos(np.deg2rad(clat)))), - 'llcrnrlat': clat - 180 * box_size / circ_earth, - 'urcrnrlon': (clon + 180 * box_size / - (circ_earth * - np.cos(np.deg2rad(clat)))), - 'urcrnrlat': clat + 180 * box_size / circ_earth} - # The 'name' of the stop, indexed from 0 to num_stops-1 - stops = np.array(range(0, num_stops)) - # normaly distributed random distribution of stops within the box - stdv = 6 # the number of standard deviations 99.9% will be within +-3 - lats = (self.extents['llcrnrlat'] + np.random.randn(num_stops) * - (self.extents['urcrnrlat'] - self.extents['llcrnrlat']) / stdv) - lons = (self.extents['llcrnrlon'] + np.random.randn(num_stops) * - (self.extents['urcrnrlon'] - self.extents['llcrnrlon']) / stdv) - # uniformly distributed integer demands. - demmands = np.random.randint(min_demand, max_demand, num_stops) - - self.time_horizon = 24 * 60 ** 2 # A 24 hour period. - - # The customers demand min_tw to max_tw hour time window for each - # delivery - time_windows = np.random.random_integers(min_tw * 3600, - max_tw * 3600, num_stops) - # The last time a delivery window can start - latest_time = self.time_horizon - time_windows - start_times = [None for o in time_windows] - stop_times = [None for o in time_windows] - # Make random timedeltas, nominaly from the start of the day. - for idx in range(self.number): - stime = int(np.random.random_integers(0, latest_time[idx])) - start_times[idx] = timedelta(seconds=stime) - stop_times[idx] = (start_times[idx] + - timedelta(seconds=int(time_windows[idx]))) - # A named tuple for the customer - Customer = namedtuple("Customer", ['index', # the index of the stop - 'demand', # the demand for the stop - 'lat', # the latitude of the stop - 'lon', # the longitude of the stop - 'tw_open', # timedelta window open - 'tw_close']) # timedelta window cls - - self.customers = [Customer(idx, dem, lat, lon, tw_open, tw_close) for - idx, dem, lat, lon, tw_open, tw_close - in zip(stops, demmands, lats, lons, - start_times, stop_times)] - - # The number of seconds needed to 'unload' 1 unit of goods. - self.service_time_per_dem = 300 # seconds - - def central_start_node(self, invert=False): - """ Return a random starting node, with probability weighted by distance from the centre of the extents, so that a central starting node is likely. - Args: - invert (Optional bool): When True, a peripheral starting node is - most likely. + Args: invert (Optional bool): When True, a peripheral starting node is + most likely. + Returns: int: a node index. @@ -185,36 +178,32 @@ class Customers(): >>> customers.central_start_node(invert=True) 42 """ - num_nodes = len(self.customers) - dist = np.empty((num_nodes, 1)) - for idx_to in range(num_nodes): - dist[idx_to] = self._haversine(self.center.lon, - self.center.lat, - self.customers[idx_to].lon, - self.customers[idx_to].lat) - furthest = np.max(dist) + num_nodes = len(self.customers) + dist = np.empty((num_nodes, 1)) + for idx_to in range(num_nodes): + dist[idx_to] = self._haversine(self.center.lon, self.center.lat, + self.customers[idx_to].lon, + self.customers[idx_to].lat) + furthest = np.max(dist) - if invert: - prob = dist * 1.0 / sum(dist) - else: - prob = (furthest - dist * 1.0) / sum(furthest - dist) - indexes = np.array([range(num_nodes)]) - start_node = np.random.choice(indexes.flatten(), - size=1, - replace=True, - p=prob.flatten()) - return start_node[0] + if invert: + prob = dist * 1.0 / sum(dist) + else: + prob = (furthest - dist * 1.0) / sum(furthest - dist) + indexes = np.array([range(num_nodes)]) + start_node = np.random.choice( + indexes.flatten(), size=1, replace=True, p=prob.flatten()) + return start_node[0] - def make_distance_mat(self, method='haversine'): - """ + def make_distance_mat(self, method='haversine'): + """ Return a distance matrix and make it a member of Customer, using the method given in the call. Currently only Haversine (GC distance) is implemented, but Manhattan, or using a maps API could be added here. Raises an AssertionError for all other methods. - Args: - method (Optional[str]): method of distance calculation to use. The - Haversine formula is the only method implemented. + Args: method (Optional[str]): method of distance calculation to use. The + Haversine formula is the only method implemented. Returns: Numpy array of node to node distances. @@ -224,22 +213,20 @@ class Customers(): >>> dist_mat = customers.make_distance_mat(method='manhattan') AssertionError """ - self.distmat = np.zeros((self.number, self.number)) - methods = {'haversine': self._haversine} - assert(method in methods) - for frm_idx in range(self.number): - for to_idx in range(self.number): - if frm_idx != to_idx: - frm_c = self.customers[frm_idx] - to_c = self.customers[to_idx] - self.distmat[frm_idx, to_idx] = self._haversine(frm_c.lon, - frm_c.lat, - to_c.lon, - to_c.lat) - return(self.distmat) + self.distmat = np.zeros((self.number, self.number)) + methods = {'haversine': self._haversine} + assert (method in methods) + for frm_idx in range(self.number): + for to_idx in range(self.number): + if frm_idx != to_idx: + frm_c = self.customers[frm_idx] + to_c = self.customers[to_idx] + self.distmat[frm_idx, to_idx] = self._haversine( + frm_c.lon, frm_c.lat, to_c.lon, to_c.lat) + return (self.distmat) - def _haversine(self, lon1, lat1, lon2, lat2): - """ + def _haversine(self, lon1, lat1, lon2, lat2): + """ Calculate the great circle distance between two points on the earth specified in decimal degrees of latitude and longitude. https://en.wikipedia.org/wiki/Haversine_formula @@ -253,80 +240,73 @@ class Customers(): Returns: the distace in km between pt1 and pt2 """ - # convert decimal degrees to radians - lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2]) + # convert decimal degrees to radians + lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2]) - # haversine formula - dlon = lon2 - lon1 - dlat = lat2 - lat1 - a = (np.sin(dlat / 2) ** 2 + np.cos(lat1) * - np.cos(lat2) * np.sin(dlon / 2) ** 2) - c = 2 * np.arcsin(np.sqrt(a)) + # haversine formula + dlon = lon2 - lon1 + dlat = lat2 - lat1 + a = ( + np.sin(dlat / 2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2)**2) + c = 2 * np.arcsin(np.sqrt(a)) - # 6367 km is the radius of the Earth - km = 6367 * c - return km + # 6367 km is the radius of the Earth + km = 6367 * c + return km - def get_total_demand(self): - """ + def get_total_demand(self): + """ Return the total demand of all customers. """ - return(sum([c.demand for c in self.customers])) + return (sum([c.demand for c in self.customers])) - def return_dist_callback(self, **kwargs): - """ + def return_dist_callback(self, **kwargs): + """ Return a callback function for the distance matrix. - Args: - **kwargs: Arbitrary keyword arguments passed on to - make_distance_mat() + Args: **kwargs: Arbitrary keyword arguments passed on to + make_distance_mat() Returns: function: dist_return(a,b) A function that takes the 'from' node index and the 'to' node index and returns the distance in km. """ - self.make_distance_mat(**kwargs) + self.make_distance_mat(**kwargs) - def dist_return(a, b): return(self.distmat[a][b]) + def dist_return(a, b): + return (self.distmat[a][b]) - return dist_return + return dist_return - def return_dem_callback(self): - """ + def return_dem_callback(self): + """ Return a callback function that gives the demands. Returns: function: dem_return(a,b) A function that takes the 'from' node index and the 'to' node index and returns the distance in km. """ - def dem_return(a, b): return(self.customers[a].demand) - return dem_return + def dem_return(a, b): + return (self.customers[a].demand) - def zero_depot_demands(self, depot): - """ + return dem_return + + def zero_depot_demands(self, depot): + """ Zero out the demands and time windows of depot. The Depots do not have demands or time windows so this function clears them. - Args: + Args: depot (int): index of the stop to modify into a depot. + Examples: >>> customers.zero_depot_demands(5) >>> + customers.customers[5].demand == 0 True + """ + start_depot = self.customers[depot] + self.customers[depot] = start_depot._replace( + demand=0, tw_open=None, tw_close=None) - depot (int): index of the stop to modify into a depot. - - Examples: - - >>> customers.zero_depot_demands(5) - >>> customers.customers[5].demand == 0 - True - - - """ - start_depot = self.customers[depot] - self.customers[depot] = start_depot._replace(demand=0, - tw_open=None, - tw_close=None) - - def make_service_time_call_callback(self): - """ + def make_service_time_call_callback(self): + """ Return a callback function that provides the time spent servicing the customer. Here is it proportional to the demand given by self.service_time_per_dem, default 300 seconds per unit demand. @@ -336,30 +316,33 @@ class Customers(): index and the to/b node index and returns the service time at a """ - def service_time_return(a, b): - return(self.customers[a].demand * self.service_time_per_dem) - return service_time_return + def service_time_return(a, b): + return (self.customers[a].demand * self.service_time_per_dem) - def make_transit_time_callback(self, speed_kmph=10): - """ + return service_time_return + + def make_transit_time_callback(self, speed_kmph=10): + """ Creates a callback function for transit time. Assuming an average speed of speed_kmph Args: speed_kmph: the average speed in km/h + Returns: function [tranit_time_return(a, b)]: A function that takes the from/a node index and the to/b node index and returns the tranit time from a to b. """ - def tranit_time_return(a, b): - return(self.distmat[a][b] / (speed_kmph * 1.0 / 60 ** 2)) - return tranit_time_return + def tranit_time_return(a, b): + return (self.distmat[a][b] / (speed_kmph * 1.0 / 60**2)) + + return tranit_time_return class Vehicles(): - """ + """ A Class to create and hold vehicle information. The Vehicles in a CVRPTW problem service the customers and belong to a @@ -375,369 +358,374 @@ class Vehicles(): If scalars are given, the fleet is homogenious, and the number of vehicles is determied by number. - Args: - capacity (scalar or numpy array): The integer capacity of demand units. + Args: capacity (scalar or numpy array): The integer capacity of demand + units. cost (scalar or numpy array): The fixed cost of the vehicle. number + (Optional [int]): The number of vehicles in a homogenious fleet. + """ - cost (scalar or numpy array): The fixed cost of the vehicle. + def __init__(self, capacity=100, cost=100, number=None): - number (Optional [int]): The number of vehicles in a homogenious fleet. - """ - def __init__(self, capacity=100, cost=100, number=None): + Vehicle = namedtuple('Vehicle', ['index', 'capacity', 'cost']) - Vehicle = namedtuple("Vehicle", ['index', 'capacity', 'cost']) + if number is None: + self.number = np.size(capacity) + else: + self.number = number + idxs = np.array(range(0, self.number)) - if number is None: - self.number = np.size(capacity) - else: - self.number = number - idxs = np.array(range(0, self.number)) + if np.isscalar(capacity): + capacities = capacity * np.ones_like(idxs) + elif np.size(capacity) != np.size(capacity): + print('capacity is neither scalar, nor the same size as num!') + else: + capacities = capacity - if np.isscalar(capacity): - capacities = capacity * np.ones_like(idxs) - elif np.size(capacity) != np.size(capacity): - print('capacity is neither scalar, nor the same size as num!') - else: - capacities = capacity + if np.isscalar(cost): + costs = cost * np.ones_like(idxs) + elif np.size(cost) != self.number: + print(np.size(cost)) + print('cost is neither scalar, nor the same size as num!') + else: + costs = cost - if np.isscalar(cost): - costs = cost * np.ones_like(idxs) - elif np.size(cost) != self.number: - print(np.size(cost)) - print('cost is neither scalar, nor the same size as num!') - else: - costs = cost + self.vehicles = [ + Vehicle(idx, capacity, cost) + for idx, capacity, cost in zip(idxs, capacities, costs) + ] - self.vehicles = [Vehicle(idx, capacity, cost) for idx, capacity, cost - in zip(idxs, capacities, costs)] + def get_total_capacity(self): + return (sum([c.capacity for c in self.vehicles])) - def get_total_capacity(self): - return(sum([c.capacity for c in self.vehicles])) + def return_starting_callback(self, customers, sameStartFinish=False): + # create a different starting and finishing depot for each vehicle + self.starts = [ + int(customers.central_start_node()) for o in range(self.number) + ] + if sameStartFinish: + self.ends = self.starts + else: + self.ends = [ + int(customers.central_start_node(invert=True)) + for o in range(self.number) + ] + # the depots will not have demands, so zero them. + for depot in self.starts: + customers.zero_depot_demands(depot) + for depot in self.ends: + customers.zero_depot_demands(depot) - def return_starting_callback(self, customers, sameStartFinish=False): - # create a different starting and finishing depot for each vehicle - self.starts = [int(customers.central_start_node()) for o in - range(self.number)] - if sameStartFinish: - self.ends = self.starts - else: - self.ends = [int(customers.central_start_node(invert=True)) for - o in range(self.number)] - # the depots will not have demands, so zero them. - for depot in self.starts: - customers.zero_depot_demands(depot) - for depot in self.ends: - customers.zero_depot_demands(depot) + def start_return(v): + return (self.starts[v]) - def start_return(v): return(self.starts[v]) - return start_return + return start_return def discrete_cmap(N, base_cmap=None): - """ + """ Create an N-bin discrete colormap from the specified input map """ - # Note that if base_cmap is a string or None, you can simply do - # return plt.cm.get_cmap(base_cmap, N) - # The following works for string, None, or a colormap instance: + # Note that if base_cmap is a string or None, you can simply do + # return plt.cm.get_cmap(base_cmap, N) + # The following works for string, None, or a colormap instance: - base = plt.cm.get_cmap(base_cmap) - color_list = base(np.linspace(0, 1, N)) - cmap_name = base.name + str(N) - return base.from_list(cmap_name, color_list, N) + base = plt.cm.get_cmap(base_cmap) + color_list = base(np.linspace(0, 1, N)) + cmap_name = base.name + str(N) + return base.from_list(cmap_name, color_list, N) def vehicle_output_string(routing, plan): - """ + """ Return a string displaying the output of the routing instance and assignment (plan). - Args: - routing (ortools.constraint_solver.pywrapcp.RoutingModel): routing. + Args: routing (ortools.constraint_solver.pywrapcp.RoutingModel): routing. + plan (ortools.constraint_solver.pywrapcp.Assignment): the assignment. - plan (ortools.constraint_solver.pywrapcp.Assignment): the assignment. Returns: (string) plan_output: describing each vehicle's plan. (List) dropped: list of dropped orders. """ - dropped = [] - for order in range(routing.Size()): - if (plan.Value(routing.NextVar(order)) == order): - dropped.append(str(order)) + dropped = [] + for order in range(routing.Size()): + if (plan.Value(routing.NextVar(order)) == order): + dropped.append(str(order)) - capacity_dimension = routing.GetDimensionOrDie("Capacity") - time_dimension = routing.GetDimensionOrDie("Time") - plan_output = '' + capacity_dimension = routing.GetDimensionOrDie('Capacity') + time_dimension = routing.GetDimensionOrDie('Time') + plan_output = '' - for route_number in range(routing.vehicles()): - order = routing.Start(route_number) - plan_output += 'Route {0}:'.format(route_number) - if routing.IsEnd(plan.Value(routing.NextVar(order))): - plan_output += ' Empty \n' - else: - while True: - load_var = capacity_dimension.CumulVar(order) - time_var = time_dimension.CumulVar(order) - plan_output += \ - " {order} Load({load}) Time({tmin}, {tmax}) -> ".format( - order=order, - load=plan.Value(load_var), - tmin=str(timedelta(seconds=plan.Min(time_var))), - tmax=str(timedelta(seconds=plan.Max(time_var)))) + for route_number in range(routing.vehicles()): + order = routing.Start(route_number) + plan_output += 'Route {0}:'.format(route_number) + if routing.IsEnd(plan.Value(routing.NextVar(order))): + plan_output += ' Empty \n' + else: + while True: + load_var = capacity_dimension.CumulVar(order) + time_var = time_dimension.CumulVar(order) + plan_output += \ + ' {order} Load({load}) Time({tmin}, {tmax}) -> '.format( + order=order, + load=plan.Value(load_var), + tmin=str(timedelta(seconds=plan.Min(time_var))), + tmax=str(timedelta(seconds=plan.Max(time_var)))) - if routing.IsEnd(order): - plan_output += ' EndRoute {0}. \n'.format(route_number) - break - order = plan.Value(routing.NextVar(order)) - plan_output += "\n" + if routing.IsEnd(order): + plan_output += ' EndRoute {0}. \n'.format(route_number) + break + order = plan.Value(routing.NextVar(order)) + plan_output += '\n' - return(plan_output, dropped) + return (plan_output, dropped) def build_vehicle_route(routing, plan, customers, veh_number): - """ + """ Build a route for a vehicle by starting at the strat node and continuing to the end node. - Args: - routing (ortools.constraint_solver.pywrapcp.RoutingModel): routing. + Args: routing (ortools.constraint_solver.pywrapcp.RoutingModel): routing. + plan (ortools.constraint_solver.pywrapcp.Assignment): the assignment. + customers (Customers): the customers instance. veh_number (int): index of + the vehicle - plan (ortools.constraint_solver.pywrapcp.Assignment): the assignment. - - customers (Customers): the customers instance. - - veh_number (int): index of the vehicle Returns: (List) route: indexes of the customers for vehicle veh_number """ - veh_used = routing.IsVehicleUsed(plan, veh_number) - print('Vehicle {0} is used {1}'.format(veh_number, veh_used)) - if veh_used: - route = [] - node = routing.Start(veh_number) # Get the starting node index - route.append(customers.customers[routing.IndexToNode(node)]) - while not routing.IsEnd(node): - route.append(customers.customers[routing.IndexToNode(node)]) - node = plan.Value(routing.NextVar(node)) + veh_used = routing.IsVehicleUsed(plan, veh_number) + print('Vehicle {0} is used {1}'.format(veh_number, veh_used)) + if veh_used: + route = [] + node = routing.Start(veh_number) # Get the starting node index + route.append(customers.customers[routing.IndexToNode(node)]) + while not routing.IsEnd(node): + route.append(customers.customers[routing.IndexToNode(node)]) + node = plan.Value(routing.NextVar(node)) - route.append(customers.customers[routing.IndexToNode(node)]) - return route - else: - return None + route.append(customers.customers[routing.IndexToNode(node)]) + return route + else: + return None def plot_vehicle_routes(veh_route, ax1, customers, vehicles): - """ + """ Plot the vehicle routes on matplotlib axis ax1. - Args: - veh_route (dict): a dictionary of routes keyed by vehicle idx. + Args: veh_route (dict): a dictionary of routes keyed by vehicle idx. ax1 + (matplotlib.axes._subplots.AxesSubplot): Matplotlib axes customers + (Customers): the customers instance. vehicles (Vehicles): the vehicles + instance. + """ + veh_used = [v for v in veh_route if veh_route[v] is not None] - ax1 (matplotlib.axes._subplots.AxesSubplot): Matplotlib axes + cmap = discrete_cmap(vehicles.number + 2, 'nipy_spectral') - customers (Customers): the customers instance. + for veh_number in veh_used: - vehicles (Vehicles): the vehicles instance. - """ - veh_used = [v for v in veh_route if veh_route[v] is not None] - - cmap = discrete_cmap(vehicles.number+2, 'nipy_spectral') - - for veh_number in veh_used: - - lats, lons = zip(*[(c.lat, c.lon) for c in veh_route[veh_number]]) - lats = np.array(lats) - lons = np.array(lons) - s_dep = customers.customers[vehicles.starts[veh_number]] - s_fin = customers.customers[vehicles.ends[veh_number]] - ax1.annotate('v({veh}) S @ {node}'.format( - veh=veh_number, - node=vehicles.starts[veh_number]), - xy=(s_dep.lon, s_dep.lat), - xytext=(10, 10), - xycoords='data', - textcoords='offset points', - arrowprops=dict( - arrowstyle="->", - connectionstyle="angle3,angleA=90,angleB=0", - shrinkA=0.05), - ) - ax1.annotate('v({veh}) F @ {node}'.format( - veh=veh_number, - node=vehicles.ends[veh_number]), - xy=(s_fin.lon, s_fin.lat), - xytext=(10, -20), - xycoords='data', - textcoords='offset points', - arrowprops=dict( - arrowstyle="->", - connectionstyle="angle3,angleA=-90,angleB=0", - shrinkA=0.05), - ) - ax1.plot(lons, lats, 'o', mfc=cmap(veh_number+1)) - ax1.quiver(lons[:-1], lats[:-1], - lons[1:]-lons[:-1], lats[1:]-lats[:-1], - scale_units='xy', angles='xy', scale=1, - color=cmap(veh_number+1)) + lats, lons = zip(*[(c.lat, c.lon) for c in veh_route[veh_number]]) + lats = np.array(lats) + lons = np.array(lons) + s_dep = customers.customers[vehicles.starts[veh_number]] + s_fin = customers.customers[vehicles.ends[veh_number]] + ax1.annotate( + 'v({veh}) S @ {node}'.format( + veh=veh_number, node=vehicles.starts[veh_number]), + xy=(s_dep.lon, s_dep.lat), + xytext=(10, 10), + xycoords='data', + textcoords='offset points', + arrowprops=dict( + arrowstyle='->', + connectionstyle='angle3,angleA=90,angleB=0', + shrinkA=0.05), + ) + ax1.annotate( + 'v({veh}) F @ {node}'.format( + veh=veh_number, node=vehicles.ends[veh_number]), + xy=(s_fin.lon, s_fin.lat), + xytext=(10, -20), + xycoords='data', + textcoords='offset points', + arrowprops=dict( + arrowstyle='->', + connectionstyle='angle3,angleA=-90,angleB=0', + shrinkA=0.05), + ) + ax1.plot(lons, lats, 'o', mfc=cmap(veh_number + 1)) + ax1.quiver( + lons[:-1], + lats[:-1], + lons[1:] - lons[:-1], + lats[1:] - lats[:-1], + scale_units='xy', + angles='xy', + scale=1, + color=cmap(veh_number + 1)) def main(): - # Create a set of customer, (and depot) stops. - customers = Customers(num_stops=50, min_demand=1, - max_demand=15, box_size=40, - min_tw=3, max_tw=6) + # Create a set of customer, (and depot) stops. + customers = Customers( + num_stops=50, + min_demand=1, + max_demand=15, + box_size=40, + min_tw=3, + max_tw=6) - # Create callback fns for distances, demands, service and transit-times. - dist_fn = customers.return_dist_callback() - dem_fn = customers.return_dem_callback() - serv_time_fn = customers.make_service_time_call_callback() - transit_time_fn = customers.make_transit_time_callback() + # Create callback fns for distances, demands, service and transit-times. + dist_fn = customers.return_dist_callback() + dem_fn = customers.return_dem_callback() + serv_time_fn = customers.make_service_time_call_callback() + transit_time_fn = customers.make_transit_time_callback() - def tot_time_fn(a, b): - """ + def tot_time_fn(a, b): + """ The time function we want is both transit time and service time. """ - return serv_time_fn(a, b) + transit_time_fn(a, b) + return serv_time_fn(a, b) + transit_time_fn(a, b) - # Create a list of inhomgenious vehicle capacities as integer units. - capacity = [50, 75, 100, 125, 150, 175, 200, 250] + # Create a list of inhomgenious vehicle capacities as integer units. + capacity = [50, 75, 100, 125, 150, 175, 200, 250] - # Create a list of inhomogenious fixed vehicle costs. - cost = [int(100 + 2 * np.sqrt(c)) for c in capacity] + # Create a list of inhomogenious fixed vehicle costs. + cost = [int(100 + 2 * np.sqrt(c)) for c in capacity] - # Create a set of vehicles, the number set by the length of capacity. - vehicles = Vehicles(capacity=capacity, cost=cost) + # Create a set of vehicles, the number set by the length of capacity. + vehicles = Vehicles(capacity=capacity, cost=cost) - # check to see that the problem is feasible, if we don't have enough - # vehicles to cover the demand, there is no point in going further. - assert(customers.get_total_demand() < vehicles.get_total_capacity()) + # check to see that the problem is feasible, if we don't have enough + # vehicles to cover the demand, there is no point in going further. + assert (customers.get_total_demand() < vehicles.get_total_capacity()) - # Set the starting nodes, and create a callback fn for the starting node. - start_fn = vehicles.return_starting_callback(customers, - sameStartFinish=False) + # Set the starting nodes, and create a callback fn for the starting node. + start_fn = vehicles.return_starting_callback(customers, sameStartFinish=False) + # Set model parameters + model_parameters = pywrapcp.RoutingModel.DefaultModelParameters() - # Set model parameters - model_parameters = pywrapcp.RoutingModel.DefaultModelParameters() + # The solver parameters can be accessed from the model parameters. For example : + # model_parameters.solver_parameters.CopyFrom( + # pywrapcp.Solver.DefaultSolverParameters()) + # model_parameters.solver_parameters.trace_propagation = True - # The solver parameters can be accessed from the model parameters. For example : -# model_parameters.solver_parameters.CopyFrom( -# pywrapcp.Solver.DefaultSolverParameters()) -# model_parameters.solver_parameters.trace_propagation = True + # Make the routing model instance. + routing = pywrapcp.RoutingModel( + customers.number, # int number + vehicles.number, # int number + vehicles.starts, # List of int start depot + vehicles.ends, # List of int end depot + model_parameters) + parameters = routing.DefaultSearchParameters() + # Setting first solution heuristic (cheapest addition). + parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # Disabling Large Neighborhood Search, (this is the default behaviour) + parameters.local_search_operators.use_path_lns = False + parameters.local_search_operators.use_inactive_lns = False + # Routing: forbids use of TSPOpt neighborhood, + parameters.local_search_operators.use_tsp_opt = False - # Make the routing model instance. - routing = pywrapcp.RoutingModel(customers.number, # int number - vehicles.number, # int number - vehicles.starts, # List of int start depot - vehicles.ends, # List of int end depot - model_parameters) + parameters.time_limit_ms = 10 * 1000 # 10 seconds + parameters.use_light_propagation = False + # parameters.log_search = True - parameters = routing.DefaultSearchParameters() - # Setting first solution heuristic (cheapest addition). - parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) - # Disabling Large Neighborhood Search, (this is the default behaviour) - parameters.local_search_operators.use_path_lns = False - parameters.local_search_operators.use_inactive_lns = False - # Routing: forbids use of TSPOpt neighborhood, - parameters.local_search_operators.use_tsp_opt = False + # Set the cost function (distance callback) for each arc, homogenious for + # all vehicles. + routing.SetArcCostEvaluatorOfAllVehicles(dist_fn) - parameters.time_limit_ms = 10 * 1000 # 10 seconds - parameters.use_light_propagation = False - # parameters.log_search = True + # Set vehicle costs for each vehicle, not homogenious. + for veh in vehicles.vehicles: + routing.SetFixedCostOfVehicle(veh.cost, int(veh.index)) + # Add a dimension for vehicle capacities + null_capacity_slack = 0 + routing.AddDimensionWithVehicleCapacity( + dem_fn, # demand callback + null_capacity_slack, + capacity, # capacity array + True, + 'Capacity') + # Add a dimension for time and a limit on the total time_horizon + routing.AddDimension( + tot_time_fn, # total time function callback + customers.time_horizon, + customers.time_horizon, + True, + 'Time') - # Set the cost function (distance callback) for each arc, homogenious for - # all vehicles. - routing.SetArcCostEvaluatorOfAllVehicles(dist_fn) - - # Set vehicle costs for each vehicle, not homogenious. - for veh in vehicles.vehicles: - routing.SetFixedCostOfVehicle(veh.cost, int(veh.index)) - - # Add a dimension for vehicle capacities - null_capacity_slack = 0 - routing.AddDimensionWithVehicleCapacity(dem_fn, # demand callback - null_capacity_slack, - capacity, # capacity array - True, - "Capacity") - # Add a dimension for time and a limit on the total time_horizon - routing.AddDimension(tot_time_fn, # total time function callback - customers.time_horizon, - customers.time_horizon, - True, - "Time") - - time_dimension = routing.GetDimensionOrDie("Time") - for cust in customers.customers: - if cust.tw_open is not None: - time_dimension.CumulVar(routing.NodeToIndex(cust.index)).SetRange( - cust.tw_open.seconds, - cust.tw_close.seconds) - """ + time_dimension = routing.GetDimensionOrDie('Time') + for cust in customers.customers: + if cust.tw_open is not None: + time_dimension.CumulVar(routing.NodeToIndex(cust.index)).SetRange( + cust.tw_open.seconds, cust.tw_close.seconds) + """ To allow the dropping of orders, we add disjunctions to all the customer nodes. Each disjunction is a list of 1 index, which allows that customer to be active or not, with a penalty if not. The penalty should be larger than the cost of servicing that customer, or it will always be dropped! """ - # To add disjunctions just to the customers, make a list of non-depots. - non_depot = set(range(customers.number)) - non_depot.difference_update(vehicles.starts) - non_depot.difference_update(vehicles.ends) - penalty = 400000 # The cost for dropping a node from the plan. - nodes = [routing.AddDisjunction([int(c)], penalty) for c in non_depot] + # To add disjunctions just to the customers, make a list of non-depots. + non_depot = set(range(customers.number)) + non_depot.difference_update(vehicles.starts) + non_depot.difference_update(vehicles.ends) + penalty = 400000 # The cost for dropping a node from the plan. + nodes = [routing.AddDisjunction([int(c)], penalty) for c in non_depot] - # This is how you would implement partial routes if you already knew part - # of a feasible solution for example: - # partial = np.random.choice(list(non_depot), size=(4,5), replace=False) + # This is how you would implement partial routes if you already knew part + # of a feasible solution for example: + # partial = np.random.choice(list(non_depot), size=(4,5), replace=False) - # routing.CloseModel() - # partial_list = [partial[0,:].tolist(), - # partial[1,:].tolist(), - # partial[2,:].tolist(), - # partial[3,:].tolist(), - # [],[],[],[]] - # print(routing.ApplyLocksToAllVehicles(partial_list, False)) + # routing.CloseModel() + # partial_list = [partial[0,:].tolist(), + # partial[1,:].tolist(), + # partial[2,:].tolist(), + # partial[3,:].tolist(), + # [],[],[],[]] + # print(routing.ApplyLocksToAllVehicles(partial_list, False)) - # Solve the problem ! - assignment = routing.SolveWithParameters(parameters) + # Solve the problem ! + assignment = routing.SolveWithParameters(parameters) - # The rest is all optional for saving, printing or plotting the solution. - if assignment: - # save the assignment, (Google Protobuf format) - save_file_base = os.path.realpath(__file__).split('.')[0] - if routing.WriteAssignment(save_file_base + '_assignment.ass'): - print('succesfully wrote assignment to file ' + - save_file_base + '_assignment.ass') + # The rest is all optional for saving, printing or plotting the solution. + if assignment: + # save the assignment, (Google Protobuf format) + save_file_base = os.path.realpath(__file__).split('.')[0] + if routing.WriteAssignment(save_file_base + '_assignment.ass'): + print('succesfully wrote assignment to file ' + save_file_base + + '_assignment.ass') - print('The Objective Value is {0}'.format(assignment.ObjectiveValue())) + print('The Objective Value is {0}'.format(assignment.ObjectiveValue())) - plan_output, dropped = vehicle_output_string(routing, assignment) - print(plan_output) - print('dropped nodes: ' + ', '.join(dropped)) + plan_output, dropped = vehicle_output_string(routing, assignment) + print(plan_output) + print('dropped nodes: ' + ', '.join(dropped)) - # you could print debug information like this: - # print(routing.DebugOutputAssignment(assignment, 'Capacity')) + # you could print debug information like this: + # print(routing.DebugOutputAssignment(assignment, 'Capacity')) - vehicle_routes = {} - for veh in range(vehicles.number): - vehicle_routes[veh] = build_vehicle_route(routing, assignment, - customers, veh) + vehicle_routes = {} + for veh in range(vehicles.number): + vehicle_routes[veh] = build_vehicle_route(routing, assignment, customers, + veh) - # Plotting of the routes in matplotlib. - fig = plt.figure() - ax = fig.add_subplot(111) - # Plot all the nodes as black dots. - clon, clat = zip(*[(c.lon, c.lat) for c in customers.customers]) - ax.plot(clon, clat, 'k.') - # plot the routes as arrows - plot_vehicle_routes(vehicle_routes, ax, customers, vehicles) + # Plotting of the routes in matplotlib. + fig = plt.figure() + ax = fig.add_subplot(111) + # Plot all the nodes as black dots. + clon, clat = zip(*[(c.lon, c.lat) for c in customers.customers]) + ax.plot(clon, clat, 'k.') + # plot the routes as arrows + plot_vehicle_routes(vehicle_routes, ax, customers, vehicles) + + else: + print('No assignment') - else: - print('No assignment') if __name__ == '__main__': - main() + main() diff --git a/examples/python/debruijn_binary.py b/examples/python/debruijn_binary.py index 0a226c8d23..0039d466f8 100644 --- a/examples/python/debruijn_binary.py +++ b/examples/python/debruijn_binary.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ de Bruijn sequences in Google CP Solver. @@ -51,8 +50,8 @@ from ortools.constraint_solver import pywrapcp def toNum(solver, t, s, base): tlen = len(t) - solver.Add( - s == solver.Sum([(base ** (tlen - i - 1)) * t[i] for i in range(tlen)])) + solver.Add(s == solver.Sum([(base**(tlen - i - 1)) * t[i] + for i in range(tlen)])) def main(base=2, n=3, m=8): @@ -99,7 +98,7 @@ def main(base=2, n=3, m=8): print("Checks gcc") # declare variables - x = [solver.IntVar(0, (base ** n) - 1, "x%i" % i) for i in range(m)] + x = [solver.IntVar(0, (base**n) - 1, "x%i" % i) for i in range(m)] binary = {} for i in range(m): for j in range(n): @@ -154,8 +153,7 @@ def main(base=2, n=3, m=8): solution.Add([gcc[i] for i in range(base)]) db = solver.Phase([x[i] for i in range(m)] + [bin_code[i] for i in range(m)], - solver.CHOOSE_MIN_SIZE_LOWEST_MAX, - solver.ASSIGN_MIN_VALUE) + solver.CHOOSE_MIN_SIZE_LOWEST_MAX, solver.ASSIGN_MIN_VALUE) num_solutions = 0 solver.NewSearch(db) @@ -185,7 +183,7 @@ def main(base=2, n=3, m=8): base = 2 n = 3 -m = base ** n +m = base**n if __name__ == "__main__": if len(sys.argv) > 1: base = int(sys.argv[1]) diff --git a/examples/python/diet1.py b/examples/python/diet1.py index 57442d9e25..65dfb39b74 100644 --- a/examples/python/diet1.py +++ b/examples/python/diet1.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Simple diet problem in Google CP Solver. @@ -92,15 +91,14 @@ def main(unused_argv): # last solution since it's a minimization problem collector = solver.LastSolutionCollector(solution) search_log = solver.SearchLog(100, cost) - solver.Solve(solver.Phase(x + [cost], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [objective, search_log, collector]) + solver.Solve( + solver.Phase(x + [cost], solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE), + [objective, search_log, collector]) # get the first (and only) solution print("cost:", collector.ObjectiveValue(0)) - print([("abcdefghij"[i], collector.Value(0, x[i])) for i in range(n)]) + print([("abcdefghij" [i], collector.Value(0, x[i])) for i in range(n)]) print() print("failures:", solver.Failures()) print("branches:", solver.Branches()) diff --git a/examples/python/diet1_b.py b/examples/python/diet1_b.py index 8baa47e13a..f89fa5b6e9 100644 --- a/examples/python/diet1_b.py +++ b/examples/python/diet1_b.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Simple diet problem in Google CP Solver. @@ -94,14 +93,13 @@ def main(unused_argv): # last solution since it's a minimization problem collector = solver.LastSolutionCollector(solution) search_log = solver.SearchLog(100, cost) - solver.Solve(solver.Phase(x + [cost], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [objective, search_log, collector]) + solver.Solve( + solver.Phase(x + [cost], solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE), + [objective, search_log, collector]) # get the first (and only) solution print("cost:", collector.ObjectiveValue(0)) - print([("abcdefghij"[i], collector.Value(0, x[i])) for i in range(n)]) + print([("abcdefghij" [i], collector.Value(0, x[i])) for i in range(n)]) print() print("failures:", solver.Failures()) print("branches:", solver.Branches()) diff --git a/examples/python/diet1_mip.py b/examples/python/diet1_mip.py index 5ecdbe96b1..4a46be7d69 100644 --- a/examples/python/diet1_mip.py +++ b/examples/python/diet1_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Simple diet problem using MIP in Google CP Solver. @@ -77,14 +76,10 @@ def main(sol='CBC'): # # constraints # - solver.Add(solver.Sum([x[i] * calories[i] - for i in range(n)]) >= limits[0]) - solver.Add(solver.Sum([x[i] * chocolate[i] - for i in range(n)]) >= limits[1]) - solver.Add(solver.Sum([x[i] * sugar[i] - for i in range(n)]) >= limits[2]) - solver.Add(solver.Sum([x[i] * fat[i] - for i in range(n)]) >= limits[3]) + solver.Add(solver.Sum([x[i] * calories[i] for i in range(n)]) >= limits[0]) + solver.Add(solver.Sum([x[i] * chocolate[i] for i in range(n)]) >= limits[1]) + solver.Add(solver.Sum([x[i] * sugar[i] for i in range(n)]) >= limits[2]) + solver.Add(solver.Sum([x[i] * fat[i] for i in range(n)]) >= limits[3]) # objective objective = solver.Minimize(cost) diff --git a/examples/python/discrete_tomography.py b/examples/python/discrete_tomography.py index b1c46f59c1..83a9b7041f 100644 --- a/examples/python/discrete_tomography.py +++ b/examples/python/discrete_tomography.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Discrete tomography in Google CP Solver. @@ -87,10 +86,16 @@ def main(row_sums="", col_sums=""): # # constraints # - [solver.Add(solver.Sum([x[i][j] for j in range(c)]) == row_sums[i]) - for i in range(r)] - [solver.Add(solver.Sum([x[i][j] for i in range(r)]) == col_sums[j]) - for j in range(c)] + [ + solver.Add(solver.Sum([x[i][j] + for j in range(c)]) == row_sums[i]) + for i in range(r) + ] + [ + solver.Add(solver.Sum([x[i][j] + for i in range(r)]) == col_sums[j]) + for j in range(c) + ] # # solution and search @@ -99,9 +104,7 @@ def main(row_sums="", col_sums=""): solution.Add(x_flat) # db: DecisionBuilder - db = solver.Phase(x_flat, - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x_flat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -118,23 +121,24 @@ def main(row_sums="", col_sums=""): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + # # Print solution # def print_solution(x, rows, cols, row_sums, col_sums): - print(" ", end=' ') + print(" ", end=" ") for j in range(cols): - print(col_sums[j], end=' ') + print(col_sums[j], end=" ") print() for i in range(rows): - print(row_sums[i], end=' ') + print(row_sums[i], end=" ") for j in range(cols): if x[i][j].Value() == 1: - print("#", end=' ') + print("#", end=" ") else: - print(".", end=' ') + print(".", end=" ") print("") @@ -150,6 +154,7 @@ def read_problem(file): return [row_sums, col_sums] + if __name__ == "__main__": if len(sys.argv) > 1: file = sys.argv[1] diff --git a/examples/python/divisible_by_9_through_1.py b/examples/python/divisible_by_9_through_1.py index f3dee52e3c..f17472e3c7 100644 --- a/examples/python/divisible_by_9_through_1.py +++ b/examples/python/divisible_by_9_through_1.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Divisible by 9 through 1 puzzle in Google CP Solver. @@ -101,8 +100,8 @@ def my_mod(solver, x, y, r): # def toNum(solver, t, s, base): tlen = len(t) - solver.Add( - s == solver.Sum([(base ** (tlen - i - 1)) * t[i] for i in range(tlen)])) + solver.Add(s == solver.Sum([(base**(tlen - i - 1)) * t[i] + for i in range(tlen)])) def main(base=10): @@ -111,7 +110,7 @@ def main(base=10): solver = pywrapcp.Solver("Divisible by 9 through 1") # data - m = base ** (base - 1) - 1 + m = base**(base - 1) - 1 n = base - 1 digits_str = "_0123456789ABCDEFGH" @@ -143,18 +142,15 @@ def main(base=10): solution.Add(x) solution.Add(t) - db = solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 while solver.NextSolution(): print("x: ", [x[i].Value() for i in range(n)]) print("t: ", [t[i].Value() for i in range(n)]) - print("number base 10: %i base %i: %s" % (t[0].Value(), - base, - "".join([digits_str[x[i].Value() + 1] for i in range(n)]))) + print("number base 10: %i base %i: %s" % (t[0].Value(), base, "".join( + [digits_str[x[i].Value() + 1] for i in range(n)]))) print() num_solutions += 1 solver.EndSearch() @@ -172,7 +168,8 @@ if __name__ == "__main__": if len(sys.argv) > 1: base = int(sys.argv[1]) if base > max_base: - print("Sorry, max allowed base is %i. Setting base to %i..." % (max_base, default_base)) + print("Sorry, max allowed base is %i. Setting base to %i..." % + (max_base, default_base)) base = default_base main(base) diff --git a/examples/python/dudeney.py b/examples/python/dudeney.py index ebe5c7ac14..d7a9e168c5 100644 --- a/examples/python/dudeney.py +++ b/examples/python/dudeney.py @@ -17,21 +17,20 @@ from ortools.constraint_solver import pywrapcp def dudeney(n): solver = pywrapcp.Solver('Dudeney') x = [solver.IntVar(list(range(10)), 'x' + str(i)) for i in range(n)] - nb = solver.IntVar(list(range(3, 10 ** n)), 'nb') + nb = solver.IntVar(list(range(3, 10**n)), 'nb') s = solver.IntVar(list(range(1, 9 * n + 1)), 's') solver.Add(nb == s * s * s) - solver.Add(sum([10 ** (n - i - 1) * x[i] for i in range(n)]) == nb) + solver.Add(sum([10**(n - i - 1) * x[i] for i in range(n)]) == nb) solver.Add(sum([x[i] for i in range(n)]) == s) solution = solver.Assignment() solution.Add(nb) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector]) + solver.Solve( + solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector]) for i in range(collector.SolutionCount()): nbsol = collector.Value(i, nb) @@ -40,5 +39,6 @@ def dudeney(n): print('#fails:', solver.Failures()) print('time:', solver.WallTime(), 'ms') + if __name__ == '__main__': dudeney(6) diff --git a/examples/python/einav_puzzle.py b/examples/python/einav_puzzle.py index 84db252cb0..07218e1c86 100644 --- a/examples/python/einav_puzzle.py +++ b/examples/python/einav_puzzle.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ A programming puzzle from Einav in Google CP Solver. @@ -88,35 +87,33 @@ def main(): # Full problem rows = 27 cols = 9 - data = [ - [33, 30, 10, -6, 18, -7, -11, 23, -6], - [16, -19, 9, -26, -8, -19, -8, -21, -14], - [17, 12, -14, 31, -30, 13, -13, 19, 16], - [-6, -11, 1, 17, -12, -4, -7, 14, -21], - [18, -31, 34, -22, 17, -19, 20, 24, 6], - [33, -18, 17, -15, 31, -5, 3, 27, -3], - [-18, -20, -18, 31, 6, 4, -2, -12, 24], - [27, 14, 4, -29, -3, 5, -29, 8, -12], - [-15, -7, -23, 23, -9, -8, 6, 8, -12], - [33, -23, -19, -4, -8, -7, 11, -12, 31], - [-20, 19, -15, -30, 11, 32, 7, 14, -5], - [-23, 18, -32, -2, -31, -7, 8, 24, 16], - [32, -4, -10, -14, -6, -1, 0, 23, 23], - [25, 0, -23, 22, 12, 28, -27, 15, 4], - [-30, -13, -16, -3, -3, -32, -3, 27, -31], - [22, 1, 26, 4, -2, -13, 26, 17, 14], - [-9, -18, 3, -20, -27, -32, -11, 27, 13], - [-17, 33, -7, 19, -32, 13, -31, -2, -24], - [-31, 27, -31, -29, 15, 2, 29, -15, 33], - [-18, -23, 15, 28, 0, 30, -4, 12, -32], - [-3, 34, 27, -25, -18, 26, 1, 34, 26], - [-21, -31, -10, -13, -30, -17, -12, -26, 31], - [23, -31, -19, 21, -17, -10, 2, -23, 23], - [-3, 6, 0, -3, -32, 0, -10, -25, 14], - [-19, 9, 14, -27, 20, 15, -5, -27, 18], - [11, -6, 24, 7, -17, 26, 20, -31, -25], - [-25, 4, -16, 30, 33, 23, -4, -4, 23] - ] + data = [[33, 30, 10, -6, 18, -7, -11, 23, + -6], [16, -19, 9, -26, -8, -19, -8, -21, + -14], [17, 12, -14, 31, -30, 13, -13, 19, + 16], [-6, -11, 1, 17, -12, -4, -7, 14, -21], + [18, -31, 34, -22, 17, -19, 20, 24, + 6], [33, -18, 17, -15, 31, -5, 3, + 27, -3], [-18, -20, -18, 31, 6, 4, -2, -12, + 24], [27, 14, 4, -29, -3, 5, -29, 8, + -12], [-15, -7, -23, 23, -9, -8, 6, 8, -12], + [33, -23, -19, -4, -8, -7, 11, -12, + 31], [-20, 19, -15, -30, 11, 32, 7, 14, + -5], [-23, 18, -32, -2, -31, -7, 8, 24, + 16], [32, -4, -10, -14, -6, -1, 0, 23, + 23], [25, 0, -23, 22, 12, 28, -27, 15, 4], + [-30, -13, -16, -3, -3, -32, -3, 27, + -31], [22, 1, 26, 4, -2, -13, + 26, 17, 14], [-9, -18, 3, -20, -27, -32, -11, 27, + 13], [-17, 33, -7, 19, -32, 13, -31, -2, -24], + [-31, 27, -31, -29, 15, 2, 29, -15, + 33], [-18, -23, 15, 28, 0, 30, -4, 12, + -32], [-3, 34, 27, -25, -18, 26, 1, 34, + 26], [-21, -31, -10, -13, -30, -17, -12, -26, + 31], [23, -31, -19, 21, -17, -10, 2, -23, 23], [ + -3, 6, 0, -3, -32, 0, -10, -25, 14 + ], [-19, 9, 14, -27, 20, 15, -5, -27, 18], [ + 11, -6, 24, 7, -17, 26, 20, -31, -25 + ], [-25, 4, -16, 30, 33, 23, -4, -4, 23]] # # variables @@ -128,15 +125,11 @@ def main(): x_flat = [x[i, j] for i in range(rows) for j in range(cols)] - row_sums = [solver.IntVar(0, 300, 'row_sums(%i)' % i) - for i in range(rows)] - col_sums = [solver.IntVar(0, 300, 'col_sums(%i)' % j) - for j in range(cols)] + row_sums = [solver.IntVar(0, 300, 'row_sums(%i)' % i) for i in range(rows)] + col_sums = [solver.IntVar(0, 300, 'col_sums(%i)' % j) for j in range(cols)] - row_signs = [solver.IntVar([-1, 1], 'row_signs(%i)' % i) - for i in range(rows)] - col_signs = [solver.IntVar([-1, 1], 'col_signs(%i)' % j) - for j in range(cols)] + row_signs = [solver.IntVar([-1, 1], 'row_signs(%i)' % i) for i in range(rows)] + col_signs = [solver.IntVar([-1, 1], 'col_signs(%i)' % j) for j in range(cols)] # total sum: to be minimized total_sum = solver.IntVar(0, 1000, 'total_sum') @@ -148,20 +141,21 @@ def main(): for j in range(cols): solver.Add(x[i, j] == data[i][j] * row_signs[i] * col_signs[j]) - total_sum_a = [data[i][j] * row_signs[i] * col_signs[j] - for i in range(rows) for j in range(cols)] + total_sum_a = [ + data[i][j] * row_signs[i] * col_signs[j] + for i in range(rows) + for j in range(cols) + ] solver.Add(total_sum == solver.Sum(total_sum_a)) # row sums for i in range(rows): - s = [row_signs[i] * col_signs[j] * data[i][j] - for j in range(cols)] + s = [row_signs[i] * col_signs[j] * data[i][j] for j in range(cols)] solver.Add(row_sums[i] == solver.Sum(s)) # column sums for j in range(cols): - s = [row_signs[i] * col_signs[j] * data[i][j] - for i in range(rows)] + s = [row_signs[i] * col_signs[j] * data[i][j] for i in range(rows)] solver.Add(col_sums[j] == solver.Sum(s)) # objective @@ -172,8 +166,7 @@ def main(): # # Note: The order of the variables makes a big difference. # If row_signs are before col_sign it is much slower. - db = solver.Phase(col_signs + row_signs, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_MAX_VALUE) solver.NewSearch(db, [objective]) diff --git a/examples/python/einav_puzzle2.py b/examples/python/einav_puzzle2.py index a595817a37..5ee2c7a09e 100644 --- a/examples/python/einav_puzzle2.py +++ b/examples/python/einav_puzzle2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ A programming puzzle from Einav in Google CP Solver. @@ -89,35 +88,33 @@ def main(): # Full problem rows = 27 cols = 9 - data = [ - [33, 30, 10, -6, 18, -7, -11, 23, -6], - [16, -19, 9, -26, -8, -19, -8, -21, -14], - [17, 12, -14, 31, -30, 13, -13, 19, 16], - [-6, -11, 1, 17, -12, -4, -7, 14, -21], - [18, -31, 34, -22, 17, -19, 20, 24, 6], - [33, -18, 17, -15, 31, -5, 3, 27, -3], - [-18, -20, -18, 31, 6, 4, -2, -12, 24], - [27, 14, 4, -29, -3, 5, -29, 8, -12], - [-15, -7, -23, 23, -9, -8, 6, 8, -12], - [33, -23, -19, -4, -8, -7, 11, -12, 31], - [-20, 19, -15, -30, 11, 32, 7, 14, -5], - [-23, 18, -32, -2, -31, -7, 8, 24, 16], - [32, -4, -10, -14, -6, -1, 0, 23, 23], - [25, 0, -23, 22, 12, 28, -27, 15, 4], - [-30, -13, -16, -3, -3, -32, -3, 27, -31], - [22, 1, 26, 4, -2, -13, 26, 17, 14], - [-9, -18, 3, -20, -27, -32, -11, 27, 13], - [-17, 33, -7, 19, -32, 13, -31, -2, -24], - [-31, 27, -31, -29, 15, 2, 29, -15, 33], - [-18, -23, 15, 28, 0, 30, -4, 12, -32], - [-3, 34, 27, -25, -18, 26, 1, 34, 26], - [-21, -31, -10, -13, -30, -17, -12, -26, 31], - [23, -31, -19, 21, -17, -10, 2, -23, 23], - [-3, 6, 0, -3, -32, 0, -10, -25, 14], - [-19, 9, 14, -27, 20, 15, -5, -27, 18], - [11, -6, 24, 7, -17, 26, 20, -31, -25], - [-25, 4, -16, 30, 33, 23, -4, -4, 23] - ] + data = [[33, 30, 10, -6, 18, -7, -11, 23, + -6], [16, -19, 9, -26, -8, -19, -8, -21, + -14], [17, 12, -14, 31, -30, 13, -13, 19, + 16], [-6, -11, 1, 17, -12, -4, -7, 14, -21], + [18, -31, 34, -22, 17, -19, 20, 24, + 6], [33, -18, 17, -15, 31, -5, 3, + 27, -3], [-18, -20, -18, 31, 6, 4, -2, -12, + 24], [27, 14, 4, -29, -3, 5, -29, 8, + -12], [-15, -7, -23, 23, -9, -8, 6, 8, -12], + [33, -23, -19, -4, -8, -7, 11, -12, + 31], [-20, 19, -15, -30, 11, 32, 7, 14, + -5], [-23, 18, -32, -2, -31, -7, 8, 24, + 16], [32, -4, -10, -14, -6, -1, 0, 23, + 23], [25, 0, -23, 22, 12, 28, -27, 15, 4], + [-30, -13, -16, -3, -3, -32, -3, 27, + -31], [22, 1, 26, 4, -2, -13, + 26, 17, 14], [-9, -18, 3, -20, -27, -32, -11, 27, + 13], [-17, 33, -7, 19, -32, 13, -31, -2, -24], + [-31, 27, -31, -29, 15, 2, 29, -15, + 33], [-18, -23, 15, 28, 0, 30, -4, 12, + -32], [-3, 34, 27, -25, -18, 26, 1, 34, + 26], [-21, -31, -10, -13, -30, -17, -12, -26, + 31], [23, -31, -19, 21, -17, -10, 2, -23, 23], [ + -3, 6, 0, -3, -32, 0, -10, -25, 14 + ], [-19, 9, 14, -27, 20, 15, -5, -27, 18], [ + 11, -6, 24, 7, -17, 26, 20, -31, -25 + ], [-25, 4, -16, 30, 33, 23, -4, -4, 23]] # # variables @@ -129,10 +126,8 @@ def main(): x_flat = [x[i, j] for i in range(rows) for j in range(cols)] - row_signs = [solver.IntVar([-1, 1], "row_signs(%i)" % i) - for i in range(rows)] - col_signs = [solver.IntVar([-1, 1], "col_signs(%i)" % j) - for j in range(cols)] + row_signs = [solver.IntVar([-1, 1], "row_signs(%i)" % i) for i in range(rows)] + col_signs = [solver.IntVar([-1, 1], "col_signs(%i)" % j) for j in range(cols)] # # constraints @@ -148,15 +143,17 @@ def main(): # # row sums - row_sums = [solver.Sum([x[i, j] for j in range(cols)]).Var() - for i in range(rows)] + row_sums = [ + solver.Sum([x[i, j] for j in range(cols)]).Var() for i in range(rows) + ] # >= 0 for i in range(rows): row_sums[i].SetMin(0) # column sums - col_sums = [solver.Sum([x[i, j] for i in range(rows)]).Var() - for j in range(cols)] + col_sums = [ + solver.Sum([x[i, j] for i in range(rows)]).Var() for j in range(cols) + ] for j in range(cols): col_sums[j].SetMin(0) @@ -166,8 +163,7 @@ def main(): # # search and result # - db = solver.Phase(col_signs + row_signs, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(col_signs + row_signs, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_MAX_VALUE) solver.NewSearch(db, [objective]) @@ -180,7 +176,7 @@ def main(): print("col_sums:", [col_sums[j].Value() for j in range(cols)]) for i in range(rows): for j in range(cols): - print("%3i" % x[i, j].Value(), end=' ') + print("%3i" % x[i, j].Value(), end=" ") print() print() diff --git a/examples/python/eq10.py b/examples/python/eq10.py index e36788aa2f..770d490270 100644 --- a/examples/python/eq10.py +++ b/examples/python/eq10.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Eq 10 in Google CP Solver. @@ -50,43 +49,40 @@ def main(): # # constraints # - solver.Add(0 + 98527 * X1 + 34588 * X2 + 5872 * X3 + 59422 * X5 + 65159 * X7 - == 1547604 + 30704 * X4 + 29649 * X6) + solver.Add(0 + 98527 * X1 + 34588 * X2 + 5872 * X3 + 59422 * X5 + + 65159 * X7 == 1547604 + 30704 * X4 + 29649 * X6) - solver.Add( - 0 + 98957 * X2 + 83634 * X3 + 69966 * X4 + 62038 * X5 + 37164 * X6 + 85413 * X7 == 1823553 + 93989 * - X1) + solver.Add(0 + 98957 * X2 + 83634 * X3 + 69966 * X4 + 62038 * X5 + + 37164 * X6 + 85413 * X7 == 1823553 + 93989 * X1) - solver.Add(900032 + 10949 * X1 + 77761 * X2 + 67052 * X5 - == 0 + 80197 * X3 + 61944 * X4 + 92964 * X6 + 44550 * X7) + solver.Add(900032 + 10949 * X1 + 77761 * X2 + 67052 * X5 == 0 + 80197 * X3 + + 61944 * X4 + 92964 * X6 + 44550 * X7) - solver.Add(0 + 73947 * X1 + 84391 * X3 + 81310 * X5 - == 1164380 + 96253 * X2 + 44247 * X4 + 70582 * X6 + 33054 * X7) + solver.Add(0 + 73947 * X1 + 84391 * X3 + 81310 * X5 == 1164380 + 96253 * X2 + + 44247 * X4 + 70582 * X6 + 33054 * X7) - solver.Add(0 + 13057 * X3 + 42253 * X4 + 77527 * X5 + 96552 * X7 - == 1185471 + 60152 * X1 + 21103 * X2 + 97932 * X6) + solver.Add(0 + 13057 * X3 + 42253 * X4 + 77527 * X5 + 96552 * X7 == 1185471 + + 60152 * X1 + 21103 * X2 + 97932 * X6) - solver.Add(1394152 + 66920 * X1 + 55679 * X4 == - 0 + 64234 * X2 + 65337 * X3 + 45581 * X5 + 67707 * X6 + 98038 * X7) + solver.Add(1394152 + 66920 * X1 + 55679 * X4 == 0 + 64234 * X2 + 65337 * X3 + + 45581 * X5 + 67707 * X6 + 98038 * X7) - solver.Add(0 + 68550 * X1 + 27886 * X2 + 31716 * X3 + 73597 * X4 + 38835 * X7 - == 279091 + 88963 * X5 + 76391 * X6) + solver.Add(0 + 68550 * X1 + 27886 * X2 + 31716 * X3 + 73597 * X4 + + 38835 * X7 == 279091 + 88963 * X5 + 76391 * X6) - solver.Add(0 + 76132 * X2 + 71860 * X3 + 22770 * X4 + 68211 * X5 + 78587 * X6 - == 480923 + 48224 * X1 + 82817 * X7) + solver.Add(0 + 76132 * X2 + 71860 * X3 + 22770 * X4 + 68211 * X5 + + 78587 * X6 == 480923 + 48224 * X1 + 82817 * X7) - solver.Add(519878 + 94198 * X2 + 87234 * X3 + 37498 * X4 - == 0 + 71583 * X1 + 25728 * X5 + 25495 * X6 + 70023 * X7) + solver.Add(519878 + 94198 * X2 + 87234 * X3 + 37498 * X4 == 0 + 71583 * X1 + + 25728 * X5 + 25495 * X6 + 70023 * X7) - solver.Add(361921 + 78693 * X1 + 38592 * X5 + 38478 * X6 - == 0 + 94129 * X2 + 43188 * X3 + 82528 * X4 + 69025 * X7) + solver.Add(361921 + 78693 * X1 + 38592 * X5 + 38478 * X6 == 0 + 94129 * X2 + + 43188 * X3 + 82528 * X4 + 69025 * X7) # # search and result # - db = solver.Phase(X, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_SIMPLE) + db = solver.Phase(X, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) solver.NewSearch(db) diff --git a/examples/python/eq20.py b/examples/python/eq20.py index b06c8e4dab..8c4ad70b06 100644 --- a/examples/python/eq20.py +++ b/examples/python/eq20.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Eq 20 in Google CP Solver. @@ -94,9 +93,7 @@ def main(): # # search and result # - db = solver.Phase(X, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(X, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/fill_a_pix.py b/examples/python/fill_a_pix.py index dfd828c29a..558089abff 100644 --- a/examples/python/fill_a_pix.py +++ b/examples/python/fill_a_pix.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Fill-a-Pix problem in Google CP Solver. @@ -55,23 +54,18 @@ from __future__ import print_function import sys from ortools.constraint_solver import pywrapcp - # Puzzle 1 from # http://www.conceptispuzzles.com/index.aspx?uri=puzzle/fill-a-pix/rules default_n = 10 X = -1 -default_puzzle = [ - [X, X, X, X, X, X, X, X, 0, X], - [X, 8, 8, X, 2, X, 0, X, X, X], - [5, X, 8, X, X, X, X, X, X, X], - [X, X, X, X, X, 2, X, X, X, 2], - [1, X, X, X, 4, 5, 6, X, X, X], - [X, 0, X, X, X, 7, 9, X, X, 6], - [X, X, X, 6, X, X, 9, X, X, 6], - [X, X, 6, 6, 8, 7, 8, 7, X, 5], - [X, 4, X, 6, 6, 6, X, 6, X, 4], - [X, X, X, X, X, X, 3, X, X, X] -] +default_puzzle = [[X, X, X, X, X, X, X, X, 0, X], [ + X, 8, 8, X, 2, X, 0, X, X, X +], [5, X, 8, X, X, X, X, X, X, + X], [X, X, X, X, X, 2, X, X, X, + 2], [1, X, X, X, 4, 5, 6, X, X, X], [X, 0, X, X, X, 7, 9, X, X, 6], [ + X, X, X, 6, X, X, 9, X, X, 6 + ], [X, X, 6, 6, 8, 7, 8, 7, X, 5], [X, 4, X, 6, 6, 6, X, 6, X, 4], + [X, X, X, X, X, X, 3, X, X, X]] def main(puzzle='', n=''): @@ -121,21 +115,17 @@ def main(puzzle='', n=''): for j in range(n): if puzzle[i][j] > X: # this cell is the sum of all the surrounding cells - solver.Add( - puzzle[i][j] == solver.Sum([pict[i + a, j + b] - for a in S for b in S - if i + a >= 0 and - j + b >= 0 and - i + a < n and - j + b < n]) - ) + solver.Add(puzzle[i][j] == solver.Sum([ + pict[i + a, j + b] + for a in S + for b in S + if i + a >= 0 and j + b >= 0 and i + a < n and j + b < n + ])) # # solution and search # - db = solver.Phase(pict_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(pict_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) num_solutions = 0 diff --git a/examples/python/flexible_job_shop_sat.py b/examples/python/flexible_job_shop_sat.py index a9b108e063..2f664efcb5 100644 --- a/examples/python/flexible_job_shop_sat.py +++ b/examples/python/flexible_job_shop_sat.py @@ -30,15 +30,12 @@ class SolutionPrinter(cp_model.CpSolverSolutionCallback): # Data part. -jobs = [ [ [(3, 0), (1, 1), (5, 2)], - [(2, 0), (4, 1), (6, 2)], - [(2, 0), (3, 1), (1, 2)] ], - [ [(2, 0), (3, 1), (4, 2)], - [(1, 0), (5, 1), (4, 2)], - [(2, 0), (1, 1), (4, 2)] ], - [ [(2, 0), (1, 1), (4, 2)], - [(2, 0), (3, 1), (4, 2)], - [(3, 0), (1, 1), (5, 2)] ] ] +jobs = [[[(3, 0), (1, 1), (5, 2)], [(2, 0), (4, 1), (6, 2)], [(2, 0), (3, 1), + (1, 2)]], + [[(2, 0), (3, 1), (4, 2)], [(1, 0), (5, 1), (4, 2)], + [(2, 0), (1, 1), (4, 2)]], [[(2, 0), (1, 1), (4, 2)], + [(2, 0), (3, 1), (4, 2)], [(3, 0), (1, 1), + (5, 2)]]] num_jobs = len(jobs) all_jobs = range(num_jobs) @@ -51,96 +48,93 @@ model = cp_model.CpModel() horizon = 0 for job in jobs: - for task in job: - max_task_duration = 0 - for alternative in task: - max_task_duration = max(max_task_duration, alternative[0]) - horizon += max_task_duration + for task in job: + max_task_duration = 0 + for alternative in task: + max_task_duration = max(max_task_duration, alternative[0]) + horizon += max_task_duration print('Horizon = %i' % horizon) - # Global storage of variables. intervals_per_resources = defaultdict(list) -starts = {} # indexed by (job_id, task_id). +starts = {} # indexed by (job_id, task_id). presences = {} # indexed by (job_id, task_id, alt_id). job_ends = [] # Scan the jobs and create the relevant variables and intervals. for job_id in all_jobs: - job = jobs[job_id] - num_tasks = len(job) - previous_end = None - for task_id in range(num_tasks): - task = job[task_id] + job = jobs[job_id] + num_tasks = len(job) + previous_end = None + for task_id in range(num_tasks): + task = job[task_id] - min_duration = task[0][0] - max_duration = task[0][0] + min_duration = task[0][0] + max_duration = task[0][0] - num_alternatives = len(task) - all_alternatives = range(num_alternatives) + num_alternatives = len(task) + all_alternatives = range(num_alternatives) - for alt_id in range(1, num_alternatives): - alt_duration = task[alt_id][0] - min_duration = min(min_duration, alt_duration) - max_duration = max(max_duration, alt_duration) + for alt_id in range(1, num_alternatives): + alt_duration = task[alt_id][0] + min_duration = min(min_duration, alt_duration) + max_duration = max(max_duration, alt_duration) - # Create main interval for the task. - suffix_name = '_j%i_t%i' % (job_id, task_id) - start = model.NewIntVar(0, horizon, 'start' + suffix_name) - duration = model.NewIntVar(min_duration, max_duration, - 'duration' + suffix_name) - end = model.NewIntVar(0, horizon, 'end' + suffix_name) - interval = model.NewIntervalVar( - start, duration, end, 'interval' + suffix_name) + # Create main interval for the task. + suffix_name = '_j%i_t%i' % (job_id, task_id) + start = model.NewIntVar(0, horizon, 'start' + suffix_name) + duration = model.NewIntVar(min_duration, max_duration, + 'duration' + suffix_name) + end = model.NewIntVar(0, horizon, 'end' + suffix_name) + interval = model.NewIntervalVar(start, duration, end, + 'interval' + suffix_name) - # Store the start for the solution. - starts[(job_id, task_id)] = start + # Store the start for the solution. + starts[(job_id, task_id)] = start - # Add precedence with previous task in the same job. - if previous_end: - model.Add(start >= previous_end) - previous_end = end + # Add precedence with previous task in the same job. + if previous_end: + model.Add(start >= previous_end) + previous_end = end - # Create alternative intervals. - if num_alternatives > 1: - l_presences = [] - for alt_id in all_alternatives: - alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id) - l_presence = model.NewBoolVar('presence' + alt_suffix) - l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix) - l_duration = task[alt_id][0] - l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix) - l_interval = model.NewOptionalIntervalVar( - l_start, l_duration, l_end, l_presence, - 'interval' + alt_suffix) - l_presences.append(l_presence) + # Create alternative intervals. + if num_alternatives > 1: + l_presences = [] + for alt_id in all_alternatives: + alt_suffix = '_j%i_t%i_a%i' % (job_id, task_id, alt_id) + l_presence = model.NewBoolVar('presence' + alt_suffix) + l_start = model.NewIntVar(0, horizon, 'start' + alt_suffix) + l_duration = task[alt_id][0] + l_end = model.NewIntVar(0, horizon, 'end' + alt_suffix) + l_interval = model.NewOptionalIntervalVar( + l_start, l_duration, l_end, l_presence, 'interval' + alt_suffix) + l_presences.append(l_presence) - # Link the master variables with the local ones. - model.Add(start == l_start).OnlyEnforceIf(l_presence) - model.Add(duration == l_duration).OnlyEnforceIf(l_presence) - model.Add(end == l_end).OnlyEnforceIf(l_presence) + # Link the master variables with the local ones. + model.Add(start == l_start).OnlyEnforceIf(l_presence) + model.Add(duration == l_duration).OnlyEnforceIf(l_presence) + model.Add(end == l_end).OnlyEnforceIf(l_presence) - # Add the local interval to the right machine. - intervals_per_resources[task[alt_id][1]].append(l_interval) + # Add the local interval to the right machine. + intervals_per_resources[task[alt_id][1]].append(l_interval) - # Store the presences for the solution. - presences[(job_id, task_id, alt_id)] = l_presence + # Store the presences for the solution. + presences[(job_id, task_id, alt_id)] = l_presence - # Select exactly one presence variable. - model.Add(sum(l_presences) == 1) - else: - intervals_per_resources[task[0][1]].append(interval) - presences[(job_id, task_id, 0)] = model.NewConstant(1) + # Select exactly one presence variable. + model.Add(sum(l_presences) == 1) + else: + intervals_per_resources[task[0][1]].append(interval) + presences[(job_id, task_id, 0)] = model.NewConstant(1) - job_ends.append(previous_end) + job_ends.append(previous_end) # Create machines constraints. for machine_id in all_machines: - intervals = intervals_per_resources[machine_id] - if len(intervals) > 1: - model.AddNoOverlap(intervals) - + intervals = intervals_per_resources[machine_id] + if len(intervals) > 1: + model.AddNoOverlap(intervals) # Makespan objective makespan = model.NewIntVar(0, horizon, 'makespan') @@ -154,20 +148,19 @@ status = solver.SolveWithSolutionObserver(model, solution_printer) # Print final solution. for job_id in all_jobs: - print('Job %i:' % job_id) - for task_id in range(len(jobs[job_id])): - start_value = solver.Value(starts[(job_id, task_id)]) - machine = -1 - duration = -1 - selected = -1 - for alt_id in range(len(jobs[job_id][task_id])): - if solver.Value(presences[(job_id, task_id, alt_id)]): - duration = jobs[job_id][task_id][alt_id][0] - machine = jobs[job_id][task_id][alt_id][1] - selected = alt_id - print( - ' task_%i_%i starts at %i (alt %i, machine %i, duration %i)' % - (job_id, task_id, start_value, selected, machine, duration)) + print('Job %i:' % job_id) + for task_id in range(len(jobs[job_id])): + start_value = solver.Value(starts[(job_id, task_id)]) + machine = -1 + duration = -1 + selected = -1 + for alt_id in range(len(jobs[job_id][task_id])): + if solver.Value(presences[(job_id, task_id, alt_id)]): + duration = jobs[job_id][task_id][alt_id][0] + machine = jobs[job_id][task_id][alt_id][1] + selected = alt_id + print(' task_%i_%i starts at %i (alt %i, machine %i, duration %i)' % + (job_id, task_id, start_value, selected, machine, duration)) print('Solve status: %s' % solver.StatusName(status)) print('Optimal objective value: %i' % solver.ObjectiveValue()) diff --git a/examples/python/furniture_moving.py b/examples/python/furniture_moving.py index 631f6e68c4..bdccc47c14 100644 --- a/examples/python/furniture_moving.py +++ b/examples/python/furniture_moving.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Moving furnitures (scheduling) problem in Google CP Solver. @@ -98,9 +97,11 @@ def main(): # declare variables # start_times = [ - solver.IntVar(0, upper_limit, "start_times[%i]" % i) for i in range(n)] + solver.IntVar(0, upper_limit, "start_times[%i]" % i) for i in range(n) + ] end_times = [ - solver.IntVar(0, upper_limit * 2, "end_times[%i]" % i) for i in range(n)] + solver.IntVar(0, upper_limit * 2, "end_times[%i]" % i) for i in range(n) + ] end_time = solver.IntVar(0, upper_limit * 2, "end_time") # number of needed resources, to be minimized @@ -145,8 +146,7 @@ def main(): solution.Add(end_time) solution.Add(num_resources) - db = solver.Phase(start_times, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(start_times, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) # @@ -171,5 +171,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/futoshiki.py b/examples/python/futoshiki.py index 44b1217bb7..c82c68b7ae 100644 --- a/examples/python/futoshiki.py +++ b/examples/python/futoshiki.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Futoshiki problem in Google CP Solver. @@ -90,14 +89,13 @@ def main(values, lt): # all < constraints are satisfied # Also: make 0-based for i in NUMQD: - solver.Add(field[lt[i][0] - 1, lt[i][1] - 1] < - field[lt[i][2] - 1, lt[i][3] - 1]) + solver.Add( + field[lt[i][0] - 1, lt[i][1] - 1] < field[lt[i][2] - 1, lt[i][3] - 1]) # # search and result # - db = solver.Phase(field_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(field_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -107,7 +105,7 @@ def main(values, lt): num_solutions += 1 for i in RANGE: for j in RANGE: - print(field[i, j].Value(), end=' ') + print(field[i, j].Value(), end=" ") print() print() @@ -131,29 +129,14 @@ def main(values, lt): # Futoshiki instance, by Andras Salamon # specify the numbers in the grid # -values1 = [ - [0, 0, 3, 2, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0]] - +values1 = [[0, 0, 3, 2, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]] # [i1,j1, i2,j2] requires that values[i1,j1] < values[i2,j2] # Note: 1-based -lt1 = [ - [1, 2, 1, 1], - [1, 4, 1, 5], - [2, 3, 1, 3], - [3, 3, 2, 3], - [3, 4, 2, 4], - [2, 5, 3, 5], - [3, 2, 4, 2], - [4, 4, 4, 3], - [5, 2, 5, 1], - [5, 4, 5, 3], - [5, 5, 4, 5]] - +lt1 = [[1, 2, 1, 1], [1, 4, 1, 5], [2, 3, 1, 3], [3, 3, 2, 3], [3, 4, 2, 4], + [2, 5, 3, 5], [3, 2, 4, 2], [4, 4, 4, 3], [5, 2, 5, 1], [5, 4, 5, 3], + [5, 5, 4, 5]] # # Example from http://en.wikipedia.org/wiki/Futoshiki @@ -164,23 +147,12 @@ lt1 = [ # 3 5 2 1 4 # 1 2 5 4 3 # -values2 = [ - [0, 0, 0, 0, 0], - [4, 0, 0, 0, 2], - [0, 0, 4, 0, 0], - [0, 0, 0, 0, 4], - [0, 0, 0, 0, 0]] +values2 = [[0, 0, 0, 0, 0], [4, 0, 0, 0, 2], [0, 0, 4, 0, 0], [0, 0, 0, 0, 4], + [0, 0, 0, 0, 0]] # Note: 1-based -lt2 = [ - [1, 2, 1, 1], - [1, 4, 1, 3], - [1, 5, 1, 4], - [4, 4, 4, 5], - [5, 1, 5, 2], - [5, 2, 5, 3] -] - +lt2 = [[1, 2, 1, 1], [1, 4, 1, 3], [1, 5, 1, 4], [4, 4, 4, 5], [5, 1, 5, 2], + [5, 2, 5, 3]] if __name__ == "__main__": print("Problem 1") diff --git a/examples/python/game_theory_taha.py b/examples/python/game_theory_taha.py index 93992287d4..2fd0b31b5b 100644 --- a/examples/python/game_theory_taha.py +++ b/examples/python/game_theory_taha.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Game theory in Google or-tools. @@ -46,9 +45,7 @@ def main(sol='CBC'): rows = 3 cols = 3 - game = [[3.0, -1.0, -3.0], - [-2.0, 4.0, -1.0], - [-5.0, -6.0, 2.0]] + game = [[3.0, -1.0, -3.0], [-2.0, 4.0, -1.0], [-5.0, -6.0, 2.0]] # # declare variables @@ -57,8 +54,7 @@ def main(sol='CBC'): # # row player # - x1 = [solver.NumVar(0, 1, 'x1[%i]' % i) - for i in range(rows)] + x1 = [solver.NumVar(0, 1, 'x1[%i]' % i) for i in range(rows)] v = solver.NumVar(-2, 2, 'v') @@ -83,8 +79,7 @@ def main(sol='CBC'): # # For column player: # - x2 = [solver.NumVar(0, 1, 'x2[%i]' % i) - for i in range(cols)] + x2 = [solver.NumVar(0, 1, 'x2[%i]' % i) for i in range(cols)] v2 = solver.NumVar(-2, 2, 'v2') @@ -110,6 +105,7 @@ def main(sol='CBC'): print('iterations:', solver.Iterations()) print() + if __name__ == '__main__': sol = 'GLPK' diff --git a/examples/python/gate_scheduling_sat.py b/examples/python/gate_scheduling_sat.py index 46c208726a..dcb70fc660 100644 --- a/examples/python/gate_scheduling_sat.py +++ b/examples/python/gate_scheduling_sat.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Gate Scheduling problem. We have a set of jobs to perform (duration, width). @@ -29,21 +28,8 @@ from ortools.sat.python import visualization def main(): model = cp_model.CpModel() - jobs = [[3, 3], - [2, 5], - [1, 3], - [3, 7], - [7, 3], - [2, 2], - [2, 2], - [5, 5], - [10, 2], - [4, 3], - [2, 6], - [1, 2], - [6, 8], - [4, 5], - [3, 7]] + jobs = [[3, 3], [2, 5], [1, 3], [3, 7], [7, 3], [2, 2], [2, 2], [5, 5], + [10, 2], [4, 3], [2, 6], [1, 2], [6, 8], [4, 5], [3, 7]] max_length = 10 @@ -74,21 +60,22 @@ def main(): performed.append(performed_on_m0) # Create an optional copy of interval to be executed on machine 0. - start0 = model.NewOptionalIntVar( - 0, horizon, performed_on_m0, 'start_%i_on_m0' % i) - end0 = model.NewOptionalIntVar( - 0, horizon, performed_on_m0, 'end_%i_on_m0' % i) + start0 = model.NewOptionalIntVar(0, horizon, performed_on_m0, + 'start_%i_on_m0' % i) + end0 = model.NewOptionalIntVar(0, horizon, performed_on_m0, + 'end_%i_on_m0' % i) interval0 = model.NewOptionalIntervalVar( start0, duration, end0, performed_on_m0, 'interval_%i_on_m0' % i) intervals0.append(interval0) # Create an optional copy of interval to be executed on machine 1. - start1 = model.NewOptionalIntVar( - 0, horizon, performed_on_m0.Not(), 'start_%i_on_m1' % i) - end1 = model.NewOptionalIntVar( - 0, horizon, performed_on_m0.Not(), 'end_%i_on_m1' % i) - interval1 = model.NewOptionalIntervalVar( - start1, duration, end1, performed_on_m0.Not(), 'interval_%i_on_m1' % i) + start1 = model.NewOptionalIntVar(0, horizon, performed_on_m0.Not(), + 'start_%i_on_m1' % i) + end1 = model.NewOptionalIntVar(0, horizon, performed_on_m0.Not(), + 'end_%i_on_m1' % i) + interval1 = model.NewOptionalIntervalVar(start1, duration, end1, + performed_on_m0.Not(), + 'interval_%i_on_m1' % i) intervals1.append(interval1) # We only propagate the constraint if the tasks is performed on the machine. @@ -114,7 +101,6 @@ def main(): solver = cp_model.CpSolver() solver.Solve(model) - # Output solution. if visualization.RunFromIPython(): output = visualization.SvgWrapper(solver.ObjectiveValue(), max_length, 40.0) @@ -140,8 +126,8 @@ def main(): for i in all_jobs: performed_machine = 1 - solver.Value(performed[i]) start = solver.Value(starts[i]) - print(' - Job %i starts at %i on machine %i' % - (i, start, performed_machine)) + print(' - Job %i starts at %i on machine %i' % (i, start, + performed_machine)) print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) diff --git a/examples/python/golomb8.py b/examples/python/golomb8.py index 08daeb1662..fb37d2c7c7 100644 --- a/examples/python/golomb8.py +++ b/examples/python/golomb8.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """This is the Golomb ruler problem. This model aims at maximizing radar interferences in a minimum space. @@ -23,7 +22,6 @@ of the rule. from ortools.constraint_solver import pywrapcp - # We disable the following warning because it is a false positive on constraints # like: solver.Add(x == 0) # pylint: disable=g-explicit-bool-comparison @@ -42,9 +40,12 @@ def main(): objective = solver.Minimize(marks[size - 1], 1) solver.Add(marks[0] == 0) - solver.Add(solver.AllDifferent([marks[j] - marks[i] - for i in range(0, size - 1) - for j in range(i + 1, size)])) + solver.Add( + solver.AllDifferent([ + marks[j] - marks[i] + for i in range(0, size - 1) + for j in range(i + 1, size) + ])) solver.Add(marks[size - 1] - marks[size - 2] > marks[1] - marks[0]) for i in range(0, size - 2): @@ -54,10 +55,9 @@ def main(): solution.Add(marks[size - 1]) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(marks, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [objective, collector]) + solver.Solve( + solver.Phase(marks, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE), + [objective, collector]) for i in range(0, collector.SolutionCount()): obj_value = collector.Value(i, marks[size - 1]) time = collector.WallTime(i) diff --git a/examples/python/grocery.py b/examples/python/grocery.py index 0b23cfc7de..98c51643a1 100644 --- a/examples/python/grocery.py +++ b/examples/python/grocery.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Grocery problem in Google CP Solver. @@ -63,7 +62,7 @@ def main(): # constraints # solver.Add(solver.Sum(item) == c) - solver.Add(reduce(lambda x, y: x * y, item) == c * 100 ** 3) + solver.Add(reduce(lambda x, y: x * y, item) == c * 100**3) # symmetry breaking for i in range(1, n): @@ -72,9 +71,7 @@ def main(): # # search and result # - db = solver.Phase(item, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_SIMPLE) + db = solver.Phase(item, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) solver.NewSearch(db) num_solutions = 0 @@ -91,5 +88,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/hidato.py b/examples/python/hidato.py index 3376beb267..86827286c1 100644 --- a/examples/python/hidato.py +++ b/examples/python/hidato.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Hidato puzzle in Google CP Solver. @@ -64,18 +63,17 @@ def main(): # [1,0,0] # ] - -# r = 7 -# c = 7 -# puzzle = [ -# [0,44,41, 0, 0, 0, 0], -# [0,43, 0,28,29, 0, 0], -# [0, 1, 0, 0, 0,33, 0], -# [0, 2,25, 4,34, 0,36], -# [49,16, 0,23, 0, 0, 0], -# [0,19, 0, 0,12, 7, 0], -# [0, 0, 0,14, 0, 0, 0] -# ] + # r = 7 + # c = 7 + # puzzle = [ + # [0,44,41, 0, 0, 0, 0], + # [0,43, 0,28,29, 0, 0], + # [0, 1, 0, 0, 0,33, 0], + # [0, 2,25, 4,34, 0,36], + # [49,16, 0,23, 0, 0, 0], + # [0,19, 0, 0,12, 7, 0], + # [0, 0, 0,14, 0, 0, 0] + # ] # Problems from the book: # Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles" @@ -91,8 +89,7 @@ def main(): # [ 0,25, 0, 0,12], # ] - -# # problem 2 (Practice) + # # problem 2 (Practice) r = 5 c = r puzzle = [ @@ -104,31 +101,31 @@ def main(): ] # problem 3 (Beginner) -# r = 6 -# c = r -# puzzle = [ -# [ 0, 26,0, 0, 0,18], -# [ 0, 0,27, 0, 0,19], -# [31,23, 0, 0,14, 0], -# [ 0,33, 8, 0,15, 1], -# [ 0, 0, 0, 5, 0, 0], -# [35,36, 0,10, 0, 0] -# ]; + # r = 6 + # c = r + # puzzle = [ + # [ 0, 26,0, 0, 0,18], + # [ 0, 0,27, 0, 0,19], + # [31,23, 0, 0,14, 0], + # [ 0,33, 8, 0,15, 1], + # [ 0, 0, 0, 5, 0, 0], + # [35,36, 0,10, 0, 0] + # ]; # Problem 15 (Intermediate) # Note: This takes very long time to solve... -# r = 8 -# c = r -# puzzle = [ -# [64, 0, 0, 0, 0, 0, 0, 0], -# [ 1,63, 0,59,15,57,53, 0], -# [ 0, 4, 0,14, 0, 0, 0, 0], -# [ 3, 0,11, 0,20,19, 0,50], -# [ 0, 0, 0, 0,22, 0,48,40], -# [ 9, 0, 0,32,23, 0, 0,41], -# [27, 0, 0, 0,36, 0,46, 0], -# [28,30, 0,35, 0, 0, 0, 0] -# ] + # r = 8 + # c = r + # puzzle = [ + # [64, 0, 0, 0, 0, 0, 0, 0], + # [ 1,63, 0,59,15,57,53, 0], + # [ 0, 4, 0,14, 0, 0, 0, 0], + # [ 3, 0,11, 0,20,19, 0,50], + # [ 0, 0, 0, 0,22, 0,48,40], + # [ 9, 0, 0,32,23, 0, 0,41], + # [27, 0, 0, 0,36, 0,46, 0], + # [28,30, 0,35, 0, 0, 0, 0] + # ] print_game(puzzle, r, c) @@ -188,22 +185,23 @@ def main(): solution.Add(x_flat) # db: DecisionBuilder - db = solver.Phase(x_flat, - # solver.INT_VAR_DEFAULT - # solver.INT_VAR_SIMPLE - # solver.CHOOSE_RANDOM - # solver.CHOOSE_MIN_SIZE_LOWEST_MIN - # solver.CHOOSE_MIN_SIZE_HIGHEST_MIN - # solver.CHOOSE_MIN_SIZE_LOWEST_MAX - # solver.CHOOSE_MIN_SIZE_HIGHEST_MAX - # solver.CHOOSE_PATH - solver.CHOOSE_FIRST_UNBOUND, - # solver.INT_VALUE_DEFAULT - # solver.INT_VALUE_SIMPLE - # solver.ASSIGN_MAX_VALUE - # solver.ASSIGN_RANDOM_VALUE - # solver.ASSIGN_CENTER_VALUE - solver.ASSIGN_MIN_VALUE) + db = solver.Phase( + x_flat, + # solver.INT_VAR_DEFAULT + # solver.INT_VAR_SIMPLE + # solver.CHOOSE_RANDOM + # solver.CHOOSE_MIN_SIZE_LOWEST_MIN + # solver.CHOOSE_MIN_SIZE_HIGHEST_MIN + # solver.CHOOSE_MIN_SIZE_LOWEST_MAX + # solver.CHOOSE_MIN_SIZE_HIGHEST_MAX + # solver.CHOOSE_PATH + solver.CHOOSE_FIRST_UNBOUND, + # solver.INT_VALUE_DEFAULT + # solver.INT_VALUE_SIMPLE + # solver.ASSIGN_MAX_VALUE + # solver.ASSIGN_RANDOM_VALUE + # solver.ASSIGN_CENTER_VALUE + solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -225,14 +223,14 @@ def main(): def print_board(x, rows, cols): for i in range(rows): for j in range(cols): - print("% 2s" % x[i, j].Value(), end=' ') + print("% 2s" % x[i, j].Value(), end=" ") print("") def print_game(game, rows, cols): for i in range(rows): for j in range(cols): - print("% 2s" % game[i][j], end=' ') + print("% 2s" % game[i][j], end=" ") print("") diff --git a/examples/python/hidato_sat.py b/examples/python/hidato_sat.py index f39cb7862a..fdb23e3525 100644 --- a/examples/python/hidato_sat.py +++ b/examples/python/hidato_sat.py @@ -28,11 +28,13 @@ def BuildPairs(rows, cols): rows: the number of rows in the grid cols: the number of columns in the grid """ - return [(x * cols + y, (x + dx) * cols + (y + dy)) - for x in range(rows) for y in range(cols) - for dx in (-1, 0, 1) for dy in (-1, 0, 1) - if (x + dx >= 0 and x + dx < rows and - y + dy >= 0 and y + dy < cols and (dx != 0 or dy != 0))] + return [ + (x * cols + y, (x + dx) * cols + (y + dy)) for x in range(rows) + for y in range(cols) for dx in (-1, 0, 1) + for dy in (-1, 0, 1) + if (x + dx >= 0 and x + dx < rows and y + dy >= 0 and y + dy < cols and + (dx != 0 or dy != 0)) + ] def PrintSolution(positions, rows, cols): @@ -72,55 +74,37 @@ def BuildPuzzle(problem): puzzle = None if problem == 1: # Simple problem - puzzle = [[6, 0, 9], - [0, 2, 8], - [1, 0, 0]] + puzzle = [[6, 0, 9], [0, 2, 8], [1, 0, 0]] elif problem == 2: - puzzle = [[0, 44, 41, 0, 0, 0, 0], - [0, 43, 0, 28, 29, 0, 0], - [0, 1, 0, 0, 0, 33, 0], - [0, 2, 25, 4, 34, 0, 36], - [49, 16, 0, 23, 0, 0, 0], - [0, 19, 0, 0, 12, 7, 0], - [0, 0, 0, 14, 0, 0, 0]] + puzzle = [[0, 44, 41, 0, 0, 0, 0], [0, 43, 0, 28, 29, 0, 0], + [0, 1, 0, 0, 0, 33, 0], [0, 2, 25, 4, 34, 0, 36], + [49, 16, 0, 23, 0, 0, 0], [0, 19, 0, 0, 12, 7, + 0], [0, 0, 0, 14, 0, 0, 0]] elif problem == 3: # Problems from the book: # Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles" # Problem 1 (Practice) - puzzle = [[0, 0, 20, 0, 0], - [0, 0, 0, 16, 18], - [22, 0, 15, 0, 0], - [23, 0, 1, 14, 11], - [0, 25, 0, 0, 12]] + puzzle = [[0, 0, 20, 0, 0], [0, 0, 0, 16, 18], [22, 0, 15, 0, 0], + [23, 0, 1, 14, 11], [0, 25, 0, 0, 12]] elif problem == 4: # problem 2 (Practice) - puzzle = [[0, 0, 0, 0, 14], - [0, 18, 12, 0, 0], - [0, 0, 17, 4, 5], - [0, 0, 7, 0, 0], - [9, 8, 25, 1, 0]] + puzzle = [[0, 0, 0, 0, 14], [0, 18, 12, 0, 0], [0, 0, 17, 4, 5], + [0, 0, 7, 0, 0], [9, 8, 25, 1, 0]] elif problem == 5: # problem 3 (Beginner) - puzzle = [[0, 26, 0, 0, 0, 18], - [0, 0, 27, 0, 0, 19], - [31, 23, 0, 0, 14, 0], - [0, 33, 8, 0, 15, 1], - [0, 0, 0, 5, 0, 0], - [35, 36, 0, 10, 0, 0]] + puzzle = [[0, 26, 0, 0, 0, 18], [0, 0, 27, 0, 0, 19], [31, 23, 0, 0, 14, 0], + [0, 33, 8, 0, 15, 1], [0, 0, 0, 5, 0, 0], [35, 36, 0, 10, 0, 0]] elif problem == 6: # Problem 15 (Intermediate) - puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], - [1, 63, 0, 59, 15, 57, 53, 0], - [0, 4, 0, 14, 0, 0, 0, 0], - [3, 0, 11, 0, 20, 19, 0, 50], - [0, 0, 0, 0, 22, 0, 48, 40], - [9, 0, 0, 32, 23, 0, 0, 41], - [27, 0, 0, 0, 36, 0, 46, 0], - [28, 30, 0, 35, 0, 0, 0, 0]] + puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], [1, 63, 0, 59, 15, 57, 53, 0], + [0, 4, 0, 14, 0, 0, 0, 0], [3, 0, 11, 0, 20, 19, 0, + 50], [0, 0, 0, 0, 22, 0, 48, 40], + [9, 0, 0, 32, 23, 0, 0, 41], [27, 0, 0, 0, 36, 0, 46, + 0], [28, 30, 0, 35, 0, 0, 0, 0]] return puzzle @@ -141,8 +125,7 @@ def SolveHidato(puzzle, index): # # declare variables # - positions = [model.NewIntVar(0, r * c - 1, 'p[%i]' % i) - for i in range(r * c)] + positions = [model.NewIntVar(0, r * c - 1, 'p[%i]' % i) for i in range(r * c)] # # constraints @@ -184,7 +167,11 @@ def SolveHidato(puzzle, index): output.AddTitle('Puzzle %i solved in %f s' % (index, solver.WallTime())) output.Display() else: - PrintSolution([solver.Value(x) for x in positions], r, c,) + PrintSolution( + [solver.Value(x) for x in positions], + r, + c, + ) print('Statistics') print(' - conflicts : %i' % solver.NumConflicts()) print(' - branches : %i' % solver.NumBranches()) diff --git a/examples/python/hidato_table.py b/examples/python/hidato_table.py index 1fb6ced8db..64d8a7a2f1 100644 --- a/examples/python/hidato_table.py +++ b/examples/python/hidato_table.py @@ -10,8 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - - """Hidato puzzle in Google CP Solver. http://www.hidato.com/ @@ -40,11 +38,13 @@ def BuildPairs(rows, cols): rows: the number of rows in the grid cols: the number of columns in the grid """ - return [(x * cols + y, (x + dx) * cols + (y + dy)) - for x in range(rows) for y in range(cols) - for dx in (-1, 0, 1) for dy in (-1, 0, 1) - if (x + dx >= 0 and x + dx < rows and - y + dy >= 0 and y + dy < cols and (dx != 0 or dy != 0))] + return [ + (x * cols + y, (x + dx) * cols + (y + dy)) for x in range(rows) + for y in range(cols) for dx in (-1, 0, 1) + for dy in (-1, 0, 1) + if (x + dx >= 0 and x + dx < rows and y + dy >= 0 and y + dy < cols and + (dx != 0 or dy != 0)) + ] def main(): @@ -67,56 +67,38 @@ def Solve(model): puzzle = None if model == 1: # Simple problem - puzzle = [[6, 0, 9], - [0, 2, 8], - [1, 0, 0]] + puzzle = [[6, 0, 9], [0, 2, 8], [1, 0, 0]] elif model == 2: - puzzle = [[0, 44, 41, 0, 0, 0, 0], - [0, 43, 0, 28, 29, 0, 0], - [0, 1, 0, 0, 0, 33, 0], - [0, 2, 25, 4, 34, 0, 36], - [49, 16, 0, 23, 0, 0, 0], - [0, 19, 0, 0, 12, 7, 0], - [0, 0, 0, 14, 0, 0, 0]] + puzzle = [[0, 44, 41, 0, 0, 0, 0], [0, 43, 0, 28, 29, 0, 0], + [0, 1, 0, 0, 0, 33, 0], [0, 2, 25, 4, 34, 0, 36], + [49, 16, 0, 23, 0, 0, 0], [0, 19, 0, 0, 12, 7, + 0], [0, 0, 0, 14, 0, 0, 0]] elif model == 3: # Problems from the book: # Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles" # Problem 1 (Practice) - puzzle = [[0, 0, 20, 0, 0], - [0, 0, 0, 16, 18], - [22, 0, 15, 0, 0], - [23, 0, 1, 14, 11], - [0, 25, 0, 0, 12]] + puzzle = [[0, 0, 20, 0, 0], [0, 0, 0, 16, 18], [22, 0, 15, 0, 0], + [23, 0, 1, 14, 11], [0, 25, 0, 0, 12]] elif model == 4: # problem 2 (Practice) - puzzle = [[0, 0, 0, 0, 14], - [0, 18, 12, 0, 0], - [0, 0, 17, 4, 5], - [0, 0, 7, 0, 0], - [9, 8, 25, 1, 0]] + puzzle = [[0, 0, 0, 0, 14], [0, 18, 12, 0, 0], [0, 0, 17, 4, 5], + [0, 0, 7, 0, 0], [9, 8, 25, 1, 0]] elif model == 5: # problem 3 (Beginner) - puzzle = [[0, 26, 0, 0, 0, 18], - [0, 0, 27, 0, 0, 19], - [31, 23, 0, 0, 14, 0], - [0, 33, 8, 0, 15, 1], - [0, 0, 0, 5, 0, 0], - [35, 36, 0, 10, 0, 0]] + puzzle = [[0, 26, 0, 0, 0, 18], [0, 0, 27, 0, 0, 19], [31, 23, 0, 0, 14, 0], + [0, 33, 8, 0, 15, 1], [0, 0, 0, 5, 0, 0], [35, 36, 0, 10, 0, 0]] elif model == 6: # Problem 15 (Intermediate) - puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], - [1, 63, 0, 59, 15, 57, 53, 0], - [0, 4, 0, 14, 0, 0, 0, 0], - [3, 0, 11, 0, 20, 19, 0, 50], - [0, 0, 0, 0, 22, 0, 48, 40], - [9, 0, 0, 32, 23, 0, 0, 41], - [27, 0, 0, 0, 36, 0, 46, 0], - [28, 30, 0, 35, 0, 0, 0, 0]] + puzzle = [[64, 0, 0, 0, 0, 0, 0, 0], [1, 63, 0, 59, 15, 57, 53, 0], + [0, 4, 0, 14, 0, 0, 0, 0], [3, 0, 11, 0, 20, 19, 0, + 50], [0, 0, 0, 0, 22, 0, 48, 40], + [9, 0, 0, 32, 23, 0, 0, 41], [27, 0, 0, 0, 36, 0, 46, + 0], [28, 30, 0, 35, 0, 0, 0, 0]] r = len(puzzle) c = len(puzzle[0]) @@ -146,16 +128,16 @@ def Solve(model): # We use an allowed assignment constraint to model it. close_tuples = BuildPairs(r, c) for k in range(1, r * c - 1): - solver.Add(solver.AllowedAssignments((positions[k], positions[k + 1]), - close_tuples)) + solver.Add( + solver.AllowedAssignments((positions[k], positions[k + 1]), + close_tuples)) # # solution and search # # db: DecisionBuilder - db = solver.Phase(positions, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(positions, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/integer_programming.py b/examples/python/integer_programming.py index 8fe396904c..f87d731361 100644 --- a/examples/python/integer_programming.py +++ b/examples/python/integer_programming.py @@ -10,10 +10,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Integer programming examples that show how to use the APIs.""" - from ortools.linear_solver import pywraplp @@ -82,8 +80,8 @@ def SolveAndPrint(solver, variable_list): def Announce(solver, api_type): - print(('---- Integer programming example with ' + solver + ' (' + - api_type + ') -----')) + print(('---- Integer programming example with ' + solver + ' (' + api_type + + ') -----')) def RunAllIntegerExampleNaturalLanguageAPI(): @@ -110,8 +108,7 @@ def RunAllIntegerExampleCppStyleAPI(): RunIntegerExampleCppStyleAPI(pywraplp.Solver.CBC_MIXED_INTEGER_PROGRAMMING) if hasattr(pywraplp.Solver, 'SCIP_MIXED_INTEGER_PROGRAMMING'): Announce('SCIP', 'C++ style API') - RunIntegerExampleCppStyleAPI( - pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING) + RunIntegerExampleCppStyleAPI(pywraplp.Solver.SCIP_MIXED_INTEGER_PROGRAMMING) def main(): diff --git a/examples/python/jobshop_ft06.py b/examples/python/jobshop_ft06.py index 1e2780ad20..ca32d99b80 100644 --- a/examples/python/jobshop_ft06.py +++ b/examples/python/jobshop_ft06.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """This model implements a simple jobshop named ft06. A jobshop is a standard scheduling problem when you must sequence a @@ -22,8 +21,6 @@ The objective is to minimize the maximum completion time of all jobs. This is called the makespan. """ - - from ortools.constraint_solver import pywrapcp @@ -36,19 +33,11 @@ def main(): all_machines = range(0, machines_count) all_jobs = range(0, jobs_count) - durations = [[1, 3, 6, 7, 3, 6], - [8, 5, 10, 10, 10, 4], - [5, 4, 8, 9, 1, 7], - [5, 5, 5, 3, 8, 9], - [9, 3, 5, 4, 3, 1], - [3, 3, 9, 10, 4, 1]] + durations = [[1, 3, 6, 7, 3, 6], [8, 5, 10, 10, 10, 4], [5, 4, 8, 9, 1, 7], + [5, 5, 5, 3, 8, 9], [9, 3, 5, 4, 3, 1], [3, 3, 9, 10, 4, 1]] - machines = [[2, 0, 1, 3, 5, 4], - [1, 2, 4, 5, 0, 3], - [2, 3, 5, 0, 1, 4], - [1, 0, 2, 3, 4, 5], - [2, 1, 4, 5, 0, 3], - [1, 3, 5, 0, 4, 2]] + machines = [[2, 0, 1, 3, 5, 4], [1, 2, 4, 5, 0, 3], [2, 3, 5, 0, 1, 4], + [1, 0, 2, 3, 4, 5], [2, 1, 4, 5, 0, 3], [1, 3, 5, 0, 4, 2]] # Computes horizon dynamically. horizon = sum([sum(durations[i]) for i in all_jobs]) @@ -57,11 +46,8 @@ def main(): all_tasks = {} for i in all_jobs: for j in all_machines: - all_tasks[(i, j)] = solver.FixedDurationIntervalVar(0, - horizon, - durations[i][j], - False, - 'Job_%i_%i' % (i, j)) + all_tasks[(i, j)] = solver.FixedDurationIntervalVar( + 0, horizon, durations[i][j], False, 'Job_%i_%i' % (i, j)) # Creates sequence variables and add disjuctive constraints. all_sequences = [] @@ -80,8 +66,8 @@ def main(): collector.Add(all_sequences) # Makespan objective. - obj_var = solver.Max([all_tasks[(i, machines_count - 1)].EndExpr() - for i in all_jobs]) + obj_var = solver.Max( + [all_tasks[(i, machines_count - 1)].EndExpr() for i in all_jobs]) objective = solver.Minimize(obj_var, 1) # Precedences inside a job. @@ -90,8 +76,7 @@ def main(): solver.Add(all_tasks[(i, j + 1)].StartsAfterEnd(all_tasks[(i, j)])) # Creates search phases. - vars_phase = solver.Phase([obj_var], - solver.CHOOSE_FIRST_UNBOUND, + vars_phase = solver.Phase([obj_var], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) sequence_phase = solver.Phase([all_sequences[i] for i in all_machines], solver.SEQUENCE_DEFAULT) diff --git a/examples/python/jobshop_ft06_distance.py b/examples/python/jobshop_ft06_distance.py index 4d64c5b553..063593d129 100644 --- a/examples/python/jobshop_ft06_distance.py +++ b/examples/python/jobshop_ft06_distance.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """This model implements a simple jobshop named ft06. A jobshop is a standard scheduling problem when you must sequence a @@ -22,11 +21,11 @@ The objective is to minimize the maximum completion time of all jobs. This is called the makespan. """ - from ortools.constraint_solver import pywrapcp class Dist: + def __init__(self): pass @@ -43,19 +42,11 @@ def main(): all_machines = range(0, machines_count) all_jobs = range(0, jobs_count) - durations = [[1, 3, 6, 7, 3, 6], - [8, 5, 10, 10, 10, 4], - [5, 4, 8, 9, 1, 7], - [5, 5, 5, 3, 8, 9], - [9, 3, 5, 4, 3, 1], - [3, 3, 9, 10, 4, 1]] + durations = [[1, 3, 6, 7, 3, 6], [8, 5, 10, 10, 10, 4], [5, 4, 8, 9, 1, 7], + [5, 5, 5, 3, 8, 9], [9, 3, 5, 4, 3, 1], [3, 3, 9, 10, 4, 1]] - machines = [[2, 0, 1, 3, 5, 4], - [1, 2, 4, 5, 0, 3], - [2, 3, 5, 0, 1, 4], - [1, 0, 2, 3, 4, 5], - [2, 1, 4, 5, 0, 3], - [1, 3, 5, 0, 4, 2]] + machines = [[2, 0, 1, 3, 5, 4], [1, 2, 4, 5, 0, 3], [2, 3, 5, 0, 1, 4], + [1, 0, 2, 3, 4, 5], [2, 1, 4, 5, 0, 3], [1, 3, 5, 0, 4, 2]] # Computes horizon dynamically. horizon = sum([sum(durations[i]) for i in all_jobs]) @@ -64,11 +55,8 @@ def main(): all_tasks = {} for i in all_jobs: for j in all_machines: - all_tasks[(i, j)] = solver.FixedDurationIntervalVar(0, - horizon, - durations[i][j], - False, - 'Job_%i_%i' % (i, j)) + all_tasks[(i, j)] = solver.FixedDurationIntervalVar( + 0, horizon, durations[i][j], False, 'Job_%i_%i' % (i, j)) # Creates sequence variables and add disjuctive constraints. all_sequences = {} @@ -90,8 +78,8 @@ def main(): solver.Add(disj) # Makespan objective. - obj_var = solver.Max([all_tasks[(i, machines_count - 1)].EndExpr() - for i in all_jobs]) + obj_var = solver.Max( + [all_tasks[(i, machines_count - 1)].EndExpr() for i in all_jobs]) objective = solver.Minimize(obj_var, 1) # Precedences inside a job. @@ -100,8 +88,7 @@ def main(): solver.Add(all_tasks[(i, j + 1)].StartsAfterEnd(all_tasks[(i, j)])) # Creates search phases. - vars_phase = solver.Phase([obj_var], - solver.CHOOSE_FIRST_UNBOUND, + vars_phase = solver.Phase([obj_var], solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) sequence_phase = solver.Phase([all_sequences[i] for i in all_machines], solver.SEQUENCE_DEFAULT) diff --git a/examples/python/jobshop_ft06_sat.py b/examples/python/jobshop_ft06_sat.py index 62a93d2a21..d4f7301a0d 100644 --- a/examples/python/jobshop_ft06_sat.py +++ b/examples/python/jobshop_ft06_sat.py @@ -25,19 +25,11 @@ def main(): all_machines = range(0, machines_count) all_jobs = range(0, jobs_count) - durations = [[1, 3, 6, 7, 3, 6], - [8, 5, 10, 10, 10, 4], - [5, 4, 8, 9, 1, 7], - [5, 5, 5, 3, 8, 9], - [9, 3, 5, 4, 3, 1], - [3, 3, 9, 10, 4, 1]] + durations = [[1, 3, 6, 7, 3, 6], [8, 5, 10, 10, 10, 4], [5, 4, 8, 9, 1, 7], + [5, 5, 5, 3, 8, 9], [9, 3, 5, 4, 3, 1], [3, 3, 9, 10, 4, 1]] - machines = [[2, 0, 1, 3, 5, 4], - [1, 2, 4, 5, 0, 3], - [2, 3, 5, 0, 1, 4], - [1, 0, 2, 3, 4, 5], - [2, 1, 4, 5, 0, 3], - [1, 3, 5, 0, 4, 2]] + machines = [[2, 0, 1, 3, 5, 4], [1, 2, 4, 5, 0, 3], [2, 3, 5, 0, 1, 4], + [1, 0, 2, 3, 4, 5], [2, 1, 4, 5, 0, 3], [1, 3, 5, 0, 4, 2]] # Computes horizon dynamically. horizon = sum([sum(durations[i]) for i in all_jobs]) @@ -52,10 +44,9 @@ def main(): duration = durations[i][j] end_var = model.NewIntVar(0, horizon, 'end_%i_%i' % (i, j)) interval_var = model.NewIntervalVar(start_var, duration, end_var, - 'interval_%i_%i' % (i, j)) - all_tasks[(i, j)] = Task(start=start_var, - end=end_var, - interval=interval_var) + 'interval_%i_%i' % (i, j)) + all_tasks[(i, j)] = Task( + start=start_var, end=end_var, interval=interval_var) # Create disjuctive constraints. machine_to_jobs = {} @@ -85,7 +76,8 @@ def main(): # Output solution. if visualization.RunFromIPython(): - starts = [[solver.Value(all_tasks[(i, j)][0]) for j in all_machines] + starts = [[solver.Value(all_tasks[(i, j)][0]) + for j in all_machines] for i in all_jobs] visualization.DisplayJobshop(starts, durations, machines, 'FT06') else: diff --git a/examples/python/just_forgotten.py b/examples/python/just_forgotten.py index d45922506c..9699f34e71 100644 --- a/examples/python/just_forgotten.py +++ b/examples/python/just_forgotten.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Just forgotten puzzle (Enigma 1517) in Google CP Solver. @@ -60,10 +59,8 @@ def main(): rows = 4 cols = 10 # The four tries - a = [[9, 4, 6, 2, 1, 5, 7, 8, 3, 0], - [8, 6, 0, 4, 3, 9, 1, 2, 5, 7], - [1, 6, 4, 0, 2, 9, 7, 8, 5, 3], - [6, 8, 2, 4, 3, 1, 9, 0, 7, 5]] + a = [[9, 4, 6, 2, 1, 5, 7, 8, 3, 0], [8, 6, 0, 4, 3, 9, 1, 2, 5, 7], + [1, 6, 4, 0, 2, 9, 7, 8, 5, 3], [6, 8, 2, 4, 3, 1, 9, 0, 7, 5]] # # variables @@ -82,9 +79,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -94,7 +89,7 @@ def main(): xval = [x[j].Value() for j in range(cols)] print("Account number:") for j in range(cols): - print("%i " % xval[j], end=' ') + print("%i " % xval[j], end=" ") print() print("\nThe four tries, where '!' represents a correct digit:") for i in range(rows): @@ -102,7 +97,7 @@ def main(): check = " " if a[i][j] == xval[j]: check = "!" - print("%i%s" % (a[i][j], check), end=' ') + print("%i%s" % (a[i][j], check), end=" ") print() print() print() @@ -114,5 +109,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/kakuro.py b/examples/python/kakuro.py index c6c80ff927..574b6d410f 100644 --- a/examples/python/kakuro.py +++ b/examples/python/kakuro.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Kakuru puzzle in Google CP Solver. @@ -93,47 +92,29 @@ def main(): # segments # [sum, [segments]] # Note: 1-based - problem = [ - [16, [1, 1], [1, 2]], - [24, [1, 5], [1, 6], [1, 7]], - [17, [2, 1], [2, 2]], - [29, [2, 4], [2, 5], [2, 6], [2, 7]], - [35, [3, 1], [3, 2], [3, 3], [3, 4], [3, 5]], - [7, [4, 2], [4, 3]], - [8, [4, 5], [4, 6]], - [16, [5, 3], [5, 4], [5, 5], [5, 6], [5, 7]], - [21, [6, 1], [6, 2], [6, 3], [6, 4]], - [5, [6, 6], [6, 7]], - [6, [7, 1], [7, 2], [7, 3]], - [3, [7, 6], [7, 7]], - - [23, [1, 1], [2, 1], [3, 1]], - [30, [1, 2], [2, 2], [3, 2], [4, 2]], - [27, [1, 5], [2, 5], [3, 5], [4, 5], [5, 5]], - [12, [1, 6], [2, 6]], - [16, [1, 7], [2, 7]], - [17, [2, 4], [3, 4]], - [15, [3, 3], [4, 3], [5, 3], [6, 3], [7, 3]], - [12, [4, 6], [5, 6], [6, 6], [7, 6]], - [7, [5, 4], [6, 4]], - [7, [5, 7], [6, 7], [7, 7]], - [11, [6, 1], [7, 1]], - [10, [6, 2], [7, 2]] - ] + problem = [[16, [1, 1], [1, 2]], [24, [1, 5], [1, 6], [1, 7]], [ + 17, [2, 1], [2, 2] + ], [29, [2, 4], [2, 5], [2, 6], + [2, 7]], [35, [3, 1], [3, 2], [3, 3], [3, 4], + [3, 5]], [7, [4, 2], [4, 3]], [8, [4, 5], [4, 6]], [ + 16, [5, 3], [5, 4], [5, 5], [5, 6], [5, 7] + ], [21, [6, 1], [6, 2], [6, 3], + [6, 4]], [5, [6, 6], [6, 7]], [6, [7, 1], [7, 2], [7, 3]], + [3, [7, 6], [7, 7]], [23, [1, 1], [2, 1], [3, 1]], [ + 30, [1, 2], [2, 2], [3, 2], [4, 2] + ], [27, [1, 5], [2, 5], [3, 5], [4, 5], [5, 5]], + [12, [1, 6], [2, 6]], [16, [1, 7], [2, 7]], [17, [2, 4], [3, 4]], [ + 15, [3, 3], [4, 3], [5, 3], [6, 3], [7, 3] + ], [12, [4, 6], [5, 6], [6, 6], [7, 6]], [7, [5, 4], [6, 4]], [ + 7, [5, 7], [6, 7], [7, 7] + ], [11, [6, 1], [7, 1]], [10, [6, 2], [7, 2]]] num_p = len(problem) # The blanks # Note: 1-based - blanks = [ - [1, 3], [1, 4], - [2, 3], - [3, 6], [3, 7], - [4, 1], [4, 4], [4, 7], - [5, 1], [5, 2], - [6, 5], - [7, 4], [7, 5] - ] + blanks = [[1, 3], [1, 4], [2, 3], [3, 6], [3, 7], [4, 1], [4, 4], [4, 7], + [5, 1], [5, 2], [6, 5], [7, 4], [7, 5]] num_blanks = len(blanks) # @@ -170,9 +151,7 @@ def main(): # # search and solution # - db = solver.Phase(x_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -182,9 +161,9 @@ def main(): for j in range(n): val = x[i, j].Value() if val > 0: - print(val, end=' ') + print(val, end=" ") else: - print(" ", end=' ') + print(" ", end=" ") print() print() diff --git a/examples/python/kenken2.py b/examples/python/kenken2.py index e236756050..8ed0b49f3c 100644 --- a/examples/python/kenken2.py +++ b/examples/python/kenken2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ KenKen puzzle in Google CP Solver. @@ -126,22 +125,16 @@ def main(): # hints # [sum, [segments]] # Note: 1-based - problem = [ - [11, [[1, 1], [2, 1]]], - [2, [[1, 2], [1, 3]]], - [20, [[1, 4], [2, 4]]], - [6, [[1, 5], [1, 6], [2, 6], [3, 6]]], - [3, [[2, 2], [2, 3]]], - [3, [[2, 5], [3, 5]]], - [240, [[3, 1], [3, 2], [4, 1], [4, 2]]], - [6, [[3, 3], [3, 4]]], - [6, [[4, 3], [5, 3]]], - [7, [[4, 4], [5, 4], [5, 5]]], - [30, [[4, 5], [4, 6]]], - [6, [[5, 1], [5, 2]]], - [9, [[5, 6], [6, 6]]], - [8, [[6, 1], [6, 2], [6, 3]]], - [2, [[6, 4], [6, 5]]]] + problem = [[11, [[1, 1], [2, 1]]], [2, [[1, 2], [1, + 3]]], [20, [[1, 4], [2, 4]]], + [6, [[1, 5], [1, 6], [2, 6], + [3, 6]]], [3, [[2, 2], [2, 3]]], [3, [[2, 5], [3, 5]]], [ + 240, [[3, 1], [3, 2], [4, 1], [4, 2]] + ], [6, [[3, 3], [3, 4]]], [6, [[4, 3], [5, 3]]], [ + 7, [[4, 4], [5, 4], [5, 5]] + ], [30, [[4, 5], [4, 6]]], [6, [[5, 1], [5, 2]]], + [9, [[5, 6], [6, 6]]], [8, [[6, 1], [6, 2], + [6, 3]]], [2, [[6, 4], [6, 5]]]] num_p = len(problem) @@ -176,9 +169,7 @@ def main(): # # search and solution # - db = solver.Phase(x_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -186,7 +177,7 @@ def main(): while solver.NextSolution(): for i in range(n): for j in range(n): - print(x[i, j].Value(), end=' ') + print(x[i, j].Value(), end=" ") print() print() diff --git a/examples/python/killer_sudoku.py b/examples/python/killer_sudoku.py index ed0fba8128..e7c1b42d9f 100644 --- a/examples/python/killer_sudoku.py +++ b/examples/python/killer_sudoku.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Killer Sudoku in Google CP Solver. @@ -106,36 +105,25 @@ def main(): # hints # [sum, [segments]] # Note: 1-based - problem = [ - [3, [[1, 1], [1, 2]]], - [15, [[1, 3], [1, 4], [1, 5]]], - [22, [[1, 6], [2, 5], [2, 6], [3, 5]]], - [4, [[1, 7], [2, 7]]], - [16, [[1, 8], [2, 8]]], - [15, [[1, 9], [2, 9], [3, 9], [4, 9]]], - [25, [[2, 1], [2, 2], [3, 1], [3, 2]]], - [17, [[2, 3], [2, 4]]], - [9, [[3, 3], [3, 4], [4, 4]]], - [8, [[3, 6], [4, 6], [5, 6]]], - [20, [[3, 7], [3, 8], [4, 7]]], - [6, [[4, 1], [5, 1]]], - [14, [[4, 2], [4, 3]]], - [17, [[4, 5], [5, 5], [6, 5]]], - [17, [[4, 8], [5, 7], [5, 8]]], - [13, [[5, 2], [5, 3], [6, 2]]], - [20, [[5, 4], [6, 4], [7, 4]]], - [12, [[5, 9], [6, 9]]], - [27, [[6, 1], [7, 1], [8, 1], [9, 1]]], - [6, [[6, 3], [7, 2], [7, 3]]], - [20, [[6, 6], [7, 6], [7, 7]]], - [6, [[6, 7], [6, 8]]], - [10, [[7, 5], [8, 4], [8, 5], [9, 4]]], - [14, [[7, 8], [7, 9], [8, 8], [8, 9]]], - [8, [[8, 2], [9, 2]]], - [16, [[8, 3], [9, 3]]], - [15, [[8, 6], [8, 7]]], - [13, [[9, 5], [9, 6], [9, 7]]], - [17, [[9, 8], [9, 9]]]] + problem = [[3, [[1, 1], [1, 2]]], [15, [[1, 3], [1, 4], [1, 5]]], + [22, [[1, 6], [2, 5], [2, 6], [3, 5]]], [4, [[1, 7], [2, 7]]], + [16, [[1, 8], [2, 8]]], [15, [[1, 9], [2, 9], [3, 9], [4, 9]]], [ + 25, [[2, 1], [2, 2], [3, 1], [3, 2]] + ], [17, [[2, 3], [2, 4]]], [9, [[3, 3], [3, 4], [4, 4]]], [ + 8, [[3, 6], [4, 6], [5, 6]] + ], [20, [[3, 7], [3, 8], [4, 7]]], [6, [[4, 1], [5, 1]]], [ + 14, [[4, 2], [4, 3]] + ], [17, [[4, 5], [5, 5], [6, 5]]], [17, [[4, 8], [5, 7], [5, 8]]], + [13, [[5, 2], [5, 3], [6, 2]]], [20, [[5, 4], [6, 4], [7, 4]]], [ + 12, [[5, 9], [6, 9]] + ], [27, [[6, 1], [7, 1], [8, 1], [9, 1]]], [ + 6, [[6, 3], [7, 2], [7, 3]] + ], [20, [[6, 6], [7, 6], [7, 7]]], [6, [[6, 7], [6, 8]]], [ + 10, [[7, 5], [8, 4], [8, 5], [9, 4]] + ], [14, [[7, 8], [7, 9], [8, 8], [8, 9]]], [8, [[8, 2], [9, 2]]], [ + 16, [[8, 3], [9, 3]] + ], [15, [[8, 6], [8, 7]]], [13, [[9, 5], [9, 6], + [9, 7]]], [17, [[9, 8], [9, 9]]]] # # variables @@ -164,9 +152,11 @@ def main(): # cells for i in range(2): for j in range(2): - cell = [x[r, c] - for r in range(i * 3, i * 3 + 3) - for c in range(j * 3, j * 3 + 3)] + cell = [ + x[r, c] + for r in range(i * 3, i * 3 + 3) + for c in range(j * 3, j * 3 + 3) + ] solver.Add(solver.AllDifferent(cell)) # calculate the segments @@ -176,9 +166,7 @@ def main(): # # search and solution # - db = solver.Phase(x_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/knapsack.py b/examples/python/knapsack.py index aa4a01c8de..0edaeabb37 100644 --- a/examples/python/knapsack.py +++ b/examples/python/knapsack.py @@ -10,11 +10,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Bi-dimensional knapsack problem.""" - - from ortools.algorithms import pywrapknapsack_solver @@ -22,26 +19,24 @@ def main(): # Create the solver. solver = pywrapknapsack_solver.KnapsackSolver( pywrapknapsack_solver.KnapsackSolver. - KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, - 'test') - profits = [360, 83, 59, 130, 431, 67, 230, 52, 93, - 125, 670, 892, 600, 38, 48, 147, 78, 256, - 63, 17, 120, 164, 432, 35, 92, 110, 22, - 42, 50, 323, 514, 28, 87, 73, 78, 15, - 26, 78, 210, 36, 85, 189, 274, 43, 33, - 10, 19, 389, 276, 312] - weights = [[7, 0, 30, 22, 80, 94, 11, 81, 70, - 64, 59, 18, 0, 36, 3, 8, 15, 42, - 9, 0, 42, 47, 52, 32, 26, 48, 55, - 6, 29, 84, 2, 4, 18, 56, 7, 29, - 93, 44, 71, 3, 86, 66, 31, 65, 0, - 79, 20, 65, 52, 13]] + KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER, 'test') + profits = [ + 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147, + 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28, 87, + 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276, 312 + ] + weights = [[ + 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0, + 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71, 3, + 86, 66, 31, 65, 0, 79, 20, 65, 52, 13 + ]] capacities = [850] optimal_profit = 7534 solver.Init(profits, weights, capacities) computed_profit = solver.Solve() - print(('optimal profit = ' + str(computed_profit) + '/' + str(optimal_profit))) + print( + ('optimal profit = ' + str(computed_profit) + '/' + str(optimal_profit))) if __name__ == '__main__': diff --git a/examples/python/knapsack_cp.py b/examples/python/knapsack_cp.py index 0437ef378b..31761fd68d 100644 --- a/examples/python/knapsack_cp.py +++ b/examples/python/knapsack_cp.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Knapsack problem in Google CP Solver. @@ -66,9 +65,7 @@ def main(values, weights, n): solution.Add(z) # db: DecisionBuilder - db = solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MAX_VALUE) + db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE) solver.NewSearch(db, [objective]) num_solutions = 0 diff --git a/examples/python/knapsack_mip.py b/examples/python/knapsack_mip.py index 0b333b713a..66214975ea 100644 --- a/examples/python/knapsack_mip.py +++ b/examples/python/knapsack_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Knapsack problem using MIP in Google or-tools. @@ -52,13 +51,13 @@ def main(sol='CBC'): capacity = [18209, 7692, 1333, 924, 26638, 61188, 13360] value = [96, 76, 56, 11, 86, 10, 66, 86, 83, 12, 9, 81] - use = [[19, 1, 10, 1, 1, 14, 152, 11, 1, 1, 1, 1], - [0, 4, 53, 0, 0, 80, 0, 4, 5, 0, 0, 0], - [4, 660, 3, 0, 30, 0, 3, 0, 4, 90, 0, 0], - [7, 0, 18, 6, 770, 330, 7, 0, 0, 6, 0, 0], - [0, 20, 0, 4, 52, 3, 0, 0, 0, 5, 4, 0], - [0, 0, 40, 70, 4, 63, 0, 0, 60, 0, 4, 0], - [0, 32, 0, 0, 0, 5, 0, 3, 0, 660, 0, 9]] + use = [[19, 1, 10, 1, 1, 14, 152, 11, 1, 1, 1, + 1], [0, 4, 53, 0, 0, 80, 0, 4, 5, 0, 0, + 0], [4, 660, 3, 0, 30, 0, 3, 0, 4, 90, 0, + 0], [7, 0, 18, 6, 770, 330, 7, 0, 0, 6, 0, 0], + [0, 20, 0, 4, 52, 3, 0, 0, 0, 5, 4, + 0], [0, 0, 40, 70, 4, 63, 0, 0, 60, 0, 4, + 0], [0, 32, 0, 0, 0, 5, 0, 3, 0, 660, 0, 9]] max_value = max(capacity) @@ -74,8 +73,7 @@ def main(sol='CBC'): # constraints # for r in resources: - solver.Add(solver.Sum([use[r][i] * take[i] - for i in items]) <= capacity[r]) + solver.Add(solver.Sum([use[r][i] * take[i] for i in items]) <= capacity[r]) # objective objective = solver.Maximize(z) diff --git a/examples/python/labeled_dice.py b/examples/python/labeled_dice.py index a554e304e7..91f43fb048 100644 --- a/examples/python/labeled_dice.py +++ b/examples/python/labeled_dice.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Labeled dice problem in Google CP Solver. @@ -63,25 +62,15 @@ def main(): m = 24 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, Y = ( list(range(m))) - letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", - "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "Y"] + letters = [ + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "Y" + ] num_words = 13 - words = [ - [B, U, O, Y], - [C, A, V, E], - [C, E, L, T], - [F, L, U, B], - [F, O, R, K], - [H, E, M, P], - [J, U, D, Y], - [J, U, N, K], - [L, I, M, N], - [Q, U, I, P], - [S, W, A, G], - [V, I, S, A], - [W, I, S, H] - ] + words = [[B, U, O, Y], [C, A, V, E], [C, E, L, T], [F, L, U, B], [F, O, R, K], + [H, E, M, P], [J, U, D, Y], [J, U, N, K], [L, I, M, N], [Q, U, I, P], + [S, W, A, G], [V, I, S, A], [W, I, S, H]] # # declare variables @@ -107,9 +96,7 @@ def main(): solution = solver.Assignment() solution.Add(dice) - db = solver.Phase(dice, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(dice, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) # # result @@ -120,16 +107,18 @@ def main(): num_solutions += 1 # print "dice:", [(letters[i],dice[i].Value()) for i in range(m)] for d in range(n): - print("die %i:" % d, end=' ') + print("die %i:" % d, end=" ") for i in range(m): if dice[i].Value() == d: - print(letters[i], end=' ') + print(letters[i], end=" ") print() print("The words with the cube label:") for i in range(num_words): for j in range(n): - print("%s (%i)" % (letters[words[i][j]], dice[words[i][j]].Value()), end=' ') + print( + "%s (%i)" % (letters[words[i][j]], dice[words[i][j]].Value()), + end=" ") print() print() @@ -142,5 +131,6 @@ def main(): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + if __name__ == "__main__": main() diff --git a/examples/python/langford.py b/examples/python/langford.py index 09ab152228..3547e23a3b 100644 --- a/examples/python/langford.py +++ b/examples/python/langford.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Langford's number problem in Google CP Solver. @@ -83,8 +82,7 @@ def main(k=8, num_sol=0): # # search and result # - db = solver.Phase(position, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(position, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -103,6 +101,7 @@ def main(k=8, num_sol=0): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + k = 8 num_sol = 0 if __name__ == "__main__": diff --git a/examples/python/least_diff.py b/examples/python/least_diff.py index 3f1ca744e1..aa7231b719 100644 --- a/examples/python/least_diff.py +++ b/examples/python/least_diff.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Least diff problem in Google CP Solver. @@ -63,11 +62,11 @@ def main(unused_argv): letters = [a, b, c, d, e, f, g, h, i, j] - digit_vector = [10000,1000,100,10,1] - x = solver.ScalProd(letters[0:5],digit_vector) - y = solver.ScalProd(letters[5:],digit_vector) + digit_vector = [10000, 1000, 100, 10, 1] + x = solver.ScalProd(letters[0:5], digit_vector) + y = solver.ScalProd(letters[5:], digit_vector) diff = x - y - + # # constraints # @@ -91,10 +90,9 @@ def main(unused_argv): search_log = solver.SearchLog(100, diff) # Note: I'm not sure what CHOOSE_PATH do, but it is fast: # find the solution in just 4 steps - solver.Solve(solver.Phase(letters, - solver.CHOOSE_PATH, - solver.ASSIGN_MIN_VALUE), - [objective, search_log, collector]) + solver.Solve( + solver.Phase(letters, solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE), + [objective, search_log, collector]) # get the first (and only) solution @@ -105,12 +103,13 @@ def main(unused_argv): print("y:", yval) print("diff:", diffval) print(xval, "-", yval, "=", diffval) - print([("abcdefghij"[i], collector.Value(0, letters[i])) for i in range(10)]) + print([("abcdefghij" [i], collector.Value(0, letters[i])) for i in range(10)]) print() print("failures:", solver.Failures()) print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) print() + if __name__ == "__main__": main("cp sample") diff --git a/examples/python/least_square.py b/examples/python/least_square.py index 0c4e0d217a..3e8202ee9c 100644 --- a/examples/python/least_square.py +++ b/examples/python/least_square.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Least square optimization problem in Google or-tools. @@ -53,7 +52,8 @@ def main(sol='CBC'): # percentage gas F = [ 0.0, 5.8, 14.7, 31.6, 43.2, 58.3, 78.4, 89.4, 96.4, 99.1, 99.5, 99.9, - 100.0, 100.0] + 100.0, 100.0 + ] p = 4 @@ -63,21 +63,20 @@ def main(sol='CBC'): a = [solver.NumVar(-100, 100, 'a[%i]' % i) for i in range(p + 1)] # to minimize - z = solver.Sum([(F[i] - - (sum([a[j] * t[i] ** j for j in range(p + 1)]))) - for i in range(num)]) + z = solver.Sum([ + (F[i] - (sum([a[j] * t[i]**j for j in range(p + 1)]))) for i in range(num) + ]) # # constraints # - solver.Add(solver.Sum([20 ** i * a[i] for i in range(p + 1)]) == 0) + solver.Add(solver.Sum([20**i * a[i] for i in range(p + 1)]) == 0) - solver.Add((a[0] + sum([700.0 ** j * a[j] - for j in range(1, p + 1)])) == 100.0) + solver.Add((a[0] + sum([700.0**j * a[j] for j in range(1, p + 1)])) == 100.0) for i in range(num): - solver.Add(solver.Sum([j * a[j] * t[i] ** (j - 1) - for j in range(p + 1)]) >= 0) + solver.Add( + solver.Sum([j * a[j] * t[i]**(j - 1) for j in range(p + 1)]) >= 0) objective = solver.Minimize(z) diff --git a/examples/python/lectures.py b/examples/python/lectures.py index e3d1643236..acda6eb81a 100644 --- a/examples/python/lectures.py +++ b/examples/python/lectures.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Lectures problem in Google CP Solver. @@ -62,15 +61,7 @@ def main(): # The schedule requirements: # lecture a cannot be held at the same time as b # Note: 1-based - g = [ - [1, 2], - [1, 4], - [3, 5], - [2, 6], - [4, 5], - [5, 6], - [1, 6] - ] + g = [[1, 2], [1, 4], [3, 5], [2, 6], [4, 5], [5, 6], [1, 6]] # number of nodes n = 6 @@ -110,8 +101,7 @@ def main(): # # solution and search # - db = solver.Phase(v, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(v, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db, [objective]) diff --git a/examples/python/linear_assignment_api.py b/examples/python/linear_assignment_api.py index f190c49d20..cad2ef4757 100644 --- a/examples/python/linear_assignment_api.py +++ b/examples/python/linear_assignment_api.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Test linear sum assignment on a 4x4 matrix. Example taken from: @@ -19,7 +18,6 @@ """ from __future__ import print_function - from ortools.graph import pywrapgraph @@ -28,9 +26,7 @@ def RunAssignmentOn4x4Matrix(): """ num_sources = 4 num_targets = 4 - cost = [[90, 76, 75, 80], - [35, 85, 55, 65], - [125, 95, 90, 105], + cost = [[90, 76, 75, 80], [35, 85, 55, 65], [125, 95, 90, 105], [45, 110, 95, 115]] expected_cost = cost[0][3] + cost[1][2] + cost[2][1] + cost[3][0] @@ -44,10 +40,8 @@ def RunAssignmentOn4x4Matrix(): print('Successful solve.') print('Total cost', assignment.OptimalCost(), '/', expected_cost) for i in range(0, assignment.NumNodes()): - print('Left node %d assigned to right node %d with cost %d.' % ( - i, - assignment.RightMate(i), - assignment.AssignmentCost(i))) + print('Left node %d assigned to right node %d with cost %d.' % + (i, assignment.RightMate(i), assignment.AssignmentCost(i))) elif solve_status == assignment.INFEASIBLE: print('No perfect matching exists.') elif solve_status == assignment.POSSIBLE_OVERFLOW: @@ -57,5 +51,6 @@ def RunAssignmentOn4x4Matrix(): def main(): RunAssignmentOn4x4Matrix() + if __name__ == '__main__': main() diff --git a/examples/python/linear_programming.py b/examples/python/linear_programming.py index 3bbc72557a..44c8ea1f50 100644 --- a/examples/python/linear_programming.py +++ b/examples/python/linear_programming.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Linear programming examples that show how to use the APIs.""" from __future__ import print_function from ortools.linear_solver import linear_solver_pb2 @@ -102,12 +101,13 @@ def SolveAndPrint(solver, variable_list, constraint_list): print('Advanced usage:') print(('Problem solved in %d iterations' % solver.iterations())) for variable in variable_list: - print(('%s: reduced cost = %f' % (variable.name(), variable.reduced_cost()))) + print( + ('%s: reduced cost = %f' % (variable.name(), variable.reduced_cost()))) activities = solver.ComputeConstraintActivities() for i, constraint in enumerate(constraint_list): print(('constraint %d: dual value = %f\n' - ' activity = %f' % - (i, constraint.dual_value(), activities[constraint.index()]))) + ' activity = %f' % (i, constraint.dual_value(), + activities[constraint.index()]))) def main(): diff --git a/examples/python/magic_sequence_distribute.py b/examples/python/magic_sequence_distribute.py index f2e163725a..d87164b65d 100644 --- a/examples/python/magic_sequence_distribute.py +++ b/examples/python/magic_sequence_distribute.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Magic sequence problem. This models aims at building a sequence of numbers such that the number of @@ -20,7 +19,6 @@ distribute(). """ from __future__ import print_function - from ortools.constraint_solver import pywrapcp @@ -35,9 +33,9 @@ def main(): solver.Add(solver.Distribute(all_vars, all_values, all_vars)) solver.Add(solver.Sum(all_vars) == size) - solver.NewSearch(solver.Phase(all_vars, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE)) + solver.NewSearch( + solver.Phase(all_vars, solver.CHOOSE_FIRST_UNBOUND, + solver.ASSIGN_MIN_VALUE)) solver.NextSolution() print(all_vars) solver.EndSearch() diff --git a/examples/python/magic_square.py b/examples/python/magic_square.py index 320ba2bd61..8df37afcbf 100644 --- a/examples/python/magic_square.py +++ b/examples/python/magic_square.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Magic squares in Google CP Solver. @@ -72,13 +71,14 @@ def main(n=4): solution.Add(s) # db: DecisionBuilder - db = solver.Phase(x_flat, - # solver.INT_VAR_DEFAULT, - solver.CHOOSE_FIRST_UNBOUND, - # solver.CHOOSE_MIN_SIZE_LOWEST_MAX, + db = solver.Phase( + x_flat, + # solver.INT_VAR_DEFAULT, + solver.CHOOSE_FIRST_UNBOUND, + # solver.CHOOSE_MIN_SIZE_LOWEST_MAX, - # solver.ASSIGN_MIN_VALUE - solver.ASSIGN_CENTER_VALUE) + # solver.ASSIGN_MIN_VALUE + solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -86,7 +86,7 @@ def main(n=4): print("s:", s.Value()) for i in range(n): for j in range(n): - print("%2i" % x[(i, j)].Value(), end=' ') + print("%2i" % x[(i, j)].Value(), end=" ") print() print() @@ -99,6 +99,7 @@ def main(n=4): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + n = 4 if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/magic_square_and_cards.py b/examples/python/magic_square_and_cards.py index 8425c76163..433353bcd3 100644 --- a/examples/python/magic_square_and_cards.py +++ b/examples/python/magic_square_and_cards.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Magic squares and cards problem in Google CP Solver. @@ -81,8 +80,7 @@ def main(n=3): solution.Add(counts) # db: DecisionBuilder - db = solver.Phase(x_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(x_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE) solver.NewSearch(db, [objective]) @@ -92,7 +90,7 @@ def main(n=3): print("counts:", [counts[i].Value() for i in range(14)]) for i in range(n): for j in range(n): - print(x[(i, j)].Value(), end=' ') + print(x[(i, j)].Value(), end=" ") print() print() diff --git a/examples/python/magic_square_mip.py b/examples/python/magic_square_mip.py index d0aec9b284..aa72c67ba0 100644 --- a/examples/python/magic_square_mip.py +++ b/examples/python/magic_square_mip.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Magic square (integer programming) in Google or-tools. @@ -112,45 +111,42 @@ def main(n=3, sol='CBC', use_output_matrix=0): # each integer must be assigned exactly to one cell for k in range_N: - solver.Add(solver.Sum([x[i, j, k] - for i in range_n - for j in range_n]) == 1) + solver.Add(solver.Sum([x[i, j, k] for i in range_n for j in range_n]) == 1) # # the sum in each row must be the magic sum for i in range_n: - solver.Add(solver.Sum([k * x[i, j, k] - for j in range_n - for k in range_N]) == s) + solver.Add( + solver.Sum([k * x[i, j, k] for j in range_n for k in range_N]) == s) # # the sum in each column must be the magic sum for j in range_n: - solver.Add(solver.Sum([k * x[i, j, k] - for i in range_n - for k in range_N]) == s) + solver.Add( + solver.Sum([k * x[i, j, k] for i in range_n for k in range_N]) == s) # # the sum in the diagonal must be the magic sum - solver.Add(solver.Sum([k * x[i, i, k] - for i in range_n - for k in range_N]) == s) + solver.Add( + solver.Sum([k * x[i, i, k] for i in range_n for k in range_N]) == s) # # the sum in the co-diagonal must be the magic sum if range_n[0] == 1: # for range_n = 1..n - solver.Add(solver.Sum([k * x[i, n - i + 1, k] - for i in range_n - for k in range_N]) == s) + solver.Add( + solver.Sum([k * x[i, n - i + 1, k] + for i in range_n + for k in range_N]) == s) else: # for range_n = 0..n-1 - solver.Add(solver.Sum([k * x[i, n - i - 1, k] - for i in range_n - for k in range_N]) == s) + solver.Add( + solver.Sum([k * x[i, n - i - 1, k] + for i in range_n + for k in range_N]) == s) # for output if use_output_matrix == 1: for i in range_n: for j in range_n: - solver.Add(square[i, j] == - solver.Sum([k * x[i, j, k] for k in range_N])) + solver.Add(square[i, j] == solver.Sum([k * x[i, j, k] + for k in range_N])) # # solution and search @@ -169,7 +165,10 @@ def main(n=3, sol='CBC', use_output_matrix=0): else: for i in range_n: for j in range_n: - print(sum([int(k * x[i, j, k].SolutionValue()) for k in range_N]), ' ', end=' ') + print( + sum([int(k * x[i, j, k].SolutionValue()) for k in range_N]), + ' ', + end=' ') print() print('\nx:') diff --git a/examples/python/map.py b/examples/python/map.py index 770e90818b..649a6da254 100644 --- a/examples/python/map.py +++ b/examples/python/map.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Map coloring problem in Google CP Solver. @@ -80,10 +79,9 @@ def main(): collector = solver.AllSolutionCollector(solution) # collector = solver.FirstSolutionCollector(solution) # search_log = solver.SearchLog(100, x[0]) - solver.Solve(solver.Phase([color[i] for i in range(n)], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([color[i] for i in range(n)], solver.INT_VAR_SIMPLE, + solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() print("num_solutions: ", num_solutions) diff --git a/examples/python/marathon2.py b/examples/python/marathon2.py index 4fd1082b96..253d7bf8aa 100644 --- a/examples/python/marathon2.py +++ b/examples/python/marathon2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Marathon puzzle in Google CP Solver. @@ -62,8 +61,9 @@ def main(): # n = 6 - runners_str = ['Dominique', 'Ignace', 'Naren', - 'Olivier', 'Philippe', 'Pascal'] + runners_str = [ + 'Dominique', 'Ignace', 'Naren', 'Olivier', 'Philippe', 'Pascal' + ] # # declare variables @@ -107,8 +107,7 @@ def main(): # # solution and search # - db = solver.Phase(runners, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(runners, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db) diff --git a/examples/python/max_flow_taha.py b/examples/python/max_flow_taha.py index 78b7edefbb..ad39843d4c 100644 --- a/examples/python/max_flow_taha.py +++ b/examples/python/max_flow_taha.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Max flow problem in Google CP Solver. @@ -47,13 +46,8 @@ def main(): nodes = list(range(n)) # cost matrix - c = [ - [0, 20, 30, 10, 0], - [0, 0, 40, 0, 30], - [0, 0, 0, 10, 20], - [0, 0, 5, 0, 20], - [0, 0, 0, 0, 0] - ] + c = [[0, 20, 30, 10, 0], [0, 0, 40, 0, 30], [0, 0, 0, 10, 20], + [0, 0, 5, 0, 20], [0, 0, 0, 0, 0]] # # declare variables @@ -89,13 +83,11 @@ def main(): s1 = [x[i, start] for i in nodes if c[i][start] > 0] if len(s1) > 0: - solver.Add(solver.Sum([x[i, start] - for i in nodes if c[i][start] > 0] == 0)) + solver.Add(solver.Sum([x[i, start] for i in nodes if c[i][start] > 0] == 0)) s2 = [x[end, j] for j in nodes if c[end][j] > 0] if len(s2) > 0: - solver.Add(solver.Sum([x[end, j] - for j in nodes if c[end][j] > 0]) == 0) + solver.Add(solver.Sum([x[end, j] for j in nodes if c[end][j] > 0]) == 0) # objective: maximize total cost objective = solver.Maximize(total, 1) @@ -103,9 +95,7 @@ def main(): # # solution and search # - db = solver.Phase(x_flat, - solver.INT_VAR_DEFAULT, - solver.ASSIGN_MAX_VALUE) + db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.ASSIGN_MAX_VALUE) solver.NewSearch(db, [objective]) num_solutions = 0 @@ -125,5 +115,6 @@ def main(): print('branches:', solver.Branches()) print('WallTime:', solver.WallTime(), 'ms') + if __name__ == '__main__': main() diff --git a/examples/python/max_flow_winston1.py b/examples/python/max_flow_winston1.py index b3dea4d136..55195cf817 100644 --- a/examples/python/max_flow_winston1.py +++ b/examples/python/max_flow_winston1.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Max flow problem in Google CP Solver. @@ -48,15 +47,7 @@ def main(): # Note: # This is 1-based to be compatible with other # implementations. - arcs1 = [ - [1, 2], - [1, 3], - [2, 3], - [2, 4], - [3, 5], - [4, 5], - [5, 1] - ] + arcs1 = [[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 5], [5, 1]] # convert arcs to 0-based arcs = [] @@ -104,10 +95,12 @@ def main(): # inflows == outflows for i in nodes: - s1 = solver.Sum([flow[arcs[k][0], arcs[k][1]] - for k in range(num_arcs) if arcs[k][1] == i]) - s2 = solver.Sum([flow[arcs[k][0], arcs[k][1]] - for k in range(num_arcs) if arcs[k][0] == i]) + s1 = solver.Sum([ + flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][1] == i + ]) + s2 = solver.Sum([ + flow[arcs[k][0], arcs[k][1]] for k in range(num_arcs) if arcs[k][0] == i + ]) solver.Add(s1 == s2) # sanity: just arcs with connections can have a flow @@ -122,9 +115,7 @@ def main(): # # solution and search # - db = solver.Phase(flow_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(flow_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db, [objective]) num_solutions = 0 @@ -142,5 +133,6 @@ def main(): print('branches:', solver.Branches()) print('WallTime:', solver.WallTime(), 'ms') + if __name__ == '__main__': main() diff --git a/examples/python/minesweeper.py b/examples/python/minesweeper.py index b1c8a53e33..61c3b79337 100644 --- a/examples/python/minesweeper.py +++ b/examples/python/minesweeper.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Minesweeper in Google CP Solver. @@ -70,16 +69,11 @@ from ortools.constraint_solver import pywrapcp default_r = 8 default_c = 8 X = -1 -default_game = [ - [2, 3, X, 2, 2, X, 2, 1], - [X, X, 4, X, X, 4, X, 2], - [X, X, X, X, X, X, 4, X], - [X, 5, X, 6, X, X, X, 2], - [2, X, X, X, 5, 5, X, 2], - [1, 3, 4, X, X, X, 4, X], - [0, 1, X, 4, X, X, X, 3], - [0, 1, 2, X, 2, 3, X, 2] -] +default_game = [[2, 3, X, 2, 2, X, 2, 1], [X, X, 4, X, X, 4, X, 2], + [X, X, X, X, X, X, 4, X], [X, 5, X, 6, X, X, X, 2], + [2, X, X, X, 5, 5, X, 2], [1, 3, 4, X, X, X, 4, + X], [0, 1, X, 4, X, X, X, + 3], [0, 1, 2, X, 2, 3, X, 2]] def main(game="", r="", c=""): @@ -125,9 +119,9 @@ def main(game="", r="", c=""): for i in range(r): for j in range(c): if game[i][j] == X: - print("X", end=' ') + print("X", end=" ") else: - print(game[i][j], end=' ') + print(game[i][j], end=" ") print() print() @@ -145,14 +139,12 @@ def main(game="", r="", c=""): if game[i][j] >= 0: solver.Add(mines[i, j] == 0) # this cell is the sum of all the surrounding cells - solver.Add( - game[i][j] == solver.Sum([mines[i + a, j + b] - for a in S for b in S - if i + a >= 0 and - j + b >= 0 and - i + a < r and - j + b < c]) - ) + solver.Add(game[i][j] == solver.Sum([ + mines[i + a, j + b] + for a in S + for b in S + if i + a >= 0 and j + b >= 0 and i + a < r and j + b < c + ])) if game[i][j] > X: # This cell cannot be a mine solver.Add(mines[i, j] == 0) @@ -164,20 +156,20 @@ def main(game="", r="", c=""): solution.Add([mines[(i, j)] for i in range(r) for j in range(c)]) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase([mines[(i, j)] for i in range(r) for j in range(c)], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([mines[(i, j)] for i in range(r) for j in range(c)], + solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() print("num_solutions: ", num_solutions) if num_solutions > 0: for s in range(num_solutions): - minesval = [collector.Value(s, mines[(i, j)]) - for i in range(r) for j in range(c)] + minesval = [ + collector.Value(s, mines[(i, j)]) for i in range(r) for j in range(c) + ] for i in range(r): for j in range(c): - print(minesval[i * c + j], end=' ') + print(minesval[i * c + j], end=" ") print() print() @@ -218,14 +210,14 @@ def read_problem(file): def print_mines(mines, rows, cols): for i in range(rows): for j in range(cols): - print(mines[i, j], end=' ') + print(mines[i, j], end=" ") print("") def print_game(game, rows, cols): for i in range(rows): for j in range(cols): - print(game[i][j], end=' ') + print(game[i][j], end=" ") print("") diff --git a/examples/python/mr_smith.py b/examples/python/mr_smith.py index 0438f94ebc..ee88880201 100644 --- a/examples/python/mr_smith.py +++ b/examples/python/mr_smith.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Mr Smith in Google CP Solver. @@ -101,9 +100,7 @@ def main(): # # solution and search # - db = solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/nonogram_default_search.py b/examples/python/nonogram_default_search.py index d368cb1fb2..c15c87e727 100644 --- a/examples/python/nonogram_default_search.py +++ b/examples/python/nonogram_default_search.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nonogram (Painting by numbers) in Google CP Solver. @@ -96,10 +95,9 @@ def check_rule(rules, y): accepting_states = [last_state] solver = y[0].solver() - solver.Add(solver.TransitionConstraint(y, - transition_tuples, - initial_state, - accepting_states)) + solver.Add( + solver.TransitionConstraint(y, transition_tuples, initial_state, + accepting_states)) def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): @@ -188,39 +186,16 @@ def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): # rows = 12 row_rule_len = 3 -row_rules = [ - [0, 0, 2], - [0, 1, 2], - [0, 1, 1], - [0, 0, 2], - [0, 0, 1], - [0, 0, 3], - [0, 0, 3], - [0, 2, 2], - [0, 2, 1], - [2, 2, 1], - [0, 2, 3], - [0, 2, 2] -] +row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3], + [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]] cols = 10 col_rule_len = 2 -col_rules = [ - [2, 1], - [1, 3], - [2, 4], - [3, 4], - [0, 4], - [0, 3], - [0, 3], - [0, 3], - [0, 2], - [0, 2] -] - +col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3], + [0, 2], [0, 2]] if __name__ == '__main__': if len(sys.argv) > 1: file = sys.argv[1] - exec(compile(open(file).read(), file, 'exec')) + exec (compile(open(file).read(), file, 'exec')) main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules) diff --git a/examples/python/nonogram_regular.py b/examples/python/nonogram_regular.py index d41135fe3e..f5305908ec 100644 --- a/examples/python/nonogram_regular.py +++ b/examples/python/nonogram_regular.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nonogram (Painting by numbers) in Google CP Solver. @@ -135,8 +134,8 @@ def regular(x, Q, S, d, q0, F): solver.Add(x[i] >= 1) solver.Add(x[i] <= S) # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] - solver.Add( - a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1))) + solver.Add(a[i + 1] == solver.Element(d2_flatten, ( + (a[i]) * S) + (x[i] - 1))) # @@ -198,6 +197,7 @@ def make_transition_matrix(pattern): return t_matrix + # # check each rule by creating an automaton # and regular @@ -221,12 +221,11 @@ def check_rule(rules, y): initial_state = 1 accepting_states = [n_states] # This is the last state - regular(y, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(y, n_states, input_max, transition_fn, initial_state, + accepting_states) -def main(rows, row_rule_len, row_rules, - cols, col_rule_len, col_rules): +def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): # Create the solver. solver = pywrapcp.Solver('Regular test') @@ -271,8 +270,7 @@ def main(rows, row_rule_len, row_rules, # # solution and search # - db = solver.Phase(board_label, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -314,40 +312,16 @@ def main(rows, row_rule_len, row_rules, # rows = 12 row_rule_len = 3 -row_rules = [ - [0, 0, 2], - [0, 1, 2], - [0, 1, 1], - [0, 0, 2], - [0, 0, 1], - [0, 0, 3], - [0, 0, 3], - [0, 2, 2], - [0, 2, 1], - [2, 2, 1], - [0, 2, 3], - [0, 2, 2] -] +row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3], + [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]] cols = 10 col_rule_len = 2 -col_rules = [ - [2, 1], - [1, 3], - [2, 4], - [3, 4], - [0, 4], - [0, 3], - [0, 3], - [0, 3], - [0, 2], - [0, 2] -] - +col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3], + [0, 2], [0, 2]] if __name__ == '__main__': if len(sys.argv) > 1: file = sys.argv[1] - exec(compile(open(file).read(), file, 'exec')) - main(rows, row_rule_len, row_rules, - cols, col_rule_len, col_rules) + exec (compile(open(file).read(), file, 'exec')) + main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules) diff --git a/examples/python/nonogram_table.py b/examples/python/nonogram_table.py index 60116ecb10..c7b2ebf7ce 100644 --- a/examples/python/nonogram_table.py +++ b/examples/python/nonogram_table.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nonogram (Painting by numbers) in Google CP Solver. @@ -132,6 +131,7 @@ def regular(x, Q, S, d, q0, F): # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] solver.Add(solver.AllowedAssignments((a[i], x[i] - 1, a[i + 1]), d2)) + # # Make a transition (automaton) matrix from a # single pattern, e.g. [3,2,1] @@ -193,6 +193,7 @@ def make_transition_matrix(pattern): return t_matrix + # # check each rule by creating an automaton # and regular @@ -216,12 +217,11 @@ def check_rule(rules, y): initial_state = 1 accepting_states = [n_states] # This is the last state - regular(y, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(y, n_states, input_max, transition_fn, initial_state, + accepting_states) -def main(rows, row_rule_len, row_rules, - cols, col_rule_len, col_rules): +def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): # Create the solver. solver = pywrapcp.Solver('Regular test') @@ -266,8 +266,7 @@ def main(rows, row_rule_len, row_rules, # # solution and search # - db = solver.Phase(board_label, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -309,39 +308,16 @@ def main(rows, row_rule_len, row_rules, # rows = 12 row_rule_len = 3 -row_rules = [ - [0, 0, 2], - [0, 1, 2], - [0, 1, 1], - [0, 0, 2], - [0, 0, 1], - [0, 0, 3], - [0, 0, 3], - [0, 2, 2], - [0, 2, 1], - [2, 2, 1], - [0, 2, 3], - [0, 2, 2] -] +row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3], + [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]] cols = 10 col_rule_len = 2 -col_rules = [ - [2, 1], - [1, 3], - [2, 4], - [3, 4], - [0, 4], - [0, 3], - [0, 3], - [0, 3], - [0, 2], - [0, 2] -] - +col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3], + [0, 2], [0, 2]] if __name__ == '__main__': if len(sys.argv) > 1: file = sys.argv[1] - exec(compile(open(file).read(), file, 'exec')) + exec (compile(open(file).read(), file, 'exec')) main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules) diff --git a/examples/python/nonogram_table2.py b/examples/python/nonogram_table2.py index 3f4d629115..1140938cea 100644 --- a/examples/python/nonogram_table2.py +++ b/examples/python/nonogram_table2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nonogram (Painting by numbers) in Google CP Solver. @@ -122,10 +121,9 @@ def check_rule(rules, y): accepting_states = [last_state] solver = y[0].solver() - solver.Add(solver.TransitionConstraint(y, - transition_tuples, - initial_state, - accepting_states)) + solver.Add( + solver.TransitionConstraint(y, transition_tuples, initial_state, + accepting_states)) def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): @@ -167,8 +165,7 @@ def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): # # solution and search # - db = solver.Phase(board_label, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(board_label, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) print('before solver, wall time = ', solver.WallTime(), 'ms') @@ -211,39 +208,16 @@ def main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules): # rows = 12 row_rule_len = 3 -row_rules = [ - [0, 0, 2], - [0, 1, 2], - [0, 1, 1], - [0, 0, 2], - [0, 0, 1], - [0, 0, 3], - [0, 0, 3], - [0, 2, 2], - [0, 2, 1], - [2, 2, 1], - [0, 2, 3], - [0, 2, 2] -] +row_rules = [[0, 0, 2], [0, 1, 2], [0, 1, 1], [0, 0, 2], [0, 0, 1], [0, 0, 3], + [0, 0, 3], [0, 2, 2], [0, 2, 1], [2, 2, 1], [0, 2, 3], [0, 2, 2]] cols = 10 col_rule_len = 2 -col_rules = [ - [2, 1], - [1, 3], - [2, 4], - [3, 4], - [0, 4], - [0, 3], - [0, 3], - [0, 3], - [0, 2], - [0, 2] -] - +col_rules = [[2, 1], [1, 3], [2, 4], [3, 4], [0, 4], [0, 3], [0, 3], [0, 3], + [0, 2], [0, 2]] if __name__ == '__main__': if len(sys.argv) > 1: file = sys.argv[1] - exec(compile(open(file).read(), file, 'exec')) + exec (compile(open(file).read(), file, 'exec')) main(rows, row_rule_len, row_rules, cols, col_rule_len, col_rules) diff --git a/examples/python/nontransitive_dice.py b/examples/python/nontransitive_dice.py index cacb600444..2ac7080438 100644 --- a/examples/python/nontransitive_dice.py +++ b/examples/python/nontransitive_dice.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nontransitive dice in Google CP Solver. @@ -120,8 +119,11 @@ def main(m=3, n=6, minimize_val=0): solver.Add(max_val == solver.Max(dice_flat)) # order of the number of each die, lowest first - [solver.Add(dice[(i, j)] <= dice[(i, j + 1)]) - for i in range(m) for j in range(n - 1)] + [ + solver.Add(dice[(i, j)] <= dice[(i, j + 1)]) + for i in range(m) + for j in range(n - 1) + ] # nontransitivity [comp[i, 0] > comp[i, 1] for i in range(m)], @@ -134,12 +136,18 @@ def main(m=3, n=6, minimize_val=0): # and now we roll... # Number of wins for [A vs B, B vs A] for d in range(m): - b1 = [solver.IsGreaterVar(dice[d % m, r1], dice[(d + 1) % m, r2]) - for r1 in range(n) for r2 in range(n)] + b1 = [ + solver.IsGreaterVar(dice[d % m, r1], dice[(d + 1) % m, r2]) + for r1 in range(n) + for r2 in range(n) + ] solver.Add(comp[d % m, 0] == solver.Sum(b1)) - b2 = [solver.IsGreaterVar(dice[(d + 1) % m, r1], dice[d % m, r2]) - for r1 in range(n) for r2 in range(n)] + b2 = [ + solver.IsGreaterVar(dice[(d + 1) % m, r1], dice[d % m, r2]) + for r1 in range(n) + for r2 in range(n) + ] solver.Add(comp[d % m, 1] == solver.Sum(b2)) # objective @@ -153,8 +161,7 @@ def main(m=3, n=6, minimize_val=0): # # solution and search # - db = solver.Phase(dice_flat + comp_flat, - solver.INT_VAR_DEFAULT, + db = solver.Phase(dice_flat + comp_flat, solver.INT_VAR_DEFAULT, solver.ASSIGN_MIN_VALUE) if minimize_val: @@ -171,12 +178,12 @@ def main(m=3, n=6, minimize_val=0): print("dice:") for i in range(m): for j in range(n): - print(dice[(i, j)].Value(), end=' ') + print(dice[(i, j)].Value(), end=" ") print() print("comp:") for i in range(m): for j in range(2): - print(comp[(i, j)].Value(), end=' ') + print(comp[(i, j)].Value(), end=" ") print() print("counts:", [counts[i].Value() for i in range(n * 2 + 1)]) print() @@ -192,8 +199,8 @@ def main(m=3, n=6, minimize_val=0): print("WallTime:", solver.WallTime()) -m = 3 # number of dice -n = 6 # number of sides of each die +m = 3 # number of dice +n = 6 # number of sides of each die minimize_val = 0 # Minimizing max value (0: no, 1: yes) if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/nqueens.py b/examples/python/nqueens.py index b8ee4b2a77..de89cea0e1 100644 --- a/examples/python/nqueens.py +++ b/examples/python/nqueens.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ n-queens problem in Google CP Solver. @@ -64,10 +63,9 @@ def main(n=8): collector = solver.AllSolutionCollector(solution) # collector = solver.FirstSolutionCollector(solution) # search_log = solver.SearchLog(100, x[0]) - solver.Solve(solver.Phase([q[i] for i in range(n)], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([q[i] for i in range(n)], solver.INT_VAR_SIMPLE, + solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() print("num_solutions: ", num_solutions) @@ -78,9 +76,9 @@ def main(n=8): for i in range(n): for j in range(n): if qval[i] == j: - print("Q", end=' ') + print("Q", end=" ") else: - print("_", end=' ') + print("_", end=" ") print() print() @@ -93,6 +91,7 @@ def main(n=8): else: print("No solutions found") + n = 8 if __name__ == "__main__": main(n) diff --git a/examples/python/nqueens2.py b/examples/python/nqueens2.py index b768de1166..96a7393046 100644 --- a/examples/python/nqueens2.py +++ b/examples/python/nqueens2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ n-queens problem in Google CP Solver. @@ -66,10 +65,11 @@ def main(n=8): solution.Add([q[i] for i in range(n)]) # db: DecisionBuilder - db = solver.Phase([q[i] for i in range(n)], - # solver.CHOOSE_FIRST_UNBOUND, - solver.CHOOSE_MIN_SIZE_LOWEST_MAX, - solver.ASSIGN_CENTER_VALUE) + db = solver.Phase( + [q[i] for i in range(n)], + # solver.CHOOSE_FIRST_UNBOUND, + solver.CHOOSE_MIN_SIZE_LOWEST_MAX, + solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -79,9 +79,9 @@ def main(n=8): for i in range(n): for j in range(n): if qval[i] == j: - print("Q", end=' ') + print("Q", end=" ") else: - print("_", end=' ') + print("_", end=" ") print() print() num_solutions += 1 diff --git a/examples/python/nqueens3.py b/examples/python/nqueens3.py index 6f6af0d98e..9dd9f65ac0 100644 --- a/examples/python/nqueens3.py +++ b/examples/python/nqueens3.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ n-queens problem in Google CP Solver. @@ -60,8 +59,7 @@ def main(n=8, num_sol=0, print_sol=1): # search # - db = solver.Phase(q, - solver.CHOOSE_MIN_SIZE_LOWEST_MAX, + db = solver.Phase(q, solver.CHOOSE_MIN_SIZE_LOWEST_MAX, solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db) @@ -73,9 +71,9 @@ def main(n=8, num_sol=0, print_sol=1): for i in range(n): for j in range(n): if qval[i] == j: - print("Q", end=' ') + print("Q", end=" ") else: - print("_", end=' ') + print("_", end=" ") print() print() num_solutions += 1 diff --git a/examples/python/nqueens_sat.py b/examples/python/nqueens_sat.py index 1673bd3f25..6f853bf74a 100644 --- a/examples/python/nqueens_sat.py +++ b/examples/python/nqueens_sat.py @@ -10,13 +10,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """OR-tools solution to the N-queens problem.""" from __future__ import print_function import time import sys from ortools.sat.python import cp_model + class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback): """Print intermediate solutions.""" @@ -30,8 +30,8 @@ class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback): def NewSolution(self): current_time = time.time() - print('Solution %i, time = %f s' % - (self.__solution_count, current_time - self.__start_time)) + print('Solution %i, time = %f s' % (self.__solution_count, + current_time - self.__start_time)) self.__solution_count += 1 all_queens = range(len(self.__queens)) @@ -39,9 +39,9 @@ class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback): for j in all_queens: if self.Value(self.__queens[j]) == i: # There is a queen in column j, row i. - print('Q', end = ' ') + print('Q', end=' ') else: - print('_', end = ' ') + print('_', end=' ') print() print() @@ -51,8 +51,9 @@ def main(board_size): model = cp_model.CpModel() # Creates the variables. # The array index is the column, and the value is the row. - queens = [model.NewIntVar(0, board_size - 1, 'x%i' % i) - for i in range(board_size)] + queens = [ + model.NewIntVar(0, board_size - 1, 'x%i' % i) for i in range(board_size) + ] # Creates the constraints. # All rows must be different. @@ -90,7 +91,6 @@ def main(board_size): # By default, solve the 8x8 problem. board_size = 8 - if __name__ == '__main__': if len(sys.argv) > 1: board_size = int(sys.argv[1]) diff --git a/examples/python/nurse_rostering.py b/examples/python/nurse_rostering.py index 4a7e671883..d6b64976b6 100644 --- a/examples/python/nurse_rostering.py +++ b/examples/python/nurse_rostering.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Nurse rostering in Google CP Solver. @@ -99,8 +98,8 @@ def regular(x, Q, S, d, q0, F): solver.Add(x[i] <= S) # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] - solver.Add( - a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1))) + solver.Add(a[i + 1] == solver.Element(d2_flatten, ( + (a[i]) * S) + (x[i] - 1))) def main(): @@ -152,8 +151,10 @@ def main(): x_flat = [x[i, j] for i in range(num_nurses) for j in range(num_days)] # summary of the nurses - nurse_stat = [solver.IntVar(0, num_days, 'nurse_stat[%i]' % i) - for i in range(num_nurses)] + nurse_stat = [ + solver.IntVar(0, num_days, 'nurse_stat[%i]' % i) + for i in range(num_nurses) + ] # summary of the shifts per day day_stat = {} @@ -168,17 +169,18 @@ def main(): # for i in range(num_nurses): reg_input = [x[i, j] for j in range(num_days)] - regular(reg_input, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(reg_input, n_states, input_max, transition_fn, initial_state, + accepting_states) # # Statistics and constraints for each nurse # for i in range(num_nurses): # number of worked days (day or night shift) - b = [solver.IsEqualCstVar(x[i, j], day_shift) + - solver.IsEqualCstVar(x[i, j], night_shift) - for j in range(num_days)] + b = [ + solver.IsEqualCstVar(x[i, j], day_shift) + solver.IsEqualCstVar( + x[i, j], night_shift) for j in range(num_days) + ] solver.Add(nurse_stat[i] == solver.Sum(b)) # Each nurse must work between 7 and 10 @@ -191,8 +193,7 @@ def main(): # for j in range(num_days): for t in shifts: - b = [solver.IsEqualCstVar(x[i, j], t) - for i in range(num_nurses)] + b = [solver.IsEqualCstVar(x[i, j], t) for i in range(num_nurses)] solver.Add(day_stat[j, t] == solver.Sum(b)) # @@ -222,8 +223,7 @@ def main(): # solution and search # db = solver.Phase(day_stat_flat + x_flat + nurse_stat, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -238,7 +238,8 @@ def main(): d = days[x[i, j].Value() - 1] this_day_stat[d] += 1 print(d, end=' ') - print(' day_stat:', [(d, this_day_stat[d]) for d in this_day_stat], end=' ') + print( + ' day_stat:', [(d, this_day_stat[d]) for d in this_day_stat], end=' ') print('total:', nurse_stat[i].Value(), 'workdays') print() diff --git a/examples/python/nurses_cp.py b/examples/python/nurses_cp.py index 0e64d434ce..a76135d6e1 100644 --- a/examples/python/nurses_cp.py +++ b/examples/python/nurses_cp.py @@ -1,14 +1,14 @@ - from __future__ import print_function import sys from ortools.constraint_solver import pywrapcp + def main(): # Creates the solver. solver = pywrapcp.Solver("schedule_shifts") num_nurses = 4 - num_shifts = 4 # Nurse assigned to shift 0 means not working that day. + num_shifts = 4 # Nurse assigned to shift 0 means not working that day. num_days = 7 # [START] # Create shift variables. @@ -16,15 +16,19 @@ def main(): for j in range(num_nurses): for i in range(num_days): - shifts[(j, i)] = solver.IntVar(0, num_shifts - 1, "shifts(%i,%i)" % (j, i)) - shifts_flat = [shifts[(j, i)] for j in range(num_nurses) for i in range(num_days)] + shifts[(j, i)] = solver.IntVar(0, num_shifts - 1, + "shifts(%i,%i)" % (j, i)) + shifts_flat = [ + shifts[(j, i)] for j in range(num_nurses) for i in range(num_days) + ] # Create nurse variables. nurses = {} for j in range(num_shifts): for i in range(num_days): - nurses[(j, i)] = solver.IntVar(0, num_nurses - 1, "shift%d day%d" % (j,i)) + nurses[(j, i)] = solver.IntVar(0, num_nurses - 1, + "shift%d day%d" % (j, i)) # Set relationships between shifts and nurses. for day in range(num_days): nurses_for_day = [nurses[(j, day)] for j in range(num_shifts)] @@ -46,37 +50,109 @@ def main(): for i in range(num_nurses): for j in range(num_shifts): - works_shift[(i, j)] = solver.BoolVar('shift%d nurse%d' % (i, j)) + works_shift[(i, j)] = solver.BoolVar("shift%d nurse%d" % (i, j)) for i in range(num_nurses): for j in range(num_shifts): - solver.Add(works_shift[(i, j)] == solver.Max([shifts[(i, k)] == j for k in range(num_days)])) + solver.Add(works_shift[( + i, j)] == solver.Max([shifts[(i, k)] == j for k in range(num_days)])) # For each shift (other than 0), at most 2 nurses are assigned to that shift # during the week. for j in range(1, num_shifts): - solver.Add(solver.Sum([works_shift[(i, j)] for i in range(num_nurses)]) <= 2) + solver.Add( + solver.Sum([works_shift[(i, j)] for i in range(num_nurses)]) <= 2) # If s nurses works shifts 2 or 3 on, he must also work that shift the previous # day or the following day. - solver.Add(solver.Max(nurses[(2, 0)] == nurses[(2, 1)], nurses[(2, 1)] == nurses[(2, 2)]) == 1) - solver.Add(solver.Max(nurses[(2, 1)] == nurses[(2, 2)], nurses[(2, 2)] == nurses[(2, 3)]) == 1) - solver.Add(solver.Max(nurses[(2, 2)] == nurses[(2, 3)], nurses[(2, 3)] == nurses[(2, 4)]) == 1) - solver.Add(solver.Max(nurses[(2, 3)] == nurses[(2, 4)], nurses[(2, 4)] == nurses[(2, 5)]) == 1) - solver.Add(solver.Max(nurses[(2, 4)] == nurses[(2, 5)], nurses[(2, 5)] == nurses[(2, 6)]) == 1) - solver.Add(solver.Max(nurses[(2, 5)] == nurses[(2, 6)], nurses[(2, 6)] == nurses[(2, 0)]) == 1) - solver.Add(solver.Max(nurses[(2, 6)] == nurses[(2, 0)], nurses[(2, 0)] == nurses[(2, 1)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 0)] == nurses[(2, + 1)], nurses[(2, + 1)] == nurses[(2, + 2)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 1)] == nurses[(2, + 2)], nurses[(2, + 2)] == nurses[(2, + 3)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 2)] == nurses[(2, + 3)], nurses[(2, + 3)] == nurses[(2, + 4)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 3)] == nurses[(2, + 4)], nurses[(2, + 4)] == nurses[(2, + 5)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 4)] == nurses[(2, + 5)], nurses[(2, + 5)] == nurses[(2, + 6)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 5)] == nurses[(2, + 6)], nurses[(2, + 6)] == nurses[(2, + 0)]) == 1) + solver.Add( + solver.Max(nurses[(2, + 6)] == nurses[(2, + 0)], nurses[(2, + 0)] == nurses[(2, + 1)]) == 1) - solver.Add(solver.Max(nurses[(3, 0)] == nurses[(3, 1)], nurses[(3, 1)] == nurses[(3, 2)]) == 1) - solver.Add(solver.Max(nurses[(3, 1)] == nurses[(3, 2)], nurses[(3, 2)] == nurses[(3, 3)]) == 1) - solver.Add(solver.Max(nurses[(3, 2)] == nurses[(3, 3)], nurses[(3, 3)] == nurses[(3, 4)]) == 1) - solver.Add(solver.Max(nurses[(3, 3)] == nurses[(3, 4)], nurses[(3, 4)] == nurses[(3, 5)]) == 1) - solver.Add(solver.Max(nurses[(3, 4)] == nurses[(3, 5)], nurses[(3, 5)] == nurses[(3, 6)]) == 1) - solver.Add(solver.Max(nurses[(3, 5)] == nurses[(3, 6)], nurses[(3, 6)] == nurses[(3, 0)]) == 1) - solver.Add(solver.Max(nurses[(3, 6)] == nurses[(3, 0)], nurses[(3, 0)] == nurses[(3, 1)]) == 1) -# Create the decision builder. + solver.Add( + solver.Max(nurses[(3, + 0)] == nurses[(3, + 1)], nurses[(3, + 1)] == nurses[(3, + 2)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 1)] == nurses[(3, + 2)], nurses[(3, + 2)] == nurses[(3, + 3)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 2)] == nurses[(3, + 3)], nurses[(3, + 3)] == nurses[(3, + 4)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 3)] == nurses[(3, + 4)], nurses[(3, + 4)] == nurses[(3, + 5)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 4)] == nurses[(3, + 5)], nurses[(3, + 5)] == nurses[(3, + 6)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 5)] == nurses[(3, + 6)], nurses[(3, + 6)] == nurses[(3, + 0)]) == 1) + solver.Add( + solver.Max(nurses[(3, + 6)] == nurses[(3, + 0)], nurses[(3, + 0)] == nurses[(3, + 1)]) == 1) + # Create the decision builder. db = solver.Phase(shifts_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) -# Create the solution collector. + # Create the solution collector. solution = solver.Assignment() solution.Add(shifts_flat) collector = solver.AllSolutionCollector(solution) @@ -89,7 +165,7 @@ def main(): a_few_solutions = [859, 2034, 5091, 7003] for sol in a_few_solutions: - print("Solution number" , sol, '\n') + print("Solution number", sol, "\n") for i in range(num_days): print("Day", i) @@ -98,5 +174,6 @@ def main(): collector.Value(sol, shifts[(j, i)])) print() + if __name__ == "__main__": main() diff --git a/examples/python/nurses_sat.py b/examples/python/nurses_sat.py index c16efa2c68..73681b2bfc 100644 --- a/examples/python/nurses_sat.py +++ b/examples/python/nurses_sat.py @@ -11,7 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - from __future__ import print_function import sys from ortools.sat.python import cp_model @@ -47,7 +46,7 @@ class NursesPartialSolutionPrinter(cp_model.CpSolverSolutionCallback): def main(): # Data. num_nurses = 4 - num_shifts = 4 # Nurse assigned to shift 0 means not working that day. + num_shifts = 4 # Nurse assigned to shift 0 means not working that day. num_days = 7 all_nurses = range(num_nurses) all_shifts = range(num_shifts) @@ -105,17 +104,17 @@ def main(): for d in all_days: yesterday = (d - 1) % num_days tomorrow = (d + 1) % num_days - model.AddBoolOr([shifts[(n, yesterday, s)], shifts[(n, d, s)].Not(), - shifts[(n, tomorrow, s)]]) - + model.AddBoolOr([ + shifts[(n, yesterday, s)], shifts[(n, d, s)].Not(), + shifts[(n, tomorrow, s)] + ]) # Creates the solver and solve. solver = cp_model.CpSolver() # Display a few solutions picked at random. a_few_solutions = [859, 2034, 5091, 7003] - solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, - num_days, num_shifts, - a_few_solutions) + solution_printer = NursesPartialSolutionPrinter(shifts, num_nurses, num_days, + num_shifts, a_few_solutions) status = solver.SearchForAllSolutions(model, solution_printer) # Statistics. @@ -127,5 +126,5 @@ def main(): print(' - solutions found : %i' % solution_printer.SolutionCount()) -if __name__ == "__main__": +if __name__ == '__main__': main() diff --git a/examples/python/olympic.py b/examples/python/olympic.py index 18f8cc1f29..5abb5294a2 100644 --- a/examples/python/olympic.py +++ b/examples/python/olympic.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Olympic puzzle in Google CP Solver. @@ -97,9 +96,7 @@ def main(): # # solution and search # - db = solver.Phase(Vars, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(Vars, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/organize_day.py b/examples/python/organize_day.py index 03c1233550..5f080647d9 100644 --- a/examples/python/organize_day.py +++ b/examples/python/organize_day.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Organizing a day in Google CP Solver. @@ -62,10 +61,7 @@ def main(): durations = [4, 1, 2, 1] # task [i,0] must be finished before task [i,1] - before_tasks = [ - [bank, shop], - [mail, work] - ] + before_tasks = [[bank, shop], [mail, work]] # the valid times of the day begin = 9 @@ -86,9 +82,7 @@ def main(): for i in tasks: for j in tasks: if i < j: - no_overlap(solver, - begins[i], durations[i], - begins[j], durations[j]) + no_overlap(solver, begins[i], durations[i], begins[j], durations[j]) # specific constraints for (before, after) in before_tasks: @@ -99,8 +93,7 @@ def main(): # # solution and search # - db = solver.Phase(begins + ends, - solver.INT_VAR_DEFAULT, + db = solver.Phase(begins + ends, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/p_median.py b/examples/python/p_median.py index 45f65c6ab9..da19a9a91e 100644 --- a/examples/python/p_median.py +++ b/examples/python/p_median.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ P-median problem in Google CP Solver. @@ -57,39 +56,32 @@ def main(): Santa_Clara, San_Jose, Berkeley = warehouses demand = [100, 80, 80, 70] - distance = [ - [2, 10, 50], - [2, 10, 52], - [50, 60, 3], - [40, 60, 1] - ] + distance = [[2, 10, 50], [2, 10, 52], [50, 60, 3], [40, 60, 1]] # # declare variables # - open = [solver.IntVar(warehouses, 'open[%i]% % i') - for w in warehouses] + open = [solver.IntVar(warehouses, 'open[%i]% % i') for w in warehouses] ship = {} for c in customers: for w in warehouses: ship[c, w] = solver.IntVar(0, 1, 'ship[%i,%i]' % (c, w)) - ship_flat = [ship[c, w] - for c in customers - for w in warehouses] + ship_flat = [ship[c, w] for c in customers for w in warehouses] z = solver.IntVar(0, 1000, 'z') # # constraints # - z_sum = solver.Sum([demand[c] * distance[c][w] * ship[c, w] - for c in customers - for w in warehouses]) + z_sum = solver.Sum([ + demand[c] * distance[c][w] * ship[c, w] + for c in customers + for w in warehouses + ]) solver.Add(z == z_sum) for c in customers: - s = solver.Sum([ship[c, w] - for w in warehouses]) + s = solver.Sum([ship[c, w] for w in warehouses]) solver.Add(s == 1) solver.Add(solver.Sum(open) == p) @@ -104,8 +96,7 @@ def main(): # # solution and search # - db = solver.Phase(open + ship_flat, - solver.INT_VAR_DEFAULT, + db = solver.Phase(open + ship_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db, [objective]) diff --git a/examples/python/pandigital_numbers.py b/examples/python/pandigital_numbers.py index 7c38c79c80..07e6b90279 100644 --- a/examples/python/pandigital_numbers.py +++ b/examples/python/pandigital_numbers.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Pandigital numbers in Google CP Solver. @@ -73,8 +72,8 @@ from ortools.constraint_solver import pywrapcp def toNum(solver, t, s, base): tlen = len(t) - solver.Add( - s == solver.Sum([(base ** (tlen - i - 1)) * t[i] for i in range(tlen)])) + solver.Add(s == solver.Sum([(base**(tlen - i - 1)) * t[i] + for i in range(tlen)])) def main(base=10, start=1, len1=1, len2=4): @@ -87,7 +86,7 @@ def main(base=10, start=1, len1=1, len2=4): # max_d = base - 1 x_len = max_d + 1 - start - max_num = base ** 4 - 1 + max_num = base**4 - 1 # # declare variables @@ -126,9 +125,7 @@ def main(base=10, start=1, len1=1, len2=4): solution.Add(num2) solution.Add(res) - db = solver.Phase(x, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) num_solutions = 0 @@ -149,8 +146,8 @@ def main(base=10, start=1, len1=1, len2=4): def print_solution(x, len1, len2, x_len): - print("".join([str(x[i]) for i in range(len1)]), "*", end=' ') - print("".join([str(x[i]) for i in range(len1, len1 + len2)]), "=", end=' ') + print("".join([str(x[i]) for i in range(len1)]), "*", end=" ") + print("".join([str(x[i]) for i in range(len1, len1 + len2)]), "=", end=" ") print("".join([str(x[i]) for i in range(len1 + len2, x_len)])) diff --git a/examples/python/photo_problem.py b/examples/python/photo_problem.py index e2caf3e5ba..3d4b4debc9 100644 --- a/examples/python/photo_problem.py +++ b/examples/python/photo_problem.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Photo problem in Google CP Solver. @@ -95,8 +94,12 @@ def main(show_all_max=0): solver.Add(solver.AllDifferent(positions)) # calculate all the successful preferences - b = [solver.IsEqualCstVar(abs(positions[i] - positions[j]), 1) - for i in range(n) for j in range(n) if preferences[i][j] == 1] + b = [ + solver.IsEqualCstVar(abs(positions[i] - positions[j]), 1) + for i in range(n) + for j in range(n) + if preferences[i][j] == 1 + ] solver.Add(z == solver.Sum(b)) # @@ -113,8 +116,7 @@ def main(show_all_max=0): # # search and result # - db = solver.Phase(positions, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(positions, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE) if show_all_max == 0: @@ -127,8 +129,8 @@ def main(show_all_max=0): print("z:", z.Value()) p = [positions[i].Value() for i in range(n)] - print(" ".join([persons[j] - for i in range(n) for j in range(n) if p[j] == i])) + print(" ".join( + [persons[j] for i in range(n) for j in range(n) if p[j] == i])) print("Successful preferences:") for i in range(n): for j in range(n): diff --git a/examples/python/place_number_puzzle.py b/examples/python/place_number_puzzle.py index 07c97c1093..a329a0b915 100644 --- a/examples/python/place_number_puzzle.py +++ b/examples/python/place_number_puzzle.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Place number puzzle Google CP Solver. @@ -54,40 +53,10 @@ def main(): m = 32 n = 8 # Note: this is 1-based for compatibility (and lazyness) - graph = [ - [1, 2], - [1, 3], - [1, 4], - [2, 1], - [2, 3], - [2, 5], - [2, 6], - [3, 2], - [3, 4], - [3, 6], - [3, 7], - [4, 1], - [4, 3], - [4, 6], - [4, 7], - [5, 2], - [5, 3], - [5, 6], - [5, 8], - [6, 2], - [6, 3], - [6, 4], - [6, 5], - [6, 7], - [6, 8], - [7, 3], - [7, 4], - [7, 6], - [7, 8], - [8, 5], - [8, 6], - [8, 7] - ] + graph = [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 5], [2, 6], [3, 2], + [3, 4], [3, 6], [3, 7], [4, 1], [4, 3], [4, 6], [4, 7], [5, 2], + [5, 3], [5, 6], [5, 8], [6, 2], [6, 3], [6, 4], [6, 5], [6, 7], + [6, 8], [7, 3], [7, 4], [7, 6], [7, 8], [8, 5], [8, 6], [8, 7]] # declare variables x = [solver.IntVar(1, n, "x%i" % i) for i in range(n)] @@ -98,8 +67,7 @@ def main(): solver.Add(solver.AllDifferent(x)) for i in range(m): # Note: make 0-based - solver.Add(abs( - x[graph[i][0] - 1] - x[graph[i][1] - 1]) > 1) + solver.Add(abs(x[graph[i][0] - 1] - x[graph[i][1] - 1]) > 1) # symmetry breaking solver.Add(x[0] < x[n - 1]) @@ -112,10 +80,9 @@ def main(): collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE), + [collector]) num_solutions = collector.SolutionCount() for s in range(num_solutions): @@ -128,5 +95,6 @@ def main(): print("WallTime:", solver.WallTime()) print() + if __name__ == "__main__": main() diff --git a/examples/python/post_office_problem2.py b/examples/python/post_office_problem2.py index 767c70dc96..8fd2acf11c 100644 --- a/examples/python/post_office_problem2.py +++ b/examples/python/post_office_problem2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Post office problem in Google CP Solver. @@ -95,8 +94,8 @@ def main(): solver.Add(num_workers == solver.Sum(x)) for i in days: - s = solver.Sum([x[j] for j in days - if j != (i + 5) % n and j != (i + 6) % n]) + s = solver.Sum( + [x[j] for j in days if j != (i + 5) % n and j != (i + 6) % n]) solver.Add(s >= need[i]) # objective @@ -105,8 +104,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(x, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db, [objective]) diff --git a/examples/python/production.py b/examples/python/production.py index 991bea974b..69a081e676 100644 --- a/examples/python/production.py +++ b/examples/python/production.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Production planning problem in Google or-tools. @@ -63,22 +62,26 @@ def main(sol='CBC'): # # declare variables # - inside = [solver.NumVar(0, 10000, 'inside[%i]' % p) - for p in range(num_products)] - outside = [solver.NumVar(0, 10000, 'outside[%i]' % p) - for p in range(num_products)] + inside = [ + solver.NumVar(0, 10000, 'inside[%i]' % p) for p in range(num_products) + ] + outside = [ + solver.NumVar(0, 10000, 'outside[%i]' % p) for p in range(num_products) + ] # to minimize - z = solver.Sum([inside_cost[p] * inside[p] + outside_cost[p] * outside[p] - for p in range(num_products)]) + z = solver.Sum([ + inside_cost[p] * inside[p] + outside_cost[p] * outside[p] + for p in range(num_products) + ]) # # constraints # for r in range(num_resources): - solver.Add(solver.Sum( - [consumption[p][r] * inside[p] - for p in range(num_products)]) <= capacity[r]) + solver.Add( + solver.Sum([consumption[p][r] * inside[p] + for p in range(num_products)]) <= capacity[r]) for p in range(num_products): solver.Add(inside[p] + outside[p] >= demand[p]) @@ -91,8 +94,16 @@ def main(sol='CBC'): print('z = ', solver.Objective().Value()) for p in range(num_products): - print(products[p], ': inside:', inside[p].SolutionValue(), '(ReducedCost:', inside[p].ReducedCost(), ')', end=' ') - print('outside:', outside[p].SolutionValue(), ' (ReducedCost:', outside[p].ReducedCost(), ')') + print( + products[p], + ': inside:', + inside[p].SolutionValue(), + '(ReducedCost:', + inside[p].ReducedCost(), + ')', + end=' ') + print('outside:', outside[p].SolutionValue(), ' (ReducedCost:', + outside[p].ReducedCost(), ')') print() diff --git a/examples/python/pyflow_example.py b/examples/python/pyflow_example.py index 480d7755e7..19db82e4a2 100644 --- a/examples/python/pyflow_example.py +++ b/examples/python/pyflow_example.py @@ -10,10 +10,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """MaxFlow and MinCostFlow examples.""" - from __future__ import print_function from ortools.graph import pywrapgraph @@ -31,11 +29,9 @@ def MaxFlow(): if max_flow.Solve(0, 5) == max_flow.OPTIMAL: print('Total flow', max_flow.OptimalFlow(), '/', expected_total_flow) for i in range(max_flow.NumArcs()): - print(('From source %d to target %d: %d / %d' % ( - max_flow.Tail(i), - max_flow.Head(i), - max_flow.Flow(i), - max_flow.Capacity(i)))) + print(('From source %d to target %d: %d / %d' % + (max_flow.Tail(i), max_flow.Head(i), max_flow.Flow(i), + max_flow.Capacity(i)))) print('Source side min-cut:', max_flow.GetSourceSideMinCut()) print('Sink side min-cut:', max_flow.GetSinkSideMinCut()) else: @@ -51,16 +47,14 @@ def MinCostFlow(): print('MinCostFlow on 4x4 matrix.') num_sources = 4 num_targets = 4 - costs = [[90, 75, 75, 80], - [35, 85, 55, 65], - [125, 95, 90, 105], + costs = [[90, 75, 75, 80], [35, 85, 55, 65], [125, 95, 90, 105], [45, 110, 95, 115]] expected_cost = 275 min_cost_flow = pywrapgraph.SimpleMinCostFlow() for source in range(0, num_sources): for target in range(0, num_targets): - min_cost_flow.AddArcWithCapacityAndUnitCost( - source, num_sources + target, 1, costs[source][target]) + min_cost_flow.AddArcWithCapacityAndUnitCost(source, num_sources + target, + 1, costs[source][target]) for node in range(0, num_sources): min_cost_flow.SetNodeSupply(node, 1) min_cost_flow.SetNodeSupply(num_sources + node, -1) @@ -69,10 +63,9 @@ def MinCostFlow(): print('Total flow', min_cost_flow.OptimalCost(), '/', expected_cost) for i in range(0, min_cost_flow.NumArcs()): if min_cost_flow.Flow(i) > 0: - print('From source %d to target %d: cost %d' % ( - min_cost_flow.Tail(i), - min_cost_flow.Head(i) - num_sources, - min_cost_flow.UnitCost(i))) + print('From source %d to target %d: cost %d' % + (min_cost_flow.Tail(i), min_cost_flow.Head(i) - num_sources, + min_cost_flow.UnitCost(i))) else: print('There was an issue with the min cost flow input.') diff --git a/examples/python/pyls_api.py b/examples/python/pyls_api.py index d48035bfb5..fc6bcd5757 100644 --- a/examples/python/pyls_api.py +++ b/examples/python/pyls_api.py @@ -1,6 +1,7 @@ from __future__ import print_function from ortools.constraint_solver import pywrapcp + class OneVarLns(pywrapcp.BaseLns): """One Var LNS.""" diff --git a/examples/python/quasigroup_completion.py b/examples/python/quasigroup_completion.py index 04b766b15e..9410aba8cc 100644 --- a/examples/python/quasigroup_completion.py +++ b/examples/python/quasigroup_completion.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Quasigroup completion Google CP Solver. @@ -61,13 +60,8 @@ default_n = 5 X = 0 # default problem # (This is the same as quasigroup1.txt) -default_puzzle = [ - [1, X, X, X, 4], - [X, 5, X, X, X], - [4, X, X, 2, X], - [X, 4, X, X, X], - [X, X, 5, X, 1] -] +default_puzzle = [[1, X, X, X, 4], [X, 5, X, X, X], [4, X, X, 2, X], + [X, 4, X, X, X], [X, X, 5, X, 1]] def main(puzzle="", n=0): @@ -122,9 +116,7 @@ def main(puzzle="", n=0): # This version prints out the solution directly, and # don't collect them as solver.FirstSolutionCollector(solution) do # (db: DecisionBuilder) - db = solver.Phase(xflat, - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(xflat, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -134,7 +126,7 @@ def main(puzzle="", n=0): xval = [x[(i, j)].Value() for i in range(n) for j in range(n)] for i in range(n): for j in range(n): - print(xval[i * n + j], end=' ') + print(xval[i * n + j], end=" ") print() print() solver.EndSearch() @@ -194,14 +186,14 @@ def read_problem(file): def print_board(x, rows, cols): for i in range(rows): for j in range(cols): - print("% 2s" % x[i, j], end=' ') + print("% 2s" % x[i, j], end=" ") print("") def print_game(game, rows, cols): for i in range(rows): for j in range(cols): - print("% 2s" % game[i][j], end=' ') + print("% 2s" % game[i][j], end=" ") print("") diff --git a/examples/python/rabbit_pheasant.py b/examples/python/rabbit_pheasant.py index 362ba930ff..265e948b7c 100644 --- a/examples/python/rabbit_pheasant.py +++ b/examples/python/rabbit_pheasant.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Rabbit + Pheasant puzzle. This example is the same one described in @@ -31,7 +30,6 @@ def main(): # Create the solver. solver = pywrapcp.Solver('rabbit+pheasant', parameters) - # Create the variables. pheasant = solver.IntVar(0, 100, 'pheasant') rabbit = solver.IntVar(0, 100, 'rabbit') @@ -41,8 +39,7 @@ def main(): solver.Add(pheasant * 2 + rabbit * 4 == 56) # Create the search phase. - db = solver.Phase([rabbit, pheasant], - solver.INT_VAR_DEFAULT, + db = solver.Phase([rabbit, pheasant], solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) # And solve. @@ -55,5 +52,6 @@ def main(): solver.EndSearch() print(solver) + if __name__ == '__main__': main() diff --git a/examples/python/rcpsp_sat.py b/examples/python/rcpsp_sat.py index eff4bde144..a5f92a9114 100644 --- a/examples/python/rcpsp_sat.py +++ b/examples/python/rcpsp_sat.py @@ -22,10 +22,12 @@ import time parser = argparse.ArgumentParser() -parser.add_argument('--input', default = "", - help = 'Input file to parse and solve.') -parser.add_argument('--output_proto', default = "", - help = 'Output file to write the cp_model proto to.') +parser.add_argument( + '--input', default='', help='Input file to parse and solve.') +parser.add_argument( + '--output_proto', + default='', + help='Output file to write the cp_model proto to.') class SolutionPrinter(cp_model.CpSolverSolutionCallback): @@ -45,17 +47,17 @@ class SolutionPrinter(cp_model.CpSolverSolutionCallback): def SolveRcpsp(problem, proto_file): # Determine problem type. - problem_type = ('Resource investment' if problem.is_resource_investment - else 'RCPSP') + problem_type = ('Resource investment' + if problem.is_resource_investment else 'RCPSP') if problem.is_rcpsp_max: problem_type += '/Max delay' if problem.is_consumer_producer: - print ('Solving %s with %i reservoir resources and %i tasks' % ( - problem_type, len(problem.resources), len(problem.tasks))) + print('Solving %s with %i reservoir resources and %i tasks' % + (problem_type, len(problem.resources), len(problem.tasks))) else: - print ('Solving %s with %i resources and %i tasks' % ( - problem_type, len(problem.resources), len(problem.tasks))) + print('Solving %s with %i resources and %i tasks' % + (problem_type, len(problem.resources), len(problem.tasks))) # Create the model. model = cp_model.CpModel() @@ -161,8 +163,8 @@ def SolveRcpsp(problem, proto_file): task_starts[t] = model.NewIntVar(0, horizon, 'start_of_task_%i' % t) task_ends[t] = model.NewIntVar(0, horizon, 'end_of_task_%i' % t) duration = model.NewIntVar(min_size, max_size, 'duration_of_task_%i' % t) - interval = model.NewIntervalVar(task_starts[t], duration, - task_ends[t], 'interval_%i' % t) + interval = model.NewIntervalVar(task_starts[t], duration, task_ends[t], + 'interval_%i' % t) # Link with optional per-recipe copies. for r in all_recipes: @@ -172,7 +174,6 @@ def SolveRcpsp(problem, proto_file): model.Add(duration == task.recipes[r].duration).OnlyEnforceIf(p) model.Add(sum(presences_per_task[t]) == 1) - # Create makespan variable makespan = model.NewIntVar(0, horizon, 'makespan') @@ -218,22 +219,23 @@ def SolveRcpsp(problem, proto_file): if problem.is_resource_investment: capacity = model.NewIntVar(0, c, 'capacity_of_%i' % r) - model.AddCumulative( - intervals_per_resource[r], demands_per_resource[r], capacity) + model.AddCumulative(intervals_per_resource[r], demands_per_resource[r], + capacity) capacities.append(capacity) max_cost += c * resource.unit_cost elif resource.renewable: if intervals_per_resource[r]: - model.AddCumulative( - intervals_per_resource[r], demands_per_resource[r], c) + model.AddCumulative(intervals_per_resource[r], demands_per_resource[r], + c) elif presences_per_resource[r]: # Non empty non renewable resource. if problem.is_consumer_producer: model.AddReservoirConstraint( starts_per_resource[r], demands_per_resource[r], resource.min_capacity, resource.max_capacity) else: - model.Add(sum(presences_per_resource[r][i] * demands_per_resource[r][i] - for i in range(len(presences_per_resource[r]))) <= c) + model.Add( + sum(presences_per_resource[r][i] * demands_per_resource[r][i] + for i in range(len(presences_per_resource[r]))) <= c) # Objective. if problem.is_resource_investment: diff --git a/examples/python/regular.py b/examples/python/regular.py index 3e76320dda..24c250d2ff 100644 --- a/examples/python/regular.py +++ b/examples/python/regular.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Global constraint regular in Google CP Solver. @@ -106,8 +105,8 @@ def regular(x, Q, S, d, q0, F): solver.Add(x[i] <= S) # Determine a[i+1]: a[i+1] == d2[a[i], x[i]] - solver.Add( - a[i + 1] == solver.Element(d2_flatten, ((a[i]) * S) + (x[i] - 1))) + solver.Add(a[i + 1] == solver.Element(d2_flatten, ( + (a[i]) * S) + (x[i] - 1))) # @@ -190,20 +189,20 @@ def main(): accepting_states = [n_states] # declare variables - reg_input = [solver.IntVar(1, input_max, 'reg_input[%i]' % i) - for i in range(this_len)] + reg_input = [ + solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len) + ] # # constraints # - regular(reg_input, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(reg_input, n_states, input_max, transition_fn, initial_state, + accepting_states) # # solution and search # - db = solver.Phase(reg_input, - solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, + db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/regular_table.py b/examples/python/regular_table.py index 1d8b16802e..e06ed72d2f 100644 --- a/examples/python/regular_table.py +++ b/examples/python/regular_table.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Global constraint regular in Google CP Solver. @@ -183,20 +182,20 @@ def main(): accepting_states = [n_states] # declare variables - reg_input = [solver.IntVar(1, input_max, 'reg_input[%i]' % i) - for i in range(this_len)] + reg_input = [ + solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len) + ] # # constraints # - regular(reg_input, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(reg_input, n_states, input_max, transition_fn, initial_state, + accepting_states) # # solution and search # - db = solver.Phase(reg_input, - solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, + db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/regular_table2.py b/examples/python/regular_table2.py index d21e366c70..95b4056c8f 100644 --- a/examples/python/regular_table2.py +++ b/examples/python/regular_table2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Global constraint regular in Google CP Solver. @@ -84,6 +83,7 @@ def regular(x, Q, S, d, q0, F): solver.Add(solver.TransitionConstraint(x, d2, q0, F)) + # # Make a transition (automaton) matrix from a # single pattern, e.g. [3,2,1] @@ -166,20 +166,20 @@ def main(): accepting_states = [n_states] # declare variables - reg_input = [solver.IntVar(1, input_max, 'reg_input[%i]' % i) - for i in range(this_len)] + reg_input = [ + solver.IntVar(1, input_max, 'reg_input[%i]' % i) for i in range(this_len) + ] # # constraints # - regular(reg_input, n_states, input_max, transition_fn, - initial_state, accepting_states) + regular(reg_input, n_states, input_max, transition_fn, initial_state, + accepting_states) # # solution and search # - db = solver.Phase(reg_input, - solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, + db = solver.Phase(reg_input, solver.CHOOSE_MIN_SIZE_HIGHEST_MAX, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/rogo2.py b/examples/python/rogo2.py index 4cc1f31878..b9710c9286 100644 --- a/examples/python/rogo2.py +++ b/examples/python/rogo2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Rogo puzzle solver in Google CP Solver. @@ -80,8 +79,9 @@ def main(problem, rows, cols, max_steps): y = [solver.IntVar(0, cols - 1, "y[%i]" % i) for i in range(max_steps)] # the collected points - points = [solver.IntVar(0, max_point, "points[%i]" % i) - for i in range(max_steps)] + points = [ + solver.IntVar(0, max_point, "points[%i]" % i) for i in range(max_steps) + ] # objective: sum of points in the path sum_points = solver.IntVar(0, max_sum) @@ -181,14 +181,10 @@ cols = 9 max_steps = 12 W = 0 B = -1 -problem = [ - [2, W, W, W, W, W, W, W, W], - [W, 3, W, W, 1, W, W, 2, W], - [W, W, W, W, W, W, B, W, 2], - [W, W, 2, B, W, W, W, W, W], - [W, W, W, W, 2, W, W, 1, W] -] +problem = [[2, W, W, W, W, W, W, W, W], [W, 3, W, W, 1, W, W, 2, W], + [W, W, W, W, W, W, B, W, 2], [W, W, 2, B, W, W, W, W, + W], [W, W, W, W, 2, W, W, 1, W]] if __name__ == "__main__": if len(sys.argv) > 1: - exec(compile(open(sys.argv[1]).read(), sys.argv[1], 'exec')) + exec (compile(open(sys.argv[1]).read(), sys.argv[1], "exec")) main(problem, rows, cols, max_steps) diff --git a/examples/python/rostering_with_travel.py b/examples/python/rostering_with_travel.py index c0458307fc..274c954ebe 100644 --- a/examples/python/rostering_with_travel.py +++ b/examples/python/rostering_with_travel.py @@ -5,11 +5,7 @@ def SolveRosteringWithTravel(): model = cp_model.CpModel() # [duration, start, end, location] - jobs = [[3, 0, 6, 1], - [5, 0, 6, 0], - [1, 3, 7, 1], - [1, 3, 5, 0], - [3, 0, 3, 0], + jobs = [[3, 0, 6, 1], [5, 0, 6, 0], [1, 3, 7, 1], [1, 3, 5, 0], [3, 0, 3, 0], [3, 0, 8, 0]] max_length = 20 @@ -65,11 +61,11 @@ def SolveRosteringWithTravel(): travel = model.NewBoolVar('is_travel_%i_on_m%i' % (i, m)) startT = model.NewOptionalIntVar(0, horizon, travel, 'start_%i_on_m%i' % (i, m)) - endT = model.NewOptionalIntVar(0, horizon, travel, 'end_%i_on_m%i' % (i, - m)) + endT = model.NewOptionalIntVar(0, horizon, travel, + 'end_%i_on_m%i' % (i, m)) intervalT = model.NewOptionalIntervalVar( - startT, travel_time, endT, travel, 'travel_interval_%i_on_m%i' % (i, - m)) + startT, travel_time, endT, travel, + 'travel_interval_%i_on_m%i' % (i, m)) optional_intervals[m].append(intervalT) job_travels.append(travel) @@ -88,7 +84,8 @@ def SolveRosteringWithTravel(): if (i != c) and (jobs[i][3] != jobs[c][3]): is_job_earlier = model.NewBoolVar('is_j%i_earlier_j%i' % (i, c)) model.Add(starts[i] < starts[c]).OnlyEnforceIf(is_job_earlier) - model.Add(starts[i] >= starts[c]).OnlyEnforceIf(is_job_earlier.Not()) + model.Add(starts[i] >= starts[c]).OnlyEnforceIf( + is_job_earlier.Not()) # Max Length constraint (modeled as a cumulative) # model.AddCumulative(intervals, demands, max_length) diff --git a/examples/python/safe_cracking.py b/examples/python/safe_cracking.py index 9a90e12c52..6f1a4f9a71 100644 --- a/examples/python/safe_cracking.py +++ b/examples/python/safe_cracking.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Safe cracking puzzle in Google CP Solver. @@ -82,9 +81,7 @@ def main(): # # search and result # - db = solver.Phase(LD, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(LD, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/scheduling_speakers.py b/examples/python/scheduling_speakers.py index ec59458f29..652a669083 100644 --- a/examples/python/scheduling_speakers.py +++ b/examples/python/scheduling_speakers.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Scheduling speakers problem in Google CP Solver. @@ -46,11 +45,11 @@ def main(): # slots available to speak available = [ # Reasoning: - [3, 4, 5, 6], # 2) the only one with 6 after speaker F -> 1 - [3, 4], # 5) 3 or 4 - [2, 3, 4, 5], # 3) only with 5 after F -> 1 and A -> 6 - [2, 3, 4], # 4) only with 2 after C -> 5 and F -> 1 - [3, 4], # 5) 3 or 4 + [3, 4, 5, 6], # 2) the only one with 6 after speaker F -> 1 + [3, 4], # 5) 3 or 4 + [2, 3, 4, 5], # 3) only with 5 after F -> 1 and A -> 6 + [2, 3, 4], # 4) only with 2 after C -> 5 and F -> 1 + [3, 4], # 5) 3 or 4 [1, 2, 3, 4, 5, 6] # 1) the only with 1 ] @@ -70,9 +69,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) diff --git a/examples/python/school_scheduling_sat.py b/examples/python/school_scheduling_sat.py index 0faa09d1eb..8222672d2b 100644 --- a/examples/python/school_scheduling_sat.py +++ b/examples/python/school_scheduling_sat.py @@ -91,8 +91,8 @@ class SchoolSchedulingSatSolver(object): for teacher in all_teachers: self.model.Add( sum([ - self.assignment[c, s, teacher, slot] - for c in all_courses for s in all_subjects for slot in all_slots + self.assignment[c, s, teacher, slot] for c in all_courses + for s in all_subjects for slot in all_slots ]) <= self.problem.teacher_work_hours[teacher]) # Teacher makes all the classes of a subject's course diff --git a/examples/python/secret_santa.py b/examples/python/secret_santa.py index 352c133321..97f2d3b144 100644 --- a/examples/python/secret_santa.py +++ b/examples/python/secret_santa.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Secret Santa problem in Google CP Solver. @@ -99,9 +98,7 @@ def main(): # # solution and search # - db = solver.Phase(x, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_SIMPLE) + db = solver.Phase(x, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) solver.NewSearch(db) num_solutions = 0 @@ -115,5 +112,6 @@ def main(): print('branches:', solver.Branches()) print('WallTime:', solver.WallTime(), 'ms') + if __name__ == '__main__': main() diff --git a/examples/python/secret_santa2.py b/examples/python/secret_santa2.py index fa5c449151..509d83d140 100644 --- a/examples/python/secret_santa2.py +++ b/examples/python/secret_santa2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Secret Santa problem II in Google CP Solver. @@ -126,8 +125,9 @@ def main(singe=0): M = n + 1 - persons = ['Noah', 'Ava', 'Ryan', 'Mia', 'Ella', - 'John', 'Lily', 'Evan', 'Single'] + persons = [ + 'Noah', 'Ava', 'Ryan', 'Mia', 'Ella', 'John', 'Lily', 'Evan', 'Single' + ] spouses = [ Ava, # Noah @@ -138,16 +138,16 @@ def main(singe=0): Ella, # John Evan, # Lily Lily, # Evan - -1 # Single has no spouse + -1 # Single has no spouse ] # # declare variables # - santas = [solver.IntVar(0, n - 1, 'santas[%i]' % i) - for i in range(n)] - santa_distance = [solver.IntVar(0, M, 'santa_distance[%i]' % i) - for i in range(n)] + santas = [solver.IntVar(0, n - 1, 'santas[%i]' % i) for i in range(n)] + santa_distance = [ + solver.IntVar(0, M, 'santa_distance[%i]' % i) for i in range(n) + ] # total of 'distance', to maximize z = solver.IntVar(0, n * n * n, 'z') @@ -171,8 +171,7 @@ def main(singe=0): # optimize 'distance' to earlier rounds: for i in range(n): - solver.Add(santa_distance[i] == - solver.Element(rounds[i], santas[i])) + solver.Add(santa_distance[i] == solver.Element(rounds[i], santas[i])) # cannot be a Secret Santa for the same person # two years in a row. @@ -187,8 +186,7 @@ def main(singe=0): # # solution and search # - db = solver.Phase(santas, - solver.CHOOSE_MIN_SIZE_LOWEST_MIN, + db = solver.Phase(santas, solver.CHOOSE_MIN_SIZE_LOWEST_MIN, solver.ASSIGN_CENTER_VALUE) solver.NewSearch(db, [objective]) @@ -212,6 +210,7 @@ def main(singe=0): print('branches:', solver.Branches()) print('WallTime:', solver.WallTime(), 'ms') + single = 0 if __name__ == '__main__': print('Secret Santas without single') diff --git a/examples/python/send_more_money_any_base.py b/examples/python/send_more_money_any_base.py index 29802a4c33..872efcad40 100644 --- a/examples/python/send_more_money_any_base.py +++ b/examples/python/send_more_money_any_base.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ SEND+MORE=MONEY in 'any' base in Google CP Solver. @@ -71,9 +70,9 @@ def main(base=10): # constraints # solver.Add(solver.AllDifferent(x)) - solver.Add(s * base ** 3 + e * base ** 2 + n * base + d + - m * base ** 3 + o * base ** 2 + r * base + e == - m * base ** 4 + o * base ** 3 + n * base ** 2 + e * base + y,) + solver.Add( + s * base**3 + e * base**2 + n * base + d + m * base**3 + o * base**2 + + r * base + e == m * base**4 + o * base**3 + n * base**2 + e * base + y,) solver.Add(s > 0) solver.Add(m > 0) @@ -85,10 +84,9 @@ def main(base=10): collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MAX_VALUE), - [collector]) + solver.Solve( + solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE), + [collector]) num_solutions = collector.SolutionCount() money_val = 0 diff --git a/examples/python/send_most_money.py b/examples/python/send_most_money.py index 385cce2d55..18d295a0f5 100644 --- a/examples/python/send_most_money.py +++ b/examples/python/send_most_money.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ SEND+MOST=MONEY in Google CP Solver. @@ -72,9 +71,8 @@ def main(MONEY=0): solver.Add(solver.AllDifferent(x)) solver.Add(money == m * 10000 + o * 1000 + n * 100 + e * 10 + y) solver.Add(money > 0) - solver.Add(1000 * s + 100 * e + 10 * n + d + - 1000 * m + 100 * o + 10 * s + t == - money) + solver.Add(1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * s + + t == money) solver.Add(s > 0) solver.Add(m > 0) @@ -92,10 +90,9 @@ def main(MONEY=0): objective = solver.Maximize(money, 1) cargs.extend([objective]) - solver.Solve(solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MAX_VALUE), - cargs) + solver.Solve( + solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE), + cargs) num_solutions = collector.SolutionCount() money_val = 0 diff --git a/examples/python/sendmore.py b/examples/python/sendmore.py index 2f96f17865..d88c177635 100644 --- a/examples/python/sendmore.py +++ b/examples/python/sendmore.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Send + more = money. In this model, we try to solve the following cryptarythm @@ -38,10 +37,8 @@ def main(): letters = [s, e, n, d, m, o, r, y] - solver.Add( - 1000 * s + 100 * e + 10 * n + d + - 1000 * m + 100 * o + 10 * r + e == - 10000 * m + 1000 * o + 100 * n + 10 * e + y) + solver.Add(1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * r + + e == 10000 * m + 1000 * o + 100 * n + 10 * e + y) # pylint: disable=g-explicit-bool-comparison solver.Add(s != 0) @@ -49,9 +46,8 @@ def main(): solver.Add(solver.AllDifferent(letters)) - solver.NewSearch(solver.Phase(letters, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT)) + solver.NewSearch( + solver.Phase(letters, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)) solver.NextSolution() print(letters) solver.EndSearch() diff --git a/examples/python/seseman.py b/examples/python/seseman.py index 1cb2889169..3099fb0f91 100644 --- a/examples/python/seseman.py +++ b/examples/python/seseman.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Seseman Convent problem in Google CP Solver. @@ -96,8 +95,7 @@ def main(unused_argv): # total solver.Add( - solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == - total_sum) + solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum) # # solution and search @@ -109,10 +107,9 @@ def main(unused_argv): # all solutions collector = solver.AllSolutionCollector(solution) # search_log = solver.SearchLog(100, total_sum) - solver.Solve(solver.Phase([x[(i, j)] for i in range(n) for j in range(n)], - solver.CHOOSE_PATH, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([x[(i, j)] for i in range(n) for j in range(n)], + solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE), [collector]) #[collector, search_log]) num_solutions = collector.SolutionCount() @@ -125,7 +122,7 @@ def main(unused_argv): print("total_sum:", collector.Value(s, total_sum)) for i in range(n): for j in range(n): - print(collector.Value(s, x[(i, j)]), end=' ') + print(collector.Value(s, x[(i, j)]), end=" ") print() print() diff --git a/examples/python/seseman_b.py b/examples/python/seseman_b.py index 84b81209ed..49622c0902 100644 --- a/examples/python/seseman_b.py +++ b/examples/python/seseman_b.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Seseman Convent problem in Google CP Solver. @@ -98,8 +97,7 @@ def main(unused_argv): # total solver.Add( - solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == - total_sum) + solver.Sum([x[(i, j)] for i in range(n) for j in range(n)]) == total_sum) # # solution and search @@ -109,8 +107,7 @@ def main(unused_argv): solution.Add(total_sum) db = solver.Phase([x[(i, j)] for i in range(n) for j in range(n)], - solver.CHOOSE_PATH, - solver.ASSIGN_MIN_VALUE) + solver.CHOOSE_PATH, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -121,7 +118,7 @@ def main(unused_argv): print("total_sum:", total_sum.Value()) for i in range(n): for j in range(n): - print(x[(i, j)].Value(), end=' ') + print(x[(i, j)].Value(), end=" ") print() print() diff --git a/examples/python/set_covering.py b/examples/python/set_covering.py index 5db7bcecc3..2dc807228c 100644 --- a/examples/python/set_covering.py +++ b/examples/python/set_covering.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering in Google CP Solver. @@ -46,14 +45,9 @@ def main(unused_argv): min_distance = 15 num_cities = 6 - distance = [ - [0, 10, 20, 30, 30, 20], - [10, 0, 25, 35, 20, 10], - [20, 25, 0, 15, 30, 20], - [30, 35, 15, 0, 15, 25], - [30, 20, 30, 15, 0, 14], - [20, 10, 20, 25, 14, 0] - ] + distance = [[0, 10, 20, 30, 30, 20], [10, 0, 25, 35, 20, 10], + [20, 25, 0, 15, 30, 20], [30, 35, 15, 0, 15, 25], + [30, 20, 30, 15, 0, 14], [20, 10, 20, 25, 14, 0]] # # declare variables @@ -82,10 +76,9 @@ def main(unused_argv): solution.AddObjective(z) collector = solver.LastSolutionCollector(solution) - solver.Solve(solver.Phase(x + [z], - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector, objective]) + solver.Solve( + solver.Phase(x + [z], solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector, objective]) print("z:", collector.ObjectiveValue(0)) print("x:", [collector.Value(0, x[i]) for i in range(num_cities)]) diff --git a/examples/python/set_covering2.py b/examples/python/set_covering2.py index 995e4aa0f4..68ac218d46 100644 --- a/examples/python/set_covering2.py +++ b/examples/python/set_covering2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering in Google CP Solver. @@ -50,19 +49,8 @@ def main(unused_argv): # corners of each street # Note: 1-based (handled below) - corner = [ - [1, 2], - [2, 3], - [4, 5], - [7, 8], - [6, 7], - [2, 6], - [1, 6], - [4, 7], - [2, 4], - [5, 8], - [3, 5] - ] + corner = [[1, 2], [2, 3], [4, 5], [7, 8], [6, 7], [2, 6], [1, 6], [4, 7], + [2, 4], [5, 8], [3, 5]] # # declare variables @@ -91,10 +79,9 @@ def main(unused_argv): solution.AddObjective(z) collector = solver.LastSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector, objective]) + solver.Solve( + solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector, objective]) print("z:", collector.ObjectiveValue(0)) print("x:", [collector.Value(0, x[i]) for i in range(n)]) diff --git a/examples/python/set_covering3.py b/examples/python/set_covering3.py index 980d09dd04..4bca057db3 100644 --- a/examples/python/set_covering3.py +++ b/examples/python/set_covering3.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering in Google CP Solver. @@ -63,12 +62,12 @@ def main(unused_argv): # which group does a senator belong to? belongs = [ - [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # 1 southern - [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], # 2 northern - [0, 1, 1, 0, 0, 0, 0, 1, 1, 1], # 3 liberals - [1, 0, 0, 0, 1, 1, 1, 0, 0, 0], # 4 conservative - [0, 0, 1, 1, 1, 1, 1, 0, 1, 0], # 5 democrats - [1, 1, 0, 0, 0, 0, 0, 1, 0, 1] # 6 republicans + [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], # 1 southern + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1], # 2 northern + [0, 1, 1, 0, 0, 0, 0, 1, 1, 1], # 3 liberals + [1, 0, 0, 0, 1, 1, 1, 0, 0, 0], # 4 conservative + [0, 0, 1, 1, 1, 1, 1, 0, 1, 0], # 5 democrats + [1, 1, 0, 0, 0, 0, 0, 1, 0, 1] # 6 republicans ] # @@ -87,9 +86,8 @@ def main(unused_argv): # one senator for i in range(num_groups): solver.Add( - solver.SumGreaterOrEqual([x[j] * belongs[i][j] - for j in range(num_senators)], - 1)) + solver.SumGreaterOrEqual( + [x[j] * belongs[i][j] for j in range(num_senators)], 1)) objective = solver.Minimize(z, 1) @@ -101,19 +99,18 @@ def main(unused_argv): solution.AddObjective(z) collector = solver.LastSolutionCollector(solution) - solver.Solve(solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector, objective]) + solver.Solve( + solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector, objective]) print("z:", collector.ObjectiveValue(0)) print("x:", [collector.Value(0, x[i]) for i in range(num_senators)]) for j in range(num_senators): if collector.Value(0, x[j]) == 1: - print("Senator", j + 1, "belongs to these groups:", end=' ') + print("Senator", j + 1, "belongs to these groups:", end=" ") for i in range(num_groups): if belongs[i][j] == 1: - print(i + 1, end=' ') + print(i + 1, end=" ") print() print() diff --git a/examples/python/set_covering4.py b/examples/python/set_covering4.py index e565387c70..9b497028b4 100644 --- a/examples/python/set_covering4.py +++ b/examples/python/set_covering4.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set partition and set covering in Google CP Solver. @@ -96,7 +95,7 @@ def main(set_partition=1): [0, 1, 1, 1, 0, 0, 0, 0], # alternative 7 [0, 0, 0, 1, 1, 0, 0, 1], # alternative 8 [0, 0, 1, 0, 0, 1, 0, 1], # alternative 9 - [1, 0, 0, 0, 0, 1, 1, 0] # alternative 10 + [1, 0, 0, 0, 0, 1, 1, 0] # alternative 10 ] # @@ -116,14 +115,12 @@ def main(set_partition=1): for j in range(num_objects): if set_partition == 1: solver.Add( - solver.SumEquality([x[i] * a[i][j] - for i in range(num_alternatives)], + solver.SumEquality([x[i] * a[i][j] for i in range(num_alternatives)], 1)) else: solver.Add( - solver.SumGreaterOrEqual([x[i] * a[i][j] - for i in range(num_alternatives)], - 1)) + solver.SumGreaterOrEqual( + [x[i] * a[i][j] for i in range(num_alternatives)], 1)) objective = solver.Minimize(z, 1) @@ -135,14 +132,15 @@ def main(set_partition=1): solution.AddObjective(z) collector = solver.LastSolutionCollector(solution) - solver.Solve(solver.Phase([x[i] for i in range(num_alternatives)], - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector, objective]) + solver.Solve( + solver.Phase([x[i] for i in range(num_alternatives)], + solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector, objective]) print("z:", collector.ObjectiveValue(0)) - print("selected alternatives:", [i + 1 for i in range(num_alternatives) - if collector.Value(0, x[i]) == 1]) + print( + "selected alternatives:", + [i + 1 for i in range(num_alternatives) if collector.Value(0, x[i]) == 1]) print("failures:", solver.Failures()) print("branches:", solver.Branches()) diff --git a/examples/python/set_covering_deployment.py b/examples/python/set_covering_deployment.py index 79923748e2..0be91a4ba9 100644 --- a/examples/python/set_covering_deployment.py +++ b/examples/python/set_covering_deployment.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering deployment in Google CP Solver @@ -52,27 +51,18 @@ def main(): # data # - countries = ["Alexandria", - "Asia Minor", - "Britain", - "Byzantium", - "Gaul", - "Iberia", - "Rome", - "Tunis"] + countries = [ + "Alexandria", "Asia Minor", "Britain", "Byzantium", "Gaul", "Iberia", + "Rome", "Tunis" + ] n = len(countries) # the incidence matrix (neighbours) - mat = [ - [0, 1, 0, 1, 0, 0, 1, 1], - [1, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 1, 0, 0], - [1, 1, 0, 0, 0, 0, 1, 0], - [0, 0, 1, 0, 0, 1, 1, 0], - [0, 0, 1, 0, 1, 0, 1, 1], - [1, 0, 0, 1, 1, 1, 0, 1], - [1, 0, 0, 0, 0, 1, 1, 0] - ] + mat = [[0, 1, 0, 1, 0, 0, 1, 1], [1, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 1, 0, 0], [1, 1, 0, 0, 0, 0, 1, 0], + [0, 0, 1, 0, 0, 1, 1, 0], [0, 0, 1, 0, 1, 0, 1, + 1], [1, 0, 0, 1, 1, 1, 0, + 1], [1, 0, 0, 0, 0, 1, 1, 0]] # # declare variables @@ -118,10 +108,9 @@ def main(): solution.AddObjective(num_armies) collector = solver.LastSolutionCollector(solution) - solver.Solve(solver.Phase(X + Y, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT), - [collector, objective]) + solver.Solve( + solver.Phase(X + Y, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT), + [collector, objective]) print("num_armies:", collector.ObjectiveValue(0)) print("X:", [collector.Value(0, X[i]) for i in range(n)]) @@ -129,7 +118,7 @@ def main(): for i in range(n): if collector.Value(0, X[i]) == 1: - print("army:", countries[i], end=' ') + print("army:", countries[i], end=" ") if collector.Value(0, Y[i]) == 1: print("reserv army:", countries[i], " ") print() diff --git a/examples/python/set_covering_skiena.py b/examples/python/set_covering_skiena.py index 3c6f483e4f..1e5d8e9ba8 100644 --- a/examples/python/set_covering_skiena.py +++ b/examples/python/set_covering_skiena.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set covering in Google CP Solver. @@ -86,10 +85,9 @@ def main(): solver.Add(s >= 1) # number of used elements - solver.Add(tot_elements == - solver.Sum([x[i] * belongs[i][j] - for i in range(num_sets) - for j in range(num_elements)])) + solver.Add(tot_elements == solver.Sum([ + x[i] * belongs[i][j] for i in range(num_sets) for j in range(num_elements) + ])) # objective objective = solver.Minimize(z, 1) @@ -97,9 +95,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db, [objective]) diff --git a/examples/python/set_partition.py b/examples/python/set_partition.py index 19d05b8869..2d291816e0 100644 --- a/examples/python/set_partition.py +++ b/examples/python/set_partition.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Set partition problem in Google CP Solver. @@ -107,21 +106,19 @@ def main(n=16, num_sets=2): for j in range(i, num_sets): # same cardinality - solver.Add(solver.Sum([a[i, k] for k in range(n)]) - == - solver.Sum([a[j, k] for k in range(n)])) + solver.Add( + solver.Sum([a[i, k] for k in range(n)]) == solver.Sum( + [a[j, k] for k in range(n)])) # same sum - solver.Add(solver.Sum([k * a[i, k] for k in range(n)]) - == - solver.Sum([k * a[j, k] for k in range(n)])) + solver.Add( + solver.Sum([k * a[i, k] for k in range(n)]) == solver.Sum( + [k * a[j, k] for k in range(n)])) # same sum squared - solver.Add(solver.Sum([(k * a[i, k]) * (k * a[i, k]) - for k in range(n)]) - == - solver.Sum([(k * a[j, k]) * (k * a[j, k]) - for k in range(n)])) + solver.Add( + solver.Sum([(k * a[i, k]) * (k * a[i, k]) for k in range(n)]) == + solver.Sum([(k * a[j, k]) * (k * a[j, k]) for k in range(n)])) # symmetry breaking for num_sets == 2 if num_sets == 2: @@ -130,9 +127,7 @@ def main(n=16, num_sets=2): # # search and result # - db = solver.Phase(a_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(a_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -145,15 +140,15 @@ def main(n=16, num_sets=2): sq = sum([(j + 1) * a_val[0, j] for j in range(n)]) print("sums:", sq) - sq2 = sum([((j + 1) * a_val[0, j]) ** 2 for j in range(n)]) + sq2 = sum([((j + 1) * a_val[0, j])**2 for j in range(n)]) print("sums squared:", sq2) for i in range(num_sets): if sum([a_val[i, j] for j in range(n)]): - print(i + 1, ":", end=' ') + print(i + 1, ":", end=" ") for j in range(n): if a_val[i, j] == 1: - print(j + 1, end=' ') + print(j + 1, end=" ") print() print() diff --git a/examples/python/sicherman_dice.py b/examples/python/sicherman_dice.py index 1cb6ec3974..cdef954b13 100644 --- a/examples/python/sicherman_dice.py +++ b/examples/python/sicherman_dice.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Sicherman Dice in Google CP Solver. @@ -111,9 +110,7 @@ def main(): solution.Add(x2) # db: DecisionBuilder - db = solver.Phase(x1 + x2, - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x1 + x2, solver.INT_VAR_SIMPLE, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -126,7 +123,8 @@ def main(): solver.EndSearch() print() - print("num_solutions:", num_solutions, "solver.solutions:", solver.Solutions()) + print("num_solutions:", num_solutions, "solver.solutions:", + solver.Solutions()) print("failures:", solver.Failures()) print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) diff --git a/examples/python/simple_meeting.py b/examples/python/simple_meeting.py index ebf89a1d91..5f6939a588 100644 --- a/examples/python/simple_meeting.py +++ b/examples/python/simple_meeting.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Simple meeting scheduler. In this model, we try to schedule a meeting. The meeting will occur @@ -45,21 +44,38 @@ def main(): # Lunch description. lunch_start_quarter = 14 # 11:30 AM - lunch_end_quarter = 25 # 2:30 PM - lunch_duration = 4 # 1 hour + lunch_end_quarter = 25 # 2:30 PM + lunch_duration = 4 # 1 hour # Predefined meetings. - existing_meetings = [{'start': 2, 'duration': 12, 'person': 1}, - {'start': 4, 'duration': 8, 'person': 4}] + existing_meetings = [{ + 'start': 2, + 'duration': 12, + 'person': 1 + }, { + 'start': 4, + 'duration': 8, + 'person': 4 + }] rooms_count = 5 all_rooms = list(range(1, rooms_count + 1)) room_sizes = {1: 7, 2: 8, 3: 10, 4: 3, 5: 8} - room_reservations = [{'start': 3, 'duration': 4, 'room': 1}, - {'start': 20, 'duration': 22, 'room': 3}, - {'start': 1, 'duration': 18, 'room': 2}] + room_reservations = [{ + 'start': 3, + 'duration': 4, + 'room': 1 + }, { + 'start': 20, + 'duration': 22, + 'room': 3 + }, { + 'start': 1, + 'duration': 18, + 'room': 2 + }] for t in existing_meetings: m = solver.FixedInterval(t['start'], t['duration'], 'existing meeting') @@ -72,30 +88,21 @@ def main(): # Meeting requirements, variables and copies. meeting_duration = 3 - meeting = solver.FixedDurationIntervalVar(1, - max_time, - meeting_duration, - False, - 'meeting') + meeting = solver.FixedDurationIntervalVar(1, max_time, meeting_duration, + False, 'meeting') people_meeting_copies = {} for p in all_people: name = 'people meeting copy %d' % p - people_meeting_copy = solver.FixedDurationIntervalVar(1, - max_time, - meeting_duration, - True, - name) + people_meeting_copy = solver.FixedDurationIntervalVar( + 1, max_time, meeting_duration, True, name) people_meeting_copies[p] = people_meeting_copy room_meeting_copies = {} for r in all_rooms: name = 'room meeting copy %d' % r - room_meeting_copy = solver.FixedDurationIntervalVar(1, - max_time, - meeting_duration, - True, - name) + room_meeting_copy = solver.FixedDurationIntervalVar( + 1, max_time, meeting_duration, True, name) room_meeting_copies[r] = room_meeting_copy meeting_location = solver.IntVar(list(all_rooms), 'meeting location') @@ -104,14 +111,12 @@ def main(): all_people_presence = {} for p in all_people: - lunch = solver.FixedDurationIntervalVar(lunch_start_quarter, - lunch_end_quarter - lunch_duration, - lunch_duration, - False, - 'lunch for %d' % p) + lunch = solver.FixedDurationIntervalVar( + lunch_start_quarter, lunch_end_quarter - lunch_duration, lunch_duration, + False, 'lunch for %d' % p) calendar = [people_meeting_copies[p], lunch] - calendar.extend([t['meeting'] - for t in existing_meetings if t['person'] == p]) + calendar.extend( + [t['meeting'] for t in existing_meetings if t['person'] == p]) disj = solver.DisjunctiveConstraint(calendar, 'people %d calendar' % p) all_people_calendars[p] = disj.SequenceVar() solver.Add(disj) @@ -123,8 +128,8 @@ def main(): all_rooms_presence = {} for r in all_rooms: calendar = [room_meeting_copies[r]] - calendar.extend([t['reservation'] - for t in room_reservations if t['room'] == r]) + calendar.extend( + [t['reservation'] for t in room_reservations if t['room'] == r]) disj = solver.DisjunctiveConstraint(calendar, 'room %d calendar' % r) all_rooms_calendars[r] = disj.SequenceVar() solver.Add(disj) @@ -136,8 +141,8 @@ def main(): # Constraints: # Maintains persons_count. - solver.Add(people_count == solver.Sum([all_people_presence[p] - for p in all_people])) + solver.Add( + people_count == solver.Sum([all_people_presence[p] for p in all_people])) # Mandatory persons. for p in all_mandatory_people: # pylint: disable=g-explicit-bool-comparison @@ -152,17 +157,16 @@ def main(): # Synchronize persons_presence and meetings. for p in all_people: - solver.Add(all_people_presence[p] == - people_meeting_copies[p].PerformedExpr()) + solver.Add( + all_people_presence[p] == people_meeting_copies[p].PerformedExpr()) # Synchronize all_presences and meetings. for r in all_rooms: - solver.Add(all_rooms_presence[r] == - room_meeting_copies[r].PerformedExpr()) + solver.Add(all_rooms_presence[r] == room_meeting_copies[r].PerformedExpr()) # Map meeting_location to room_meeting presence. - solver.Add((meeting_location - 1).MapTo([all_rooms_presence[p] - for p in all_rooms])) + solver.Add( + (meeting_location - 1).MapTo([all_rooms_presence[p] for p in all_rooms])) # Persons must fit in the room. sizes = [room_sizes[r] for r in all_rooms] solver.Add(people_count <= (meeting_location - 1).IndexOf(sizes)) @@ -175,8 +179,7 @@ def main(): # Build decision builder. # Chosse the location. vars_phase = solver.Phase([meeting_location, people_count], - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_SIMPLE) + solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) # Solve people calendars conflicts. sequence_phase = solver.Phase(all_calendars, solver.SEQUENCE_DEFAULT) @@ -200,9 +203,8 @@ def main(): if collector.SolutionCount() > 0: print('we could schedule %d persons in room %d starting at quarter %d' % - (collector.Value(0, people_count), - collector.Value(0, meeting_location), - collector.StartValue(0, meeting))) + (collector.Value(0, people_count), collector.Value( + 0, meeting_location), collector.StartValue(0, meeting))) if __name__ == '__main__': diff --git a/examples/python/ski_assignment.py b/examples/python/ski_assignment.py index 63899ead9a..4240f34170 100644 --- a/examples/python/ski_assignment.py +++ b/examples/python/ski_assignment.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Ski assignment in Google CP Solver. @@ -72,8 +71,7 @@ def main(): # # which ski to choose for each skier - x = [solver.IntVar(0, num_skis - 1, 'x[%i]' % i) - for i in range(num_skiers)] + x = [solver.IntVar(0, num_skis - 1, 'x[%i]' % i) for i in range(num_skiers)] z = solver.IntVar(0, sum(ski_heights), 'z') # @@ -81,8 +79,10 @@ def main(): # solver.Add(solver.AllDifferent(x)) - z_tmp = [abs(solver.Element(ski_heights, x[i]) - skier_heights[i]) - for i in range(num_skiers)] + z_tmp = [ + abs(solver.Element(ski_heights, x[i]) - skier_heights[i]) + for i in range(num_skiers) + ] solver.Add(z == sum(z_tmp)) # objective @@ -91,9 +91,7 @@ def main(): # # search and result # - db = solver.Phase(x, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db, [objective]) diff --git a/examples/python/slitherlink.py b/examples/python/slitherlink.py index bfb7461b18..bbce75214e 100644 --- a/examples/python/slitherlink.py +++ b/examples/python/slitherlink.py @@ -1,32 +1,23 @@ from ortools.constraint_solver import pywrapcp from collections import deque +small = [[3, 2, -1, 3], [-1, -1, -1, 2], [3, -1, -1, -1], [3, -1, 3, 1]] -small = [[3, 2, -1, 3], - [-1, -1, -1, 2], - [3, -1, -1, -1], - [3, -1, 3, 1]] - -medium = [[ -1, 0, -1, 1, -1, -1, 1, -1 ], - [ -1, 3, -1, -1, 2, 3, -1, 2 ], - [ -1, -1, 0, -1, -1, -1, -1, 0 ], - [ -1, 3, -1, -1, 0, -1, -1, -1 ], - [ -1, -1, -1, 3, -1, -1, 0, -1 ], - [ 1, -1, -1, -1, -1, 3, -1, -1 ], - [ 3, -1, 1, 3, -1, -1, 3, -1 ], - [ -1, 0, -1, -1, 3, -1, 3, -1 ]] - -big = [[ 3, -1, -1, -1, 2, -1, 1, -1, 1, 2 ], - [ 1, -1, 0, -1, 3, -1, 2, 0, -1, -1 ], - [ -1, 3, -1, -1, -1, -1, -1, -1, 3, -1 ], - [ 2, 0, -1, 3, -1, 2, 3, -1, -1, -1 ], - [ -1, -1, -1, 1, 1, 1, -1, -1, 3, 3 ], - [ 2, 3, -1, -1, 2, 2, 3, -1, -1, -1 ], - [ -1, -1, -1, 1, 2, -1, 2, -1, 3, 3 ], - [ -1, 2, -1, -1, -1, -1, -1, -1, 2, -1 ], - [ -1, -1, 1, 1, -1, 2, -1, 1, -1, 3 ], - [ 3, 3, -1, 1, -1, 2, -1, -1, -1, 2 ]] +medium = [[-1, 0, -1, 1, -1, -1, 1, -1], [-1, 3, -1, -1, 2, 3, -1, 2], + [-1, -1, 0, -1, -1, -1, -1, 0], [-1, 3, -1, -1, 0, -1, -1, + -1], [-1, -1, -1, 3, -1, -1, 0, -1], + [1, -1, -1, -1, -1, 3, -1, -1], [3, -1, 1, 3, -1, -1, 3, + -1], [-1, 0, -1, -1, 3, -1, 3, -1]] +big = [[3, -1, -1, -1, 2, -1, 1, -1, 1, 2], [1, -1, 0, -1, 3, -1, 2, 0, -1, -1], + [-1, 3, -1, -1, -1, -1, -1, -1, 3, + -1], [2, 0, -1, 3, -1, 2, 3, -1, -1, + -1], [-1, -1, -1, 1, 1, 1, -1, -1, 3, 3], + [2, 3, -1, -1, 2, 2, 3, -1, -1, + -1], [-1, -1, -1, 1, 2, -1, 2, -1, + 3, 3], [-1, 2, -1, -1, -1, -1, -1, -1, + 2, -1], [-1, -1, 1, 1, -1, 2, -1, 1, + -1, 3], [3, 3, -1, 1, -1, 2, -1, -1, -1, 2]] def NeighboringArcs(i, j, h_arcs, v_arcs): @@ -157,7 +148,6 @@ class GridSinglePath(pywrapcp.PyConstraint): for var in column: var.WhenBound(demon) - # This constraint implements a single propagation. # If one point is on the path, it checks the reachability of all possible # nodes, and zero out the unreachable parts. @@ -230,13 +220,13 @@ def SlitherLink(data): num_columns = len(data[0]) solver = pywrapcp.Solver('slitherlink') - h_arcs = [[solver.BoolVar('h_arcs[%i][%i]' % (i, j)) - for j in range(num_columns)] - for i in range(num_rows + 1)] + h_arcs = [[ + solver.BoolVar('h_arcs[%i][%i]' % (i, j)) for j in range(num_columns) + ] for i in range(num_rows + 1)] - v_arcs = [[solver.BoolVar('v_arcs[%i][%i]' % (i, j)) - for j in range(num_rows)] - for i in range(num_columns + 1)] + v_arcs = [[ + solver.BoolVar('v_arcs[%i][%i]' % (i, j)) for j in range(num_rows) + ] for i in range(num_columns + 1)] # Constraint on the sum or arcs for i in range(num_rows): @@ -285,8 +275,7 @@ def SlitherLink(data): for column in v_arcs: all_vars.extend(column) - db = solver.Phase(all_vars, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(all_vars, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MAX_VALUE) log = solver.SearchLog(1000000) diff --git a/examples/python/stable_marriage.py b/examples/python/stable_marriage.py index 1742287123..c3dfc5c728 100644 --- a/examples/python/stable_marriage.py +++ b/examples/python/stable_marriage.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Stable marriage problem in Google CP Solver. @@ -109,8 +108,7 @@ def main(ranks, problem_name): solution.Add(wife) solution.Add(husband) - db = solver.Phase(wife + husband, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(wife + husband, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -138,21 +136,10 @@ def main(ranks, problem_name): # From Van Hentenryck's OPL book # van_hentenryck = { - "rankWomen": [ - [1, 2, 4, 3, 5], - [3, 5, 1, 2, 4], - [5, 4, 2, 1, 3], - [1, 3, 5, 4, 2], - [4, 2, 3, 5, 1] - ], - - "rankMen": [ - [5, 1, 2, 4, 3], - [4, 1, 3, 2, 5], - [5, 3, 2, 4, 1], - [1, 5, 4, 3, 2], - [4, 3, 2, 1, 5] - ] + "rankWomen": [[1, 2, 4, 3, 5], [3, 5, 1, 2, 4], [5, 4, 2, 1, 3], + [1, 3, 5, 4, 2], [4, 2, 3, 5, 1]], + "rankMen": [[5, 1, 2, 4, 3], [4, 1, 3, 2, 5], [5, 3, 2, 4, 1], + [1, 5, 4, 3, 2], [4, 3, 2, 1, 5]] } # @@ -160,27 +147,17 @@ van_hentenryck = { # http://mathworld.wolfram.com/StableMarriageProblem.html # mathworld = { - "rankWomen": [ - [3, 1, 5, 2, 8, 7, 6, 9, 4], - [9, 4, 8, 1, 7, 6, 3, 2, 5], - [3, 1, 8, 9, 5, 4, 2, 6, 7], - [8, 7, 5, 3, 2, 6, 4, 9, 1], - [6, 9, 2, 5, 1, 4, 7, 3, 8], - [2, 4, 5, 1, 6, 8, 3, 9, 7], - [9, 3, 8, 2, 7, 5, 4, 6, 1], - [6, 3, 2, 1, 8, 4, 5, 9, 7], - [8, 2, 6, 4, 9, 1, 3, 7, 5]], - - "rankMen": [ - [7, 3, 8, 9, 6, 4, 2, 1, 5], - [5, 4, 8, 3, 1, 2, 6, 7, 9], - [4, 8, 3, 9, 7, 5, 6, 1, 2], - [9, 7, 4, 2, 5, 8, 3, 1, 6], - [2, 6, 4, 9, 8, 7, 5, 1, 3], - [2, 7, 8, 6, 5, 3, 4, 1, 9], - [1, 6, 2, 3, 8, 5, 4, 9, 7], - [5, 6, 9, 1, 2, 8, 4, 3, 7], - [6, 1, 4, 7, 5, 8, 3, 9, 2]] + "rankWomen": [[3, 1, 5, 2, 8, 7, 6, 9, 4], [9, 4, 8, 1, 7, 6, 3, 2, 5], + [3, 1, 8, 9, 5, 4, 2, 6, 7], [8, 7, 5, 3, 2, 6, 4, 9, 1], [ + 6, 9, 2, 5, 1, 4, 7, 3, 8 + ], [2, 4, 5, 1, 6, 8, 3, 9, 7], [9, 3, 8, 2, 7, 5, 4, 6, 1], + [6, 3, 2, 1, 8, 4, 5, 9, 7], [8, 2, 6, 4, 9, 1, 3, 7, 5]], + "rankMen": [[7, 3, 8, 9, 6, 4, 2, 1, 5], [5, 4, 8, 3, 1, 2, 6, 7, + 9], [4, 8, 3, 9, 7, 5, 6, 1, 2], + [9, 7, 4, 2, 5, 8, 3, 1, 6], [2, 6, 4, 9, 8, 7, 5, 1, + 3], [2, 7, 8, 6, 5, 3, 4, 1, 9], + [1, 6, 2, 3, 8, 5, 4, 9, 7], [5, 6, 9, 1, 2, 8, 4, 3, + 7], [6, 1, 4, 7, 5, 8, 3, 9, 2]] } # @@ -188,44 +165,22 @@ mathworld = { # http://www.csee.wvu.edu/~ksmani/courses/fa01/random/lecnotes/lecture5.pdf # problem3 = { - "rankWomen": [ - [1, 2, 3, 4], - [4, 3, 2, 1], - [1, 2, 3, 4], - [3, 4, 1, 2]], - - "rankMen": [ - [1, 2, 3, 4], - [2, 1, 3, 4], - [1, 4, 3, 2], - [4, 3, 1, 2]] + "rankWomen": [[1, 2, 3, 4], [4, 3, 2, 1], [1, 2, 3, 4], [3, 4, 1, 2]], + "rankMen": [[1, 2, 3, 4], [2, 1, 3, 4], [1, 4, 3, 2], [4, 3, 1, 2]] } - # # Data from # http://www.comp.rgu.ac.uk/staff/ha/ZCSP/additional_problems/stable_marriage/stable_marriage.pdf # page 4 # problem4 = { - "rankWomen": [ - [1, 5, 4, 6, 2, 3], - [4, 1, 5, 2, 6, 3], - [6, 4, 2, 1, 5, 3], - [1, 5, 2, 4, 3, 6], - [4, 2, 1, 5, 6, 3], - [2, 6, 3, 5, 1, 4]], - - "rankMen": [ - [1, 4, 2, 5, 6, 3], - [3, 4, 6, 1, 5, 2], - [1, 6, 4, 2, 3, 5], - [6, 5, 3, 4, 2, 1], - [3, 1, 2, 4, 5, 6], - [2, 3, 1, 6, 5, 4]] + "rankWomen": [[1, 5, 4, 6, 2, 3], [4, 1, 5, 2, 6, 3], [6, 4, 2, 1, 5, 3], + [1, 5, 2, 4, 3, 6], [4, 2, 1, 5, 6, 3], [2, 6, 3, 5, 1, 4]], + "rankMen": [[1, 4, 2, 5, 6, 3], [3, 4, 6, 1, 5, 2], [1, 6, 4, 2, 3, 5], + [6, 5, 3, 4, 2, 1], [3, 1, 2, 4, 5, 6], [2, 3, 1, 6, 5, 4]] } - if __name__ == "__main__": main(van_hentenryck, "Van Hentenryck") main(mathworld, "MathWorld") diff --git a/examples/python/steel.py b/examples/python/steel.py index f258701fe9..ce65101364 100644 --- a/examples/python/steel.py +++ b/examples/python/steel.py @@ -17,24 +17,27 @@ import argparse from ortools.constraint_solver import pywrapcp parser = argparse.ArgumentParser() -parser.add_argument('--data', default = 'examples/data/steel_mill/steel_mill_slab.txt', - help = 'path to data file') -parser.add_argument('--time_limit', default = 20000, type = int, - help = 'global time limit') +parser.add_argument( + '--data', + default='examples/data/steel_mill/steel_mill_slab.txt', + help='path to data file') +parser.add_argument( + '--time_limit', default=20000, type=int, help='global time limit') #----------------helper for binpacking posting---------------- def BinPacking(solver, binvars, weights, loadvars): - '''post the load constraint on bins. + """post the load constraint on bins. constraints forall j: loadvars[j] == sum_i (binvars[i] == j) * weights[i]) - ''' + """ pack = solver.Pack(binvars, len(binvars)) pack.AddWeightedSumEqualVarDimension(weights, loadvars) solver.Add(pack) solver.Add(solver.SumEquality(loadvars, sum(weights))) + #------------------------------data reading------------------- @@ -50,18 +53,22 @@ def ReadData(filename): wc = [[int(j) for j in f.readline().split()] for i in range(nb_slabs)] weights = [x[0] for x in wc] colors = [x[1] for x in wc] - loss = [min([x for x in capacity if x >= c]) - c - for c in range(max_capacity + 1)] - color_orders = [[o for o in range(nb_slabs) if colors[o] == c] + loss = [ + min([x for x in capacity if x >= c]) - c for c in range(max_capacity + 1) + ] + color_orders = [[o + for o in range(nb_slabs) + if colors[o] == c] for c in range(1, nb_colors + 1)] print('Solving steel mill with', nb_slabs, 'slabs') return (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) + #------------------dedicated search for this problem----------- class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): - '''Dedicated Decision Builder for steel mill slab. + """Dedicated Decision Builder for steel mill slab. Search for the steel mill slab problem with Dynamic Symmetry Breaking during search is an adaptation (for binary tree) from the @@ -71,7 +78,7 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): Solving Steel Mill Slab Problems with Constraint-Based Techniques: CP, LNS, and CBLS, Schaus et. al. to appear in Constraints 2010 - ''' + """ def __init__(self, x, nb_slabs, weights, losstab, loads): pywrapcp.PyDecisionBuilder.__init__(self) @@ -97,7 +104,8 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): # the least increase of the loss loads = self.getLoads() l, v = min((self.__losstab[loads[i] + weight], i) - for i in range(var.Min(), var.Max() + 1) + for i in range(var.Min(), + var.Max() + 1) if var.Contains(i) and loads[i] + weight <= self.__maxcapa) decision = solver.AssignVariableValue(var, v) return decision @@ -113,9 +121,11 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): def MaxBound(self): """ returns the max value bound to a variable, -1 if no variables bound""" - return max([-1] + [self.__x[o].Min() - for o in range(self.__nb_slabs) - if self.__x[o].Bound()]) + return max([-1] + [ + self.__x[o].Min() + for o in range(self.__nb_slabs) + if self.__x[o].Bound() + ]) def NextVar(self): """ mindom size heuristic with tie break on the weights of orders """ @@ -138,10 +148,11 @@ def main(args): ReadData(args.data) nb_colors = len(color_orders) solver = pywrapcp.Solver('Steel Mill Slab') - x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) - for i in range(nb_slabs)] - load_vars = [solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i)) - for i in range(nb_slabs)] + x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)] + load_vars = [ + solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i)) + for i in range(nb_slabs) + ] #-------------------post of the constraints-------------- @@ -149,9 +160,12 @@ def main(args): BinPacking(solver, x, weights, load_vars) # At most two colors per slab. for s in range(nb_slabs): - solver.Add(solver.SumLessOrEqual( - [solver.Max([solver.IsEqualCstVar(x[c], s) for c in o]) - for o in color_orders], 2)) + solver.Add( + solver.SumLessOrEqual([ + solver.Max([solver.IsEqualCstVar(x[c], s) + for c in o]) + for o in color_orders + ], 2)) #----------------Objective------------------------------- diff --git a/examples/python/steel_lns.py b/examples/python/steel_lns.py index 3e58181be2..0806142330 100644 --- a/examples/python/steel_lns.py +++ b/examples/python/steel_lns.py @@ -18,31 +18,42 @@ import random parser = argparse.ArgumentParser() -parser.add_argument('--data', default = 'examples/data/steel_mill/steel_mill_slab.txt', - help = 'path to data file') -parser.add_argument('--time_limit', default = 20000, type = int, - help = 'global time limit') -parser.add_argument('--lns_fragment_size', default = 10, type = int, - help = 'size of the random lns fragment') -parser.add_argument('--lns_random_seed', default = 0, type = int, - help = 'seed for the lns random generator') -parser.add_argument('--lns_fail_limit', default = 30, type = int, - help = 'fail limit when exploring fragments') - +parser.add_argument( + '--data', + default='examples/data/steel_mill/steel_mill_slab.txt', + help='path to data file') +parser.add_argument( + '--time_limit', default=20000, type=int, help='global time limit') +parser.add_argument( + '--lns_fragment_size', + default=10, + type=int, + help='size of the random lns fragment') +parser.add_argument( + '--lns_random_seed', + default=0, + type=int, + help='seed for the lns random generator') +parser.add_argument( + '--lns_fail_limit', + default=30, + type=int, + help='fail limit when exploring fragments') # ---------- helper for binpacking posting ---------- def BinPacking(solver, binvars, weights, loadvars): - '''post the load constraint on bins. + """post the load constraint on bins. constraints forall j: loadvars[j] == sum_i (binvars[i] == j) * weights[i]) - ''' + """ pack = solver.Pack(binvars, len(binvars)) pack.AddWeightedSumEqualVarDimension(weights, loadvars) solver.Add(pack) solver.Add(solver.SumEquality(loadvars, sum(weights))) + # ---------- data reading ---------- @@ -58,17 +69,22 @@ def ReadData(filename): wc = [[int(j) for j in f.readline().split()] for i in range(nb_slabs)] weights = [x[0] for x in wc] colors = [x[1] for x in wc] - loss = [min([x for x in capacity if x >= c]) - c - for c in range(max_capacity + 1)] - color_orders = [[o for o in range(nb_slabs) if colors[o] == c] + loss = [ + min([x for x in capacity if x >= c]) - c for c in range(max_capacity + 1) + ] + color_orders = [[o + for o in range(nb_slabs) + if colors[o] == c] for c in range(1, nb_colors + 1)] print('Solving steel mill with', nb_slabs, 'slabs') return (nb_slabs, capacity, max_capacity, weights, colors, loss, color_orders) + # ---------- dedicated search for this problem ---------- + class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): - '''Dedicated Decision Builder for steel mill slab. + """Dedicated Decision Builder for steel mill slab. Search for the steel mill slab problem with Dynamic Symmetry Breaking during search is an adaptation (for binary tree) from the @@ -78,7 +94,7 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): Solving Steel Mill Slab Problems with Constraint-Based Techniques: CP, LNS, and CBLS, Schaus et. al. to appear in Constraints 2010 - ''' + """ def __init__(self, x, nb_slabs, weights, loss_array, loads): pywrapcp.PyDecisionBuilder.__init__(self) @@ -103,10 +119,11 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): # try first to place the order in the slab that will induce # the least increase of the loss loads = self.getLoads() - l, v = min((self.__loss_array[loads[i] + weight], i) - for i in range(var.Min(), var.Max() + 1) - if var.Contains(i) and - loads[i] + weight <= self.__max_capacity) + l, v = min( + (self.__loss_array[loads[i] + weight], i) + for i in range(var.Min(), + var.Max() + 1) + if var.Contains(i) and loads[i] + weight <= self.__max_capacity) decision = solver.AssignVariableValue(var, v) return decision else: @@ -121,9 +138,11 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): def MaxBound(self): """ returns the max value bound to a variable, -1 if no variables bound""" - return max([-1] + [self.__x[o].Min() - for o in range(self.__nb_slabs) - if self.__x[o].Bound()]) + return max([-1] + [ + self.__x[o].Min() + for o in range(self.__nb_slabs) + if self.__x[o].Bound() + ]) def NextVar(self): """ mindom size heuristic with tie break on the weights of orders """ @@ -139,6 +158,7 @@ class SteelDecisionBuilder(pywrapcp.PyDecisionBuilder): def DebugString(self): return 'SteelMillDecisionBuilder(' + str(self.__x) + ')' + # ----------- LNS Operator ---------- @@ -159,6 +179,7 @@ class SteelRandomLns(pywrapcp.BaseLns): self.AppendToFragment(pos) return True + # ----------- Main Function ----------- @@ -168,10 +189,11 @@ def main(args): ReadData(args.data) nb_colors = len(color_orders) solver = pywrapcp.Solver('Steel Mill Slab') - x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) - for i in range(nb_slabs)] - load_vars = [solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i)) - for i in range(nb_slabs)] + x = [solver.IntVar(0, nb_slabs - 1, 'x' + str(i)) for i in range(nb_slabs)] + load_vars = [ + solver.IntVar(0, max_capacity - 1, 'load_vars' + str(i)) + for i in range(nb_slabs) + ] # ----- post of the constraints ----- @@ -179,9 +201,12 @@ def main(args): BinPacking(solver, x, weights, load_vars) # At most two colors per slab. for s in range(nb_slabs): - solver.Add(solver.SumLessOrEqual( - [solver.Max([solver.IsEqualCstVar(x[c], s) for c in o]) - for o in color_orders], 2)) + solver.Add( + solver.SumLessOrEqual([ + solver.Max([solver.IsEqualCstVar(x[c], s) + for c in o]) + for o in color_orders + ], 2)) # ----- Objective ----- @@ -203,9 +228,7 @@ def main(args): # To search a fragment, we use a basic randomized decision builder. # We can also use assign_db instead of inner_db. - inner_db = solver.Phase(x, - solver.CHOOSE_RANDOM, - solver.ASSIGN_MIN_VALUE) + inner_db = solver.Phase(x, solver.CHOOSE_RANDOM, solver.ASSIGN_MIN_VALUE) # The most important aspect is to limit the time exploring each fragment. inner_limit = solver.FailuresLimit(args.lns_fail_limit) continuation_db = solver.SolveOnce(inner_db, [inner_limit]) diff --git a/examples/python/steel_mill_slab_sat.py b/examples/python/steel_mill_slab_sat.py index 4365535700..3c9f40adb7 100644 --- a/examples/python/steel_mill_slab_sat.py +++ b/examples/python/steel_mill_slab_sat.py @@ -20,16 +20,21 @@ import time parser = argparse.ArgumentParser() -parser.add_argument('--problem', default = 2, type = int, - help = 'Problem id to solve.') -parser.add_argument('--break_symmetries', default = True, type = bool, - help = 'Break symmetries between equivalent orders.') parser.add_argument( - '--solver', default = "mip_column", - help = 'Method used to solve: sat, sat_table, sat_column, mip_column.') -parser.add_argument('--output_proto', default = "", - help = 'Output file to write the cp_model proto to.') - + '--problem', default=2, type=int, help='Problem id to solve.') +parser.add_argument( + '--break_symmetries', + default=True, + type=bool, + help='Break symmetries between equivalent orders.') +parser.add_argument( + '--solver', + default='mip_column', + help='Method used to solve: sat, sat_table, sat_column, mip_column.') +parser.add_argument( + '--output_proto', + default='', + help='Output file to write the cp_model proto to.') def BuildProblem(problem_id): @@ -271,16 +276,16 @@ class SteelMillSlabSolutionPrinter(cp_model.CpSolverSolutionCallback): print('Solution %i, time = %f s, objective = %i' % (self.__solution_count, current_time - self.__start_time, objective)) self.__solution_count += 1 - orders_in_slab = [[o for o in self.__all_orders - if self.Value(self.__assign[o][s])] - for s in self.__all_slabs] + orders_in_slab = [[ + o for o in self.__all_orders if self.Value(self.__assign[o][s]) + ] for s in self.__all_slabs] for s in self.__all_slabs: if orders_in_slab[s]: line = ' - slab %i, load = %i, loss = %i, orders = [' % ( s, self.Value(self.__load[s]), self.Value(self.__loss[s])) for o in orders_in_slab[s]: - line += '#%i(w%i, c%i) ' % ( - o, self.__orders[o][0], self.__orders[o][1]) + line += '#%i(w%i, c%i) ' % (o, self.__orders[o][0], + self.__orders[o][1]) line += ']' print(line) @@ -321,8 +326,9 @@ def SteelMillSlab(problem, break_symmetries, output_proto): min(x for x in capacities if x >= c) - c for c in range(max_capacity + 1) ] max_loss = max(loss_array) - orders_per_color = [[o for o in all_orders if colors[o] == c + 1] - for c in all_colors] + orders_per_color = [ + [o for o in all_orders if colors[o] == c + 1] for c in all_colors + ] unique_color_orders = [ o for o in all_orders if len(orders_per_color[colors[o] - 1]) == 1 ] @@ -457,8 +463,9 @@ def CollectValidSlabs(capacities, colors, widths, loss_array, all_colors): """Collect valid columns (assign, loss) for one slab.""" all_orders = range(len(colors)) max_capacity = max(capacities) - orders_per_color = [[o for o in all_orders if colors[o] == c + 1] - for c in all_colors] + orders_per_color = [ + [o for o in all_orders if colors[o] == c + 1] for c in all_colors + ] model = cp_model.CpModel() assign = [model.NewBoolVar('assign_%i' % o) for o in all_orders] @@ -534,15 +541,13 @@ def SteelMillSlabWithValidSlabs(problem, break_symmetries, output_proto): unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths, loss_array, all_colors) # Sort slab by descending load/loss. Remove duplicates. - valid_slabs = sorted(unsorted_valid_slabs, - key = lambda c : 1000 * c[-1] + c[-2]) + valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2]) num_valid_slabs = len(valid_slabs) print(' - %i valid slab combinations' % num_valid_slabs) for s in all_slabs: model.AddAllowedAssignments( - [assign[o][s] for o in all_orders] + [losses[s], loads[s]], - valid_slabs) + [assign[o][s] for o in all_orders] + [losses[s], loads[s]], valid_slabs) # Orders are assigned to one slab. for o in all_orders: @@ -560,8 +565,9 @@ def SteelMillSlabWithValidSlabs(problem, break_symmetries, output_proto): print('Breaking symmetries') width_to_unique_color_order = {} ordered_equivalent_orders = [] - orders_per_color = [[o for o in all_orders if colors[o] == c + 1] - for c in all_colors] + orders_per_color = [ + [o for o in all_orders if colors[o] == c + 1] for c in all_colors + ] for c in all_colors: colored_orders = orders_per_color[c] if not colored_orders: @@ -659,8 +665,7 @@ def SteelMillSlabWithColumnGeneration(problem, output_proto): unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths, loss_array, all_colors) # Sort slab by descending load/loss. Remove duplicates. - valid_slabs = sorted(unsorted_valid_slabs, - key = lambda c : 1000 * c[-1] + c[-2]) + valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2]) num_valid_slabs = len(valid_slabs) all_valid_slabs = range(num_valid_slabs) print(' - %i valid slab combinations' % num_valid_slabs) @@ -670,19 +675,19 @@ def SteelMillSlabWithColumnGeneration(problem, output_proto): selected = [model.NewBoolVar('selected_%i' % i) for i in all_valid_slabs] for o in all_orders: - model.Add(sum(selected[i] for i in all_valid_slabs - if valid_slabs[i][o]) == 1) - + model.Add( + sum(selected[i] for i in all_valid_slabs if valid_slabs[i][o]) == 1) # Redundant constraint (sum of loads == sum of widths). - model.Add(sum(selected[i] * valid_slabs[i][-1] for i in all_valid_slabs) == - sum(widths)) + model.Add( + sum(selected[i] * valid_slabs[i][-1] + for i in all_valid_slabs) == sum(widths)) # Objective. max_loss = max(valid_slabs[i][-2] for i in all_valid_slabs) obj = model.NewIntVar(0, num_slabs * max_loss, 'obj') - model.Add(obj == sum(selected[i] * valid_slabs[i][-2] - for i in all_valid_slabs)) + model.Add(obj == sum( + selected[i] * valid_slabs[i][-2] for i in all_valid_slabs)) model.Minimize(obj) print('Model created') @@ -734,39 +739,38 @@ def SteelMillSlabWithMipColumnGeneration(problem): unsorted_valid_slabs = CollectValidSlabs(capacities, colors, widths, loss_array, all_colors) # Sort slab by descending load/loss. Remove duplicates. - valid_slabs = sorted(unsorted_valid_slabs, - key = lambda c : 1000 * c[-1] + c[-2]) + valid_slabs = sorted(unsorted_valid_slabs, key=lambda c: 1000 * c[-1] + c[-2]) num_valid_slabs = len(valid_slabs) all_valid_slabs = range(num_valid_slabs) generate = time.time() - print(' - %i valid slab combinations generated in %f s' % ( - num_valid_slabs, generate - start)) + print(' - %i valid slab combinations generated in %f s' % (num_valid_slabs, + generate - start)) # create model and decision variables. - solver = pywraplp.Solver('Steel', - pywraplp.Solver.BOP_INTEGER_PROGRAMMING) - selected = [solver.IntVar(0.0, 1.0, 'selected_%i' % i) - for i in all_valid_slabs] + solver = pywraplp.Solver('Steel', pywraplp.Solver.BOP_INTEGER_PROGRAMMING) + selected = [ + solver.IntVar(0.0, 1.0, 'selected_%i' % i) for i in all_valid_slabs + ] for o in all_orders: - solver.Add(sum(selected[i] for i in all_valid_slabs - if valid_slabs[i][o]) == 1) - + solver.Add( + sum(selected[i] for i in all_valid_slabs if valid_slabs[i][o]) == 1) # Redundant constraint (sum of loads == sum of widths). - solver.Add(sum(selected[i] * valid_slabs[i][-1] for i in all_valid_slabs) == - sum(widths)) + solver.Add( + sum(selected[i] * valid_slabs[i][-1] + for i in all_valid_slabs) == sum(widths)) # Objective. - solver.Minimize(sum(selected[i] * valid_slabs[i][-2] - for i in all_valid_slabs)) + solver.Minimize( + sum(selected[i] * valid_slabs[i][-2] for i in all_valid_slabs)) status = solver.Solve() ### Output the solution. if status == pywraplp.Solver.OPTIMAL: - print('Objective value = %f found in %f s' % ( - solver.Objective().Value(), time.time() - generate)) + print('Objective value = %f found in %f s' % (solver.Objective().Value(), + time.time() - generate)) else: print('No solution') diff --git a/examples/python/stigler.py b/examples/python/stigler.py index a29a4adb70..fc01abe592 100644 --- a/examples/python/stigler.py +++ b/examples/python/stigler.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Original Stigler's 1939 diet problem Google or-tools. @@ -153,176 +152,148 @@ def main(sol="CBC"): N = list(range(num_nutrients)) nutrients = [ - "calories", # Calories, unit = 1000 - "protein", # Protein, unit = grams - "calcium", # Calcium, unit = grams - "iron", # Iron, unit = milligrams - "vitaminA", # Vitamin A, unit = 1000 International Units - "thiamine", # Thiamine, Vit. B1, unit = milligrams - "riboflavin", # Riboflavin, Vit. B2, unit = milligrams - "niacin", # Niacin (Nicotinic Acid), unit = milligrams - "ascorbicAcid" # Ascorbic Acid, Vit. C, unit = milligrams + "calories", # Calories, unit = 1000 + "protein", # Protein, unit = grams + "calcium", # Calcium, unit = grams + "iron", # Iron, unit = milligrams + "vitaminA", # Vitamin A, unit = 1000 International Units + "thiamine", # Thiamine, Vit. B1, unit = milligrams + "riboflavin", # Riboflavin, Vit. B2, unit = milligrams + "niacin", # Niacin (Nicotinic Acid), unit = milligrams + "ascorbicAcid" # Ascorbic Acid, Vit. C, unit = milligrams ] - commodities = [ - ["Wheat Flour (Enriched)", "10 lb."], - ["Macaroni", "1 lb."], - ["Wheat Cereal (Enriched)", "28 oz."], - ["Corn Flakes", "8 oz."], - ["Corn Meal", "1 lb."], - ["Hominy Grits", "24 oz."], - ["Rice", "1 lb."], - ["Rolled Oats", "1 lb."], - ["White Bread (Enriched)", "1 lb."], - ["Whole Wheat Bread", "1 lb."], - ["Rye Bread", "1 lb."], - ["Pound Cake", "1 lb."], - ["Soda Crackers", "1 lb."], - ["Milk", "1 qt."], - ["Evaporated Milk (can)", "14.5 oz."], - ["Butter", "1 lb."], - ["Oleomargarine", "1 lb."], - ["Eggs", "1 doz."], - ["Cheese (Cheddar)", "1 lb."], - ["Cream", "1/2 pt."], - ["Peanut Butter", "1 lb."], - ["Mayonnaise", "1/2 pt."], - ["Crisco", "1 lb."], - ["Lard", "1 lb."], - ["Sirloin Steak", "1 lb."], - ["Round Steak", "1 lb."], - ["Rib Roast", "1 lb."], - ["Chuck Roast", "1 lb."], - ["Plate", "1 lb."], - ["Liver (Beef)", "1 lb."], - ["Leg of Lamb", "1 lb."], - ["Lamb Chops (Rib)", "1 lb."], - ["Pork Chops", "1 lb."], - ["Pork Loin Roast", "1 lb."], - ["Bacon", "1 lb."], - ["Ham - smoked", "1 lb."], - ["Salt Pork", "1 lb."], - ["Roasting Chicken", "1 lb."], - ["Veal Cutlets", "1 lb."], - ["Salmon, Pink (can)", "16 oz."], - ["Apples", "1 lb."], - ["Bananas", "1 lb."], - ["Lemons", "1 doz."], - ["Oranges", "1 doz."], - ["Green Beans", "1 lb."], - ["Cabbage", "1 lb."], - ["Carrots", "1 bunch"], - ["Celery", "1 stalk"], - ["Lettuce", "1 head"], - ["Onions", "1 lb."], - ["Potatoes", "15 lb."], - ["Spinach", "1 lb."], - ["Sweet Potatoes", "1 lb."], - ["Peaches (can)", "No. 2 1/2"], - ["Pears (can)", "No. 2 1/2,"], - ["Pineapple (can)", "No. 2 1/2"], - ["Asparagus (can)", "No. 2"], - ["Grean Beans (can)", "No. 2"], - ["Pork and Beans (can)", "16 oz."], - ["Corn (can)", "No. 2"], - ["Peas (can)", "No. 2"], - ["Tomatoes (can)", "No. 2"], - ["Tomato Soup (can)", "10 1/2 oz."], - ["Peaches, Dried", "1 lb."], - ["Prunes, Dried", "1 lb."], - ["Raisins, Dried", "15 oz."], - ["Peas, Dried", "1 lb."], - ["Lima Beans, Dried", "1 lb."], - ["Navy Beans, Dried", "1 lb."], - ["Coffee", "1 lb."], - ["Tea", "1/4 lb."], - ["Cocoa", "8 oz."], - ["Chocolate", "8 oz."], - ["Sugar", "10 lb."], - ["Corn Sirup", "24 oz."], - ["Molasses", "18 oz."], - ["Strawberry Preserve", "1 lb."] - ] + commodities = [["Wheat Flour (Enriched)", "10 lb."], ["Macaroni", "1 lb."], [ + "Wheat Cereal (Enriched)", "28 oz." + ], ["Corn Flakes", "8 oz."], ["Corn Meal", "1 lb."], [ + "Hominy Grits", "24 oz." + ], ["Rice", "1 lb."], ["Rolled Oats", "1 lb."], [ + "White Bread (Enriched)", "1 lb." + ], ["Whole Wheat Bread", "1 lb."], ["Rye Bread", "1 lb."], [ + "Pound Cake", "1 lb." + ], ["Soda Crackers", "1 lb."], ["Milk", "1 qt."], [ + "Evaporated Milk (can)", "14.5 oz." + ], ["Butter", "1 lb."], ["Oleomargarine", "1 lb."], ["Eggs", "1 doz."], [ + "Cheese (Cheddar)", "1 lb." + ], ["Cream", "1/2 pt."], ["Peanut Butter", "1 lb."], [ + "Mayonnaise", "1/2 pt." + ], ["Crisco", "1 lb."], ["Lard", "1 lb."], ["Sirloin Steak", "1 lb."], [ + "Round Steak", "1 lb." + ], ["Rib Roast", "1 lb."], ["Chuck Roast", "1 lb."], ["Plate", "1 lb."], [ + "Liver (Beef)", "1 lb." + ], ["Leg of Lamb", + "1 lb."], ["Lamb Chops (Rib)", "1 lb."], ["Pork Chops", "1 lb."], [ + "Pork Loin Roast", "1 lb." + ], ["Bacon", "1 lb."], ["Ham - smoked", "1 lb."], ["Salt Pork", "1 lb."], + ["Roasting Chicken", "1 lb."], ["Veal Cutlets", "1 lb."], [ + "Salmon, Pink (can)", "16 oz." + ], ["Apples", "1 lb."], ["Bananas", "1 lb."], [ + "Lemons", "1 doz." + ], ["Oranges", "1 doz."], ["Green Beans", "1 lb."], + ["Cabbage", "1 lb."], ["Carrots", "1 bunch"], [ + "Celery", "1 stalk" + ], ["Lettuce", "1 head"], ["Onions", "1 lb."], [ + "Potatoes", "15 lb." + ], ["Spinach", "1 lb."], ["Sweet Potatoes", "1 lb."], [ + "Peaches (can)", "No. 2 1/2" + ], ["Pears (can)", "No. 2 1/2,"], [ + "Pineapple (can)", "No. 2 1/2" + ], ["Asparagus (can)", "No. 2"], [ + "Grean Beans (can)", "No. 2" + ], ["Pork and Beans (can)", "16 oz."], ["Corn (can)", "No. 2"], + ["Peas (can)", "No. 2"], ["Tomatoes (can)", "No. 2"], [ + "Tomato Soup (can)", "10 1/2 oz." + ], ["Peaches, Dried", "1 lb."], ["Prunes, Dried", "1 lb."], [ + "Raisins, Dried", "15 oz." + ], ["Peas, Dried", "1 lb."], ["Lima Beans, Dried", "1 lb."], [ + "Navy Beans, Dried", "1 lb." + ], ["Coffee", "1 lb."], ["Tea", "1/4 lb."], ["Cocoa", "8 oz."], + ["Chocolate", "8 oz."], ["Sugar", "10 lb."], [ + "Corn Sirup", "24 oz." + ], ["Molasses", "18 oz."], ["Strawberry Preserve", "1 lb."]] # price and weight are the two first columns data = [ - [36.0, 12600.0, 44.7, 1411.0, 2.0, 365.0, 0.0, 55.4, 33.3, 441.0, 0.0], - [14.1, 3217.0, 11.6, 418.0, 0.7, 54.0, 0.0, 3.2, 1.9, 68.0, 0.0], - [24.2, 3280.0, 11.8, 377.0, 14.4, 175.0, 0.0, 14.4, 8.8, 114.0, 0.0], - [7.1, 3194.0, 11.4, 252.0, 0.1, 56.0, 0.0, 13.5, 2.3, 68.0, 0.0], - [4.6, 9861.0, 36.0, 897.0, 1.7, 99.0, 30.9, 17.4, 7.9, 106.0, 0.0], - [8.5, 8005.0, 28.6, 680.0, 0.8, 80.0, 0.0, 10.6, 1.6, 110.0, 0.0], - [7.5, 6048.0, 21.2, 460.0, 0.6, 41.0, 0.0, 2.0, 4.8, 60.0, 0.0], - [7.1, 6389.0, 25.3, 907.0, 5.1, 341.0, 0.0, 37.1, 8.9, 64.0, 0.0], - [7.9, 5742.0, 15.6, 488.0, 2.5, 115.0, 0.0, 13.8, 8.5, 126.0, 0.0], - [9.1, 4985.0, 12.2, 484.0, 2.7, 125.0, 0.0, 13.9, 6.4, 160.0, 0.0], - [9.2, 4930.0, 12.4, 439.0, 1.1, 82.0, 0.0, 9.9, 3.0, 66.0, 0.0], - [24.8, 1829.0, 8.0, 130.0, 0.4, 31.0, 18.9, 2.8, 3.0, 17.0, 0.0], - [15.1, 3004.0, 12.5, 288.0, 0.5, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0], - [11.0, 8867.0, 6.1, 310.0, 10.5, 18.0, 16.8, 4.0, 16.0, 7.0, 177.0], - [6.7, 6035.0, 8.4, 422.0, 15.1, 9.0, 26.0, 3.0, 23.5, 11.0, 60.0], - [20.8, 1473.0, 10.8, 9.0, 0.2, 3.0, 44.2, 0.0, 0.2, 2.0, 0.0], - [16.1, 2817.0, 20.6, 17.0, 0.6, 6.0, 55.8, 0.2, 0.0, 0.0, 0.0], - [32.6, 1857.0, 2.9, 238.0, 1.0, 52.0, 18.6, 2.8, 6.5, 1.0, 0.0], - [24.2, 1874.0, 7.4, 448.0, 16.4, 19.0, 28.1, 0.8, 10.3, 4.0, 0.0], - [14.1, 1689.0, 3.5, 49.0, 1.7, 3.0, 16.9, 0.6, 2.5, 0.0, 17.0], - [17.9, 2534.0, 15.7, 661.0, 1.0, 48.0, 0.0, 9.6, 8.1, 471.0, 0.0], - [16.7, 1198.0, 8.6, 18.0, 0.2, 8.0, 2.7, 0.4, 0.5, 0.0, 0.0], - [20.3, 2234.0, 20.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - [9.8, 4628.0, 41.7, 0.0, 0.0, 0.0, 0.2, 0.0, 0.5, 5.0, 0.0], - [39.6, 1145.0, 2.9, 166.0, 0.1, 34.0, 0.2, 2.1, 2.9, 69.0, 0.0], - [36.4, 1246.0, 2.2, 214.0, 0.1, 32.0, 0.4, 2.5, 2.4, 87.0, 0.0], - [29.2, 1553.0, 3.4, 213.0, 0.1, 33.0, 0.0, 0.0, 2.0, 0.0, 0.0], - [22.6, 2007.0, 3.6, 309.0, 0.2, 46.0, 0.4, 1.0, 4.0, 120.0, 0.0], - [14.6, 3107.0, 8.5, 404.0, 0.2, 62.0, 0.0, 0.9, 0.0, 0.0, 0.0], - [26.8, 1692.0, 2.2, 333.0, 0.2, 139.0, 169.2, 6.4, 50.8, 316.0, 525.0], - [27.6, 1643.0, 3.1, 245.0, 0.1, 20.0, 0.0, 2.8, 3.0, 86.0, 0.0], - [36.6, 1239.0, 3.3, 140.0, 0.1, 15.0, 0.0, 1.7, 2.7, 54.0, 0.0], - [30.7, 1477.0, 3.5, 196.0, 0.2, 80.0, 0.0, 17.4, 2.7, 60.0, 0.0], - [24.2, 1874.0, 4.4, 249.0, 0.3, 37.0, 0.0, 18.2, 3.6, 79.0, 0.0], - [25.6, 1772.0, 10.4, 152.0, 0.2, 23.0, 0.0, 1.8, 1.8, 71.0, 0.0], - [27.4, 1655.0, 6.7, 212.0, 0.2, 31.0, 0.0, 9.9, 3.3, 50.0, 0.0], - [16.0, 2835.0, 18.8, 164.0, 0.1, 26.0, 0.0, 1.4, 1.8, 0.0, 0.0], - [30.3, 1497.0, 1.8, 184.0, 0.1, 30.0, 0.1, 0.9, 1.8, 68.0, 46.0], - [42.3, 1072.0, 1.7, 156.0, 0.1, 24.0, 0.0, 1.4, 2.4, 57.0, 0.0], - [13.0, 3489.0, 5.8, 705.0, 6.8, 45.0, 3.5, 1.0, 4.9, 209.0, 0.0], - [4.4, 9072.0, 5.8, 27.0, 0.5, 36.0, 7.3, 3.6, 2.7, 5.0, 544.0], - [6.1, 4982.0, 4.9, 60.0, 0.4, 30.0, 17.4, 2.5, 3.5, 28.0, 498.0], - [26.0, 2380.0, 1.0, 21.0, 0.5, 14.0, 0.0, 0.5, 0.0, 4.0, 952.0], - [30.9, 4439.0, 2.2, 40.0, 1.1, 18.0, 11.1, 3.6, 1.3, 10.0, 1993.0], - [7.1, 5750.0, 2.4, 138.0, 3.7, 80.0, 69.0, 4.3, 5.8, 37.0, 862.0], - [3.7, 8949.0, 2.6, 125.0, 4.0, 36.0, 7.2, 9.0, 4.5, 26.0, 5369.0], - [4.7, 6080.0, 2.7, 73.0, 2.8, 43.0, 188.5, 6.1, 4.3, 89.0, 608.0], - [7.3, 3915.0, 0.9, 51.0, 3.0, 23.0, 0.9, 1.4, 1.4, 9.0, 313.0], - [8.2, 2247.0, 0.4, 27.0, 1.1, 22.0, 112.4, 1.8, 3.4, 11.0, 449.0], - [3.6, 11844.0, 5.8, 166.0, 3.8, 59.0, 16.6, 4.7, 5.9, 21.0, 1184.0], - [34.0, 16810.0, 14.3, 336.0, 1.8, 118.0, 6.7, 29.4, 7.1, 198.0, 2522.0], - [8.1, 4592.0, 1.1, 106.0, 0.0, 138.0, 918.4, 5.7, 13.8, 33.0, 2755.0], - [5.1, 7649.0, 9.6, 138.0, 2.7, 54.0, 290.7, 8.4, 5.4, 83.0, 1912.0], - [16.8, 4894.0, 3.7, 20.0, 0.4, 10.0, 21.5, 0.5, 1.0, 31.0, 196.0], - [20.4, 4030.0, 3.0, 8.0, 0.3, 8.0, 0.8, 0.8, 0.8, 5.0, 81.0], - [21.3, 3993.0, 2.4, 16.0, 0.4, 8.0, 2.0, 2.8, 0.8, 7.0, 399.0], - [27.7, 1945.0, 0.4, 33.0, 0.3, 12.0, 16.3, 1.4, 2.1, 17.0, 272.0], - [10.0, 5386.0, 1.0, 54.0, 2.0, 65.0, 53.9, 1.6, 4.3, 32.0, 431.0], - [7.1, 6389.0, 7.5, 364.0, 4.0, 134.0, 3.5, 8.3, 7.7, 56.0, 0.0], - [10.4, 5452.0, 5.2, 136.0, 0.2, 16.0, 12.0, 1.6, 2.7, 42.0, 218.0], - [13.8, 4109.0, 2.3, 136.0, 0.6, 45.0, 34.9, 4.9, 2.5, 37.0, 370.0], - [8.6, 6263.0, 1.3, 63.0, 0.7, 38.0, 53.2, 3.4, 2.5, 36.0, 1253.0], - [7.6, 3917.0, 1.6, 71.0, 0.6, 43.0, 57.9, 3.5, 2.4, 67.0, 862.0], - [15.7, 2889.0, 8.5, 87.0, 1.7, 173.0, 86.8, 1.2, 4.3, 55.0, 57.0], - [9.0, 4284.0, 12.8, 99.0, 2.5, 154.0, 85.7, 3.9, 4.3, 65.0, 257.0], - [9.4, 4524.0, 13.5, 104.0, 2.5, 136.0, 4.5, 6.3, 1.4, 24.0, 136.0], - [7.9, 5742.0, 20.0, 1367.0, 4.2, 345.0, 2.9, 28.7, 18.4, 162.0, 0.0], - [8.9, 5097.0, 17.4, 1055.0, 3.7, 459.0, 5.1, 26.9, 38.2, 93.0, 0.0], - [5.9, 7688.0, 26.9, 1691.0, 11.4, 792.0, 0.0, 38.4, 24.6, 217.0, 0.0], - [22.4, 2025.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.1, 50.0, 0.0], - [17.4, 652.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.3, 42.0, 0.0], - [8.6, 2637.0, 8.7, 237.0, 3.0, 72.0, 0.0, 2.0, 11.9, 40.0, 0.0], - [16.2, 1400.0, 8.0, 77.0, 1.3, 39.0, 0.0, 0.9, 3.4, 14.0, 0.0], - [51.7, 8773.0, 34.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], - [13.7, 4996.0, 14.7, 0.0, 0.5, 74.0, 0.0, 0.0, 0.0, 5.0, 0.0], - [13.6, 3752.0, 9.0, 0.0, 10.3, 244.0, 0.0, 1.9, 7.5, 146.0, 0.0], - [20.5, 2213.0, 6.4, 11.0, 0.4, 7.0, 0.2, 0.2, 0.4, 3.0, 0.0]] + [36.0, 12600.0, 44.7, 1411.0, 2.0, 365.0, 0.0, 55.4, 33.3, 441.0, 0.0], [ + 14.1, 3217.0, 11.6, 418.0, 0.7, 54.0, 0.0, 3.2, 1.9, 68.0, 0.0 + ], [24.2, 3280.0, 11.8, 377.0, 14.4, 175.0, 0.0, 14.4, 8.8, 114.0, 0.0], + [7.1, 3194.0, 11.4, 252.0, 0.1, 56.0, 0.0, 13.5, 2.3, 68.0, 0.0], [ + 4.6, 9861.0, 36.0, 897.0, 1.7, 99.0, 30.9, 17.4, 7.9, 106.0, 0.0 + ], [8.5, 8005.0, 28.6, 680.0, 0.8, 80.0, 0.0, 10.6, 1.6, 110.0, 0.0], [ + 7.5, 6048.0, 21.2, 460.0, 0.6, 41.0, 0.0, 2.0, 4.8, 60.0, 0.0 + ], [7.1, 6389.0, 25.3, 907.0, 5.1, 341.0, 0.0, 37.1, 8.9, 64.0, 0.0], [ + 7.9, 5742.0, 15.6, 488.0, 2.5, 115.0, 0.0, 13.8, 8.5, 126.0, 0.0 + ], [9.1, 4985.0, 12.2, 484.0, 2.7, 125.0, 0.0, 13.9, 6.4, 160.0, 0.0], [ + 9.2, 4930.0, 12.4, 439.0, 1.1, 82.0, 0.0, 9.9, 3.0, 66.0, 0.0 + ], [24.8, 1829.0, 8.0, 130.0, 0.4, 31.0, 18.9, 2.8, 3.0, 17.0, 0.0], [ + 15.1, 3004.0, 12.5, 288.0, 0.5, 50.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ], [11.0, 8867.0, 6.1, 310.0, 10.5, 18.0, 16.8, 4.0, 16.0, 7.0, 177.0], [ + 6.7, 6035.0, 8.4, 422.0, 15.1, 9.0, 26.0, 3.0, 23.5, 11.0, 60.0 + ], [20.8, 1473.0, 10.8, 9.0, 0.2, 3.0, 44.2, 0.0, 0.2, 2.0, 0.0], [ + 16.1, 2817.0, 20.6, 17.0, 0.6, 6.0, 55.8, 0.2, 0.0, 0.0, 0.0 + ], [32.6, 1857.0, 2.9, 238.0, 1.0, 52.0, 18.6, 2.8, 6.5, 1.0, 0.0], [ + 24.2, 1874.0, 7.4, 448.0, 16.4, 19.0, 28.1, 0.8, 10.3, 4.0, 0.0 + ], [14.1, 1689.0, 3.5, 49.0, 1.7, 3.0, 16.9, 0.6, 2.5, 0.0, 17.0], [ + 17.9, 2534.0, 15.7, 661.0, 1.0, 48.0, 0.0, 9.6, 8.1, 471.0, 0.0 + ], [16.7, 1198.0, 8.6, 18.0, 0.2, 8.0, 2.7, 0.4, 0.5, 0.0, 0.0], [ + 20.3, 2234.0, 20.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ], [9.8, 4628.0, 41.7, 0.0, 0.0, 0.0, 0.2, 0.0, 0.5, 5.0, 0.0], [ + 39.6, 1145.0, 2.9, 166.0, 0.1, 34.0, 0.2, 2.1, 2.9, 69.0, 0.0 + ], [36.4, 1246.0, 2.2, 214.0, 0.1, 32.0, 0.4, 2.5, 2.4, 87.0, 0.0], [ + 29.2, 1553.0, 3.4, 213.0, 0.1, 33.0, 0.0, 0.0, 2.0, 0.0, 0.0 + ], [22.6, 2007.0, 3.6, 309.0, 0.2, 46.0, 0.4, 1.0, 4.0, 120.0, 0.0], [ + 14.6, 3107.0, 8.5, 404.0, 0.2, 62.0, 0.0, 0.9, 0.0, 0.0, 0.0 + ], [26.8, 1692.0, 2.2, 333.0, 0.2, 139.0, 169.2, 6.4, 50.8, 316.0, 525.0], + [27.6, 1643.0, 3.1, 245.0, 0.1, 20.0, 0.0, 2.8, 3.0, 86.0, 0.0], [ + 36.6, 1239.0, 3.3, 140.0, 0.1, 15.0, 0.0, 1.7, 2.7, 54.0, 0.0 + ], [30.7, 1477.0, 3.5, 196.0, 0.2, 80.0, 0.0, 17.4, 2.7, 60.0, 0.0], [ + 24.2, 1874.0, 4.4, 249.0, 0.3, 37.0, 0.0, 18.2, 3.6, 79.0, 0.0 + ], [25.6, 1772.0, 10.4, 152.0, 0.2, 23.0, 0.0, 1.8, 1.8, 71.0, 0.0], [ + 27.4, 1655.0, 6.7, 212.0, 0.2, 31.0, 0.0, 9.9, 3.3, 50.0, 0.0 + ], [16.0, 2835.0, 18.8, 164.0, 0.1, 26.0, 0.0, 1.4, 1.8, 0.0, 0.0], [ + 30.3, 1497.0, 1.8, 184.0, 0.1, 30.0, 0.1, 0.9, 1.8, 68.0, 46.0 + ], [42.3, 1072.0, 1.7, 156.0, 0.1, 24.0, 0.0, 1.4, 2.4, 57.0, 0.0], [ + 13.0, 3489.0, 5.8, 705.0, 6.8, 45.0, 3.5, 1.0, 4.9, 209.0, 0.0 + ], [4.4, 9072.0, 5.8, 27.0, 0.5, 36.0, 7.3, 3.6, 2.7, 5.0, 544.0], [ + 6.1, 4982.0, 4.9, 60.0, 0.4, 30.0, 17.4, 2.5, 3.5, 28.0, 498.0 + ], [26.0, 2380.0, 1.0, 21.0, 0.5, 14.0, 0.0, 0.5, 0.0, 4.0, 952.0], [ + 30.9, 4439.0, 2.2, 40.0, 1.1, 18.0, 11.1, 3.6, 1.3, 10.0, 1993.0 + ], [7.1, 5750.0, 2.4, 138.0, 3.7, 80.0, 69.0, 4.3, 5.8, 37.0, 862.0], [ + 3.7, 8949.0, 2.6, 125.0, 4.0, 36.0, 7.2, 9.0, 4.5, 26.0, 5369.0 + ], [4.7, 6080.0, 2.7, 73.0, 2.8, 43.0, 188.5, 6.1, 4.3, 89.0, 608.0], [ + 7.3, 3915.0, 0.9, 51.0, 3.0, 23.0, 0.9, 1.4, 1.4, 9.0, 313.0 + ], [8.2, 2247.0, 0.4, 27.0, 1.1, 22.0, 112.4, 1.8, 3.4, 11.0, 449.0], [ + 3.6, 11844.0, 5.8, 166.0, 3.8, 59.0, 16.6, 4.7, 5.9, 21.0, 1184.0 + ], [ + 34.0, 16810.0, 14.3, 336.0, 1.8, 118.0, 6.7, 29.4, 7.1, 198.0, 2522.0 + ], [8.1, 4592.0, 1.1, 106.0, 0.0, 138.0, 918.4, 5.7, 13.8, 33.0, + 2755.0], [ + 5.1, 7649.0, 9.6, 138.0, 2.7, 54.0, 290.7, 8.4, 5.4, 83.0, 1912.0 + ], [16.8, 4894.0, 3.7, 20.0, 0.4, 10.0, 21.5, 0.5, 1.0, 31.0, 196.0], + [20.4, 4030.0, 3.0, 8.0, 0.3, 8.0, 0.8, 0.8, 0.8, 5.0, + 81.0], [21.3, 3993.0, 2.4, 16.0, 0.4, 8.0, 2.0, 2.8, 0.8, 7.0, 399.0], [ + 27.7, 1945.0, 0.4, 33.0, 0.3, 12.0, 16.3, 1.4, 2.1, 17.0, 272.0 + ], [10.0, 5386.0, 1.0, 54.0, 2.0, 65.0, 53.9, 1.6, 4.3, 32.0, 431.0], [ + 7.1, 6389.0, 7.5, 364.0, 4.0, 134.0, 3.5, 8.3, 7.7, 56.0, 0.0 + ], [10.4, 5452.0, 5.2, 136.0, 0.2, 16.0, 12.0, 1.6, 2.7, 42.0, 218.0], [ + 13.8, 4109.0, 2.3, 136.0, 0.6, 45.0, 34.9, 4.9, 2.5, 37.0, 370.0 + ], [8.6, 6263.0, 1.3, 63.0, 0.7, 38.0, 53.2, 3.4, 2.5, 36.0, 1253.0], [ + 7.6, 3917.0, 1.6, 71.0, 0.6, 43.0, 57.9, 3.5, 2.4, 67.0, 862.0 + ], [15.7, 2889.0, 8.5, 87.0, 1.7, 173.0, 86.8, 1.2, 4.3, 55.0, 57.0], [ + 9.0, 4284.0, 12.8, 99.0, 2.5, 154.0, 85.7, 3.9, 4.3, 65.0, 257.0 + ], [9.4, 4524.0, 13.5, 104.0, 2.5, 136.0, 4.5, 6.3, 1.4, 24.0, 136.0], [ + 7.9, 5742.0, 20.0, 1367.0, 4.2, 345.0, 2.9, 28.7, 18.4, 162.0, 0.0 + ], [8.9, 5097.0, 17.4, 1055.0, 3.7, 459.0, 5.1, 26.9, 38.2, 93.0, 0.0], [ + 5.9, 7688.0, 26.9, 1691.0, 11.4, 792.0, 0.0, 38.4, 24.6, 217.0, 0.0 + ], [22.4, 2025.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.0, 5.1, 50.0, + 0.0], [17.4, 652.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.3, 42.0, 0.0], [ + 8.6, 2637.0, 8.7, 237.0, 3.0, 72.0, 0.0, 2.0, 11.9, 40.0, 0.0 + ], [16.2, 1400.0, 8.0, 77.0, 1.3, 39.0, 0.0, 0.9, 3.4, 14.0, 0.0], [ + 51.7, 8773.0, 34.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 + ], [13.7, 4996.0, 14.7, 0.0, 0.5, 74.0, 0.0, 0.0, 0.0, 5.0, 0.0], [ + 13.6, 3752.0, 9.0, 0.0, 10.3, 244.0, 0.0, 1.9, 7.5, 146.0, 0.0 + ], [20.5, 2213.0, 6.4, 11.0, 0.4, 7.0, 0.2, 0.2, 0.4, 3.0, 0.0] + ] # recommended daily allowance for a moderately active man allowance = [3.0, 70.0, 0.8, 12.0, 5.0, 1.8, 2.7, 18.0, 75.0] @@ -368,8 +339,9 @@ def main(sol="CBC"): print() for i in C: if x[i].SolutionValue() > 0: - print("%-21s %-11s %0.2f %0.2f" % (commodities[i][0], commodities[i][1], - x_cost[i].SolutionValue(), quant[i].SolutionValue())) + print("%-21s %-11s %0.2f %0.2f" % + (commodities[i][0], commodities[i][1], x_cost[i].SolutionValue(), + quant[i].SolutionValue())) print() diff --git a/examples/python/strimko2.py b/examples/python/strimko2.py index 4216a28c20..d3b95a07ba 100644 --- a/examples/python/strimko2.py +++ b/examples/python/strimko2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Strimko problem in Google CP Solver. From @@ -58,27 +57,14 @@ def main(streams='', placed=''): # default problem # if streams == '': - streams = [ - [1, 1, 2, 2, 2, 2, 2], - [1, 1, 2, 3, 3, 3, 2], - [1, 4, 1, 3, 3, 5, 5], - [4, 4, 3, 1, 3, 5, 5], - [4, 6, 6, 6, 7, 7, 5], - [6, 4, 6, 4, 5, 5, 7], - [6, 6, 4, 7, 7, 7, 7]] + streams = [[1, 1, 2, 2, 2, 2, 2], [1, 1, 2, 3, 3, 3, 2], + [1, 4, 1, 3, 3, 5, 5], [4, 4, 3, 1, 3, 5, 5], + [4, 6, 6, 6, 7, 7, 5], [6, 4, 6, 4, 5, 5, + 7], [6, 6, 4, 7, 7, 7, 7]] # Note: This is 1-based - placed = [ - [2, 1, 1], - [2, 3, 7], - [2, 5, 6], - [2, 7, 4], - [3, 2, 7], - [3, 6, 1], - [4, 1, 4], - [4, 7, 5], - [5, 2, 2], - [5, 6, 6]] + placed = [[2, 1, 1], [2, 3, 7], [2, 5, 6], [2, 7, 4], [3, 2, 7], [3, 6, 1], + [4, 1, 4], [4, 7, 5], [5, 2, 2], [5, 6, 6]] n = len(streams) num_placed = len(placed) @@ -125,9 +111,7 @@ def main(streams='', placed=''): # # search and solution # - db = solver.Phase(x_flat, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(x_flat, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) @@ -149,10 +133,11 @@ def main(streams='', placed=''): print('branches:', solver.Branches()) print('WallTime:', solver.WallTime(), 'ms') + if __name__ == '__main__': if len(sys.argv) > 1: problem_file = sys.argv[1] - exec(compile(open(problem_file).read(), problem_file, 'exec')) + exec (compile(open(problem_file).read(), problem_file, 'exec')) main(streams, placed) else: main() diff --git a/examples/python/subset_sum.py b/examples/python/subset_sum.py index 99df66ce9a..ff2119cafc 100644 --- a/examples/python/subset_sum.py +++ b/examples/python/subset_sum.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Subset sum problem in Google CP Solver. @@ -84,9 +83,7 @@ def main(coins, total): solution.Add(ss) # db: DecisionBuilder - db = solver.Phase(x, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE) + db = solver.Phase(x, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) num_solutions = 0 @@ -103,6 +100,7 @@ def main(coins, total): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + coins = [16, 17, 23, 24, 39, 40] total = 100 if __name__ == "__main__": diff --git a/examples/python/sudoku.py b/examples/python/sudoku.py index 027c02c733..7f3d984ac5 100644 --- a/examples/python/sudoku.py +++ b/examples/python/sudoku.py @@ -10,30 +10,27 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """This model implements a sudoku solver.""" from __future__ import print_function from ortools.constraint_solver import pywrapcp + def main(): # Create the solver. solver = pywrapcp.Solver('sudoku') cell_size = 3 - line_size = cell_size ** 2 + line_size = cell_size**2 line = list(range(0, line_size)) cell = list(range(0, cell_size)) - initial_grid = [[0, 6, 0, 0, 5, 0, 0, 2, 0], - [0, 0, 0, 3, 0, 0, 0, 9, 0], - [7, 0, 0, 6, 0, 0, 0, 1, 0], - [0, 0, 6, 0, 3, 0, 4, 0, 0], - [0, 0, 4, 0, 7, 0, 1, 0, 0], - [0, 0, 5, 0, 9, 0, 8, 0, 0], - [0, 4, 0, 0, 0, 1, 0, 0, 6], - [0, 3, 0, 0, 0, 8, 0, 0, 0], - [0, 2, 0, 0, 4, 0, 0, 5, 0]] + initial_grid = [[0, 6, 0, 0, 5, 0, 0, 2, 0], [0, 0, 0, 3, 0, 0, 0, 9, + 0], [7, 0, 0, 6, 0, 0, 0, 1, 0], + [0, 0, 6, 0, 3, 0, 4, 0, 0], [0, 0, 4, 0, 7, 0, 1, 0, + 0], [0, 0, 5, 0, 9, 0, 8, 0, 0], + [0, 4, 0, 0, 0, 1, 0, 0, 6], [0, 3, 0, 0, 0, 8, 0, 0, + 0], [0, 2, 0, 0, 4, 0, 0, 5, 0]] grid = {} for i in line: @@ -68,8 +65,7 @@ def main(): all_vars = [grid[(i, j)] for i in line for j in line] # Create search phases. - vars_phase = solver.Phase(all_vars, - solver.INT_VAR_SIMPLE, + vars_phase = solver.Phase(all_vars, solver.INT_VAR_SIMPLE, solver.INT_VALUE_SIMPLE) solution = solver.Assignment() diff --git a/examples/python/survo_puzzle.py b/examples/python/survo_puzzle.py index 556ab9a623..e8f2e4b18a 100644 --- a/examples/python/survo_puzzle.py +++ b/examples/python/survo_puzzle.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Survo puzzle Google CP Solver. @@ -78,9 +77,7 @@ def main(r=0, c=0, rowsums=[], colsums=[], game=[]): c = 4 rowsums = [30, 18, 30] colsums = [27, 16, 10, 25] - game = [[0, 6, 0, 0], - [8, 0, 0, 0], - [0, 0, 3, 0]] + game = [[0, 6, 0, 0], [8, 0, 0, 0], [0, 0, 3, 0]] print("r:", r, "c:", c) @@ -120,21 +117,19 @@ def main(r=0, c=0, rowsums=[], colsums=[], game=[]): solution.Add([x[(i, j)] for i in range(r) for j in range(c)]) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase(xflat, - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase(xflat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE), + [collector]) num_solutions = collector.SolutionCount() print("\nnum_solutions: ", num_solutions) if num_solutions > 0: for s in range(num_solutions): - xval = [collector.Value(s, x[(i, j)]) - for i in range(r) for j in range(c)] + xval = [collector.Value(s, x[(i, j)]) for i in range(r) for j in range(c)] for i in range(r): for j in range(c): - print("%2i" % (xval[i * c + j]), end=' ') + print("%2i" % (xval[i * c + j]), end=" ") print() print() diff --git a/examples/python/toNum.py b/examples/python/toNum.py index 433fe16f81..04b1cbfe5b 100644 --- a/examples/python/toNum.py +++ b/examples/python/toNum.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ toNum in Google CP Solver. @@ -33,8 +32,8 @@ from ortools.constraint_solver import pywrapcp def toNum(solver, t, s, base): tlen = len(t) - solver.Add( - s == solver.Sum([(base ** (tlen - i - 1)) * t[i] for i in range(tlen)])) + solver.Add(s == solver.Sum([(base**(tlen - i - 1)) * t[i] + for i in range(tlen)])) def main(unused_argv): @@ -47,7 +46,7 @@ def main(unused_argv): # declare variables x = [solver.IntVar(0, n - 1, "x%i" % i) for i in range(n)] - y = solver.IntVar(0, 10 ** n - 1, "y") + y = solver.IntVar(0, 10**n - 1, "y") # # constraints @@ -66,10 +65,9 @@ def main(unused_argv): solution.Add(y) collector = solver.AllSolutionCollector(solution) - solver.Solve(solver.Phase([x[i] for i in range(n)], - solver.CHOOSE_FIRST_UNBOUND, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([x[i] for i in range(n)], solver.CHOOSE_FIRST_UNBOUND, + solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() for s in range(num_solutions): diff --git a/examples/python/traffic_lights.py b/examples/python/traffic_lights.py index d51cc1eebb..8333c0cb53 100644 --- a/examples/python/traffic_lights.py +++ b/examples/python/traffic_lights.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Traffic lights problem in Google CP Solver. @@ -90,10 +89,7 @@ def main(base=10, start=1, len1=1, len2=4): # The allowed combinations allowed = [] - allowed.extend([(r, r, g, g), - (ry, r, y, r), - (g, g, r, r), - (y, r, ry, r)]) + allowed.extend([(r, r, g, g), (ry, r, y, r), (g, g, r, r), (y, r, ry, r)]) # # declare variables @@ -112,15 +108,13 @@ def main(base=10, start=1, len1=1, len2=4): # # Search and result # - db = solver.Phase(V + P, - solver.INT_VAR_SIMPLE, - solver.INT_VALUE_DEFAULT) + db = solver.Phase(V + P, solver.INT_VAR_SIMPLE, solver.INT_VALUE_DEFAULT) solver.NewSearch(db) num_solutions = 0 while solver.NextSolution(): for i in range(n): - print("%+2s %+2s" % (lights[V[i].Value()], lights[P[i].Value()]), end=' ') + print("%+2s %+2s" % (lights[V[i].Value()], lights[P[i].Value()]), end=" ") print() num_solutions += 1 diff --git a/examples/python/transit_time.py b/examples/python/transit_time.py index be37dc6391..f5adc01786 100755 --- a/examples/python/transit_time.py +++ b/examples/python/transit_time.py @@ -13,7 +13,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Display Transit Time Distances are in meters and time in minutes. @@ -27,189 +26,202 @@ from six.moves import xrange from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 + ########################### # Problem Data Definition # ########################### class Vehicle(): - """Stores the property of a vehicle""" - def __init__(self): - """Initializes the vehicle properties""" - self._capacity = 15 - # Travel speed: 5km/h to convert in m/min - self._speed = 5 * 60 / 3.6 + """Stores the property of a vehicle""" + + def __init__(self): + """Initializes the vehicle properties""" + self._capacity = 15 + # Travel speed: 5km/h to convert in m/min + self._speed = 5 * 60 / 3.6 + + @property + def speed(self): + """Gets the average travel speed of a vehicle""" + return self._speed - @property - def speed(self): - """Gets the average travel speed of a vehicle""" - return self._speed class CityBlock(): - """City block definition""" - @property - def width(self): - """Gets Block size West to East""" - return 228/2 + """City block definition""" + + @property + def width(self): + """Gets Block size West to East""" + return 228 / 2 + + @property + def height(self): + """Gets Block size North to South""" + return 80 - @property - def height(self): - """Gets Block size North to South""" - return 80 class DataProblem(): - """Stores the data for the problem""" - def __init__(self): - """Initializes the data for the problem""" - self._vehicle = Vehicle() + """Stores the data for the problem""" - # Locations in block unit - locations = \ - [(4, 4), # depot - (2, 0), (8, 0), # row 0 - (0, 1), (1, 1), - (5, 2), (7, 2), - (3, 3), (6, 3), - (5, 5), (8, 5), - (1, 6), (2, 6), - (3, 7), (6, 7), - (0, 8), (7, 8)] - # locations in meters using the city block dimension - city_block = CityBlock() - self._locations = [( - loc[0]*city_block.width, - loc[1]*city_block.height) for loc in locations] + def __init__(self): + """Initializes the data for the problem""" + self._vehicle = Vehicle() - self._depot = 0 + # Locations in block unit + locations = \ + [(4, 4), # depot + (2, 0), (8, 0), # row 0 + (0, 1), (1, 1), + (5, 2), (7, 2), + (3, 3), (6, 3), + (5, 5), (8, 5), + (1, 6), (2, 6), + (3, 7), (6, 7), + (0, 8), (7, 8)] + # locations in meters using the city block dimension + city_block = CityBlock() + self._locations = [(loc[0] * city_block.width, loc[1] * city_block.height) + for loc in locations] - self._demands = \ - [0, # depot - 1, 1, # 1, 2 - 2, 4, # 3, 4 - 2, 4, # 5, 6 - 8, 8, # 7, 8 - 1, 2, # 9,10 - 1, 2, # 11,12 - 4, 4, # 13, 14 - 8, 8] # 15, 16 + self._depot = 0 - self._time_windows = \ - [(0, 0), - (75, 85), (75, 85), # 1, 2 - (60, 70), (45, 55), # 3, 4 - (0, 8), (50, 60), # 5, 6 - (0, 10), (10, 20), # 7, 8 - (0, 10), (75, 85), # 9, 10 - (85, 95), (5, 15), # 11, 12 - (15, 25), (10, 20), # 13, 14 - (45, 55), (30, 40)] # 15, 16 + self._demands = \ + [0, # depot + 1, 1, # 1, 2 + 2, 4, # 3, 4 + 2, 4, # 5, 6 + 8, 8, # 7, 8 + 1, 2, # 9,10 + 1, 2, # 11,12 + 4, 4, # 13, 14 + 8, 8] # 15, 16 - @property - def vehicle(self): - """Gets a vehicle""" - return self._vehicle + self._time_windows = \ + [(0, 0), + (75, 85), (75, 85), # 1, 2 + (60, 70), (45, 55), # 3, 4 + (0, 8), (50, 60), # 5, 6 + (0, 10), (10, 20), # 7, 8 + (0, 10), (75, 85), # 9, 10 + (85, 95), (5, 15), # 11, 12 + (15, 25), (10, 20), # 13, 14 + (45, 55), (30, 40)] # 15, 16 - @property - def locations(self): - """Gets locations""" - return self._locations + @property + def vehicle(self): + """Gets a vehicle""" + return self._vehicle - @property - def num_locations(self): - """Gets number of locations""" - return len(self.locations) + @property + def locations(self): + """Gets locations""" + return self._locations - @property - def depot(self): - """Gets depot location index""" - return self._depot + @property + def num_locations(self): + """Gets number of locations""" + return len(self.locations) - @property - def demands(self): - """Gets demands at each location""" - return self._demands + @property + def depot(self): + """Gets depot location index""" + return self._depot - @property - def time_per_demand_unit(self): - """Gets the time (in min) to load a demand""" - return 5 # 5 minutes/unit + @property + def demands(self): + """Gets demands at each location""" + return self._demands + + @property + def time_per_demand_unit(self): + """Gets the time (in min) to load a demand""" + return 5 # 5 minutes/unit + + @property + def time_windows(self): + """Gets (start time, end time) for each locations""" + return self._time_windows - @property - def time_windows(self): - """Gets (start time, end time) for each locations""" - return self._time_windows ####################### # Problem Constraints # ####################### def manhattan_distance(position_1, position_2): - """Computes the Manhattan distance between two points""" - return (abs(position_1[0] - position_2[0]) + - abs(position_1[1] - position_2[1])) + """Computes the Manhattan distance between two points""" + return ( + abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1])) + class CreateTimeEvaluator(object): - """Creates callback to get total times between locations.""" - @staticmethod - def service_time(data, node): - """Gets the service time for the specified location.""" - return data.demands[node] * data.time_per_demand_unit + """Creates callback to get total times between locations.""" - @staticmethod - def travel_time(data, from_node, to_node): - """Gets the travel times between two locations.""" + @staticmethod + def service_time(data, node): + """Gets the service time for the specified location.""" + return data.demands[node] * data.time_per_demand_unit + + @staticmethod + def travel_time(data, from_node, to_node): + """Gets the travel times between two locations.""" + if from_node == to_node: + travel_time = 0 + else: + travel_time = manhattan_distance( + data.locations[from_node], + data.locations[to_node]) / data.vehicle.speed + return travel_time + + def __init__(self, data): + """Initializes the total time matrix.""" + self._total_time = {} + # precompute total time to have time callback in O(1) + for from_node in xrange(data.num_locations): + self._total_time[from_node] = {} + for to_node in xrange(data.num_locations): if from_node == to_node: - travel_time = 0 + self._total_time[from_node][to_node] = 0 else: - travel_time = manhattan_distance( - data.locations[from_node], - data.locations[to_node]) / data.vehicle.speed - return travel_time + self._total_time[from_node][to_node] = int( + self.service_time(data, from_node) + + self.travel_time(data, from_node, to_node)) - def __init__(self, data): - """Initializes the total time matrix.""" - self._total_time = {} - # precompute total time to have time callback in O(1) - for from_node in xrange(data.num_locations): - self._total_time[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._total_time[from_node][to_node] = 0 - else: - self._total_time[from_node][to_node] = int( - self.service_time(data, from_node) + - self.travel_time(data, from_node, to_node)) + def time_evaluator(self, from_node, to_node): + """Returns the total time between the two nodes""" + return self._total_time[from_node][to_node] - def time_evaluator(self, from_node, to_node): - """Returns the total time between the two nodes""" - return self._total_time[from_node][to_node] def print_transit_time(route, time_evaluator): - """Print transit time between nodes of a route""" - total_time = 0 - for i, j in route: - total_time += time_evaluator(i, j) - print('{0} -> {1}: {2}min'.format(i, j, time_evaluator(i, j))) - print('Total time: {0}min\n'.format(total_time)) + """Print transit time between nodes of a route""" + total_time = 0 + for i, j in route: + total_time += time_evaluator(i, j) + print('{0} -> {1}: {2}min'.format(i, j, time_evaluator(i, j))) + print('Total time: {0}min\n'.format(total_time)) + ######## # Main # ######## def main(): - """Entry point of the program""" - # Instantiate the data problem. - data = DataProblem() + """Entry point of the program""" + # Instantiate the data problem. + data = DataProblem() - # Print Transit Time - time_evaluator = CreateTimeEvaluator(data).time_evaluator - print('Route 0:') - print_transit_time([[0, 5], [5, 8], [8, 6], [6, 2], [2, 0]], time_evaluator) + # Print Transit Time + time_evaluator = CreateTimeEvaluator(data).time_evaluator + print('Route 0:') + print_transit_time([[0, 5], [5, 8], [8, 6], [6, 2], [2, 0]], time_evaluator) - print('Route 1:') - print_transit_time([[0, 9], [9, 14], [14, 16], [16, 10], [10, 0]], time_evaluator) + print('Route 1:') + print_transit_time([[0, 9], [9, 14], [14, 16], [16, 10], [10, 0]], + time_evaluator) - print('Route 2:') - print_transit_time([[0, 12], [12, 13], [13, 15], [15, 11], [11, 0]], time_evaluator) + print('Route 2:') + print_transit_time([[0, 12], [12, 13], [13, 15], [15, 11], [11, 0]], + time_evaluator) + + print('Route 3:') + print_transit_time([[0, 7], [7, 4], [4, 3], [3, 1], [1, 0]], time_evaluator) - print('Route 3:') - print_transit_time([[0, 7], [7, 4], [4, 3], [3, 1], [1, 0]], time_evaluator) if __name__ == '__main__': - main() + main() diff --git a/examples/python/tsp.py b/examples/python/tsp.py index 4a0f10d743..4aad95cf70 100644 --- a/examples/python/tsp.py +++ b/examples/python/tsp.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Traveling Salesman Sample. This is a sample using the routing library python wrapper to solve a @@ -23,8 +22,6 @@ (forbidden arcs). """ - - import random import argparse from ortools.constraint_solver import pywrapcp @@ -32,16 +29,28 @@ from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 parser = argparse.ArgumentParser() -parser.add_argument('--tsp_size', default = 10, type = int, - help='Size of Traveling Salesman Problem instance.') -parser.add_argument('--tsp_use_random_matrix', default=True, type=bool, - help='Use random cost matrix.') -parser.add_argument('--tsp_random_forbidden_connections', default = 0, - type = int, help='Number of random forbidden connections.') -parser.add_argument('--tsp_random_seed', default = 0, type = int, - help = 'Random seed.') -parser.add_argument('--light_propagation', default = False, - type = bool, help = 'Use light propagation') +parser.add_argument( + '--tsp_size', + default=10, + type=int, + help='Size of Traveling Salesman Problem instance.') +parser.add_argument( + '--tsp_use_random_matrix', + default=True, + type=bool, + help='Use random cost matrix.') +parser.add_argument( + '--tsp_random_forbidden_connections', + default=0, + type=int, + help='Number of random forbidden connections.') +parser.add_argument( + '--tsp_random_seed', default=0, type=int, help='Random seed.') +parser.add_argument( + '--light_propagation', + default=False, + type=bool, + help='Use light propagation') # Cost/distance functions. @@ -111,6 +120,8 @@ def main(args): forbidden_connections += 1 # Solve, returns a solution if any. + + # assignment = routing.SolveWithParameters(search_parameters) assignment = routing.Solve() if assignment: diff --git a/examples/python/vendor_scheduling.py b/examples/python/vendor_scheduling.py index d913559c2e..3a4dd15a00 100644 --- a/examples/python/vendor_scheduling.py +++ b/examples/python/vendor_scheduling.py @@ -20,13 +20,12 @@ def main(): # Last columns are : # index_of_the_schedule, sum of worked hours (per work type). # The index is useful for branching. - possible_schedules = [ - [1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 8], - [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4], - [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 5], - [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4], - [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, 3], - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]] + possible_schedules = [[1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, + 8], [1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, + 4], [0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, + 5], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3, 4], + [1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 4, + 3], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0]] num_possible_schedules = len(possible_schedules) selected_schedules = [] @@ -70,8 +69,7 @@ def main(): # # Search # - db = solver.Phase(selected_schedules, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(selected_schedules, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/volsay.py b/examples/python/volsay.py index 481542e411..89eac28f0f 100644 --- a/examples/python/volsay.py +++ b/examples/python/volsay.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Volsay problem in Google or-tools. @@ -36,7 +35,7 @@ def main(unused_argv): # Using CLP solver = pywraplp.Solver('CoinsGridCLP', - pywraplp.Solver.CLP_LINEAR_PROGRAMMING) + pywraplp.Solver.CLP_LINEAR_PROGRAMMING) # data @@ -63,7 +62,9 @@ def main(unused_argv): print() print('objective = ', solver.Objective().Value()) print('Gas = ', Gas.SolutionValue(), 'ReducedCost =', Gas.ReducedCost()) - print('Chloride:', Chloride.SolutionValue(), 'ReducedCost =', Chloride.ReducedCost()) + print('Chloride:', Chloride.SolutionValue(), 'ReducedCost =', + Chloride.ReducedCost()) + if __name__ == '__main__': main('Volsay') diff --git a/examples/python/volsay2.py b/examples/python/volsay2.py index 5d3b15b238..2fe5ed92b5 100644 --- a/examples/python/volsay2.py +++ b/examples/python/volsay2.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Volsay problem in Google or-tools. @@ -47,8 +46,10 @@ def main(unused_argv): products = ['Gas', 'Chloride'] # declare variables - production = [solver.NumVar(0, 100000, 'production[%i]' % i) - for i in range(num_products)] + production = [ + solver.NumVar(0, 100000, 'production[%i]' % i) + for i in range(num_products) + ] # # constraints @@ -72,5 +73,6 @@ def main(unused_argv): print(products[i], '=', production[i].SolutionValue(), end=' ') print('ReducedCost = ', production[i].ReducedCost()) + if __name__ == '__main__': main('Volsay') diff --git a/examples/python/volsay3.py b/examples/python/volsay3.py index 6ce4594be1..3742a75c1c 100644 --- a/examples/python/volsay3.py +++ b/examples/python/volsay3.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Volsay problem in Google or-tools. @@ -50,20 +49,23 @@ def main(unused_argv): stock = [50, 180, 40] # declare variables - production = [solver.NumVar(0, 100000, 'production[%i]' % i) - for i in range(num_products)] + production = [ + solver.NumVar(0, 100000, 'production[%i]' % i) + for i in range(num_products) + ] # # constraints # for c in range(len(components)): - solver.Add(solver.Sum([demand[p][c] * production[p] - for p in range(len(products))]) <= stock[c]) + solver.Add( + solver.Sum([demand[p][c] * production[p] + for p in range(len(products))]) <= stock[c]) # objective # Note: there is no support for solver.ScalProd in the LP/IP interface - objective = solver.Maximize(solver.Sum([production[p] * profit[p] - for p in range(num_products)])) + objective = solver.Maximize( + solver.Sum([production[p] * profit[p] for p in range(num_products)])) print('NumConstraints:', solver.NumConstraints()) print('NumVariables:', solver.NumVariables()) diff --git a/examples/python/vrp.py b/examples/python/vrp.py index 7726fece3f..279d090180 100755 --- a/examples/python/vrp.py +++ b/examples/python/vrp.py @@ -13,9 +13,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Vehicle Routing Problem (VRP). - This is a sample using the routing library python wrapper to solve a VRP problem. + + This is a sample using the routing library python wrapper to solve a VRP + problem. A description of the problem can be found here: http://en.wikipedia.org/wiki/Vehicle_routing_problem. @@ -31,169 +32,178 @@ from six.moves import xrange from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 + ########################### # Problem Data Definition # ########################### class CityBlock(): - """City block definition""" - @property - def width(self): - """Gets Block size West to East""" - return 228/2 + """City block definition""" + + @property + def width(self): + """Gets Block size West to East""" + return 228 / 2 + + @property + def height(self): + """Gets Block size North to South""" + return 80 - @property - def height(self): - """Gets Block size North to South""" - return 80 class DataProblem(): - """Stores the data for the problem""" - def __init__(self): - """Initializes the data for the problem""" - self._num_vehicles = 4 + """Stores the data for the problem""" - # Locations in block unit - locations = \ - [(4, 4), # depot - (2, 0), (8, 0), # row 0 - (0, 1), (1, 1), - (5, 2), (7, 2), - (3, 3), (6, 3), - (5, 5), (8, 5), - (1, 6), (2, 6), - (3, 7), (6, 7), - (0, 8), (7, 8)] - # locations in meters using the block dimension defined - city_block = CityBlock() - self._locations = [( - loc[0]*city_block.width, - loc[1]*city_block.height) for loc in locations] + def __init__(self): + """Initializes the data for the problem""" + self._num_vehicles = 4 - self._depot = 0 + # Locations in block unit + locations = \ + [(4, 4), # depot + (2, 0), (8, 0), # row 0 + (0, 1), (1, 1), + (5, 2), (7, 2), + (3, 3), (6, 3), + (5, 5), (8, 5), + (1, 6), (2, 6), + (3, 7), (6, 7), + (0, 8), (7, 8)] + # locations in meters using the block dimension defined + city_block = CityBlock() + self._locations = [(loc[0] * city_block.width, loc[1] * city_block.height) + for loc in locations] - @property - def num_vehicles(self): - """Gets number of vehicles""" - return self._num_vehicles + self._depot = 0 - @property - def locations(self): - """Gets locations""" - return self._locations + @property + def num_vehicles(self): + """Gets number of vehicles""" + return self._num_vehicles - @property - def num_locations(self): - """Gets number of locations""" - return len(self.locations) + @property + def locations(self): + """Gets locations""" + return self._locations + + @property + def num_locations(self): + """Gets number of locations""" + return len(self.locations) + + @property + def depot(self): + """Gets depot location index""" + return self._depot - @property - def depot(self): - """Gets depot location index""" - return self._depot ####################### # Problem Constraints # ####################### def manhattan_distance(position_1, position_2): - """Computes the Manhattan distance between two points""" - return (abs(position_1[0] - position_2[0]) + - abs(position_1[1] - position_2[1])) + """Computes the Manhattan distance between two points""" + return ( + abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1])) -class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to return distance between points.""" - def __init__(self, data): - """Initializes the distance matrix.""" - self._distances = {} - # precompute distance between location to have distance callback in O(1) - for from_node in xrange(data.num_locations): - self._distances[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._distances[from_node][to_node] = 0 - else: - self._distances[from_node][to_node] = ( - manhattan_distance( - data.locations[from_node], - data.locations[to_node])) +class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to return distance between points.""" + + def __init__(self, data): + """Initializes the distance matrix.""" + self._distances = {} + + # precompute distance between location to have distance callback in O(1) + for from_node in xrange(data.num_locations): + self._distances[from_node] = {} + for to_node in xrange(data.num_locations): + if from_node == to_node: + self._distances[from_node][to_node] = 0 + else: + self._distances[from_node][to_node] = ( + manhattan_distance(data.locations[from_node], + data.locations[to_node])) + + def distance_evaluator(self, from_node, to_node): + """Returns the manhattan distance between the two nodes""" + return self._distances[from_node][to_node] - def distance_evaluator(self, from_node, to_node): - """Returns the manhattan distance between the two nodes""" - return self._distances[from_node][to_node] ########### # Printer # ########### class ConsolePrinter(): - """Print solution to console""" - def __init__(self, data, routing, assignment): - """Initializes the printer""" - self._data = data - self._routing = routing - self._assignment = assignment + """Print solution to console""" - @property - def data(self): - """Gets problem data""" - return self._data + def __init__(self, data, routing, assignment): + """Initializes the printer""" + self._data = data + self._routing = routing + self._assignment = assignment - @property - def routing(self): - """Gets routing model""" - return self._routing + @property + def data(self): + """Gets problem data""" + return self._data - @property - def assignment(self): - """Gets routing model""" - return self._assignment + @property + def routing(self): + """Gets routing model""" + return self._routing - def print(self): - """Prints assignment on console""" - # Inspect solution. - total_dist = 0 - for vehicle_id in xrange(self.data.num_vehicles): - index = self.routing.Start(vehicle_id) - plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) - route_dist = 0 - while not self.routing.IsEnd(index): - node_index = self.routing.IndexToNode(index) - next_node_index = self.routing.IndexToNode( - self.assignment.Value(self.routing.NextVar(index))) - route_dist += manhattan_distance( - self.data.locations[node_index], - self.data.locations[next_node_index]) - plan_output += ' {0} -> '.format(node_index) - index = self.assignment.Value(self.routing.NextVar(index)) + @property + def assignment(self): + """Gets routing model""" + return self._assignment + + def print(self): + """Prints assignment on console""" + # Inspect solution. + total_dist = 0 + for vehicle_id in xrange(self.data.num_vehicles): + index = self.routing.Start(vehicle_id) + plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) + route_dist = 0 + while not self.routing.IsEnd(index): + node_index = self.routing.IndexToNode(index) + next_node_index = self.routing.IndexToNode( + self.assignment.Value(self.routing.NextVar(index))) + route_dist += manhattan_distance(self.data.locations[node_index], + self.data.locations[next_node_index]) + plan_output += ' {0} -> '.format(node_index) + index = self.assignment.Value(self.routing.NextVar(index)) + + node_index = self.routing.IndexToNode(index) + total_dist += route_dist + plan_output += ' {0}\n'.format(node_index) + plan_output += 'Distance of the route: {0}m\n'.format(route_dist) + print(plan_output) + print('Total Distance of all routes: {0}m'.format(total_dist)) - node_index = self.routing.IndexToNode(index) - total_dist += route_dist - plan_output += ' {0}\n'.format(node_index) - plan_output += 'Distance of the route: {0}m\n'.format(route_dist) - print(plan_output) - print('Total Distance of all routes: {0}m'.format(total_dist)) ######## # Main # ######## def main(): - """Entry point of the program""" - # Instantiate the data problem. - data = DataProblem() + """Entry point of the program""" + # Instantiate the data problem. + data = DataProblem() - # Create Routing Model - routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, data.depot) - # Define weight of each edge - distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator - routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) + # Create Routing Model + routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, + data.depot) + # Define weight of each edge + distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator + routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) + + # Setting first solution heuristic (cheapest addition). + search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # Solve the problem. + assignment = routing.SolveWithParameters(search_parameters) + printer = ConsolePrinter(data, routing, assignment) + printer. print() - # Setting first solution heuristic (cheapest addition). - search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() - search_parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) - # Solve the problem. - assignment = routing.SolveWithParameters(search_parameters) - printer = ConsolePrinter(data, routing, assignment) - printer.print() if __name__ == '__main__': - main() + main() diff --git a/examples/python/vrpgs.py b/examples/python/vrpgs.py index 3e49df11be..0687de9dd9 100755 --- a/examples/python/vrpgs.py +++ b/examples/python/vrpgs.py @@ -13,9 +13,10 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """Vehicle Routing Problem (VRP). - This is a sample using the routing library python wrapper to solve a VRP problem. + + This is a sample using the routing library python wrapper to solve a VRP + problem. A description of the problem can be found here: http://en.wikipedia.org/wiki/Vehicle_routing_problem. @@ -31,184 +32,194 @@ from six.moves import xrange from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import routing_enums_pb2 + ########################### # Problem Data Definition # ########################### class CityBlock(): - """City block definition""" - @property - def width(self): - """Gets Block size West to East""" - return 228/2 + """City block definition""" + + @property + def width(self): + """Gets Block size West to East""" + return 228 / 2 + + @property + def height(self): + """Gets Block size North to South""" + return 80 - @property - def height(self): - """Gets Block size North to South""" - return 80 class DataProblem(): - """Stores the data for the problem""" - def __init__(self): - """Initializes the data for the problem""" - self._num_vehicles = 4 + """Stores the data for the problem""" - # Locations in block unit - locations = \ - [(4, 4), # depot - (2, 0), (8, 0), # row 0 - (0, 1), (1, 1), - (5, 2), (7, 2), - (3, 3), (6, 3), - (5, 5), (8, 5), - (1, 6), (2, 6), - (3, 7), (6, 7), - (0, 8), (7, 8)] - # locations in meters using the block dimension defined - city_block = CityBlock() - self._locations = [( - loc[0]*city_block.width, - loc[1]*city_block.height) for loc in locations] + def __init__(self): + """Initializes the data for the problem""" + self._num_vehicles = 4 - self._depot = 0 + # Locations in block unit + locations = \ + [(4, 4), # depot + (2, 0), (8, 0), # row 0 + (0, 1), (1, 1), + (5, 2), (7, 2), + (3, 3), (6, 3), + (5, 5), (8, 5), + (1, 6), (2, 6), + (3, 7), (6, 7), + (0, 8), (7, 8)] + # locations in meters using the block dimension defined + city_block = CityBlock() + self._locations = [(loc[0] * city_block.width, loc[1] * city_block.height) + for loc in locations] - @property - def num_vehicles(self): - """Gets number of vehicles""" - return self._num_vehicles + self._depot = 0 - @property - def locations(self): - """Gets locations""" - return self._locations + @property + def num_vehicles(self): + """Gets number of vehicles""" + return self._num_vehicles - @property - def num_locations(self): - """Gets number of locations""" - return len(self.locations) + @property + def locations(self): + """Gets locations""" + return self._locations + + @property + def num_locations(self): + """Gets number of locations""" + return len(self.locations) + + @property + def depot(self): + """Gets depot location index""" + return self._depot - @property - def depot(self): - """Gets depot location index""" - return self._depot ####################### # Problem Constraints # ####################### def manhattan_distance(position_1, position_2): - """Computes the Manhattan distance between two points""" - return (abs(position_1[0] - position_2[0]) + - abs(position_1[1] - position_2[1])) + """Computes the Manhattan distance between two points""" + return ( + abs(position_1[0] - position_2[0]) + abs(position_1[1] - position_2[1])) -class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods - """Creates callback to return distance between points.""" - def __init__(self, data): - """Initializes the distance matrix.""" - self._distances = {} - # precompute distance between location to have distance callback in O(1) - for from_node in xrange(data.num_locations): - self._distances[from_node] = {} - for to_node in xrange(data.num_locations): - if from_node == to_node: - self._distances[from_node][to_node] = 0 - else: - self._distances[from_node][to_node] = ( - manhattan_distance( - data.locations[from_node], - data.locations[to_node])) +class CreateDistanceEvaluator(object): # pylint: disable=too-few-public-methods + """Creates callback to return distance between points.""" + + def __init__(self, data): + """Initializes the distance matrix.""" + self._distances = {} + + # precompute distance between location to have distance callback in O(1) + for from_node in xrange(data.num_locations): + self._distances[from_node] = {} + for to_node in xrange(data.num_locations): + if from_node == to_node: + self._distances[from_node][to_node] = 0 + else: + self._distances[from_node][to_node] = ( + manhattan_distance(data.locations[from_node], + data.locations[to_node])) + + def distance_evaluator(self, from_node, to_node): + """Returns the manhattan distance between the two nodes""" + return self._distances[from_node][to_node] - def distance_evaluator(self, from_node, to_node): - """Returns the manhattan distance between the two nodes""" - return self._distances[from_node][to_node] def add_distance_dimension(routing, distance_evaluator): - """Add Global Span constraint""" - distance = "Distance" - routing.AddDimension( - distance_evaluator, - 0, # null slack - 3000, # maximum distance per vehicle - True, # start cumul to zero - distance) - distance_dimension = routing.GetDimensionOrDie(distance) - # Try to minimize the max distance among vehicles. - # /!\ It doesn't mean the standard deviation is minimized - distance_dimension.SetGlobalSpanCostCoefficient(100) + """Add Global Span constraint""" + distance = 'Distance' + routing.AddDimension( + distance_evaluator, + 0, # null slack + 3000, # maximum distance per vehicle + True, # start cumul to zero + distance) + distance_dimension = routing.GetDimensionOrDie(distance) + # Try to minimize the max distance among vehicles. + # /!\ It doesn't mean the standard deviation is minimized + distance_dimension.SetGlobalSpanCostCoefficient(100) + ########### # Printer # ########### class ConsolePrinter(): - """Print solution to console""" - def __init__(self, data, routing, assignment): - """Initializes the printer""" - self._data = data - self._routing = routing - self._assignment = assignment + """Print solution to console""" - @property - def data(self): - """Gets problem data""" - return self._data + def __init__(self, data, routing, assignment): + """Initializes the printer""" + self._data = data + self._routing = routing + self._assignment = assignment - @property - def routing(self): - """Gets routing model""" - return self._routing + @property + def data(self): + """Gets problem data""" + return self._data - @property - def assignment(self): - """Gets routing model""" - return self._assignment + @property + def routing(self): + """Gets routing model""" + return self._routing - def print(self): - """Prints assignment on console""" - # Inspect solution. - total_dist = 0 - for vehicle_id in xrange(self.data.num_vehicles): - index = self.routing.Start(vehicle_id) - plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) - route_dist = 0 - while not self.routing.IsEnd(index): - node_index = self.routing.IndexToNode(index) - next_node_index = self.routing.IndexToNode( - self.assignment.Value(self.routing.NextVar(index))) - route_dist += manhattan_distance( - self.data.locations[node_index], - self.data.locations[next_node_index]) - plan_output += ' {0} -> '.format(node_index) - index = self.assignment.Value(self.routing.NextVar(index)) + @property + def assignment(self): + """Gets routing model""" + return self._assignment + + def print(self): + """Prints assignment on console""" + # Inspect solution. + total_dist = 0 + for vehicle_id in xrange(self.data.num_vehicles): + index = self.routing.Start(vehicle_id) + plan_output = 'Route for vehicle {0}:\n'.format(vehicle_id) + route_dist = 0 + while not self.routing.IsEnd(index): + node_index = self.routing.IndexToNode(index) + next_node_index = self.routing.IndexToNode( + self.assignment.Value(self.routing.NextVar(index))) + route_dist += manhattan_distance(self.data.locations[node_index], + self.data.locations[next_node_index]) + plan_output += ' {0} -> '.format(node_index) + index = self.assignment.Value(self.routing.NextVar(index)) + + node_index = self.routing.IndexToNode(index) + total_dist += route_dist + plan_output += ' {0}\n'.format(node_index) + plan_output += 'Distance of the route: {0}m\n'.format(route_dist) + print(plan_output) + print('Total Distance of all routes: {0}m'.format(total_dist)) - node_index = self.routing.IndexToNode(index) - total_dist += route_dist - plan_output += ' {0}\n'.format(node_index) - plan_output += 'Distance of the route: {0}m\n'.format(route_dist) - print(plan_output) - print('Total Distance of all routes: {0}m'.format(total_dist)) ######## # Main # ######## def main(): - """Entry point of the program""" - # Instantiate the data problem. - data = DataProblem() + """Entry point of the program""" + # Instantiate the data problem. + data = DataProblem() - # Create Routing Model - routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, data.depot) - # Define weight of each edge - distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator - routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) - add_distance_dimension(routing, distance_evaluator) + # Create Routing Model + routing = pywrapcp.RoutingModel(data.num_locations, data.num_vehicles, + data.depot) + # Define weight of each edge + distance_evaluator = CreateDistanceEvaluator(data).distance_evaluator + routing.SetArcCostEvaluatorOfAllVehicles(distance_evaluator) + add_distance_dimension(routing, distance_evaluator) + + # Setting first solution heuristic (cheapest addition). + search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() + search_parameters.first_solution_strategy = ( + routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) + # Solve the problem. + assignment = routing.SolveWithParameters(search_parameters) + printer = ConsolePrinter(data, routing, assignment) + printer. print() - # Setting first solution heuristic (cheapest addition). - search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters() - search_parameters.first_solution_strategy = ( - routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC) - # Solve the problem. - assignment = routing.SolveWithParameters(search_parameters) - printer = ConsolePrinter(data, routing, assignment) - printer.print() if __name__ == '__main__': - main() + main() diff --git a/examples/python/wedding_optimal_chart.py b/examples/python/wedding_optimal_chart.py index e8360e03cd..00685a0553 100644 --- a/examples/python/wedding_optimal_chart.py +++ b/examples/python/wedding_optimal_chart.py @@ -16,10 +16,7 @@ from __future__ import print_function from ortools.constraint_solver import pywrapcp from ortools.constraint_solver import solver_parameters_pb2 - - -""" -Finding an optimal wedding seating chart. +"""Finding an optimal wedding seating chart. From Meghan L. Bellows and J. D. Luc Peterson @@ -39,141 +36,127 @@ be solved to find the optimal arrangement of guests at tables. At the very least, it can provide a starting point and hopefully minimize stress and arguments. -Adapted from https://github.com/google/or-tools/blob/master/examples/csharp/wedding_optimal_chart.cs +Adapted from +https://github.com/google/or-tools/blob/master/examples/csharp/wedding_optimal_chart.cs """ + + def main(): - # Instantiate a CP solver. - parameters = pywrapcp.Solver.DefaultSolverParameters() - solver = pywrapcp.Solver("WeddingOptimalChart", parameters) + # Instantiate a CP solver. + parameters = pywrapcp.Solver.DefaultSolverParameters() + solver = pywrapcp.Solver("WeddingOptimalChart", parameters) - # - # Data - # + # + # Data + # - # Easy problem (from the paper) - # n = 2 # number of tables - # a = 10 # maximum number of guests a table can seat - # b = 1 # minimum number of people each guest knows at their table + # Easy problem (from the paper) + # n = 2 # number of tables + # a = 10 # maximum number of guests a table can seat + # b = 1 # minimum number of people each guest knows at their table - # Slightly harder problem (also from the paper) - n = 5 # number of tables - a = 4 # maximum number of guests a table can seat - b = 1 # minimum number of people each guest knows at their table + # Slightly harder problem (also from the paper) + n = 5 # number of tables + a = 4 # maximum number of guests a table can seat + b = 1 # minimum number of people each guest knows at their table - # Connection matrix: who knows who, and how strong - # is the relation - C = [ - [ 1,50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1,50, 1, 1, 1, 1,10, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1,50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1,50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1,50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1, 1, 1,50, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1, 1,50, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1,10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,50, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0,50, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - ] + # Connection matrix: who knows who, and how strong + # is the relation + C = [[1, 50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 50, 1, 1, 1, 1, 10, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 1, 50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 1, 1, 1, 1, 50, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 50, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 50, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 1, 1, 1, 1, 1, 1, + 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]] - # Names of the guests. B: Bride side, G: Groom side - names = [ - "Deb (B)", - "John (B)", - "Martha (B)", - "Travis (B)", - "Allan (B)", - "Lois (B)", - "Jayne (B)", - "Brad (B)", - "Abby (B)", - "Mary Helen (G)", - "Lee (G)", - "Annika (G)", - "Carl (G)", - "Colin (G)", - "Shirley (G)", - "DeAnn (G)", - "Lori (G)" - ] + # Names of the guests. B: Bride side, G: Groom side + names = [ + "Deb (B)", "John (B)", "Martha (B)", "Travis (B)", "Allan (B)", + "Lois (B)", "Jayne (B)", "Brad (B)", "Abby (B)", "Mary Helen (G)", + "Lee (G)", "Annika (G)", "Carl (G)", "Colin (G)", "Shirley (G)", + "DeAnn (G)", "Lori (G)" + ] - m = len(C) + m = len(C) - NRANGE = range(n) - MRANGE = range(m) + NRANGE = range(n) + MRANGE = range(m) - # - # Decision variables - # - tables = [solver.IntVar(0, n-1, 'x[%i]' % i) for i in MRANGE] + # + # Decision variables + # + tables = [solver.IntVar(0, n - 1, "x[%i]" % i) for i in MRANGE] - z = solver.Sum([ C[j][k] * (tables[j] == tables[k]) - for j in MRANGE - for k in MRANGE if j < k]) + z = solver.Sum([ + C[j][k] * (tables[j] == tables[k]) + for j in MRANGE + for k in MRANGE + if j < k + ]) - # - # Constraints - # - for i in NRANGE: - minGuests = [ - (tables[j] == i) * (tables[k] == i) - for j in MRANGE - for k in MRANGE if j < k and C[j][k] > 0 - ] - solver.Add(solver.Sum(minGuests) >= b); + # + # Constraints + # + for i in NRANGE: + minGuests = [(tables[j] == i) * (tables[k] == i) + for j in MRANGE + for k in MRANGE + if j < k and C[j][k] > 0] + solver.Add(solver.Sum(minGuests) >= b) - maxGuests = [tables[j] == i for j in MRANGE] - solver.Add(solver.Sum(maxGuests) <= a); + maxGuests = [tables[j] == i for j in MRANGE] + solver.Add(solver.Sum(maxGuests) <= a) - # Symmetry breaking - solver.Add(tables[0] == 0) + # Symmetry breaking + solver.Add(tables[0] == 0) - # - # Objective - # - objective = solver.Maximize(z, 1) + # + # Objective + # + objective = solver.Maximize(z, 1) - # - # Search - # - db = solver.Phase(tables, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT); + # + # Search + # + db = solver.Phase(tables, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT) - solver.NewSearch(db, [objective]) + solver.NewSearch(db, [objective]) - while solver.NextSolution(): - print("z:", z) - print("Table: ") - for j in MRANGE: - print(tables[j].Value(), " "); - print() + while solver.NextSolution(): + print("z:", z) + print("Table: ") + for j in MRANGE: + print(tables[j].Value(), " ") + print() - for i in NRANGE: - print("Table %d: " % i); - for j in MRANGE: - if tables[j].Value() == i: - print(names[j] + " ") - print() + for i in NRANGE: + print("Table %d: " % i) + for j in MRANGE: + if tables[j].Value() == i: + print(names[j] + " ") + print() - print() + print() - solver.EndSearch() + solver.EndSearch() - print() - print("Solutions: %d" % solver.Solutions()) - print("WallTime: %dms" % solver.WallTime()) - print("Failures: %d" % solver.Failures()) - print("Branches: %d" % solver.Branches()) + print() + print("Solutions: %d" % solver.Solutions()) + print("WallTime: %dms" % solver.WallTime()) + print("Failures: %d" % solver.Failures()) + print("Branches: %d" % solver.Branches()) - - -if __name__ == '__main__': - main() +if __name__ == "__main__": + main() diff --git a/examples/python/wedding_optimal_chart_sat.py b/examples/python/wedding_optimal_chart_sat.py index d110f06ee8..6200a4ef35 100644 --- a/examples/python/wedding_optimal_chart_sat.py +++ b/examples/python/wedding_optimal_chart_sat.py @@ -16,10 +16,7 @@ from __future__ import print_function from ortools.sat.python import cp_model import time - - -""" -Finding an optimal wedding seating chart. +"""Finding an optimal wedding seating chart. From Meghan L. Bellows and J. D. Luc Peterson @@ -39,7 +36,8 @@ be solved to find the optimal arrangement of guests at tables. At the very least, it can provide a starting point and hopefully minimize stress and arguments. -Adapted from https://github.com/google/or-tools/blob/master/examples/csharp/wedding_optimal_chart.cs +Adapted from +https://github.com/google/or-tools/blob/master/examples/csharp/wedding_optimal_chart.cs """ @@ -57,15 +55,15 @@ class WeddingChartPrinter(cp_model.CpSolverSolutionCallback): def NewSolution(self): current_time = time.time() objective = self.ObjectiveValue() - print('Solution %i, time = %f s, objective = %i' % + print("Solution %i, time = %f s, objective = %i" % (self.__solution_count, current_time - self.__start_time, objective)) self.__solution_count += 1 for t in range(self.__num_tables): - print("Table %d: " % t); + print("Table %d: " % t) for g in range(self.__num_guests): if self.Value(self.__seats[(t, g)]): - print(' ' + self.__names[g]) + print(" " + self.__names[g]) def NumSolutions(self): return self.__solution_count @@ -88,45 +86,30 @@ def BuildData(): # Connection matrix: who knows who, and how strong # is the relation - C = [ - [ 1,50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1,50, 1, 1, 1, 1,10, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1,50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1,50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1,50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1, 1, 1,50, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1, 1, 1, 1, 1,50, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 1, 1,10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,50, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0,50, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - ] + C = [[1, 50, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [50, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 50, 1, 1, 1, 1, 10, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 50, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 50, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 1, 50, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 1, 1, 1, 1, 1, 50, 1, 0, 0, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 50, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [1, 1, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 50, 1, 1, 1, 1, 1, 1], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 1, 1, 1, 1, 1, 1, + 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 + ], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1]] # Names of the guests. B: Bride side, G: Groom side - names = [ - "Deb (B)", - "John (B)", - "Martha (B)", - "Travis (B)", - "Allan (B)", - "Lois (B)", - "Jayne (B)", - "Brad (B)", - "Abby (B)", - "Mary Helen (G)", - "Lee (G)", - "Annika (G)", - "Carl (G)", - "Colin (G)", - "Shirley (G)", - "DeAnn (G)", - "Lori (G)" + names = [ + "Deb (B)", "John (B)", "Martha (B)", "Travis (B)", "Allan (B)", + "Lois (B)", "Jayne (B)", "Brad (B)", "Abby (B)", "Mary Helen (G)", + "Lee (G)", "Annika (G)", "Carl (G)", "Colin (G)", "Shirley (G)", + "DeAnn (G)", "Lori (G)" ] return num_tables, table_capacity, min_known_neighbors, C, names @@ -148,26 +131,27 @@ def SolveWithDiscreteModel(): seats = {} for t in all_tables: for g in all_guests: - seats[(t, g)] = model.NewBoolVar('guest %i seats on table %i' % (g, t)) + seats[(t, g)] = model.NewBoolVar("guest %i seats on table %i" % (g, t)) colocated = {} for g1 in range(num_guests - 1): for g2 in range(g1 + 1, num_guests): colocated[(g1, g2)] = model.NewBoolVar( - 'guest %i seats with guest %i' % (g1, g2)) + "guest %i seats with guest %i" % (g1, g2)) same_table = {} for g1 in range(num_guests - 1): for g2 in range(g1 + 1, num_guests): for t in all_tables: same_table[(g1, g2, t)] = model.NewBoolVar( - 'guest %i seats with guest %i on table %i' % (g1, g2, t)) + "guest %i seats with guest %i on table %i" % (g1, g2, t)) # Objective - model.Maximize(sum(C[g1][g2] * colocated[g1, g2] - for g1 in range(num_guests - 1) - for g2 in range(g1 + 1, num_guests) - if C[g1][g2] > 0)) + model.Maximize( + sum(C[g1][g2] * colocated[g1, g2] + for g1 in range(num_guests - 1) + for g2 in range(g1 + 1, num_guests) + if C[g1][g2] > 0)) # # Constraints @@ -186,23 +170,24 @@ def SolveWithDiscreteModel(): for g2 in range(g1 + 1, num_guests): for t in all_tables: # Link same_table and seats. - model.AddBoolOr([seats[(t, g1)].Not(), - seats[(t, g2)].Not(), - same_table[(g1, g2, t)]]) + model.AddBoolOr([ + seats[(t, g1)].Not(), seats[(t, g2)].Not(), same_table[(g1, g2, t)] + ]) model.AddImplication(same_table[(g1, g2, t)], seats[(t, g1)]) model.AddImplication(same_table[(g1, g2, t)], seats[(t, g2)]) # Link colocated and same_table. - model.Add(sum(same_table[(g1, g2, t)] - for t in all_tables) == colocated[(g1, g2)]) + model.Add( + sum(same_table[(g1, g2, t)] for t in all_tables) == colocated[(g1, + g2)]) # Min known neighbors rule. for t in all_tables: - model.Add(sum(same_table[(g1, g2, t)] - for g1 in range(num_guests - 1) - for g2 in range(g1 + 1, num_guests) - for t in all_tables - if C[g1][g2] > 0) >= min_known_neighbors) + model.Add( + sum(same_table[(g1, g2, t)] for g1 in range(num_guests - 1) + for g2 in range(g1 + 1, num_guests) + for t in all_tables + if C[g1][g2] > 0) >= min_known_neighbors) # Symmetry breaking. First guest seats on the first table. model.Add(seats[(0, 0)] == 1) @@ -212,16 +197,16 @@ def SolveWithDiscreteModel(): solution_printer = WeddingChartPrinter(seats, names, num_tables, num_guests) status = solver.SolveWithSolutionObserver(model, solution_printer) - print('Statistics') - print(' - conflicts : %i' % solver.NumConflicts()) - print(' - branches : %i' % solver.NumBranches()) - print(' - wall time : %f ms' % solver.WallTime()) - print(' - num solutions: %i' % solution_printer.NumSolutions()) + print("Statistics") + print(" - conflicts : %i" % solver.NumConflicts()) + print(" - branches : %i" % solver.NumBranches()) + print(" - wall time : %f ms" % solver.WallTime()) + print(" - num solutions: %i" % solution_printer.NumSolutions()) def main(): SolveWithDiscreteModel() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/examples/python/who_killed_agatha.py b/examples/python/who_killed_agatha.py index 0c2f24b949..6e8398d0c1 100644 --- a/examples/python/who_killed_agatha.py +++ b/examples/python/who_killed_agatha.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Who killed agatha? (The Dreadsbury Mansion Murder Mystery) in Google CP @@ -83,7 +82,7 @@ def flatten_matrix(solver, m, rows, cols): def print_flat_matrix(m_flat, rows, cols): for i in range(rows): for j in range(cols): - print(m_flat[i * cols + j].Value(), end=' ') + print(m_flat[i * cols + j].Value(), end=" ") print() print() @@ -180,8 +179,7 @@ def main(the_killers): solution.Add(richer_flat) # db: DecisionBuilder - db = solver.Phase(hates_flat + richer_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(hates_flat + richer_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) diff --git a/examples/python/word_square.py b/examples/python/word_square.py index 8c2ff42b25..0d20730ea7 100644 --- a/examples/python/word_square.py +++ b/examples/python/word_square.py @@ -12,7 +12,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """ Word square in Google CP Solver. @@ -84,8 +83,9 @@ def main(words, word_len, num_answers=20): # solver.Add(A[(E[i],j)] == A[(E[j],i)]) # We must use Element explicitly - solver.Add(solver.Element(A_flat, E[i] * word_len + j) == - solver.Element(A_flat, E[j] * word_len + i)) + solver.Add( + solver.Element(A_flat, E[i] * word_len + + j) == solver.Element(A_flat, E[j] * word_len + i)) # # solution and search @@ -94,8 +94,7 @@ def main(words, word_len, num_answers=20): solution.Add(E) # db: DecisionBuilder - db = solver.Phase(E + A_flat, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(E + A_flat, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -145,8 +144,7 @@ def read_words(word_list, word_len, limit): w = w.strip().lower() # if len(w) == word_len and not dict.has_key(w) and not re.search("[^a-zåäö]",w) and count < limit: # Later note: The limit is not needed anymore with Mistral - if len(w) == word_len and w not in dict and not re.search( - "[^a-zåäö]", w): + if len(w) == word_len and w not in dict and not re.search("[^a-zåäö]", w): dict[w] = 1 all_words.append(w) count += 1 diff --git a/examples/python/worker_schedule_sat.py b/examples/python/worker_schedule_sat.py index e00f08e12d..b47a781b44 100644 --- a/examples/python/worker_schedule_sat.py +++ b/examples/python/worker_schedule_sat.py @@ -114,13 +114,15 @@ def schedule(): # Model the problem. model = cp_model.CpModel() - workers_per_shift = [model.NewIntVar(0, num_workers, 'shift[%i]' % i) - for i in all_shifts] + workers_per_shift = [ + model.NewIntVar(0, num_workers, 'shift[%i]' % i) for i in all_shifts + ] # Satisfy min requirements. for slot in all_slots: - model.Add(sum(workers_per_shift[shift] * possible_shifts[shift][slot] - for shift in all_shifts) >= min_number_of_workers[slot]) + model.Add( + sum(workers_per_shift[shift] * possible_shifts[shift][slot] + for shift in all_shifts) >= min_number_of_workers[slot]) # Create the objective variable. objective = model.NewIntVar(0, num_workers, 'objective') diff --git a/examples/python/xkcd.py b/examples/python/xkcd.py index e34d130a70..285eb1067e 100644 --- a/examples/python/xkcd.py +++ b/examples/python/xkcd.py @@ -53,8 +53,10 @@ def main(): price = [215, 275, 335, 355, 420, 580] total = 1505 - products = ["mixed fruit", "french fries", "side salad", - "host wings", "mozzarella sticks", "samples place"] + products = [ + "mixed fruit", "french fries", "side salad", "host wings", + "mozzarella sticks", "samples place" + ] # declare variables @@ -78,10 +80,9 @@ def main(): collector = solver.AllSolutionCollector(solution) # collector = solver.FirstSolutionCollector(solution) # search_log = solver.SearchLog(100, x[0]) - solver.Solve(solver.Phase([x[i] for i in range(num_prices)], - solver.INT_VAR_SIMPLE, - solver.ASSIGN_MIN_VALUE), - [collector]) + solver.Solve( + solver.Phase([x[i] for i in range(num_prices)], solver.INT_VAR_SIMPLE, + solver.ASSIGN_MIN_VALUE), [collector]) num_solutions = collector.SolutionCount() print("num_solutions: ", num_solutions) diff --git a/examples/python/young_tableaux.py b/examples/python/young_tableaux.py index bbae9ea1c1..085ce02211 100644 --- a/examples/python/young_tableaux.py +++ b/examples/python/young_tableaux.py @@ -110,8 +110,8 @@ def main(n=5): # calculate the structure (the partition) for i in range(n): - # MiniZinc/Zinc version: - # p[i] == sum(j in 1..n) (bool2int(x[i,j] <= n)) + # MiniZinc/Zinc version: + # p[i] == sum(j in 1..n) (bool2int(x[i,j] <= n)) b = [solver.IsLessOrEqualCstVar(x[(i, j)], n) for j in range(n)] solver.Add(p[i] == solver.Sum(b)) @@ -129,8 +129,7 @@ def main(n=5): solution.Add(p) # db: DecisionBuilder - db = solver.Phase(x_flat + p, - solver.CHOOSE_FIRST_UNBOUND, + db = solver.Phase(x_flat + p, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE) solver.NewSearch(db) @@ -142,7 +141,7 @@ def main(n=5): for j in range(n): val = x_flat[i * n + j].Value() if val <= n: - print(val, end=' ') + print(val, end=" ") if p[i].Value() > 0: print() print() @@ -156,6 +155,7 @@ def main(n=5): print("branches:", solver.Branches()) print("WallTime:", solver.WallTime()) + n = 5 if __name__ == "__main__": if len(sys.argv) > 1: diff --git a/examples/python/zebra.py b/examples/python/zebra.py index 11f05ce179..0d44867643 100644 --- a/examples/python/zebra.py +++ b/examples/python/zebra.py @@ -10,7 +10,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - """This is the zebra problem as invented by Lewis Caroll. There are five houses. @@ -73,13 +72,14 @@ def main(): parliaments = solver.IntVar(1, 5, 'parliaments') solver.Add(solver.AllDifferent([red, green, yellow, blue, ivory])) - solver.Add(solver.AllDifferent([englishman, spaniard, japanese, - ukrainian, norwegian])) + solver.Add( + solver.AllDifferent( + [englishman, spaniard, japanese, ukrainian, norwegian])) solver.Add(solver.AllDifferent([dog, snails, fox, zebra, horse])) - solver.Add(solver.AllDifferent([tea, coffee, water, milk, - fruit_juice])) - solver.Add(solver.AllDifferent([parliaments, kools, chesterfields, - lucky_strike, old_gold])) + solver.Add(solver.AllDifferent([tea, coffee, water, milk, fruit_juice])) + solver.Add( + solver.AllDifferent( + [parliaments, kools, chesterfields, lucky_strike, old_gold])) solver.Add(englishman == red) solver.Add(spaniard == dog) @@ -96,15 +96,14 @@ def main(): solver.Add(japanese == parliaments) solver.Add(abs(norwegian - blue) == 1) - all_vars = [parliaments, kools, chesterfields, lucky_strike, old_gold, - englishman, spaniard, japanese, ukrainian, norwegian, - dog, snails, fox, zebra, horse, - tea, coffee, water, milk, fruit_juice, - red, green, yellow, blue, ivory] + all_vars = [ + parliaments, kools, chesterfields, lucky_strike, old_gold, englishman, + spaniard, japanese, ukrainian, norwegian, dog, snails, fox, zebra, horse, + tea, coffee, water, milk, fruit_juice, red, green, yellow, blue, ivory + ] - solver.NewSearch(solver.Phase(all_vars, - solver.INT_VAR_DEFAULT, - solver.INT_VALUE_DEFAULT)) + solver.NewSearch( + solver.Phase(all_vars, solver.INT_VAR_DEFAULT, solver.INT_VALUE_DEFAULT)) if solver.NextSolution(): people = [englishman, spaniard, japanese, ukrainian, norwegian] water_drinker = [p for p in people if p.Value() == water.Value()][0]