Files
ortools-clone/ortools/sat/cp_model.h
Corentin Le Molgat b4b226801b update include guards
2025-11-05 11:54:02 +01:00

1370 lines
46 KiB
C++

// 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.
/**
* \file
* This file implements a wrapper around the CP-SAT model proto.
*
* Here is a minimal example that shows how to create a model, solve it, and
* print out the solution.
* \code
CpModelBuilder cp_model;
const Domain all_animals(0, 20);
const IntVar rabbits = cp_model.NewIntVar(all_animals).WithName("rabbits");
const IntVar pheasants = cp_model.NewIntVar(all_animals).WithName("pheasants");
cp_model.AddEquality(rabbits + pheasants, 20);
cp_model.AddEquality(4 * rabbits + 2 * pheasants, 56);
const CpSolverResponse response = Solve(cp_model.Build());
if (response.status() == CpSolverStatus::OPTIMAL) {
LOG(INFO) << SolutionIntegerValue(response, rabbits)
<< " rabbits, and " << SolutionIntegerValue(response, pheasants)
<< " pheasants.";
}
\endcode
*/
#ifndef ORTOOLS_SAT_CP_MODEL_H_
#define ORTOOLS_SAT_CP_MODEL_H_
#include <cstdint>
#include <initializer_list>
#include <iosfwd>
#include <limits>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h" // IWYU pragma: export.
#include "ortools/sat/cp_model_utils.h"
#include "ortools/sat/model.h" // IWYU pragma: export.
#include "ortools/sat/sat_parameters.pb.h"
#include "ortools/util/sorted_interval_list.h"
namespace operations_research {
namespace sat {
class CpModelBuilder;
class IntVar;
class LinearExpr;
/**
* A Boolean variable.
*
* This class refer to an IntegerVariableProto with domain [0, 1] or to its
* logical negation (Not). This is called a Boolean Literal in other context.
*
* This can only be constructed via \c CpModelBuilder.NewBoolVar().
*/
class BoolVar {
public:
/// A default constructed BoolVar can be used to mean not defined yet.
/// However, it shouldn't be passed to any of the functions in this file.
/// Doing so will crash in debug mode and will result in an invalid model in
/// opt mode.
BoolVar() = default;
/// Sets the name of the variable.
/// Note that this will always set the "positive" version of this Boolean.
BoolVar WithName(absl::string_view name);
/// Returns the name of the variable.
std::string Name() const;
/// Returns the logical negation of the current Boolean variable.
BoolVar Not() const { return BoolVar(NegatedRef(index_), builder_); }
bool operator==(const BoolVar& other) const {
return other.builder_ == builder_ && other.index_ == index_;
}
bool operator!=(const BoolVar& other) const {
return other.builder_ != builder_ || other.index_ != index_;
}
BoolVar operator~() const { return Not(); }
std::string DebugString() const;
/**
* Returns the index of the variable in the model.
*
* Warning: If the variable is the negation of another variable v, its index
* is -v.index() - 1. So this can be negative.
*/
int index() const { return index_; }
private:
friend class CircuitConstraint;
friend class Constraint;
friend class CpModelBuilder;
friend class DoubleLinearExpr;
friend class IntVar;
friend class IntervalVar;
friend class MultipleCircuitConstraint;
friend class LinearExpr;
friend class ReservoirConstraint;
friend bool SolutionBooleanValue(const CpSolverResponse& r, BoolVar x);
BoolVar(int index, CpModelBuilder* builder);
CpModelBuilder* builder_ = nullptr;
int index_ = std::numeric_limits<int32_t>::min();
};
std::ostream& operator<<(std::ostream& os, const BoolVar& var);
/**
* A convenient wrapper so we can write Not(x) instead of x.Not() which is
* sometimes clearer.
*/
BoolVar Not(BoolVar x);
/**
* An integer variable.
*
* This class wraps an IntegerVariableProto.
* This can only be constructed via \c CpModelBuilder.NewIntVar().
*/
class IntVar {
public:
/// A default constructed IntVar can be used to mean not defined yet.
/// However, it shouldn't be passed to any of the functions in this file.
/// Doing so will crash in debug mode and will result in an invalid model in
/// opt mode.
IntVar() = default;
/// Cast BoolVar -> IntVar.
/// The IntVar will take the value 1 (when the bool is true) and 0 otherwise.
///
/// Warning: If you construct an IntVar from a negated BoolVar, this might
/// create a new variable in the model. Otherwise this just point to the same
/// underlying variable.
explicit IntVar(const BoolVar& var);
/// Cast IntVar -> BoolVar.
///
/// Warning: The domain of the var must be within {0,1}. If not, we crash
/// in debug mode, and in opt mode you will get an invalid model if you use
/// this BoolVar anywhere since it will not have a valid domain.
BoolVar ToBoolVar() const;
/// Sets the name of the variable.
IntVar WithName(absl::string_view name);
/// Returns the name of the variable (or the empty string if not set).
std::string Name() const;
bool operator==(const IntVar& other) const {
return other.builder_ == builder_ && other.index_ == index_;
}
bool operator!=(const IntVar& other) const {
return other.builder_ != builder_ || other.index_ != index_;
}
// Returns the domain of the variable.
// Note that we keep the fully qualified return type as compilation fails with
// gcc otherwise.
::operations_research::Domain Domain() const;
std::string DebugString() const;
/// Returns the index of the variable in the model. This will be non-negative.
int index() const { return index_; }
private:
friend class BoolVar;
friend class CpModelBuilder;
friend class CumulativeConstraint;
friend class DoubleLinearExpr;
friend class LinearExpr;
friend class IntervalVar;
friend class ReservoirConstraint;
friend int64_t SolutionIntegerValue(const CpSolverResponse& r,
const LinearExpr& expr);
IntVar(int index, CpModelBuilder* builder);
CpModelBuilder* builder_ = nullptr;
int index_ = std::numeric_limits<int32_t>::min();
};
std::ostream& operator<<(std::ostream& os, const IntVar& var);
/**
* A dedicated container for linear expressions.
*
* With the use of implicit constructors, it can accept integer values, Boolean
* and Integer variables. Note that Not(x) will be silently transformed into 1 -
* x when added to the linear expression. It also support operator overloads to
* construct the linear expression naturally.
*
* Furthermore, static methods allow to construct a linear expression from sums
* or scalar products.
*
* Usage:
* \code
CpModelBuilder cp_model;
IntVar x = model.NewIntVar({0, 10}).WithName("x");
IntVar y = model.NewIntVar({0, 10}).WithName("y");
BoolVar b = model.NewBoolVar().WithName("b");
BoolVar c = model.NewBoolVar().WithName("c");
LinearExpr e1(x); // Or e1 = x.
LinearExpr e2 = x + y + 5;
LinearExpr e3 = 2 * x - y;
LinearExpr e4 = b;
LinearExpr e5 = b.Not(); // 1 - b.
std::vector<BoolVar> bools = {b, Not(c)};
LinearExpr e6 = LinearExpr::Sum(bools); // b + 1 - c;
LinearExpr e7 = -3 * b + Not(c); // -3 * b + 1 - c;
\endcode
* This can be used implicitly in some of the CpModelBuilder methods.
* \code
cp_model.AddGreaterThan(x, 5);
cp_model.AddEquality(x, y + 5);
\endcode
*/
class LinearExpr {
public:
/// Creates an empty linear expression with value zero.
LinearExpr() = default;
// NOLINTBEGIN(google-explicit-constructor)
/// Constructs a linear expression from a Boolean variable.
/// It deals with logical negation correctly.
LinearExpr(BoolVar var);
/// Constructs a linear expression from an integer variable.
LinearExpr(IntVar var);
/// Constructs a constant linear expression.
LinearExpr(int64_t constant);
// NOLINTEND(google-explicit-constructor)
/// Constructs the sum of a list of variables.
static LinearExpr Sum(absl::Span<const IntVar> vars);
/// Constructs the sum of a list of Boolean variables.
static LinearExpr Sum(absl::Span<const BoolVar> vars);
/// Constructs the scalar product of variables and coefficients.
static LinearExpr WeightedSum(absl::Span<const IntVar> vars,
absl::Span<const int64_t> coeffs);
/// Constructs the scalar product of Boolean variables and coefficients.
static LinearExpr WeightedSum(absl::Span<const BoolVar> vars,
absl::Span<const int64_t> coeffs);
/// Constructs var * coefficient.
static LinearExpr Term(IntVar var, int64_t coefficient);
/// Constructs bool * coefficient.
static LinearExpr Term(BoolVar var, int64_t coefficient);
/// Constructs a linear expr from its proto representation.
static LinearExpr FromProto(const LinearExpressionProto& proto);
// Operators.
LinearExpr& operator+=(const LinearExpr& other);
LinearExpr& operator-=(const LinearExpr& other);
LinearExpr& operator*=(int64_t factor);
/// Returns the vector of variable indices.
const std::vector<int>& variables() const { return variables_; }
/// Returns the vector of coefficients.
const std::vector<int64_t>& coefficients() const { return coefficients_; }
/// Returns true if the expression has no variables.
bool IsConstant() const { return variables_.empty(); }
/// Returns the constant term.
int64_t constant() const { return constant_; }
/**
* Debug string. If the CpModelBuilder is passed, the string will include
* variable names and domains. Otherwise, you will get a shorter string with
* only variable indices.
*/
std::string DebugString(const CpModelProto* proto = nullptr) const;
private:
std::vector<int> variables_;
std::vector<int64_t> coefficients_;
int64_t constant_ = 0;
};
std::ostream& operator<<(std::ostream& os, const LinearExpr& e);
/**
* A dedicated container for linear expressions with double coefficients.
* This is currently only usable to define a floating point objective.
*
* Usage:
* \code
CpModelBuilder cp_model;
IntVar x = model.NewIntVar({0, 10}).WithName("x");
IntVar y = model.NewIntVar({0, 10}).WithName("y");
BoolVar b = model.NewBoolVar().WithName("b");
BoolVar c = model.NewBoolVar().WithName("c");
DoubleLinearExpr e1(x); // e1 = x.
// e2 = x + y + 5
DoubleLinearExpr e2 = DoubleLinearExpr::Sum({x, y}).AddConstant(5.0);
// e3 = 2 * x - y
DoubleLinearExpr e3 = DoubleLinearExpr::WeightedSum({x, y}, {2, -1});
DoubleLinearExpr e4(b); // e4 = b.
DoubleLinearExpr e5(b.Not()); // e5 = 1 - b.
// If passing a std::vector<BoolVar>, a specialized method must be called.
std::vector<BoolVar> bools = {b, Not(c)};
DoubleLinearExpr e6 = DoubleLinearExpr::Sum(bools); // e6 = b + 1 - c;
// e7 = -3.0 * b + 1.5 - 1.5 * c;
DoubleLinearExpr e7 = DoubleLinearExpr::WeightedSum(bools, {-3.0, 1.5});
\endcode
* This can be used in the objective definition.
* \code
// Minimize 3.4 * y + 5.2
cp_model.Minimize(DoubleLinearExpr::Term(y, 3.4).AddConstant(5.2));
\endcode
*/
class DoubleLinearExpr {
public:
DoubleLinearExpr();
/// Constructs a linear expression from a Boolean variable.
/// It deals with logical negation correctly.
explicit DoubleLinearExpr(BoolVar var);
/// Constructs a linear expression from an integer variable.
explicit DoubleLinearExpr(IntVar var);
/// Constructs a constant linear expression.
explicit DoubleLinearExpr(double constant);
/// Adds a constant value to the linear expression.
DoubleLinearExpr& operator+=(double value);
/// Adds a single integer variable to the linear expression.
DoubleLinearExpr& operator+=(IntVar var);
DoubleLinearExpr& operator+=(BoolVar var);
/// Adds another linear expression to the linear expression.
DoubleLinearExpr& operator+=(const DoubleLinearExpr& expr);
/// Adds a term (var * coeff) to the linear expression.
DoubleLinearExpr& AddTerm(IntVar var, double coeff);
DoubleLinearExpr& AddTerm(BoolVar var, double coeff);
/// Adds a linear expression to the double linear expression.
DoubleLinearExpr& AddExpression(const LinearExpr& exprs, double coeff = 1.0);
/// Adds a constant value to the linear expression.
DoubleLinearExpr& operator-=(double value);
/// Adds a single integer variable to the linear expression.
DoubleLinearExpr& operator-=(IntVar var);
/// Adds another linear expression to the linear expression.
DoubleLinearExpr& operator-=(const DoubleLinearExpr& expr);
/// Multiply the linear expression by a constant.
DoubleLinearExpr& operator*=(double coeff);
/// Constructs the sum of a list of variables.
static DoubleLinearExpr Sum(absl::Span<const IntVar> vars);
/// Constructs the sum of a list of Boolean variables.
static DoubleLinearExpr Sum(absl::Span<const BoolVar> vars);
/// Constructs the scalar product of variables and coefficients.
static DoubleLinearExpr WeightedSum(absl::Span<const IntVar> vars,
absl::Span<const double> coeffs);
/// Constructs the scalar product of Boolean variables and coefficients.
static DoubleLinearExpr WeightedSum(absl::Span<const BoolVar> vars,
absl::Span<const double> coeffs);
/// Returns the vector of variable indices.
const std::vector<int>& variables() const { return variables_; }
/// Returns the vector of coefficients.
const std::vector<double>& coefficients() const { return coefficients_; }
// Returns true if the expression has no variable.
bool IsConstant() const { return variables_.empty(); }
/// Returns the constant term.
double constant() const { return constant_; }
/// Debug string. See the documentation for LinearExpr::DebugString().
std::string DebugString(const CpModelProto* proto = nullptr) const;
private:
std::vector<int> variables_;
std::vector<double> coefficients_;
double constant_ = 0;
};
std::ostream& operator<<(std::ostream& os, const DoubleLinearExpr& e);
/**
* Represents a Interval variable.
*
* An interval variable is both a constraint and a variable. It is defined by
* three objects: start, size, and end. All three can be an integer variable, a
* constant, or an affine expression.
*
* It is a constraint because, internally, it enforces that start + size == end.
*
* It is also a variable as it can appear in specific scheduling constraints:
* NoOverlap, NoOverlap2D, Cumulative.
*
* Optionally, a presence literal can be added to this constraint. This presence
* literal is understood by the same constraints. These constraints ignore
* interval variables with precence literals assigned to false. Conversely,
* these constraints will also set these presence literals to false if they
* cannot fit these intervals into the schedule.
*
* It can only be constructed via \c CpModelBuilder.NewIntervalVar().
*/
class IntervalVar {
public:
/// A default constructed IntervalVar can be used to mean not defined yet.
/// However, it shouldn't be passed to any of the functions in this file.
/// Doing so will crash in debug mode and will result in an invalid model in
/// opt mode.
IntervalVar();
/// Sets the name of the variable.
IntervalVar WithName(absl::string_view name);
/// Returns the name of the interval (or the empty string if not set).
std::string Name() const;
/// Returns the start linear expression. Note that this rebuilds the
/// expression each time this method is called.
LinearExpr StartExpr() const;
/// Returns the size linear expression. Note that this rebuilds the
/// expression each time this method is called.
LinearExpr SizeExpr() const;
/// Returns the end linear expression. Note that this rebuilds the
/// expression each time this method is called.
LinearExpr EndExpr() const;
/**
* Returns a BoolVar indicating the presence of this interval.
*
* It returns \c CpModelBuilder.TrueVar() if the interval is not optional.
*/
BoolVar PresenceBoolVar() const;
/// Equality test with another interval variable.
bool operator==(const IntervalVar& other) const {
return other.builder_ == builder_ && other.index_ == index_;
}
/// Difference test with another interval variable.
bool operator!=(const IntervalVar& other) const {
return other.builder_ != builder_ || other.index_ != index_;
}
/// Returns a debug string.
std::string DebugString() const;
/// Returns the index of the interval constraint in the model.
int index() const { return index_; }
private:
friend class CpModelBuilder;
friend class CumulativeConstraint;
friend class NoOverlap2DConstraint;
friend std::ostream& operator<<(std::ostream& os, const IntervalVar& var);
IntervalVar(int index, CpModelBuilder* builder);
CpModelBuilder* builder_ = nullptr;
int index_ = std::numeric_limits<int32_t>::min();
};
std::ostream& operator<<(std::ostream& os, const IntervalVar& var);
// -- ABSL HASHING SUPPORT -----------------------------------------------------
template <typename H>
H AbslHashValue(H h, const IntVar& i) {
return H::combine(std::move(h), i.index());
}
template <typename H>
H AbslHashValue(H h, const IntervalVar& i) {
return H::combine(std::move(h), i.index());
}
/**
* A constraint.
*
* This class enables you to modify the constraint that was previously added to
* the model.
*
* The constraint must be built using the different \c CpModelBuilder::AddXXX
* methods.
*/
class Constraint {
public:
/**
* The constraint will be enforced iff all literals listed here are true.
*
* If this is empty, then the constraint will always be enforced. An enforced
* constraint must be satisfied, and an un-enforced one will simply be
* ignored.
*
* This is also called half-reification. To have an equivalence between a
* literal and a constraint (full reification), one must add both a constraint
* (controlled by a literal l) and its negation (controlled by the negation of
* l).
*
* [Important] currently, only a few constraints support enforcement:
* - bool_or, bool_and, linear: fully supported.
* - interval: only support a single enforcement literal.
* - other: no support (but can be added on a per-demand basis).
*/
Constraint OnlyEnforceIf(absl::Span<const BoolVar> literals);
/// See OnlyEnforceIf(absl::Span<const BoolVar> literals).
Constraint OnlyEnforceIf(BoolVar literal);
/// Sets the name of the constraint.
Constraint WithName(absl::string_view name);
/// Returns the name of the constraint (or the empty string if not set).
absl::string_view Name() const;
/// Returns the underlying protobuf object (useful for testing).
const ConstraintProto& Proto() const { return *proto_; }
/// Returns the mutable underlying protobuf object (useful for model edition).
ConstraintProto* MutableProto() const { return proto_; }
protected:
friend class CpModelBuilder;
explicit Constraint(ConstraintProto* proto);
ConstraintProto* proto_ = nullptr;
};
/**
* Specialized circuit constraint.
*
* This constraint allows adding arcs to the circuit constraint incrementally.
*/
class CircuitConstraint : public Constraint {
public:
/**
* Add an arc to the circuit.
*
* @param tail the index of the tail node.
* @param head the index of the head node.
* @param literal it will be set to true if the arc is selected.
*/
void AddArc(int tail, int head, BoolVar literal);
private:
friend class CpModelBuilder;
using Constraint::Constraint;
};
/**
* Specialized circuit constraint.
*
* This constraint allows adding arcs to the multiple circuit constraint
* incrementally.
*/
class MultipleCircuitConstraint : public Constraint {
public:
/**
* Add an arc to the circuit.
*
* @param tail the index of the tail node.
* @param head the index of the head node.
* @param literal it will be set to true if the arc is selected.
*/
void AddArc(int tail, int head, BoolVar literal);
private:
friend class CpModelBuilder;
using Constraint::Constraint;
};
/**
* Specialized assignment constraint.
*
* This constraint allows adding tuples to the allowed/forbidden assignment
* constraint incrementally.
*/
class TableConstraint : public Constraint {
public:
/// Adds a tuple of possible values to the constraint.
void AddTuple(absl::Span<const int64_t> tuple);
private:
friend class CpModelBuilder;
using Constraint::Constraint;
};
/**
* Specialized reservoir constraint.
*
* This constraint allows adding emptying/refilling events to the reservoir
* constraint incrementally.
*/
class ReservoirConstraint : public Constraint {
public:
/**
* Adds a mandatory event
*
* It will increase the used capacity by `level_change` at time `time`.
* `time` must be an affine expression.
*/
void AddEvent(LinearExpr time, int64_t level_change);
/**
* Adds an optional event
*
* If `is_active` is true, It will increase the used capacity by
* `level_change` at time `time. `time` must be an affine expression.
*/
void AddOptionalEvent(LinearExpr time, int64_t level_change,
BoolVar is_active);
private:
friend class CpModelBuilder;
ReservoirConstraint(ConstraintProto* proto, CpModelBuilder* builder);
CpModelBuilder* builder_;
};
/**
* Specialized automaton constraint.
*
* This constraint allows adding transitions to the automaton constraint
* incrementally.
*/
class AutomatonConstraint : public Constraint {
public:
/// Adds a transitions to the automaton.
void AddTransition(int tail, int head, int64_t transition_label);
private:
friend class CpModelBuilder;
using Constraint::Constraint;
};
/**
* Specialized no_overlap2D constraint.
*
* This constraint allows adding rectangles to the no_overlap2D
* constraint incrementally.
*/
class NoOverlap2DConstraint : public Constraint {
public:
/// Adds a rectangle (parallel to the axis) to the constraint.
void AddRectangle(IntervalVar x_coordinate, IntervalVar y_coordinate);
private:
friend class CpModelBuilder;
using Constraint::Constraint;
};
/**
* Specialized cumulative constraint.
*
* This constraint allows adding fixed or variables demands to the cumulative
* constraint incrementally.
*
* One cannot mix the AddDemand() and AddDemandWithEnergy() APIs in the same
* cumulative API. Either always supply energy info, or never.
*/
class CumulativeConstraint : public Constraint {
public:
/// Adds a pair (interval, demand) to the constraint.
void AddDemand(IntervalVar interval, LinearExpr demand);
private:
friend class CpModelBuilder;
CumulativeConstraint(ConstraintProto* proto, CpModelBuilder* builder);
CpModelBuilder* builder_;
};
/**
* Wrapper class around the cp_model proto.
*
* This class provides two types of methods:
* - NewXXX to create integer, boolean, or interval variables.
* - AddXXX to create new constraints and add them to the model.
*/
class CpModelBuilder {
public:
/// Sets the name of the model.
void SetName(absl::string_view name);
/// Creates an integer variable with the given domain.
IntVar NewIntVar(const Domain& domain);
/// Creates a Boolean variable.
BoolVar NewBoolVar();
/// Creates a constant variable. This is a shortcut for
/// NewVariable(Domain(value)).but it will return the same variable if used
/// twice with the same constant.
IntVar NewConstant(int64_t value);
/// Creates an always true Boolean variable.
/// If this is called multiple times, the same variable will always be
/// returned.
BoolVar TrueVar();
/// Creates an always false Boolean variable.
/// If this is called multiple times, the same variable will always be
/// returned.
BoolVar FalseVar();
/// Creates an interval variable from 3 affine expressions.
IntervalVar NewIntervalVar(const LinearExpr& start, const LinearExpr& size,
const LinearExpr& end);
/// Creates an interval variable with a fixed size.
IntervalVar NewFixedSizeIntervalVar(const LinearExpr& start, int64_t size);
/// Creates an optional interval variable from 3 affine expressions and a
/// Boolean variable.
IntervalVar NewOptionalIntervalVar(const LinearExpr& start,
const LinearExpr& size,
const LinearExpr& end, BoolVar presence);
/// Creates an optional interval variable with a fixed size.
IntervalVar NewOptionalFixedSizeIntervalVar(const LinearExpr& start,
int64_t size, BoolVar presence);
/// It is sometime convenient when building a model to create a bunch of
/// variables that will later be fixed. Instead of doing AddEquality(var,
/// value) which add a constraint, these functions modify directly the
/// underlying variable domain.
///
/// Note that this ignore completely the original variable domain and just fix
/// the given variable to the given value, even if it was outside the given
/// variable domain. You can still use AddEquality() if this is not what you
/// want.
void FixVariable(IntVar var, int64_t value);
void FixVariable(BoolVar var, bool value);
/// Adds the constraint that at least one of the literals must be true.
Constraint AddBoolOr(absl::Span<const BoolVar> literals);
/// Same as AddBoolOr(). Sum literals >= 1.
Constraint AddAtLeastOne(absl::Span<const BoolVar> literals);
/// At most one literal is true. Sum literals <= 1.
Constraint AddAtMostOne(absl::Span<const BoolVar> literals);
/// Exactly one literal is true. Sum literals == 1.
Constraint AddExactlyOne(absl::Span<const BoolVar> literals);
/// Adds the constraint that all literals must be true.
Constraint AddBoolAnd(absl::Span<const BoolVar> literals);
/// Adds the constraint that an odd number of literals is true.
Constraint AddBoolXor(absl::Span<const BoolVar> literals);
/// Adds a => b.
Constraint AddImplication(BoolVar a, BoolVar b) {
return AddBoolOr({a.Not(), b});
}
/// Adds implication: if all lhs vars are true then all rhs vars must be true.
Constraint AddImplication(absl::Span<const BoolVar> lhs,
absl::Span<const BoolVar> rhs) {
return AddBoolAnd(rhs).OnlyEnforceIf(lhs);
}
/// Adds left == right.
Constraint AddEquality(const LinearExpr& left, const LinearExpr& right);
/// Adds left >= right.
Constraint AddGreaterOrEqual(const LinearExpr& left, const LinearExpr& right);
/// Adds left > right.
Constraint AddGreaterThan(const LinearExpr& left, const LinearExpr& right);
/// Adds left <= right.
Constraint AddLessOrEqual(const LinearExpr& left, const LinearExpr& right);
/// Adds left < right.
Constraint AddLessThan(const LinearExpr& left, const LinearExpr& right);
/// Adds expr in domain.
Constraint AddLinearConstraint(const LinearExpr& expr, const Domain& domain);
/// Adds left != right.
Constraint AddNotEqual(const LinearExpr& left, const LinearExpr& right);
/// This constraint forces all variables to have different values.
Constraint AddAllDifferent(absl::Span<const IntVar> vars);
/// This constraint forces all expressions to have different values.
Constraint AddAllDifferent(absl::Span<const LinearExpr> exprs);
/// This constraint forces all expressions to have different values.
Constraint AddAllDifferent(std::initializer_list<LinearExpr> exprs);
/// Adds the element constraint: variables[index] == target
Constraint AddVariableElement(LinearExpr index,
absl::Span<const IntVar> variables,
LinearExpr target);
/// Adds the element constraint: expressions[index] == target.
Constraint AddElement(LinearExpr index,
absl::Span<const LinearExpr> expressions,
LinearExpr target);
/// Adds the element constraint: expressions[index] == target.
Constraint AddElement(LinearExpr index,
std::initializer_list<LinearExpr> expressions,
LinearExpr target);
/// Adds the element constraint: values[index] == target
Constraint AddElement(LinearExpr index, absl::Span<const int64_t> values,
LinearExpr target);
/**
* Adds a circuit constraint.
*
* The circuit constraint is defined on a graph where the arc presence is
* controlled by literals. That is the arc is part of the circuit of its
* corresponding literal is assigned to true.
*
* For now, we ignore node indices with no incident arc. All the other nodes
* must have exactly one incoming and one outgoing selected arc (i.e. literal
* at true). All the selected arcs that are not self-loops must form a single
* circuit.
*
* It returns a circuit constraint that allows adding arcs incrementally after
* construction.
*
*/
CircuitConstraint AddCircuitConstraint();
/**
* Adds a multiple circuit constraint, aka the "VRP" (Vehicle Routing Problem)
* constraint.
*
* The direct graph where arc #i (from tails[i] to head[i]) is present iff
* literals[i] is true must satisfy this set of properties:
* - #incoming arcs == 1 except for node 0.
* - #outgoing arcs == 1 except for node 0.
* - for node zero, #incoming arcs == #outgoing arcs.
* - There are no duplicate arcs.
* - Self-arcs are allowed except for node 0.
* - There is no cycle in this graph, except through node 0.
*/
MultipleCircuitConstraint AddMultipleCircuitConstraint();
/**
* Adds an allowed assignments constraint.
*
* An AllowedAssignments constraint is a constraint on an array of affine
* expressions (a * var + b) that forces, when all expressions are fixed to a
* single value, that the corresponding list of values is equal to one of the
* tuples added to the constraint.
*
* It returns a table constraint that allows adding tuples incrementally after
* construction.
*/
TableConstraint AddAllowedAssignments(
absl::Span<const LinearExpr> expressions);
/**
* Adds an allowed assignments constraint.
*/
TableConstraint AddAllowedAssignments(absl::Span<const IntVar> variables);
/**
* Adds an allowed assignments constraint.
*/
TableConstraint AddAllowedAssignments(
std::initializer_list<LinearExpr> expressions);
/**
* Adds an forbidden assignments constraint.
*
* A ForbiddenAssignments constraint is a constraint on an array of affine
* expressions (a * var + b) where the list of impossible combinations is
* provided in the tuples added to the constraint.
*
* It returns a table constraint that allows adding tuples incrementally after
* construction.
*/
TableConstraint AddForbiddenAssignments(
absl::Span<const LinearExpr> expression);
/**
* Adds an forbidden assignments constraint.
*/
TableConstraint AddForbiddenAssignments(absl::Span<const IntVar> variables);
/**
* Adds an forbidden assignments constraint.
*/
TableConstraint AddForbiddenAssignments(
std::initializer_list<LinearExpr> expressions);
/** An inverse constraint.
*
* It enforces that if 'variables[i]' is assigned a value
* 'j', then inverse_variables[j] is assigned a value 'i'. And vice versa.
*/
Constraint AddInverseConstraint(absl::Span<const IntVar> variables,
absl::Span<const IntVar> inverse_variables);
/**
* Adds a reservoir constraint with optional refill/emptying events.
*
* Maintain a reservoir level within bounds. The water level starts at 0, and
* at any time, it must be within [min_level, max_level].
*
* Given an event (time, level_change, active), if active is true, and if time
* is assigned a value t, then the level of the reservoir changes by
* level_change (which is constant) at time t. Therefore, at any time t:
*
* sum(level_changes[i] * actives[i] if times[i] <= t)
* in [min_level, max_level]
*
* Note that min level must be <= 0, and the max level must be >= 0.
* Please use fixed level_changes to simulate an initial state.
*
* It returns a ReservoirConstraint that allows adding optional and non
* optional events incrementally after construction.
*/
ReservoirConstraint AddReservoirConstraint(int64_t min_level,
int64_t max_level);
/**
* An automaton constraint.
*
* An automaton constraint takes a list of variables (of size n), an initial
* state, a set of final states, and a set of transitions. A transition is a
* triplet ('tail', 'head', 'label'), where 'tail' and 'head' are states,
* and 'label' is the label of an arc from 'head' to 'tail',
* corresponding to the value of one variable in the list of variables.
*
* This automaton will be unrolled into a flow with n + 1 phases. Each phase
* contains the possible states of the automaton. The first state contains the
* initial state. The last phase contains the final states.
*
* Between two consecutive phases i and i + 1, the automaton creates a set of
* arcs. For each transition (tail, head, label), it will add an arc from
* the state 'tail' of phase i and the state 'head' of phase i + 1. This arc
* labeled by the value 'label' of the variables 'variables[i]'. That is,
* this arc can only be selected if 'variables[i]' is assigned the value
* 'label'. A feasible solution of this constraint is an assignment of
* variables such that, starting from the initial state in phase 0, there is a
* path labeled by the values of the variables that ends in one of the final
* states in the final phase.
*
* It returns an AutomatonConstraint that allows adding transition
* incrementally after construction.
*/
AutomatonConstraint AddAutomaton(
absl::Span<const LinearExpr> transition_expressions, int starting_state,
absl::Span<const int> final_states);
/**
* An automaton constraint.
*/
AutomatonConstraint AddAutomaton(
absl::Span<const IntVar> transition_variables, int starting_state,
absl::Span<const int> final_states);
/**
* An automaton constraint.
*/
AutomatonConstraint AddAutomaton(
std::initializer_list<LinearExpr> transition_expressions,
int starting_state, absl::Span<const int> final_states);
/// Adds target == min(vars).
Constraint AddMinEquality(const LinearExpr& target,
absl::Span<const IntVar> vars);
/// Adds target == min(exprs).
Constraint AddMinEquality(const LinearExpr& target,
absl::Span<const LinearExpr> exprs);
/// Adds target == min(exprs).
Constraint AddMinEquality(const LinearExpr& target,
std::initializer_list<LinearExpr> exprs);
/// Adds target == max(vars).
Constraint AddMaxEquality(const LinearExpr& target,
absl::Span<const IntVar> vars);
/// Adds target == max(exprs).
Constraint AddMaxEquality(const LinearExpr& target,
absl::Span<const LinearExpr> exprs);
/// Adds target == max(exprs).
Constraint AddMaxEquality(const LinearExpr& target,
std::initializer_list<LinearExpr> exprs);
/// Adds target = num / denom (integer division rounded towards 0).
Constraint AddDivisionEquality(const LinearExpr& target,
const LinearExpr& numerator,
const LinearExpr& denominator);
/// Adds target == abs(expr).
Constraint AddAbsEquality(const LinearExpr& target, const LinearExpr& expr);
/// Adds target = var % mod.
Constraint AddModuloEquality(const LinearExpr& target, const LinearExpr& var,
const LinearExpr& mod);
/// Adds target == prod(exprs).
Constraint AddMultiplicationEquality(const LinearExpr& target,
absl::Span<const LinearExpr> exprs);
/// Adds target == prod(vars).
Constraint AddMultiplicationEquality(const LinearExpr& target,
absl::Span<const IntVar> vars);
/// Adds target == prod(vars).
Constraint AddMultiplicationEquality(const LinearExpr& target,
std::initializer_list<LinearExpr> exprs);
/// Adds target == left * right.
Constraint AddMultiplicationEquality(const LinearExpr& target,
const LinearExpr& left,
const LinearExpr& right);
/**
* Adds a no-overlap constraint that ensures that all present intervals do
* not overlap in time.
*/
Constraint AddNoOverlap(absl::Span<const IntervalVar> vars);
/**
* The no_overlap_2d constraint prevents a set of boxes from overlapping.
*/
NoOverlap2DConstraint AddNoOverlap2D();
/**
* The cumulative constraint
*
* It ensures that for any integer point, the sum of the demands of the
* intervals containing that point does not exceed the capacity.
*/
CumulativeConstraint AddCumulative(LinearExpr capacity);
/// Adds a linear minimization objective.
void Minimize(const LinearExpr& expr);
/// Adds a linear floating point minimization objective.
/// Note that the coefficients will be internally scaled to integer.
void Minimize(const DoubleLinearExpr& expr);
/// Adds a linear maximization objective.
void Maximize(const LinearExpr& expr);
/// Adds a linear floating point maximization objective.
/// Note that the coefficients will be internally scaled to integer.
void Maximize(const DoubleLinearExpr& expr);
/// Removes the objective from the model.
void ClearObjective();
/// Checks whether the model contains an objective.
bool HasObjective() const;
/// Adds a decision strategy on a list of integer variables.
void AddDecisionStrategy(
absl::Span<const IntVar> variables,
DecisionStrategyProto::VariableSelectionStrategy var_strategy,
DecisionStrategyProto::DomainReductionStrategy domain_strategy);
/// Adds a decision strategy on a list of integer variables.
void AddDecisionStrategy(
absl::Span<const BoolVar> variables,
DecisionStrategyProto::VariableSelectionStrategy var_strategy,
DecisionStrategyProto::DomainReductionStrategy domain_strategy);
/// Adds a decision strategy on a list of affine expressions.
void AddDecisionStrategy(
absl::Span<const LinearExpr> expressions,
DecisionStrategyProto::VariableSelectionStrategy var_strategy,
DecisionStrategyProto::DomainReductionStrategy domain_strategy);
/// Adds a decision strategy on a list of affine expressions.
void AddDecisionStrategy(
std::initializer_list<LinearExpr> expressions,
DecisionStrategyProto::VariableSelectionStrategy var_strategy,
DecisionStrategyProto::DomainReductionStrategy domain_strategy);
/// Adds hinting to a variable.
void AddHint(IntVar var, int64_t value);
/// Adds hinting to a Boolean variable.
void AddHint(BoolVar var, bool value);
/// Removes all hints.
void ClearHints();
/// Adds a literal to the model as assumptions.
void AddAssumption(BoolVar lit);
/// Adds multiple literals to the model as assumptions.
void AddAssumptions(absl::Span<const BoolVar> literals);
/// Remove all assumptions from the model.
void ClearAssumptions();
const CpModelProto& Build() const { return cp_model_; }
const CpModelProto& Proto() const { return cp_model_; }
CpModelProto* MutableProto() { return &cp_model_; }
/// Export the model to file.
bool ExportToFile(absl::string_view filename) const;
/// Returns a cloned version of the current model.
CpModelBuilder Clone() const;
/// Returns the Boolean variable from its index in the proto.
BoolVar GetBoolVarFromProtoIndex(int index);
/// Returns the integer variable from its index in the proto.
IntVar GetIntVarFromProtoIndex(int index);
/// Returns the interval variable from its index in the proto.
IntervalVar GetIntervalVarFromProtoIndex(int index);
private:
friend class CumulativeConstraint;
friend class ReservoirConstraint;
friend class IntervalVar;
friend class IntVar;
// Used for cloning a model.
void ResetAndImport(const CpModelProto& model_proto);
// Fills the 'expr_proto' with the linear expression represented by 'expr'.
LinearExpressionProto LinearExprToProto(const LinearExpr& expr,
bool negate = false);
// Returns a (cached) integer variable index with a constant value.
int IndexFromConstant(int64_t value);
// Returns a valid integer index from a BoolVar index.
// If the input index is a positive, it returns this index.
// If the input index is negative, it creates a cached IntVar equal to
// 1 - BoolVar(PositiveRef(index)), and returns the index of this new
// variable.
int GetOrCreateIntegerIndex(int index);
void FillLinearTerms(const LinearExpr& left, const LinearExpr& right,
LinearConstraintProto* proto);
CpModelProto cp_model_;
absl::flat_hash_map<int64_t, int> constant_to_index_map_;
absl::flat_hash_map<int, int> bool_to_integer_index_map_;
};
/// Evaluates the value of an linear expression in a solver response.
int64_t SolutionIntegerValue(const CpSolverResponse& r, const LinearExpr& expr);
/// Evaluates the value of a Boolean literal in a solver response.
bool SolutionBooleanValue(const CpSolverResponse& r, BoolVar x);
// Returns a more readable and compact DebugString() than
// proto.variables(index).DebugString(). This is used by IntVar::DebugString()
// but also allow to get the same string from a const proto.
std::string VarDebugString(const CpModelProto& proto, int index);
// ============================================================================
// Minimal support for "natural" API to create LinearExpr.
//
// Note(user): This might be optimized further by optimizing LinearExpr for
// holding one term, or introducing an LinearTerm class, but these should mainly
// be used to construct small expressions. Revisit if we run into performance
// issues. Note that if perf become a bottleneck for a client, then probably
// directly writing the proto will be even faster.
// ============================================================================
inline LinearExpr operator-(LinearExpr expr) { return expr *= -1; }
inline LinearExpr operator+(const LinearExpr& lhs, const LinearExpr& rhs) {
LinearExpr temp(lhs);
temp += rhs;
return temp;
}
inline LinearExpr operator+(LinearExpr&& lhs, const LinearExpr& rhs) {
lhs += rhs;
return std::move(lhs);
}
inline LinearExpr operator+(const LinearExpr& lhs, LinearExpr&& rhs) {
rhs += lhs;
return std::move(rhs);
}
inline LinearExpr operator+(LinearExpr&& lhs, LinearExpr&& rhs) {
if (lhs.variables().size() < rhs.variables().size()) {
rhs += std::move(lhs);
return std::move(rhs);
} else {
lhs += std::move(rhs);
return std::move(lhs);
}
}
inline LinearExpr operator-(const LinearExpr& lhs, const LinearExpr& rhs) {
LinearExpr temp(lhs);
temp -= rhs;
return temp;
}
inline LinearExpr operator-(LinearExpr&& lhs, const LinearExpr& rhs) {
lhs -= rhs;
return std::move(lhs);
}
inline LinearExpr operator-(const LinearExpr& lhs, LinearExpr&& rhs) {
rhs *= -1;
rhs += lhs;
return std::move(rhs);
}
inline LinearExpr operator-(LinearExpr&& lhs, LinearExpr&& rhs) {
lhs -= std::move(rhs);
return std::move(lhs);
}
inline LinearExpr operator*(LinearExpr expr, int64_t factor) {
expr *= factor;
return expr;
}
inline LinearExpr operator*(int64_t factor, LinearExpr expr) {
expr *= factor;
return expr;
}
// For DoubleLinearExpr.
inline DoubleLinearExpr operator-(DoubleLinearExpr expr) {
expr *= -1;
return expr;
}
inline DoubleLinearExpr operator+(const DoubleLinearExpr& lhs,
const DoubleLinearExpr& rhs) {
DoubleLinearExpr temp(lhs);
temp += rhs;
return temp;
}
inline DoubleLinearExpr operator+(DoubleLinearExpr&& lhs,
const DoubleLinearExpr& rhs) {
lhs += rhs;
return std::move(lhs);
}
inline DoubleLinearExpr operator+(const DoubleLinearExpr& lhs,
DoubleLinearExpr&& rhs) {
rhs += lhs;
return std::move(rhs);
}
inline DoubleLinearExpr operator+(DoubleLinearExpr&& lhs,
DoubleLinearExpr&& rhs) {
if (lhs.variables().size() < rhs.variables().size()) {
rhs += std::move(lhs);
return std::move(rhs);
} else {
lhs += std::move(rhs);
return std::move(lhs);
}
}
inline DoubleLinearExpr operator+(DoubleLinearExpr expr, double rhs) {
expr += rhs;
return expr;
}
inline DoubleLinearExpr operator+(double lhs, DoubleLinearExpr expr) {
expr += lhs;
return expr;
}
inline DoubleLinearExpr operator-(const DoubleLinearExpr& lhs,
const DoubleLinearExpr& rhs) {
DoubleLinearExpr temp(lhs);
temp -= rhs;
return temp;
}
inline DoubleLinearExpr operator-(DoubleLinearExpr&& lhs,
const DoubleLinearExpr& rhs) {
lhs -= rhs;
return std::move(lhs);
}
inline DoubleLinearExpr operator-(const DoubleLinearExpr& lhs,
DoubleLinearExpr&& rhs) {
rhs *= -1;
rhs += lhs;
return std::move(rhs);
}
inline DoubleLinearExpr operator-(DoubleLinearExpr&& lhs,
DoubleLinearExpr&& rhs) {
lhs -= std::move(rhs);
return std::move(lhs);
}
inline DoubleLinearExpr operator-(DoubleLinearExpr epxr, double rhs) {
epxr -= rhs;
return epxr;
}
inline DoubleLinearExpr operator-(double lhs, DoubleLinearExpr expr) {
expr *= -1;
expr += lhs;
return expr;
}
inline DoubleLinearExpr operator*(DoubleLinearExpr expr, double factor) {
expr *= factor;
return expr;
}
inline DoubleLinearExpr operator*(double factor, DoubleLinearExpr expr) {
expr *= factor;
return expr;
}
} // namespace sat
} // namespace operations_research
#endif // ORTOOLS_SAT_CP_MODEL_H_