examples: backport from main
This commit is contained in:
committed by
Mizux Seiha
parent
a7f49a2585
commit
f0d0fe71ba
@@ -27,7 +27,6 @@ import numpy as np
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_PARAMS = flags.DEFINE_string(
|
||||
@@ -149,7 +148,7 @@ def permutation_flow_shop(
|
||||
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solver.parameters.log_search_progress = log
|
||||
solver.parameters.max_time_in_seconds = time_limit
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import argparse
|
||||
import collections
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
from google.protobuf import text_format
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Command line arguments.
|
||||
@@ -295,7 +294,7 @@ def main(args):
|
||||
solver = cp_model.CpSolver()
|
||||
solver.parameters.max_time_in_seconds = 60 * 60 * 2
|
||||
if parameters:
|
||||
text_format.Merge(parameters, solver.parameters)
|
||||
solver.parameters.merge_text_format(parameters)
|
||||
solution_printer = SolutionPrinter(makespan)
|
||||
status = solver.Solve(model, solution_printer)
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ code_sample_py("balance_group_sat")
|
||||
|
||||
code_sample_py("bus_driver_scheduling_sat")
|
||||
|
||||
code_sample_py("car_sequencing_optimization_sat")
|
||||
|
||||
code_sample_py("chemical_balance_sat")
|
||||
|
||||
code_sample_py("clustering_sat")
|
||||
|
||||
@@ -180,7 +180,7 @@ def aggregate_item_collections_optimally(
|
||||
|
||||
|
||||
def get_optimal_schedule(
|
||||
demand: list[tuple[float, str, int]]
|
||||
demand: list[tuple[float, str, int]],
|
||||
) -> list[tuple[int, list[tuple[int, str]]]]:
|
||||
"""Computes the optimal schedule for the installation input.
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ from absl import app
|
||||
from absl import flags
|
||||
import numpy as np
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.linear_solver.python import model_builder as mb
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
@@ -319,7 +318,7 @@ def solve_cutting_stock_with_arc_flow_and_sat(output_proto_file: str, params: st
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.Solve(model)
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ be as close to the average as possible.
|
||||
Furthermore, if one color is an a group, at least k items with this color must
|
||||
be in that group.
|
||||
"""
|
||||
|
||||
from typing import Dict, Sequence
|
||||
|
||||
from absl import app
|
||||
|
||||
@@ -29,7 +29,7 @@ import math
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
from google.protobuf import text_format
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_OUTPUT_PROTO = flags.DEFINE_string(
|
||||
@@ -81,7 +81,7 @@ SAMPLE_SHIFTS_TINY = [
|
||||
[25, "15:40", "15:56", 940, 956, 16],
|
||||
[26, "15:58", "16:45", 958, 1005, 47],
|
||||
[27, "16:04", "17:30", 964, 1050, 86],
|
||||
] # yapf:disable
|
||||
]
|
||||
|
||||
SAMPLE_SHIFTS_SMALL = [
|
||||
#
|
||||
@@ -143,7 +143,7 @@ SAMPLE_SHIFTS_SMALL = [
|
||||
[47, "18:34", "19:58", 1114, 1198, 84],
|
||||
[48, "19:56", "20:34", 1196, 1234, 38],
|
||||
[49, "20:05", "20:48", 1205, 1248, 43],
|
||||
] # yapf:disable
|
||||
]
|
||||
|
||||
SAMPLE_SHIFTS_MEDIUM = [
|
||||
[0, "04:30", "04:53", 270, 293, 23],
|
||||
@@ -346,7 +346,7 @@ SAMPLE_SHIFTS_MEDIUM = [
|
||||
[197, "00:02", "00:12", 1442, 1452, 10],
|
||||
[198, "00:07", "00:39", 1447, 1479, 32],
|
||||
[199, "00:25", "01:12", 1465, 1512, 47],
|
||||
] # yapf:disable
|
||||
]
|
||||
|
||||
SAMPLE_SHIFTS_LARGE = [
|
||||
[0, "04:18", "05:00", 258, 300, 42],
|
||||
@@ -1705,7 +1705,7 @@ SAMPLE_SHIFTS_LARGE = [
|
||||
[1353, "00:47", "01:26", 1487, 1526, 39],
|
||||
[1354, "00:54", "01:04", 1494, 1504, 10],
|
||||
[1355, "00:57", "01:07", 1497, 1507, 10],
|
||||
] # yapf:disable
|
||||
]
|
||||
|
||||
|
||||
def bus_driver_scheduling(minimize_drivers: bool, max_num_drivers: int) -> int:
|
||||
@@ -1981,7 +1981,7 @@ def bus_driver_scheduling(minimize_drivers: bool, max_num_drivers: int) -> int:
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
|
||||
status = solver.solve(model)
|
||||
|
||||
|
||||
271
examples/python/car_sequencing_optimization_sat.py
Normal file
271
examples/python/car_sequencing_optimization_sat.py
Normal file
@@ -0,0 +1,271 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2010-2025 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.
|
||||
|
||||
"""Solve the car sequencing problem as an optimization problem.
|
||||
|
||||
Problem Description: The Car Sequencing Problem with Optimization
|
||||
-----------------------------------------------------------------
|
||||
|
||||
See https://en.wikipedia.org/wiki/Car_sequencing_problem for more details.
|
||||
|
||||
We are tasked with determining the optimal production sequence for a set of cars
|
||||
on an assembly line. This is a classic and challenging combinatorial
|
||||
optimization problem with the following characteristics:
|
||||
|
||||
Fixed Production Demand: There is a specific, non-negotiable number of cars of
|
||||
different types (or 'classes') that must be produced. In our case, we have 6
|
||||
distinct classes of cars, and we must produce exactly 5 of each, for a total of
|
||||
30 'real' cars.
|
||||
|
||||
Diverse Car Configurations: Each car class is defined by a unique combination of
|
||||
optional features. For example, 'Class 1' might require a sunroof (Option 1) and
|
||||
a special engine (Option 4), while 'Class 3' only requires air conditioning
|
||||
(Option 2).
|
||||
|
||||
Specialized Assembly Stations: The assembly line is composed of a series of
|
||||
specialized stations. Each station is responsible for installing one specific
|
||||
option. For example, there is one station for sunroofs, one for special engines,
|
||||
and so on.
|
||||
|
||||
Capacity-Limited Stations: The core challenge of the problem lies here. The
|
||||
stations cannot handle an unlimited, dense flow of cars requiring their specific
|
||||
option. Their capacity is defined by a 'sliding window' constraint. For example,
|
||||
the sunroof station might have a constraint of 'at most 1 car with a sunroof in
|
||||
any sequence of 3 consecutive cars'. This means sequences like [Sunroof, No, No,
|
||||
Sunroof] are valid, but [Sunroof, No, Sunroof, No] are not.
|
||||
|
||||
The Need for Spacing (Optimization): The combination of high demand for certain
|
||||
options and tight capacity constraints may make it impossible to produce the 30
|
||||
real cars consecutively. To create a valid sequence, we may need to insert
|
||||
'dummy' or 'filler' cars into the production line. These dummy cars have no
|
||||
options and therefore do not consume capacity at any station. They serve purely
|
||||
as spacers to break up dense sequences of option-heavy cars.
|
||||
|
||||
The Goal: The objective is to find a production sequence that fulfills the
|
||||
demand for all 30 real cars while using the minimum number of dummy cars. This
|
||||
is equivalent to finding the shortest possible total production schedule (real
|
||||
cars + dummy cars).
|
||||
|
||||
Modeling and Solution Approach with CP-SAT
|
||||
------------------------------------------
|
||||
|
||||
To solve this problem, we use the CP-SAT solver from Google's OR-Tools library.
|
||||
This is a constraint programming approach, which works by defining variables,
|
||||
constraints, and an objective function.
|
||||
|
||||
1. Decision Variables
|
||||
The fundamental decision the solver must make is: 'Which class of car should be
|
||||
placed in each production slot?'
|
||||
We define a large number of boolean variables: produces[c][s]. This variable is
|
||||
True if a car of class c is scheduled in slot s, and False otherwise. We create
|
||||
these for all car classes (including the dummy class) and for an extended number
|
||||
of slots (30 real + a buffer of 20 for dummies).
|
||||
We introduce a key integer variable: makespan. This variable represents the
|
||||
total length of the 'meaningful' part of our schedule. It's the slot number
|
||||
where the first dummy car appears, after which all subsequent cars are also
|
||||
dummies.
|
||||
|
||||
2. Constraints (The Rules of the Game)
|
||||
We translate the problem's rules into mathematical constraints that the solver
|
||||
must obey:
|
||||
|
||||
One Car Per Slot: For every production slot s, exactly one car class can be
|
||||
assigned. We enforce this using an AddExactlyOne constraint over all
|
||||
produces[c][s] variables for that slot.
|
||||
|
||||
Fulfill Real Car Demand: The total number of times each real car class c appears
|
||||
across all slots must equal its required demand (5 in our case). This is a
|
||||
simple Add(sum(...) == 5) constraint.
|
||||
|
||||
Station Capacity (Sliding Window): This is the most critical constraint. For
|
||||
each option (e.g., 'sunroof') and its capacity rule (e.g., '1 in 3'), we create
|
||||
constraints for every possible sliding window. For every subsequence of 3 slots,
|
||||
we sum up the produces variables corresponding to car classes that require that
|
||||
option and constrain this sum to be less than or equal to 1.
|
||||
|
||||
Makespan Definition: This is the clever part of the model. We link our makespan
|
||||
objective variable to the placement of dummy cars using logical equivalences for
|
||||
each slot s:
|
||||
(makespan <= s) is equivalent to (slot s contains a dummy car)
|
||||
This ensures that if the solver chooses a makespan of 32, for example, it is
|
||||
forced to place dummy cars in slots 32, 33, 34, and so on. Conversely, if the
|
||||
solver is forced to place a dummy car in slot 32 to satisfy a capacity
|
||||
constraint, the makespan must be at most 32.
|
||||
|
||||
3. The Objective Function
|
||||
|
||||
The objective is simple and directly tied to our goal:
|
||||
|
||||
Minimize makespan: By instructing the solver to find a solution with the
|
||||
smallest possible value for the makespan variable, we are asking it to find the
|
||||
shortest possible production schedule that satisfies all the rules. This
|
||||
inherently minimizes the number of dummy cars used.
|
||||
|
||||
By defining the problem in this way, we let the CP-SAT solver explore the vast
|
||||
search space of possible sequences efficiently, using its powerful constraint
|
||||
propagation and search techniques to find an optimal arrangement that meets all
|
||||
our complex requirements.
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from absl import app
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
def solve_car_sequencing_optimization() -> None:
|
||||
"""Solves the car sequencing problem with an optimization approach."""
|
||||
|
||||
# --------------------
|
||||
# 1. Data
|
||||
# --------------------
|
||||
num_real_cars: int = 30
|
||||
max_dummy_cars: int = 20
|
||||
num_slots = num_real_cars + max_dummy_cars
|
||||
all_slots = range(num_slots)
|
||||
|
||||
class_options = [
|
||||
# Options: 1 2 3 4 5
|
||||
[0, 0, 0, 0, 0], # Class 0 (Dummy)
|
||||
[1, 0, 0, 1, 0], # Class 1
|
||||
[0, 1, 0, 0, 1], # Class 2
|
||||
[0, 1, 0, 0, 0], # Class 3
|
||||
[0, 0, 1, 1, 0], # Class 4
|
||||
[0, 0, 1, 0, 0], # Class 5
|
||||
[0, 0, 0, 0, 1], # Class 6
|
||||
]
|
||||
num_classes = len(class_options)
|
||||
all_classes = range(num_classes)
|
||||
real_classes = range(1, num_classes)
|
||||
dummy_class = 0
|
||||
|
||||
demands = [5, 5, 5, 5, 5, 5]
|
||||
|
||||
capacity_constraints = [(1, 3), (1, 2), (1, 3), (2, 5), (1, 5)]
|
||||
num_options = len(capacity_constraints)
|
||||
all_options = range(num_options)
|
||||
|
||||
classes_with_option = [
|
||||
[c for c in real_classes if class_options[c][o] == 1] for o in all_options
|
||||
]
|
||||
|
||||
# --------------------
|
||||
# 2. Model Creation
|
||||
# --------------------
|
||||
model = cp_model.CpModel()
|
||||
|
||||
# --------------------
|
||||
# 3. Decision Variables
|
||||
# --------------------
|
||||
produces = {}
|
||||
for c in all_classes:
|
||||
for s in all_slots:
|
||||
produces[(c, s)] = model.new_bool_var(f"produces_c{c}_s{s}")
|
||||
|
||||
makespan = model.new_int_var(num_real_cars, num_slots, "makespan")
|
||||
|
||||
# --------------------
|
||||
# 4. Constraints
|
||||
# --------------------
|
||||
|
||||
# Constraint 1: Only one car produced per slot.
|
||||
for s in all_slots:
|
||||
model.add_exactly_one([produces[(c, s)] for c in all_classes])
|
||||
|
||||
# Constraint 2: Meet the demand of real cars.
|
||||
for i, c in enumerate(real_classes):
|
||||
model.add(sum(produces[(c, s)] for s in all_slots) == demands[i])
|
||||
|
||||
# Constraint 3: Enforce the capacity constraints on options.
|
||||
for o in all_options:
|
||||
max_cars, subsequence_len = capacity_constraints[o]
|
||||
for start in range(num_slots - subsequence_len + 1):
|
||||
window = range(start, start + subsequence_len)
|
||||
cars_with_option_in_window = []
|
||||
for c in classes_with_option[o]:
|
||||
for s in window:
|
||||
cars_with_option_in_window.append(produces[(c, s)])
|
||||
model.add(sum(cars_with_option_in_window) <= max_cars)
|
||||
|
||||
# Constraint 4 (Link objective and dummy cars at the end of the schedule)
|
||||
for s in all_slots:
|
||||
makespan_le_s = model.new_bool_var(f"makespan_le_{s}")
|
||||
|
||||
# Enforce makespan_le_s <=> (makespan <= s)
|
||||
model.add(makespan <= s).only_enforce_if(makespan_le_s)
|
||||
# Use ~ for negation
|
||||
model.add(makespan > s).only_enforce_if(~makespan_le_s)
|
||||
|
||||
# Enforce makespan_le_s => produces[dummy_class, s]
|
||||
model.add_implication(makespan_le_s, produces[dummy_class, s])
|
||||
|
||||
# --------------------
|
||||
# 5. Objective
|
||||
# --------------------
|
||||
model.minimize(makespan)
|
||||
|
||||
# --------------------
|
||||
# 6. Solve and Print Solution
|
||||
# --------------------
|
||||
solver = cp_model.CpSolver()
|
||||
solver.parameters.max_time_in_seconds = 30.0
|
||||
solver.parameters.num_search_workers = 1 # The problem is easy to solve.
|
||||
# solver.parameters.log_search_progress = True # uncomment to see the log.
|
||||
|
||||
status = solver.Solve(model)
|
||||
|
||||
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
|
||||
final_makespan = int(solver.ObjectiveValue())
|
||||
num_dummies_needed = final_makespan - num_real_cars
|
||||
|
||||
print(
|
||||
f'\n{"Optimal" if status == cp_model.OPTIMAL else "Feasible"}'
|
||||
f" solution found with a makespan of {final_makespan}."
|
||||
)
|
||||
print(
|
||||
f"This requires the conceptual equivalent of {num_dummies_needed} dummy"
|
||||
" car(s) to be used as spacers."
|
||||
)
|
||||
|
||||
sequence = [-1] * num_slots
|
||||
for s in all_slots:
|
||||
for c in all_classes:
|
||||
if solver.Value(produces[(c, s)]) == 1:
|
||||
sequence[s] = c
|
||||
break
|
||||
|
||||
print("\nFull Production Sequence (Class 0 is dummy):")
|
||||
print("Slot: | " + " | ".join(f"{i:2}" for i in range(num_slots)) + " |")
|
||||
print("-------|-" + "--|-" * num_slots)
|
||||
print("Class: | " + " | ".join(f"{c:2}" for c in sequence) + " |")
|
||||
|
||||
elif status == cp_model.INFEASIBLE:
|
||||
print("\nNo solution found.")
|
||||
|
||||
else:
|
||||
print(f"\nSomething went wrong. Solver status: {status}")
|
||||
|
||||
print("\nSolver statistics:")
|
||||
print(solver.response_stats())
|
||||
|
||||
|
||||
def main(argv: Sequence[str]) -> None:
|
||||
if len(argv) > 1:
|
||||
raise app.UsageError("Too many command-line arguments.")
|
||||
solve_car_sequencing_optimization()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(main)
|
||||
@@ -12,8 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Use CP-SAT to solve a simple cryptarithmetic problem: SEND+MORE=MONEY.
|
||||
"""
|
||||
"""Use CP-SAT to solve a simple cryptarithmetic problem: SEND+MORE=MONEY."""
|
||||
|
||||
from absl import app
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
@@ -69,7 +69,7 @@ def main(_) -> None:
|
||||
branches = collector.Branches(i)
|
||||
failures = collector.Failures(i)
|
||||
print(
|
||||
("Solution #%i: value = %i, failures = %i, branches = %i," "time = %i ms")
|
||||
"Solution #%i: value = %i, failures = %i, branches = %i,time = %i ms"
|
||||
% (i, obj_value, failures, branches, time)
|
||||
)
|
||||
time = solver.WallTime()
|
||||
|
||||
@@ -24,10 +24,10 @@ see: https://en.wikipedia.org/wiki/Golomb_ruler
|
||||
"""
|
||||
|
||||
from typing import Sequence
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_ORDER = flags.DEFINE_integer("order", 8, "Order of the ruler.")
|
||||
@@ -70,7 +70,7 @@ def solve_golomb_ruler(order: int, params: str) -> None:
|
||||
# Solve the model.
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solution_printer = cp_model.ObjectiveSolutionPrinter()
|
||||
print(f"Golomb ruler(order={order})")
|
||||
status = solver.solve(model, solution_printer)
|
||||
|
||||
@@ -25,8 +25,6 @@ from absl import flags
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from google.protobuf import text_format
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
@@ -159,7 +157,7 @@ def solve_with_duplicate_items(
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
|
||||
status = solver.solve(model)
|
||||
|
||||
@@ -261,7 +259,7 @@ def solve_with_duplicate_optional_items(
|
||||
# solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
|
||||
status = solver.solve(model)
|
||||
|
||||
@@ -382,7 +380,7 @@ def solve_with_rotations(data: pd.Series, max_height: int, max_width: int):
|
||||
# solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
|
||||
status = solver.solve(model)
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ from typing import Dict, Sequence
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
from google.protobuf import text_format
|
||||
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
@@ -272,7 +272,7 @@ def solve_problem_with_boolean_model(
|
||||
# solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.solve(model)
|
||||
|
||||
@@ -339,7 +339,7 @@ def solve_problem_with_scheduling_model(
|
||||
# solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.solve(model)
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
|
||||
"""Test linear sum assignment on a 4x4 matrix.
|
||||
|
||||
Example taken from:
|
||||
http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1]
|
||||
modified so the optimum solution is unique.
|
||||
Example taken from:
|
||||
http://www.ee.oulu.fi/~mpa/matreng/eem1_2-1.htm with kCost[0][1]
|
||||
modified so the optimum solution is unique.
|
||||
"""
|
||||
|
||||
from typing import Sequence
|
||||
@@ -28,7 +28,12 @@ def run_assignment_on_4x4_matrix():
|
||||
"""Test linear sum assignment on a 4x4 matrix."""
|
||||
num_sources = 4
|
||||
num_targets = 4
|
||||
cost = [[90, 76, 75, 80], [35, 85, 55, 65], [125, 95, 90, 105], [45, 110, 95, 115]]
|
||||
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]
|
||||
|
||||
assignment = linear_sum_assignment.SimpleLinearSumAssignment()
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"""Maximize the number of valid combinations of Boolean variables."""
|
||||
|
||||
from typing import Sequence
|
||||
|
||||
from absl import app
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
@@ -20,12 +20,12 @@ visit all boxes in order, and walk on each block in a 4x4x4 map exactly once.
|
||||
Admissible moves are one step in one of the 6 directions:
|
||||
x+, x-, y+, y-, z+(up), z-(down)
|
||||
"""
|
||||
|
||||
from typing import Dict, Sequence, Tuple
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_OUTPUT_PROTO = flags.DEFINE_string(
|
||||
@@ -140,7 +140,7 @@ def escape_the_maze(params: str, output_proto: str) -> None:
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solver.parameters.log_search_progress = True
|
||||
result = solver.solve(model)
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ from typing import List
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
@@ -72,7 +71,7 @@ def solve_hard_model(output_proto: str, params: str) -> bool:
|
||||
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
status = solver.solve(model)
|
||||
print(solver.response_stats())
|
||||
|
||||
@@ -158,7 +157,7 @@ def solve_soft_model_with_maximization(params: str) -> None:
|
||||
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
status = solver.solve(model)
|
||||
print(solver.response_stats())
|
||||
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
|
||||
|
||||
@@ -26,7 +26,6 @@ from typing import List, Sequence, Tuple
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_PARAMS = flags.DEFINE_string(
|
||||
@@ -287,7 +286,7 @@ def solve_with_cp_sat(
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
solver.parameters.log_search_progress = True
|
||||
status = solver.solve(model)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import time
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_SIZE = flags.DEFINE_integer("size", 8, "Number of queens.")
|
||||
|
||||
@@ -18,6 +18,7 @@ from collections.abc import Sequence
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ from typing import Dict, List
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
@@ -144,7 +143,7 @@ def generate_and_solve_problem(pieces: Dict[str, List[List[int]]]) -> None:
|
||||
# Solve the model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
status = solver.solve(model)
|
||||
|
||||
print(
|
||||
|
||||
@@ -82,6 +82,8 @@ def print_solution(manager, routing, assignment):
|
||||
total_distance = 0
|
||||
total_value_collected = 0
|
||||
for v in range(manager.GetNumberOfVehicles()):
|
||||
if not routing.IsVehicleUsed(assignment, v):
|
||||
continue
|
||||
index = routing.Start(v)
|
||||
plan_output = f'Route for vehicle {v}:\n'
|
||||
route_distance = 0
|
||||
|
||||
@@ -52,7 +52,12 @@ def min_cost_flow_api():
|
||||
print("MinCostFlow on 4x4 matrix.")
|
||||
num_sources = 4
|
||||
num_targets = 4
|
||||
costs = [[90, 75, 75, 80], [35, 85, 55, 65], [125, 95, 90, 105], [45, 110, 95, 115]]
|
||||
costs = [
|
||||
[90, 75, 75, 80],
|
||||
[35, 85, 55, 65],
|
||||
[125, 95, 90, 105],
|
||||
[45, 110, 95, 115],
|
||||
]
|
||||
expected_cost = 275
|
||||
smcf = min_cost_flow.SimpleMinCostFlow()
|
||||
for source in range(0, num_sources):
|
||||
|
||||
@@ -26,7 +26,6 @@ import collections
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
from ortools.scheduling import rcpsp_pb2
|
||||
from ortools.scheduling.python import rcpsp
|
||||
@@ -361,7 +360,7 @@ def solve_rcpsp(
|
||||
|
||||
# Parse user specified parameters.
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
|
||||
# Favor objective_shaving over objective_lb_search.
|
||||
if solver.parameters.num_workers >= 16 and solver.parameters.num_workers < 24:
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_OUTPUT_PROTO = flags.DEFINE_string(
|
||||
@@ -410,7 +409,7 @@ def solve_shift_scheduling(params: str, output_proto: str):
|
||||
# Solve the model.
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solution_printer = cp_model.ObjectiveSolutionPrinter()
|
||||
status = solver.solve(model, solution_printer)
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
from typing import Sequence
|
||||
from absl import app
|
||||
from absl import flags
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -498,7 +497,7 @@ def single_machine_scheduling():
|
||||
# Solve.
|
||||
solver = cp_model.CpSolver()
|
||||
if parameters:
|
||||
text_format.Parse(parameters, solver.parameters)
|
||||
solver.parameters.parse_text_format(parameters)
|
||||
solution_printer = SolutionPrinter()
|
||||
solver.best_bound_callback = lambda a: print(f"New objective lower bound: {a}")
|
||||
solver.solve(model, solution_printer)
|
||||
|
||||
@@ -18,8 +18,6 @@ import math
|
||||
from typing import Sequence
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_NUM_ROBOTS = flags.DEFINE_integer("num_robots", 8, "Number of robots to place.")
|
||||
@@ -94,7 +92,7 @@ def spread_robots(num_robots: int, room_size: int, params: str) -> None:
|
||||
# Creates a solver and solves the model.
|
||||
solver = cp_model.CpSolver()
|
||||
if params:
|
||||
text_format.Parse(params, solver.parameters)
|
||||
solver.parameters.parse_text_format(params)
|
||||
solver.parameters.log_search_progress = True
|
||||
status = solver.solve(model)
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import time
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
from google.protobuf import text_format
|
||||
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
@@ -293,7 +293,7 @@ def steel_mill_slab(problem_id: int, break_symmetries: bool) -> None:
|
||||
### Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
objective_printer = cp_model.ObjectiveSolutionPrinter()
|
||||
status = solver.solve(model, objective_printer)
|
||||
|
||||
@@ -477,7 +477,7 @@ def steel_mill_slab_with_valid_slabs(problem_id: int, break_symmetries: bool) ->
|
||||
### Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
|
||||
solution_printer = SteelMillSlabSolutionPrinter(orders, assign, loads, losses)
|
||||
status = solver.solve(model, solution_printer)
|
||||
@@ -547,7 +547,7 @@ def steel_mill_slab_with_column_generation(problem_id: int) -> None:
|
||||
### Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
solution_printer = cp_model.ObjectiveSolutionPrinter()
|
||||
status = solver.solve(model, solution_printer)
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ from absl import app
|
||||
from absl import flags
|
||||
import pandas as pd
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
|
||||
@@ -141,7 +140,7 @@ def solve(
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
status = solver.solve(model)
|
||||
|
||||
# Report solution.
|
||||
|
||||
6
examples/python/testdata/BUILD.bazel
vendored
6
examples/python/testdata/BUILD.bazel
vendored
@@ -13,8 +13,4 @@
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
exports_files(
|
||||
[
|
||||
"salbp_20_1.alb",
|
||||
],
|
||||
)
|
||||
exports_files(["salbp_20_1.alb"])
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
"""
|
||||
|
||||
from ortools.constraint_solver import pywrapcp
|
||||
from ortools.constraint_solver import routing_enums_pb2
|
||||
|
||||
|
||||
###########################
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
import random
|
||||
from typing import Sequence
|
||||
|
||||
from absl import app
|
||||
from absl import flags
|
||||
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
_NUM_NODES = flags.DEFINE_integer("num_nodes", 12, "Number of nodes to visit.")
|
||||
@@ -27,7 +27,9 @@ _GRID_SIZE = flags.DEFINE_integer("grid_size", 20, "Size of the grid where nodes
|
||||
_PROFIT_RANGE = flags.DEFINE_integer("profit_range", 50, "Range of profit.")
|
||||
_SEED = flags.DEFINE_integer("seed", 0, "Random seed.")
|
||||
_PARAMS = flags.DEFINE_string(
|
||||
"params", "num_search_workers:16, max_time_in_seconds:5", "Sat solver parameters."
|
||||
"params",
|
||||
"num_search_workers:16, max_time_in_seconds:5",
|
||||
"Sat solver parameters.",
|
||||
)
|
||||
_PROTO_FILE = flags.DEFINE_string(
|
||||
"proto_file", "", "If not empty, output the proto to this file."
|
||||
@@ -96,7 +98,7 @@ def solve_with_cp_sat(x, y, profits) -> None:
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.parse_text_format(_PARAMS.value)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.solve(model)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user