From f4fdf9466f3fd2b9d53c0390a2aee95cc96e6cb0 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Wed, 17 Dec 2025 21:23:58 +0100 Subject: [PATCH] Update Bazel linear solver build (#4956) --- ortools/linear_solver/BUILD.bazel | 387 ++++++++++++++++++++++-------- 1 file changed, 283 insertions(+), 104 deletions(-) diff --git a/ortools/linear_solver/BUILD.bazel b/ortools/linear_solver/BUILD.bazel index 871c25c4f0..f26292ab8b 100644 --- a/ortools/linear_solver/BUILD.bazel +++ b/ortools/linear_solver/BUILD.bazel @@ -170,140 +170,52 @@ py_proto_library( cc_library( name = "linear_solver", srcs = [ - "linear_expr.cc", - "linear_solver.cc", - "linear_solver_callback.cc", "sat_interface.cc", ] + select({ - ":use_bop": ["bop_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_cbc": ["cbc_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_clp": ["clp_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_glop": [ - "glop_interface.cc", - "glop_utils.cc", - ], - "//conditions:default": [], - }) + select({ - ":use_glpk": ["glpk_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_gurobi": [ - "gurobi_interface.cc", - "gurobi_util.cc", - ], - "//conditions:default": [], - }) + select({ - ":use_highs": ["highs_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_pdlp": ["pdlp_interface.cc"], - "//conditions:default": [], - }) + select({ - ":use_scip": [ - "scip_callback.cc", - "scip_interface.cc", - ], - "//conditions:default": [], - }) + select({ ":use_cplex": ["cplex_interface.cc"], "//conditions:default": [], }) + select({ ":use_xpress": ["xpress_interface.cc"], "//conditions:default": [], }), - hdrs = [ - "linear_expr.h", - "linear_solver.h", - "linear_solver_callback.h", - ] + select({ - ":use_glop": ["glop_utils.h"], - "//conditions:default": [], - }) + select({ - ":use_gurobi": ["gurobi_util.h"], - "//conditions:default": [], - }) + select({ - ":use_scip": [ - "scip_callback.h", - "scip_helper_macros.h", - ], - "//conditions:default": [], - }), deps = [ + ":linear_solver_base", ":linear_solver_cc_proto", - ":model_exporter", - ":model_validator", "//ortools/base", - "//ortools/base:accurate_sum", - "//ortools/base:hash", - "//ortools/base:logging", - "//ortools/base:map_util", - "//ortools/base:status_macros", - "//ortools/base:stl_util", - "//ortools/base:timer", + "//ortools/linear_solver/proto_solver:proto_utils", "//ortools/linear_solver/proto_solver:sat_proto_solver", - "//ortools/port:file", "//ortools/port:proto_utils", "//ortools/sat:cp_model_cc_proto", "//ortools/sat:cp_model_solver", - "//ortools/sat:lp_utils", - "//ortools/util:fp_utils", "//ortools/util:lazy_mutable_copy", + "@abseil-cpp//absl/base:core_headers", "@abseil-cpp//absl/status", - "@abseil-cpp//absl/status:statusor", - "@abseil-cpp//absl/strings", - "@abseil-cpp//absl/synchronization", - "@abseil-cpp//absl/types:optional", ] + select({ - ":use_bop": [ - "//ortools/bop:bop_parameters_cc_proto", - "//ortools/bop:integral_solver", - ], + ":use_bop": [":linear_solver_bop"], "//conditions:default": [], }) + select({ - ":use_glop": [ - "//ortools/glop:lp_solver", - "//ortools/glop:parameters_cc_proto", - "//ortools/linear_solver/proto_solver:glop_proto_solver", - ], + ":use_cbc": [":linear_solver_cbc"], "//conditions:default": [], }) + select({ - ":use_glpk": [ - "//ortools/glpk:glpk_env_deleter", - "@glpk", - ], + ":use_clp": [":linear_solver_clp"], "//conditions:default": [], }) + select({ - ":use_gurobi": [ - "//ortools/linear_solver/proto_solver:gurobi_proto_solver", - "//ortools/third_party_solvers:gurobi_environment", - ], + ":use_glop": [":linear_solver_glop"], "//conditions:default": [], }) + select({ - ":use_pdlp": [ - "//ortools/linear_solver/proto_solver:pdlp_proto_solver", - "//ortools/pdlp:primal_dual_hybrid_gradient", - "//ortools/pdlp:solve_log_cc_proto", - "//ortools/pdlp:solvers_cc_proto", - ], + ":use_glpk": [":linear_solver_glpk"], "//conditions:default": [], }) + select({ - ":use_scip": [ - "//ortools/linear_solver/proto_solver:scip_params", - "//ortools/linear_solver/proto_solver:scip_proto_solver", - "@scip", - ], + ":use_gurobi": [":linear_solver_gurobi"], "//conditions:default": [], }) + select({ - ":use_highs": [ - "//ortools/linear_solver/proto_solver:highs_proto_solver", - "@highs", - ], + ":use_pdlp": [":linear_solver_pdlp"], + "//conditions:default": [], + }) + select({ + ":use_scip": [":linear_solver_scip"], + "//conditions:default": [], + }) + select({ + ":use_highs": [":linear_solver_highs"], "//conditions:default": [], }) + select({ ":use_xpress": ["//ortools/third_party_solvers:xpress_environment"], @@ -312,6 +224,160 @@ cc_library( alwayslink = 1, # Important! Library is used via dependency injection. ) +# Recommended target to do linear programming (LP). +cc_library( + name = "linear_solver_glop", + srcs = ["glop_interface.cc"], + deps = [ + ":glop_utils", + ":linear_solver_base", + "//ortools/base", + "//ortools/glop:lp_solver", + "//ortools/glop:parameters_cc_proto", + "//ortools/linear_solver/proto_solver:glop_proto_solver", + "//ortools/lp_data", + "//ortools/lp_data:base", + "//ortools/port:proto_utils", + "//ortools/util:lazy_mutable_copy", + "//ortools/util:time_limit", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/log:check", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +# Most problems are solved faster by GLOP (and with better numerical accuracy +# and better behavior on ill-conditioned problems); but we still provide +# some free third-party solvers. CLP is usually the best among those. +# GUROBI is the best, even better than GLOP, but it has a restricted license. +cc_library( + name = "linear_solver_clp", + srcs = ["clp_interface.cc"], + target_compatible_with = select({ + ":use_clp": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + deps = [ + ":linear_solver_base", + "//ortools/base", + "//ortools/base:timer", + "//third_party/cbc:clp", + "//third_party/cbc:coinutils", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/strings:str_format", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +cc_library( + name = "scip_callback", + srcs = ["scip_callback.cc"], + hdrs = ["scip_callback.h"], + deps = [ + ":linear_solver_base", + ":scip_helper_macros", + "//ortools/base", + "@abseil-cpp//absl/types:span", + "@scip", + ], +) + +# Recommended target for mixed integer programming. +# +# NOTE: You can change the default underlying LP engine (Soplex) to GLOP or CLP +# by setting a define when you build your end target: +# blaze build -c opt --define scip_lp_solver=glop my/build:target. +# blaze build -c opt --define scip_lp_solver=clp my/build:target. +cc_library( + name = "linear_solver_scip", + srcs = ["scip_interface.cc"], + deps = [ + ":linear_solver_base", + ":linear_solver_cc_proto", + ":scip_callback", + ":scip_helper_macros", + "//ortools/base", + "//ortools/base:sysinfo", + "//ortools/base:timer", + "//ortools/linear_solver/proto_solver:proto_utils", + "//ortools/linear_solver/proto_solver:scip_params", + "//ortools/linear_solver/proto_solver:scip_proto_solver", + "//ortools/util:lazy_mutable_copy", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/cleanup", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/synchronization", + "@abseil-cpp//absl/time", + "@scip", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +# Use with caution. For example, it is not thread-safe. +cc_library( + name = "linear_solver_glpk", + srcs = ["glpk_interface.cc"], + deps = [ + ":linear_solver_base", + "//ortools/base", + "//ortools/base:timer", + "//ortools/third_party_solvers/glpk:glpk_env_deleter", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/strings:str_format", + "@glpk", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +# Use with caution. For example, it has yielded erroneous solutions +# in the past (contact or-core-team@ for details). +cc_library( + name = "linear_solver_cbc", + srcs = ["cbc_interface.cc"], + target_compatible_with = select({ + ":use_cbc": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + deps = [ + ":linear_solver_base", + "//ortools/base", + "//ortools/base:timer", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/strings:str_format", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +cc_library( + name = "linear_solver_gurobi", + srcs = ["gurobi_interface.cc"], + deps = [ + ":gurobi_util", + ":linear_solver_base", + "//ortools/base", + "//ortools/base:status_macros", + "//ortools/base:timer", + "//ortools/linear_solver/proto_solver:gurobi_proto_solver", + "//ortools/linear_solver/proto_solver:proto_utils", + "//ortools/util:lazy_mutable_copy", + "//ortools/util:time_limit", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/container:flat_hash_map", + "@abseil-cpp//absl/container:flat_hash_set", + "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/log:die_if_null", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/synchronization", + "@abseil-cpp//absl/time", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + cc_library( name = "gurobi_util", srcs = ["gurobi_util.cc"], @@ -328,6 +394,119 @@ cc_library( ], ) +# Experimental. Boolean optimization problem solver. +# This works best on MIP problem where all the variables are Boolean integers. +cc_library( + name = "linear_solver_bop", + srcs = ["bop_interface.cc"], + deps = [ + ":linear_solver_base", + "//ortools/base", + "//ortools/bop:bop_parameters_cc_proto", + "//ortools/bop:integral_solver", + "@abseil-cpp//absl/base:core_headers", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +cc_library( + name = "linear_solver_pdlp", + srcs = ["pdlp_interface.cc"], + deps = [ + ":linear_solver_base", + ":linear_solver_cc_proto", + "//ortools/base", + "//ortools/linear_solver/proto_solver:pdlp_proto_solver", + "//ortools/linear_solver/proto_solver:proto_utils", + "//ortools/pdlp:solve_log_cc_proto", + "//ortools/pdlp:solvers_cc_proto", + "//ortools/port:proto_utils", + "//ortools/util:lazy_mutable_copy", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", + "@abseil-cpp//absl/strings", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +# Highs solver; +cc_library( + name = "linear_solver_highs", + srcs = ["highs_interface.cc"], + deps = [ + ":linear_solver_base", + ":linear_solver_cc_proto", + "//ortools/base", + "//ortools/linear_solver/proto_solver:highs_proto_solver", + "//ortools/linear_solver/proto_solver:proto_utils", + "//ortools/util:lazy_mutable_copy", + "@abseil-cpp//absl/base:core_headers", + "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", + "@abseil-cpp//absl/strings", + ], + alwayslink = 1, # Important! Library is used via dependency injection. +) + +cc_library( + name = "linear_solver_base", + srcs = [ + "linear_expr.cc", + "linear_solver.cc", + "linear_solver_callback.cc", + ], + hdrs = [ + "linear_expr.h", + "linear_solver.h", + "linear_solver_callback.h", + ], + deps = [ + ":linear_solver_cc_proto", + ":model_exporter", + ":model_validator", + "//ortools/base", + "//ortools/base:accurate_sum", + "//ortools/base:base_export", + "//ortools/base:map_util", + "//ortools/base:numbers", + "//ortools/base:stl_util", + "//ortools/base:threadpool", + "//ortools/glop:parameters_cc_proto", + "//ortools/port:file", # Needed by go/lp-specific-params. Don't remove! + "//ortools/port:proto_utils", + "//ortools/util:fp_utils", + "//ortools/util:lazy_mutable_copy", + "//ortools/util:testing_utils", + "//ortools/util:time_limit", + "@abseil-cpp//absl/base:core_headers", + "@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/status", + "@abseil-cpp//absl/status:statusor", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@abseil-cpp//absl/synchronization", + "@abseil-cpp//absl/time", + "@protobuf", + ], +) + +cc_library( + name = "glop_utils", + srcs = ["glop_utils.cc"], + hdrs = ["glop_utils.h"], + deps = [ + ":linear_solver_base", + "//ortools/lp_data:base", + "@abseil-cpp//absl/log", + ], +) + # Model exporter that can write MPS and LP file formats from an MPModelProto. cc_library( name = "model_exporter",