// 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. // Linear Programming Protocol Buffers. // // The protocol buffers below make it possible to store and transfer the // representation of Linear and Mixed-Integer Programs. // // A Linear Program (LP) is a mathematical optimization model with a linear // objective function, and linear equality and inequality constraints. // The goal is to achieve the best outcome (such as maximum profit or lowest // cost) by modeling the real-world problem at hand using linear functions. // In a Mixed Integer Program (MIP), some variables may also be constrained to // take integer values. // // Check ./linear_solver.h and Wikipedia for more detail: // http://en.wikipedia.org/wiki/Linear_programming syntax = "proto2"; option java_package = "com.google.ortools.linearsolver"; option java_multiple_files = true; import "ortools/util/optional_boolean.proto"; package operations_research; // A variable is always constrained in the form: // lower_bound <= x <= upper_bound // where lower_bound and upper_bound: // - Can form a singleton: x = constant = lower_bound = upper_bound. // - Can form a finite interval: lower_bound <= x <= upper_bound. (x is boxed.) // - Can form a semi-infinite interval. // - lower_bound = -infinity: x <= upper_bound. // - upper_bound = +infinity: x >= lower_bound. // - Can form the infinite interval: lower_bound = -infinity and // upper_bound = +infinity, x is free. // MPVariableProto furthermore stores: // - The coefficient of the variable in the objective. // - Whether the variable is integer. message MPVariableProto { // lower_bound must be <= upper_bound. optional double lower_bound = 1 [default = -inf]; optional double upper_bound = 2 [default = inf]; // The coefficient of the variable in the objective. Must be finite. optional double objective_coefficient = 3 [default = 0.0]; // True if the variable is constrained to be integer. // Ignored if MPModelProto::solver_type is *LINEAR_PROGRAMMING*. optional bool is_integer = 4 [default = false]; // The name of the variable. optional string name = 5 [default = ""]; optional int32 branching_priority = 6 [default = 0]; } // A linear constraint is always of the form: // lower_bound <= sum of linear term elements <= upper_bound, // where lower_bound and upper_bound: // - Can form a singleton: lower_bound == upper_bound. The constraint is an // equation. // - Can form a finite interval [lower_bound, upper_bound]. The constraint is // both lower- and upper-bounded, i.e. "boxed". // - Can form a semi-infinite interval. lower_bound = -infinity: the constraint // is upper-bounded. upper_bound = +infinity: the constraint is lower-bounded. // - Can form the infinite interval: lower_bound = -infinity and // upper_bound = +infinity. The constraint is free. message MPConstraintProto { // var_index[i] is the variable index (w.r.t. to "variable" field of // MPModelProto) of the i-th linear term involved in this constraint, and // coefficient[i] is its coefficient. Only the terms with non-zero // coefficients need to appear. var_index may not contain duplicates. repeated int32 var_index = 6 [packed = true]; repeated double coefficient = 7 [packed = true]; // Must be finite. // lower_bound must be <= upper_bound. optional double lower_bound = 2 [default = -inf]; optional double upper_bound = 3 [default = inf]; // The name of the constraint. optional string name = 4 [default = ""]; // [Advanced usage: do not use this if you don't know what you're doing.] // A lazy constraint is handled differently by the core solving engine, but // it does not change the result. It may or may not impact the performance. // For more info see: http://tinyurl.com/lazy-constraints. optional bool is_lazy = 5 [default = false]; } // General constraints. See each individual proto type for more information. message MPGeneralConstraintProto { // The name of the constraint. optional string name = 1 [default = ""]; oneof general_constraint { MPIndicatorConstraint indicator_constraint = 2; MPSosConstraint sos_constraint = 3; MPQuadraticConstraint quadratic_constraint = 4; MPAbsConstraint abs_constraint = 5; // All variables in "and" constraints must be Boolean. // resultant_var = and(var_1, var_2... var_n) MPArrayConstraint and_constraint = 6; // All variables in "or" constraints must be Boolean. // resultant_var = or(var_1, var_2... var_n) MPArrayConstraint or_constraint = 7; // resultant_var = min(var_1, var_2, ..., constant) MPArrayWithConstantConstraint min_constraint = 8; // resultant_var = max(var_1, var_2, ..., constant) MPArrayWithConstantConstraint max_constraint = 9; } } // Indicator constraints encode the activation or deactivation of linear // constraints given the value of one Boolean variable in the model. For // example: // y = 0 => 2 * x1 + 3 * x2 >= 42 // The 2 * x1 + 3 * x2 >= 42 constraint is only active if the variable y is // equal to 0. // As of 2019/04, only SCIP, CP-SAT and Gurobi support this constraint type. message MPIndicatorConstraint { // Variable index (w.r.t. the "variable" field of MPModelProto) of the Boolean // variable used as indicator. optional int32 var_index = 1; // Value the above variable should take. Must be 0 or 1. optional int32 var_value = 2; // The constraint activated by the indicator variable. optional MPConstraintProto constraint = 3; } // Special Ordered Set (SOS) constraints of type 1 or 2. // See https://en.wikipedia.org/wiki/Special_ordered_set // As of 2019/04, only SCIP and Gurobi support this constraint type. message MPSosConstraint { enum Type { // At most one variable in `var_index` must be non-zero. SOS1_DEFAULT = 0; // At most two consecutive variables from `var_index` can be non-zero (i.e. // for some i, var_index[i] and var_index[i+1]). See // https://en.wikipedia.org/wiki/Special_ordered_set#Types_of_SOS SOS2 = 1; } optional Type type = 1 [default = SOS1_DEFAULT]; // Variable index (w.r.t. the "variable" field of MPModelProto) of the // variables in the SOS. repeated int32 var_index = 2; // Optional: SOS weights. If non-empty, must be of the same size as // "var_index", and strictly increasing. If empty and required by the // underlying solver, the 1..n sequence will be given as weights. // SUBTLE: The weights can help the solver make branch-and-bound decisions // that fit the underlying optimization model: after each LP relaxation, it // will compute the "average weight" of the SOS variables, weighted by value // (this is confusing: here we're using the values as weights), and the binary // branch decision will be: is the non-zero variable above or below that? // (weights are strictly monotonous, so the "cutoff" average weight // corresponds to a "cutoff" index in the var_index sequence). repeated double weight = 3; } // Quadratic constraints of the form lb <= sum a_i x_i + sum b_ij x_i x_j <= ub, // where a, b, lb and ub are constants, and x are the model's variables. // Quadratic matrices that are Positive Semi-Definite, Second-Order Cones or // rotated Second-Order Cones are always accepted. Other forms may or may not be // accepted depending on the underlying solver used. // See https://scip.zib.de/doc/html/cons__quadratic_8h.php and // https://www.gurobi.com/documentation/9.0/refman/constraints.html#subsubsection:QuadraticConstraints message MPQuadraticConstraint { // Sparse representation of linear terms in the quadratic constraint, where // term i is var_index[i] * coefficient[i]. // `var_index` are variable indices w.r.t the "variable" field in // MPModelProto, and should be unique. repeated int32 var_index = 1; repeated double coefficient = 2; // Must be finite. // Sparse representation of quadratic terms in the quadratic constraint, where // term i is qvar1_index[i] * qvar2_index[i] * qcoefficient[i]. // `qvar1_index` and `qvar2_index` are variable indices w.r.t the "variable" // field in MPModelProto. // `qvar1_index`, `qvar2_index` and `coefficients` must have the same size. // If the same unordered pair (qvar1_index, qvar2_index) appears several // times, the sum of all of the associated coefficients will be applied. repeated int32 qvar1_index = 3; repeated int32 qvar2_index = 4; repeated double qcoefficient = 5; // Must be finite. // lower_bound must be <= upper_bound. optional double lower_bound = 6 [default = -inf]; optional double upper_bound = 7 [default = inf]; } // Sets a variable's value to the absolute value of another variable. message MPAbsConstraint { // Variable indices are relative to the "variable" field in MPModelProto. // resultant_var = abs(var) optional int32 var_index = 1; optional int32 resultant_var_index = 2; } // Sets a variable's value equal to a function on a set of variables. message MPArrayConstraint { // Variable indices are relative to the "variable" field in MPModelProto. repeated int32 var_index = 1; optional int32 resultant_var_index = 2; } // Sets a variable's value equal to a function on a set of variables and, // optionally, a constant. message MPArrayWithConstantConstraint { // Variable indices are relative to the "variable" field in MPModelProto. // resultant_var = f(var_1, var_2, ..., constant) repeated int32 var_index = 1; optional double constant = 2; optional int32 resultant_var_index = 3; } // Quadratic part of a model's objective. Added with other objectives (such as // linear), this creates the model's objective function to be optimized. // Note: the linear part of the objective currently needs to be specified in the // MPVariableProto.objective_coefficient fields. If you'd rather have a // dedicated linear array here, talk to or-core-team@ message MPQuadraticObjective { // Sparse representation of quadratic terms in the objective function, where // term i is qvar1_index[i] * qvar2_index[i] * coefficient[i]. // `qvar1_index` and `qvar2_index` are variable indices w.r.t the "variable" // field in MPModelProto. // `qvar1_index`, `qvar2_index` and `coefficients` must have the same size. // If the same unordered pair (qvar1_index, qvar2_index) appears several // times, the sum of all of the associated coefficients will be applied. repeated int32 qvar1_index = 1; repeated int32 qvar2_index = 2; repeated double coefficient = 3; // Must be finite. } // This message encodes a partial (or full) assignment of the variables of a // MPModelProto problem. The indices in var_index should be unique and valid // variable indices of the associated problem. message PartialVariableAssignment { repeated int32 var_index = 1 [packed = true]; repeated double var_value = 2 [packed = true]; } // MPModelProto contains all the information for a Linear Programming model. message MPModelProto { // All the variables appearing in the model. repeated MPVariableProto variable = 3; // All the constraints appearing in the model. repeated MPConstraintProto constraint = 4; // All the general constraints appearing in the model. Note that not all // solvers support all types of general constraints. repeated MPGeneralConstraintProto general_constraint = 7; // True if the problem is a maximization problem. Minimize by default. optional bool maximize = 1 [default = false]; // Offset for the objective function. Must be finite. optional double objective_offset = 2 [default = 0.0]; // Optionally, a quadratic objective. // As of 2019/06, only SCIP and Gurobi support quadratic objectives. optional MPQuadraticObjective quadratic_objective = 8; // Name of the model. optional string name = 5 [default = ""]; // Solution hint. // // If a feasible or almost-feasible solution to the problem is already known, // it may be helpful to pass it to the solver so that it can be used. A solver // that supports this feature will try to use this information to create its // initial feasible solution. // // Note that it may not always be faster to give a hint like this to the // solver. There is also no guarantee that the solver will use this hint or // try to return a solution "close" to this assignment in case of multiple // optimal solutions. optional PartialVariableAssignment solution_hint = 6; // Annotations can be freely added by users who want to attach arbitrary // payload to the model's variables or constraints. message Annotation { // The target of an Annotation is a single entity (e.g. a variable). // Several Annotations may apply to the same entity. enum TargetType { VARIABLE_DEFAULT = 0; CONSTRAINT = 1; GENERAL_CONSTRAINT = 2; } optional TargetType target_type = 1; // If both `target_index` and `target_name` are set, they must point to the // same entity. optional int32 target_index = 2; // Index in the MPModelProto. optional string target_name = 3; // Alternate to index. Assumes uniqueness. // The payload is a (key, value) string pair. Depending on the use cases, // one of the two may be omitted. optional string payload_key = 4; optional string payload_value = 5; } repeated Annotation annotation = 9; } // To support 'unspecified' double value in proto3, the simplest is to wrap // any double value in a nested message (has_XXX works for message fields). message OptionalDouble { optional double value = 1; } // MPSolverCommonParameters holds advanced usage parameters that apply to any of // the solvers we support. // All of the fields in this proto can have a value of unspecified. In this // case each inner solver will use their own safe defaults. // Some values won't be supported by some solvers. The behavior in that case is // not defined yet. message MPSolverCommonParameters { // The solver stops if the relative MIP gap reaches this value or below. // The relative MIP gap is an upper bound of the relative distance to the // optimum, and it is defined as: // // abs(best_bound - incumbent) / abs(incumbent) [Gurobi] // abs(best_bound - incumbent) / min(abs(best_bound), abs(incumbent)) [SCIP] // // where "incumbent" is the objective value of the best solution found so far // (i.e., lowest when minimizing, highest when maximizing), and "best_bound" // is the tightest bound of the objective determined so far (i.e., highest // when minimizing, and lowest when maximizing). The MIP Gap is sensitive to // objective offset. If the denominator is 0 the MIP Gap is INFINITY for SCIP // and Gurobi. Of note, "incumbent" and "best bound" are called "primal bound" // and "dual bound" in SCIP, respectively. // Ask or-core-team@ for other solvers. optional OptionalDouble relative_mip_gap = 1; // Tolerance for primal feasibility of basic solutions: this is the maximum // allowed error in constraint satisfiability. // For SCIP this includes integrality constraints. For Gurobi it does not, you // need to set the custom parameter IntFeasTol. optional OptionalDouble primal_tolerance = 2; // Tolerance for dual feasibility. // For SCIP and Gurobi this is the feasibility tolerance for reduced costs in // LP solution: reduced costs must all be smaller than this value in the // improving direction in order for a model to be declared optimal. // Not supported for other solvers. optional OptionalDouble dual_tolerance = 3; enum LPAlgorithmValues { LP_ALGO_UNSPECIFIED = 0; LP_ALGO_DUAL = 1; // Dual simplex. LP_ALGO_PRIMAL = 2; // Primal simplex. LP_ALGO_BARRIER = 3; // Barrier algorithm. } // Algorithm to solve linear programs. // Ask or-core-team@ if you want to know what this does exactly. optional LPAlgorithmValues lp_algorithm = 4 [default = LP_ALGO_UNSPECIFIED]; // Gurobi and SCIP enable presolve by default. // Ask or-core-team@ for other solvers. optional OptionalBoolean presolve = 5 [default = BOOL_UNSPECIFIED]; // Enable automatic scaling of matrix coefficients and objective. Available // for Gurobi and GLOP. // Ask or-core-team@ if you want more details. optional OptionalBoolean scaling = 7 [default = BOOL_UNSPECIFIED]; } // Encodes a full MPModelProto by way of referencing to a "baseline" // MPModelProto stored in a file, and a "delta" to apply to this model. message MPModelDeltaProto { optional /*required*/ string baseline_model_file_path = 1; // The variable protos listed here will override (via MergeFrom()) the ones // in the baseline model: you only need to specify the fields that change. // To add a new variable, add it with a new variable index (variable indices // still need to span a dense integer interval). // You can't "delete" a variable but you can "neutralize" it by fixing its // value, setting its objective coefficient to zero, and by nullifying all // the terms involving it in the constraints. map variable_overrides = 2; // Constraints can be changed (or added) in the same way as variables, see // above. It's mostly like applying MergeFrom(), except that: // - the "var_index" and "coefficient" fields will be overridden like a map: // if a key pre-exists, we overwrite its value, otherwise we add it. // - if you set the lower bound to -inf and the upper bound to +inf, thus // effectively neutralizing the constraint, the solver will implicitly // remove all of the constraint's terms. map constraint_overrides = 3; // NOTE(user): We may also add more deltas, eg. objective offset. } // Next id: 18. message MPModelRequest { // The model to be optimized by the server. optional MPModelProto model = 1; // The solver type, which will select a specific implementation, and will also // impact the interpretation of the model (i.e. are we solving the problem // as a mixed integer program or are we relaxing it as a continuous linear // program?). // This must remain consistent with MPSolver::OptimizationProblemType. enum SolverType { CLP_LINEAR_PROGRAMMING = 0; GLOP_LINEAR_PROGRAMMING = 2; // Recommended default for LP models. GLPK_LINEAR_PROGRAMMING = 1; GUROBI_LINEAR_PROGRAMMING = 6; // Commercial, needs a valid license. XPRESS_LINEAR_PROGRAMMING = 101; // Commercial, needs a valid license. NOLINT CPLEX_LINEAR_PROGRAMMING = 10; // Commercial, needs a valid license. NOLINT HIGHS_LINEAR_PROGRAMMING = 15; SCIP_MIXED_INTEGER_PROGRAMMING = 3; // Recommended default for MIP models. GLPK_MIXED_INTEGER_PROGRAMMING = 4; CBC_MIXED_INTEGER_PROGRAMMING = 5; GUROBI_MIXED_INTEGER_PROGRAMMING = 7; // Commercial, needs a valid license. XPRESS_MIXED_INTEGER_PROGRAMMING = 102; // Commercial, needs a valid license. NOLINT CPLEX_MIXED_INTEGER_PROGRAMMING = 11; // Commercial, needs a valid license. NOLINT HIGHS_MIXED_INTEGER_PROGRAMMING = 16; BOP_INTEGER_PROGRAMMING = 12; // WARNING: This solver will currently interpret all variables as integer, // so any solution you get will be valid, but the optimal might be far away // for the real one (when you authorise non-integer value for continuous // variables). SAT_INTEGER_PROGRAMMING = 14; // Recommended for pure integer problems. // In-house linear programming solver based on the primal-dual hybrid // gradient method. Sometimes faster than Glop for medium-size problems and // scales to much larger problems than Glop. PDLP_LINEAR_PROGRAMMING = 8; KNAPSACK_MIXED_INTEGER_PROGRAMMING = 13; } optional SolverType solver_type = 2 [default = GLOP_LINEAR_PROGRAMMING]; // Maximum time to be spent by the solver to solve 'model'. If the server is // busy and the RPC's deadline_left is less than this, it will immediately // give up and return an error, without even trying to solve. // // The client can use this to have a guarantee on how much time the // solver will spend on the problem (unless it finds and proves // an optimal solution more quickly). // // If not specified, the time limit on the solver is the RPC's deadline_left. optional double solver_time_limit_seconds = 3; // If this is set, then EnableOutput() will be set on the internal MPSolver // that solves the model. // WARNING: if you set this on a request to prod servers, it will be rejected // and yield the RPC Application Error code MPSOLVER_SOLVER_TYPE_UNAVAILABLE. optional bool enable_internal_solver_output = 4 [default = false]; // Advanced usage. Solver-specific parameters in the solver's own format, // different for each solver. For example, if you use SCIP and you want to // stop the solve earlier than the time limit if it reached a solution that is // at most 1% away from the optimal, you can set this to "limits/gap=0.01". // // Note however that there is no "security" mechanism in place so it is up to // the client to make sure that the given options don't make the solve // non thread safe or use up too much memory for instance. // // If the option format is not understood by the solver, the request will be // rejected and yield an RPC Application error with code // MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS, unless you have set // ignore_solver_specific_parameters_failure=true (in which case they are // simply ignored). optional string solver_specific_parameters = 5; optional bool ignore_solver_specific_parameters_failure = 9 [default = false]; // Advanced usage: model "delta". If used, "model" must be unset. See the // definition of MPModelDeltaProto. optional MPModelDeltaProto model_delta = 8; // Controls the recovery of additional solutions, if any, saved by the // underlying solver back in the MPSolutionResponse.additional_solutions. // The repeated field will be length // min(populate_addition_solutions_up_to, // #additional_solutions_available_in_underlying_solver) // These additional solutions may have a worse objective than the main // solution returned in the response. optional int32 populate_additional_solutions_up_to = 11 [default = 0]; reserved 12; } // Status returned by the solver. They follow a hierarchical nomenclature, to // allow us to add more enum values in the future. Clients should use // InCategory() to match these enums, with the following C++ pseudo-code: // // bool InCategory(MPSolverResponseStatus status, MPSolverResponseStatus cat) { // if (cat == MPSOLVER_OPTIMAL) return status == MPSOLVER_OPTIMAL; // while (status > cat) status >>= 4; // return status == cat; // } enum MPSolverResponseStatus { // Normal responses -- the model was valid, and the solver ran. // These statuses should be "somewhat" repeatable, modulo the fact that the // solver's time limit makes it undeterministic, and could change a FEASIBLE // model to an OPTIMAL and vice-versa (the others, except NOT_SOLVED, should // normally be deterministic). Also, the solver libraries can be buggy. // The solver found the proven optimal solution. This is what should be // returned in most cases. // // WARNING: for historical reason, the value is zero, which means that this // value can't have any subcategories. MPSOLVER_OPTIMAL = 0x0; // The solver had enough time to find some solution that satisfies all // constraints, but it did not prove optimality (which means it may or may // not have reached the optimal). // // This can happen for large LP models (Linear Programming), and is a frequent // response for time-limited MIPs (Mixed Integer Programming). In the MIP // case, the difference between the solution 'objective_value' and // 'best_objective_bound' fields of the MPSolutionResponse will give an // indication of how far this solution is from the optimal one. MPSOLVER_FEASIBLE = 0x1; // The model does not have any solution, according to the solver (which // "proved" it, with the caveat that numerical proofs aren't actual proofs), // or based on trivial considerations (eg. a variable whose lower bound is // strictly greater than its upper bound). MPSOLVER_INFEASIBLE = 0x2; // There exist solutions that make the magnitude of the objective value // as large as wanted (i.e. -infinity (resp. +infinity) for a minimization // (resp. maximization) problem. MPSOLVER_UNBOUNDED = 0x3; // An error (most probably numerical) occurred. // One likely cause for such errors is a large numerical range among variable // coefficients (eg. 1e-16, 1e20), in which case one should try to shrink it. MPSOLVER_ABNORMAL = 0x4; // The solver did not have a chance to diagnose the model in one of the // categories above. MPSOLVER_NOT_SOLVED = 0x6; // Like "NOT_SOLVED", but typically used by model validation functions // returning a "model status", to enhance readability of the client code. MPSOLVER_MODEL_IS_VALID = 0x61; // The solve was interrupted by the user, and the solver didn't have time to // return a proper status. MPSOLVER_CANCELLED_BY_USER = 0x62; // Special value: the solver status could not be properly translated and is // unknown. MPSOLVER_UNKNOWN_STATUS = 0x63; // Model errors. These are always deterministic and repeatable. // They should be accompanied with a string description of the error. MPSOLVER_MODEL_INVALID = 0x5; // Something is wrong with the fields "solution_hint_var_index" and/or // "solution_hint_var_value". MPSOLVER_MODEL_INVALID_SOLUTION_HINT = 0x54; // Something is wrong with the solver_specific_parameters request field. MPSOLVER_MODEL_INVALID_SOLVER_PARAMETERS = 0x55; // Implementation error: the requested solver implementation is not // available (see MPModelRequest.solver_type). // The linear solver binary was probably not linked with the required library, MPSOLVER_SOLVER_TYPE_UNAVAILABLE = 0x7; // Some of the selected options were incompatible, e.g. a cancellable solve // was requested via SolverClient::SolveMipRemotely() with an underlying // solver that doesn't support cancellation. status_str should contain a // description of the issue. MPSOLVER_INCOMPATIBLE_OPTIONS = 0x71; } message MPSolution { optional double objective_value = 1; repeated double variable_value = 2 [packed = true]; } message MPSolveInfo { // How much wall time (resp. user time) elapsed during the Solve() of the // underlying solver library. "wall" time and "user" time are to be // interpreted like for the "time" command in bash (see "help time"). // In particular, "user time" is CPU time and can be greater than wall time // when using several threads. optional double solve_wall_time_seconds = 1; optional double solve_user_time_seconds = 2; } // Next id: 12. message MPSolutionResponse { // Result of the optimization. optional /*required*/ MPSolverResponseStatus status = 1 [default = MPSOLVER_UNKNOWN_STATUS]; // Human-readable string giving more details about the status. For example, // when the status is MPSOLVER_INVALID_MODE, this can hold a description of // why the model is invalid. // This isn't always filled: don't depend on its value or even its presence. optional string status_str = 7; // Objective value corresponding to the "variable_value" below, taking into // account the source "objective_offset" and "objective_coefficient". // This is set iff 'status' is OPTIMAL or FEASIBLE. optional double objective_value = 2; // This field is only filled for MIP problems. For a minimization problem, // this is a lower bound on the optimal objective value. For a maximization // problem, it is an upper bound. It is only filled if the status is OPTIMAL // or FEASIBLE. In the former case, best_objective_bound should be equal to // objective_value (modulo numerical errors). optional double best_objective_bound = 5; // Variable values in the same order as the MPModelProto::variable field. // This is a dense representation. These are set iff 'status' is OPTIMAL or // FEASIBLE. repeated double variable_value = 3 [packed = true]; // Contains extra information about the solve, populated if the underlying // solver (and its interface) supports it. As of 2021/07/19 this is supported // by SCIP and Gurobi proto solves. optional MPSolveInfo solve_info = 10; // Opaque solver-specific information. // For the PDLP solver, this is a serialized pdlp::SolveLog proto. optional bytes solver_specific_info = 11; // [Advanced usage.] // Values of the dual variables values in the same order as the // MPModelProto::constraint field. This is a dense representation. // These are not set if the problem was solved with a MIP solver (even if // it is actually a linear program). // These are set iff 'status' is OPTIMAL or FEASIBLE. repeated double dual_value = 4 [packed = true]; // [Advanced usage.] // Values of the reduced cost of the variables in the same order as the // MPModelProto::variable. This is a dense representation. // These are not set if the problem was solved with a MIP solver (even if it // is actually a linear program). // These are set iff 'status' is OPTIMAL or FEASIBLE. repeated double reduced_cost = 6 [packed = true]; // [Advanced usage.] // If `MPModelRequest.populate_additional_solutions_up_to` > 0, up to that // number of additional solutions may be populated here, if available. These // additional solutions are different than the main solution described by the // above fields `objective_value` and `variable_value`. repeated MPSolution additional_solutions = 8; reserved 9; }