Skip to content

Commit

Permalink
polish python examples: use string interpolations; remove many mypy w…
Browse files Browse the repository at this point in the history
…arnings
  • Loading branch information
lperron committed Jul 25, 2024
1 parent c0c709c commit 1430011
Show file tree
Hide file tree
Showing 21 changed files with 287 additions and 302 deletions.
2 changes: 0 additions & 2 deletions examples/python/arc_flow_cutting_stock_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from ortools.linear_solver.python import model_builder as mb
from ortools.sat.python import cp_model

FLAGS = flags.FLAGS

_OUTPUT_PROTO = flags.DEFINE_string(
"output_proto", "", "Output file to write the cp_model proto to."
Expand Down Expand Up @@ -225,7 +224,6 @@ def create_state_graph(items, max_capacity):
new_state = current_state + size * (card + 1)
if new_state > max_capacity:
break
new_state_index = -1
if new_state in state_to_index:
new_state_index = state_to_index[new_state]
else:
Expand Down
28 changes: 11 additions & 17 deletions examples/python/assignment_with_constraints_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,24 @@ def solve_assignment():
[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
[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
[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
[1, 0, 0, 1], # Workers 8, 11
]

sizes = [10, 7, 3, 12, 15, 4, 11, 5]
total_size_max = 15
Expand All @@ -73,10 +73,9 @@ def solve_assignment():
model = cp_model.CpModel()
# Variables
selected = [
[model.new_bool_var("x[%i,%i]" % (i, j)) for j in all_tasks]
for i in all_workers
[model.new_bool_var(f"x[{i},{j}]") for j in all_tasks] for i in all_workers
]
works = [model.new_bool_var("works[%i]" % i) for i in all_workers]
works = [model.new_bool_var(f"works[{i}]") for i in all_workers]

# Constraints

Expand Down Expand Up @@ -107,21 +106,16 @@ def solve_assignment():
status = solver.solve(model)

if status == cp_model.OPTIMAL:
print("Total cost = %i" % solver.objective_value)
print(f"Total cost = {solver.objective_value}")
print()
for i in all_workers:
for j in all_tasks:
if solver.boolean_value(selected[i][j]):
print(
"Worker ", i, " assigned to task ", j, " Cost = ", cost[i][j]
)
print(f"Worker {i} assigned to task {j} with Cost = {cost[i][j]}")

print()

print("Statistics")
print(" - conflicts : %i" % solver.num_conflicts)
print(" - branches : %i" % solver.num_branches)
print(" - wall time : %f s" % solver.wall_time)
print(solver.response_stats())


def main(argv: Sequence[str]) -> None:
Expand Down
25 changes: 11 additions & 14 deletions examples/python/balance_group_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ def __init__(self, values, colors, all_groups, all_items, item_in_group):
self.__item_in_group = item_in_group

def on_solution_callback(self):
print("Solution %i" % self.__solution_count)
print(f"Solution {self.__solution_count}")
self.__solution_count += 1

print(" objective value = %i" % self.objective_value)
print(f" objective value = {self.objective_value}")
groups = {}
sums = {}
for g in self.__all_groups:
Expand All @@ -56,11 +56,11 @@ def on_solution_callback(self):

for g in self.__all_groups:
group = groups[g]
print("group %i: sum = %0.2f [" % (g, sums[g]), end="")
print(f"group {g}: sum = {sums[g]:0.2f} [", end="")
for item in group:
value = self.__values[item]
color = self.__colors[item]
print(" (%i, %i, %i)" % (item, value, color), end="")
print(f" ({item}, {value}, {color})", end="")
print("]")


Expand Down Expand Up @@ -97,7 +97,9 @@ def main(argv: Sequence[str]) -> None:
if colors[i] == color:
items_per_color[color].append(i)

print(f"Model has {num_items} items, {num_groups} groups, and {num_colors} colors")
print(
f"Model has {num_items} items, {num_groups} groups, and" f" {num_colors} colors"
)
print(f" average sum per group = {average_sum_per_group}")

# Model.
Expand All @@ -107,7 +109,7 @@ def main(argv: Sequence[str]) -> None:
item_in_group = {}
for i in all_items:
for g in all_groups:
item_in_group[(i, g)] = model.new_bool_var("item %d in group %d" % (i, g))
item_in_group[(i, g)] = model.new_bool_var(f"item {i} in group {g}")

# Each group must have the same size.
for g in all_groups:
Expand Down Expand Up @@ -135,9 +137,7 @@ def main(argv: Sequence[str]) -> None:
color_in_group = {}
for g in all_groups:
for c in all_colors:
color_in_group[(c, g)] = model.new_bool_var(
"color %d is in group %d" % (c, g)
)
color_in_group[(c, g)] = model.new_bool_var(f"color {c} is in group {g}")

# Item is in a group implies its color is in that group.
for i in all_items:
Expand Down Expand Up @@ -174,11 +174,8 @@ def main(argv: Sequence[str]) -> None:
status = solver.solve(model, solution_printer)

if status == cp_model.OPTIMAL:
print("Optimal epsilon: %i" % solver.objective_value)
print("Statistics")
print(" - conflicts : %i" % solver.num_conflicts)
print(" - branches : %i" % solver.num_branches)
print(" - wall time : %f s" % solver.wall_time)
print(f"Optimal epsilon: {solver.objective_value}")
print(solver.response_stats())
else:
print("No solution found")

Expand Down
36 changes: 18 additions & 18 deletions examples/python/chemical_balance_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,24 +89,24 @@ def chemical_balance():
# Creates a solver and solves.
solver = cp_model.CpSolver()
status = solver.solve(model)
print(f"Status = {solver.status_name(status)}")
# The objective value of the solution.
print(f"Optimal objective value = {solver.objective_value / 10000.0}")

for s in all_sets:
print(
f" {chemical_set[s][0]} = {solver.value(set_vars[s]) / 1000.0}",
end=" ",
)
print()
for p in all_products:
name = max_quantities[p][0]
max_quantity = max_quantities[p][1]
quantity = sum(
solver.value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]
for s in all_sets
)
print(f"{name}: {quantity} out of {max_quantity}")
if status == cp_model.OPTIMAL:
# The objective value of the solution.
print(f"Optimal objective value = {solver.objective_value / 10000.0}")

for s in all_sets:
print(
f" {chemical_set[s][0]} = {solver.value(set_vars[s]) / 1000.0}",
end=" ",
)
print()
for p in all_products:
name = max_quantities[p][0]
max_quantity = max_quantities[p][1]
quantity = sum(
solver.value(set_vars[s]) / 1000.0 * chemical_set[s][p + 1]
for s in all_sets
)
print(f"{name}: {quantity:.3f} out of {max_quantity}")


def main(argv: Sequence[str]) -> None:
Expand Down
55 changes: 26 additions & 29 deletions examples/python/flexible_job_shop_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
class SolutionPrinter(cp_model.CpSolverSolutionCallback):
"""Print intermediate solutions."""

def __init__(self):
def __init__(self) -> None:
cp_model.CpSolverSolutionCallback.__init__(self)
self.__solution_count = 0

def on_solution_callback(self):
def on_solution_callback(self) -> None:
"""Called at each new solution."""
print(
"Solution %i, time = %f s, objective = %i"
% (self.__solution_count, self.wall_time, self.objective_value)
f"Solution {self.__solution_count}, time = {self.wall_time} s,"
f" objective = {self.objective_value}"
)
self.__solution_count += 1

Expand Down Expand Up @@ -84,7 +84,7 @@ def flexible_jobshop() -> None:
max_task_duration = max(max_task_duration, alternative[0])
horizon += max_task_duration

print("Horizon = %i" % horizon)
print(f"Horizon = {horizon}")

# Global storage of variables.
intervals_per_resources = collections.defaultdict(list)
Expand Down Expand Up @@ -112,7 +112,7 @@ def flexible_jobshop() -> None:
max_duration = max(max_duration, alt_duration)

# Create main interval for the task.
suffix_name = "_j%i_t%i" % (job_id, task_id)
suffix_name = f"_j{job_id}_t{task_id}"
start = model.new_int_var(0, horizon, "start" + suffix_name)
duration = model.new_int_var(
min_duration, max_duration, "duration" + suffix_name
Expand All @@ -134,7 +134,7 @@ def flexible_jobshop() -> None:
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)
alt_suffix = f"_j{job_id}_t{task_id}_a{alt_id}"
l_presence = model.new_bool_var("presence" + alt_suffix)
l_start = model.new_int_var(0, horizon, "start" + alt_suffix)
l_duration = task[alt_id][0]
Expand Down Expand Up @@ -181,28 +181,25 @@ def flexible_jobshop() -> None:
status = solver.solve(model, solution_printer)

# Print final solution.
for job_id in all_jobs:
print(f"Job {job_id}")
for task_id in range(len(jobs[job_id])):
start_value = solver.value(starts[(job_id, task_id)])
machine: int = -1
task_duration: int = -1
selected: int = -1
for alt_id in range(len(jobs[job_id][task_id])):
if solver.boolean_value(presences[(job_id, task_id, alt_id)]):
task_duration = jobs[job_id][task_id][alt_id][0]
machine = jobs[job_id][task_id][alt_id][1]
selected = alt_id
print(
f" task_{job_id}_{task_id} starts at {start_value} (alt {selected}, machine {machine}, duration {task_duration})"
)

print(f"solve status: {solver.status_name(status)}")
print(f"Optimal objective value: {solver.objective_value}")
print("Statistics")
print(f" - conflicts : {solver.num_conflicts}")
print(f" - branches : {solver.num_branches}")
print(f" - wall time : {solver.wall_time} s")
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
print(f"Optimal objective value: {solver.objective_value}")
for job_id in all_jobs:
print(f"Job {job_id}")
for task_id, task in enumerate(jobs[job_id]):
start_value = solver.value(starts[(job_id, task_id)])
machine: int = -1
task_duration: int = -1
selected: int = -1
for alt_id, alt in enumerate(task):
if solver.boolean_value(presences[(job_id, task_id, alt_id)]):
task_duration, machine = alt
selected = alt_id
print(
f" task_{job_id}_{task_id} starts at {start_value} (alt"
f" {selected}, machine {machine}, duration {task_duration})"
)

print(solver.response_stats())


flexible_jobshop()
8 changes: 3 additions & 5 deletions examples/python/gate_scheduling_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,10 @@ def main(_) -> None:
performed_machine = 1 - solver.value(performed[i])
start_of_task = solver.value(starts[i])
print(
f" - Job {i} starts at {start_of_task} on machine {performed_machine}"
f" - Job {i} starts at {start_of_task} on machine"
f" {performed_machine}"
)
print("Statistics")
print(f" - conflicts : {solver.num_conflicts}")
print(f" - branches : {solver.num_branches}")
print(f" - wall time : {solver.wall_time} s")
print(solver.response_stats())


if __name__ == "__main__":
Expand Down
7 changes: 1 addition & 6 deletions examples/python/golomb_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,13 @@ def solve_golomb_ruler(order: int, params: str) -> None:
status = solver.solve(model, solution_printer)

# Print solution.
print(f"status: {solver.status_name(status)}")
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
for idx, var in enumerate(marks):
print(f"mark[{idx}]: {solver.value(var)}")
intervals = [solver.value(diff) for diff in diffs]
intervals.sort()
print(f"intervals: {intervals}")

print("Statistics:")
print(f"- conflicts: {solver.num_conflicts}")
print(f"- branches : {solver.num_branches}")
print(f"- wall time: {solver.wall_time}s\n")
print(solver.response_stats())


def main(argv: Sequence[str]) -> None:
Expand Down
17 changes: 7 additions & 10 deletions examples/python/hidato_sat.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def print_matrix(game: list[list[int]]) -> None:
if game[i][j] == 0:
line += " ."
else:
line += "% 3s" % game[i][j]
line += f"{game[i][j]:3}"
print(line)


Expand Down Expand Up @@ -102,7 +102,7 @@ def build_puzzle(problem: int) -> Union[None, list[list[int]]]:

elif problem == 3:
# Problems from the book:
# Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles"
# Gyora Bededek: 'Hidato: 2000 Pure Logic Puzzles'
# Problem 1 (Practice)
puzzle = [
[0, 0, 20, 0, 0],
Expand Down Expand Up @@ -156,15 +156,15 @@ def solve_hidato(puzzle: list[list[int]], index: int) -> None:
c = len(puzzle[0])
if not visualization.RunFromIPython():
print("")
print("----- Solving problem %i -----" % index)
print(f"----- Solving problem {index} -----")
print("")
print(("Initial game (%i x %i)" % (r, c)))
print(f"Initial game ({r} x {c})")
print_matrix(puzzle)

#
# Declare variables.
#
positions = [model.new_int_var(0, r * c - 1, "p[%i]" % i) for i in range(r * c)]
positions = [model.new_int_var(0, r * c - 1, f"p[{i}]") for i in range(r * c)]

#
# Constraints.
Expand Down Expand Up @@ -202,18 +202,15 @@ def solve_hidato(puzzle: list[list[int]], index: int) -> None:
color = "white" if puzzle[y][x] == 0 else "lightgreen"
output.AddRectangle(x, r - y - 1, 1, 1, color, "black", str(i + 1))

output.AddTitle("Puzzle %i solved in %f s" % (index, solver.wall_time))
output.AddTitle(f"Puzzle {index} solved in {solver.wall_time:.2f} s")
output.Display()
else:
print_solution(
[solver.value(x) for x in positions],
r,
c,
)
print("Statistics")
print(" - conflicts : %i" % solver.num_conflicts)
print(" - branches : %i" % solver.num_branches)
print(" - wall time : %f s" % solver.wall_time)
print(solver.response_stats())


def main(_):
Expand Down
Loading

0 comments on commit 1430011

Please sign in to comment.