// Copyright 2010-2025 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // IWYU pragma: private, include "ortools/math_opt/cpp/math_opt.h" // IWYU pragma: friend "ortools/math_opt/cpp/.*" #ifndef ORTOOLS_MATH_OPT_CPP_PARAMETERS_H_ #define ORTOOLS_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 "ortools/base/linked_hash_map.h" #include "ortools/glop/parameters.pb.h" // IWYU pragma: export #include "ortools/math_opt/cpp/enums.h" // IWYU pragma: export #include "ortools/math_opt/parameters.pb.h" #include "ortools/math_opt/solvers/gscip/gscip.pb.h" // IWYU pragma: export #include "ortools/math_opt/solvers/gurobi.pb.h" // IWYU pragma: export #include "ortools/math_opt/solvers/highs.pb.h" // IWYU pragma: export #include "ortools/pdlp/solvers.pb.h" // IWYU pragma: export #include "ortools/sat/sat_parameters.pb.h" // IWYU pragma: export namespace operations_research { namespace math_opt { // The solvers supported by MathOpt. enum class SolverType { // Solving Constraint Integer Programs (SCIP) solver (third party). // // Supports LP, MIP, and nonconvex integer quadratic problems. No dual data // for LPs is returned though. Prefer GLOP for LPs. kGscip = SOLVER_TYPE_GSCIP, // Gurobi solver (third party). // // Supports LP, MIP, and nonconvex integer quadratic problems. Generally the // fastest option, but has special licensing. kGurobi = SOLVER_TYPE_GUROBI, // Google's Glop solver. // // Supports LP with primal and dual simplex methods. kGlop = SOLVER_TYPE_GLOP, // Google's CP-SAT solver. // // Supports problems where all variables are integer and bounded (or implied // to be after presolve). Experimental support to rescale and discretize // problems with continuous variables. kCpSat = SOLVER_TYPE_CP_SAT, // Google's PDLP solver. // // Supports LP and convex diagonal quadratic objectives. Uses first order // methods rather than simplex. Can solve very large problems. kPdlp = SOLVER_TYPE_PDLP, // GNU Linear Programming Kit (GLPK) (third party). // // Supports MIP and LP. // // Thread-safety: GLPK use thread-local storage for memory allocations. As a // consequence when using IncrementalSolver, the user must make sure that // instances are destroyed on the same thread as they are created or GLPK will // crash. It seems OK to call IncrementalSolver::Solve() from another thread // than the one used to create the Solver but it is not documented by GLPK and // should be avoided. Of course these limitations do not apply to the Solve() // function that recreates a new GLPK problem in the calling thread and // destroys before returning. // // When solving a LP with the presolver, a solution (and the unbound rays) are // only returned if an optimal solution has been found. Else nothing is // returned. See glpk-5.0/doc/glpk.pdf page #40 available from glpk-5.0.tar.gz // for details. kGlpk = SOLVER_TYPE_GLPK, // The Embedded Conic Solver (ECOS). // // Supports LP and SOCP problems. Uses interior point methods (barrier). kEcos = SOLVER_TYPE_ECOS, // The Splitting Conic Solver (SCS) (third party). // // Supports LP and SOCP problems. Uses a first-order method. kScs = SOLVER_TYPE_SCS, // The HiGHS Solver (third party). // // Supports LP and MIP problems (convex QPs are unimplemented). kHighs = SOLVER_TYPE_HIGHS, // MathOpt's reference implementation of a MIP solver. // // Slow/not recommended for production. Not an LP solver (no dual information // returned). kSantorini = SOLVER_TYPE_SANTORINI, // Fico XPRESS solver (third party). // // Supports LP, MIP, and nonconvex integer quadratic problems. // A fast option, but has special licensing. kXpress = SOLVER_TYPE_XPRESS, }; MATH_OPT_DEFINE_ENUM(SolverType, SOLVER_TYPE_UNSPECIFIED); // Parses a flag of type SolverType. // // The expected values are the one returned by EnumToString(). bool AbslParseFlag(absl::string_view text, SolverType* value, std::string* error); // Unparses a flag of type SolverType. // // The returned values are the same as EnumToString(). std::string AbslUnparseFlag(SolverType value); // Selects an algorithm for solving linear programs. enum class LPAlgorithm { // The (primal) simplex method. Typically can provide primal and dual // solutions, primal/dual rays on primal/dual unbounded problems, and a basis. kPrimalSimplex = LP_ALGORITHM_PRIMAL_SIMPLEX, // The dual simplex method. Typically can provide primal and dual // solutions, primal/dual rays on primal/dual unbounded problems, and a basis. kDualSimplex = LP_ALGORITHM_DUAL_SIMPLEX, // The barrier method, also commonly called an interior point method (IPM). // Can typically give both primal and dual solutions. Some implementations can // also produce rays on unbounded/infeasible problems. A basis is not given // unless the underlying solver does "crossover" and finishes with simplex. kBarrier = LP_ALGORITHM_BARRIER, // An algorithm based around a first-order method. These will typically // produce both primal and dual solutions, and potentially also certificates // of primal and/or dual infeasibility. First-order methods typically will // provide solutions with lower accuracy, so users should take care to set // solution quality parameters (e.g., tolerances) and to validate solutions. kFirstOrder = LP_ALGORITHM_FIRST_ORDER, }; MATH_OPT_DEFINE_ENUM(LPAlgorithm, LP_ALGORITHM_UNSPECIFIED); // Parses a flag of type LPAlgorithm. // // The expected values are the one returned by EnumToString(). bool AbslParseFlag(absl::string_view text, LPAlgorithm* value, std::string* error); // Unparses a flag of type LPAlgorithm. // // The returned values are the same as EnumToString(). std::string AbslUnparseFlag(LPAlgorithm value); // Effort level applied to an optional task while solving (see SolveParameters // for use). // // Typically used as a std::optional. It's used to configure a solver // feature as follows: // * 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 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 an error, and will map onto their best match. enum class Emphasis { kOff = EMPHASIS_OFF, kLow = EMPHASIS_LOW, kMedium = EMPHASIS_MEDIUM, kHigh = EMPHASIS_HIGH, kVeryHigh = EMPHASIS_VERY_HIGH }; MATH_OPT_DEFINE_ENUM(Emphasis, EMPHASIS_UNSPECIFIED); // Parses a flag of type Emphasis. // // The expected values are the one returned by EnumToString(). bool AbslParseFlag(absl::string_view text, Emphasis* value, std::string* error); // Unparses a flag of type Emphasis. // // The returned values are the same as EnumToString(). std::string AbslUnparseFlag(Emphasis value); // Gurobi specific parameters for solving. See // https://www.gurobi.com/documentation/9.1/refman/parameters.html // for a list of possible parameters. // // Example use: // GurobiParameters gurobi; // gurobi.param_values["BarIterLimit"] = "10"; // // With Gurobi, the order that parameters are applied can have an impact in rare // situations. Parameters are applied in the following order: // * LogToConsole is set from SolveParameters.enable_output. // * Any common parameters not overwritten by GurobiParameters. // * param_values in iteration order (insertion order). // We set LogToConsole first because setting other parameters can generate // output. struct GurobiParameters { // Parameter name-value pairs to set in insertion order. gtl::linked_hash_map param_values; GurobiParametersProto Proto() const; static GurobiParameters FromProto(const GurobiParametersProto& proto); bool empty() const { return param_values.empty(); } }; // GLPK specific parameters for solving. // // Fields are optional to enable capturing user intention; if the user // explicitly sets a value, then no generic solve parameters will overwrite this // parameter. User specified solver specific parameters have priority over // generic parameters. struct GlpkParameters { // Compute the primal or dual unbound ray when the variable (structural or // auxiliary) causing the unboundness is identified (see glp_get_unbnd_ray()). // // The unset value is equivalent to false. // // Rays are only available when solving linear programs, they are not // available for MIPs. On top of that they are only available when using a // simplex algorithm with the presolve disabled. // // A primal ray can only be built if the chosen LP algorithm is // LPAlgorithm::kPrimalSimplex. Same for a dual ray and // LPAlgorithm::kDualSimplex. // // The computation involves the basis factorization to be available which may // lead to extra computations/errors. std::optional compute_unbound_rays_if_possible = std::nullopt; GlpkParametersProto Proto() const; static GlpkParameters FromProto(const GlpkParametersProto& proto); }; // Xpress specific parameters for solving. See // https://www.fico.com/fico-xpress-optimization/docs/latest/solver/optimizer/HTML/chapter7.html // for a list of possible parameters (called "controls" in Xpress). // In addition to all Xpress controls, the following special parameters are // also supported: // "EXPORT_MODEL"(string) If present then the low level Xpress model // (the XPRSprob instance) is written to that file // right before XPRSoptimize() is called. This can // be useful for debugging. // "FORCE_POSTSOLVE"(int) If set to a non-zero value then the low-level code // will call XPRSpostsolve() right after calling // XPRSoptimize(). If not set or set to zero then // calling XPRSpostsolve() is delayed to the latest // possible point in time to enable incremental // solves. // "STOP_AFTER_LP"(int) If set to a non-zero value then the solve will be // stopped right after solving the root relaxation. // This is the same as passing the ' l' (ell) flag // to XPRSoptimize() and stops the process earlier // than a limit like MAXNODE=0. // // Example use: // XpressParameters xpress; // xpress.param_values["BarIterLimit"] = "10"; // // Parameters are applied in the following order: // * Any parameters derived from ortools parameters (like LP algorithm). // * param_values in iteration order (insertion order). struct XpressParameters { // Parameter name-value pairs to set in insertion order. gtl::linked_hash_map param_values; XpressParametersProto Proto() const; static XpressParameters FromProto(const XpressParametersProto& proto); bool empty() const { return param_values.empty(); } }; // Parameters to control a single solve. // // Contains both parameters common to all solvers, e.g. time_limit, and // parameters for a specific solver, e.g. gscip. If a value is set in both // common and solver specific fields, the solver specific setting is used. // // The common parameters that are optional and unset indicate that the solver // default is used. // // Solver specific parameters for solvers other than the one in use are ignored. // // Parameters that depends on the model (e.g. branching priority is set for // each variable) are passed in ModelSolveParametersProto. struct SolveParameters { // Enables printing the solver implementation traces. These traces are sent // to the standard output stream. // // Note that if the user registers a message callback, then this parameter // value is ignored and no traces are printed. bool enable_output = false; // Maximum time a solver should spend on the problem. // // This value is not a hard limit, solve time may slightly exceed this value. // Always passed to the underlying solver, the solver default is not used. absl::Duration time_limit = absl::InfiniteDuration(); // Limit on the iterations of the underlying algorithm (e.g. simplex pivots). // The specific behavior is dependent on the solver and algorithm used, but // often can give a deterministic solve limit (further configuration may be // needed, e.g. one thread). // // Typically supported by LP, QP, and MIP solvers, but for MIP solvers see // also node_limit. std::optional iteration_limit; // Limit on the number of subproblems solved in enumerative search (e.g. // branch and bound). For many solvers this can be used to deterministically // limit computation (further configuration may be needed, e.g. one thread). // // Typically for MIP solvers, see also iteration_limit. std::optional node_limit; // The solver stops early if it can prove there are no primal solutions at // least as good as cutoff. // // On an early stop, the solver returns termination reason kNoSolutionFound // and with limit kCutoff and is not required to give any extra solution // information. Has no effect on the return value if there is no early stop. // // It is recommended that you use a tolerance if you want solutions with // objective exactly equal to cutoff to be returned. // // See the user guide for more details and a comparison with best_bound_limit. std::optional cutoff_limit; // The solver stops early as soon as it finds a solution at least this good, // with termination reason kFeasible and limit kObjective. std::optional objective_limit; // The solver stops early as soon as it proves the best bound is at least this // good, with termination reason kFeasible or kNoSolutionFound and limit // kObjective. // // See the user guide for a comparison with cutoff_limit. std::optional best_bound_limit; // The solver stops early after finding this many feasible solutions, with // termination reason kFeasible and limit kSolution. Must be greater than // zero if set. It is often used to get the solver to stop on the first // feasible solution found. Note that there is no guarantee on the objective // value for any of the returned solutions. // // Solvers will typically not return more solutions than the solution limit, // but this is not enforced by MathOpt, see also b/214041169. // // Currently supported for Gurobi, Xpress and SCIP, and for CP-SAT only with // value 1. std::optional solution_limit; // If unset, use the solver default. If set, it must be >= 1. std::optional threads; // Seed for the pseudo-random number generator in the underlying // solver. Note that all solvers use pseudo-random numbers to select things // such as perturbation in the LP algorithm, for tie-break-up rules, and for // heuristic fixings. Varying this can have a noticeable impact on solver // behavior. // // Although all solvers have a concept of seeds, note that valid values // depend on the actual solver. // - Gurobi: [0:GRB_MAXINT] (which as of Gurobi 9.0 is 2x10^9). // - GSCIP: [0:2147483647] (which is MAX_INT or kint32max or 2^31-1). // - GLOP: [0:2147483647] (same as above) // - Xpress: Any 32bit signed integer is allowed // In all cases, the solver will receive a value equal to: // MAX(0, MIN(MAX_VALID_VALUE_FOR_SOLVER, random_seed)). std::optional random_seed; // An absolute optimality tolerance (primarily) for MIP solvers. // // The absolute GAP is the absolute value of the difference between: // * the objective value of the best feasible solution found, // * the dual bound produced by the search. // The solver can stop once the absolute GAP is at most absolute_gap_tolerance // (when set), and return TerminationReason::kOptimal. // // Must be >= 0 if set. // // See also relative_gap_tolerance. std::optional absolute_gap_tolerance; // A relative optimality tolerance (primarily) for MIP solvers. // // The relative GAP is a normalized version of the absolute GAP (defined on // absolute_gap_tolerance), where the normalization is solver-dependent, e.g. // the absolute GAP divided by the objective value of the best feasible // solution found. // // The solver can stop once the relative GAP is at most relative_gap_tolerance // (when set), and return TerminationReason::kOptimal. // // Must be >= 0 if set. // // See also absolute_gap_tolerance. std::optional relative_gap_tolerance; // Maintain up to `solution_pool_size` solutions while searching. The solution // pool generally has two functions: // (1) For solvers that can return more than one solution, this limits how // many solutions will be returned. // (2) Some solvers may run heuristics using solutions from the solution // pool, so changing this value may affect the algorithm's path. // To force the solver to fill the solution pool, e.g. with the n best // solutions, requires further, solver specific configuration. std::optional solution_pool_size; // The algorithm for solving a linear program. If nullopt, use the solver // default algorithm. // // For problems that are not linear programs but where linear programming is // a subroutine, solvers may use this value. E.g. MIP solvers will typically // use this for the root LP solve only (and use dual simplex otherwise). std::optional lp_algorithm; // Effort on simplifying the problem before starting the main algorithm, or // the solver default effort level if unset. std::optional presolve; // Effort on getting a stronger LP relaxation (MIP only) or the solver default // effort level if unset. // // NOTE: disabling cuts may prevent callbacks from having a chance to add cuts // at MIP_NODE, this behavior is solver specific. std::optional cuts; // Effort in finding feasible solutions beyond those encountered in the // complete search procedure (MIP only), or the solver default effort level if // unset. std::optional heuristics; // Effort in rescaling the problem to improve numerical stability, or the // solver default effort level if unset. std::optional scaling; GScipParameters gscip; GurobiParameters gurobi; glop::GlopParameters glop; sat::SatParameters cp_sat; pdlp::PrimalDualHybridGradientParams pdlp; GlpkParameters glpk; HighsOptionsProto highs; XpressParameters xpress; SolveParametersProto Proto() const; static absl::StatusOr FromProto( const SolveParametersProto& proto); }; bool AbslParseFlag(absl::string_view text, SolveParameters* solve_parameters, std::string* error); std::string AbslUnparseFlag(SolveParameters solve_parameters); } // namespace math_opt } // namespace operations_research #endif // ORTOOLS_MATH_OPT_CPP_PARAMETERS_H_