diff --git a/ortools/algorithms/BUILD.bazel b/ortools/algorithms/BUILD.bazel index 4c7779d85f..538a6555af 100644 --- a/ortools/algorithms/BUILD.bazel +++ b/ortools/algorithms/BUILD.bazel @@ -67,7 +67,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:ptr_util", "//ortools/base:strong_vector", "//ortools/util:time_limit", diff --git a/ortools/algorithms/find_graph_symmetries.cc b/ortools/algorithms/find_graph_symmetries.cc index bf6979e924..23422f4ec5 100644 --- a/ortools/algorithms/find_graph_symmetries.cc +++ b/ortools/algorithms/find_graph_symmetries.cc @@ -933,7 +933,7 @@ void GraphSymmetryFinder::PruneOrbitsUnderPermutationsCompatibleWithPartition( compatible = false; break; } - part = partition.PartOf(node); // Initilization of 'part'. + part = partition.PartOf(node); // Initialization of 'part'. } } } diff --git a/ortools/algorithms/knapsack_solver_for_cuts.h b/ortools/algorithms/knapsack_solver_for_cuts.h index a4513fa3de..b08b18e11e 100644 --- a/ortools/algorithms/knapsack_solver_for_cuts.h +++ b/ortools/algorithms/knapsack_solver_for_cuts.h @@ -51,8 +51,8 @@ #include #include "absl/memory/memory.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/util/time_limit.h" namespace operations_research { diff --git a/ortools/base/BUILD.bazel b/ortools/base/BUILD.bazel index a658189ab6..486d21ecaf 100644 --- a/ortools/base/BUILD.bazel +++ b/ortools/base/BUILD.bazel @@ -339,6 +339,12 @@ cc_library( deps = [":base"], ) +cc_library( + name = "intops", + hdrs = ["strong_int.h"], + deps = [":int_type"], +) + cc_library( name = "source_location", hdrs = ["source_location.h"], diff --git a/ortools/base/strong_int.h b/ortools/base/strong_int.h new file mode 100644 index 0000000000..b5352a0652 --- /dev/null +++ b/ortools/base/strong_int.h @@ -0,0 +1,367 @@ +// Copyright 2010-2021 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. + +// StrongInt is a simple template class mechanism for defining "logical" +// integer-like class types that support many of the same functionalities +// as native integer types, but which prevent assignment, construction, and +// other operations from other similar integer-like types. Essentially, the +// template class StrongInt (where ValueType assumes +// valid scalar types such as int, uint, int32_t, etc) has the additional +// property that it cannot be assigned to or constructed from other StrongInts +// or native integer types of equal or implicitly convertible type. +// +// The class is useful for preventing mingling of integer variables with +// different logical roles or units. Unfortunately, C++ provides relatively +// good type-safety for user-defined classes but not for integer types. It is +// essentially up to the user to use nice variable names and comments to prevent +// accidental mismatches, such as confusing a user-index with a group-index or a +// time-in-milliseconds with a time-in-seconds. The use of typedefs are limited +// in that regard as they do not enforce type-safety. +// +// USAGE ----------------------------------------------------------------------- +// +// DEFINE_STRONG_INT_TYPE(StrongIntName, ValueType); +// +// where: +// StrongIntName: is the desired (unique) name for the "logical" integer type +// ValueType: is one of the integral types as defined by std::is_integral +// (see ). +// +// DISALLOWED OPERATIONS / TYPE-SAFETY ENFORCEMENT ----------------------------- +// +// Consider these definitions and variable declarations: +// DEFINE_STRONG_INT_TYPE(GlobalDocID, int64_t); +// DEFINE_STRONG_INT_TYPE(LocalDocID, int64_t); +// GlobalDocID global; +// LocalDocID local; +// +// The class StrongInt prevents: +// +// 1) Assignments of other StrongInts with different StrongIntNames. +// +// global = local; <-- Fails to compile! +// local = global; <-- Fails to compile! +// +// 2) Explicit/implicit conversion from an StrongInt to another StrongInt. +// +// LocalDocID l(global); <-- Fails to compile! +// LocalDocID l = global; <-- Fails to compile! +// +// void GetGlobalDoc(GlobalDocID global) { } +// GetGlobalDoc(global); <-- Compiles fine, types match! +// GetGlobalDoc(local); <-- Fails to compile! +// +// 3) Implicit conversion from an StrongInt to a native integer type. +// +// void GetGlobalDoc(int64_t global) { ... +// GetGlobalDoc(global); <-- Fails to compile! +// GetGlobalDoc(local); <-- Fails to compile! +// +// void GetLocalDoc(int32_t local) { ... +// GetLocalDoc(global); <-- Fails to compile! +// GetLocalDoc(local); <-- Fails to compile! +// +// +// SUPPORTED OPERATIONS -------------------------------------------------------- +// +// The following operators are supported: unary: ++ (both prefix and postfix), +// +, -, ! (logical not), ~ (one's complement); comparison: ==, !=, <, <=, >, +// >=; numerical: +, -, *, /; assignment: =, +=, -=, /=, *=; stream: <<. Each +// operator allows the same StrongIntName and the ValueType to be used on +// both left- and right-hand sides. +// +// It also supports an accessor value() returning the stored value as ValueType, +// and a templatized accessor value() method that serves as syntactic sugar +// for static_cast(var.value()). These accessors are useful when assigning +// the stored value into protocol buffer fields and using it as printf args. +// +// The class also defines a hash functor that allows the StrongInt to be used +// as key to hashable containers such as hash_map and hash_set. +// +// FixedArray and STL vector (see int-type-indexed-container.h) if an StrongInt +// is intended to be used as an index into these containers. These wrappers are +// indexed in a type-safe manner using StrongInts to ensure type-safety. +// +// NB: this implementation does not attempt to abide by or enforce dimensional +// analysis on these scalar types. +// +// EXAMPLES -------------------------------------------------------------------- +// +// DEFINE_STRONG_INT_TYPE(GlobalDocID, int64_t); +// GlobalDocID global = 3; +// std::cout << global; <-- Prints 3 to stdout. +// +// for (GlobalDocID i(0); i < global; ++i) { +// std::cout << i; +// } <-- Print(ln)s 0 1 2 to stdout +// +// DEFINE_STRONG_INT_TYPE(LocalDocID, int64_t); +// LocalDocID local; +// std::cout << local; <-- Prints 0 to stdout it +// default +// initializes the value to 0. +// +// local = 5; +// local *= 2; +// LocalDocID l(local); +// std::cout << l + local; <-- Prints 20 to stdout. +// +// GenericSearchRequest request; +// request.set_doc_id(global.value()); <-- Uses value() to extract the value +// from the StrongInt class. +// +// REMARKS --------------------------------------------------------------------- +// +// The following bad usage is permissible although discouraged. Essentially, it +// involves using the value*() accessors to extract the native integer type out +// of the StrongInt class. Keep in mind that the primary reason for the +// StrongInt class is to prevent *accidental* mingling of similar logical +// integer types -- and not type casting from one type to another. +// +// DEFINE_STRONG_INT_TYPE(GlobalDocID, int64_t); +// DEFINE_STRONG_INT_TYPE(LocalDocID, int64_t); +// GlobalDocID global; +// LocalDocID local; +// +// global = local.value(); <-- Compiles fine. +// +// void GetGlobalDoc(GlobalDocID global) { ... +// GetGlobalDoc(local.value()); <-- Compiles fine. +// +// void GetGlobalDoc(int64_t global) { ... +// GetGlobalDoc(local.value()); <-- Compiles fine. + +#ifndef OR_TOOLS_BASE_STRONG_INT_H_ +#define OR_TOOLS_BASE_STRONG_INT_H_ + +#include + +#include +#include +#include // NOLINT +#include + +#include "absl/base/port.h" +#include "absl/strings/string_view.h" +#include "ortools/base/macros.h" + +namespace util_intops { + +template +class StrongInt; + +// Defines the StrongInt using value_type and typedefs it to int_type_name. +// The struct int_type_name ## _tag_ trickery is needed to ensure that a new +// type is created per int_type_name. +#define DEFINE_STRONG_INT_TYPE(int_type_name, value_type) \ + struct int_type_name##_tag_ { \ + static constexpr absl::string_view TypeName() { return #int_type_name; } \ + }; \ + typedef ::util_intops::StrongInt \ + int_type_name; + +// Holds a integral value (of type ValueType) and behaves as a +// ValueType by exposing assignment, unary, comparison, and arithmetic +// operators. +// +// The template parameter StrongIntName defines the name for the int type and +// must be unique within a binary (the convenient DEFINE_STRONG_INT macro at the +// end of the file generates a unique StrongIntName). The parameter ValueType +// defines the integer type value (see supported list above). +// +// This class is NOT thread-safe. +template +class StrongInt { + public: + typedef _ValueType ValueType; // for non-member operators + typedef StrongInt ThisType; // Syntactic sugar. + + static constexpr absl::string_view TypeName() { + return StrongIntName::TypeName(); + } + + // Note that this may change from time to time without notice. + struct Hasher { + size_t operator()(const StrongInt& arg) const { + return static_cast(arg.value()); + } + }; + + public: + // Default c'tor initializing value_ to 0. + constexpr StrongInt() : value_(0) {} + // C'tor explicitly initializing from a ValueType. + constexpr explicit StrongInt(ValueType value) : value_(value) {} + + // StrongInt uses the default copy constructor, destructor and assign + // operator. The defaults are sufficient and omitting them allows the compiler + // to add the move constructor/assignment. + + // -- ACCESSORS -------------------------------------------------------------- + // The class provides a value() accessor returning the stored ValueType value_ + // as well as a templatized accessor that is just a syntactic sugar for + // static_cast(var.value()); + constexpr ValueType value() const { return value_; } + + template + constexpr ValType value() const { + return static_cast(value_); + } + + // -- UNARY OPERATORS -------------------------------------------------------- + ThisType& operator++() { // prefix ++ + ++value_; + return *this; + } + const ThisType operator++(int v) { // postfix ++ + ThisType temp(*this); + ++value_; + return temp; + } + ThisType& operator--() { // prefix -- + --value_; + return *this; + } + const ThisType operator--(int v) { // postfix -- + ThisType temp(*this); + --value_; + return temp; + } + + constexpr bool operator!() const { return value_ == 0; } + constexpr const ThisType operator+() const { return ThisType(value_); } + constexpr const ThisType operator-() const { return ThisType(-value_); } + constexpr const ThisType operator~() const { return ThisType(~value_); } + + // -- ASSIGNMENT OPERATORS --------------------------------------------------- + // We support the following assignment operators: =, +=, -=, *=, /=, <<=, >>= + // and %= for both ThisType and ValueType. +#define STRONG_INT_TYPE_ASSIGNMENT_OP(op) \ + ThisType& operator op(const ThisType& arg_value) { \ + value_ op arg_value.value(); \ + return *this; \ + } \ + ThisType& operator op(ValueType arg_value) { \ + value_ op arg_value; \ + return *this; \ + } + STRONG_INT_TYPE_ASSIGNMENT_OP(+=); + STRONG_INT_TYPE_ASSIGNMENT_OP(-=); + STRONG_INT_TYPE_ASSIGNMENT_OP(*=); + STRONG_INT_TYPE_ASSIGNMENT_OP(/=); + STRONG_INT_TYPE_ASSIGNMENT_OP(<<=); // NOLINT + STRONG_INT_TYPE_ASSIGNMENT_OP(>>=); // NOLINT + STRONG_INT_TYPE_ASSIGNMENT_OP(%=); +#undef STRONG_INT_TYPE_ASSIGNMENT_OP + + ThisType& operator=(ValueType arg_value) { + value_ = arg_value; + return *this; + } + + private: + // The integer value of type ValueType. + ValueType value_; + + COMPILE_ASSERT(std::is_integral::value, + invalid_integer_type_for_id_type_); +} ABSL_ATTRIBUTE_PACKED; + +// -- NON-MEMBER STREAM OPERATORS ---------------------------------------------- +// We provide the << operator, primarily for logging purposes. Currently, there +// seems to be no need for an >> operator. +template +std::ostream& operator<<(std::ostream& os, // NOLINT + StrongInt arg) { + return os << arg.value(); +} + +// -- NON-MEMBER ARITHMETIC OPERATORS ------------------------------------------ +// We support only the +, -, *, and / operators with the same StrongInt and +// ValueType types. The reason is to allow simple manipulation on these IDs +// when used as indices in vectors and arrays. +// +// NB: Although it is possible to do StrongInt * StrongInt and StrongInt / +// StrongInt, it is probably non-sensical from a dimensionality analysis +// perspective. +#define STRONG_INT_TYPE_ARITHMETIC_OP(op) \ + template \ + constexpr StrongInt operator op( \ + StrongInt id_1, \ + StrongInt id_2) { \ + return StrongInt(id_1.value() op id_2.value()); \ + } \ + template \ + constexpr StrongInt operator op( \ + StrongInt id, \ + typename StrongInt::ValueType arg_val) { \ + return StrongInt(id.value() op arg_val); \ + } \ + template \ + constexpr StrongInt operator op( \ + typename StrongInt::ValueType arg_val, \ + StrongInt id) { \ + return StrongInt(arg_val op id.value()); \ + } +STRONG_INT_TYPE_ARITHMETIC_OP(+); +STRONG_INT_TYPE_ARITHMETIC_OP(-); +STRONG_INT_TYPE_ARITHMETIC_OP(*); +STRONG_INT_TYPE_ARITHMETIC_OP(/); +STRONG_INT_TYPE_ARITHMETIC_OP(<<); // NOLINT +STRONG_INT_TYPE_ARITHMETIC_OP(>>); // NOLINT +STRONG_INT_TYPE_ARITHMETIC_OP(%); +#undef STRONG_INT_TYPE_ARITHMETIC_OP + +// -- NON-MEMBER COMPARISON OPERATORS ------------------------------------------ +// Static inline comparison operators. We allow all comparison operators among +// the following types (OP \in [==, !=, <, <=, >, >=]: +// StrongInt OP StrongInt +// StrongInt OP ValueType +// ValueType OP StrongInt +#define STRONG_INT_TYPE_COMPARISON_OP(op) \ + template \ + static inline constexpr bool operator op( \ + StrongInt id_1, \ + StrongInt id_2) { \ + return id_1.value() op id_2.value(); \ + } \ + template \ + static inline constexpr bool operator op( \ + StrongInt id, \ + typename StrongInt::ValueType val) { \ + return id.value() op val; \ + } \ + template \ + static inline constexpr bool operator op( \ + typename StrongInt::ValueType val, \ + StrongInt id) { \ + return val op id.value(); \ + } +STRONG_INT_TYPE_COMPARISON_OP(==); // NOLINT +STRONG_INT_TYPE_COMPARISON_OP(!=); // NOLINT +STRONG_INT_TYPE_COMPARISON_OP(<); // NOLINT +STRONG_INT_TYPE_COMPARISON_OP(<=); // NOLINT +STRONG_INT_TYPE_COMPARISON_OP(>); // NOLINT +STRONG_INT_TYPE_COMPARISON_OP(>=); // NOLINT +#undef STRONG_INT_TYPE_COMPARISON_OP + +} // namespace util_intops + +// Allows it to be used as a key to hashable containers. +namespace std { +template +struct hash > + : util_intops::StrongInt::Hasher {}; +} // namespace std + +#endif // OR_TOOLS_BASE_STRONG_INT_H_ diff --git a/ortools/base/strong_vector.h b/ortools/base/strong_vector.h index 4719ca910c..609c38f201 100644 --- a/ortools/base/strong_vector.h +++ b/ortools/base/strong_vector.h @@ -14,7 +14,7 @@ // This file provides the StrongVector container that wraps around the STL // std::vector. // The wrapper restricts indexing to a pre-specified type-safe integer type or -// IntType (see int_type.h). It prevents accidental indexing +// IntType (see strong_int.h). It prevents accidental indexing // by different "logical" integer-like types (e.g. another IntType) or native // integer types. The wrapper is useful as C++ and the standard template // library allows the user to mix "logical" integral indices that might have a @@ -23,11 +23,11 @@ // The container can only be indexed by an instance of an IntType class, which // can be declared as: // -// DEFINE_INT_TYPE(IntTypeName, IntTypeValueType); +// DEFINE_STRONG_INT_TYPE(IntTypeName, IntTypeValueType); // // where IntTypeName is the desired name for the "logical" integer-like type // and the ValueType is a supported native integer type such as int or -// uint64_t (see int_type.h for details). +// uint64_t (see strong_int.h for details). // // The wrapper exposes all public methods of STL vector and behaves mostly as // pass-through. The only method modified to ensure type-safety is the operator @@ -35,7 +35,7 @@ // // EXAMPLES -------------------------------------------------------------------- // -// DEFINE_INT_TYPE(PhysicalChildIndex, int32_t); +// DEFINE_STRONG_INT_TYPE(PhysicalChildIndex, int32_t); // absl::StrongVector vec; // // PhysicalChildIndex physical_index; @@ -46,7 +46,7 @@ // vec[physical_index] = ...; <-- fails to compile. // vec.at(physical_index) = ...; <-- fails to compile. // -// DEFINE_INT_TYPE(LogicalChildIndex, int32_t); +// DEFINE_STRONG_INT_TYPE(LogicalChildIndex, int32_t); // int32_t logical_index; // vec[logical_index] = ...; <-- fails to compile. // vec.at(logical_index) = ...; <-- fails to compile. @@ -66,8 +66,8 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" namespace absl { diff --git a/ortools/bop/BUILD.bazel b/ortools/bop/BUILD.bazel index bb9b327688..02b72b5249 100644 --- a/ortools/bop/BUILD.bazel +++ b/ortools/bop/BUILD.bazel @@ -17,7 +17,7 @@ cc_library( hdrs = ["bop_types.h"], deps = [ "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", ], ) @@ -31,7 +31,7 @@ cc_library( ":bop_solution", ":bop_types", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "@com_google_absl//absl/synchronization", "//ortools/glop:lp_solver", @@ -68,7 +68,7 @@ cc_library( deps = [ ":bop_types", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/sat:boolean_problem", "//ortools/sat:boolean_problem_cc_proto", @@ -87,7 +87,7 @@ cc_library( ":bop_util", "//ortools/algorithms:sparse_permutation", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/base:stl_util", "//ortools/glop:lp_solver", @@ -119,7 +119,7 @@ cc_library( ":bop_util", "//ortools/base", "//ortools/base:cleanup", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/base:stl_util", "//ortools/glop:lp_solver", @@ -147,7 +147,7 @@ cc_library( ":bop_types", ":bop_util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/sat:boolean_problem", @@ -170,7 +170,7 @@ cc_library( ":bop_util", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/sat:boolean_problem", "//ortools/sat:boolean_problem_cc_proto", @@ -196,7 +196,7 @@ cc_library( ":complete_optimizer", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "@com_google_absl//absl/status:statusor", "//ortools/base:stl_util", @@ -228,7 +228,7 @@ cc_library( ":bop_util", ":complete_optimizer", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/base:stl_util", "//ortools/glop:lp_solver", @@ -261,7 +261,7 @@ cc_library( ":bop_types", ":bop_util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/glop:lp_solver", diff --git a/ortools/bop/bop_fs.h b/ortools/bop/bop_fs.h index b0586ff9b3..8b4ceb202e 100644 --- a/ortools/bop/bop_fs.h +++ b/ortools/bop/bop_fs.h @@ -18,10 +18,10 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/bop/bop_base.h" #include "ortools/bop/bop_parameters.pb.h" #include "ortools/bop/bop_solution.h" diff --git a/ortools/bop/bop_lns.h b/ortools/bop/bop_lns.h index 4e381ee233..5799e1d4eb 100644 --- a/ortools/bop/bop_lns.h +++ b/ortools/bop/bop_lns.h @@ -19,10 +19,10 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/bop/bop_base.h" #include "ortools/bop/bop_parameters.pb.h" diff --git a/ortools/bop/bop_ls.h b/ortools/bop/bop_ls.h index f5a07a33fd..c6437bcc55 100644 --- a/ortools/bop/bop_ls.h +++ b/ortools/bop/bop_ls.h @@ -374,7 +374,7 @@ class AssignmentAndConstraintFeasibilityMaintainer { // constraint infeasible. An "up" direction means that the constraint activity // is lower than the lower bound and we need to make the activity move up to // fix the infeasibility. - DEFINE_INT_TYPE(ConstraintIndexWithDirection, int32_t); + DEFINE_STRONG_INT_TYPE(ConstraintIndexWithDirection, int32_t); ConstraintIndexWithDirection FromConstraintIndex(ConstraintIndex index, bool up) const { return ConstraintIndexWithDirection(2 * index.value() + (up ? 1 : 0)); diff --git a/ortools/bop/bop_portfolio.h b/ortools/bop/bop_portfolio.h index 1627e92e27..b86f391e4d 100644 --- a/ortools/bop/bop_portfolio.h +++ b/ortools/bop/bop_portfolio.h @@ -32,7 +32,7 @@ namespace operations_research { namespace bop { -DEFINE_INT_TYPE(OptimizerIndex, int); +DEFINE_STRONG_INT_TYPE(OptimizerIndex, int); const OptimizerIndex kInvalidOptimizerIndex(-1); // Forward declaration. diff --git a/ortools/bop/bop_solver.h b/ortools/bop/bop_solver.h index 3c5ba0e5c1..6bcfcdeb60 100644 --- a/ortools/bop/bop_solver.h +++ b/ortools/bop/bop_solver.h @@ -40,10 +40,10 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/bop/bop_base.h" #include "ortools/bop/bop_parameters.pb.h" #include "ortools/bop/bop_solution.h" diff --git a/ortools/bop/bop_types.h b/ortools/bop/bop_types.h index fb512673ca..9dc0fc1c00 100644 --- a/ortools/bop/bop_types.h +++ b/ortools/bop/bop_types.h @@ -17,17 +17,17 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" namespace operations_research { namespace bop { -DEFINE_INT_TYPE(ConstraintIndex, int); -DEFINE_INT_TYPE(EntryIndex, int); -DEFINE_INT_TYPE(SearchIndex, int); -DEFINE_INT_TYPE(TermIndex, int); -DEFINE_INT_TYPE(VariableIndex, int); -DEFINE_INT_TYPE(SolverTimeStamp, int64_t); +DEFINE_STRONG_INT_TYPE(ConstraintIndex, int); +DEFINE_STRONG_INT_TYPE(EntryIndex, int); +DEFINE_STRONG_INT_TYPE(SearchIndex, int); +DEFINE_STRONG_INT_TYPE(TermIndex, int); +DEFINE_STRONG_INT_TYPE(VariableIndex, int); +DEFINE_STRONG_INT_TYPE(SolverTimeStamp, int64_t); // Status of the solve of Bop. enum class BopSolveStatus { @@ -71,7 +71,7 @@ inline std::ostream& operator<<(std::ostream& os, BopSolveStatus status) { } // TODO(user): Remove. -DEFINE_INT_TYPE(SparseIndex, int); +DEFINE_STRONG_INT_TYPE(SparseIndex, int); struct BopConstraintTerm { BopConstraintTerm(VariableIndex _var_id, int64_t _weight) : var_id(_var_id), search_id(0), weight(_weight) {} diff --git a/ortools/constraint_solver/BUILD.bazel b/ortools/constraint_solver/BUILD.bazel index 0d9bc6fca9..7ece5806fe 100644 --- a/ortools/constraint_solver/BUILD.bazel +++ b/ortools/constraint_solver/BUILD.bazel @@ -151,7 +151,7 @@ cc_library( "@com_google_absl//absl/time", # "//zlib:zlibonly", "//ortools/base:bitmap", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/base:iterator_adaptors", "//ortools/base:map_util", @@ -273,7 +273,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", ], ) diff --git a/ortools/constraint_solver/constraint_solveri.h b/ortools/constraint_solver/constraint_solveri.h index 027107f90f..49176a0a0a 100644 --- a/ortools/constraint_solver/constraint_solveri.h +++ b/ortools/constraint_solver/constraint_solveri.h @@ -1009,6 +1009,7 @@ class IntVarLocalSearchHandler { IntVarLocalSearchHandler>::OnStart; // clang-format on #endif // SWIGPYTHON + // clang-format off %rename(IntVarLocalSearchOperatorTemplate) VarLocalSearchOperator; diff --git a/ortools/constraint_solver/samples/simple_ls_program.cc b/ortools/constraint_solver/samples/simple_ls_program.cc index 12f0574150..bcfabc2881 100644 --- a/ortools/constraint_solver/samples/simple_ls_program.cc +++ b/ortools/constraint_solver/samples/simple_ls_program.cc @@ -15,11 +15,9 @@ // Local Search. It solves the same trivial problem with a Large // Neighborhood Search approach, a Local Search approach, and a Local // Search with Filter approach. - -#include "ortools/base/commandlineflags.h" -#include "ortools/base/hash.h" -#include "ortools/base/map_util.h" -#include "ortools/base/stl_util.h" +#include "ortools/base/init_google.h" +#include "ortools/base/logging.h" +#include "ortools/base/logging_flags.h" #include "ortools/constraint_solver/constraint_solver.h" #include "ortools/constraint_solver/constraint_solveri.h" @@ -199,7 +197,8 @@ void SolveProblem(SolveType solve_type) { } // namespace operations_research int main(int argc, char** argv) { - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); + absl::SetFlag(&FLAGS_logtostderr, true); operations_research::SolveProblem(operations_research::LNS); operations_research::SolveProblem(operations_research::LS); operations_research::SolveProblem(operations_research::LS_WITH_FILTER); diff --git a/ortools/graph/BUILD.bazel b/ortools/graph/BUILD.bazel index 8e1fc00aac..2c1db9a9b4 100644 --- a/ortools/graph/BUILD.bazel +++ b/ortools/graph/BUILD.bazel @@ -57,7 +57,7 @@ cc_library( # hdrs = ["digraph.h"], # deps = [ # "//ortools/base", -# "//ortools/base:int_type", +# "//ortools/base:intops", # "//ortools/base:strong_vector", # ], #) @@ -88,7 +88,7 @@ cc_library( "//ortools/base:adjustable_priority_queue", "//ortools/base:file", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", # "//ortools/base:strong_bitmap", "//ortools/base:strong_vector", "//ortools/base:recordio", @@ -137,7 +137,7 @@ cc_library( deps = [ "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:time_limit", "@com_google_absl//absl/container:flat_hash_set", @@ -236,7 +236,7 @@ cc_library( deps = [ "//ortools/base", "//ortools/base:adjustable_priority_queue", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:saturated_arithmetic", "@com_google_absl//absl/base", diff --git a/ortools/graph/cliques.h b/ortools/graph/cliques.h index 8ac98f6dee..e22ef0ac20 100644 --- a/ortools/graph/cliques.h +++ b/ortools/graph/cliques.h @@ -31,8 +31,8 @@ #include #include "absl/strings/str_cat.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/util/time_limit.h" @@ -208,7 +208,7 @@ class BronKerboschAlgorithm { } private: - DEFINE_INT_TYPE(CandidateIndex, ptrdiff_t); + DEFINE_STRONG_INT_TYPE(CandidateIndex, ptrdiff_t); // A data structure that maintains the variables of one "iteration" of the // search algorithm. These are the variables that would normally be allocated diff --git a/ortools/graph/perfect_matching.h b/ortools/graph/perfect_matching.h index 9ee3c30b97..121d399ef4 100644 --- a/ortools/graph/perfect_matching.h +++ b/ortools/graph/perfect_matching.h @@ -35,10 +35,10 @@ #include "absl/strings/str_join.h" #include "ortools/base/adjustable_priority_queue-inl.h" #include "ortools/base/adjustable_priority_queue.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" namespace operations_research { @@ -167,13 +167,13 @@ class MinCostPerfectMatching { class BlossomGraph { public: // Typed index used by this class. - DEFINE_INT_TYPE(NodeIndex, int); - DEFINE_INT_TYPE(EdgeIndex, int); - DEFINE_INT_TYPE(CostValue, int64_t); + DEFINE_STRONG_INT_TYPE(NodeIndex, int); + DEFINE_STRONG_INT_TYPE(EdgeIndex, int); + DEFINE_STRONG_INT_TYPE(CostValue, int64_t); // Basic constants. // NOTE(user): Those can't be constexpr because of the or-tools export, - // which complains for constexpr DEFINE_INT_TYPE. + // which complains for constexpr DEFINE_STRONG_INT_TYPE. static const NodeIndex kNoNodeIndex; static const EdgeIndex kNoEdgeIndex; static const CostValue kMaxCostValue; diff --git a/ortools/lp_data/BUILD.bazel b/ortools/lp_data/BUILD.bazel index d2e7998def..75e730202a 100644 --- a/ortools/lp_data/BUILD.bazel +++ b/ortools/lp_data/BUILD.bazel @@ -38,7 +38,7 @@ cc_library( deps = [ "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:bitset", ], @@ -63,7 +63,7 @@ cc_library( deps = [ ":base", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:bitset", ], @@ -122,7 +122,7 @@ cc_library( ":sparse_column", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:fp_utils", "//ortools/util:return_macros", @@ -173,7 +173,7 @@ cc_library( ":sparse", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/glop:parameters_cc_proto", "//ortools/util:fp_utils", @@ -291,7 +291,7 @@ cc_library( "//ortools/base", "//ortools/base:file", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:protobuf_util", "//ortools/base:status_builder", diff --git a/ortools/lp_data/lp_data.h b/ortools/lp_data/lp_data.h index 85d8ffcef2..c31bfa521c 100644 --- a/ortools/lp_data/lp_data.h +++ b/ortools/lp_data/lp_data.h @@ -33,9 +33,9 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" // for CHECK* #include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL +#include "ortools/base/strong_int.h" #include "ortools/glop/parameters.pb.h" #include "ortools/lp_data/lp_types.h" #include "ortools/lp_data/sparse.h" diff --git a/ortools/lp_data/lp_types.h b/ortools/lp_data/lp_types.h index 7d111ecf8a..4a25a236e5 100644 --- a/ortools/lp_data/lp_types.h +++ b/ortools/lp_data/lp_types.h @@ -21,8 +21,8 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/util/bitset.h" @@ -39,11 +39,11 @@ typedef int32_t Index; // ColIndex is the type for integers representing column/variable indices. // int32s are enough for handling even the largest problems. -DEFINE_INT_TYPE(ColIndex, Index); +DEFINE_STRONG_INT_TYPE(ColIndex, Index); // RowIndex is the type for integers representing row/constraint indices. // int32s are enough for handling even the largest problems. -DEFINE_INT_TYPE(RowIndex, Index); +DEFINE_STRONG_INT_TYPE(RowIndex, Index); // Get the ColIndex corresponding to the column # row. inline ColIndex RowToColIndex(RowIndex row) { return ColIndex(row.value()); } @@ -61,9 +61,9 @@ inline Index RowToIntIndex(RowIndex row) { return row.value(); } // An entry in a sparse matrix is a pair (row, value) for a given known column. // See classes SparseColumn and SparseMatrix. #if defined(__ANDROID__) -DEFINE_INT_TYPE(EntryIndex, int32_t); +DEFINE_STRONG_INT_TYPE(EntryIndex, int32_t); #else -DEFINE_INT_TYPE(EntryIndex, int64_t); +DEFINE_STRONG_INT_TYPE(EntryIndex, int64_t); #endif static inline double ToDouble(double f) { return f; } diff --git a/ortools/lp_data/mps_reader.h b/ortools/lp_data/mps_reader.h index c2ff7654e5..4c408d8d1e 100644 --- a/ortools/lp_data/mps_reader.h +++ b/ortools/lp_data/mps_reader.h @@ -36,12 +36,12 @@ #include "absl/status/statusor.h" #include "absl/strings/numbers.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" // for DISALLOW_COPY_AND_ASSIGN, NULL #include "ortools/base/map_util.h" #include "ortools/base/protobuf_util.h" #include "ortools/base/status_macros.h" +#include "ortools/base/strong_int.h" #include "ortools/linear_solver/linear_solver.pb.h" #include "ortools/lp_data/lp_data.h" #include "ortools/lp_data/lp_types.h" diff --git a/ortools/lp_data/scattered_vector.h b/ortools/lp_data/scattered_vector.h index 4c3ae05422..1339fe61b1 100644 --- a/ortools/lp_data/scattered_vector.h +++ b/ortools/lp_data/scattered_vector.h @@ -18,8 +18,8 @@ #include #include "ortools/base/basictypes.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/lp_data/lp_types.h" #include "ortools/util/bitset.h" diff --git a/ortools/math_opt/core/BUILD.bazel b/ortools/math_opt/core/BUILD.bazel index f656e1165b..4f6b8b0c9f 100644 --- a/ortools/math_opt/core/BUILD.bazel +++ b/ortools/math_opt/core/BUILD.bazel @@ -52,7 +52,7 @@ cc_library( ":model_update_merge", ":sparse_vector_view", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/math_opt:model_cc_proto", "//ortools/math_opt:model_update_cc_proto", @@ -149,7 +149,7 @@ cc_library( hdrs = ["solve_interrupter.h"], deps = [ "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:linked_hash_map", "//ortools/base:map_util", "@com_google_absl//absl/base:core_headers", @@ -179,3 +179,17 @@ cc_library( name = "sparse_vector", hdrs = ["sparse_vector.h"], ) + +cc_library( + name = "sparse_submatrix", + srcs = ["sparse_submatrix.cc"], + hdrs = ["sparse_submatrix.h"], + deps = [ + ":sparse_vector", + ":sparse_vector_view", + "//ortools/base", + "//ortools/math_opt:sparse_containers_cc_proto", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/types:span", + ], +) diff --git a/ortools/math_opt/core/math_opt_proto_utils.h b/ortools/math_opt/core/math_opt_proto_utils.h index b99a79d120..332cde8532 100644 --- a/ortools/math_opt/core/math_opt_proto_utils.h +++ b/ortools/math_opt/core/math_opt_proto_utils.h @@ -41,6 +41,22 @@ inline int NumMatrixNonzeros(const SparseDoubleMatrixProto& matrix) { return matrix.row_ids_size(); } +// Returns the id of the first variable if there is one. If the input proto is +// valid, this will also be the smallest id. +inline std::optional FirstVariableId(const VariablesProto& variables) { + return variables.ids().empty() ? std::nullopt + : std::make_optional(variables.ids()[0]); +} + +// Returns the id of the first linear constraint if there is one. If the input +// proto is valid, this will also be the smallest id. +inline std::optional FirstLinearConstraintId( + const LinearConstraintsProto& linear_constraints) { + return linear_constraints.ids().empty() + ? std::nullopt + : std::make_optional(linear_constraints.ids()[0]); +} + // Removes the items in the sparse double vector for all indices whose value is // exactly 0.0. // diff --git a/ortools/math_opt/core/model_storage.cc b/ortools/math_opt/core/model_storage.cc index 70f3318f6d..0c6c95e375 100644 --- a/ortools/math_opt/core/model_storage.cc +++ b/ortools/math_opt/core/model_storage.cc @@ -29,10 +29,10 @@ #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/base/status_macros.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_update_merge.h" #include "ortools/math_opt/core/sparse_vector_view.h" #include "ortools/math_opt/model.pb.h" diff --git a/ortools/math_opt/core/model_storage.h b/ortools/math_opt/core/model_storage.h index 0acd7e2df2..20b46fc84b 100644 --- a/ortools/math_opt/core/model_storage.h +++ b/ortools/math_opt/core/model_storage.h @@ -29,17 +29,17 @@ #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" -#include "ortools/base/int_type.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/model.pb.h" #include "ortools/math_opt/model_update.pb.h" namespace operations_research { namespace math_opt { -DEFINE_INT_TYPE(VariableId, int64_t); -DEFINE_INT_TYPE(LinearConstraintId, int64_t); -DEFINE_INT_TYPE(UpdateTrackerId, int64_t); +DEFINE_STRONG_INT_TYPE(VariableId, int64_t); +DEFINE_STRONG_INT_TYPE(LinearConstraintId, int64_t); +DEFINE_STRONG_INT_TYPE(UpdateTrackerId, int64_t); // An index based C++ API for building & storing optimization problems. // diff --git a/ortools/math_opt/core/solve_interrupter.cc b/ortools/math_opt/core/solve_interrupter.cc index 3154e99708..1a7868fb9d 100644 --- a/ortools/math_opt/core/solve_interrupter.cc +++ b/ortools/math_opt/core/solve_interrupter.cc @@ -20,9 +20,9 @@ #include #include "absl/synchronization/mutex.h" -#include "ortools/base/int_type.h" #include "ortools/base/linked_hash_map.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" namespace operations_research { namespace math_opt { diff --git a/ortools/math_opt/core/solve_interrupter.h b/ortools/math_opt/core/solve_interrupter.h index 5c9fee1f0e..8bfe4e5eb9 100644 --- a/ortools/math_opt/core/solve_interrupter.h +++ b/ortools/math_opt/core/solve_interrupter.h @@ -23,8 +23,8 @@ #include "absl/base/thread_annotations.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" -#include "ortools/base/int_type.h" #include "ortools/base/linked_hash_map.h" +#include "ortools/base/strong_int.h" namespace operations_research { namespace math_opt { @@ -39,7 +39,7 @@ namespace math_opt { class SolveInterrupter { public: // Id used to identify a callback. - DEFINE_INT_TYPE(CallbackId, int64_t); + DEFINE_STRONG_INT_TYPE(CallbackId, int64_t); using Callback = std::function; diff --git a/ortools/math_opt/cpp/BUILD.bazel b/ortools/math_opt/cpp/BUILD.bazel index a06f58a159..fae599abdc 100644 --- a/ortools/math_opt/cpp/BUILD.bazel +++ b/ortools/math_opt/cpp/BUILD.bazel @@ -23,7 +23,7 @@ cc_library( ":variable_and_expressions", "//ortools/base", "//ortools/base:status_macros", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/math_opt:model_cc_proto", "//ortools/math_opt:model_update_cc_proto", "//ortools/math_opt/core:model_storage", @@ -41,7 +41,7 @@ cc_library( deps = [ ":key_types", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/math_opt/core:arrow_operator_proxy", "//ortools/math_opt/core:model_storage", "@com_google_absl//absl/container:flat_hash_map", @@ -58,7 +58,7 @@ cc_library( ":id_map", ":key_types", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/math_opt/core:model_storage", "@com_google_absl//absl/base:core_headers", @@ -74,7 +74,7 @@ cc_library( ":key_types", ":variable_and_expressions", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/math_opt/core:model_storage", ], ) @@ -88,7 +88,7 @@ cc_library( ":linear_constraint", ":variable_and_expressions", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/math_opt:result_cc_proto", "//ortools/math_opt:solution_cc_proto", "//ortools/math_opt/core:model_storage", @@ -129,7 +129,7 @@ cc_library( hdrs = ["map_filter.h"], deps = [ ":id_set", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/math_opt:sparse_containers_cc_proto", "//ortools/math_opt/core:model_storage", ], @@ -145,7 +145,7 @@ cc_library( ":map_filter", ":variable_and_expressions", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:protoutil", "//ortools/base:status_macros", "//ortools/math_opt:callback_cc_proto", @@ -214,34 +214,70 @@ cc_library( ], ) +cc_library( + name = "message_callback", + srcs = [ + "message_callback.cc", + ], + hdrs = [ + "message_callback.h", + ], + deps = [ + "//ortools/base", + "//ortools/base:source_location", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + ], +) + +cc_library( + name = "solver_init_arguments", + srcs = [ + "solver_init_arguments.cc", + ], + hdrs = [ + "solver_init_arguments.h", + ], + deps = [ + ":streamable_solver_init_arguments", + "//ortools/math_opt/core:non_streamable_solver_init_arguments", + ], +) + +cc_library( + name = "solve_arguments", + hdrs = [ + "solve_arguments.h", + ], + deps = [ + ":callback", + ":message_callback", + ":model_solve_parameters", + ":parameters", + "//ortools/math_opt/core:solve_interrupter", + ], +) + cc_library( name = "solve", srcs = ["solve.cc"], hdrs = ["solve.h"], deps = [ - ":callback", - ":key_types", ":model", - ":model_solve_parameters", ":parameters", + ":solve_arguments", ":solve_result", - ":streamable_solver_init_arguments", + ":solver_init_arguments", "//ortools/base", "//ortools/base:status_macros", - "//ortools/base:source_location", "//ortools/math_opt:callback_cc_proto", "//ortools/math_opt:parameters_cc_proto", "//ortools/math_opt/core:model_storage", - "//ortools/math_opt/core:non_streamable_solver_init_arguments", - "//ortools/math_opt/core:solve_interrupter", "//ortools/math_opt/core:solver", - "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/memory", - "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/synchronization", ], ) @@ -251,6 +287,7 @@ cc_library( hdrs = ["streamable_solver_init_arguments.h"], deps = [ "//ortools/math_opt:parameters_cc_proto", + "//ortools/math_opt/cpp:enums", "//ortools/math_opt/solvers:gurobi_cc_proto", ], ) diff --git a/ortools/math_opt/cpp/callback.cc b/ortools/math_opt/cpp/callback.cc index fb4df506b7..fbaf58f221 100644 --- a/ortools/math_opt/cpp/callback.cc +++ b/ortools/math_opt/cpp/callback.cc @@ -24,16 +24,14 @@ #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/protoutil.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/callback.pb.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/core/sparse_vector_view.h" -#include "ortools/math_opt/cpp/key_types.h" #include "ortools/math_opt/cpp/map_filter.h" #include "ortools/math_opt/cpp/variable_and_expressions.h" -#include "ortools/math_opt/solution.pb.h" #include "ortools/math_opt/sparse_containers.pb.h" namespace operations_research { diff --git a/ortools/math_opt/cpp/id_map.h b/ortools/math_opt/cpp/id_map.h index 1040adaec3..34ef15c35d 100644 --- a/ortools/math_opt/cpp/id_map.h +++ b/ortools/math_opt/cpp/id_map.h @@ -23,8 +23,8 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/arrow_operator_proxy.h" // IWYU pragma: export #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/cpp/key_types.h" diff --git a/ortools/math_opt/cpp/linear_constraint.h b/ortools/math_opt/cpp/linear_constraint.h index c829a776ec..d112f1a811 100644 --- a/ortools/math_opt/cpp/linear_constraint.h +++ b/ortools/math_opt/cpp/linear_constraint.h @@ -19,11 +19,10 @@ #include -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/cpp/id_map.h" // IWYU pragma: export -#include "ortools/math_opt/cpp/key_types.h" #include "ortools/math_opt/cpp/variable_and_expressions.h" namespace operations_research { diff --git a/ortools/math_opt/cpp/map_filter.h b/ortools/math_opt/cpp/map_filter.h index 01f6265f2d..faa26f3998 100644 --- a/ortools/math_opt/cpp/map_filter.h +++ b/ortools/math_opt/cpp/map_filter.h @@ -18,7 +18,7 @@ #include #include -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/cpp/id_set.h" #include "ortools/math_opt/sparse_containers.pb.h" diff --git a/ortools/math_opt/cpp/matchers.cc b/ortools/math_opt/cpp/matchers.cc index 67f9d92529..dbf20a9fab 100644 --- a/ortools/math_opt/cpp/matchers.cc +++ b/ortools/math_opt/cpp/matchers.cc @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include #include @@ -27,7 +27,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" #include "ortools/base/logging.h" -#include "ortools/port/proto_utils.h" +#include "ortools/math_opt/cpp/math_opt.h" namespace operations_research { namespace math_opt { @@ -123,7 +123,6 @@ void PrintTo(const Solution& solution, std::ostream* const os) { void PrintTo(const SolveResult& result, std::ostream* const os) { *os << "{termination: " << Print(result.termination) - << ", warnings: " << Print(result.warnings) << ", solve_stats: " << Print(result.solve_stats) << ", solutions: " << Print(result.solutions) << ", primal_rays: " << Print(result.primal_rays) @@ -475,26 +474,14 @@ Matcher IsNear(DualRay expected, const double tolerance) { //////////////////////////////////////////////////////////////////////////////// Matcher TerminatesWithOneOf( - const std::vector& allowed, const bool check_warnings) { - std::vector> matchers; - matchers.push_back( - Field("termination", &SolveResult::termination, - Field("reason", &Termination::reason, AnyOfArray(allowed)))); - if (check_warnings) { - matchers.push_back(Field("warnings", &SolveResult::warnings, IsEmpty())); - } - return ::testing::AllOfArray(matchers); + const std::vector& allowed) { + return Field("termination", &SolveResult::termination, + Field("reason", &Termination::reason, AnyOfArray(allowed))); } -Matcher TerminatesWith(const TerminationReason expected, - const bool check_warnings) { - std::vector> matchers; - matchers.push_back(Field("termination", &SolveResult::termination, - Field("reason", &Termination::reason, expected))); - if (check_warnings) { - matchers.push_back(Field("warnings", &SolveResult::warnings, IsEmpty())); - } - return ::testing::AllOfArray(matchers); +Matcher TerminatesWith(const TerminationReason expected) { + return Field("termination", &SolveResult::termination, + Field("reason", &Termination::reason, expected)); } namespace { @@ -508,36 +495,31 @@ testing::Matcher LimitIs(const Limit expected, return Field("termination", &SolveResult::termination, Field("limit", &Termination::limit, expected)); } + } // namespace testing::Matcher TerminatesWithLimit( - const Limit expected, const bool allow_limit_undetermined, - const bool check_warnings) { + const Limit expected, const bool allow_limit_undetermined) { std::vector> matchers; matchers.push_back(LimitIs(expected, allow_limit_undetermined)); matchers.push_back(TerminatesWithOneOf( - {TerminationReason::kFeasible, TerminationReason::kNoSolutionFound}, - /*check_warnings=*/check_warnings)); + {TerminationReason::kFeasible, TerminationReason::kNoSolutionFound})); return ::testing::AllOfArray(matchers); } testing::Matcher TerminatesWithReasonFeasible( - const Limit expected, const bool allow_limit_undetermined, - const bool check_warnings) { + const Limit expected, const bool allow_limit_undetermined) { std::vector> matchers; matchers.push_back(LimitIs(expected, allow_limit_undetermined)); - matchers.push_back(TerminatesWith(TerminationReason::kFeasible, - /*check_warnings=*/check_warnings)); + matchers.push_back(TerminatesWith(TerminationReason::kFeasible)); return ::testing::AllOfArray(matchers); } testing::Matcher TerminatesWithReasonNoSolutionFound( - const Limit expected, const bool allow_limit_undetermined, - const bool check_warnings) { + const Limit expected, const bool allow_limit_undetermined) { std::vector> matchers; matchers.push_back(LimitIs(expected, allow_limit_undetermined)); - matchers.push_back(TerminatesWith(TerminationReason::kNoSolutionFound, - /*check_warnings=*/check_warnings)); + matchers.push_back(TerminatesWith(TerminationReason::kNoSolutionFound)); return ::testing::AllOfArray(matchers); } @@ -576,15 +558,11 @@ MATCHER_P(FirstElementIs, first_element_matcher, } Matcher IsOptimal(const std::optional expected_objective, - const bool check_warnings, const double tolerance) { std::vector> matchers; matchers.push_back(Field( "termination", &SolveResult::termination, Field("reason", &Termination::reason, TerminationReason::kOptimal))); - if (check_warnings) { - matchers.push_back(Field("warnings", &SolveResult::warnings, IsEmpty())); - } if (expected_objective.has_value()) { matchers.push_back(Field( "solutions", &SolveResult::solutions, @@ -599,10 +577,9 @@ Matcher IsOptimal(const std::optional expected_objective, Matcher IsOptimalWithSolution( const double expected_objective, const VariableMap expected_variable_values, - const bool check_warnings, const double tolerance) { + const double tolerance) { return AllOf( - IsOptimal(std::make_optional(expected_objective), check_warnings, - tolerance), + IsOptimal(std::make_optional(expected_objective), tolerance), HasSolution( PrimalSolution{.variable_values = expected_variable_values, .objective_value = expected_objective, @@ -613,11 +590,9 @@ Matcher IsOptimalWithSolution( Matcher IsOptimalWithDualSolution( const double expected_objective, const LinearConstraintMap expected_dual_values, - const VariableMap expected_reduced_costs, const bool check_warnings, - const double tolerance) { + const VariableMap expected_reduced_costs, const double tolerance) { return AllOf( - IsOptimal(std::make_optional(expected_objective), check_warnings, - tolerance), + IsOptimal(std::make_optional(expected_objective), tolerance), HasDualSolution( DualSolution{ .dual_values = expected_dual_values, @@ -749,15 +724,8 @@ Matcher> CheckRays( Matcher IsConsistentWith( const SolveResult& expected, const SolveResultMatcherOptions& options) { std::vector> to_check; - to_check.push_back( - TerminatesWithOneOf(CompatibleReasons(expected.termination.reason, - options.inf_or_unb_soft_match), - /*check_warnings=*/false)); - if (options.check_warnings) { - to_check.push_back( - Field("warnings", &SolveResult::warnings, - ::testing::UnorderedElementsAreArray(expected.warnings))); - } + to_check.push_back(TerminatesWithOneOf(CompatibleReasons( + expected.termination.reason, options.inf_or_unb_soft_match))); const bool skip_solution = MightTerminateWithRays(expected.termination.reason) && !options.check_solutions_if_inf_or_unbounded; diff --git a/ortools/math_opt/cpp/matchers.h b/ortools/math_opt/cpp/matchers.h index 4c4d95cf21..26606f32a1 100644 --- a/ortools/math_opt/cpp/matchers.h +++ b/ortools/math_opt/cpp/matchers.h @@ -56,7 +56,7 @@ // TerminationReason::kUnbounded, // TerminationReason::kInfeasibleOrUnbounded)); // if(!result.primal_rays.empty()) { -// EXPECT_THAT(result.primal_rays[0], IsNear({{x, 1,}, {y, 0}})); +// EXPECT_THAT(result.primal_rays[0], PrimalRayIsNear({{x, 1,}, {y, 0}})); // } // // @@ -97,7 +97,7 @@ #include "gtest/gtest.h" #include "ortools/math_opt/cpp/linear_constraint.h" -#include "ortools/math_opt/cpp/solve.h" +#include "ortools/math_opt/cpp/math_opt.h" #include "ortools/math_opt/cpp/variable_and_expressions.h" namespace operations_research { @@ -186,55 +186,44 @@ testing::Matcher IsNear(DualRay expected, // * If expected_objective contains a value, there is at least one feasible // solution and that solution has an objective value within tolerance of // expected_objective. -// * If check_warnings, the result has no warnings. testing::Matcher IsOptimal( std::optional expected_objective = std::nullopt, - bool check_warnings = true, double tolerance = kMatcherDefaultTolerance); + double tolerance = kMatcherDefaultTolerance); testing::Matcher IsOptimalWithSolution( double expected_objective, VariableMap expected_variable_values, - bool check_warnings = true, double tolerance = kMatcherDefaultTolerance); + double tolerance = kMatcherDefaultTolerance); testing::Matcher IsOptimalWithDualSolution( double expected_objective, LinearConstraintMap expected_dual_values, - VariableMap expected_reduced_costs, bool check_warnings = true, + VariableMap expected_reduced_costs, double tolerance = kMatcherDefaultTolerance); // Checks the following: // * The result has the expected termination reason. -// * If check_warnings, the result has no warnings. -testing::Matcher TerminatesWith(TerminationReason expected, - bool check_warnings = true); +testing::Matcher TerminatesWith(TerminationReason expected); -// Checks the following: -// * The result has one of the allowed termination reasons. -// * If check_warnings, the result has no warnings. +// Checks that the result has one of the allowed termination reasons. testing::Matcher TerminatesWithOneOf( - const std::vector& allowed, bool check_warnings = true); + const std::vector& allowed); // Checks the following: // * The result has termination reason kFeasible or kNoSolutionFound. // * The limit is expected, or is kUndetermined if allow_limit_undetermined. -// * If check_warnings, the result has no warnings. testing::Matcher TerminatesWithLimit( - Limit expected, bool allow_limit_undetermined = false, - bool check_warnings = true); + Limit expected, bool allow_limit_undetermined = false); // Checks the following: // * The result has termination reason kFeasible. // * The limit is expected, or is kUndetermined if allow_limit_undetermined. -// * If check_warnings, the result has no warnings. testing::Matcher TerminatesWithReasonFeasible( - Limit expected, bool allow_limit_undetermined = false, - bool check_warnings = true); + Limit expected, bool allow_limit_undetermined = false); // Checks the following: // * The result has termination reason kNoSolutionFound. // * The limit is expected, or is kUndetermined if allow_limit_undetermined. -// * If check_warnings, the result has no warnings. testing::Matcher TerminatesWithReasonNoSolutionFound( - Limit expected, bool allow_limit_undetermined = false, - bool check_warnings = true); + Limit expected, bool allow_limit_undetermined = false); // SolveResult has a primal solution matching expected within tolerance. testing::Matcher HasSolution( @@ -263,7 +252,6 @@ testing::Matcher HasDualRay( // Configures SolveResult matcher IsConsistentWith() below. struct SolveResultMatcherOptions { - bool check_warnings = true; double tolerance = 1e-5; bool first_solution_only = true; bool check_dual = true; @@ -337,8 +325,6 @@ struct SolveResultMatcherOptions { // EXPECT_THAT(actual, IsConsistentWith(expected)); // // Equivalence is defined as follows: -// * The warnings are the same (in any order). -// - Disabled if options.check_warnings=false. // * The termination reasons are the same. // - For infeasible and unbounded problems, see // options.inf_or_unb_soft_match. diff --git a/ortools/math_opt/cpp/message_callback.cc b/ortools/math_opt/cpp/message_callback.cc new file mode 100644 index 0000000000..4ca02eba08 --- /dev/null +++ b/ortools/math_opt/cpp/message_callback.cc @@ -0,0 +1,63 @@ +// Copyright 2010-2021 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 "ortools/math_opt/cpp/message_callback.h" + +#include +#include +#include +#include + +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/mutex.h" +#include "ortools/base/logging.h" +#include "ortools/base/source_location.h" + +namespace operations_research::math_opt { +namespace { + +class PrinterMessageCallbackImpl { + public: + PrinterMessageCallbackImpl(std::ostream& output_stream, + const absl::string_view prefix) + : output_stream_(output_stream), prefix_(prefix) {} + + void Call(const std::vector& messages) { + const absl::MutexLock lock(&mutex_); + for (const std::string& message : messages) { + output_stream_ << prefix_ << message << '\n'; + } + output_stream_.flush(); + } + + private: + absl::Mutex mutex_; + std::ostream& output_stream_ ABSL_GUARDED_BY(mutex_); + const std::string prefix_; +}; + +} // namespace + +MessageCallback PrinterMessageCallback(std::ostream& output_stream, + const absl::string_view prefix) { + // Here we must use an std::shared_ptr since std::function requires that its + // input is copyable. And PrinterMessageCallbackImpl can't be copyable since + // it uses an absl::Mutex that is not. + const auto impl = + std::make_shared(output_stream, prefix); + return + [=](const std::vector& messages) { impl->Call(messages); }; +} + +} // namespace operations_research::math_opt diff --git a/ortools/math_opt/cpp/message_callback.h b/ortools/math_opt/cpp/message_callback.h new file mode 100644 index 0000000000..f6568194fc --- /dev/null +++ b/ortools/math_opt/cpp/message_callback.h @@ -0,0 +1,50 @@ +// Copyright 2010-2021 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. + +#ifndef OR_TOOLS_MATH_OPT_CPP_MESSAGE_CALLBACK_H_ +#define OR_TOOLS_MATH_OPT_CPP_MESSAGE_CALLBACK_H_ + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "ortools/base/source_location.h" + +namespace operations_research::math_opt { + +// Callback function for messages callback sent by the solver. +// +// Each message represents a single output line from the solver, and each +// message does not contain any '\n' character in it. +// +// Thread-safety: a callback may be called concurrently from multiple +// threads. The users is expected to use proper synchronization primitives to +// deal with that. +using MessageCallback = std::function&)>; + +// Returns a message callback function that prints its output to the given +// output stream, prefixing each line with the given prefix. +// +// For each call to the returned message callback, the output_stream is flushed. +// +// Usage: +// +// SolveArguments args; +// args.message_callback = PrinterMessageCallback(std::cerr, "solver logs> "); +MessageCallback PrinterMessageCallback(std::ostream& output_stream = std::cout, + absl::string_view prefix = ""); + +} // namespace operations_research::math_opt + +#endif // OR_TOOLS_MATH_OPT_CPP_MESSAGE_CALLBACK_H_ diff --git a/ortools/math_opt/cpp/model.cc b/ortools/math_opt/cpp/model.cc index ad0e181016..1afca1ff19 100644 --- a/ortools/math_opt/cpp/model.cc +++ b/ortools/math_opt/cpp/model.cc @@ -23,9 +23,9 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/status_macros.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_storage.h" namespace operations_research { diff --git a/ortools/math_opt/cpp/model_solve_parameters.cc b/ortools/math_opt/cpp/model_solve_parameters.cc index 5f1af03250..006a822c42 100644 --- a/ortools/math_opt/cpp/model_solve_parameters.cc +++ b/ortools/math_opt/cpp/model_solve_parameters.cc @@ -21,7 +21,6 @@ #include "google/protobuf/message.h" #include "ortools/math_opt/core/model_storage.h" -#include "ortools/math_opt/cpp/key_types.h" #include "ortools/math_opt/cpp/linear_constraint.h" #include "ortools/math_opt/cpp/solution.h" #include "ortools/math_opt/cpp/variable_and_expressions.h" diff --git a/ortools/math_opt/cpp/parameters.cc b/ortools/math_opt/cpp/parameters.cc index 1857b67727..32453b3afc 100644 --- a/ortools/math_opt/cpp/parameters.cc +++ b/ortools/math_opt/cpp/parameters.cc @@ -13,16 +13,22 @@ #include "ortools/math_opt/cpp/parameters.h" +#include #include #include +#include #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "absl/types/span.h" +#include "ortools/base/linked_hash_map.h" +#include "ortools/base/logging.h" #include "ortools/base/protoutil.h" #include "ortools/base/status_macros.h" +#include "ortools/math_opt/parameters.pb.h" #include "ortools/math_opt/solvers/gurobi.pb.h" -#include "ortools/port/proto_utils.h" namespace operations_research { namespace math_opt { @@ -116,16 +122,6 @@ absl::Span Enum::AllValues() { return absl::MakeConstSpan(kEmphasisValues); } -StrictnessProto Strictness::Proto() const { - StrictnessProto result; - result.set_bad_parameter(bad_parameter); - return result; -} - -Strictness Strictness::FromProto(const StrictnessProto& proto) { - return {.bad_parameter = proto.bad_parameter()}; -} - GurobiParametersProto GurobiParameters::Proto() const { GurobiParametersProto result; for (const auto& [key, val] : param_values) { @@ -147,7 +143,6 @@ GurobiParameters GurobiParameters::FromProto( SolveParametersProto SolveParameters::Proto() const { SolveParametersProto result; - *result.mutable_strictness() = strictness.Proto(); result.set_enable_output(enable_output); if (time_limit < absl::InfiniteDuration()) { CHECK_OK(util_time::EncodeGoogleApiProto(time_limit, @@ -195,7 +190,6 @@ SolveParametersProto SolveParameters::Proto() const { absl::StatusOr SolveParameters::FromProto( const SolveParametersProto& proto) { SolveParameters result; - result.strictness = Strictness::FromProto(proto.strictness()); result.enable_output = proto.enable_output(); if (proto.has_time_limit()) { ASSIGN_OR_RETURN(result.time_limit, diff --git a/ortools/math_opt/cpp/parameters.h b/ortools/math_opt/cpp/parameters.h index f27161a5be..c84de098f6 100644 --- a/ortools/math_opt/cpp/parameters.h +++ b/ortools/math_opt/cpp/parameters.h @@ -14,10 +14,12 @@ #ifndef OR_TOOLS_MATH_OPT_CPP_PARAMETERS_H_ #define OR_TOOLS_MATH_OPT_CPP_PARAMETERS_H_ +#include #include #include #include "absl/status/statusor.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/span.h" #include "ortools/base/linked_hash_map.h" @@ -112,16 +114,16 @@ MATH_OPT_DEFINE_ENUM(LPAlgorithm, LP_ALGORITHM_UNSPECIFIED); // // Typically used as a std::optional. It used to configure a solver // feature as follows: -// * If a solver doesn't support the feature, only nullopt and kOff are -// valid, any other setting will give either a warning or error (as -// configured for Strictness). +// * If a solver doesn't support the feature, only nullopt will always be +// valid, any other setting will give an invalid argument error (some solvers +// may also accept kOff). // * If the solver supports the feature: // - When unset, the underlying default is used. -// - When the feature cannot be turned off, kOff will a warning/error. +// - When the feature cannot be turned off, kOff will return an error. // - If the feature is enabled by default, the solver default is typically // mapped to kMedium. // - If the feature is supported, kLow, kMedium, kHigh, and kVeryHigh will -// never give a warning or error, and will map onto their best match. +// never give an error, and will map onto their best match. enum class Emphasis { kOff = EMPHASIS_OFF, kLow = EMPHASIS_LOW, @@ -132,15 +134,6 @@ enum class Emphasis { MATH_OPT_DEFINE_ENUM(Emphasis, EMPHASIS_UNSPECIFIED); -// Configures if potentially bad solver input is a warning or an error. -struct Strictness { - // If true, warnings on bad parameters are converted to Status errors. - bool bad_parameter = false; - - StrictnessProto Proto() const; - static Strictness FromProto(const StrictnessProto& proto); -}; - // Gurobi specific parameters for solving. See // https://www.gurobi.com/documentation/9.1/refman/parameters.html // for a list of possible parameters. @@ -298,9 +291,6 @@ struct SolveParameters { glop::GlopParameters glop; sat::SatParameters cp_sat; - // TODO(b/196132970): this needs to move into SolverInitializerProto. - Strictness strictness; - SolveParametersProto Proto() const; static absl::StatusOr FromProto( const SolveParametersProto& proto); diff --git a/ortools/math_opt/cpp/solution.cc b/ortools/math_opt/cpp/solution.cc index 1d099de4cd..7bdf43bfcf 100644 --- a/ortools/math_opt/cpp/solution.cc +++ b/ortools/math_opt/cpp/solution.cc @@ -19,11 +19,14 @@ #include "absl/container/flat_hash_map.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/core/sparse_vector_view.h" +#include "ortools/math_opt/cpp/linear_constraint.h" +#include "ortools/math_opt/cpp/variable_and_expressions.h" #include "ortools/math_opt/solution.pb.h" +#include "ortools/math_opt/sparse_containers.pb.h" namespace operations_research { namespace math_opt { diff --git a/ortools/math_opt/cpp/solve.cc b/ortools/math_opt/cpp/solve.cc index 97e0676aa6..60a5e8347b 100644 --- a/ortools/math_opt/cpp/solve.cc +++ b/ortools/math_opt/cpp/solve.cc @@ -16,23 +16,16 @@ #include #include #include -#include #include -#include -#include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_set.h" #include "absl/memory/memory.h" #include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" #include "ortools/base/logging.h" -#include "ortools/base/source_location.h" #include "ortools/base/status_macros.h" #include "ortools/math_opt/callback.pb.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/core/solver.h" -#include "ortools/math_opt/cpp/key_types.h" #include "ortools/math_opt/cpp/model.h" namespace operations_research { @@ -96,62 +89,8 @@ absl::StatusOr CallSolve( return SolveResult::FromProto(expected_storage, solve_result); } -class PrinterMessageCallbackImpl { - public: - PrinterMessageCallbackImpl(std::ostream& output_stream, - const absl::string_view prefix) - : output_stream_(output_stream), prefix_(prefix) {} - - void Call(const std::vector& messages) { - const absl::MutexLock lock(&mutex_); - for (const std::string& message : messages) { - output_stream_ << prefix_ << message << '\n'; - } - output_stream_.flush(); - } - - private: - absl::Mutex mutex_; - std::ostream& output_stream_ ABSL_GUARDED_BY(mutex_); - const std::string prefix_; -}; - } // namespace -SolverInitArguments::SolverInitArguments( - StreamableSolverInitArguments streamable) - : streamable(std::move(streamable)) {} - -SolverInitArguments::SolverInitArguments( - const NonStreamableSolverInitArguments& non_streamable) - : non_streamable(non_streamable.Clone()) {} - -SolverInitArguments::SolverInitArguments( - StreamableSolverInitArguments streamable, - const NonStreamableSolverInitArguments& non_streamable) - : streamable(std::move(streamable)), - non_streamable(non_streamable.Clone()) {} - -SolverInitArguments::SolverInitArguments(const SolverInitArguments& other) - : streamable(other.streamable), - non_streamable(other.non_streamable != nullptr - ? other.non_streamable->Clone() - : nullptr) {} - -SolverInitArguments& SolverInitArguments::operator=( - const SolverInitArguments& other) { - // Assignment to self is possible. - if (&other == this) { - return *this; - } - - streamable = other.streamable; - non_streamable = - other.non_streamable != nullptr ? other.non_streamable->Clone() : nullptr; - - return *this; -} - absl::StatusOr Solve(const Model& model, const SolverType solver_type, const SolveArguments& solve_args, @@ -217,16 +156,5 @@ absl::StatusOr IncrementalSolver::SolveWithoutUpdate( return CallSolve(*solver_, expected_storage_, arguments); } -MessageCallback PrinterMessageCallback(std::ostream& output_stream, - const absl::string_view prefix) { - // Here we must use an std::shared_ptr since std::function requires that its - // input is copyable. And PrinterMessageCallbackImpl can't be copyable since - // it uses an absl::Mutex that is not. - const auto impl = - std::make_shared(output_stream, prefix); - return - [=](const std::vector& messages) { impl->Call(messages); }; -} - } // namespace math_opt } // namespace operations_research diff --git a/ortools/math_opt/cpp/solve.h b/ortools/math_opt/cpp/solve.h index 44742aa80b..83daf557a4 100644 --- a/ortools/math_opt/cpp/solve.h +++ b/ortools/math_opt/cpp/solve.h @@ -20,190 +20,23 @@ #ifndef OR_TOOLS_MATH_OPT_CPP_SOLVE_H_ #define OR_TOOLS_MATH_OPT_CPP_SOLVE_H_ -#include -#include #include #include -#include #include -#include #include "absl/status/statusor.h" -#include "absl/strings/string_view.h" -#include "ortools/base/source_location.h" #include "ortools/math_opt/core/model_storage.h" -#include "ortools/math_opt/core/non_streamable_solver_init_arguments.h" // IWYU pragma: export -#include "ortools/math_opt/core/solve_interrupter.h" // IWYU pragma: export #include "ortools/math_opt/core/solver.h" -#include "ortools/math_opt/cpp/callback.h" // IWYU pragma: export #include "ortools/math_opt/cpp/model.h" -#include "ortools/math_opt/cpp/model_solve_parameters.h" // IWYU pragma: export -#include "ortools/math_opt/cpp/parameters.h" // IWYU pragma: export -#include "ortools/math_opt/cpp/solve_result.h" // IWYU pragma: export -#include "ortools/math_opt/cpp/streamable_solver_init_arguments.h" // IWYU pragma: export -#include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/parameters.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/solve_arguments.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/solve_result.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/solver_init_arguments.h" // IWYU pragma: export +#include "ortools/math_opt/parameters.pb.h" // IWYU pragma: export namespace operations_research { namespace math_opt { -// Callback function for messages callback sent by the solver. -// -// Each message represents a single output line from the solver, and each -// message does not contain any '\n' character in it. -// -// Thread-safety: a callback may be called concurrently from multiple -// threads. The users is expected to use proper synchronization primitives to -// deal with that. -using MessageCallback = std::function&)>; - -// Returns a message callback function that prints its output to the given -// output stream, prefixing each line with the given prefix. -// -// For each call to the returned message callback, the output_stream is flushed. -// -// Usage: -// -// SolveArguments args; -// args.message_callback = PrinterMessageCallback(std::cerr, "solver logs> "); -MessageCallback PrinterMessageCallback(std::ostream& output_stream = std::cout, - absl::string_view prefix = ""); - -// Arguments passed to Solve() and IncrementalSolver::New() to control the -// instantiation of the solver. -// -// For convenience, constructors with streamable or/and non-streamable arguments -// are provided. The non-streamable arguments are cloned so any change made -// after passing them to this class are ignored. -// -// Usage with streamable arguments: -// -// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{}, -// SolverInitArguments({ -// .gurobi = StreamableGurobiInitArguments{ -// .isv_key = GurobiISVKey{ -// .name = "some name", -// .application_name = "some app name", -// .expiration = -1, -// .key = "random", -// } -// } -// }); -// -// Usage with non-streamable arguments: -// -// NonStreamableGurobiInitArguments gurobi_args; -// gurobi_args.master_env = master_env.get(); -// -// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{}, -// SolverInitArguments(gurobi_args)); -// -struct SolverInitArguments { - SolverInitArguments() = default; - - // Initializes this class with a copy of the provided streamable arguments. - explicit SolverInitArguments(StreamableSolverInitArguments streamable); - - // Initializes this class with a clone of the provided non-streamable - // arguments. - // - // Note that since this constructors calls Clone() to initialize the - // non_streamable_solver_init_arguments field, changes made after calling it - // to the input non_streamable are ignored. - explicit SolverInitArguments( - const NonStreamableSolverInitArguments& non_streamable); - - // Initializes this class with both the provided a copy streamable arguments - // and a clone of the non-streamable ones. - SolverInitArguments(StreamableSolverInitArguments streamable, - const NonStreamableSolverInitArguments& non_streamable); - - // Initializes this class as a copy of the provided arguments. The - // non_streamable field is cloned if not nullptr. - SolverInitArguments(const SolverInitArguments& other); - - // Sets this class as a copy of the provided arguments. The non_streamable - // field is cloned if not nullptr. - SolverInitArguments& operator=(const SolverInitArguments& other); - - SolverInitArguments(SolverInitArguments&&) = default; - SolverInitArguments& operator=(SolverInitArguments&&) = default; - - StreamableSolverInitArguments streamable; - - // This should either be the solver specific class or nullptr. - // - // Solvers will fail (by returning an absl::Status) if called with arguments - // for another solver. - std::unique_ptr non_streamable; -}; - -// Arguments passed to Solve() and IncrementalSolver::Solve() to control the -// solve. -struct SolveArguments { - // Model independent parameters, e.g. time limit. - SolveParameters parameters; - - // Model dependent parameters, e.g. solution hint. - ModelSolveParameters model_parameters; - - // An optional callback for messages emitted by the solver. - // - // When set it enables the solver messages and ignores the `enable_output` in - // solve parameters; messages are redirected to the callback and not printed - // on stdout/stderr/logs anymore. - // - // See PrinterMessageCallback() for logging to stdout/stderr. - // - // Usage: - // - // // To print messages to stdout with a prefix. - // ASSIGN_OR_RETURN( - // const SolveResult result, - // Solve(model, SOLVER_TYPE_GLOP, - // { .message_callback = PrinterMessageCallback(std::cout, - // "logs| "); }); - // - // // To print messages to the INFO log. - // ASSIGN_OR_RETURN( - // const SolveResult result, - // Solve(model, SOLVER_TYPE_GLOP, - // { .message_callback = InfoLoggerMessageCallback("[solver] "); }); - // - // // To print messages to the VLOG(1) log. - // ASSIGN_OR_RETURN( - // const SolveResult result, - // Solve(model, SOLVER_TYPE_GLOP, - // { .message_callback = VLoggerMessageCallback(1, "[solver] "); }); - // - MessageCallback message_callback = nullptr; - - // Callback registration parameters. Usually `callback` should also be set - // when these parameters are modified. - CallbackRegistration callback_registration; - - // The callback. The `callback_registration` parameters have to be set, in - // particular `callback_registration.events`. - Callback callback = nullptr; - - // An optional interrupter that the solver can use to interrupt the solve - // early. - // - // Usage: - // auto interrupter = std::make_shared(); - // - // // Use another thread to trigger the interrupter. - // RunInOtherThread([interrupter](){ - // ... wait for something that should interrupt the solve ... - // interrupter->Interrupt(); - // }); - // - // ASSIGN_OR_RETURN(const SolveResult result, - // Solve(model, SOLVER_TYPE_GLOP, - // { .interrupter = interrupter.get() }); - // - SolveInterrupter* interrupter = nullptr; -}; - // Solves the input model. // // A Status error will be returned if there is an unexpected failure in an @@ -221,9 +54,6 @@ struct SolveArguments { // solve_args.callback_registration only contain variables and constraints from // the input model. // -// See callback.h for documentation on solve_args.callback and -// solve_args.callback_registration. -// // Thread-safety: this method is safe to call concurrently on the same Model. // // Some solvers may add more restrictions regarding threading. Please see @@ -253,7 +83,7 @@ absl::StatusOr Solve(const Model& model, SolverType solver_type, // Model model = ...; // ASSIGN_OR_RETURN( // const std::unique_ptr incremental_solve, -// IncrementalSolver::New(model, SOLVER_TYPE_XXX)); +// IncrementalSolver::New(model, SolverType::kXxx)); // // ASSIGN_OR_RETURN(const SolveResult result1, incremental_solve->Solve()); // diff --git a/ortools/math_opt/cpp/solve_arguments.h b/ortools/math_opt/cpp/solve_arguments.h new file mode 100644 index 0000000000..7a5d52cd75 --- /dev/null +++ b/ortools/math_opt/cpp/solve_arguments.h @@ -0,0 +1,85 @@ +// Copyright 2010-2021 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. + +#ifndef OR_TOOLS_MATH_OPT_CPP_SOLVE_ARGUMENTS_H_ +#define OR_TOOLS_MATH_OPT_CPP_SOLVE_ARGUMENTS_H_ + +#include "ortools/math_opt/core/solve_interrupter.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/callback.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/message_callback.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/model_solve_parameters.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/parameters.h" // IWYU pragma: export + +namespace operations_research::math_opt { + +// Arguments passed to Solve() and IncrementalSolver::Solve() to control the +// solve. +struct SolveArguments { + // Model independent parameters, e.g. time limit. + SolveParameters parameters; + + // Model dependent parameters, e.g. solution hint. + ModelSolveParameters model_parameters; + + // An optional callback for messages emitted by the solver. + // + // When set it enables the solver messages and ignores the `enable_output` in + // solve parameters; messages are redirected to the callback and not printed + // on stdout/stderr/logs anymore. + // + // See PrinterMessageCallback() for logging to stdout/stderr. + // + // Usage: + // + // // To print messages to stdout with a prefix. + // ASSIGN_OR_RETURN( + // const SolveResult result, + // Solve(model, SOLVER_TYPE_GLOP, + // { .message_callback = PrinterMessageCallback(std::cout, + // "logs| "); }); + MessageCallback message_callback = nullptr; + + // Callback registration parameters. Usually `callback` should also be set + // when these parameters are modified. + CallbackRegistration callback_registration; + + // The optional callback for LP/MIP events. + // + // The `callback_registration` parameters have to be set, in particular + // `callback_registration.events`. + // + // See callback.h file comment for documentation on callbacks. + Callback callback = nullptr; + + // An optional interrupter that the solver can use to interrupt the solve + // early. + // + // Usage: + // auto interrupter = std::make_shared(); + // + // // Use another thread to trigger the interrupter. + // RunInOtherThread([interrupter](){ + // ... wait for something that should interrupt the solve ... + // interrupter->Interrupt(); + // }); + // + // ASSIGN_OR_RETURN(const SolveResult result, + // Solve(model, SOLVER_TYPE_GLOP, + // { .interrupter = interrupter.get() }); + // + SolveInterrupter* interrupter = nullptr; +}; + +} // namespace operations_research::math_opt + +#endif // OR_TOOLS_MATH_OPT_CPP_SOLVE_ARGUMENTS_H_ diff --git a/ortools/math_opt/cpp/solve_result.cc b/ortools/math_opt/cpp/solve_result.cc index 8d1e45f1c4..795941d480 100644 --- a/ortools/math_opt/cpp/solve_result.cc +++ b/ortools/math_opt/cpp/solve_result.cc @@ -20,10 +20,15 @@ #include "absl/container/flat_hash_map.h" #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" #include "absl/types/span.h" #include "ortools/base/logging.h" +#include "ortools/base/protoutil.h" #include "ortools/math_opt/core/model_storage.h" +#include "ortools/math_opt/cpp/linear_constraint.h" +#include "ortools/math_opt/cpp/variable_and_expressions.h" #include "ortools/math_opt/solution.pb.h" #include "ortools/port/proto_utils.h" @@ -319,8 +324,6 @@ std::string SolveStats::ToString() const { SolveResult SolveResult::FromProto(const ModelStorage* model, const SolveResultProto& solve_result_proto) { SolveResult result(Termination::FromProto(solve_result_proto.termination())); - result.warnings = {solve_result_proto.warnings().begin(), - solve_result_proto.warnings().end()}; result.solve_stats = SolveStats::FromProto(solve_result_proto.solve_stats()); for (const SolutionProto& solution : solve_result_proto.solutions()) { @@ -332,6 +335,10 @@ SolveResult SolveResult::FromProto(const ModelStorage* model, for (const DualRayProto& dual_ray : solve_result_proto.dual_rays()) { result.dual_rays.push_back(DualRay::FromProto(model, dual_ray)); } + if (solve_result_proto.has_gscip_output()) { + result.gscip_solver_specific_output = + std::move(solve_result_proto.gscip_output()); + } return result; } diff --git a/ortools/math_opt/cpp/solve_result.h b/ortools/math_opt/cpp/solve_result.h index 807e024cea..75754aac62 100644 --- a/ortools/math_opt/cpp/solve_result.h +++ b/ortools/math_opt/cpp/solve_result.h @@ -16,13 +16,13 @@ #include #include +#include #include -#include "absl/status/statusor.h" #include "absl/time/time.h" #include "absl/types/span.h" #include "ortools/base/logging.h" -#include "ortools/base/protoutil.h" +#include "ortools/gscip/gscip.pb.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/cpp/enums.h" // IWYU pragma: export #include "ortools/math_opt/cpp/linear_constraint.h" @@ -294,9 +294,6 @@ struct SolveResult { explicit SolveResult(Termination termination) : termination(std::move(termination)) {} - // Non-fatal errors, e.g. an unsupported parameter that was skipped. - std::vector warnings; - // The reason the solver stopped. Termination termination; @@ -330,6 +327,9 @@ struct SolveResult { // kInfeasible. std::vector dual_rays; + // Solver specific output from Gscip. Only populated if Gscip is used. + GScipOutput gscip_solver_specific_output; + static SolveResult FromProto(const ModelStorage* model, const SolveResultProto& solve_result_proto); diff --git a/ortools/math_opt/cpp/solver_init_arguments.cc b/ortools/math_opt/cpp/solver_init_arguments.cc new file mode 100644 index 0000000000..a0cf90e759 --- /dev/null +++ b/ortools/math_opt/cpp/solver_init_arguments.cc @@ -0,0 +1,55 @@ +// Copyright 2010-2021 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 "ortools/math_opt/cpp/solver_init_arguments.h" + +#include +#include + +namespace operations_research::math_opt { + +SolverInitArguments::SolverInitArguments( + StreamableSolverInitArguments streamable) + : streamable(std::move(streamable)) {} + +SolverInitArguments::SolverInitArguments( + const NonStreamableSolverInitArguments& non_streamable) + : non_streamable(non_streamable.Clone()) {} + +SolverInitArguments::SolverInitArguments( + StreamableSolverInitArguments streamable, + const NonStreamableSolverInitArguments& non_streamable) + : streamable(std::move(streamable)), + non_streamable(non_streamable.Clone()) {} + +SolverInitArguments::SolverInitArguments(const SolverInitArguments& other) + : streamable(other.streamable), + non_streamable(other.non_streamable != nullptr + ? other.non_streamable->Clone() + : nullptr) {} + +SolverInitArguments& SolverInitArguments::operator=( + const SolverInitArguments& other) { + // Assignment to self is possible. + if (&other == this) { + return *this; + } + + streamable = other.streamable; + non_streamable = + other.non_streamable != nullptr ? other.non_streamable->Clone() : nullptr; + + return *this; +} + +} // namespace operations_research::math_opt diff --git a/ortools/math_opt/cpp/solver_init_arguments.h b/ortools/math_opt/cpp/solver_init_arguments.h new file mode 100644 index 0000000000..67272e936f --- /dev/null +++ b/ortools/math_opt/cpp/solver_init_arguments.h @@ -0,0 +1,95 @@ +// Copyright 2010-2021 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. + +#ifndef OR_TOOLS_MATH_OPT_CPP_SOLVER_INIT_ARGUMENTS_H_ +#define OR_TOOLS_MATH_OPT_CPP_SOLVER_INIT_ARGUMENTS_H_ + +#include + +#include "ortools/math_opt/core/non_streamable_solver_init_arguments.h" // IWYU pragma: export +#include "ortools/math_opt/cpp/streamable_solver_init_arguments.h" // IWYU pragma: export + +namespace operations_research::math_opt { + +// Arguments passed to Solve() and IncrementalSolver::New() to control the +// instantiation of the solver. +// +// For convenience, constructors with streamable or/and non-streamable arguments +// are provided. The non-streamable arguments are cloned so any change made +// after passing them to this class are ignored. +// +// Usage with streamable arguments: +// +// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{}, +// SolverInitArguments({ +// .gurobi = StreamableGurobiInitArguments{ +// .isv_key = GurobiISVKey{ +// .name = "some name", +// .application_name = "some app name", +// .expiration = -1, +// .key = "random", +// } +// } +// }); +// +// Usage with non-streamable arguments: +// +// NonStreamableGurobiInitArguments gurobi_args; +// gurobi_args.master_env = master_env.get(); +// +// Solve(model, SOLVER_TYPE_GUROBI, /*solver_args=*/{}, +// SolverInitArguments(gurobi_args)); +// +struct SolverInitArguments { + SolverInitArguments() = default; + + // Initializes this class with the provided streamable arguments. + explicit SolverInitArguments(StreamableSolverInitArguments streamable); + + // Initializes this class with a clone of the provided non-streamable + // arguments. + // + // Note that since this constructors calls Clone() to initialize the + // non_streamable_solver_init_arguments field, changes made after calling it + // to the input non_streamable are ignored. + explicit SolverInitArguments( + const NonStreamableSolverInitArguments& non_streamable); + + // Initializes this class with both the provided streamable arguments and a + // clone of the non-streamable ones. + SolverInitArguments(StreamableSolverInitArguments streamable, + const NonStreamableSolverInitArguments& non_streamable); + + // Initializes this class as a copy of the provided arguments. The + // non_streamable field is cloned if not nullptr. + SolverInitArguments(const SolverInitArguments& other); + + // Sets this class as a copy of the provided arguments. The non_streamable + // field is cloned if not nullptr. + SolverInitArguments& operator=(const SolverInitArguments& other); + + SolverInitArguments(SolverInitArguments&&) = default; + SolverInitArguments& operator=(SolverInitArguments&&) = default; + + StreamableSolverInitArguments streamable; + + // This should either be the solver specific class or nullptr. + // + // Solvers will fail (by returning an absl::Status) if called with arguments + // for another solver. + std::unique_ptr non_streamable; +}; + +} // namespace operations_research::math_opt + +#endif // OR_TOOLS_MATH_OPT_CPP_SOLVER_INIT_ARGUMENTS_H_ diff --git a/ortools/math_opt/cpp/streamable_solver_init_arguments.h b/ortools/math_opt/cpp/streamable_solver_init_arguments.h index fa85fcba14..e6f4510b10 100644 --- a/ortools/math_opt/cpp/streamable_solver_init_arguments.h +++ b/ortools/math_opt/cpp/streamable_solver_init_arguments.h @@ -24,6 +24,7 @@ #include #include +#include "ortools/math_opt/cpp/enums.h" #include "ortools/math_opt/parameters.pb.h" #include "ortools/math_opt/solvers/gurobi.pb.h" @@ -67,8 +68,8 @@ struct StreamableGurobiInitArguments { GurobiInitializerProto Proto() const; }; -// Solver specific initialization parameters that can be streamed to be -// exchanged with another process. +// Solver initialization parameters that can be streamed to be exchanged with +// another process. // // Parameters that can't be streamed (for example instances of C/C++ types that // only exist in the process memory) are dealt with implementations of diff --git a/ortools/math_opt/cpp/variable_and_expressions.cc b/ortools/math_opt/cpp/variable_and_expressions.cc index fc147c301b..f1ff75c159 100644 --- a/ortools/math_opt/cpp/variable_and_expressions.cc +++ b/ortools/math_opt/cpp/variable_and_expressions.cc @@ -18,9 +18,10 @@ #include #include -#include "ortools/base/int_type.h" +#include "absl/base/attributes.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" namespace operations_research { namespace math_opt { diff --git a/ortools/math_opt/cpp/variable_and_expressions.h b/ortools/math_opt/cpp/variable_and_expressions.h index f4cc850feb..8c3edee573 100644 --- a/ortools/math_opt/cpp/variable_and_expressions.h +++ b/ortools/math_opt/cpp/variable_and_expressions.h @@ -98,8 +98,8 @@ #include #include "absl/container/flat_hash_map.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/math_opt/core/model_storage.h" #include "ortools/math_opt/cpp/id_map.h" // IWYU pragma: export #include "ortools/math_opt/cpp/key_types.h" // IWYU pragma: export diff --git a/ortools/math_opt/parameters.proto b/ortools/math_opt/parameters.proto index 1173a1488f..f16616b7ff 100644 --- a/ortools/math_opt/parameters.proto +++ b/ortools/math_opt/parameters.proto @@ -95,16 +95,16 @@ enum LPAlgorithmProto { // SolveParametersProto for use). // // Emphasis is used to configure a solver feature as follows: -// * If a solver doesn't support the feature, only UNSPECIFIED and OFF are -// valid, any other setting will give either a warning or error (as -// configured for Strictness). +// * If a solver doesn't support the feature, only UNSPECIFIED will always be +// valid, any other setting will typically an invalid argument error (some +// solvers may also accept OFF). // * If the solver supports the feature: // - When set to UNSPECIFIED, the underlying default is used. -// - When the feature cannot be turned off, OFF will a warning/error. +// - When the feature cannot be turned off, OFF will return an error. // - If the feature is enabled by default, the solver default is typically // mapped to MEDIUM. // - If the feature is supported, LOW, MEDIUM, HIGH, and VERY HIGH will never -// give a warning or error, and will map onto their best match. +// give an error, and will map onto their best match. enum EmphasisProto { EMPHASIS_UNSPECIFIED = 0; EMPHASIS_OFF = 1; @@ -116,7 +116,6 @@ enum EmphasisProto { // Configures if potentially bad solver input is a warning or an error. message StrictnessProto { - // If true, warnings on bad parameters are converted to Status errors. bool bad_parameter = 1; } @@ -263,9 +262,6 @@ message SolveParametersProto { // solver default effort level if EMPHASIS_UNSPECIFIED. EmphasisProto scaling = 10; - // TODO(b/196132970): this needs to move into SolverInitializerProto. - StrictnessProto strictness = 11; - ////////////////////////////////////////////////////////////////////////////// // Solver specific parameters ////////////////////////////////////////////////////////////////////////////// @@ -276,4 +272,6 @@ message SolveParametersProto { reserved 16; reserved 19; + + reserved 11; // Deleted } diff --git a/ortools/math_opt/result.proto b/ortools/math_opt/result.proto index f602329e1c..36c6d021ba 100644 --- a/ortools/math_opt/result.proto +++ b/ortools/math_opt/result.proto @@ -20,6 +20,7 @@ import "google/protobuf/duration.proto"; import "ortools/gscip/gscip.proto"; import "ortools/math_opt/solution.proto"; + option java_package = "com.google.ortools.mathopt"; option java_multiple_files = true; @@ -245,9 +246,6 @@ message TerminationProto { // Until an exact contract is finalized, it is safest to simply check if a // solution/ray is present rather than relying on the termination reason. message SolveResultProto { - // Non-fatal errors, e.g. an unsupported parameter that was skipped. - repeated string warnings = 1; - // The reason the solver stopped. TerminationProto termination = 2; @@ -284,4 +282,6 @@ message SolveResultProto { oneof solver_specific_output { GScipOutput gscip_output = 7; } + + reserved 1; // Deleted fields. } diff --git a/ortools/math_opt/samples/basic_example.cc b/ortools/math_opt/samples/basic_example.cc index c33569a787..7e2a010a96 100644 --- a/ortools/math_opt/samples/basic_example.cc +++ b/ortools/math_opt/samples/basic_example.cc @@ -16,9 +16,8 @@ #include #include -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/status/statusor.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/math_opt/cpp/math_opt.h" @@ -50,9 +49,6 @@ void SolveVersion1() { model.set_objective_coefficient(y, 1.0); model.set_maximize(); const SolveResult result = Solve(model, SolverType::kGscip).value(); - for (const auto& warning : result.warnings) { - std::cerr << "Solver warning: " << warning << std::endl; - } CHECK_EQ(result.termination.reason, TerminationReason::kOptimal) << result.termination; // The following code will print: @@ -82,9 +78,6 @@ void SolveVersion2() { objective_expression += y; model.Maximize(objective_expression); const SolveResult result = Solve(model, SolverType::kGscip).value(); - for (const auto& warning : result.warnings) { - std::cerr << "Solver warning: " << warning << std::endl; - } CHECK_EQ(result.termination.reason, TerminationReason::kOptimal) << result.termination; // The following code will print: @@ -97,8 +90,7 @@ void SolveVersion2() { } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); SolveVersion1(); SolveVersion2(); return 0; diff --git a/ortools/math_opt/samples/cocktail_hour.cc b/ortools/math_opt/samples/cocktail_hour.cc index 458ed31b8d..eb64d05064 100644 --- a/ortools/math_opt/samples/cocktail_hour.cc +++ b/ortools/math_opt/samples/cocktail_hour.cc @@ -35,13 +35,12 @@ #include #include "absl/container/flat_hash_set.h" -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_join.h" #include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/base/status_macros.h" @@ -369,8 +368,7 @@ void RealMain() { } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); RealMain(); return 0; } diff --git a/ortools/math_opt/samples/cutting_stock.cc b/ortools/math_opt/samples/cutting_stock.cc index cad24b620f..ac30760d4c 100644 --- a/ortools/math_opt/samples/cutting_stock.cc +++ b/ortools/math_opt/samples/cutting_stock.cc @@ -73,10 +73,9 @@ #include #include -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/base/status_builder.h" #include "ortools/base/status_macros.h" @@ -256,8 +255,7 @@ absl::Status RealMain() { } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); absl::Status result = RealMain(); if (!result.ok()) { std::cout << result; diff --git a/ortools/math_opt/samples/facility_lp_benders.cc b/ortools/math_opt/samples/facility_lp_benders.cc index ceba15b3b0..cd13dcd268 100644 --- a/ortools/math_opt/samples/facility_lp_benders.cc +++ b/ortools/math_opt/samples/facility_lp_benders.cc @@ -21,8 +21,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/flags/flag.h" -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/random/random.h" #include "absl/random/uniform_int_distribution.h" #include "absl/status/statusor.h" @@ -30,6 +28,7 @@ #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/math_opt/cpp/math_opt.h" @@ -219,9 +218,6 @@ void FullProblem(const Network& network, const double location_demand, } } const SolveResult result = Solve(model, SolverType::kGurobi).value(); - for (const auto& warning : result.warnings) { - LOG(WARNING) << "Solver warning: " << warning << std::endl; - } QCHECK_EQ(result.termination.reason, TerminationReason::kOptimal) << "Failed to find an optimal solution: " << result.termination; std::cout << "Full problem optimal objective: " @@ -304,9 +300,6 @@ void Benders(const Network network, const double location_demand, LOG(INFO) << "Iteration: " << iteration; // Solve and process first stage. const SolveResult first_stage_result = first_stage_solver->Solve().value(); - for (const auto& warning : first_stage_result.warnings) { - LOG(WARNING) << "Solver warning: " << warning << std::endl; - } QCHECK_EQ(first_stage_result.termination.reason, TerminationReason::kOptimal) << first_stage_result.termination; @@ -328,9 +321,6 @@ void Benders(const Network network, const double location_demand, // Solve and process second stage. const SolveResult second_stage_result = second_stage_solver->Solve(second_stage_args).value(); - for (const auto& warning : second_stage_result.warnings) { - LOG(WARNING) << "Solver warning: " << warning << std::endl; - } if (second_stage_result.termination.reason == TerminationReason::kInfeasible) { // If the second stage problem is infeasible we will get a dual ray @@ -448,8 +438,7 @@ void Benders(const Network network, const double location_demand, } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); const Network network(absl::GetFlag(FLAGS_num_facilities), absl::GetFlag(FLAGS_num_locations), absl::GetFlag(FLAGS_edge_probability)); diff --git a/ortools/math_opt/samples/integer_programming.cc b/ortools/math_opt/samples/integer_programming.cc index f45212aa6b..e5b4cba694 100644 --- a/ortools/math_opt/samples/integer_programming.cc +++ b/ortools/math_opt/samples/integer_programming.cc @@ -16,10 +16,9 @@ #include #include -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/status/statusor.h" #include "absl/time/time.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/math_opt/cpp/math_opt.h" @@ -59,11 +58,6 @@ void SolveSimpleMIP() { << std::endl; const SolveResult result = Solve(model, SolverType::kGscip).value(); - - // Check for warnings. - for (const auto& warning : result.warnings) { - LOG(ERROR) << "Solver warning: " << warning << std::endl; - } // Check that the problem has an optimal solution. QCHECK_EQ(result.termination.reason, TerminationReason::kOptimal) << "Failed to find an optimal solution: " << result.termination; @@ -80,8 +74,7 @@ void SolveSimpleMIP() { } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); SolveSimpleMIP(); return 0; } diff --git a/ortools/math_opt/samples/lagrangian_relaxation.cc b/ortools/math_opt/samples/lagrangian_relaxation.cc index ed005ec800..41291dbcdf 100644 --- a/ortools/math_opt/samples/lagrangian_relaxation.cc +++ b/ortools/math_opt/samples/lagrangian_relaxation.cc @@ -86,13 +86,12 @@ #include #include "absl/flags/flag.h" -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/memory/memory.h" #include "absl/status/statusor.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "ortools/base/container_logging.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/base/mathutil.h" #include "ortools/math_opt/cpp/math_opt.h" @@ -441,8 +440,7 @@ void SolveFullModel(const Graph& graph, double max_resource_1, } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); // Problem data const Graph graph = CreateSampleNetwork(); diff --git a/ortools/math_opt/samples/linear_programming.cc b/ortools/math_opt/samples/linear_programming.cc index 18ce9a991e..8ef6a691a6 100644 --- a/ortools/math_opt/samples/linear_programming.cc +++ b/ortools/math_opt/samples/linear_programming.cc @@ -18,12 +18,11 @@ #include #include -#include "absl/flags/parse.h" -#include "absl/flags/usage.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/time/time.h" +#include "ortools/base/init_google.h" #include "ortools/base/logging.h" #include "ortools/math_opt/cpp/math_opt.h" @@ -75,10 +74,6 @@ void SolveSimpleLp() { const SolveResult result = Solve(model, SolverType::kGlop).value(); - // Check for warnings. - for (const auto& warning : result.warnings) { - LOG(ERROR) << "Solver warning: " << warning << std::endl; - } // Check that the problem has an optimal solution. QCHECK_EQ(result.termination.reason, TerminationReason::kOptimal) << "Failed to find an optimal solution: " << result.termination; @@ -101,8 +96,7 @@ void SolveSimpleLp() { } // namespace int main(int argc, char** argv) { - google::InitGoogleLogging(argv[0]); - absl::ParseCommandLine(argc, argv); + InitGoogle(argv[0], &argc, &argv, true); SolveSimpleLp(); return 0; } diff --git a/ortools/math_opt/solvers/BUILD.bazel b/ortools/math_opt/solvers/BUILD.bazel index 5d93555500..a64559523e 100644 --- a/ortools/math_opt/solvers/BUILD.bazel +++ b/ortools/math_opt/solvers/BUILD.bazel @@ -31,7 +31,9 @@ cc_library( "//ortools/math_opt:solution_cc_proto", "//ortools/math_opt:sparse_containers_cc_proto", "//ortools/math_opt/core:math_opt_proto_utils", + "//ortools/math_opt/core:solve_interrupter", "//ortools/math_opt/core:solver_interface", + "//ortools/math_opt/core:sparse_submatrix", "//ortools/math_opt/core:sparse_vector_view", "//ortools/math_opt/validators:callback_validator", "//ortools/port:proto_utils", @@ -134,7 +136,7 @@ cc_library( deps = [ "//ortools/base", "//ortools/base:cleanup", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:protoutil", "//ortools/base:status_macros", diff --git a/ortools/math_opt/solvers/cp_sat_solver.cc b/ortools/math_opt/solvers/cp_sat_solver.cc index 6d28b9283d..7af8a8c79b 100644 --- a/ortools/math_opt/solvers/cp_sat_solver.cc +++ b/ortools/math_opt/solvers/cp_sat_solver.cc @@ -32,7 +32,6 @@ #include "absl/strings/str_split.h" #include "absl/time/clock.h" #include "absl/time/time.h" -#include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/protoutil.h" #include "ortools/base/status_macros.h" @@ -374,13 +373,7 @@ absl::StatusOr CpSatSolver::Solve( } } if (!param_warnings.empty()) { - if (parameters.strictness().bad_parameter()) { - return absl::InvalidArgumentError(absl::StrJoin(param_warnings, "; ")); - } else { - for (std::string& warning : param_warnings) { - result.add_warnings(std::move(warning)); - } - } + return absl::InvalidArgumentError(absl::StrJoin(param_warnings, "; ")); } } diff --git a/ortools/math_opt/solvers/glop_solver.cc b/ortools/math_opt/solvers/glop_solver.cc index 7526b2fde8..69764a3f45 100644 --- a/ortools/math_opt/solvers/glop_solver.cc +++ b/ortools/math_opt/solvers/glop_solver.cc @@ -35,12 +35,12 @@ #include "absl/time/time.h" #include "absl/types/span.h" #include "ortools/base/cleanup.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/base/protoutil.h" #include "ortools/base/status_macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/glop/lp_solver.h" #include "ortools/glop/parameters.pb.h" @@ -264,10 +264,9 @@ void GlopSolver::UpdateLinearConstraintBounds( } } -std::pair> -GlopSolver::MergeSolveParameters(const SolveParametersProto& solver_parameters, - const bool setting_initial_basis, - const bool has_message_callback) { +absl::StatusOr GlopSolver::MergeSolveParameters( + const SolveParametersProto& solver_parameters, + const bool setting_initial_basis, const bool has_message_callback) { glop::GlopParameters result = solver_parameters.glop(); std::vector warnings; if (!result.has_max_time_in_seconds() && solver_parameters.has_time_limit()) { @@ -310,7 +309,7 @@ GlopSolver::MergeSolveParameters(const SolveParametersProto& solver_parameters, result.set_use_dual_simplex(true); break; case LP_ALGORITHM_BARRIER: - warnings.push_back( + warnings.emplace_back( "GLOP does not support 'LP_ALGORITHM_BARRIER' value for " "'lp_algorithm' parameter."); break; @@ -385,7 +384,10 @@ GlopSolver::MergeSolveParameters(const SolveParametersProto& solver_parameters, if (solver_parameters.has_solution_limit()) { warnings.push_back("GLOP does not support 'solution_limit' parameter"); } - return std::make_pair(std::move(result), std::move(warnings)); + if (!warnings.empty()) { + return absl::InvalidArgumentError(absl::StrJoin(warnings, "; ")); + } + return result; } bool GlopSolver::CanUpdate(const ModelUpdateProto& model_update) { @@ -673,17 +675,18 @@ absl::Status GlopSolver::FillSolveStats(const glop::ProblemStatus status, return absl::OkStatus(); } -absl::Status GlopSolver::FillSolveResult( +absl::StatusOr GlopSolver::MakeSolveResult( const glop::ProblemStatus status, const ModelSolveParametersProto& model_parameters, - const SolveInterrupter* const interrupter, const absl::Duration solve_time, - SolveResultProto& solve_result) { + const SolveInterrupter* const interrupter, + const absl::Duration solve_time) { + SolveResultProto solve_result; ASSIGN_OR_RETURN(*solve_result.mutable_termination(), BuildTermination(status, interrupter)); FillSolution(status, model_parameters, solve_result); RETURN_IF_ERROR( FillSolveStats(status, solve_time, *solve_result.mutable_solve_stats())); - return absl::OkStatus(); + return solve_result; } void GlopSolver::SetGlopBasis(const BasisProto& basis) { @@ -713,23 +716,13 @@ absl::StatusOr GlopSolver::Solve( /*supported_events=*/{})); const absl::Time start = absl::Now(); - SolveResultProto result; - { - auto [glop_parameters, warnings] = MergeSolveParameters( - parameters, - /*setting_initial_basis=*/model_parameters.has_initial_basis(), - /*has_message_callback=*/message_cb != nullptr); - if (!warnings.empty()) { - if (parameters.strictness().bad_parameter()) { - return absl::InvalidArgumentError(absl::StrJoin(warnings, "; ")); - } else { - for (std::string& warning : warnings) { - result.add_warnings(std::move(warning)); - } - } - } - lp_solver_.SetParameters(glop_parameters); - } + ASSIGN_OR_RETURN( + const glop::GlopParameters glop_parameters, + MergeSolveParameters( + parameters, + /*setting_initial_basis=*/model_parameters.has_initial_basis(), + /*has_message_callback=*/message_cb != nullptr)); + lp_solver_.SetParameters(glop_parameters); if (model_parameters.has_initial_basis()) { SetGlopBasis(model_parameters.initial_basis()); @@ -770,11 +763,7 @@ absl::StatusOr GlopSolver::Solve( const glop::ProblemStatus status = lp_solver_.SolveWithTimeLimit(linear_program_, time_limit.get()); const absl::Duration solve_time = absl::Now() - start; - - RETURN_IF_ERROR(FillSolveResult(status, model_parameters, interrupter, - solve_time, result)); - - return result; + return MakeSolveResult(status, model_parameters, interrupter, solve_time); } absl::StatusOr> GlopSolver::New( diff --git a/ortools/math_opt/solvers/glop_solver.h b/ortools/math_opt/solvers/glop_solver.h index 1c32b9fc43..978681fae8 100644 --- a/ortools/math_opt/solvers/glop_solver.h +++ b/ortools/math_opt/solvers/glop_solver.h @@ -60,9 +60,9 @@ class GlopSolver : public SolverInterface { // Returns the merged parameters and a list of warnings from any parameter // settings that are invalid for this solver. - static std::pair> - MergeSolveParameters(const SolveParametersProto& solver_parameters, - bool setting_initial_basis, bool has_message_callback); + static absl::StatusOr MergeSolveParameters( + const SolveParametersProto& solver_parameters, bool setting_initial_basis, + bool has_message_callback); private: GlopSolver(); @@ -85,11 +85,10 @@ class GlopSolver : public SolverInterface { void FillSolution(glop::ProblemStatus status, const ModelSolveParametersProto& model_parameters, SolveResultProto& solve_result); - absl::Status FillSolveResult( + absl::StatusOr MakeSolveResult( glop::ProblemStatus status, const ModelSolveParametersProto& model_parameters, - const SolveInterrupter* interrupter, absl::Duration solve_time, - SolveResultProto& solve_result); + const SolveInterrupter* interrupter, absl::Duration solve_time); absl::Status FillSolveStats(const glop::ProblemStatus status, absl::Duration solve_time, diff --git a/ortools/math_opt/solvers/gscip_solver.cc b/ortools/math_opt/solvers/gscip_solver.cc index c44a5852af..814ba79a11 100644 --- a/ortools/math_opt/solvers/gscip_solver.cc +++ b/ortools/math_opt/solvers/gscip_solver.cc @@ -48,6 +48,7 @@ #include "ortools/math_opt/core/math_opt_proto_utils.h" #include "ortools/math_opt/core/solve_interrupter.h" #include "ortools/math_opt/core/solver_interface.h" +#include "ortools/math_opt/core/sparse_submatrix.h" #include "ortools/math_opt/core/sparse_vector_view.h" #include "ortools/math_opt/model.pb.h" #include "ortools/math_opt/model_parameters.pb.h" @@ -299,16 +300,25 @@ absl::Status GScipSolver::AddVariables( const absl::flat_hash_map& linear_objective_coefficients) { for (int i = 0; i < NumVariables(variables); ++i) { const int64_t id = SafeId(variables, i); - CHECK_GE(id, next_unused_variable_id_); + // SCIP is failing with an assert in SCIPcreateVar() when input bounds are + // inverted. That said, it is not an issue if the bounds are created + // non-inverted and later changed. Thus here we use this hack to bypass the + // assertion in this corner case. + const bool inverted_bounds = + variables.lower_bounds(i) > variables.upper_bounds(i); ASSIGN_OR_RETURN( SCIP_VAR* const v, gscip_->AddVariable( - variables.lower_bounds(i), variables.upper_bounds(i), + variables.lower_bounds(i), + inverted_bounds ? variables.lower_bounds(i) + : variables.upper_bounds(i), gtl::FindWithDefault(linear_objective_coefficients, id), GScipVarTypeFromIsInteger(variables.integers(i)), SafeName(variables, i))); + if (inverted_bounds) { + RETURN_IF_ERROR(gscip_->SetUb(v, variables.upper_bounds(i))); + } gtl::InsertOrDie(&variables_, id, v); - next_unused_variable_id_ = id + 1; } return absl::OkStatus(); } @@ -335,7 +345,6 @@ absl::Status GScipSolver::AddLinearConstraints( &linear_constraint_matrix); !lin_con_it.IsDone(); lin_con_it.Next()) { const LinearConstraintView current = lin_con_it.Current(); - CHECK_GE(current.linear_constraint_id, next_unused_linear_constraint_id_); GScipLinearRange range; range.lower_bound = current.lower_bound; @@ -351,14 +360,15 @@ absl::Status GScipSolver::AddLinearConstraints( gscip_->AddLinearConstraint(range, std::string(current.name))); gtl::InsertOrDie(&linear_constraints_, current.linear_constraint_id, scip_con); - next_unused_linear_constraint_id_ = current.linear_constraint_id + 1; } return absl::OkStatus(); } absl::Status GScipSolver::UpdateLinearConstraints( const LinearConstraintUpdatesProto linear_constraint_updates, - const SparseDoubleMatrixProto& linear_constraint_matrix) { + const SparseDoubleMatrixProto& linear_constraint_matrix, + const std::optional first_new_var_id, + const std::optional first_new_cstr_id) { for (const auto [id, lb] : MakeView(linear_constraint_updates.lower_bounds())) { RETURN_IF_ERROR( @@ -369,15 +379,14 @@ absl::Status GScipSolver::UpdateLinearConstraints( RETURN_IF_ERROR( gscip_->SetLinearConstraintUb(linear_constraints_.at(id), ub)); } - for (int i = 0; i < linear_constraint_matrix.row_ids_size(); ++i) { - const int64_t lin_con_id = linear_constraint_matrix.row_ids(i); - if (lin_con_id >= next_unused_linear_constraint_id_) { - break; + for (const auto& [lin_con_id, var_coeffs] : SparseSubmatrixByRows( + linear_constraint_matrix, /*start_row_id=*/0, + /*end_row_id=*/first_new_cstr_id, /*start_col_id=*/0, + /*end_col_id=*/first_new_var_id)) { + for (const auto& [var_id, value] : var_coeffs) { + RETURN_IF_ERROR(gscip_->SetLinearConstraintCoef( + linear_constraints_.at(lin_con_id), variables_.at(var_id), value)); } - const int64_t var_id = linear_constraint_matrix.column_ids(i); - const double value = linear_constraint_matrix.coefficients(i); - RETURN_IF_ERROR(gscip_->SetLinearConstraintCoef( - linear_constraints_.at(lin_con_id), variables_.at(var_id), value)); } return absl::OkStatus(); } @@ -401,8 +410,8 @@ GScipParameters::MetaParamValue ConvertMathOptEmphasis(EmphasisProto emphasis) { } } -std::pair> -GScipSolver::MergeParameters(const SolveParametersProto& solve_parameters) { +absl::StatusOr GScipSolver::MergeParameters( + const SolveParametersProto& solve_parameters) { // First build the result by translating common parameters to a // GScipParameters, and then merging with user provided gscip_parameters. // This results in user provided solver specific parameters overwriting @@ -516,7 +525,10 @@ GScipSolver::MergeParameters(const SolveParametersProto& solve_parameters) { result.MergeFrom(solve_parameters.gscip()); - return {std::move(result), std::move(warnings)}; + if (!warnings.empty()) { + return absl::InvalidArgumentError(absl::StrJoin(warnings, "; ")); + } + return result; } namespace { @@ -804,12 +816,7 @@ absl::StatusOr GScipSolver::Solve( std::make_unique(message_cb); } - const auto [gscip_parameters, warnings] = MergeParameters(parameters); - if (parameters.strictness().bad_parameter() && !warnings.empty()) { - return absl::InvalidArgumentError(absl::StrJoin(warnings, "; ")); - } - // TODO(user): reorganize gscip to respect warning is error argument on bad - // parameters. + ASSIGN_OR_RETURN(auto gscip_parameters, MergeParameters(parameters)); for (const SolutionHintProto& hint : model_parameters.solution_hints()) { absl::flat_hash_map partial_solution; @@ -851,9 +858,6 @@ absl::StatusOr GScipSolver::Solve( parameters.has_cutoff_limit() ? std::make_optional(parameters.cutoff_limit()) : std::nullopt)); - for (const std::string& warning : warnings) { - result.add_warnings(warning); - } CHECK_OK(util_time::EncodeGoogleApiProto( absl::Now() - start, result.mutable_solve_stats()->mutable_solve_time())); return result; @@ -896,6 +900,12 @@ absl::Status GScipSolver::Update(const ModelUpdateProto& model_update) { } RETURN_IF_ERROR(gscip_->SafeBulkDelete(vars_to_delete)); } + + const std::optional first_new_var_id = + FirstVariableId(model_update.new_variables()); + const std::optional first_new_cstr_id = + FirstLinearConstraintId(model_update.new_linear_constraints()); + if (model_update.objective_updates().has_direction_update()) { RETURN_IF_ERROR(gscip_->SetMaximize( model_update.objective_updates().direction_update())); @@ -909,16 +919,69 @@ absl::Status GScipSolver::Update(const ModelUpdateProto& model_update) { SparseDoubleVectorAsMap( model_update.objective_updates().linear_coefficients()); for (const auto& obj_pair : linear_objective_updates) { - if (obj_pair.first < next_unused_variable_id_) { + // New variables' coefficient is set when the variables are added below. + if (!first_new_var_id.has_value() || obj_pair.first < *first_new_var_id) { RETURN_IF_ERROR( gscip_->SetObjCoef(variables_.at(obj_pair.first), obj_pair.second)); } } + + // Here the model_update.linear_constraint_matrix_updates is split into three + // sub-matrix: + // + // existing new + // columns columns + // / | \ + // existing | 1 | 2 | + // rows | | | + // |---------+---------| + // new | | + // rows | 3 | + // \ / + // + // The coefficients of sub-matrix 1 are set by UpdateLinearConstraints(), the + // ones of sub-matrix 2 by AddVariables() and the ones of the sub-matrix 3 by + // AddLinearConstraints(). The rationale here is that SCIPchgCoefLinear() has + // a complexity of O(non_zeros). Thus it is inefficient and can lead to O(n^2) + // behaviors if it was used for new rows or for new columns. For new rows it + // is more efficient to pass all the variables coefficients at once when + // building the constraints. For new columns and existing rows, since we can + // assume there is no existing coefficient, we can use SCIPaddCoefLinear() + // which is O(1). This leads to only use SCIPchgCoefLinear() for changing the + // coefficients of existing rows and columns. + // + // TODO(b/215722113): maybe we could use SCIPaddCoefLinear() for sub-matrix 1. + + // Add new variables. RETURN_IF_ERROR( AddVariables(model_update.new_variables(), linear_objective_updates)); + + // Update linear constraints properties and sub-matrix 1. RETURN_IF_ERROR( UpdateLinearConstraints(model_update.linear_constraint_updates(), - model_update.linear_constraint_matrix_updates())); + model_update.linear_constraint_matrix_updates(), + /*first_new_var_id=*/first_new_var_id, + /*first_new_cstr_id=*/first_new_cstr_id)); + + // Update the sub-matrix 2. + const std::optional first_new_variable_id = + FirstVariableId(model_update.new_variables()); + if (first_new_variable_id.has_value()) { + for (const auto& [lin_con_id, var_coeffs] : + SparseSubmatrixByRows(model_update.linear_constraint_matrix_updates(), + /*start_row_id=*/0, + /*end_row_id=*/first_new_cstr_id, + /*start_col_id=*/*first_new_variable_id, + /*end_col_id=*/std::nullopt)) { + for (const auto& [var_id, value] : var_coeffs) { + // See above why we use AddLinearConstraintCoef(). + RETURN_IF_ERROR(gscip_->AddLinearConstraintCoef( + linear_constraints_.at(lin_con_id), variables_.at(var_id), value)); + } + } + } + + // Add the new constraints and sets sub-matrix 3. RETURN_IF_ERROR( AddLinearConstraints(model_update.new_linear_constraints(), model_update.linear_constraint_matrix_updates())); diff --git a/ortools/math_opt/solvers/gscip_solver.h b/ortools/math_opt/solvers/gscip_solver.h index 92a8cd0b3c..f8cb3a4488 100644 --- a/ortools/math_opt/solvers/gscip_solver.h +++ b/ortools/math_opt/solvers/gscip_solver.h @@ -57,7 +57,7 @@ class GScipSolver : public SolverInterface { // Returns the merged parameters and a list of warnings for unsupported // parameters. - static std::pair> MergeParameters( + static absl::StatusOr MergeParameters( const SolveParametersProto& solve_parameters); private: @@ -100,16 +100,27 @@ class GScipSolver : public SolverInterface { explicit GScipSolver(std::unique_ptr gscip); + // Adds the new variables. absl::Status AddVariables(const VariablesProto& variables, const absl::flat_hash_map& linear_objective_coefficients); + + // Update existing variables' parameters. absl::Status UpdateVariables(const VariableUpdatesProto& variable_updates); + + // Adds the new linear constraints. absl::Status AddLinearConstraints( const LinearConstraintsProto& linear_constraints, const SparseDoubleMatrixProto& linear_constraint_matrix); + + // Updates the existing constraints and the coefficients of the existing + // variables of these constraints. absl::Status UpdateLinearConstraints( const LinearConstraintUpdatesProto linear_constraint_updates, - const SparseDoubleMatrixProto& linear_constraint_matrix); + const SparseDoubleMatrixProto& linear_constraint_matrix, + std::optional first_new_var_id, + std::optional first_new_cstr_id); + absl::flat_hash_set LookupAllVariables( absl::Span variable_ids); absl::StatusOr CreateSolveResultProto( @@ -121,8 +132,6 @@ class GScipSolver : public SolverInterface { InterruptEventHandler interrupt_event_handler_; absl::flat_hash_map variables_; absl::flat_hash_map linear_constraints_; - int64_t next_unused_variable_id_ = 0; - int64_t next_unused_linear_constraint_id_ = 0; }; } // namespace math_opt diff --git a/ortools/math_opt/solvers/gurobi_solver.cc b/ortools/math_opt/solvers/gurobi_solver.cc index c73f7bc46e..e4bd6d93a9 100644 --- a/ortools/math_opt/solvers/gurobi_solver.cc +++ b/ortools/math_opt/solvers/gurobi_solver.cc @@ -34,6 +34,7 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" +#include "absl/strings/str_join.h" #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" @@ -350,15 +351,6 @@ GurobiParametersProto MergeParameters( return merged_parameters; } -std::string JoinErrors(const std::vector& errors) { - std::string result = "["; - for (const absl::Status& error : errors) { - absl::StrAppend(&result, error.message()); - } - absl::StrAppend(&result, "]"); - return result; -} - absl::StatusOr SafeInt64FromDouble(const double d) { const int64_t result = static_cast(d); if (static_cast(result) != d) { @@ -1211,19 +1203,22 @@ absl::StatusOr GurobiSolver::GetQpSolution( return solution_and_claims; } -std::vector GurobiSolver::SetParameters( +absl::Status GurobiSolver::SetParameters( const SolveParametersProto& parameters) { const GurobiParametersProto gurobi_parameters = MergeParameters(parameters); - std::vector parameter_errors; + std::vector parameter_errors; for (const GurobiParametersProto::Parameter& parameter : gurobi_parameters.parameters()) { absl::Status param_status = gurobi_->SetParam(parameter.name().c_str(), parameter.value()); if (!param_status.ok()) { - parameter_errors.emplace_back(std::move(param_status)); + parameter_errors.emplace_back(std::move(param_status).message()); } } - return parameter_errors; + if (!parameter_errors.empty()) { + return absl::InvalidArgumentError(absl::StrJoin(parameter_errors, "; ")); + } + return absl::OkStatus(); } absl::Status GurobiSolver::AddNewVariables( @@ -1874,17 +1869,7 @@ absl::StatusOr GurobiSolver::Solve( const absl::Time start = absl::Now(); // We must set the parameters before calling RegisterCallback since it changes // some parameters depending on the callback registration. - const std::vector param_errors = SetParameters(parameters); - std::vector warnings; - if (!param_errors.empty()) { - if (parameters.strictness().bad_parameter()) { - return absl::InvalidArgumentError(JoinErrors(param_errors)); - } else { - for (const absl::Status& param_error : param_errors) { - warnings.push_back(std::string(param_error.message())); - } - } - } + RETURN_IF_ERROR(SetParameters(parameters)); // We use a local interrupter that will triggers the calls to GRBterminate() // when either the user interrupter is triggered or when a callback returns a @@ -1914,9 +1899,6 @@ absl::StatusOr GurobiSolver::Solve( const ScopedSolveInterrupterCallback scoped_chaining_callback( interrupter, [&]() { local_interrupter->Interrupt(); }); - // TODO(user): any warnings above will be lost if we get an error Status - // below, reconsider the Solve API. - // Need to run GRBupdatemodel before registering callbacks (to test if the // problem is a MIP), setting basis and getting the obj sense. RETURN_IF_ERROR(gurobi_->UpdateModel()); @@ -1963,10 +1945,6 @@ absl::StatusOr GurobiSolver::Solve( ASSIGN_OR_RETURN(SolveResultProto solve_result, ExtractSolveResultProto(start, model_parameters)); - for (const auto& warning : warnings) { - solve_result.add_warnings(warning); - } - // Reset Gurobi parameters. // TODO(user): ensure that resetting parameters does not degrade // incrementalism performance. diff --git a/ortools/math_opt/solvers/gurobi_solver.h b/ortools/math_opt/solvers/gurobi_solver.h index 4143c3c35f..82ee086fb8 100644 --- a/ortools/math_opt/solvers/gurobi_solver.h +++ b/ortools/math_opt/solvers/gurobi_solver.h @@ -174,10 +174,7 @@ class GurobiSolver : public SolverInterface { const ModelSolveParametersProto& model_parameters); absl::StatusOr> GetBasisIfAvailable(); - // Returns a list of errors for failures only (and the empty list when all - // parameters succeed). - std::vector SetParameters( - const SolveParametersProto& parameters); + absl::Status SetParameters(const SolveParametersProto& parameters); absl::Status AddNewConstraints(const LinearConstraintsProto& constraints); absl::Status AddNewVariables(const VariablesProto& new_variables); absl::Status AddNewSlacks(const std::vector& new_slacks); diff --git a/ortools/math_opt/solvers/pdlp_solver.cc b/ortools/math_opt/solvers/pdlp_solver.cc index c0f43849f5..51633bc206 100644 --- a/ortools/math_opt/solvers/pdlp_solver.cc +++ b/ortools/math_opt/solvers/pdlp_solver.cc @@ -66,8 +66,8 @@ absl::StatusOr> PdlpSolver::New( return result; } -std::pair> -PdlpSolver::MergeParameters(const SolveParametersProto& parameters) { +absl::StatusOr PdlpSolver::MergeParameters( + const SolveParametersProto& parameters) { PrimalDualHybridGradientParams result; std::vector warnings; if (parameters.enable_output()) { @@ -120,7 +120,10 @@ PdlpSolver::MergeParameters(const SolveParametersProto& parameters) { static_cast(limit)); } result.MergeFrom(parameters.pdlp()); - return {std::move(result), std::move(warnings)}; + if (!warnings.empty()) { + return absl::InvalidArgumentError(absl::StrJoin(warnings, "; ")); + } + return result; } namespace { @@ -201,9 +204,10 @@ ProblemStatusProto GetProblemStatus(const pdlp::TerminationReason pdlp_reason, } // namespace -absl::Status PdlpSolver::FillSolveResult( +absl::StatusOr PdlpSolver::MakeSolveResult( const pdlp::SolverResult& pdlp_result, - const ModelSolveParametersProto& model_params, SolveResultProto& result) { + const ModelSolveParametersProto& model_params) { + SolveResultProto result; ASSIGN_OR_RETURN(*result.mutable_termination(), ConvertReason(pdlp_result.solve_log.termination_reason(), pdlp_result.solve_log.termination_string())); @@ -319,7 +323,7 @@ absl::Status PdlpSolver::FillSolveResult( *result.mutable_solve_stats()->mutable_problem_status() = GetProblemStatus(pdlp_result.solve_log.termination_reason(), std::isfinite(result.solve_stats().best_dual_bound())); - return absl::OkStatus(); + return result; } absl::StatusOr PdlpSolver::Solve( @@ -338,21 +342,10 @@ absl::StatusOr PdlpSolver::Solve( RETURN_IF_ERROR(CheckRegisteredCallbackEvents(callback_registration, /*supported_events=*/{})); - SolveResultProto result; - auto [pdlp_params, param_warnings] = MergeParameters(parameters); - if (!param_warnings.empty()) { - if (parameters.strictness().bad_parameter()) { - return absl::InvalidArgumentError(absl::StrJoin(param_warnings, "; ")); - } else { - for (std::string& warning : param_warnings) { - result.add_warnings(std::move(warning)); - } - } - } + ASSIGN_OR_RETURN(auto pdlp_params, MergeParameters(parameters)); const SolverResult pdlp_result = PrimalDualHybridGradient(pdlp_bridge_.pdlp_lp(), pdlp_params); - RETURN_IF_ERROR(FillSolveResult(pdlp_result, model_parameters, result)); - return result; + return MakeSolveResult(pdlp_result, model_parameters); } absl::Status PdlpSolver::Update(const ModelUpdateProto& model_update) { // This function should never be called since CanUpdate() always returns diff --git a/ortools/math_opt/solvers/pdlp_solver.h b/ortools/math_opt/solvers/pdlp_solver.h index f62ee50f93..8fb115e6f9 100644 --- a/ortools/math_opt/solvers/pdlp_solver.h +++ b/ortools/math_opt/solvers/pdlp_solver.h @@ -51,16 +51,15 @@ class PdlpSolver : public SolverInterface { bool CanUpdate(const ModelUpdateProto& model_update) override; // Returns the merged parameters and a list of warnings. - static std::pair> - MergeParameters(const SolveParametersProto& parameters); + static absl::StatusOr MergeParameters( + const SolveParametersProto& parameters); private: PdlpSolver() = default; - absl::Status FillSolveResult(const pdlp::SolverResult& pdlp_result, - const ModelSolveParametersProto& model_params, - SolveResultProto& result); + absl::StatusOr MakeSolveResult( + const pdlp::SolverResult& pdlp_result, + const ModelSolveParametersProto& model_params); PdlpBridge pdlp_bridge_; }; diff --git a/ortools/math_opt/validators/result_validator.cc b/ortools/math_opt/validators/result_validator.cc index 560475eafc..469cd03f03 100644 --- a/ortools/math_opt/validators/result_validator.cc +++ b/ortools/math_opt/validators/result_validator.cc @@ -204,7 +204,6 @@ absl::Status ValidateTerminationConsistency(const SolveResultProto& result) { // Dual feasible solution is not required. // Primal/dual requirements imply primal/dual solution-status consistency. return absl::OkStatus(); - // TODO(b/211677729): update when TERMINATION_REASON_FEASIBLE is added. case TERMINATION_REASON_INFEASIBLE: RETURN_IF_ERROR( CheckPrimalStatusIs(status, FEASIBILITY_STATUS_INFEASIBLE)); diff --git a/ortools/sat/BUILD.bazel b/ortools/sat/BUILD.bazel index a8e35e495f..9f0b6b699c 100644 --- a/ortools/sat/BUILD.bazel +++ b/ortools/sat/BUILD.bazel @@ -209,7 +209,7 @@ cc_library( ":synchronization", "//ortools/base", "//ortools/base:file", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:stl_util", "//ortools/base:strong_vector", @@ -244,7 +244,7 @@ cc_library( ":model", ":sat_base", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:logging", "//ortools/util:sorted_interval_list", @@ -285,7 +285,7 @@ cc_library( ":timetable", "//ortools/base", "//ortools/base:file", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:stl_util", "//ortools/base:strong_vector", @@ -306,7 +306,7 @@ cc_library( ":cp_model_cc_proto", ":cp_model_utils", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:strong_vector", "//ortools/util:bitset", @@ -329,7 +329,7 @@ cc_library( ":sat_parameters_cc_proto", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:mathutil", "//ortools/base:strong_vector", @@ -421,7 +421,7 @@ cc_library( deps = [ ":model", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:bitset", "@com_google_absl//absl/base:core_headers", @@ -452,7 +452,7 @@ cc_library( ":util", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:stl_util", "//ortools/base:strong_vector", @@ -548,7 +548,7 @@ cc_library( ":util", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/graph:strongly_connected_components", @@ -577,7 +577,7 @@ cc_library( "//ortools/algorithms:dynamic_partition", "//ortools/base", "//ortools/base:adjustable_priority_queue", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/graph:strongly_connected_components", @@ -598,7 +598,7 @@ cc_library( ":sat_parameters_cc_proto", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:murmur", "//ortools/base:strong_vector", "//ortools/util:bitset", @@ -618,7 +618,7 @@ cc_library( ":sat_base", "//ortools/algorithms:sparse_permutation", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:stats", "@com_google_absl//absl/types:span", @@ -647,7 +647,7 @@ cc_library( ":presolve_context", "//ortools/algorithms:dynamic_partition", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "@com_google_absl//absl/types:span", ], @@ -664,7 +664,7 @@ cc_library( ":sat_solver", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:iterator_adaptors", "//ortools/base:map_util", "//ortools/base:stl_util", @@ -747,7 +747,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/util:sort", ], @@ -766,7 +766,7 @@ cc_library( ":sat_solver", "//ortools/base", "//ortools/base:cleanup", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/util:bitset", @@ -784,7 +784,7 @@ cc_library( ":model", ":sat_base", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:strong_vector", "//ortools/util:bitset", @@ -813,7 +813,7 @@ cc_library( ":sat_solver", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/util:sorted_interval_list", "@com_google_absl//absl/container:flat_hash_map", @@ -830,7 +830,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/graph:strongly_connected_components", "//ortools/util:sort", @@ -847,7 +847,7 @@ cc_library( deps = [ ":integer", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", ], ) @@ -867,7 +867,7 @@ cc_library( ":theta_tree", ":timetable", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:iterator_adaptors", ], ) @@ -882,7 +882,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/util:rev", "//ortools/util:sort", ], @@ -897,7 +897,7 @@ cc_library( ":intervals", ":sat_base", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/util:sort", ], ) @@ -921,7 +921,7 @@ cc_library( ":timetable", ":timetable_edgefinding", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", ], ) @@ -936,7 +936,7 @@ cc_library( ":sat_base", ":theta_tree", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/util:sort", ], ) @@ -957,7 +957,7 @@ cc_library( "//ortools/algorithms:sparse_permutation", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:strong_vector", "//ortools/graph:io", @@ -1021,7 +1021,7 @@ cc_library( ":util", ":zero_half_cuts", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:strong_vector", "//ortools/glop:parameters_cc_proto", @@ -1070,7 +1070,7 @@ cc_library( ":util", "//ortools/algorithms:knapsack_solver_for_cuts", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/util:time_limit", "@com_google_absl//absl/container:btree", @@ -1092,7 +1092,7 @@ cc_library( ":sat_base", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/util:time_limit", ], @@ -1106,7 +1106,7 @@ cc_library( ":integer", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/lp_data:base", ], ) @@ -1125,7 +1125,7 @@ cc_library( ":sat_parameters_cc_proto", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "//ortools/glop:lp_solver", "//ortools/glop:parameters_cc_proto", @@ -1155,7 +1155,7 @@ cc_library( ":sat_solver", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/linear_solver:linear_solver_cc_proto", "//ortools/port:proto_utils", @@ -1197,7 +1197,7 @@ cc_library( ":sat_solver", ":util", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/base:stl_util", "//ortools/util:sorted_interval_list", @@ -1216,7 +1216,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/util:rev", "//ortools/util:sort", @@ -1235,7 +1235,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "@com_google_absl//absl/container:flat_hash_map", ], ) @@ -1267,7 +1267,7 @@ cc_library( ":sat_solver", ":theta_tree", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/util:rev", "//ortools/util:sort", @@ -1285,7 +1285,7 @@ cc_library( ":sat_base", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:map_util", "//ortools/util:rev", "@com_google_absl//absl/container:flat_hash_map", @@ -1303,7 +1303,7 @@ cc_library( ":sat_parameters_cc_proto", ":sat_solver", "//ortools/base", - "//ortools/base:int_type", + "//ortools/base:intops", ], ) @@ -1398,7 +1398,7 @@ cc_library( ":sat_base", "//ortools/base", "//ortools/base:file", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:strong_vector", "@com_google_absl//absl/hash", "@com_google_absl//absl/memory", @@ -1419,7 +1419,7 @@ cc_library( ":sat_base", "//ortools/base", "//ortools/base:hash", - "//ortools/base:int_type", + "//ortools/base:intops", "//ortools/base:stl_util", "//ortools/base:strong_vector", "//ortools/util:time_limit", diff --git a/ortools/sat/all_different.cc b/ortools/sat/all_different.cc index ea4362367e..2599b2c62d 100644 --- a/ortools/sat/all_different.cc +++ b/ortools/sat/all_different.cc @@ -20,9 +20,9 @@ #include #include "absl/container/flat_hash_set.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/graph/strongly_connected_components.h" #include "ortools/sat/sat_solver.h" #include "ortools/util/sort.h" diff --git a/ortools/sat/boolean_problem.cc b/ortools/sat/boolean_problem.cc index a6f92e7996..351cb096fc 100644 --- a/ortools/sat/boolean_problem.cc +++ b/ortools/sat/boolean_problem.cc @@ -31,8 +31,8 @@ #endif // __PORTABLE_PLATFORM__ #include "ortools/algorithms/find_graph_symmetries.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/graph/util.h" #include "ortools/port/proto_utils.h" diff --git a/ortools/sat/circuit.h b/ortools/sat/circuit.h index 15a6db8ec5..352a8b9ea7 100644 --- a/ortools/sat/circuit.h +++ b/ortools/sat/circuit.h @@ -19,10 +19,10 @@ #include #include "absl/container/flat_hash_map.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/model.h" #include "ortools/sat/sat_base.h" diff --git a/ortools/sat/clause.h b/ortools/sat/clause.h index 1e29605781..ce8f993be1 100644 --- a/ortools/sat/clause.h +++ b/ortools/sat/clause.h @@ -29,9 +29,9 @@ #include "absl/random/bit_gen_ref.h" #include "absl/types/span.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/drat_proof_handler.h" #include "ortools/sat/model.h" diff --git a/ortools/sat/cp_constraints.h b/ortools/sat/cp_constraints.h index c1d84d32e6..5dd3354f80 100644 --- a/ortools/sat/cp_constraints.h +++ b/ortools/sat/cp_constraints.h @@ -19,10 +19,10 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/model.h" #include "ortools/sat/sat_base.h" diff --git a/ortools/sat/cp_model_loader.cc b/ortools/sat/cp_model_loader.cc index 8613b81966..5bc9a45642 100644 --- a/ortools/sat/cp_model_loader.cc +++ b/ortools/sat/cp_model_loader.cc @@ -25,10 +25,10 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/base/stl_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/base/vlog_is_on.h" #include "ortools/sat/all_different.h" diff --git a/ortools/sat/cp_model_loader.h b/ortools/sat/cp_model_loader.h index 275ed9fa96..c93256b539 100644 --- a/ortools/sat/cp_model_loader.h +++ b/ortools/sat/cp_model_loader.h @@ -19,10 +19,10 @@ #include #include "absl/container/flat_hash_set.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_mapping.h" diff --git a/ortools/sat/cp_model_mapping.h b/ortools/sat/cp_model_mapping.h index 6bb0e44016..fcccf4bd3a 100644 --- a/ortools/sat/cp_model_mapping.h +++ b/ortools/sat/cp_model_mapping.h @@ -20,9 +20,9 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_utils.h" diff --git a/ortools/sat/cp_model_solver.cc b/ortools/sat/cp_model_solver.cc index cb59049592..1b34fe752e 100644 --- a/ortools/sat/cp_model_solver.cc +++ b/ortools/sat/cp_model_solver.cc @@ -46,10 +46,10 @@ #include "absl/synchronization/mutex.h" #include "ortools/base/cleanup.h" #include "ortools/base/commandlineflags.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/threadpool.h" #include "ortools/base/timer.h" #include "ortools/base/version.h" diff --git a/ortools/sat/cumulative.cc b/ortools/sat/cumulative.cc index 74f67d9060..5e81d71e22 100644 --- a/ortools/sat/cumulative.cc +++ b/ortools/sat/cumulative.cc @@ -16,8 +16,8 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/cumulative_energy.h" #include "ortools/sat/disjunctive.h" #include "ortools/sat/linear_constraint.h" diff --git a/ortools/sat/cumulative_energy.cc b/ortools/sat/cumulative_energy.cc index 48dc9815e8..be990cbc56 100644 --- a/ortools/sat/cumulative_energy.cc +++ b/ortools/sat/cumulative_energy.cc @@ -16,9 +16,9 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/iterator_adaptors.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/sat_base.h" namespace operations_research { diff --git a/ortools/sat/cuts.h b/ortools/sat/cuts.h index eb6d17a5a7..801b704a08 100644 --- a/ortools/sat/cuts.h +++ b/ortools/sat/cuts.h @@ -19,7 +19,7 @@ #include #include -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/implied_bounds.h" #include "ortools/sat/integer.h" diff --git a/ortools/sat/diffn.h b/ortools/sat/diffn.h index 67b40b5f50..150fc79ecd 100644 --- a/ortools/sat/diffn.h +++ b/ortools/sat/diffn.h @@ -17,10 +17,10 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/diffn_util.h" #include "ortools/sat/disjunctive.h" #include "ortools/sat/integer.h" diff --git a/ortools/sat/disjunctive.h b/ortools/sat/disjunctive.h index 1e25046ee6..e20cec25b8 100644 --- a/ortools/sat/disjunctive.h +++ b/ortools/sat/disjunctive.h @@ -18,8 +18,8 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/intervals.h" #include "ortools/sat/model.h" diff --git a/ortools/sat/drat_checker.h b/ortools/sat/drat_checker.h index c3f96479a0..d80f1d8752 100644 --- a/ortools/sat/drat_checker.h +++ b/ortools/sat/drat_checker.h @@ -20,7 +20,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/sat_base.h" @@ -28,7 +28,7 @@ namespace operations_research { namespace sat { // Index of a clause (>= 0). -DEFINE_INT_TYPE(ClauseIndex, int); +DEFINE_STRONG_INT_TYPE(ClauseIndex, int); const ClauseIndex kNoClauseIndex(-1); // DRAT is a SAT proof format that allows a simple program to check that a diff --git a/ortools/sat/drat_proof_handler.cc b/ortools/sat/drat_proof_handler.cc index e3c705ceca..549998b175 100644 --- a/ortools/sat/drat_proof_handler.cc +++ b/ortools/sat/drat_proof_handler.cc @@ -16,8 +16,8 @@ #include #include "absl/memory/memory.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" namespace operations_research { diff --git a/ortools/sat/encoding.h b/ortools/sat/encoding.h index 7c08e30699..24063a9659 100644 --- a/ortools/sat/encoding.h +++ b/ortools/sat/encoding.h @@ -22,10 +22,10 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/boolean_problem.pb.h" #include "ortools/sat/pb_constraint.h" #include "ortools/sat/sat_base.h" diff --git a/ortools/sat/implied_bounds.h b/ortools/sat/implied_bounds.h index c3301c0164..1989119aa1 100644 --- a/ortools/sat/implied_bounds.h +++ b/ortools/sat/implied_bounds.h @@ -19,9 +19,9 @@ #include #include "absl/container/flat_hash_map.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/integer.h" #include "ortools/sat/linear_constraint.h" diff --git a/ortools/sat/integer.h b/ortools/sat/integer.h index 768f9ad2e1..d8612cd65a 100644 --- a/ortools/sat/integer.h +++ b/ortools/sat/integer.h @@ -30,11 +30,11 @@ #include "absl/strings/str_cat.h" #include "absl/types/span.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" #include "ortools/base/map_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/graph/iterators.h" #include "ortools/sat/model.h" @@ -55,7 +55,7 @@ namespace sat { // Note that both bounds are inclusive, which allows to write many propagation // algorithms for just one of the bound and apply it to the negated variables to // get the symmetric algorithm for the other bound. -DEFINE_INT_TYPE(IntegerValue, int64_t); +DEFINE_STRONG_INT_TYPE(IntegerValue, int64_t); // The max range of an integer variable is [kMinIntegerValue, kMaxIntegerValue]. // @@ -130,7 +130,7 @@ inline bool AddProductTo(IntegerValue a, IntegerValue b, IntegerValue* result) { // Each time we create an IntegerVariable we also create its negation. This is // done like that so internally we only stores and deal with lower bound. The // upper bound beeing the lower bound of the negated variable. -DEFINE_INT_TYPE(IntegerVariable, int32_t); +DEFINE_STRONG_INT_TYPE(IntegerVariable, int32_t); const IntegerVariable kNoIntegerVariable(-1); inline IntegerVariable NegationOf(IntegerVariable i) { return IntegerVariable(i.value() ^ 1); @@ -145,7 +145,7 @@ inline IntegerVariable PositiveVariable(IntegerVariable i) { } // Special type for storing only one thing for var and NegationOf(var). -DEFINE_INT_TYPE(PositiveOnlyIndex, int32_t); +DEFINE_STRONG_INT_TYPE(PositiveOnlyIndex, int32_t); inline PositiveOnlyIndex GetPositiveOnlyIndex(IntegerVariable var) { return PositiveOnlyIndex(var.value() / 2); } @@ -1349,7 +1349,7 @@ class GenericLiteralWatcher : public SatPropagator { std::vector in_queue_; // Data for each propagator. - DEFINE_INT_TYPE(IdType, int32_t); + DEFINE_STRONG_INT_TYPE(IdType, int32_t); std::vector id_to_level_at_last_call_; RevVector id_to_greatest_common_level_since_last_call_; std::vector> id_to_reversible_classes_; diff --git a/ortools/sat/integer_expr.h b/ortools/sat/integer_expr.h index 222ed86a32..3c0fee36e5 100644 --- a/ortools/sat/integer_expr.h +++ b/ortools/sat/integer_expr.h @@ -18,11 +18,11 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" #include "ortools/base/mathutil.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/linear_constraint.h" #include "ortools/sat/model.h" diff --git a/ortools/sat/intervals.h b/ortools/sat/intervals.h index 0cb430d9f1..0ea270bf6c 100644 --- a/ortools/sat/intervals.h +++ b/ortools/sat/intervals.h @@ -20,10 +20,10 @@ #include #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/cp_constraints.h" #include "ortools/sat/integer.h" @@ -37,7 +37,7 @@ namespace operations_research { namespace sat { -DEFINE_INT_TYPE(IntervalVariable, int32_t); +DEFINE_STRONG_INT_TYPE(IntervalVariable, int32_t); const IntervalVariable kNoIntervalVariable(-1); // This class maintains a set of intervals which correspond to three integer diff --git a/ortools/sat/lb_tree_search.h b/ortools/sat/lb_tree_search.h index 7610e2a296..dbe195350f 100644 --- a/ortools/sat/lb_tree_search.h +++ b/ortools/sat/lb_tree_search.h @@ -50,7 +50,7 @@ class LbTreeSearch { private: // Code a binary tree. - DEFINE_INT_TYPE(NodeIndex, int); + DEFINE_STRONG_INT_TYPE(NodeIndex, int); struct Node { Node(Literal l, IntegerValue lb) : literal(l), true_objective(lb), false_objective(lb) {} diff --git a/ortools/sat/linear_constraint_manager.h b/ortools/sat/linear_constraint_manager.h index a852c8d778..69befefab9 100644 --- a/ortools/sat/linear_constraint_manager.h +++ b/ortools/sat/linear_constraint_manager.h @@ -77,7 +77,7 @@ class LinearConstraintManager { // basic preprocessing. If added is given, it will be set to true if this // constraint was actually a new one and to false if it was dominated by an // already existing one. - DEFINE_INT_TYPE(ConstraintIndex, int32_t); + DEFINE_STRONG_INT_TYPE(ConstraintIndex, int32_t); ConstraintIndex Add(LinearConstraint ct, bool* added = nullptr); // Same as Add(), but logs some information about the newly added constraint. diff --git a/ortools/sat/linear_programming_constraint.h b/ortools/sat/linear_programming_constraint.h index 4cc98bf702..6c7d226e09 100644 --- a/ortools/sat/linear_programming_constraint.h +++ b/ortools/sat/linear_programming_constraint.h @@ -20,7 +20,7 @@ #include #include "absl/container/flat_hash_map.h" -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/glop/revised_simplex.h" #include "ortools/lp_data/lp_data.h" diff --git a/ortools/sat/lp_utils.cc b/ortools/sat/lp_utils.cc index 7fe8ea221c..fb283337b6 100644 --- a/ortools/sat/lp_utils.cc +++ b/ortools/sat/lp_utils.cc @@ -23,9 +23,9 @@ #include #include "absl/strings/str_cat.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/glop/lp_solver.h" #include "ortools/glop/parameters.pb.h" #include "ortools/lp_data/lp_types.h" diff --git a/ortools/sat/optimization.cc b/ortools/sat/optimization.cc index ee111490b1..f71255f459 100644 --- a/ortools/sat/optimization.cc +++ b/ortools/sat/optimization.cc @@ -30,11 +30,11 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "ortools/base/cleanup.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" #include "ortools/base/map_util.h" #include "ortools/base/stl_util.h" +#include "ortools/base/strong_int.h" #include "ortools/base/timer.h" #if !defined(__PORTABLE_PLATFORM__) && defined(USE_SCIP) #include "ortools/linear_solver/linear_solver.h" diff --git a/ortools/sat/pb_constraint.h b/ortools/sat/pb_constraint.h index 401280c922..d6ce5e5792 100644 --- a/ortools/sat/pb_constraint.h +++ b/ortools/sat/pb_constraint.h @@ -23,10 +23,10 @@ #include "absl/container/flat_hash_map.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/model.h" #include "ortools/sat/sat_base.h" @@ -39,7 +39,7 @@ namespace sat { // The type of the integer coefficients in a pseudo-Boolean constraint. // This is also used for the current value of a constraint or its bounds. -DEFINE_INT_TYPE(Coefficient, int64_t); +DEFINE_STRONG_INT_TYPE(Coefficient, int64_t); // IMPORTANT: We can't use numeric_limits::max() which will compile // but just returns zero!! @@ -626,7 +626,7 @@ class PbConstraints : public SatPropagator { // about two times faster with this implementation than one with direct // pointer to an UpperBoundedLinearConstraint. The main reason for this is // probably that the thresholds_ vector is a lot more efficient cache-wise. - DEFINE_INT_TYPE(ConstraintIndex, int32_t); + DEFINE_STRONG_INT_TYPE(ConstraintIndex, int32_t); struct ConstraintIndexWithCoeff { ConstraintIndexWithCoeff() {} // Needed for vector.resize() ConstraintIndexWithCoeff(bool n, ConstraintIndex i, Coefficient c) diff --git a/ortools/sat/precedences.h b/ortools/sat/precedences.h index a847c89b5d..8b71b3da74 100644 --- a/ortools/sat/precedences.h +++ b/ortools/sat/precedences.h @@ -20,9 +20,9 @@ #include #include "absl/container/inlined_vector.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/integer.h" #include "ortools/sat/model.h" @@ -132,8 +132,8 @@ class PrecedencesPropagator : public SatPropagator, PropagatorInterface { int AddGreaterThanAtLeastOneOfConstraints(Model* model); private: - DEFINE_INT_TYPE(ArcIndex, int); - DEFINE_INT_TYPE(OptionalArcIndex, int); + DEFINE_STRONG_INT_TYPE(ArcIndex, int); + DEFINE_STRONG_INT_TYPE(OptionalArcIndex, int); // Given an existing clause, sees if it can be used to add "greater than at // least one of" type of constraints. Returns the number of such constraint diff --git a/ortools/sat/presolve_util.h b/ortools/sat/presolve_util.h index fb93a92844..62b1bd587b 100644 --- a/ortools/sat/presolve_util.h +++ b/ortools/sat/presolve_util.h @@ -19,9 +19,9 @@ #include #include "absl/container/flat_hash_map.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/cp_model.pb.h" #include "ortools/sat/cp_model_utils.h" @@ -72,7 +72,7 @@ class DomainDeductions { int NumDeductions() const { return deductions_.size(); } private: - DEFINE_INT_TYPE(Index, int); + DEFINE_STRONG_INT_TYPE(Index, int); Index IndexFromLiteral(int ref) { return Index(ref >= 0 ? 2 * ref : -2 * ref - 1); } diff --git a/ortools/sat/sat_base.h b/ortools/sat/sat_base.h index 4af7aa9d77..84369a45bd 100644 --- a/ortools/sat/sat_base.h +++ b/ortools/sat/sat_base.h @@ -26,10 +26,10 @@ #include "absl/base/attributes.h" #include "absl/strings/str_format.h" #include "absl/types/span.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/model.h" #include "ortools/util/bitset.h" @@ -38,11 +38,11 @@ namespace operations_research { namespace sat { // Index of a variable (>= 0). -DEFINE_INT_TYPE(BooleanVariable, int); +DEFINE_STRONG_INT_TYPE(BooleanVariable, int); const BooleanVariable kNoBooleanVariable(-1); // Index of a literal (>= 0), see Literal below. -DEFINE_INT_TYPE(LiteralIndex, int); +DEFINE_STRONG_INT_TYPE(LiteralIndex, int); const LiteralIndex kNoLiteralIndex(-1); // Special values used in some API to indicate a literal that is always true diff --git a/ortools/sat/sat_inprocessing.h b/ortools/sat/sat_inprocessing.h index f84dc06238..5f15f6e5ce 100644 --- a/ortools/sat/sat_inprocessing.h +++ b/ortools/sat/sat_inprocessing.h @@ -285,7 +285,7 @@ class BlockedClauseSimplifier { // We compute the occurrence graph just once at the beginning of each round // and we do not shrink it as we remove blocked clauses. - DEFINE_INT_TYPE(ClauseIndex, int32_t); + DEFINE_STRONG_INT_TYPE(ClauseIndex, int32_t); absl::StrongVector clauses_; absl::StrongVector> literal_to_clauses_; @@ -368,7 +368,7 @@ class BoundedVariableElimination { // We compute the occurrence graph just once at the beginning of each round. // We maintains the sizes at all time and lazily shrink the graph with deleted // clauses. - DEFINE_INT_TYPE(ClauseIndex, int32_t); + DEFINE_STRONG_INT_TYPE(ClauseIndex, int32_t); absl::StrongVector clauses_; absl::StrongVector> literal_to_clauses_; diff --git a/ortools/sat/sat_solver.h b/ortools/sat/sat_solver.h index ffe6a633c2..0ac2c460a7 100644 --- a/ortools/sat/sat_solver.h +++ b/ortools/sat/sat_solver.h @@ -30,10 +30,10 @@ #include "absl/container/flat_hash_map.h" #include "absl/types/span.h" #include "ortools/base/hash.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/timer.h" #include "ortools/sat/clause.h" #include "ortools/sat/drat_proof_handler.h" @@ -806,7 +806,7 @@ class SatSolver { std::vector literals_scratchpad_; // A boolean vector used to temporarily mark decision levels. - DEFINE_INT_TYPE(SatDecisionLevel, int); + DEFINE_STRONG_INT_TYPE(SatDecisionLevel, int); SparseBitset is_level_marked_; // Temporary vectors used by EnqueueDecisionAndBackjumpOnConflict(). diff --git a/ortools/sat/scheduling_constraints.h b/ortools/sat/scheduling_constraints.h index 3d65a30a74..b541d556eb 100644 --- a/ortools/sat/scheduling_constraints.h +++ b/ortools/sat/scheduling_constraints.h @@ -17,10 +17,10 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/logging.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/intervals.h" #include "ortools/sat/model.h" diff --git a/ortools/sat/scheduling_cuts.h b/ortools/sat/scheduling_cuts.h index f31be54974..792b6447bd 100644 --- a/ortools/sat/scheduling_cuts.h +++ b/ortools/sat/scheduling_cuts.h @@ -19,7 +19,7 @@ #include #include -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/cuts.h" #include "ortools/sat/integer.h" diff --git a/ortools/sat/simplification.h b/ortools/sat/simplification.h index 24026e575e..378f40772e 100644 --- a/ortools/sat/simplification.h +++ b/ortools/sat/simplification.h @@ -27,9 +27,9 @@ #include "absl/types/span.h" #include "ortools/base/adjustable_priority_queue.h" -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/base/strong_vector.h" #include "ortools/sat/drat_proof_handler.h" #include "ortools/sat/sat_base.h" diff --git a/ortools/sat/symmetry.cc b/ortools/sat/symmetry.cc index f20fb9aef9..7c03827771 100644 --- a/ortools/sat/symmetry.cc +++ b/ortools/sat/symmetry.cc @@ -13,8 +13,8 @@ #include "ortools/sat/symmetry.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" namespace operations_research { namespace sat { diff --git a/ortools/sat/table.cc b/ortools/sat/table.cc index 3882a7cd72..02a7ee9921 100644 --- a/ortools/sat/table.cc +++ b/ortools/sat/table.cc @@ -24,10 +24,10 @@ #include "absl/container/flat_hash_set.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" #include "ortools/base/map_util.h" #include "ortools/base/stl_util.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/sat_base.h" #include "ortools/sat/sat_solver.h" #include "ortools/sat/util.h" diff --git a/ortools/sat/theta_tree.cc b/ortools/sat/theta_tree.cc index ac0bf7d183..1235c16ef9 100644 --- a/ortools/sat/theta_tree.cc +++ b/ortools/sat/theta_tree.cc @@ -17,7 +17,7 @@ #include #include -#include "ortools/base/int_type.h" +#include "ortools/base/strong_int.h" namespace operations_research { namespace sat { diff --git a/ortools/sat/timetable.cc b/ortools/sat/timetable.cc index f09a64d642..7efa6f9c61 100644 --- a/ortools/sat/timetable.cc +++ b/ortools/sat/timetable.cc @@ -18,8 +18,8 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/util/sort.h" namespace operations_research { diff --git a/ortools/sat/timetable_edgefinding.cc b/ortools/sat/timetable_edgefinding.cc index 6da8844746..c3d8a7d34f 100644 --- a/ortools/sat/timetable_edgefinding.cc +++ b/ortools/sat/timetable_edgefinding.cc @@ -19,10 +19,10 @@ #include #include -#include "ortools/base/int_type.h" #include "ortools/base/integral_types.h" #include "ortools/base/iterator_adaptors.h" #include "ortools/base/logging.h" +#include "ortools/base/strong_int.h" #include "ortools/util/sort.h" namespace operations_research { diff --git a/ortools/sat/timetable_edgefinding.h b/ortools/sat/timetable_edgefinding.h index 59c825f1f1..cbe74a11f7 100644 --- a/ortools/sat/timetable_edgefinding.h +++ b/ortools/sat/timetable_edgefinding.h @@ -16,8 +16,8 @@ #include -#include "ortools/base/int_type.h" #include "ortools/base/macros.h" +#include "ortools/base/strong_int.h" #include "ortools/sat/integer.h" #include "ortools/sat/intervals.h" #include "ortools/sat/sat_base.h"