14#ifndef OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
15#define OR_TOOLS_CONSTRAINT_SOLVER_ROUTING_LP_SCHEDULING_H_
28#include "absl/container/flat_hash_map.h"
29#include "absl/memory/memory.h"
30#include "absl/time/time.h"
34#include "ortools/constraint_solver/routing_parameters.pb.h"
36#include "ortools/glop/parameters.pb.h"
39#include "ortools/sat/cp_model.pb.h"
43#include "ortools/sat/sat_parameters.pb.h"
65 const std::function<int64_t(int64_t)>& next_accessor,
66 int64_t cumul_offset);
69 return propagated_bounds_[PositiveNode(
index)];
73 const int64_t negated_upper_bound = propagated_bounds_[NegativeNode(
index)];
76 : -negated_upper_bound;
89 static const int kNoParent;
90 static const int kParentToBePropagated;
94 int PositiveNode(
int index)
const {
return 2 *
index; }
95 int NegativeNode(
int index)
const {
return 2 *
index + 1; }
97 void AddNodeToQueue(
int node) {
98 if (!node_in_queue_[node]) {
99 bf_queue_.push_back(node);
100 node_in_queue_[node] =
true;
107 void AddArcs(
int first_index,
int second_index, int64_t offset);
109 bool InitializeArcsAndBounds(
110 const std::function<int64_t(int64_t)>& next_accessor,
111 int64_t cumul_offset);
113 bool UpdateCurrentLowerBoundOfNode(
int node, int64_t new_lb, int64_t offset);
115 bool DisassembleSubtree(
int source,
int target);
117 bool CleanupAndReturnFalse() {
119 for (
int node_to_cleanup : bf_queue_) {
120 node_in_queue_[node_to_cleanup] =
false;
126 const RoutingDimension& dimension_;
127 const int64_t num_nodes_;
132 std::vector<std::vector<ArcInfo>> outgoing_arcs_;
134 std::deque<int> bf_queue_;
135 std::vector<bool> node_in_queue_;
136 std::vector<int> tree_parent_node_of_;
140 std::vector<int64_t> propagated_bounds_;
143 std::vector<int> tmp_dfs_stack_;
146 std::vector<std::pair<int64_t, int64_t>>
147 visited_pickup_delivery_indices_for_pair_;
168 const std::vector<int64_t>& starts,
169 const std::vector<int64_t>& ends) = 0;
200 const std::vector<std::pair<int, double>>& variable_coeffs) {
203 for (
const auto& variable_coeff : variable_coeffs) {
213 const std::vector<std::pair<int, double>>& weighted_variables) {
218 const int under_lower_bound_ct =
233 const int within_bounds_ct =
236 return within_bounds;
243 : is_relaxation_(is_relaxation) {
248 linear_program_.
Clear();
250 allowed_intervals_.clear();
261 const int64_t kMaxValue = 1e10;
263 const double lp_max =
265 if (lp_min <= lp_max) {
274 const std::vector<int64_t>& ends)
override {
279 allowed_intervals_[
index] =
280 absl::make_unique<SortedDisjointIntervalList>(starts, ends);
299 for (glop::ColIndex i(0); i < linear_program_.
num_variables(); ++i) {
323 for (
int variable = 0; variable <
NumVariables(); variable++) {
335 absl::ToDoubleSeconds(duration_limit));
349 if (is_relaxation_) {
352 for (
const auto& allowed_interval : allowed_intervals_) {
353 const double value_double =
GetValue(allowed_interval.first);
354 const int64_t
value =
359 allowed_interval.second.get();
361 if (it == interval_list->
end() || value < it->
start) {
379 const bool is_relaxation_;
382 absl::flat_hash_map<int, std::unique_ptr<SortedDisjointIntervalList>>
389 parameters_.set_num_search_workers(1);
392 parameters_.set_cp_model_presolve(
true);
393 parameters_.set_max_presolve_iterations(0);
394 parameters_.set_catch_sigint_signal(
false);
395 parameters_.set_mip_max_bound(1e8);
396 parameters_.set_search_branching(sat::SatParameters::LP_SEARCH);
402 objective_coefficients_.clear();
405 const int index = model_.variables_size();
406 sat::IntegerVariableProto*
const variable = model_.add_variables();
407 variable->add_domain(0);
408 variable->add_domain(
static_cast<int64_t
>(parameters_.mip_max_bound()));
414 const int64_t capped_upper_bound =
415 std::min<int64_t>(
upper_bound, parameters_.mip_max_bound());
416 if (
lower_bound > capped_upper_bound)
return false;
417 sat::IntegerVariableProto*
const variable = model_.mutable_variables(
index);
419 variable->set_domain(1, capped_upper_bound);
423 const std::vector<int64_t>& ends)
override {
426 for (
int i = 0; i < starts.size(); ++i) {
432 model_.mutable_constraints(window_ct)->add_enforcement_literal(variable);
436 return model_.variables(
index).domain(0);
439 const auto& domain = model_.variables(
index).domain();
440 return domain[domain.size() - 1];
443 if (
index >= objective_coefficients_.size()) {
444 objective_coefficients_.resize(
index + 1, 0);
447 sat::FloatObjectiveProto*
const objective =
448 model_.mutable_floating_point_objective();
449 objective->add_vars(
index);
453 return (
index < objective_coefficients_.size())
454 ? objective_coefficients_[
index]
458 model_.mutable_floating_point_objective()->Clear();
462 sat::LinearConstraintProto*
const ct =
463 model_.add_constraints()->mutable_linear();
466 return model_.constraints_size() - 1;
469 sat::LinearConstraintProto*
const ct =
470 model_.mutable_constraints(ct_index)->mutable_linear();
473 ct->add_coeffs(integer_coefficient);
478 const sat::FloatObjectiveProto& fp_objective =
479 model_.floating_point_objective();
480 std::vector<std::pair<int, double>> terms;
481 for (
int i = 0; i < fp_objective.vars_size(); ++i) {
482 terms.push_back({fp_objective.vars(i), fp_objective.coeffs(i)});
487 fp_objective.maximize(), &model_, &logger);
489 const sat::CpObjectiveProto& objective = model_.objective();
490 int64_t activity = 0;
491 for (
int i = 0; i < objective.vars_size(); ++i) {
492 activity += response_.solution(objective.vars(i)) * objective.coeffs(i);
495 for (
int i = 0; i < objective.vars_size(); ++i) {
498 model_.clear_objective();
501 sat::LinearArgumentProto*
const ct =
502 model_.add_constraints()->mutable_lin_max();
503 ct->mutable_target()->add_vars(max_var);
504 ct->mutable_target()->add_coeffs(1);
505 for (
const int var : vars) {
506 sat::LinearExpressionProto*
const expr =
ct->add_exprs();
512 sat::LinearArgumentProto*
const ct =
513 model_.add_constraints()->mutable_int_prod();
514 ct->mutable_target()->add_vars(product_var);
515 ct->mutable_target()->add_coeffs(1);
516 for (
const int var : vars) {
517 sat::LinearExpressionProto* expr =
ct->add_exprs();
524 model_.mutable_constraints(
ct)->add_enforcement_literal(condition);
527 parameters_.set_max_time_in_seconds(absl::ToDoubleSeconds(duration_limit));
528 VLOG(2) << model_.DebugString();
529 if (hint_.vars_size() == model_.variables_size()) {
530 *model_.mutable_solution_hint() = hint_;
535 VLOG(2) << response_.DebugString();
536 if (response_.status() == sat::CpSolverStatus::OPTIMAL ||
537 (response_.status() == sat::CpSolverStatus::FEASIBLE &&
538 !model_.has_floating_point_objective())) {
540 for (
int i = 0; i < response_.solution_size(); ++i) {
542 hint_.add_values(response_.solution(i));
552 return response_.solution(
index);
557 sat::CpModelProto model_;
558 sat::CpSolverResponse response_;
559 sat::SatParameters parameters_;
560 std::vector<double> objective_coefficients_;
561 sat::PartialVariableAssignment hint_;
569 bool use_precedence_propagator);
576 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
578 std::vector<int64_t>* break_values, int64_t*
cost, int64_t* transit_cost,
579 bool clear_lp =
true);
582 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
583 const std::vector<RoutingModel::ResourceGroup::Resource>& resources,
584 const std::vector<int>& resource_indices,
bool optimize_vehicle_costs,
586 std::vector<int64_t>* costs_without_transits,
587 std::vector<std::vector<int64_t>>* cumul_values,
588 std::vector<std::vector<int64_t>>* break_values,
bool clear_lp =
true);
591 const std::function<int64_t(int64_t)>& next_accessor,
593 std::vector<int64_t>* break_values,
594 std::vector<std::vector<int>>* resource_indices_per_group, int64_t*
cost,
595 int64_t* transit_cost,
bool clear_lp =
true);
598 const std::function<int64_t(int64_t)>& next_accessor,
600 std::vector<int64_t>* break_values,
601 std::vector<std::vector<int>>* resource_indices_per_group);
604 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
607 std::vector<int64_t>* break_values);
622 bool ComputeRouteCumulBounds(
const std::vector<int64_t>& route,
623 const std::vector<int64_t>& fixed_transits,
624 int64_t cumul_offset);
630 bool SetRouteCumulConstraints(
631 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
632 int64_t cumul_offset,
bool optimize_costs,
634 int64_t* route_cost_offset);
643 bool SetGlobalConstraints(
644 const std::function<int64_t(int64_t)>& next_accessor,
645 int64_t cumul_offset,
bool optimize_costs,
648 void SetValuesFromLP(
const std::vector<int>& lp_variables, int64_t offset,
650 std::vector<int64_t>* lp_values)
const;
652 void SetResourceIndices(
654 std::vector<std::vector<int>>* resource_indices_per_group)
const;
665 std::unique_ptr<CumulBoundsPropagator> propagator_;
666 std::vector<int64_t> current_route_min_cumuls_;
667 std::vector<int64_t> current_route_max_cumuls_;
670 std::vector<int> current_route_cumul_variables_;
671 std::vector<int> index_to_cumul_variable_;
676 std::vector<int> current_route_break_variables_;
680 std::vector<int> all_break_variables_;
684 std::vector<int> vehicle_to_all_break_variables_offset_;
689 std::vector<std::vector<int>>
690 resource_group_to_resource_to_vehicle_assignment_variables_;
693 int min_start_cumul_;
694 std::vector<std::pair<int64_t, int64_t>>
695 visited_pickup_delivery_indices_for_pair_;
707 RoutingSearchParameters::SchedulingSolver solver_type);
714 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
715 int64_t* optimal_cost);
720 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
721 int64_t* optimal_cost_without_transits);
723 std::vector<DimensionSchedulingStatus>
725 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
726 const std::vector<RoutingModel::ResourceGroup::Resource>& resources,
727 const std::vector<int>& resource_indices,
bool optimize_vehicle_costs,
728 std::vector<int64_t>* optimal_costs_without_transits,
729 std::vector<std::vector<int64_t>>* optimal_cumuls,
730 std::vector<std::vector<int64_t>>* optimal_breaks);
738 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
739 std::vector<int64_t>* optimal_cumuls,
740 std::vector<int64_t>* optimal_breaks);
748 int vehicle,
const std::function<int64_t(int64_t)>& next_accessor,
750 std::vector<int64_t>* packed_cumuls, std::vector<int64_t>* packed_breaks);
757 std::vector<std::unique_ptr<RoutingLinearSolverWrapper>> solver_;
765 RoutingSearchParameters::SchedulingSolver solver_type);
772 const std::function<int64_t(int64_t)>& next_accessor,
773 int64_t* optimal_cost_without_transits);
780 const std::function<int64_t(int64_t)>& next_accessor,
781 std::vector<int64_t>* optimal_cumuls,
782 std::vector<int64_t>* optimal_breaks,
783 std::vector<std::vector<int>>* optimal_resource_indices_per_group);
789 const std::function<int64_t(int64_t)>& next_accessor,
790 std::vector<int64_t>* packed_cumuls, std::vector<int64_t>* packed_breaks,
791 std::vector<std::vector<int>>* resource_indices_per_group);
798 std::unique_ptr<RoutingLinearSolverWrapper> solver_;
818 const std::vector<std::vector<int64_t>>&
819 primary_vehicle_to_resource_assignment_costs,
820 const std::vector<std::vector<int64_t>>&
821 secondary_vehicle_to_resource_assignment_costs,
822 const std::function<
bool(
int)>& use_primary_for_vehicle,
823 std::vector<int>* resource_indices)
const;
834 int v,
const std::function<int64_t(int64_t)>& next_accessor,
835 bool optimize_vehicle_costs, std::vector<int64_t>* assignment_costs,
836 std::vector<std::vector<int64_t>>* cumul_values,
837 std::vector<std::vector<int64_t>>* break_values);
#define DCHECK_GE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK(condition)
#define CHECK_LE(val1, val2)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
const RoutingDimension & dimension() const
int64_t CumulMax(int index) const
bool PropagateCumulBounds(const std::function< int64_t(int64_t)> &next_accessor, int64_t cumul_offset)
int64_t CumulMin(int index) const
CumulBoundsPropagator(const RoutingDimension *dimension)
std::vector< DimensionSchedulingStatus > OptimizeSingleRouteWithResources(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RoutingModel::ResourceGroup::Resource > &resources, const std::vector< int > &resource_indices, bool optimize_vehicle_costs, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *costs_without_transits, std::vector< std::vector< int64_t > > *cumul_values, std::vector< std::vector< int64_t > > *break_values, bool clear_lp=true)
DimensionSchedulingStatus Optimize(const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, std::vector< std::vector< int > > *resource_indices_per_group, int64_t *cost, int64_t *transit_cost, bool clear_lp=true)
DimensionCumulOptimizerCore(const RoutingDimension *dimension, bool use_precedence_propagator)
const RoutingDimension * dimension() const
DimensionSchedulingStatus OptimizeAndPack(const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, std::vector< std::vector< int > > *resource_indices_per_group)
DimensionSchedulingStatus OptimizeSingleRoute(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values, int64_t *cost, int64_t *transit_cost, bool clear_lp=true)
DimensionSchedulingStatus OptimizeAndPackSingleRoute(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::ResourceGroup::Resource *resource, RoutingLinearSolverWrapper *solver, std::vector< int64_t > *cumul_values, std::vector< int64_t > *break_values)
GlobalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
DimensionSchedulingStatus ComputeCumuls(const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks, std::vector< std::vector< int > > *optimal_resource_indices_per_group)
DimensionSchedulingStatus ComputeCumulCostWithoutFixedTransits(const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
DimensionSchedulingStatus ComputePackedCumuls(const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks, std::vector< std::vector< int > > *resource_indices_per_group)
const RoutingDimension * dimension() const
DimensionSchedulingStatus ComputePackedRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const RoutingModel::ResourceGroup::Resource *resource, std::vector< int64_t > *packed_cumuls, std::vector< int64_t > *packed_breaks)
DimensionSchedulingStatus ComputeRouteCumulCost(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost)
DimensionSchedulingStatus ComputeRouteCumuls(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, std::vector< int64_t > *optimal_cumuls, std::vector< int64_t > *optimal_breaks)
DimensionSchedulingStatus ComputeRouteCumulCostWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, int64_t *optimal_cost_without_transits)
LocalDimensionCumulOptimizer(const RoutingDimension *dimension, RoutingSearchParameters::SchedulingSolver solver_type)
const RoutingDimension * dimension() const
std::vector< DimensionSchedulingStatus > ComputeRouteCumulCostsForResourcesWithoutFixedTransits(int vehicle, const std::function< int64_t(int64_t)> &next_accessor, const std::vector< RoutingModel::ResourceGroup::Resource > &resources, const std::vector< int > &resource_indices, bool optimize_vehicle_costs, std::vector< int64_t > *optimal_costs_without_transits, std::vector< std::vector< int64_t > > *optimal_cumuls, std::vector< std::vector< int64_t > > *optimal_breaks)
static int64_t FastInt64Round(double x)
ResourceAssignmentOptimizer(const RoutingModel::ResourceGroup *resource_group, LocalDimensionCumulOptimizer *optimizer, LocalDimensionCumulOptimizer *mp_optimizer)
const RoutingDimension *const dimension() const
bool ComputeAssignmentCostsForVehicle(int v, const std::function< int64_t(int64_t)> &next_accessor, bool optimize_vehicle_costs, std::vector< int64_t > *assignment_costs, std::vector< std::vector< int64_t > > *cumul_values, std::vector< std::vector< int64_t > > *break_values)
int64_t ComputeBestAssignmentCost(const std::vector< std::vector< int64_t > > &primary_vehicle_to_resource_assignment_costs, const std::vector< std::vector< int64_t > > &secondary_vehicle_to_resource_assignment_costs, const std::function< bool(int)> &use_primary_for_vehicle, std::vector< int > *resource_indices) const
void SetCoefficient(int ct_index, int index, double coefficient) override
int NumVariables() const override
bool IsCPSATSolver() override
int CreateNewPositiveVariable() override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
double GetValue(int index) const override
int64_t GetObjectiveValue() const override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
~RoutingCPSatWrapper() override
void AddMaximumConstraint(int max_var, std::vector< int > vars) override
void AddProductConstraint(int product_var, std::vector< int > vars) override
void SetEnforcementLiteral(int ct, int condition) override
double GetObjectiveCoefficient(int index) const override
int64_t GetVariableUpperBound(int index) const override
void AddObjectiveConstraint() override
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
bool SolutionIsInteger() const override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
int64_t GetVariableLowerBound(int index) const override
void ClearObjective() override
Dimensions represent quantities accumulated at nodes along the routes.
int NumVariables() const override
bool IsCPSATSolver() override
RoutingGlopWrapper(bool is_relaxation, const glop::GlopParameters ¶meters)
int CreateNewPositiveVariable() override
bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound) override
double GetValue(int index) const override
int64_t GetObjectiveValue() const override
DimensionSchedulingStatus Solve(absl::Duration duration_limit) override
void SetCoefficient(int ct, int index, double coefficient) override
void AddMaximumConstraint(int max_var, std::vector< int > vars) override
void AddProductConstraint(int product_var, std::vector< int > vars) override
void SetEnforcementLiteral(int ct, int condition) override
double GetObjectiveCoefficient(int index) const override
int64_t GetVariableUpperBound(int index) const override
void AddObjectiveConstraint() override
void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends) override
bool SolutionIsInteger() const override
int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound) override
void SetObjectiveCoefficient(int index, double coefficient) override
int64_t GetVariableLowerBound(int index) const override
void ClearObjective() override
virtual void SetCoefficient(int ct, int index, double coefficient)=0
virtual int NumVariables() const =0
int AddReifiedLinearConstraint(int64_t lower_bound, int64_t upper_bound, const std::vector< std::pair< int, double > > &weighted_variables)
virtual double GetObjectiveCoefficient(int index) const =0
virtual void AddProductConstraint(int product_var, std::vector< int > vars)=0
virtual int CreateNewPositiveVariable()=0
int AddVariable(int64_t lower_bound, int64_t upper_bound)
virtual bool IsCPSATSolver()=0
virtual int64_t GetObjectiveValue() const =0
virtual void AddObjectiveConstraint()=0
virtual void ClearObjective()=0
virtual int CreateNewConstraint(int64_t lower_bound, int64_t upper_bound)=0
int AddLinearConstraint(int64_t lower_bound, int64_t upper_bound, const std::vector< std::pair< int, double > > &variable_coeffs)
virtual double GetValue(int index) const =0
virtual DimensionSchedulingStatus Solve(absl::Duration duration_limit)=0
virtual void SetVariableDisjointBounds(int index, const std::vector< int64_t > &starts, const std::vector< int64_t > &ends)=0
virtual bool SetVariableBounds(int index, int64_t lower_bound, int64_t upper_bound)=0
virtual void SetObjectiveCoefficient(int index, double coefficient)=0
virtual void SetEnforcementLiteral(int ct, int condition)=0
virtual int64_t GetVariableUpperBound(int index) const =0
virtual bool SolutionIsInteger() const =0
virtual ~RoutingLinearSolverWrapper()
virtual int64_t GetVariableLowerBound(int index) const =0
virtual void AddMaximumConstraint(int max_var, std::vector< int > vars)=0
A Resource sets attributes (costs/constraints) for a set of dimensions.
A ResourceGroup defines a set of available Resources with attributes on one or multiple dimensions.
This class represents a sorted list of disjoint, closed intervals.
ConstIterator end() const
Iterator FirstIntervalGreaterOrEqual(int64_t value) const
Returns an iterator to either:
GlopParameters * GetMutableParameters()
Fractional GetObjectiveValue() const
const DenseRow & variable_values() const
ABSL_MUST_USE_RESULT ProblemStatus Solve(const LinearProgram &lp)
void SetParameters(const GlopParameters ¶meters)
void SetVariableBounds(ColIndex col, Fractional lower_bound, Fractional upper_bound)
void SetCoefficient(RowIndex row, ColIndex col, Fractional value)
void SetConstraintBounds(RowIndex row, Fractional lower_bound, Fractional upper_bound)
ColIndex CreateNewVariable()
const DenseRow & variable_upper_bounds() const
bool SolutionIsInteger(const DenseRow &solution, Fractional absolute_tolerance) const
const DenseRow & objective_coefficients() const
void NotifyThatColumnsAreClean()
void SetObjectiveCoefficient(ColIndex col, Fractional value)
ColIndex num_variables() const
RowIndex CreateNewConstraint()
const DenseRow & variable_lower_bounds() const
void SetMaximizationProblem(bool maximize)
Class that owns everything related to a particular optimization model.
bool ScaleAndSetObjective(const SatParameters ¶ms, const std::vector< std::pair< int, double > > &objective, double objective_offset, bool maximize, CpModelProto *cp_model, SolverLogger *logger)
std::function< SatParameters(Model *)> NewSatParameters(const std::string ¶ms)
Creates parameters for the solver, which you can add to the model with.
CpSolverResponse SolveCpModel(const CpModelProto &model_proto, Model *model)
Solves the given CpModelProto.
Collection of objects used to extend the Constraint Solver library.
DimensionSchedulingStatus