add new python example; add simple typing annotations

This commit is contained in:
Laurent Perron
2024-07-23 14:07:41 +02:00
parent 08e9085d36
commit 905770c995
24 changed files with 111 additions and 27 deletions

View File

@@ -54,6 +54,8 @@ code_sample_test_arg_py(
suffix = "salbp_20_1",
)
code_sample_py("maximize_combinations_sat")
code_sample_py("maze_escape_sat")
code_sample_py("no_wait_baking_scheduling_sat")

View File

@@ -65,7 +65,7 @@ distance_matrix = [
]
def clustering_sat():
def clustering_sat() -> None:
"""Entry point of the program."""
num_nodes = len(distance_matrix)
print("Num nodes =", num_nodes)

View File

@@ -19,7 +19,7 @@ from absl import app
from ortools.sat.python import cp_model
def send_more_money():
def send_more_money() -> None:
"""solve the cryptarithmic puzzle SEND+MORE=MONEY."""
model = cp_model.CpModel()
@@ -74,7 +74,7 @@ def send_more_money():
print("y:", solver.value(y))
def main(_):
def main(_) -> None:
send_more_money()

View File

@@ -46,7 +46,7 @@ class SolutionPrinter(cp_model.CpSolverSolutionCallback):
self.__solution_count += 1
def flexible_jobshop():
def flexible_jobshop() -> None:
"""solve a small flexible jobshop problem."""
# Data part.
jobs = [ # task = (processing_time, machine_id)

View File

@@ -29,7 +29,7 @@ from ortools.sat.colab import visualization
from ortools.sat.python import cp_model
def main(_):
def main(_) -> None:
"""Solves the gate scheduling problem."""
model = cp_model.CpModel()

View File

@@ -30,7 +30,7 @@ from ortools.constraint_solver import pywrapcp
# pylint: disable=g-explicit-bool-comparison
def main(_):
def main(_) -> None:
# Create the solver.
solver = pywrapcp.Solver("golomb ruler")

View File

@@ -38,7 +38,7 @@ _PARAMS = flags.DEFINE_string(
)
def solve_golomb_ruler(order: int, params: str):
def solve_golomb_ruler(order: int, params: str) -> None:
"""Solve the Golomb ruler problem."""
# Create the model.
model = cp_model.CpModel()

View File

@@ -147,7 +147,7 @@ def build_puzzle(problem: int) -> Union[None, list[list[int]]]:
return puzzle
def solve_hidato(puzzle: list[list[int]], index: int):
def solve_hidato(puzzle: list[list[int]], index: int) -> None:
"""solve the given hidato table."""
# Create the model.
model = cp_model.CpModel()

View File

@@ -36,7 +36,7 @@ def distance_between_jobs(x: int, y: int) -> int:
return abs(x - y)
def jobshop_ft06_distance():
def jobshop_ft06_distance() -> None:
"""Solves the ft06 jobshop with distances between tasks."""
# Creates the model.
model = cp_model.CpModel()

View File

@@ -36,7 +36,7 @@ class SolutionPrinter(cp_model.CpSolverSolutionCallback):
self.__solution_count += 1
def jobshop_with_maintenance():
def jobshop_with_maintenance() -> None:
"""Solves a jobshop with maintenance on one machine."""
# Create the model.
model = cp_model.CpModel()

View File

@@ -71,7 +71,9 @@ def build_data() -> tuple[pd.Series, int, int]:
return (data, max_height, max_width)
def solve_with_duplicate_items(data: pd.Series, max_height: int, max_width: int):
def solve_with_duplicate_items(
data: pd.Series, max_height: int, max_width: int
) -> None:
"""solve the problem by building 2 items (rotated or not) for each item."""
# Derived data (expanded to individual items).
data_widths = data["width"].to_numpy()

View File

@@ -115,7 +115,7 @@ def read_model(filename):
return model
def print_stats(model):
def print_stats(model) -> None:
print("Model Statistics")
for key, value in model.items():
print(f" - {key}: {value}")
@@ -183,7 +183,7 @@ def solve_model_greedily(model):
return assignment
def solve_boolean_model(model, hint):
def solve_boolean_model(model, hint) -> None:
"""solve the given model."""
print("Solving using the Boolean model")

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
# Copyright 2010-2024 Google LLC
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Maximize the number of valid combinations of Boolean variables."""
from typing import Sequence
from absl import app
from ortools.sat.python import cp_model
def maximize_combinations_sat() -> None:
"""Maximize the number of valid combinations of Boolean variables."""
model = cp_model.CpModel()
cards: list[cp_model.IntVar] = [
model.new_bool_var("card1"),
model.new_bool_var("card2"),
model.new_bool_var("card3"),
model.new_bool_var("card4"),
]
combos: list[list[cp_model.IntVar]] = [
[cards[0], cards[1]],
[cards[0], cards[2]],
[cards[1], cards[3]],
[cards[0], cards[2], cards[3]],
]
deck_size: int = 3
model.add(sum(cards) == deck_size)
valid_combos: list[cp_model.IntVar] = []
for combination in combos:
is_valid = model.new_bool_var("")
# All true implies is_valid.
model.add_bool_and(is_valid).only_enforce_if(combination)
# is_valid implies all true.
for literal in combination:
model.add_implication(is_valid, literal)
valid_combos.append(is_valid)
model.maximize(sum(valid_combos))
solver = cp_model.CpSolver()
solver.parameters.log_search_progress = True
status = solver.solve(model)
if status == cp_model.OPTIMAL:
print(
"chosen cards:",
[card.name for card in cards if solver.boolean_value(card)],
)
def main(argv: Sequence[str]) -> None:
if len(argv) > 1:
raise app.UsageError("Too many command-line arguments.")
maximize_combinations_sat()
if __name__ == "__main__":
app.run(main)

View File

@@ -35,7 +35,9 @@ _PARAMS = flags.DEFINE_string(
)
def add_neighbor(size, x, y, z, dx, dy, dz, model, index_map, position_to_rank, arcs):
def add_neighbor(
size, x, y, z, dx, dy, dz, model, index_map, position_to_rank, arcs
) -> None:
"""Checks if the neighbor is valid, and adds it to the model."""
if (
x + dx < 0
@@ -55,7 +57,7 @@ def add_neighbor(size, x, y, z, dx, dy, dz, model, index_map, position_to_rank,
arcs.append((before_index, after_index, move_literal))
def escape_the_maze(params, output_proto):
def escape_the_maze(params, output_proto) -> None:
"""Escapes the maze."""
size = 4
boxes = [(0, 1, 0), (2, 0, 1), (1, 3, 1), (3, 1, 3)]

View File

@@ -21,7 +21,8 @@ We are scheduling a full day of baking:
"""
import collections
from typing import Sequence
from typing import List, Sequence, Tuple
from absl import app
from absl import flags
@@ -124,7 +125,7 @@ class Order:
self.quantity = quantity
def set_up_data():
def set_up_data() -> Tuple[List[Recipe], List[Resource], List[Order]]:
"""Set up the bakery problem data."""
# Recipes.
@@ -193,7 +194,9 @@ def set_up_data():
return recipes, resources, orders
def solve_with_cp_sat(recipes, resources, orders):
def solve_with_cp_sat(
recipes: List[Recipe], resources: List[Resource], orders: List[Order]
) -> None:
"""Build the optimization model, and solve the problem."""
model = cp_model.CpModel()

View File

@@ -25,7 +25,7 @@ _COEFF = flags.DEFINE_integer("coeff", 1, "The Pell equation coefficient.")
_MAX_VALUE = flags.DEFINE_integer("max_value", 5000_000, "The maximum value.")
def solve_pell(coeff: int, max_value: int):
def solve_pell(coeff: int, max_value: int) -> None:
"""Solves Pell's equation x^2 - coeff * y^2 = 1."""
model = cp_model.CpModel()

View File

@@ -33,7 +33,7 @@ _PARAMS = flags.DEFINE_string(
)
def spread_robots(num_robots: int, room_size: int, params: str):
def spread_robots(num_robots: int, room_size: int, params: str) -> None:
"""Optimize robots placement."""
model = cp_model.CpModel()

View File

@@ -158,7 +158,7 @@ class SteelMillSlabSolutionPrinter(cp_model.CpSolverSolutionCallback):
print(line)
def steel_mill_slab(problem, break_symmetries):
def steel_mill_slab(problem, break_symmetries) -> None:
"""Solves the Steel Mill Slab Problem."""
### Load problem.
(num_slabs, capacities, num_colors, orders) = build_problem(problem)

View File

@@ -17,7 +17,7 @@
from ortools.sat.python import cp_model
def solve_sudoku():
def solve_sudoku() -> None:
"""Solves the sudoku problem with the CP-SAT solver."""
# Create the model.
model = cp_model.CpModel()

View File

@@ -23,7 +23,7 @@ from absl import app
from ortools.sat.python import cp_model
def task_allocation_sat():
def task_allocation_sat() -> None:
"""Solves the task allocation problem."""
# Availability matrix.
available = [

View File

@@ -34,7 +34,7 @@ class ObjectivePrinter(cp_model.CpSolverSolutionCallback):
self.__solution_count += 1
def tasks_and_workers_assignment_sat():
def tasks_and_workers_assignment_sat() -> None:
"""solve the assignment problem."""
model = cp_model.CpModel()

View File

@@ -63,7 +63,7 @@ class SolutionPrinter(cp_model.CpSolverSolutionCallback):
return self.__solution_count
def vendor_scheduling_sat():
def vendor_scheduling_sat() -> None:
"""Create the shift scheduling model and solve it."""
# Create the model.
model = cp_model.CpModel()

View File

@@ -130,7 +130,7 @@ def build_data():
return num_tables, table_capacity, min_known_neighbors, connections, names
def solve_with_discrete_model():
def solve_with_discrete_model() -> None:
"""Discrete approach."""
num_tables, table_capacity, min_known_neighbors, connections, names = build_data()

View File

@@ -55,7 +55,7 @@ def build_model():
return x, y, profits
def solve_with_cp_sat(x, y, profits):
def solve_with_cp_sat(x, y, profits) -> None:
"""Solves the problem with the CP-SAT solver."""
model = cp_model.CpModel()