Files
ortools-clone/ortools/math_opt/callback.proto
2025-11-24 13:56:15 +01:00

229 lines
9.6 KiB
Protocol Buffer

// 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.
// Solver-Callback handling protos:
// Callback functions allow for a fine-grain control, and ongoing interaction
// with the solver during the solve process. The overall architecture is that
// upon solve invocation the user will select what type of interactions to have
// with the solver, and whenever the solver offers an interaction enabled by the
// user, return the statistics collected up to that point, and any additional
// information required by the user. Once done, the callback function must
// return a message to the solver to continue with the solve process.
syntax = "proto3";
package operations_research.math_opt;
import "google/protobuf/duration.proto";
import "ortools/math_opt/sparse_containers.proto";
option java_package = "com.google.ortools.mathopt";
option java_multiple_files = true;
// The supported events during a solve for callbacks.
enum CallbackEventProto {
CALLBACK_EVENT_UNSPECIFIED = 0;
// The solver is currently running presolve.
//
// This event is supported by SOLVER_TYPE_GUROBI only.
CALLBACK_EVENT_PRESOLVE = 1;
// The solver is currently running the simplex method.
//
// This event is supported by SOLVER_TYPE_GUROBI only.
CALLBACK_EVENT_SIMPLEX = 2;
// The solver is in the MIP loop (called periodically before starting a new
// node). Useful for early termination. Note that this event does not provide
// information on LP relaxations nor about new incumbent solutions.
//
// This event is fully supported for MIP models by SOLVER_TYPE_GUROBI only. If
// used with SOLVER_TYPE_CP_SAT, it is called when the dual bound is improved.
CALLBACK_EVENT_MIP = 3;
// Called every time a new MIP incumbent is found.
//
// This event is fully supported for MIP models by SOLVER_TYPE_GUROBI.
// SOLVER_TYPE_CP_SAT has partial support: you can view the solutions and
// request termination, but you cannot add lazy constraints. Other solvers
// don't support this event.
CALLBACK_EVENT_MIP_SOLUTION = 4;
// Called inside a MIP node. Note that there is no guarantee that the
// callback function will be called on every node. That behavior is
// solver-dependent.
//
// Disabling cuts using SolveParametersProto may interfere with this event
// being called and/or adding cuts at this event, the behavior is solver
// specific.
//
// This event is supported for MIP models by SOLVER_TYPE_GUROBI only.
CALLBACK_EVENT_MIP_NODE = 5;
// Called in each iterate of an interior point/barrier method.
//
// This event is supported for SOLVER_TYPE_GUROBI only.
CALLBACK_EVENT_BARRIER = 6;
}
// The callback function input data.
// Note that depending on the event, some information might be unavailable.
message CallbackDataProto {
CallbackEventProto event = 1;
// if event == CALLBACK_EVENT_MIP_NODE, the primal_solution_vector contains
// the variable values of the primal solution for the current LP-node
// relaxation. In some cases, no solution will be available (e.g. because
// LP was infeasible or the solve was imprecise).
// if event == CALLBACK_EVENT_MIP_SOLUTION, the primal_solution_vector
// contains variable values for the newly found primal (integer) feasible
// solution.
// Otherwise, the primal_solution_vector is not available.
//
// Note that, because of variable filters, it is possible that when a solution
// is found, it is empty. The message will be set but left empty in this case,
// while it will be unset when no solution is available.
SparseDoubleVectorProto primal_solution_vector = 2;
// Running time since the `Solve` call.
google.protobuf.Duration runtime = 3;
// Presolve stats. Only available during CALLBACK_EVENT_PRESOLVE.
message PresolveStats {
optional int64 removed_variables = 1;
optional int64 removed_constraints = 2;
optional int64 bound_changes = 3;
optional int64 coefficient_changes = 4;
}
PresolveStats presolve_stats = 4;
// Simplex stats. Only available during CALLBACK_EVENT_SIMPLEX.
message SimplexStats {
optional int64 iteration_count = 1;
optional double objective_value = 2;
optional double primal_infeasibility = 3;
optional double dual_infeasibility = 4;
optional bool is_pertubated = 5;
}
SimplexStats simplex_stats = 5;
// Barrier stats. Only available during CALLBACK_EVENT_BARRIER.
message BarrierStats {
optional int32 iteration_count = 1;
optional double primal_objective = 2;
optional double dual_objective = 3;
optional double complementarity = 4;
optional double primal_infeasibility = 5;
optional double dual_infeasibility = 6;
}
BarrierStats barrier_stats = 6;
// MIP B&B stats. Only available during CALLBACK_EVENT_MIPxxxx events.
// When using CP-SAT, only primal_bound, dual_bound and
// number_of_solutions_found are populated.
message MipStats {
optional double primal_bound = 1;
optional double dual_bound = 2;
optional int64 explored_nodes = 3;
optional int64 open_nodes = 4;
optional int64 simplex_iterations = 5;
optional int32 number_of_solutions_found = 6;
optional int32 cutting_planes_in_lp = 7;
}
MipStats mip_stats = 7;
}
// Return value of a callback function.
message CallbackResultProto {
message GeneratedLinearConstraint {
// This message encode linear constraints of the form
// lower_bound <= linear_expression <= upper_bound
SparseDoubleVectorProto linear_expression = 1;
double lower_bound = 2;
double upper_bound = 3;
// Two types of generated linear constraints are supported based on is_lazy:
// * The "lazy constraint" can remove integer points from the feasible
// region and can be added at event CALLBACK_EVENT_MIP_NODE or
// CALLBACK_EVENT_MIP_SOLUTION
// * The "user cut" (on is_lazy=false) strengthens the LP without removing
// integer points. It can only be added at CALLBACK_EVENT_MIP_NODE.
bool is_lazy = 4;
}
// When true it tells the solver to interrupt the solve as soon as possible.
//
// It can be set from any event. This is equivalent to using a
// SolveInterrupter and triggering it from the callback.
//
// Some solvers don't support interruption, in that case this is simply
// ignored and the solve terminates as usual. On top of that solvers may not
// immediately stop the solve. Thus the user should expect the callback to
// still be called after they set `terminate` to true in a previous
// call. Returning with `terminate` false after having previously returned
// true won't cancel the interruption.
bool terminate = 1;
// TODO(b/172214608): SCIP allows to reject a feasible solution without
// providing a cut. This is something we might support at a later stage.
// Dynamically generated linear constraints to add to the MIP. See
// GeneratedLinearConstraint::is_lazy for details.
repeated GeneratedLinearConstraint cuts = 4;
// Use only for CALLBACK_EVENT_MIP_NODE.
//
// Note that some solvers (e.g. Gurobi) support partially-defined solutions.
// The most common use case is to specify a value for each variable in the
// model. If a variable is not present in the primal solution, its value is
// taken to be undefined, and is up to the underlying solver to deal with it.
// For example, Gurobi will try to solve a Sub-MIP to get a fully feasible
// solution if necessary.
repeated SparseDoubleVectorProto suggested_solutions = 5;
}
// Provided with a callback at the start of a Solve() to inform the solver:
// * what information the callback needs,
// * how the callback might alter the solve process.
message CallbackRegistrationProto {
// The events the solver should invoke the callback at.
//
// When a solver is called with registered events that are not supported,
// an InvalidArgument is returned. The supported events may depend on the
// model. For example registering for CALLBACK_EVENT_MIP with a model that
// only contains continuous variables will fail for most solvers. See the
// documentation of each event to see their supported solvers/model types.
repeated CallbackEventProto request_registration = 1;
// If CALLBACK_EVENT_MIP_SOLUTION is in `request_registration`, then
// the returned primal_solution information will be filtered according to
// this rule.
SparseVectorFilterProto mip_solution_filter = 2;
// If CALLBCK_EVENT_MIP_NODE is in `request_registration`, then the
// returned primal_solution information will be filtered according to this
// rule.
SparseVectorFilterProto mip_node_filter = 3;
//////////////////////////////////////////////////////////////////////////////
// What might you do in your callback (typically some solver features need
// to be disabled before the solve starts to support these features).
//////////////////////////////////////////////////////////////////////////////
// Dynamically add linear constraints that strength the formulation but do not
// exclude integer points during CALLBACK_EVENT_MIP_NODE events.
bool add_cuts = 4;
// Dynamically add linear constraints that exclude integer points during
// CALLBACK_EVENT_MIP_NODE and/or CALLBACK_EVENT_MIP_SOLUTION events.
bool add_lazy_constraints = 5;
}