diff --git a/bazel/BUILD.bazel b/bazel/BUILD.bazel index b9bd7d3d5c..9c85c96307 100644 --- a/bazel/BUILD.bazel +++ b/bazel/BUILD.bazel @@ -34,3 +34,12 @@ compile_pip_requirements( requirements_in = "notebook_requirements.in", requirements_txt = "notebook_requirements.txt", ) + +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "test_runner_template", + testonly = 1, + srcs = ["test_runner_template.sh"], + visibility = ["//visibility:public"], +) diff --git a/bazel/run_binary_test.bzl b/bazel/run_binary_test.bzl new file mode 100644 index 0000000000..ea2cd11f69 --- /dev/null +++ b/bazel/run_binary_test.bzl @@ -0,0 +1,105 @@ +# 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. + +"""run_binary_test will run a xx_binary as test with the given args.""" + +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +def parse_label(label): + """Parse a label into (package, name). + + Args: + label: string in relative or absolute form. + + Returns: + Pair of strings: package, relative_name + + Raises: + ValueError for malformed label (does not do an exhaustive validation) + """ + if label.startswith("//"): + label = label[2:] # drop the leading // + colon_split = label.split(":") + if len(colon_split) == 1: # no ":" in label + pkg = label + _, _, target = label.rpartition("/") + else: + pkg, target = colon_split # fails if len(colon_split) != 2 + else: + colon_split = label.split(":") + if len(colon_split) == 1: # no ":" in label + pkg, target = native.package_name(), label + else: + pkg2, target = colon_split # fails if len(colon_split) != 2 + pkg = native.package_name() + ("/" + pkg2 if pkg2 else "") + return pkg, target + +def get_check_contains_code(line): + return """ +if ! grep -qF "{line}" "${{LOGFILE}}"; then + cat "${{LOGFILE}}" + echo "---------------------------------------------------------------" + echo "FAILURE: string '{line}' was not found in the output." + echo "---------------------------------------------------------------" + exit 1 +fi + """.format(line = line) + +def run_binary_test( + name, + binary, + template = "//bazel:test_runner_template", + args = [], + data = [], + grep_lines = [], + **kwargs): + """Create a sh_test to run the given binary as test. + + Args: + name: name of the test target. + binary: name of the binary target to run. + template: template file for executing the binary target. + args: args to use to run the binary. + data: data files required by this test. + grep_lines: lines to grep for in the log file. + **kwargs: other attributes that are applicable to tests, size, tags, etc. + + """ + shell_script = name + ".sh" + + # Get the path to the binary we want to run. + binary_pkg, binary_name = parse_label(binary) + binary_path = "/".join([binary_pkg, binary_name]) + + # We would like to include args in the generated shell script, so that "blaze-bin/.../test" can + # be run manually. Unfortunately `expand_template` does not resolve $(location) and other Make + # variables so we only pass them in `sh_test` below. + expand_template( + name = name + "_gensh", + template = template, + out = shell_script, + testonly = 1, + substitutions = { + "{{binary_path}}": binary_path, + "{{post_script}}": "\n".join([get_check_contains_code(line) for line in grep_lines]), + }, + ) + sh_test( + name = name, + testonly = 1, + srcs = [shell_script], + data = data + [binary], + args = args, + **kwargs + ) diff --git a/bazel/run_binary_test.bzl.orig b/bazel/run_binary_test.bzl.orig new file mode 100644 index 0000000000..a1cd24ee84 --- /dev/null +++ b/bazel/run_binary_test.bzl.orig @@ -0,0 +1,94 @@ +# 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. + +"""run_binary_test will run a xx_binary as test with the given args. +""" + +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +def parse_label(label): + """Parse a label into (package, name). + + Args: + label: string in relative or absolute form. + + Returns: + Pair of strings: package, relative_name + + Raises: + ValueError for malformed label (does not do an exhaustive validation) + """ + if label.startswith("//"): + label = label[2:] # drop the leading // + colon_split = label.split(":") + if len(colon_split) == 1: # no ":" in label + pkg = label + _, _, target = label.rpartition("/") + else: + pkg, target = colon_split # fails if len(colon_split) != 2 + else: + colon_split = label.split(":") + if len(colon_split) == 1: # no ":" in label + pkg, target = native.package_name(), label + else: + pkg2, target = colon_split # fails if len(colon_split) != 2 + pkg = native.package_name() + ("/" + pkg2 if pkg2 else "") + return pkg, target + +def run_binary_test( + name, + binary, + template = "//bazel:test_runner_template", + args = [], + data = [], + **kwargs): + """Create a sh_test to run the given binary as test. + + Args: + name: name of the test target. + binary: name of the binary target to run. + template: template file for executing the binary target. + args: args to use to run the binary. + data: data files required by this test. + **kwargs: other attributes that are applicable to tests, size, tags, etc. + + """ + shell_script = name + ".sh" + + # Get the path to the binary we want to run. + binary_pkg, binary_name = parse_label(binary) + binary_path = "/".join([binary_pkg, binary_name]) + + # We would like to Include args in the generated shell script, so the "blaze-bin/.../test" can + # be run manually. Unfortunately expand_template does not resolve $(location) and other Make + # variables so we only pass them in `sh_test` below. + expand_template( + name = name + "_gensh", + template = template, + out = shell_script, + testonly = 1, + substitutions = { + "{package_name}": native.package_name(), + "{target}": name, + "{binary_path}": binary_path, + }, + ) + sh_test( + name = name, + testonly = 1, + srcs = [shell_script], + data = data + [binary], + args = args, + **kwargs + ) diff --git a/bazel/test_runner_template.sh b/bazel/test_runner_template.sh new file mode 100644 index 0000000000..a6c038a902 --- /dev/null +++ b/bazel/test_runner_template.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# 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. + +set -e # Fail on error + +declare -r LOGFILE="${TEST_TMPDIR}/log.txt" +{{binary_path}} "$@" > "${LOGFILE}" +{{post_script}} diff --git a/examples/cpp/BUILD.bazel b/examples/cpp/BUILD.bazel index e83fbd1de2..6c3bb6ecb1 100644 --- a/examples/cpp/BUILD.bazel +++ b/examples/cpp/BUILD.bazel @@ -13,44 +13,43 @@ load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") +load("//bazel:run_binary_test.bzl", "run_binary_test") + +# Description: +# C++ examples for operations_research. +package(default_visibility = ["//visibility:public"]) -# Constraint solver examples. cc_binary( name = "binpacking_2d_sat", - srcs = [ - "binpacking_2d_sat.cc", - ], + srcs = ["binpacking_2d_sat.cc"], deps = [ "//ortools/base", + "//ortools/base:mathutil", "//ortools/base:path", "//ortools/packing:binpacking_2d_parser", "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "//ortools/sat:sat_parameters_cc_proto", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", "@protobuf", ], ) -cc_test( +run_binary_test( name = "binpacking_2d_sat_class01_instance2_test", size = "medium", - srcs = [ - "binpacking_2d_sat.cc", - ], args = ["--input $(rootpath //ortools/packing/testdata:Class_01.2bp) --instance 2"], + binary = ":binpacking_2d_sat", data = ["//ortools/packing/testdata:Class_01.2bp"], - deps = [ - "//ortools/base", - "//ortools/base:path", - "//ortools/packing:binpacking_2d_parser", - "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", - "//ortools/sat:cp_model", - "@abseil-cpp//absl/flags:flag", - "@protobuf", - ], ) cc_binary( @@ -59,17 +58,16 @@ cc_binary( deps = [ "//ortools/base", "//ortools/constraint_solver:cp", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", ], ) -cc_test( +run_binary_test( name = "constraint_programming_cp_test", size = "small", - srcs = ["constraint_programming_cp.cc"], - deps = [ - "//ortools/base", - "//ortools/constraint_solver:cp", - ], + binary = ":constraint_programming_cp", ) cc_binary( @@ -77,86 +75,50 @@ cc_binary( srcs = ["costas_array_sat.cc"], deps = [ "//ortools/base", + "//ortools/base:types", "//ortools/sat:cp_model", "//ortools/sat:model", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", ], ) -cc_test( +run_binary_test( name = "costas_array_sat_model1_test", size = "medium", - srcs = ["costas_array_sat.cc"], - args = [ - "--minsize=6 --maxsize=6 --model=1", - ], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - ], + args = ["--minsize=6 --maxsize=6 --model=1"], + binary = ":costas_array_sat", ) -cc_test( +run_binary_test( name = "costas_array_sat_model2_test", size = "medium", - srcs = ["costas_array_sat.cc"], - args = [ - "--minsize=6 --maxsize=6 --model=2", - ], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - ], + args = ["--minsize=6 --maxsize=6 --model=2"], + binary = ":costas_array_sat", ) -cc_test( +run_binary_test( name = "costas_array_sat_model3_test", size = "medium", - srcs = ["costas_array_sat.cc"], - args = [ - "--minsize=6 --maxsize=6 --model=3", - ], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - ], + args = ["--minsize=6 --maxsize=6 --model=3"], + binary = ":costas_array_sat", ) cc_binary( name = "cryptarithm_sat", srcs = ["cryptarithm_sat.cc"], - deps = [ - "//ortools/sat:cp_model", - "//ortools/sat:model", - ], + deps = ["//ortools/sat:cp_model"], ) -cc_test( +run_binary_test( name = "cryptarithm_sat_test", size = "small", - srcs = ["cryptarithm_sat.cc"], - deps = [ - "//ortools/sat:cp_model", - "//ortools/sat:model", - ], + binary = ":cryptarithm_sat", ) cc_binary( @@ -165,26 +127,20 @@ cc_binary( deps = [ "//ortools/base", "//ortools/base:map_util", + "//ortools/base:types", "//ortools/constraint_solver:cp", "//ortools/util:bitset", "@abseil-cpp//absl/random", "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", ], ) -cc_test( +run_binary_test( name = "dobble_ls_test", size = "medium", - srcs = ["dobble_ls.cc"], args = ["--time_limit_in_ms=10000"], - deps = [ - "//ortools/base", - "//ortools/base:map_util", - "//ortools/constraint_solver:cp", - "//ortools/util:bitset", - "@abseil-cpp//absl/random", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":dobble_ls", ) cc_binary( @@ -194,102 +150,85 @@ cc_binary( "//ortools/base", "//ortools/sat:cp_model", "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings:str_format", "@protobuf", ], ) -cc_test( +run_binary_test( name = "golomb_sat_test", size = "medium", - srcs = ["golomb_sat.cc"], args = ["--size 5"], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings:str_format", - "@protobuf", - ], + binary = ":golomb_sat", ) cc_binary( name = "knapsack_2d_sat", - srcs = [ - "knapsack_2d_sat.cc", - ], + srcs = ["knapsack_2d_sat.cc"], deps = [ "//ortools/base", "//ortools/packing:binpacking_2d_parser", "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", "//ortools/sat:cp_model", "//ortools/sat:cp_model_solver", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/types:span", "@protobuf", ], ) -cc_test( +run_binary_test( name = "knapsack_2d_sat_class01_instance2_test", size = "medium", - srcs = [ - "knapsack_2d_sat.cc", - ], args = ["--input $(rootpath //ortools/packing/testdata:Class_01.2bp) --instance 2"], + binary = ":knapsack_2d_sat", data = ["//ortools/packing/testdata:Class_01.2bp"], - deps = [ - "//ortools/base", - "//ortools/packing:binpacking_2d_parser", - "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", - "//ortools/sat:cp_model", - "@abseil-cpp//absl/flags:flag", - "@protobuf", - ], ) cc_binary( name = "jobshop_sat", - srcs = [ - "jobshop_sat.cc", - ], + srcs = ["jobshop_sat.cc"], deps = [ "//ortools/base", - "//ortools/base:file", - "//ortools/base:timer", + "//ortools/graph:connected_components", "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", "//ortools/sat:cp_model_solver", - "//ortools/sat:model", + "//ortools/sat:sat_parameters_cc_proto", "//ortools/scheduling:jobshop_scheduling_cc_proto", "//ortools/scheduling:jobshop_scheduling_parser", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/container:flat_hash_set", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + "@protobuf", + "@protobuf//:wrappers_cc_proto", ], ) -cc_test( +run_binary_test( name = "jobshop_sat_ft06", size = "small", - srcs = [ - "jobshop_sat.cc", - ], args = ["--input $(rootpath //ortools/scheduling/testdata:ft06)"], + binary = ":jobshop_sat", data = ["//ortools/scheduling/testdata:ft06"], - deps = [ - "//ortools/base", - "//ortools/base:file", - "//ortools/base:timer", - "//ortools/sat:cp_model", - "//ortools/sat:cp_model_solver", - "//ortools/sat:model", - "//ortools/scheduling:jobshop_scheduling_cc_proto", - "//ortools/scheduling:jobshop_scheduling_parser", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - ], ) cc_binary( @@ -298,140 +237,96 @@ cc_binary( deps = [ "//ortools/base", "//ortools/sat:cp_model", - "//ortools/sat:model", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings:str_format", ], ) -cc_test( +run_binary_test( name = "magic_sequence_sat_test", size = "medium", - srcs = ["magic_sequence_sat.cc"], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":magic_sequence_sat", ) cc_binary( name = "multi_knapsack_sat", - srcs = [ - "multi_knapsack_sat.cc", - ], + srcs = ["multi_knapsack_sat.cc"], deps = [ "//ortools/base", "//ortools/sat:cp_model", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", ], ) -cc_test( +run_binary_test( name = "multi_knapsack_sat_test", size = "medium", - srcs = [ - "multi_knapsack_sat.cc", - ], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "@abseil-cpp//absl/flags:flag", - ], + binary = ":multi_knapsack_sat", ) cc_binary( name = "shift_minimization_sat", - srcs = [ - "shift_minimization_sat.cc", - ], + srcs = ["shift_minimization_sat.cc"], deps = [ "//ortools/base", - "//ortools/base:file", "//ortools/sat:cp_model", "//ortools/sat:model", "//ortools/util:filelineiter", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", ], ) -cc_test( +run_binary_test( name = "shift_minimization_sat_test", size = "medium", - srcs = [ - "shift_minimization_sat.cc", - ], - args = ["--input $(rootpath //examples/cpp:shift_minimization.dat)"], - data = ["//examples/cpp:shift_minimization.dat"], - deps = [ - "//ortools/base", - "//ortools/base:file", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "//ortools/util:filelineiter", - "@abseil-cpp//absl/container:btree", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - ], + args = ["--input $(rootpath :shift_minimization.dat)"], + binary = ":shift_minimization_sat", + data = [":shift_minimization.dat"], ) cc_binary( name = "weighted_tardiness_sat", - srcs = [ - "weighted_tardiness_sat.cc", - ], + srcs = ["weighted_tardiness_sat.cc"], deps = [ "//ortools/base", - "//ortools/base:file", "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", "//ortools/sat:cp_model_solver", - "//ortools/sat:disjunctive", - "//ortools/sat:integer", - "//ortools/sat:integer_expr", - "//ortools/sat:intervals", "//ortools/sat:model", - "//ortools/sat:optimization", - "//ortools/sat:precedences", - "//ortools/sat:sat_solver", + "//ortools/sat:sat_parameters_cc_proto", "//ortools/util:filelineiter", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", - "@protobuf", + "@abseil-cpp//absl/types:span", ], ) -cc_test( +run_binary_test( name = "weighted_tardiness_sat_test", size = "medium", - srcs = [ - "weighted_tardiness_sat.cc", - ], - args = ["--input $(rootpath //examples/cpp:wt40.txt)"], - data = ["//examples/cpp:wt40.txt"], - deps = [ - "//ortools/base", - "//ortools/base:file", - "//ortools/sat:cp_model", - "//ortools/sat:cp_model_solver", - "//ortools/sat:disjunctive", - "//ortools/sat:integer", - "//ortools/sat:integer_expr", - "//ortools/sat:intervals", - "//ortools/sat:model", - "//ortools/sat:optimization", - "//ortools/sat:precedences", - "//ortools/sat:sat_solver", - "//ortools/util:filelineiter", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - "@protobuf", - ], + args = ["--input $(rootpath :wt40.txt)"], + binary = ":weighted_tardiness_sat", + data = [":wt40.txt"], ) cc_binary( @@ -441,26 +336,19 @@ cc_binary( "//ortools/base", "//ortools/sat:cp_model", "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings:str_format", ], ) -cc_test( +run_binary_test( name = "magic_square_sat_test", size = "medium", - srcs = ["magic_square_sat.cc"], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/flags:parse", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":magic_square_sat", ) cc_binary( @@ -468,41 +356,43 @@ cc_binary( srcs = ["network_routing_sat.cc"], deps = [ "//ortools/base", - "//ortools/base:hash", - "//ortools/base:map_util", + "//ortools/graph", "//ortools/graph:shortest_paths", "//ortools/sat:cp_model", "//ortools/sat:model", - "//ortools/util:tuple_set", + "//ortools/util:sorted_interval_list", + "//ortools/util:time_limit", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/container:flat_hash_set", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/random:distributions", "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/strings:string_view", ], ) -cc_test( +run_binary_test( name = "network_routing_sat_test", size = "medium", - srcs = ["network_routing_sat.cc"], - args = ["--clients=10 --backbones=5 --demands=10 --traffic_min=5 --traffic_max=10 --min_client_degree=2 --max_client_degree=5 --min_backbone_degree=3 --max_backbone_degree=5 --max_capacity=20 --fixed_charge_cost=10"], - deps = [ - "//ortools/base", - "//ortools/base:hash", - "//ortools/base:map_util", - "//ortools/graph:shortest_paths", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "//ortools/util:tuple_set", - "@abseil-cpp//absl/container:btree", - "@abseil-cpp//absl/container:flat_hash_map", - "@abseil-cpp//absl/container:flat_hash_set", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", + args = [ + "--clients=10", + "--backbones=5", + "--demands=10", + "--traffic_min=5", + "--traffic_max=10", + "--min_client_degree=2", + "--max_client_degree=5", + "--min_backbone_degree=3", + "--max_backbone_degree=5", + "--max_capacity=20", + "--fixed_charge_cost=10", ], + binary = ":network_routing_sat", ) cc_binary( @@ -511,22 +401,17 @@ cc_binary( deps = [ "//ortools/base", "//ortools/base:map_util", + "//ortools/base:types", "//ortools/constraint_solver:cp", "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/strings:str_format", ], ) -cc_test( +run_binary_test( name = "nqueens_test", - srcs = ["nqueens.cc"], - deps = [ - "//ortools/base", - "//ortools/base:map_util", - "//ortools/constraint_solver:cp", - "@abseil-cpp//absl/container:flat_hash_map", - "@abseil-cpp//absl/strings:str_format", - ], + size = "small", + binary = ":nqueens", ) cc_binary( @@ -535,63 +420,50 @@ cc_binary( deps = [ "//ortools/base", "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", ], ) -cc_test( +run_binary_test( name = "sports_scheduling_sat_test", size = "medium", - srcs = ["sports_scheduling_sat.cc"], - deps = [ - "//ortools/base", - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":sports_scheduling_sat", ) cc_binary( - name = "vector_bin_packing_solver", - srcs = [ - "vector_bin_packing_solver.cc", - ], + name = "pdptw", + srcs = ["pdptw.cc"], deps = [ "//ortools/base", - "//ortools/base:file", - "//ortools/packing:arc_flow_builder", - "//ortools/packing:arc_flow_solver", - "//ortools/packing:vector_bin_packing_cc_proto", - "//ortools/packing:vector_bin_packing_parser", + "//ortools/base:mathutil", + "//ortools/base:timer", + "//ortools/constraint_solver:cp", + "//ortools/routing", + "//ortools/routing:enums_cc_proto", + "//ortools/routing:index_manager", + "//ortools/routing:parameters", + "//ortools/routing:parameters_cc_proto", + "//ortools/routing:types", + "//ortools/routing/parsers:lilim_parser", + "//ortools/routing/parsers:simple_graph", + "@abseil-cpp//absl/algorithm:container", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/status", - "@abseil-cpp//absl/strings", - ], -) - -cc_test( - name = "vector_bin_packing_solver_test", - size = "medium", - srcs = [ - "vector_bin_packing_solver.cc", - ], - args = ["--input $(rootpath //ortools/packing/testdata:1D__bpp_scholl__bin2data.N2W2B1R0.vbp)"], - data = ["//ortools/packing/testdata:1D__bpp_scholl__bin2data.N2W2B1R0.vbp"], - deps = [ - "//ortools/base", - "//ortools/base:file", - "//ortools/packing:arc_flow_builder", - "//ortools/packing:arc_flow_solver", - "//ortools/packing:vector_bin_packing_cc_proto", - "//ortools/packing:vector_bin_packing_parser", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/status", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@protobuf", ], ) @@ -600,26 +472,21 @@ cc_binary( name = "random_tsp", srcs = ["random_tsp.cc"], deps = [ - "//ortools/base", - "//ortools/constraint_solver:routing", + "//ortools/constraint_solver:cp", + "//ortools/routing", + "//ortools/routing:index_manager", + "//ortools/routing:parameters", + "//ortools/routing:parameters_cc_proto", "//ortools/util:random_engine", - "@abseil-cpp//absl/strings", - "@protobuf", - ], -) - -cc_binary( - name = "pdptw", - srcs = ["pdptw.cc"], - deps = [ - "//ortools/base", - "//ortools/base:file", - "//ortools/base:mathutil", - "//ortools/constraint_solver:routing", - "//ortools/routing/parsers:lilim_parser", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/log:initialize", + "@abseil-cpp//absl/random", "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", "@protobuf", ], ) @@ -631,19 +498,17 @@ cc_binary( deps = [ "//ortools/base", "//ortools/linear_solver", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", ], ) -cc_test( +run_binary_test( name = "integer_programming_test", size = "small", - srcs = ["integer_programming.cc"], - deps = [ - "//ortools/base", - "//ortools/linear_solver", - "@abseil-cpp//absl/strings", - ], + binary = ":integer_programming", ) cc_binary( @@ -653,22 +518,17 @@ cc_binary( "//ortools/base", "//ortools/linear_solver", "//ortools/linear_solver:linear_solver_cc_proto", - "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", ], ) -cc_test( +run_binary_test( name = "linear_programming_test", size = "small", - srcs = ["linear_programming.cc"], - deps = [ - "//ortools/base", - "//ortools/linear_solver", - "//ortools/linear_solver:linear_solver_cc_proto", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/strings", - ], + binary = ":linear_programming", ) cc_binary( @@ -676,32 +536,36 @@ cc_binary( srcs = ["linear_solver_protocol_buffers.cc"], deps = [ "//ortools/base", - "//ortools/linear_solver", "//ortools/linear_solver:linear_solver_cc_proto", "//ortools/linear_solver:solve_mp_model", ], ) +run_binary_test( + name = "linear_solver_protocol_buffers_test", + size = "small", + binary = ":linear_solver_protocol_buffers", +) + cc_binary( name = "strawberry_fields_with_column_generation", srcs = ["strawberry_fields_with_column_generation.cc"], deps = [ "//ortools/base", "//ortools/linear_solver", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", ], ) -cc_test( +run_binary_test( name = "strawberry_fields_with_column_generation_test", size = "large", - srcs = ["strawberry_fields_with_column_generation.cc"], args = ["--colgen_instance=4"], - deps = [ - "//ortools/base", - "//ortools/linear_solver", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":strawberry_fields_with_column_generation", ) # Dimacs assignment problems @@ -711,9 +575,7 @@ cc_library( deps = [ "//ortools/base", "//ortools/base:file", - "//ortools/graph", "//ortools/graph:linear_assignment", - "@abseil-cpp//absl/status", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", ], @@ -724,10 +586,10 @@ cc_library( srcs = ["parse_dimacs_assignment.cc"], hdrs = ["parse_dimacs_assignment.h"], deps = [ - "//ortools/base", - "//ortools/graph", "//ortools/graph:linear_assignment", "//ortools/util:filelineiter", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", "@abseil-cpp//absl/strings", ], ) @@ -744,6 +606,7 @@ cc_binary( "//ortools/graph", "//ortools/graph:linear_assignment", "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/strings:str_format", ], ) @@ -752,14 +615,24 @@ cc_binary( cc_binary( name = "mps_driver", srcs = ["mps_driver.cc"], + copts = ["-Wfloat-conversion"], deps = [ "//ortools/base", + "//ortools/base:file", "//ortools/base:timer", "//ortools/glop:lp_solver", "//ortools/glop:parameters_cc_proto", + "//ortools/lp_data", + "//ortools/lp_data:base", "//ortools/lp_data:mps_reader", + "//ortools/lp_data:proto_utils", + "//ortools/util:file_util", "//ortools/util:proto_tools", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/status", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", @@ -767,25 +640,12 @@ cc_binary( ], ) -cc_test( +run_binary_test( name = "mps_driver_test", size = "small", - srcs = ["mps_driver.cc"], args = ["--input $(rootpath //ortools/linear_solver/testdata:maximization.mps)"], + binary = ":mps_driver", data = ["//ortools/linear_solver/testdata:maximization.mps"], - deps = [ - "//ortools/base", - "//ortools/base:timer", - "//ortools/glop:lp_solver", - "//ortools/glop:parameters_cc_proto", - "//ortools/lp_data:mps_reader", - "//ortools/util:proto_tools", - "@abseil-cpp//absl/flags:flag", - "@abseil-cpp//absl/status", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/strings:str_format", - "@protobuf", - ], ) # Linear Assignment C++ Example @@ -799,15 +659,10 @@ cc_binary( ], ) -cc_test( +run_binary_test( name = "linear_assignment_api_test", size = "small", - srcs = ["linear_assignment_api.cc"], - deps = [ - "//ortools/base", - "//ortools/graph", - "//ortools/graph:linear_assignment", - ], + binary = ":linear_assignment_api", ) # Flow C++ Example @@ -817,21 +672,15 @@ cc_binary( deps = [ "//ortools/base", "//ortools/graph", - "//ortools/graph:max_flow", + "//ortools/graph:generic_max_flow", "//ortools/graph:min_cost_flow", ], ) -cc_test( +run_binary_test( name = "flow_api_test", size = "small", - srcs = ["flow_api.cc"], - deps = [ - "//ortools/base", - "//ortools/graph", - "//ortools/graph:max_flow", - "//ortools/graph:min_cost_flow", - ], + binary = ":flow_api", ) cc_binary( @@ -839,18 +688,18 @@ cc_binary( srcs = ["max_flow.cc"], deps = [ "//ortools/base", - "//ortools/graph:max_flow", + "//ortools/graph", + "//ortools/graph:generic_max_flow", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", ], ) -cc_test( +run_binary_test( name = "max_flow_test", size = "small", - srcs = ["max_flow.cc"], - deps = [ - "//ortools/base", - "//ortools/graph:max_flow", - ], + binary = ":max_flow", ) cc_binary( @@ -859,17 +708,16 @@ cc_binary( deps = [ "//ortools/base", "//ortools/graph:min_cost_flow", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", ], ) -cc_test( +run_binary_test( name = "min_cost_flow_test", size = "small", - srcs = ["min_cost_flow.cc"], - deps = [ - "//ortools/base", - "//ortools/graph:min_cost_flow", - ], + binary = ":min_cost_flow", ) # Frequency Assignment Problem @@ -878,12 +726,12 @@ cc_library( srcs = ["fap_parser.cc"], hdrs = ["fap_parser.h"], deps = [ - "//ortools/base", "//ortools/base:file", - "//ortools/base:hash", "//ortools/base:map_util", + "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", ], ) @@ -893,8 +741,8 @@ cc_library( hdrs = ["fap_model_printer.h"], deps = [ ":fap_parser", - "//ortools/base", - "//ortools/base:file", + "//ortools/base:logging", + "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", ], @@ -910,6 +758,7 @@ cc_library( "//ortools/base:map_util", "//ortools/constraint_solver:cp", "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/types:span", ], ) @@ -925,17 +774,18 @@ cc_binary( "//ortools/constraint_solver:cp", "@abseil-cpp//absl/container:btree", "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", ], ) # Quadratic assignment problem. + cc_binary( name = "qap_sat", srcs = ["qap_sat.cc"], deps = [ "//ortools/base", "//ortools/sat:cp_model", - "//ortools/sat:model", "//ortools/sat:sat_parameters_cc_proto", "//ortools/util:qap_reader", "@abseil-cpp//absl/flags:flag", @@ -949,20 +799,20 @@ cc_binary( srcs = ["slitherlink_sat.cc"], deps = [ "//ortools/sat:cp_model", - "//ortools/sat:model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", ], ) -cc_test( +run_binary_test( name = "slitherlink_sat_test", size = "small", - srcs = ["slitherlink_sat.cc"], - deps = [ - "//ortools/sat:cp_model", - "//ortools/sat:model", - "@abseil-cpp//absl/strings:str_format", - ], + binary = ":slitherlink_sat", ) cc_binary( @@ -971,10 +821,14 @@ cc_binary( deps = [ "//ortools/base", "//ortools/linear_solver", + "//ortools/util:random_engine", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/flags:usage", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/log:initialize", "@abseil-cpp//absl/random", - "@protobuf", ], ) @@ -983,20 +837,17 @@ cc_binary( srcs = ["variable_intervals_sat.cc"], deps = [ "//ortools/sat:cp_model", + "//ortools/sat:cp_model_solver", "//ortools/sat:sat_parameters_cc_proto", "//ortools/util:time_limit", + "@abseil-cpp//absl/log", ], ) -cc_test( +run_binary_test( name = "variable_intervals_sat_test", size = "small", - srcs = ["variable_intervals_sat.cc"], - deps = [ - "//ortools/sat:cp_model", - "//ortools/sat:sat_parameters_cc_proto", - "//ortools/util:time_limit", - ], + binary = ":variable_intervals_sat", ) cc_binary( @@ -1004,7 +855,7 @@ cc_binary( srcs = ["pdlp_solve.cc"], deps = [ "//ortools/base", - "//ortools/linear_solver:linear_solver_cc_proto", + "//ortools/base:file", "//ortools/pdlp:iteration_stats", "//ortools/pdlp:primal_dual_hybrid_gradient", "//ortools/pdlp:quadratic_program", @@ -1015,9 +866,11 @@ cc_binary( "//ortools/util:file_util", "//ortools/util:fp_roundtrip_conv", "//ortools/util:sigint", + "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/log:check", "@abseil-cpp//absl/log:flags", + "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/strings", ], ) diff --git a/examples/cpp/BUILD.bazel.orig b/examples/cpp/BUILD.bazel.orig new file mode 100644 index 0000000000..f6203afed7 --- /dev/null +++ b/examples/cpp/BUILD.bazel.orig @@ -0,0 +1,1029 @@ +# 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. + +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("//bazel:run_binary_test.bzl", "run_binary_test") + +# Description: +# C++ examples for operations_research. +package(default_visibility = ["//visibility:public"]) + +cc_binary( + name = "binpacking_2d_sat", + srcs = [ + "binpacking_2d_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/base:mathutil", + "//ortools/base:path", + "//ortools/packing:binpacking_2d_parser", + "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "//ortools/sat:sat_parameters_cc_proto", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + "@protobuf", + ], +) + +run_binary_test( + name = "binpacking_2d_sat_class01_instance2_test", + size = "medium", +<<<<<<< HEAD + srcs = [ + "binpacking_2d_sat.cc", + ], +======= +>>>>>>> 3b384e83a4 ([bazel] Update examples) + args = ["--input $(rootpath //ortools/packing/testdata:Class_01.2bp) --instance 2"], + binary = ":binpacking_2d_sat", + data = ["//ortools/packing/testdata:Class_01.2bp"], +) + +cc_binary( + name = "constraint_programming_cp", + srcs = ["constraint_programming_cp.cc"], + deps = [ + "//ortools/base", + "//ortools/constraint_solver:cp", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + ], +) + +run_binary_test( + name = "constraint_programming_cp_test", + size = "small", + binary = ":constraint_programming_cp", +) + +cc_binary( + name = "costas_array_sat", + srcs = ["costas_array_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/base:types", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", + ], +) + +run_binary_test( + name = "costas_array_sat_model1_test", + size = "medium", +<<<<<<< HEAD + srcs = ["costas_array_sat.cc"], + args = [ + "--minsize=6 --maxsize=6 --model=1", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +======= + args = ["--minsize=6 --maxsize=6 --model=1"], + binary = ":costas_array_sat", +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +run_binary_test( + name = "costas_array_sat_model2_test", + size = "medium", +<<<<<<< HEAD + srcs = ["costas_array_sat.cc"], + args = [ + "--minsize=6 --maxsize=6 --model=2", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +======= + args = ["--minsize=6 --maxsize=6 --model=2"], + binary = ":costas_array_sat", +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +run_binary_test( + name = "costas_array_sat_model3_test", + size = "medium", +<<<<<<< HEAD + srcs = ["costas_array_sat.cc"], + args = [ + "--minsize=6 --maxsize=6 --model=3", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +======= + args = ["--minsize=6 --maxsize=6 --model=3"], + binary = ":costas_array_sat", +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +cc_binary( + name = "cryptarithm_sat", + srcs = ["cryptarithm_sat.cc"], + deps = ["//ortools/sat:cp_model"], +) + +run_binary_test( + name = "cryptarithm_sat_test", + size = "small", + binary = ":cryptarithm_sat", +) + +cc_binary( + name = "dobble_ls", + srcs = ["dobble_ls.cc"], + deps = [ + "//ortools/base", + "//ortools/base:map_util", + "//ortools/base:types", + "//ortools/constraint_solver:cp", + "//ortools/util:bitset", + "@abseil-cpp//absl/random", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", + ], +) + +run_binary_test( + name = "dobble_ls_test", + size = "medium", + args = ["--time_limit_in_ms=10000"], + binary = ":dobble_ls", +) + +cc_binary( + name = "golomb_sat", + srcs = ["golomb_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings:str_format", + "@protobuf", + ], +) + +run_binary_test( + name = "golomb_sat_test", + size = "medium", + args = ["--size 5"], + binary = ":golomb_sat", +) + +cc_binary( + name = "knapsack_2d_sat", + srcs = [ + "knapsack_2d_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/packing:binpacking_2d_parser", + "//ortools/packing:multiple_dimensions_bin_packing_cc_proto", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_solver", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/types:span", + "@protobuf", + ], +) + +run_binary_test( + name = "knapsack_2d_sat_class01_instance2_test", + size = "medium", +<<<<<<< HEAD + srcs = [ + "knapsack_2d_sat.cc", + ], +======= +>>>>>>> 3b384e83a4 ([bazel] Update examples) + args = ["--input $(rootpath //ortools/packing/testdata:Class_01.2bp) --instance 2"], + binary = ":knapsack_2d_sat", + data = ["//ortools/packing/testdata:Class_01.2bp"], +) + +cc_binary( + name = "jobshop_sat", + srcs = [ + "jobshop_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/graph:connected_components", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "//ortools/sat:sat_parameters_cc_proto", + "//ortools/scheduling:jobshop_scheduling_cc_proto", + "//ortools/scheduling:jobshop_scheduling_parser", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/container:flat_hash_set", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + "@protobuf", + "@protobuf//:wrappers_cc_proto", + ], +) + +run_binary_test( + name = "jobshop_sat_ft06", + size = "small", +<<<<<<< HEAD + srcs = [ + "jobshop_sat.cc", + ], +======= +>>>>>>> 3b384e83a4 ([bazel] Update examples) + args = ["--input $(rootpath //ortools/scheduling/testdata:ft06)"], + binary = ":jobshop_sat", + data = ["//ortools/scheduling/testdata:ft06"], +) + +cc_binary( + name = "magic_sequence_sat", + srcs = ["magic_sequence_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings:str_format", + ], +) + +run_binary_test( + name = "magic_sequence_sat_test", + size = "medium", + binary = ":magic_sequence_sat", +) + +cc_binary( + name = "multi_knapsack_sat", + srcs = [ + "multi_knapsack_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + ], +) + +run_binary_test( + name = "multi_knapsack_sat_test", + size = "medium", +<<<<<<< HEAD + srcs = [ + "multi_knapsack_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "@abseil-cpp//absl/flags:flag", + ], +======= + binary = ":multi_knapsack_sat", +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +cc_binary( + name = "shift_minimization_sat", + srcs = [ + "shift_minimization_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "//ortools/util:filelineiter", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + ], +) + +run_binary_test( + name = "shift_minimization_sat_test", + size = "medium", +<<<<<<< HEAD + srcs = [ + "shift_minimization_sat.cc", + ], + args = ["--input $(rootpath //examples/cpp:shift_minimization.dat)"], + data = ["//examples/cpp:shift_minimization.dat"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "//ortools/util:filelineiter", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/strings", + ], +======= + args = ["--input $(rootpath :shift_minimization.dat)"], + binary = ":shift_minimization_sat", + data = [":shift_minimization.dat"], +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +cc_binary( + name = "weighted_tardiness_sat", + srcs = [ + "weighted_tardiness_sat.cc", + ], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "//ortools/sat:model", + "//ortools/sat:sat_parameters_cc_proto", + "//ortools/util:filelineiter", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + ], +) + +run_binary_test( + name = "weighted_tardiness_sat_test", + size = "medium", +<<<<<<< HEAD + srcs = [ + "weighted_tardiness_sat.cc", + ], + args = ["--input $(rootpath //examples/cpp:wt40.txt)"], + data = ["//examples/cpp:wt40.txt"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_solver", + "//ortools/sat:disjunctive", + "//ortools/sat:integer", + "//ortools/sat:integer_expr", + "//ortools/sat:intervals", + "//ortools/sat:model", + "//ortools/sat:optimization", + "//ortools/sat:precedences", + "//ortools/sat:sat_solver", + "//ortools/util:filelineiter", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/strings", + "@protobuf", + ], +======= + args = ["--input $(rootpath :wt40.txt)"], + binary = ":weighted_tardiness_sat", + data = [":wt40.txt"], +>>>>>>> 3b384e83a4 ([bazel] Update examples) +) + +cc_binary( + name = "magic_square_sat", + srcs = ["magic_square_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings:str_format", + ], +) + +run_binary_test( + name = "magic_square_sat_test", + size = "medium", + binary = ":magic_square_sat", +) + +cc_binary( + name = "network_routing_sat", + srcs = ["network_routing_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/graph", + "//ortools/graph:shortest_paths", + "//ortools/sat:cp_model", + "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "//ortools/util:time_limit", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/container:flat_hash_set", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/random:distributions", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/strings:string_view", + ], +) + +run_binary_test( + name = "network_routing_sat_test", + size = "medium", + args = [ + "--clients=10", + "--backbones=5", + "--demands=10", + "--traffic_min=5", + "--traffic_max=10", + "--min_client_degree=2", + "--max_client_degree=5", + "--min_backbone_degree=3", + "--max_backbone_degree=5", + "--max_capacity=20", + "--fixed_charge_cost=10", + ], + binary = ":network_routing_sat", +) + +cc_binary( + name = "nqueens", + srcs = ["nqueens.cc"], + deps = [ + "//ortools/base", + "//ortools/base:map_util", + "//ortools/base:types", + "//ortools/constraint_solver:cp", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/strings:str_format", + ], +) + +run_binary_test( + name = "nqueens_test", + size = "small", + binary = ":nqueens", +) + +cc_binary( + name = "sports_scheduling_sat", + srcs = ["sports_scheduling_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:model", + "//ortools/util:sorted_interval_list", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +) + +run_binary_test( + name = "sports_scheduling_sat_test", + size = "medium", + binary = ":sports_scheduling_sat", +) + +cc_binary( + name = "pdptw", + srcs = ["pdptw.cc"], + deps = [ + "//ortools/base", + "//ortools/base:mathutil", + "//ortools/base:timer", + "//ortools/constraint_solver:cp", + "//ortools/routing", + "//ortools/routing:enums_cc_proto", + "//ortools/routing:index_manager", + "//ortools/routing:parameters", + "//ortools/routing:parameters_cc_proto", + "//ortools/routing:types", + "//ortools/routing/parsers:lilim_parser", + "//ortools/routing/parsers:simple_graph", + "@abseil-cpp//absl/algorithm:container", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@protobuf", + ], +) + +# Routing examples. +cc_binary( + name = "random_tsp", + srcs = ["random_tsp.cc"], + deps = [ +<<<<<<< HEAD + "//ortools/base", + "//ortools/constraint_solver:routing", + "//ortools/util:random_engine", + "@abseil-cpp//absl/strings", + "@protobuf", + ], +) + +cc_binary( + name = "pdptw", + srcs = ["pdptw.cc"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/base:mathutil", + "//ortools/constraint_solver:routing", + "//ortools/routing/parsers:lilim_parser", +======= + "//ortools/constraint_solver:cp", + "//ortools/routing", + "//ortools/routing:index_manager", + "//ortools/routing:parameters", + "//ortools/routing:parameters_cc_proto", + "//ortools/util:random_engine", + "@abseil-cpp//absl/base:log_severity", +>>>>>>> 3b384e83a4 ([bazel] Update examples) + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/log:initialize", + "@abseil-cpp//absl/random", + "@abseil-cpp//absl/strings", + "@protobuf", + ], +) + +# Linear and integer programming examples. +cc_binary( + name = "integer_programming", + srcs = ["integer_programming.cc"], + deps = [ + "//ortools/base", + "//ortools/linear_solver", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + ], +) + +run_binary_test( + name = "integer_programming_test", + size = "small", + binary = ":integer_programming", +) + +cc_binary( + name = "linear_programming", + srcs = ["linear_programming.cc"], + deps = [ + "//ortools/base", + "//ortools/linear_solver", + "//ortools/linear_solver:linear_solver_cc_proto", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + ], +) + +run_binary_test( + name = "linear_programming_test", + size = "small", + binary = ":linear_programming", +) + +cc_binary( + name = "linear_solver_protocol_buffers", + srcs = ["linear_solver_protocol_buffers.cc"], + deps = [ + "//ortools/base", + "//ortools/linear_solver:linear_solver_cc_proto", + "//ortools/linear_solver:solve_mp_model", + ], +) + +run_binary_test( + name = "linear_solver_protocol_buffers_test", + size = "small", + binary = ":linear_solver_protocol_buffers", +) + +cc_binary( + name = "strawberry_fields_with_column_generation", + srcs = ["strawberry_fields_with_column_generation.cc"], + deps = [ + "//ortools/base", + "//ortools/linear_solver", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", + ], +) + +run_binary_test( + name = "strawberry_fields_with_column_generation_test", + size = "large", + args = ["--colgen_instance=4"], + binary = ":strawberry_fields_with_column_generation", +) + +# Dimacs assignment problems +cc_library( + name = "print_dimacs_assignment", + hdrs = ["print_dimacs_assignment.h"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/graph:linear_assignment", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +) + +cc_library( + name = "parse_dimacs_assignment", + srcs = ["parse_dimacs_assignment.cc"], + hdrs = ["parse_dimacs_assignment.h"], + deps = [ + "//ortools/graph:linear_assignment", + "//ortools/util:filelineiter", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/strings", + ], +) + +cc_binary( + name = "dimacs_assignment", + srcs = ["dimacs_assignment.cc"], + deps = [ + ":parse_dimacs_assignment", + ":print_dimacs_assignment", + "//ortools/algorithms:hungarian", + "//ortools/base", + "//ortools/base:timer", + "//ortools/graph", + "//ortools/graph:linear_assignment", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/strings:str_format", + ], +) + +# MPS driver for LP and MIP. +cc_binary( + name = "mps_driver", + srcs = ["mps_driver.cc"], + copts = ["-Wfloat-conversion"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/base:timer", + "//ortools/glop:lp_solver", + "//ortools/glop:parameters_cc_proto", + "//ortools/lp_data", + "//ortools/lp_data:base", + "//ortools/lp_data:mps_reader", + "//ortools/lp_data:proto_utils", + "//ortools/util:file_util", + "//ortools/util:proto_tools", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@protobuf", + ], +) + +run_binary_test( + name = "mps_driver_test", + size = "small", + args = ["--input $(rootpath //ortools/linear_solver/testdata:maximization.mps)"], + binary = ":mps_driver", + data = ["//ortools/linear_solver/testdata:maximization.mps"], +) + +# Linear Assignment C++ Example +cc_binary( + name = "linear_assignment_api", + srcs = ["linear_assignment_api.cc"], + deps = [ + "//ortools/base", + "//ortools/graph", + "//ortools/graph:linear_assignment", + ], +) + +run_binary_test( + name = "linear_assignment_api_test", + size = "small", + binary = ":linear_assignment_api", +) + +# Flow C++ Example +cc_binary( + name = "flow_api", + srcs = ["flow_api.cc"], + deps = [ + "//ortools/base", + "//ortools/graph", + "//ortools/graph:generic_max_flow", + "//ortools/graph:min_cost_flow", + ], +) + +run_binary_test( + name = "flow_api_test", + size = "small", + binary = ":flow_api", +) + +cc_binary( + name = "max_flow", + srcs = ["max_flow.cc"], + deps = [ + "//ortools/base", + "//ortools/graph", + "//ortools/graph:generic_max_flow", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + ], +) + +run_binary_test( + name = "max_flow_test", + size = "small", + binary = ":max_flow", +) + +cc_binary( + name = "min_cost_flow", + srcs = ["min_cost_flow.cc"], + deps = [ + "//ortools/base", + "//ortools/graph:min_cost_flow", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:globals", + ], +) + +run_binary_test( + name = "min_cost_flow_test", + size = "small", + binary = ":min_cost_flow", +) + +# Frequency Assignment Problem +cc_library( + name = "fap_parser", + srcs = ["fap_parser.cc"], + hdrs = ["fap_parser.h"], + deps = [ + "//ortools/base:file", + "//ortools/base:map_util", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + ], +) + +cc_library( + name = "fap_model_printer", + srcs = ["fap_model_printer.cc"], + hdrs = ["fap_model_printer.h"], + deps = [ + ":fap_parser", + "//ortools/base:logging", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + ], +) + +cc_library( + name = "fap_utilities", + srcs = ["fap_utilities.cc"], + hdrs = ["fap_utilities.h"], + deps = [ + ":fap_parser", + "//ortools/base", + "//ortools/base:map_util", + "//ortools/constraint_solver:cp", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/types:span", + ], +) + +cc_binary( + name = "frequency_assignment_problem", + srcs = ["frequency_assignment_problem.cc"], + deps = [ + ":fap_model_printer", + ":fap_parser", + ":fap_utilities", + "//ortools/base", + "//ortools/base:map_util", + "//ortools/constraint_solver:cp", + "@abseil-cpp//absl/container:btree", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/types:span", + ], +) + +# Quadratic assignment problem. + +cc_binary( + name = "qap_sat", + srcs = ["qap_sat.cc"], + deps = [ + "//ortools/base", + "//ortools/sat:cp_model", + "//ortools/sat:sat_parameters_cc_proto", + "//ortools/util:qap_reader", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/strings", + "@protobuf", + ], +) + +cc_binary( + name = "slitherlink_sat", + srcs = ["slitherlink_sat.cc"], + deps = [ + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_cc_proto", + "//ortools/sat:cp_model_solver", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/log", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/types:span", + ], +) + +run_binary_test( + name = "slitherlink_sat_test", + size = "small", + binary = ":slitherlink_sat", +) + +cc_binary( + name = "uncapacitated_facility_location", + srcs = ["uncapacitated_facility_location.cc"], + deps = [ + "//ortools/base", + "//ortools/linear_solver", + "//ortools/util:random_engine", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/flags:parse", + "@abseil-cpp//absl/flags:usage", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/log:initialize", + "@abseil-cpp//absl/random", + ], +) + +cc_binary( + name = "variable_intervals_sat", + srcs = ["variable_intervals_sat.cc"], + deps = [ + "//ortools/sat:cp_model", + "//ortools/sat:cp_model_solver", + "//ortools/sat:sat_parameters_cc_proto", + "//ortools/util:time_limit", + "@abseil-cpp//absl/log", + ], +) + +run_binary_test( + name = "variable_intervals_sat_test", + size = "small", + binary = ":variable_intervals_sat", +) + +cc_binary( + name = "pdlp_solve", + srcs = ["pdlp_solve.cc"], + deps = [ + "//ortools/base", + "//ortools/base:file", + "//ortools/pdlp:iteration_stats", + "//ortools/pdlp:primal_dual_hybrid_gradient", + "//ortools/pdlp:quadratic_program", + "//ortools/pdlp:quadratic_program_io", + "//ortools/pdlp:solve_log_cc_proto", + "//ortools/pdlp:solvers_cc_proto", + "//ortools/port:proto_utils", + "//ortools/util:file_util", + "//ortools/util:fp_roundtrip_conv", + "//ortools/util:sigint", + "@abseil-cpp//absl/base:log_severity", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:flags", + "@abseil-cpp//absl/log:globals", + "@abseil-cpp//absl/strings", + ], +) diff --git a/examples/cpp/vector_bin_packing_solver.cc b/examples/cpp/vector_bin_packing_solver.cc deleted file mode 100644 index 3aa7a9b3c4..0000000000 --- a/examples/cpp/vector_bin_packing_solver.cc +++ /dev/null @@ -1,112 +0,0 @@ -// 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. - -#include -#include - -#include "absl/flags/flag.h" -#include "absl/log/globals.h" -#include "absl/status/status.h" -#include "absl/strings/match.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_join.h" -#include "absl/strings/string_view.h" -#include "ortools/base/commandlineflags.h" -#include "ortools/base/file.h" -#include "ortools/base/helpers.h" -#include "ortools/base/init_google.h" -#include "ortools/base/logging.h" -#include "ortools/base/timer.h" -#include "ortools/packing/arc_flow_builder.h" -#include "ortools/packing/arc_flow_solver.h" -#include "ortools/packing/vector_bin_packing.pb.h" -#include "ortools/packing/vector_bin_packing_parser.h" - -ABSL_FLAG(std::string, input, "", "Vector Bin Packing (.vpb) data file name."); -ABSL_FLAG(std::string, params, "num_workers:16,max_time_in_seconds:10", - "Parameters in solver specific text format."); -ABSL_FLAG(std::string, solver, "sat", "Solver to use: sat, scip"); -ABSL_FLAG(double, time_limit, 900.0, "Time limit in seconds"); -ABSL_FLAG(int, threads, 1, "Number of threads"); -ABSL_FLAG(bool, display_proto, false, "Print the input protobuf"); -ABSL_FLAG(int, max_bins, -1, - "Maximum number of bins: default = -1 meaning no limits"); - -namespace operations_research { -void ParseAndSolve(const std::string& filename, absl::string_view solver, - const std::string& params) { - std::string problem_name = filename; - const size_t found = problem_name.find_last_of("/\\"); - if (found != std::string::npos) { - problem_name = problem_name.substr(found + 1); - } - if (absl::EndsWith(problem_name, ".vbp")) { - // TODO(user): Move naming code to parser. - problem_name.resize(problem_name.size() - 4); - } - - packing::vbp::VectorBinPackingProblem data; - - packing::vbp::VbpParser parser; - if (!parser.ParseFile(filename)) { - LOG(FATAL) << "Cannot read " << filename; - } - data = parser.problem(); - data.set_name(problem_name); - - if (data.max_bins() != 0) { - LOG(WARNING) - << "Ignoring max_bins value. The feasibility problem is not supported."; - } - - LOG(INFO) << "Solving vector packing problem '" << data.name() << "' with " - << data.item_size() << " item types, and " - << data.resource_capacity_size() << " dimensions."; - if (absl::GetFlag(FLAGS_display_proto)) { - LOG(INFO) << data; - } - - // Build optimization model. - MPSolver::OptimizationProblemType solver_type; - MPSolver::ParseSolverType(solver, &solver_type); - packing::vbp::VectorBinPackingSolution solution = - packing::SolveVectorBinPackingWithArcFlow( - data, solver_type, params, absl::GetFlag(FLAGS_time_limit), - absl::GetFlag(FLAGS_threads), absl::GetFlag(FLAGS_max_bins)); - if (!solution.bins().empty()) { - for (int b = 0; b < solution.bins_size(); ++b) { - LOG(INFO) << "Bin " << b; - const packing::vbp::VectorBinPackingOneBinInSolution& bin = - solution.bins(b); - for (int i = 0; i < bin.item_indices_size(); ++i) { - LOG(INFO) << " - item: " << bin.item_indices(i) - << ", copies: " << bin.item_copies(i); - } - } - } -} - -} // namespace operations_research - -int main(int argc, char** argv) { - absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo); - InitGoogle(argv[0], &argc, &argv, true); - if (absl::GetFlag(FLAGS_input).empty()) { - LOG(FATAL) << "Please supply a data file with --input="; - } - - operations_research::ParseAndSolve(absl::GetFlag(FLAGS_input), - absl::GetFlag(FLAGS_solver), - absl::GetFlag(FLAGS_params)); - return EXIT_SUCCESS; -} diff --git a/examples/python/BUILD.bazel b/examples/python/BUILD.bazel index 632e68bbb6..03313e71d6 100644 --- a/examples/python/BUILD.bazel +++ b/examples/python/BUILD.bazel @@ -11,103 +11,622 @@ # See the License for the specific language governing permissions and # limitations under the License. -# BUILD file to run python examples. +load("@pip_deps//:requirements.bzl", "requirement") +load("@rules_python//python:py_binary.bzl", "py_binary") +load("//bazel:run_binary_test.bzl", "run_binary_test") -load(":code_samples.bzl", "code_sample_compile_py", "code_sample_py", "code_sample_test_arg_py") +package(default_visibility = ["//visibility:public"]) -code_sample_compile_py("arc_flow_cutting_stock_sat") +py_binary( + name = "arc_flow_cutting_stock_sat_py3", + srcs = ["arc_flow_cutting_stock_sat.py"], + main = "arc_flow_cutting_stock_sat.py", + deps = [ + requirement("absl-py"), + requirement("numpy"), + "//ortools/linear_solver/python:model_builder", + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("assignment_with_constraints_sat") +py_binary( + name = "assignment_with_constraints_sat_py3", + srcs = ["assignment_with_constraints_sat.py"], + main = "assignment_with_constraints_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("balance_group_sat") +run_binary_test( + name = "assignment_with_constraints_sat_py_test", + size = "medium", + binary = ":assignment_with_constraints_sat_py3", +) -code_sample_py("bus_driver_scheduling_sat") +py_binary( + name = "balance_group_sat_py3", + srcs = ["balance_group_sat.py"], + main = "balance_group_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("car_sequencing_optimization_sat") +run_binary_test( + name = "balance_group_sat_py_test", + size = "medium", + binary = ":balance_group_sat_py3", +) -code_sample_py("chemical_balance_sat") +py_binary( + name = "bus_driver_scheduling_sat_py3", + srcs = ["bus_driver_scheduling_sat.py"], + main = "bus_driver_scheduling_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("clustering_sat") +run_binary_test( + name = "bus_driver_scheduling_sat_py_test", + size = "medium", + args = ["--params=max_time_in_seconds:40"], + binary = ":bus_driver_scheduling_sat_py3", +) -code_sample_py("cover_rectangle_sat") +py_binary( + name = "car_sequencing_optimization_sat_py3", + srcs = ["car_sequencing_optimization_sat.py"], + main = "car_sequencing_optimization_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("flexible_job_shop_sat") +run_binary_test( + name = "car_sequencing_optimization_sat_py_test", + size = "small", + binary = ":car_sequencing_optimization_sat_py3", +) -code_sample_py("gate_scheduling_sat") +py_binary( + name = "chemical_balance_sat_py3", + srcs = ["chemical_balance_sat.py"], + main = "chemical_balance_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("golomb_sat") +run_binary_test( + name = "chemical_balance_sat_py_test", + size = "medium", + binary = ":chemical_balance_sat_py3", +) -code_sample_py("hidato_sat") +py_binary( + name = "clustering_sat_py3", + srcs = ["clustering_sat.py"], + main = "clustering_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("jobshop_ft06_distance_sat") +run_binary_test( + name = "clustering_sat_py_test", + size = "medium", + binary = ":clustering_sat_py3", +) -code_sample_py("jobshop_ft06_sat") +py_binary( + name = "cover_rectangle_sat_py3", + srcs = ["cover_rectangle_sat.py"], + main = "cover_rectangle_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("jobshop_with_maintenance_sat") +run_binary_test( + name = "cover_rectangle_sat_py_test", + size = "medium", + binary = ":cover_rectangle_sat_py3", +) -code_sample_py("knapsack_2d_sat") +py_binary( + name = "flexible_job_shop_sat_py3", + srcs = ["flexible_job_shop_sat.py"], + main = "flexible_job_shop_sat.py", + deps = ["//ortools/sat/python:cp_model"], +) -code_sample_compile_py("line_balancing_sat") +run_binary_test( + name = "flexible_job_shop_sat_py_test", + binary = ":flexible_job_shop_sat_py3", +) -code_sample_test_arg_py( - name = "line_balancing_sat", - args = ["--input $(rootpath //examples/python/testdata:salbp_20_1.alb)"], +py_binary( + name = "gate_scheduling_sat_py3", + srcs = ["gate_scheduling_sat.py"], + main = "gate_scheduling_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/colab:visualization", + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "gate_scheduling_sat_py_test", + binary = ":gate_scheduling_sat_py3", +) + +py_binary( + name = "golomb_sat_py3", + srcs = ["golomb_sat.py"], + main = "golomb_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "golomb_sat_py_test", + size = "medium", + binary = ":golomb_sat_py3", +) + +py_binary( + name = "hidato_sat_py3", + srcs = ["hidato_sat.py"], + main = "hidato_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/colab:visualization", + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "hidato_sat_py_test", + binary = ":hidato_sat_py3", +) + +py_binary( + name = "jobshop_ft06_distance_sat_py3", + srcs = ["jobshop_ft06_distance_sat.py"], + main = "jobshop_ft06_distance_sat.py", + deps = ["//ortools/sat/python:cp_model"], +) + +run_binary_test( + name = "jobshop_ft06_distance_sat_py_test", + binary = ":jobshop_ft06_distance_sat_py3", +) + +py_binary( + name = "jobshop_ft06_sat_py3", + srcs = ["jobshop_ft06_sat.py"], + main = "jobshop_ft06_sat.py", + deps = [ + "//ortools/sat/colab:visualization", + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "jobshop_ft06_sat_py_test", + binary = ":jobshop_ft06_sat_py3", +) + +py_binary( + name = "jobshop_with_maintenance_sat_py3", + srcs = ["jobshop_with_maintenance_sat.py"], + main = "jobshop_with_maintenance_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "jobshop_with_maintenance_sat_py_test", + size = "medium", + binary = ":jobshop_with_maintenance_sat_py3", +) + +py_binary( + name = "knapsack_2d_sat_py3", + srcs = ["knapsack_2d_sat.py"], + main = "knapsack_2d_sat.py", + deps = [ + requirement("absl-py"), + requirement("numpy"), + requirement("pandas"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "knapsack_2d_sat_py_test", + size = "medium", + binary = ":knapsack_2d_sat_py3", +) + +py_binary( + name = "line_balancing_sat_py3", + srcs = ["line_balancing_sat.py"], + main = "line_balancing_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "line_balancing_sat_salbp_20_1_py_test", + args = ["--input=$(rootpath //examples/python/testdata:salbp_20_1.alb)"], + binary = ":line_balancing_sat_py3", data = ["//examples/python/testdata:salbp_20_1.alb"], - suffix = "salbp_20_1", + grep_lines = ["objective: 3"], ) -code_sample_py("maximize_combinations_sat") - -code_sample_py("maze_escape_sat") - -code_sample_py("no_wait_baking_scheduling_sat") - -code_sample_py("pell_equation_sat") - -code_sample_py("pentominoes_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") - -code_sample_test_arg_py( - name = "rcpsp_sat", - args = ["--input $(rootpath //ortools/scheduling/testdata:j301_1.sm)"], - data = ["//ortools/scheduling/testdata:j301_1.sm"], - suffix = "j301_1", +py_binary( + name = "maximize_combinations_sat_py3", + srcs = ["maximize_combinations_sat.py"], + main = "maximize_combinations_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], ) -code_sample_test_arg_py( - name = "rcpsp_sat", - args = ["--input $(rootpath //ortools/scheduling/testdata:c1510_1.mm.txt)"], +run_binary_test( + name = "maximize_combinations_sat_py_test", + size = "medium", + binary = ":maximize_combinations_sat_py3", +) + +py_binary( + name = "maze_escape_sat_py3", + srcs = ["maze_escape_sat.py"], + main = "maze_escape_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "maze_escape_sat_py_test", + binary = ":maze_escape_sat_py3", +) + +py_binary( + name = "music_playlist_sat_py3", + srcs = ["music_playlist_sat.py"], + main = "music_playlist_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "music_playlist_sat_py_test", + binary = ":music_playlist_sat_py3", +) + +py_binary( + name = "no_wait_baking_scheduling_sat_py3", + srcs = ["no_wait_baking_scheduling_sat.py"], + main = "no_wait_baking_scheduling_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "no_wait_baking_scheduling_sat_py_test", + size = "medium", + binary = ":no_wait_baking_scheduling_sat_py3", +) + +py_binary( + name = "pell_equation_sat_py3", + srcs = ["pell_equation_sat.py"], + main = "pell_equation_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "pell_equation_sat_py_test", + size = "medium", + binary = ":pell_equation_sat_py3", +) + +py_binary( + name = "pentominoes_sat_py3", + srcs = ["pentominoes_sat.py"], + main = "pentominoes_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "pentominoes_sat_py_test", + size = "medium", + binary = ":pentominoes_sat_py3", +) + +py_binary( + name = "prize_collecting_tsp_sat_py3", + srcs = ["prize_collecting_tsp_sat.py"], + main = "prize_collecting_tsp_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "prize_collecting_tsp_sat_py_test", + size = "medium", + binary = ":prize_collecting_tsp_sat_py3", +) + +py_binary( + name = "prize_collecting_vrp_sat_py3", + srcs = ["prize_collecting_vrp_sat.py"], + main = "prize_collecting_vrp_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "prize_collecting_vrp_sat_py_test", + size = "medium", + binary = ":prize_collecting_vrp_sat_py3", +) + +py_binary( + name = "qubo_sat_py3", + srcs = ["qubo_sat.py"], + main = "qubo_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "qubo_sat_py_test", + size = "medium", + binary = ":qubo_sat_py3", +) + +run_binary_test( + name = "rcpsp_sat_c1510_1_py_test", + args = ["--input=$(rootpath //ortools/scheduling/testdata:c1510_1.mm.txt)"], + binary = ":rcpsp_sat_py3", data = ["//ortools/scheduling/testdata:c1510_1.mm.txt"], - suffix = "c1510_1", + grep_lines = ["objective: 21"], ) -code_sample_py("shift_scheduling_sat") +run_binary_test( + name = "rcpsp_sat_j301_1_py_test", + args = ["--input=$(rootpath //ortools/scheduling/testdata:j301_1.sm)"], + binary = ":rcpsp_sat_py3", + data = ["//ortools/scheduling/testdata:j301_1.sm"], + grep_lines = ["objective: 43"], +) -code_sample_py("single_machine_scheduling_with_setup_release_due_dates_sat") +py_binary( + name = "rcpsp_sat_py3", + srcs = ["rcpsp_sat.py"], + main = "rcpsp_sat.py", + deps = [ + "//ortools/scheduling:rcpsp_py_pb2", + "//ortools/scheduling/python:rcpsp", + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("spread_robots_sat") +py_binary( + name = "shift_scheduling_sat_py3", + srcs = ["shift_scheduling_sat.py"], + main = "shift_scheduling_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("steel_mill_slab_sat") +run_binary_test( + name = "shift_scheduling_sat_py_test", + args = ["--params=max_time_in_seconds:10"], + binary = ":shift_scheduling_sat_py3", +) -code_sample_py("sudoku_sat") +py_binary( + name = "single_machine_scheduling_with_setup_release_due_dates_sat_py3", + srcs = ["single_machine_scheduling_with_setup_release_due_dates_sat.py"], + main = "single_machine_scheduling_with_setup_release_due_dates_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("task_allocation_sat") +run_binary_test( + name = "single_machine_scheduling_with_setup_release_due_dates_sat_py_test", + size = "medium", + binary = ":single_machine_scheduling_with_setup_release_due_dates_sat_py3", +) -code_sample_py("tasks_and_workers_assignment_sat") +py_binary( + name = "spread_robots_sat_py3", + srcs = ["spread_robots_sat.py"], + main = "spread_robots_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("test_scheduling_sat") +run_binary_test( + name = "spread_robots_sat_py_test", + binary = ":spread_robots_sat_py3", +) -code_sample_py("tsp_sat") +py_binary( + name = "steel_mill_slab_sat_py3", + srcs = ["steel_mill_slab_sat.py"], + main = "steel_mill_slab_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) -code_sample_py("vendor_scheduling_sat") +run_binary_test( + name = "steel_mill_slab_sat_py_test", + binary = ":steel_mill_slab_sat_py3", +) -code_sample_py("wedding_optimal_chart_sat") +py_binary( + name = "sudoku_sat_py3", + srcs = ["sudoku_sat.py"], + main = "sudoku_sat.py", + deps = ["//ortools/sat/python:cp_model"], +) -code_sample_py("zebra_sat") +run_binary_test( + name = "sudoku_sat_py_test", + binary = ":sudoku_sat_py3", +) + +py_binary( + name = "task_allocation_sat_py3", + srcs = ["task_allocation_sat.py"], + main = "task_allocation_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "task_allocation_sat_py_test", + size = "medium", + binary = ":task_allocation_sat_py3", +) + +py_binary( + name = "tasks_and_workers_assignment_sat_py3", + srcs = ["tasks_and_workers_assignment_sat.py"], + main = "tasks_and_workers_assignment_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "tasks_and_workers_assignment_sat_py_test", + size = "medium", + binary = ":tasks_and_workers_assignment_sat_py3", +) + +py_binary( + name = "test_scheduling_sat_py3", + srcs = ["test_scheduling_sat.py"], + main = "test_scheduling_sat.py", + deps = [ + requirement("absl-py"), + requirement("pandas"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "test_scheduling_sat_py_test", + size = "medium", + binary = ":test_scheduling_sat_py3", +) + +py_binary( + name = "tsp_sat_py3", + srcs = ["tsp_sat.py"], + main = "tsp_sat.py", + deps = ["//ortools/sat/python:cp_model"], +) + +run_binary_test( + name = "tsp_sat_py_test", + size = "medium", + binary = ":tsp_sat_py3", +) + +py_binary( + name = "vendor_scheduling_sat_py3", + srcs = ["vendor_scheduling_sat.py"], + main = "vendor_scheduling_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "vendor_scheduling_sat_py_test", + size = "medium", + binary = ":vendor_scheduling_sat_py3", +) + +py_binary( + name = "wedding_optimal_chart_sat_py3", + srcs = ["wedding_optimal_chart_sat.py"], + main = "wedding_optimal_chart_sat.py", + deps = [ + requirement("absl-py"), + "//ortools/sat/python:cp_model", + ], +) + +run_binary_test( + name = "wedding_optimal_chart_sat_py_test", + size = "medium", + binary = ":wedding_optimal_chart_sat_py3", +) + +py_binary( + name = "zebra_sat_py3", + srcs = ["zebra_sat.py"], + main = "zebra_sat.py", + deps = ["//ortools/sat/python:cp_model"], +) + +run_binary_test( + name = "zebra_sat_py_test", + binary = ":zebra_sat_py3", +) diff --git a/examples/python/code_samples.bzl b/examples/python/code_samples.bzl deleted file mode 100644 index bf95011b86..0000000000 --- a/examples/python/code_samples.bzl +++ /dev/null @@ -1,66 +0,0 @@ -# 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. - -"""Helper macro to compile and test code samples.""" - -load("@pip_deps//:requirements.bzl", "requirement") -load("@rules_python//python:py_binary.bzl", "py_binary") -load("@rules_python//python:py_test.bzl", "py_test") - -PYTHON_DEPS = [ - "//ortools/init/python:init", - "//ortools/linear_solver/python:model_builder", - "//ortools/sat/python:cp_model", - "//ortools/sat/colab:visualization", - "//ortools/scheduling:rcpsp_py_proto", - "//ortools/scheduling/python:rcpsp", - requirement("absl-py"), - requirement("numpy"), - requirement("pandas"), - requirement("protobuf"), - requirement("python_dateutil"), - requirement("pytz"), - requirement("six"), -] - -def code_sample_compile_py(name): - py_binary( - name = name + "_py3", - srcs = [name + ".py"], - main = name + ".py", - deps = PYTHON_DEPS, - ) - -def code_sample_test_py(name): - py_test( - name = name + "_py_test", - size = "medium", - srcs = [name + ".py"], - main = name + ".py", - deps = PYTHON_DEPS, - ) - -def code_sample_test_arg_py(name, suffix, args, data): - py_test( - name = name + "_" + suffix + "_py_test", - size = "medium", - srcs = [name + ".py"], - main = name + ".py", - data = data, - args = args, - deps = PYTHON_DEPS, - ) - -def code_sample_py(name): - code_sample_compile_py(name) - code_sample_test_py(name) diff --git a/examples/python/music_playlist_sat.py b/examples/python/music_playlist_sat.py new file mode 100644 index 0000000000..ee0b3fe2c9 --- /dev/null +++ b/examples/python/music_playlist_sat.py @@ -0,0 +1,309 @@ +#!/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. + +"""Create a balanced music playlist. + +Create a music playlist by selecting tunes from a list of tunes. + +Each tune has a duration in seconds and a music genre (e.g. Rock, Disco, Techno, +etc). + +The total playlist duration must be as close as possible to a given total +duration. Each tune can appear at most once in the playlist. All existing +genres must appear at least once in the playlist. Two consecutive tunes must be +of different genres. There is a positive cost to go from a genre to another, and +the playlist must minimize this cost overall. +""" + +from collections.abc import Sequence + +from absl import app +from ortools.sat.python import cp_model + + +def Solve(): + """Solves the music playlist problem.""" + + # -------------------- + # 1. Data + # -------------------- + tunes = [ + ("Song 01", 202, "Pop"), + ("Song 02", 233, "Techno"), + ("Song 03", 108, "Disco"), + ("Song 04", 281, "Disco"), + ("Song 05", 129, "Techno"), + ("Song 06", 122, "Techno"), + ("Song 07", 244, "Pop"), + ("Song 08", 178, "Techno"), + ("Song 09", 213, "Techno"), + ("Song 10", 124, "Rock"), + ("Song 11", 120, "Disco"), + ("Song 12", 196, "Rock"), + ("Song 13", 249, "Disco"), + ("Song 14", 294, "Disco"), + ("Song 15", 103, "Techno"), + ("Song 16", 179, "Disco"), + ("Song 17", 146, "Disco"), + ("Song 18", 126, "Techno"), + ("Song 19", 100, "Pop"), + ("Song 20", 122, "Disco"), + ("Song 21", 190, "Disco"), + ("Song 22", 181, "Techno"), + ("Song 23", 273, "Pop"), + ("Song 24", 121, "Disco"), + ("Song 25", 159, "Pop"), + ("Song 26", 234, "Rock"), + ("Song 27", 169, "Rock"), + ("Song 28", 151, "Rock"), + ("Song 29", 142, "Techno"), + ("Song 30", 245, "Pop"), + ("Song 31", 281, "Techno"), + ("Song 32", 154, "Rock"), + ("Song 33", 148, "Disco"), + ("Song 34", 120, "Pop"), + ("Song 35", 163, "Disco"), + ("Song 36", 158, "Pop"), + ("Song 37", 235, "Rock"), + ("Song 38", 106, "Techno"), + ("Song 39", 117, "Disco"), + ("Song 40", 110, "Pop"), + ("Song 41", 144, "Rock"), + ("Song 42", 156, "Disco"), + ("Song 43", 204, "Rock"), + ("Song 44", 108, "Pop"), + ("Song 45", 255, "Pop"), + ("Song 46", 165, "Rock"), + ("Song 47", 290, "Disco"), + ("Song 48", 242, "Pop"), + ("Song 49", 272, "Rock"), + ("Song 50", 212, "Pop"), + ] + + # Genre transition costs. A higher cost means a less desirable transition. + genre_transition_costs = { + "Rock": {"Pop": 3, "Disco": 5, "Techno": 7}, + "Pop": {"Rock": 3, "Disco": 6, "Techno": 8}, + "Disco": {"Rock": 5, "Pop": 6, "Techno": 9}, + "Techno": {"Rock": 7, "Pop": 8, "Disco": 9}, + } + + num_tunes = len(tunes) + all_tunes = range(num_tunes) + + # Playlist target duration in seconds. + target_duration = 60 * 60 # 1 hour + + # We use a circuit constraint to model the playlist. In the circuit constraint + # graph, each node is a tune, and each arc represents a pair of consecutive + # tunes in the playlist. We introduce a dummy node to represent the start and + # the end of the playlist. + # + # The constraint that two consecutive tunes must be of different genres is + # encoded by not creating an arc between two tunes that are of the same genre. + # This is crucial in the modelisation of this problem: it reduces the number + # of variables in the model, and it avoids additional constraints to ensure + # two consecutive tunes are of different genres. + + # Dummy node representing the start and end of the playlist. + dummy_node = num_tunes + + # `possible_successors[i]` contains the list of nodes that can be reached + # after node `i`. + possible_successors = {} + possible_successors[dummy_node] = [dummy_node] + for i in all_tunes: + # Any node can be the first tune in the playlist. + possible_successors[dummy_node].append(i) + # Any node can be the last tune in the playlist. + possible_successors[i] = [dummy_node] + genre_i = tunes[i][2] + for j in all_tunes: + genre_j = tunes[j][2] + # If `i` and `j` are of different genres, we can go from `i` to `j`. + if genre_i != genre_j: + possible_successors[i].append(j) + + # -------------------- + # 2. Model + # -------------------- + model = cp_model.CpModel() + + # -------------------- + # 3. Decision Variables + # -------------------- + # `literals[i][j]` is true if tune `j` follows tune `i` in the playlist. + literals = {} + + # -------------------- + # 4. Constraints + # -------------------- + + # 4.1 Two consecutive tunes must be of different genres. + # This is encoded in possible_successors, which doesn't contain any arcs + # between two tunes that are of the same genre. Now we just have to add a + # circuit constraint. + + # `arcs` contains the list of possible arcs in the circuit graph, each arc + # is a tuple (i, j, literals[i][j]). + arcs = [] + + def AddArc(i, j): + literals[(i, j)] = model.new_bool_var(f"lit_{i}_{j}") + arcs.append((i, j, literals[(i, j)])) + + # Add all possible arcs between different nodes. + for i, successors in possible_successors.items(): + for j in successors: + AddArc(i, j) + + # Add self-arcs to let tunes not be in the playlist. + for i in all_tunes: + AddArc(i, i) + + # Add a circuit constraint with the arcs. + model.add_circuit(arcs) + + # 4.2 All genres must appear at least once. + # This is encoded by adding a constraint that the sum of all literals for a + # given genre is at least 1. + + # `is_active[i]` is true iff tune `i` is in the playlist, i.e. if its self-arc + # is not active in the circuit. + is_active = {} + for i in all_tunes: + is_active[i] = literals[(i, i)].Not() + + # `genre_tunes[genre]` contains the list of tunes that are of genre `genre`. + genre_tunes = {} + for genre in genre_transition_costs: + genre_tunes[genre] = [] + for i in all_tunes: + genre_tunes[tunes[i][2]].append(i) + + # For each genre, at least one tune must be active: the sum of all literals + # for this genre is at least 1. + for t in genre_tunes.values(): + model.add(sum(is_active[i] for i in t) >= 1) + + # -------------------- + # 5. Objective + # -------------------- + + # 5.1. Minimize genre transition costs. + + # Add a total_transition_cost variable representing the sum of all transition + # costs in the playlist. + max_transition_cost = 0 + for genre_costs in genre_transition_costs.values(): + for cost in genre_costs.values(): + max_transition_cost = max(cost, max_transition_cost) + total_transition_cost_upper_bound = (num_tunes - 1) * max_transition_cost + total_transition_cost = model.new_int_var( + 0, total_transition_cost_upper_bound, "total_transition_cost" + ) + + transition_cost_terms = [] + for i, successors in possible_successors.items(): + if i == dummy_node: + continue + genre_i = tunes[i][2] + for j in successors: + if j == dummy_node: + continue + genre_j = tunes[j][2] + cost = genre_transition_costs[genre_i][genre_j] + transition_cost_terms.append(cost * literals[(i, j)]) + model.add(total_transition_cost == sum(transition_cost_terms)) + + # 5.2. Minimize the deviation between the target duration and the actual total + # duration. + + # Add a total_duration variable representing the duration of all active tunes. + total_duration_upper_bound = sum([t[1] for t in tunes]) + total_duration = model.new_int_var(0, total_duration_upper_bound, "total_duration") + model.add(total_duration == sum(tunes[i][1] * is_active[i] for i in all_tunes)) + + # Minimize the absolute difference from the target duration. + deviation = model.new_int_var(0, target_duration, "deviation") + model.add_abs_equality(deviation, total_duration - target_duration) + + # 5.3 Combine the objectives. + # + # You can add a weight to prioritize one over the other. + # For example, `model.minimize(10 * total_transition_cost + deviation)` + model.minimize(total_transition_cost + deviation) + + # -------------------- + # 6. Solve + # -------------------- + solver = cp_model.CpSolver() + # Set a time limit for the solver + solver.parameters.max_time_in_seconds = 30.0 + status = solver.solve(model) + + # ----------------------- + # 7. Print the solution + # ----------------------- + if status == cp_model.OPTIMAL: + print("Found Optimal Playlist:") + elif status == cp_model.FEASIBLE: + print("Found Feasible Playlist:") + else: + print("No solution found.") + return + + print(f" Total Transition Cost: {solver.value(total_transition_cost)}") + print( + f" Playlist Duration: {solver.value(total_duration)} seconds " + f"({solver.value(total_duration) / 60:.2f} minutes)" + ) + print( + f" Deviation from target duration ({target_duration}):" + f" {solver.value(deviation)} seconds" + ) + print("-" * 30) + + # Reconstruct the playlist sequence by starting from the dummy node. + playlist = [] + current_node = dummy_node + while True: + # Find the successor of the current node. + next_node = dummy_node + for next_node in possible_successors[current_node]: + if solver.value(literals[(current_node, next_node)]): + break + + if next_node == dummy_node: + break # We've completed the loop back to the start. + + playlist.append(next_node) + current_node = next_node + + if not playlist: + print("Empty playlist.") + else: + for i in playlist: + (name, duration, genre) = tunes[i] + print(f"{i+1}. {name} ({genre}) - {duration}s") + + +def main(argv: Sequence[str]) -> None: + if len(argv) > 1: + raise app.UsageError("Too many command-line arguments.") + Solve() + + +if __name__ == "__main__": + app.run(main) diff --git a/ortools/routing/samples/cvrptw_test.sh b/ortools/routing/samples/cvrptw_test.sh index 40fd632509..e42ee0239f 100755 --- a/ortools/routing/samples/cvrptw_test.sh +++ b/ortools/routing/samples/cvrptw_test.sh @@ -12,13 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. - -source gbash.sh || exit -source module gbash_unit.sh - -function test::operations_research_examples::cvrptw() { - declare -r DIR="${TEST_SRCDIR}/ortools/routing/samples" - EXPECT_SUCCEED '${DIR}/cvrptw --vrp_use_deterministic_random_seed' -} - -gbash::unit::main "$@" +set -x +exec {binary_path} "$@"