run tests in examples/python under bazel; sync/clean examples
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
absl-py==1.4.0
|
||||
numpy==1.24.1
|
||||
pandas==1.5.3
|
||||
protobuf==4.21.12
|
||||
python_dateutil==2.8.2
|
||||
pytz==2022.7.1
|
||||
scipy==1.10.0
|
||||
six==1.16
|
||||
|
||||
90
examples/python/BUILD.bazel
Normal file
90
examples/python/BUILD.bazel
Normal file
@@ -0,0 +1,90 @@
|
||||
# Copyright 2010-2022 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.
|
||||
|
||||
# BUILD file to run python examples.
|
||||
|
||||
load(":code_samples.bzl", "code_sample_compile_py", "code_sample_py")
|
||||
|
||||
# code_sample_py("arc_flow_cutting_stock_sat") # using pywraplp
|
||||
|
||||
code_sample_py("assignment2_sat")
|
||||
|
||||
code_sample_py("assignment_with_constraints_sat")
|
||||
|
||||
code_sample_py("balance_group_sat")
|
||||
|
||||
code_sample_py("bus_driver_scheduling_flow_sat")
|
||||
|
||||
code_sample_py("bus_driver_scheduling_sat")
|
||||
|
||||
code_sample_py("chemical_balance_sat")
|
||||
|
||||
code_sample_py("clustering_sat")
|
||||
|
||||
code_sample_py("cover_rectangle_sat")
|
||||
|
||||
code_sample_py("flexible_job_shop_sat")
|
||||
|
||||
code_sample_py("gate_scheduling_sat")
|
||||
|
||||
code_sample_py("golomb_sat")
|
||||
|
||||
code_sample_py("hidato_sat")
|
||||
|
||||
code_sample_py("jobshop_ft06_distance_sat")
|
||||
|
||||
code_sample_py("jobshop_ft06_sat")
|
||||
|
||||
code_sample_py("jobshop_with_maintenance_sat")
|
||||
|
||||
code_sample_py("knapsack_2d_sat")
|
||||
|
||||
code_sample_compile_py("line_balancing_sat") # no input
|
||||
|
||||
code_sample_py("maze_escape_sat")
|
||||
|
||||
code_sample_py("no_wait_baking_scheduling_sat")
|
||||
|
||||
code_sample_py("prize_collecting_tsp_sat")
|
||||
|
||||
code_sample_py("prize_collecting_vrp_sat")
|
||||
|
||||
code_sample_py("qubo_sat")
|
||||
|
||||
code_sample_compile_py("rcpsp_sat") # no input
|
||||
|
||||
code_sample_py("reallocate_sat")
|
||||
|
||||
code_sample_py("shift_scheduling_sat")
|
||||
|
||||
code_sample_py("single_machine_scheduling_with_setup_release_due_dates_sat")
|
||||
|
||||
# code_sample_py("steel_mill_slab_sat") # using pywraplp
|
||||
|
||||
code_sample_py("sudoku_sat")
|
||||
|
||||
code_sample_py("task_allocation_sat")
|
||||
|
||||
code_sample_py("tasks_and_workers_assignment_sat")
|
||||
|
||||
code_sample_py("tsp_sat")
|
||||
|
||||
code_sample_py("vendor_scheduling_sat")
|
||||
|
||||
code_sample_py("wedding_optimal_chart_sat")
|
||||
|
||||
code_sample_py("weighted_latency_problem_sat")
|
||||
|
||||
code_sample_py("worker_schedule_sat")
|
||||
|
||||
code_sample_py("zebra_sat")
|
||||
@@ -100,14 +100,13 @@ def AggregateItemCollectionsOptimally(item_collections, max_num_collections,
|
||||
Each collection may be selected more than one time.
|
||||
|
||||
Args:
|
||||
item_collections: a list of item collections. Each item collection is a
|
||||
list of integers [#item0, ..., #itemN-1], where #itemK is the number
|
||||
of times item #K appears in the collection, and N is the number of
|
||||
distinct items.
|
||||
max_num_collections: an integer, the maximum number of item collections
|
||||
that may be selected (counting repetitions of the same collection).
|
||||
item_collections: a list of item collections. Each item collection is a list
|
||||
of integers [#item0, ..., #itemN-1], where #itemK is the number of times
|
||||
item #K appears in the collection, and N is the number of distinct items.
|
||||
max_num_collections: an integer, the maximum number of item collections that
|
||||
may be selected (counting repetitions of the same collection).
|
||||
ideal_item_ratios: A list of N float which sums to 1.0: the K-th element is
|
||||
the ideal ratio of item #K in the whole aggregated selection.
|
||||
the ideal ratio of item #K in the whole aggregated selection.
|
||||
|
||||
Returns:
|
||||
A pair (objective value, list of pairs (item collection, num_selections)),
|
||||
@@ -184,10 +183,10 @@ def GetOptimalSchedule(demand):
|
||||
"""Computes the optimal schedule for the installation input.
|
||||
|
||||
Args:
|
||||
demand: a list of "appointment types". Each "appointment type" is
|
||||
a triple (ideal_ratio_pct, name, duration_minutes), where
|
||||
ideal_ratio_pct is the ideal percentage (in [0..100.0]) of that
|
||||
type of appointment among all appointments scheduled.
|
||||
demand: a list of "appointment types". Each "appointment type" is a triple
|
||||
(ideal_ratio_pct, name, duration_minutes), where ideal_ratio_pct is the
|
||||
ideal percentage (in [0..100.0]) of that type of appointment among all
|
||||
appointments scheduled.
|
||||
|
||||
Returns:
|
||||
The same output type as EnumerateAllKnapsacksWithRepetition.
|
||||
|
||||
56
examples/python/code_samples.bzl
Normal file
56
examples/python/code_samples.bzl
Normal file
@@ -0,0 +1,56 @@
|
||||
# Copyright 2010-2022 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.
|
||||
|
||||
"""Helper macro to compile and test code samples."""
|
||||
|
||||
load("@ortools_deps//:requirements.bzl", "requirement")
|
||||
|
||||
PYTHON_DEPS = [
|
||||
"//ortools/sat/python:cp_model",
|
||||
"//ortools/sat/python:visualization",
|
||||
requirement("absl-py"),
|
||||
requirement("numpy"),
|
||||
requirement("pandas"),
|
||||
requirement("protobuf"),
|
||||
requirement("python_dateutil"),
|
||||
requirement("pytz"),
|
||||
requirement("six"),
|
||||
]
|
||||
|
||||
def code_sample_compile_py(name):
|
||||
native.py_binary(
|
||||
name = name + "_py3",
|
||||
srcs = [name + ".py"],
|
||||
main = name + ".py",
|
||||
deps = PYTHON_DEPS,
|
||||
python_version = "PY3",
|
||||
srcs_version = "PY3",
|
||||
)
|
||||
|
||||
def code_sample_test_py(name):
|
||||
native.py_test(
|
||||
name = name + "_py_test",
|
||||
size = "small",
|
||||
srcs = [name + ".py"],
|
||||
main = name + ".py",
|
||||
data = [
|
||||
"//ortools/sat/python:cp_model",
|
||||
],
|
||||
deps = PYTHON_DEPS,
|
||||
python_version = "PY3",
|
||||
srcs_version = "PY3",
|
||||
)
|
||||
|
||||
def code_sample_py(name):
|
||||
code_sample_compile_py(name)
|
||||
code_sample_test_py(name)
|
||||
@@ -30,10 +30,9 @@ from ortools.sat.python import cp_model
|
||||
|
||||
_OUTPUT_PROTO = flags.DEFINE_string(
|
||||
'output_proto', '', 'Output file to write the cp_model proto to.')
|
||||
_PARAMS = flags.DEFINE_string(
|
||||
'params',
|
||||
'num_search_workers:16,log_search_progress:true,max_time_in_seconds:10.0',
|
||||
'Sat solver parameters.')
|
||||
_PARAMS = flags.DEFINE_string('params',
|
||||
'num_search_workers:16,log_search_progress:true',
|
||||
'Sat solver parameters.')
|
||||
_MODEL = flags.DEFINE_string('model', 'rotation',
|
||||
'\'duplicate\' or \'rotation\' or \'optional\'')
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ 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
|
||||
|
||||
_INPUT = flags.DEFINE_string('input', '', 'Input file to parse and solve.')
|
||||
@@ -259,14 +260,14 @@ def solve_boolean_model(model, hint):
|
||||
for t in all_tasks:
|
||||
model.AddHint(assign[t, hint[t]], 1)
|
||||
|
||||
if FLAGS.output_proto:
|
||||
print(f'Writing proto to {FLAGS.output_proto}')
|
||||
model.ExportToFile(FLAGS.output_proto)
|
||||
if _OUTPUT_PROTO.value:
|
||||
print(f'Writing proto to {_OUTPUT_PROTO.value}')
|
||||
model.ExportToFile(_OUTPUT_PROTO.value)
|
||||
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if FLAGS.params:
|
||||
text_format.Parse(FLAGS.params, solver.parameters)
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.Solve(model)
|
||||
|
||||
@@ -321,32 +322,31 @@ def solve_scheduling_model(model, hint):
|
||||
for t in all_tasks:
|
||||
model.AddHint(pods[t], hint[t])
|
||||
|
||||
if FLAGS.output_proto:
|
||||
print(f'Writing proto to{FLAGS.output_proto}')
|
||||
model.ExportToFile(FLAGS.output_proto)
|
||||
if _OUTPUT_PROTO.value:
|
||||
print(f'Writing proto to{_OUTPUT_PROTO.value}')
|
||||
model.ExportToFile(_OUTPUT_PROTO.value)
|
||||
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if FLAGS.params:
|
||||
text_format.Parse(FLAGS.params, solver.parameters)
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.parameters.exploit_all_precedences = True # Helps with the lower bound.
|
||||
solver.Solve(model)
|
||||
|
||||
|
||||
def main(argv: Sequence[str]) -> None:
|
||||
if len(argv) > 1:
|
||||
raise app.UsageError('Too many command-line arguments.')
|
||||
if FLAGS.input == '':
|
||||
if _INPUT.value == '':
|
||||
raise app.UsageError('Missing input file.')
|
||||
|
||||
model = read_model(FLAGS.input)
|
||||
model = read_model(_INPUT.value)
|
||||
print_stats(model)
|
||||
greedy_solution = solve_model_greedily(model)
|
||||
|
||||
if FLAGS.model == 'boolean':
|
||||
if _MODEL.value == 'boolean':
|
||||
solve_boolean_model(model, greedy_solution)
|
||||
elif FLAGS.model == 'scheduling':
|
||||
elif _MODEL.value == 'scheduling':
|
||||
solve_scheduling_model(model, greedy_solution)
|
||||
|
||||
|
||||
|
||||
@@ -26,12 +26,11 @@ from absl import flags
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
flags.DEFINE_string('output_proto', '',
|
||||
'Output file to write the cp_model proto to.')
|
||||
flags.DEFINE_string('params', 'num_search_workers:8,log_search_progress:true',
|
||||
'Sat solver parameters.')
|
||||
_OUTPUT_PROTO = flags.DEFINE_string(
|
||||
'output_proto', '', 'Output file to write the cp_model proto to.')
|
||||
_PARAMS = flags.DEFINE_string('params',
|
||||
'num_search_workers:8,log_search_progress:true',
|
||||
'Sat solver parameters.')
|
||||
|
||||
|
||||
def add_neighbor(size, x, y, z, dx, dy, dz, model, index_map, position_to_rank,
|
||||
@@ -142,7 +141,7 @@ def escape_the_maze(params, output_proto):
|
||||
def main(argv: Sequence[str]) -> None:
|
||||
if len(argv) > 1:
|
||||
raise app.UsageError('Too many command-line arguments.')
|
||||
escape_the_maze(FLAGS.params, FLAGS.output_proto)
|
||||
escape_the_maze(_PARAMS.value, _OUTPUT_PROTO.value)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -27,12 +27,11 @@ from absl import flags
|
||||
from google.protobuf import text_format
|
||||
from ortools.sat.python import cp_model
|
||||
|
||||
FLAGS = flags.FLAGS
|
||||
|
||||
flags.DEFINE_string('params', 'num_search_workers:16, max_time_in_seconds:30',
|
||||
'Sat solver parameters.')
|
||||
flags.DEFINE_string('proto_file', '',
|
||||
'If not empty, output the proto to this file.')
|
||||
_PARAMS = flags.DEFINE_string('params',
|
||||
'num_search_workers:16, max_time_in_seconds:30',
|
||||
'Sat solver parameters.')
|
||||
_PROTO_FILE = flags.DEFINE_string(
|
||||
'proto_file', '', 'If not empty, output the proto to this file.')
|
||||
|
||||
# Recipes
|
||||
CROISSANT = 'croissant'
|
||||
@@ -277,8 +276,8 @@ def solve_with_cp_sat(recipes, resources, orders):
|
||||
|
||||
# Solve model.
|
||||
solver = cp_model.CpSolver()
|
||||
if FLAGS.params:
|
||||
text_format.Parse(FLAGS.params, solver.parameters)
|
||||
if _PARAMS.value:
|
||||
text_format.Parse(_PARAMS.value, solver.parameters)
|
||||
solver.parameters.log_search_progress = True
|
||||
status = solver.Solve(model)
|
||||
|
||||
|
||||
@@ -575,6 +575,7 @@ def solve_qubo():
|
||||
solver = cp_model.CpSolver()
|
||||
solver.parameters.num_search_workers = 16
|
||||
solver.parameters.log_search_progress = True
|
||||
solver.parameters.max_time_in_seconds = 30
|
||||
solver.Solve(model)
|
||||
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ def add_soft_sequence_constraint(model, works, hard_min, soft_min, min_cost,
|
||||
soft_max, hard_max, max_cost, prefix):
|
||||
"""Sequence constraint on true variables with soft and hard bounds.
|
||||
|
||||
This constraint looks at every maximal contiguous sequence of variables
|
||||
assigned to true. It forbids sequence of length < hard_min or > hard_max.
|
||||
This constraint look at every maximal contiguous sequence of variables
|
||||
assigned to true. If forbids sequence of length < hard_min or > hard_max.
|
||||
Then it creates penalty terms if the length is < soft_min or > soft_max.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -88,3 +88,10 @@ py_test(
|
||||
requirement("absl-py"),
|
||||
],
|
||||
)
|
||||
|
||||
py_library(
|
||||
name = "visualization",
|
||||
srcs = ["visualization.py"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user