2014-07-09 11:10:20 +00:00
|
|
|
// Copyright 2010-2014 Google
|
2010-09-15 12:42:33 +00:00
|
|
|
// 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.
|
|
|
|
|
//
|
|
|
|
|
// Range constraints
|
|
|
|
|
|
2011-09-21 15:16:48 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
#include "base/logging.h"
|
2011-09-21 15:16:48 +00:00
|
|
|
#include "constraint_solver/constraint_solver.h"
|
2012-07-04 22:05:58 +00:00
|
|
|
#include "constraint_solver/constraint_solveri.h"
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
namespace operations_research {
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RangeEquality
|
|
|
|
|
|
2011-08-11 05:15:18 +00:00
|
|
|
namespace {
|
2010-09-15 12:42:33 +00:00
|
|
|
class RangeEquality : public Constraint {
|
|
|
|
|
public:
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeEquality(Solver* const s, IntExpr* const l, IntExpr* const r)
|
2012-07-05 14:36:19 +00:00
|
|
|
: Constraint(s), left_(l), right_(r) {}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
virtual ~RangeEquality() {}
|
2012-07-05 14:36:19 +00:00
|
|
|
|
|
|
|
|
virtual void Post() {
|
|
|
|
|
Demon* const d = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(d);
|
|
|
|
|
right_->WhenRange(d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void InitialPropagate() {
|
|
|
|
|
left_->SetRange(right_->Min(), right_->Max());
|
|
|
|
|
right_->SetRange(left_->Min(), left_->Max());
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const {
|
2012-07-05 14:36:19 +00:00
|
|
|
return left_->DebugString() + " == " + right_->DebugString();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
virtual IntVar* Var() { return solver()->MakeIsEqualVar(left_, right_); }
|
2012-07-05 14:36:19 +00:00
|
|
|
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
2011-08-11 05:15:18 +00:00
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kEquality, this);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
|
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kEquality, this);
|
2011-07-11 20:13:14 +00:00
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2010-09-15 12:42:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RangeLessOrEqual
|
|
|
|
|
|
|
|
|
|
class RangeLessOrEqual : public Constraint {
|
|
|
|
|
public:
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeLessOrEqual(Solver* const s, IntExpr* const l, IntExpr* const r);
|
2010-09-15 12:42:33 +00:00
|
|
|
virtual ~RangeLessOrEqual() {}
|
|
|
|
|
virtual void Post();
|
|
|
|
|
virtual void InitialPropagate();
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const;
|
2012-03-20 13:11:01 +00:00
|
|
|
virtual IntVar* Var() {
|
2012-03-19 17:14:57 +00:00
|
|
|
return solver()->MakeIsLessOrEqualVar(left_, right_);
|
|
|
|
|
}
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kLessOrEqual, this);
|
2011-07-14 23:37:47 +00:00
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
2011-07-11 20:13:14 +00:00
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kLessOrEqual, this);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-06 13:47:48 +00:00
|
|
|
Demon* demon_;
|
2010-09-15 12:42:33 +00:00
|
|
|
};
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeLessOrEqual::RangeLessOrEqual(Solver* const s, IntExpr* const l,
|
|
|
|
|
IntExpr* const r)
|
2013-10-10 15:23:20 +00:00
|
|
|
: Constraint(s), left_(l), right_(r), demon_(nullptr) {}
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
void RangeLessOrEqual::Post() {
|
2012-07-06 13:47:48 +00:00
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RangeLessOrEqual::InitialPropagate() {
|
|
|
|
|
left_->SetMax(right_->Max());
|
|
|
|
|
right_->SetMin(left_->Min());
|
2012-07-06 13:47:48 +00:00
|
|
|
if (left_->Max() <= right_->Min()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string RangeLessOrEqual::DebugString() const {
|
2010-09-15 12:42:33 +00:00
|
|
|
return left_->DebugString() + " <= " + right_->DebugString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RangeGreaterOrEqual
|
|
|
|
|
|
|
|
|
|
class RangeGreaterOrEqual : public Constraint {
|
|
|
|
|
public:
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeGreaterOrEqual(Solver* const s, IntExpr* const l, IntExpr* const r);
|
2010-09-15 12:42:33 +00:00
|
|
|
virtual ~RangeGreaterOrEqual() {}
|
|
|
|
|
virtual void Post();
|
|
|
|
|
virtual void InitialPropagate();
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const;
|
2012-03-20 13:11:01 +00:00
|
|
|
virtual IntVar* Var() {
|
2012-03-19 17:14:57 +00:00
|
|
|
return solver()->MakeIsGreaterOrEqualVar(left_, right_);
|
|
|
|
|
}
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kGreaterOrEqual, this);
|
2011-07-14 23:37:47 +00:00
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
2011-07-11 20:13:14 +00:00
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kGreaterOrEqual, this);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-06 13:47:48 +00:00
|
|
|
Demon* demon_;
|
2010-09-15 12:42:33 +00:00
|
|
|
};
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeGreaterOrEqual::RangeGreaterOrEqual(Solver* const s, IntExpr* const l,
|
|
|
|
|
IntExpr* const r)
|
2013-10-10 15:23:20 +00:00
|
|
|
: Constraint(s), left_(l), right_(r), demon_(nullptr) {}
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
void RangeGreaterOrEqual::Post() {
|
2012-07-06 13:47:48 +00:00
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RangeGreaterOrEqual::InitialPropagate() {
|
|
|
|
|
left_->SetMin(right_->Min());
|
|
|
|
|
right_->SetMax(left_->Max());
|
2012-07-06 13:47:48 +00:00
|
|
|
if (left_->Min() >= right_->Max()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string RangeGreaterOrEqual::DebugString() const {
|
2010-09-15 12:42:33 +00:00
|
|
|
return left_->DebugString() + " >= " + right_->DebugString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RangeLess
|
|
|
|
|
|
|
|
|
|
class RangeLess : public Constraint {
|
|
|
|
|
public:
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeLess(Solver* const s, IntExpr* const l, IntExpr* const r);
|
2010-09-15 12:42:33 +00:00
|
|
|
virtual ~RangeLess() {}
|
|
|
|
|
virtual void Post();
|
|
|
|
|
virtual void InitialPropagate();
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const;
|
2013-10-10 15:23:20 +00:00
|
|
|
virtual IntVar* Var() { return solver()->MakeIsLessVar(left_, right_); }
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kLess, this);
|
2011-07-14 23:37:47 +00:00
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
2011-07-11 20:13:14 +00:00
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kLess, this);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-06 13:49:59 +00:00
|
|
|
Demon* demon_;
|
2010-09-15 12:42:33 +00:00
|
|
|
};
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeLess::RangeLess(Solver* const s, IntExpr* const l, IntExpr* const r)
|
2013-10-10 15:23:20 +00:00
|
|
|
: Constraint(s), left_(l), right_(r), demon_(nullptr) {}
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
void RangeLess::Post() {
|
2012-07-06 13:49:59 +00:00
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RangeLess::InitialPropagate() {
|
|
|
|
|
left_->SetMax(right_->Max() - 1);
|
|
|
|
|
right_->SetMin(left_->Min() + 1);
|
2012-07-06 13:49:59 +00:00
|
|
|
if (left_->Max() < right_->Min()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string RangeLess::DebugString() const {
|
2010-09-15 12:42:33 +00:00
|
|
|
return left_->DebugString() + " < " + right_->DebugString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// RangeGreater
|
|
|
|
|
|
|
|
|
|
class RangeGreater : public Constraint {
|
|
|
|
|
public:
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeGreater(Solver* const s, IntExpr* const l, IntExpr* const r);
|
2010-09-15 12:42:33 +00:00
|
|
|
virtual ~RangeGreater() {}
|
|
|
|
|
virtual void Post();
|
|
|
|
|
virtual void InitialPropagate();
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const;
|
2013-10-10 15:23:20 +00:00
|
|
|
virtual IntVar* Var() { return solver()->MakeIsGreaterVar(left_, right_); }
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kGreater, this);
|
2011-07-14 23:37:47 +00:00
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
2011-07-11 20:13:14 +00:00
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kGreater, this);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-06 13:49:59 +00:00
|
|
|
Demon* demon_;
|
2010-09-15 12:42:33 +00:00
|
|
|
};
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
RangeGreater::RangeGreater(Solver* const s, IntExpr* const l, IntExpr* const r)
|
2013-10-10 15:23:20 +00:00
|
|
|
: Constraint(s), left_(l), right_(r), demon_(nullptr) {}
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
void RangeGreater::Post() {
|
2012-07-06 13:49:59 +00:00
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RangeGreater::InitialPropagate() {
|
|
|
|
|
left_->SetMin(right_->Min() + 1);
|
|
|
|
|
right_->SetMax(left_->Max() - 1);
|
2012-07-06 13:49:59 +00:00
|
|
|
if (left_->Min() > right_->Max()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string RangeGreater::DebugString() const {
|
2010-09-15 12:42:33 +00:00
|
|
|
return left_->DebugString() + " > " + right_->DebugString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
// DiffVar
|
|
|
|
|
|
|
|
|
|
class DiffVar : public Constraint {
|
|
|
|
|
public:
|
|
|
|
|
DiffVar(Solver* const s, IntVar* const l, IntVar* const r);
|
|
|
|
|
virtual ~DiffVar() {}
|
|
|
|
|
virtual void Post();
|
|
|
|
|
virtual void InitialPropagate();
|
2013-12-16 10:24:42 +00:00
|
|
|
virtual std::string DebugString() const;
|
2013-10-10 15:23:20 +00:00
|
|
|
virtual IntVar* Var() { return solver()->MakeIsDifferentVar(left_, right_); }
|
2012-03-19 17:14:57 +00:00
|
|
|
|
2011-07-11 20:13:14 +00:00
|
|
|
virtual void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kNonEqual, this);
|
2011-07-14 23:37:47 +00:00
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
2011-07-11 20:13:14 +00:00
|
|
|
right_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kNonEqual, this);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
private:
|
|
|
|
|
IntVar* const left_;
|
|
|
|
|
IntVar* const right_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DiffVar::DiffVar(Solver* const s, IntVar* const l, IntVar* const r)
|
2013-10-10 15:23:20 +00:00
|
|
|
: Constraint(s), left_(l), right_(r) {}
|
2010-09-15 12:42:33 +00:00
|
|
|
|
|
|
|
|
void DiffVar::Post() {
|
|
|
|
|
Demon* d = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenBound(d);
|
|
|
|
|
right_->WhenBound(d);
|
|
|
|
|
// TODO(user) : improve me, separated demons, actually to test
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DiffVar::InitialPropagate() {
|
|
|
|
|
if (left_->Bound()) {
|
2012-06-16 07:30:12 +00:00
|
|
|
if (right_->Size() < 0xFFFFFF) {
|
|
|
|
|
right_->RemoveValue(left_->Min()); // we use min instead of value
|
|
|
|
|
} else {
|
|
|
|
|
solver()->AddConstraint(solver()->MakeNonEquality(right_, left_->Min()));
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
if (right_->Bound()) {
|
2012-06-16 07:30:12 +00:00
|
|
|
if (left_->Size() < 0xFFFFFF) {
|
|
|
|
|
left_->RemoveValue(right_->Min()); // see above
|
|
|
|
|
} else {
|
|
|
|
|
solver()->AddConstraint(solver()->MakeNonEquality(left_, right_->Min()));
|
|
|
|
|
}
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string DiffVar::DebugString() const {
|
2010-09-15 12:42:33 +00:00
|
|
|
return left_->DebugString() + " != " + right_->DebugString();
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
// --------------------- Reified API -------------------
|
2013-01-10 17:01:34 +00:00
|
|
|
// A reified API transforms an constraint into a status variables.
|
|
|
|
|
// For example x == y is transformed into IsEqual(x, y, b) where
|
|
|
|
|
// b is a boolean variable which is true if and only if x is equal to b.
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
// IsEqualCt
|
|
|
|
|
|
|
|
|
|
class IsEqualCt : public CastConstraint {
|
|
|
|
|
public:
|
2013-10-10 15:23:20 +00:00
|
|
|
IsEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* const b)
|
2013-10-10 15:23:20 +00:00
|
|
|
: CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
virtual ~IsEqualCt() {}
|
|
|
|
|
|
|
|
|
|
virtual void Post() {
|
2013-07-14 04:22:33 +00:00
|
|
|
range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
2012-07-04 22:05:58 +00:00
|
|
|
left_->WhenRange(range_demon_);
|
|
|
|
|
right_->WhenRange(range_demon_);
|
2013-10-10 15:23:20 +00:00
|
|
|
Demon* const target_demon = MakeConstraintDemon0(
|
|
|
|
|
solver(), this, &IsEqualCt::PropagateTarget, "PropagateTarget");
|
2012-07-04 22:05:58 +00:00
|
|
|
target_var_->WhenBound(target_demon);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void InitialPropagate() {
|
|
|
|
|
if (target_var_->Bound()) {
|
|
|
|
|
PropagateTarget();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-09-05 16:37:24 +00:00
|
|
|
if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
|
2012-07-04 22:05:58 +00:00
|
|
|
target_var_->SetValue(0);
|
|
|
|
|
range_demon_->inhibit(solver());
|
2012-09-06 09:50:39 +00:00
|
|
|
} else if (left_->Bound()) {
|
|
|
|
|
if (right_->Bound()) {
|
|
|
|
|
target_var_->SetValue(left_->Min() == right_->Min());
|
|
|
|
|
} else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(0);
|
|
|
|
|
}
|
2013-10-10 15:23:20 +00:00
|
|
|
} else if (right_->Bound() && left_->IsVar() &&
|
2012-09-06 09:50:39 +00:00
|
|
|
!left_->Var()->Contains(right_->Min())) {
|
2013-10-10 15:23:20 +00:00
|
|
|
range_demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(0);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PropagateTarget() {
|
|
|
|
|
if (target_var_->Min() == 0) {
|
|
|
|
|
if (left_->Bound()) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
2013-07-14 04:22:33 +00:00
|
|
|
if (right_->IsVar()) {
|
|
|
|
|
right_->Var()->RemoveValue(left_->Min());
|
|
|
|
|
} else {
|
|
|
|
|
solver()->AddConstraint(
|
|
|
|
|
solver()->MakeNonEquality(right_, left_->Min()));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right_->Bound()) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
2013-07-14 04:22:33 +00:00
|
|
|
if (left_->IsVar()) {
|
|
|
|
|
left_->Var()->RemoveValue(right_->Min());
|
|
|
|
|
} else {
|
|
|
|
|
solver()->AddConstraint(
|
|
|
|
|
solver()->MakeNonEquality(left_, right_->Min()));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
} else { // Var is true.
|
|
|
|
|
left_->SetRange(right_->Min(), right_->Max());
|
|
|
|
|
right_->SetRange(left_->Min(), left_->Max());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string DebugString() const {
|
2013-10-10 15:23:20 +00:00
|
|
|
return StringPrintf("IsEqualCt(%s, %s, %s)", left_->DebugString().c_str(),
|
2012-07-04 22:05:58 +00:00
|
|
|
right_->DebugString().c_str(),
|
|
|
|
|
target_var_->DebugString().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kIsEqual, this);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
|
|
|
|
right_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
|
|
|
|
|
target_var_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kIsEqual, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2012-09-05 16:37:24 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-04 22:05:58 +00:00
|
|
|
Demon* range_demon_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// IsDifferentCt
|
|
|
|
|
|
|
|
|
|
class IsDifferentCt : public CastConstraint {
|
|
|
|
|
public:
|
2013-10-10 15:23:20 +00:00
|
|
|
IsDifferentCt(Solver* const s, IntExpr* const l, IntExpr* const r,
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* const b)
|
2013-10-10 15:23:20 +00:00
|
|
|
: CastConstraint(s, b), left_(l), right_(r), range_demon_(nullptr) {}
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
virtual ~IsDifferentCt() {}
|
|
|
|
|
|
|
|
|
|
virtual void Post() {
|
2013-10-18 13:50:35 +00:00
|
|
|
range_demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
2012-07-04 22:05:58 +00:00
|
|
|
left_->WhenRange(range_demon_);
|
|
|
|
|
right_->WhenRange(range_demon_);
|
2013-10-10 15:23:20 +00:00
|
|
|
Demon* const target_demon = MakeConstraintDemon0(
|
|
|
|
|
solver(), this, &IsDifferentCt::PropagateTarget, "PropagateTarget");
|
2012-07-04 22:05:58 +00:00
|
|
|
target_var_->WhenBound(target_demon);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-18 13:50:35 +00:00
|
|
|
virtual void InitialPropagate() {
|
2012-07-04 22:05:58 +00:00
|
|
|
if (target_var_->Bound()) {
|
|
|
|
|
PropagateTarget();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2012-09-05 16:42:49 +00:00
|
|
|
if (left_->Min() > right_->Max() || left_->Max() < right_->Min()) {
|
2012-07-04 22:05:58 +00:00
|
|
|
target_var_->SetValue(1);
|
|
|
|
|
range_demon_->inhibit(solver());
|
2012-09-06 09:50:39 +00:00
|
|
|
} else if (left_->Bound()) {
|
|
|
|
|
if (right_->Bound()) {
|
|
|
|
|
target_var_->SetValue(left_->Min() != right_->Min());
|
|
|
|
|
} else if (right_->IsVar() && !right_->Var()->Contains(left_->Min())) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(1);
|
|
|
|
|
}
|
2013-10-10 15:23:20 +00:00
|
|
|
} else if (right_->Bound() && left_->IsVar() &&
|
2012-09-06 09:50:39 +00:00
|
|
|
!left_->Var()->Contains(right_->Min())) {
|
2013-10-10 15:23:20 +00:00
|
|
|
range_demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(1);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PropagateTarget() {
|
|
|
|
|
if (target_var_->Min() == 0) {
|
|
|
|
|
left_->SetRange(right_->Min(), right_->Max());
|
|
|
|
|
right_->SetRange(left_->Min(), left_->Max());
|
|
|
|
|
} else { // Var is true.
|
|
|
|
|
if (left_->Bound()) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
2012-09-05 16:42:49 +00:00
|
|
|
solver()->AddConstraint(
|
|
|
|
|
solver()->MakeNonEquality(right_, left_->Min()));
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right_->Bound()) {
|
|
|
|
|
range_demon_->inhibit(solver());
|
2012-09-05 16:42:49 +00:00
|
|
|
solver()->AddConstraint(
|
|
|
|
|
solver()->MakeNonEquality(left_, right_->Min()));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string DebugString() const {
|
2013-10-10 15:23:20 +00:00
|
|
|
return StringPrintf(
|
|
|
|
|
"IsDifferentCt(%s, %s, %s)", left_->DebugString().c_str(),
|
|
|
|
|
right_->DebugString().c_str(), target_var_->DebugString().c_str());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kIsDifferent, this);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
|
|
|
|
right_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
|
|
|
|
|
target_var_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kIsDifferent, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2012-09-05 16:42:49 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-04 22:05:58 +00:00
|
|
|
Demon* range_demon_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class IsLessOrEqualCt : public CastConstraint {
|
|
|
|
|
public:
|
2013-10-10 15:23:20 +00:00
|
|
|
IsLessOrEqualCt(Solver* const s, IntExpr* const l, IntExpr* const r,
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* const b)
|
2013-10-10 15:23:20 +00:00
|
|
|
: CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
virtual ~IsLessOrEqualCt() {}
|
|
|
|
|
|
|
|
|
|
virtual void Post() {
|
|
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
|
|
|
|
target_var_->WhenBound(demon_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void InitialPropagate() {
|
|
|
|
|
if (target_var_->Bound()) {
|
|
|
|
|
if (target_var_->Min() == 0) {
|
2012-08-15 23:46:59 +00:00
|
|
|
right_->SetMax(left_->Max() - 1);
|
|
|
|
|
left_->SetMin(right_->Min() + 1);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else { // Var is true.
|
|
|
|
|
right_->SetMin(left_->Min());
|
|
|
|
|
left_->SetMax(right_->Max());
|
|
|
|
|
}
|
|
|
|
|
} else if (right_->Min() >= left_->Max()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(1);
|
|
|
|
|
} else if (right_->Max() < left_->Min()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string DebugString() const {
|
2013-10-10 15:23:20 +00:00
|
|
|
return StringPrintf(
|
|
|
|
|
"IsLessOrEqualCt(%s, %s, %s)", left_->DebugString().c_str(),
|
|
|
|
|
right_->DebugString().c_str(), target_var_->DebugString().c_str());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
|
|
|
|
right_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
|
|
|
|
|
target_var_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kIsLessOrEqual, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-04 22:05:58 +00:00
|
|
|
Demon* demon_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class IsLessCt : public CastConstraint {
|
|
|
|
|
public:
|
2013-10-10 15:23:20 +00:00
|
|
|
IsLessCt(Solver* const s, IntExpr* const l, IntExpr* const r, IntVar* const b)
|
|
|
|
|
: CastConstraint(s, b), left_(l), right_(r), demon_(nullptr) {}
|
2012-07-04 22:05:58 +00:00
|
|
|
|
|
|
|
|
virtual ~IsLessCt() {}
|
|
|
|
|
|
|
|
|
|
virtual void Post() {
|
|
|
|
|
demon_ = solver()->MakeConstraintInitialPropagateCallback(this);
|
|
|
|
|
left_->WhenRange(demon_);
|
|
|
|
|
right_->WhenRange(demon_);
|
|
|
|
|
target_var_->WhenBound(demon_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void InitialPropagate() {
|
|
|
|
|
if (target_var_->Bound()) {
|
|
|
|
|
if (target_var_->Min() == 0) {
|
2012-08-15 23:17:20 +00:00
|
|
|
right_->SetMax(left_->Max());
|
|
|
|
|
left_->SetMin(right_->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
} else { // Var is true.
|
|
|
|
|
right_->SetMin(left_->Min() + 1);
|
|
|
|
|
left_->SetMax(right_->Max() - 1);
|
|
|
|
|
}
|
|
|
|
|
} else if (right_->Min() > left_->Max()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(1);
|
|
|
|
|
} else if (right_->Max() <= left_->Min()) {
|
|
|
|
|
demon_->inhibit(solver());
|
|
|
|
|
target_var_->SetValue(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string DebugString() const {
|
2013-10-10 15:23:20 +00:00
|
|
|
return StringPrintf("IsLessCt(%s, %s, %s)", left_->DebugString().c_str(),
|
2012-07-04 22:05:58 +00:00
|
|
|
right_->DebugString().c_str(),
|
|
|
|
|
target_var_->DebugString().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Accept(ModelVisitor* const visitor) const {
|
|
|
|
|
visitor->BeginVisitConstraint(ModelVisitor::kIsLess, this);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kLeftArgument, left_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kRightArgument,
|
|
|
|
|
right_);
|
|
|
|
|
visitor->VisitIntegerExpressionArgument(ModelVisitor::kTargetArgument,
|
|
|
|
|
target_var_);
|
|
|
|
|
visitor->EndVisitConstraint(ModelVisitor::kIsLess, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const left_;
|
|
|
|
|
IntExpr* const right_;
|
2012-07-04 22:05:58 +00:00
|
|
|
Demon* demon_;
|
|
|
|
|
};
|
2011-08-11 05:15:18 +00:00
|
|
|
} // namespace
|
2010-09-15 12:42:33 +00:00
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeEquality(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2012-07-05 13:27:16 +00:00
|
|
|
if (l->Bound()) {
|
|
|
|
|
return MakeEquality(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeEquality(l, r->Min());
|
|
|
|
|
} else {
|
|
|
|
|
return RevAlloc(new RangeEquality(this, l, r));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeLessOrEqual(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2014-05-26 01:23:59 +00:00
|
|
|
if (l == r) {
|
|
|
|
|
return MakeTrueConstraint();
|
|
|
|
|
} else if (l->Bound()) {
|
2012-07-05 13:43:02 +00:00
|
|
|
return MakeGreaterOrEqual(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeLessOrEqual(l, r->Min());
|
|
|
|
|
} else {
|
|
|
|
|
return RevAlloc(new RangeLessOrEqual(this, l, r));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeGreaterOrEqual(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2014-05-26 01:23:59 +00:00
|
|
|
if (l == r) {
|
|
|
|
|
return MakeTrueConstraint();
|
|
|
|
|
} else if (l->Bound()) {
|
2012-07-05 13:43:02 +00:00
|
|
|
return MakeLessOrEqual(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeGreaterOrEqual(l, r->Min());
|
|
|
|
|
} else {
|
|
|
|
|
return RevAlloc(new RangeGreaterOrEqual(this, l, r));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeLess(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2012-07-05 13:43:02 +00:00
|
|
|
if (l->Bound()) {
|
|
|
|
|
return MakeGreater(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeLess(l, r->Min());
|
|
|
|
|
} else {
|
|
|
|
|
return RevAlloc(new RangeLess(this, l, r));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeGreater(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2012-07-05 13:43:02 +00:00
|
|
|
if (l->Bound()) {
|
|
|
|
|
return MakeLess(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeGreater(l, r->Min());
|
|
|
|
|
} else {
|
|
|
|
|
return RevAlloc(new RangeGreater(this, l, r));
|
|
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
Constraint* Solver::MakeNonEquality(IntExpr* const l, IntExpr* const r) {
|
2013-10-10 15:23:20 +00:00
|
|
|
CHECK(l != nullptr) << "left expression nullptr, maybe a bad cast";
|
|
|
|
|
CHECK(r != nullptr) << "left expression nullptr, maybe a bad cast";
|
2010-09-15 12:42:33 +00:00
|
|
|
CHECK_EQ(this, l->solver());
|
|
|
|
|
CHECK_EQ(this, r->solver());
|
2012-06-29 09:41:24 +00:00
|
|
|
if (l->Bound()) {
|
|
|
|
|
return MakeNonEquality(r, l->Min());
|
|
|
|
|
} else if (r->Bound()) {
|
|
|
|
|
return MakeNonEquality(l, r->Min());
|
|
|
|
|
}
|
2012-07-05 16:27:57 +00:00
|
|
|
return RevAlloc(new DiffVar(this, l->Var(), r->Var()));
|
2010-09-15 12:42:33 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* Solver::MakeIsEqualVar(IntExpr* const v1, IntExpr* const v2) {
|
|
|
|
|
CHECK_EQ(this, v1->solver());
|
|
|
|
|
CHECK_EQ(this, v2->solver());
|
|
|
|
|
if (v1->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsEqualCstVar(v2, v1->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (v2->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsEqualCstVar(v1, v2->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const cache = model_cache_->FindExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
|
|
|
|
|
if (cache != nullptr) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return cache->Var();
|
|
|
|
|
} else {
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name1 = v1->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name1.empty()) {
|
2012-09-05 16:37:24 +00:00
|
|
|
name1 = v1->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name2 = v2->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name2.empty()) {
|
2012-09-05 16:37:24 +00:00
|
|
|
name2 = v2->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
IntVar* const boolvar = MakeBoolVar(
|
|
|
|
|
StringPrintf("IsEqualVar(%s, %s)", name1.c_str(), name2.c_str()));
|
|
|
|
|
AddConstraint(MakeIsEqualCt(v1, v2, boolvar));
|
2013-10-10 15:23:20 +00:00
|
|
|
model_cache_->InsertExprExprExpression(boolvar, v1, v2,
|
|
|
|
|
ModelCache::EXPR_EXPR_IS_EQUAL);
|
2012-07-04 22:05:58 +00:00
|
|
|
return boolvar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsEqualCt(IntExpr* const v1, IntExpr* const v2,
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* b) {
|
|
|
|
|
CHECK_EQ(this, v1->solver());
|
|
|
|
|
CHECK_EQ(this, v2->solver());
|
|
|
|
|
if (v1->Bound()) {
|
2012-09-05 16:37:24 +00:00
|
|
|
return MakeIsEqualCstCt(v2, v1->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (v2->Bound()) {
|
2012-09-05 16:37:24 +00:00
|
|
|
return MakeIsEqualCstCt(v1, v2->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
if (b->Bound()) {
|
|
|
|
|
if (b->Min() == 0) {
|
2012-09-05 16:37:24 +00:00
|
|
|
return MakeNonEquality(v1, v2);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else {
|
2012-09-05 16:37:24 +00:00
|
|
|
return MakeEquality(v1, v2);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
2012-09-05 16:37:24 +00:00
|
|
|
return RevAlloc(new IsEqualCt(this, v1, v2, b));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IntVar* Solver::MakeIsDifferentVar(IntExpr* const v1, IntExpr* const v2) {
|
|
|
|
|
CHECK_EQ(this, v1->solver());
|
|
|
|
|
CHECK_EQ(this, v2->solver());
|
|
|
|
|
if (v1->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsDifferentCstVar(v2, v1->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (v2->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsDifferentCstVar(v1, v2->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-09-18 16:16:53 +00:00
|
|
|
IntExpr* cache = model_cache_->FindExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
v1, v2, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
|
2013-09-18 16:16:53 +00:00
|
|
|
if (cache == nullptr) {
|
|
|
|
|
cache = model_cache_->FindExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
v2, v1, ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
|
2013-09-18 16:16:53 +00:00
|
|
|
}
|
2012-07-04 22:05:58 +00:00
|
|
|
if (cache != NULL) {
|
|
|
|
|
return cache->Var();
|
|
|
|
|
} else {
|
2013-09-18 16:16:53 +00:00
|
|
|
IntVar* boolvar = nullptr;
|
2013-10-10 15:23:20 +00:00
|
|
|
IntExpr* reverse_cache = model_cache_->FindExprExprExpression(
|
|
|
|
|
v1, v2, ModelCache::EXPR_EXPR_IS_EQUAL);
|
2013-09-18 16:16:53 +00:00
|
|
|
if (reverse_cache == nullptr) {
|
2013-10-10 15:23:20 +00:00
|
|
|
reverse_cache = model_cache_->FindExprExprExpression(
|
|
|
|
|
v2, v1, ModelCache::EXPR_EXPR_IS_EQUAL);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-09-18 16:16:53 +00:00
|
|
|
if (reverse_cache != nullptr) {
|
|
|
|
|
boolvar = MakeDifference(1, reverse_cache)->Var();
|
|
|
|
|
} else {
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name1 = v1->name();
|
2013-09-18 16:16:53 +00:00
|
|
|
if (name1.empty()) {
|
|
|
|
|
name1 = v1->DebugString();
|
|
|
|
|
}
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name2 = v2->name();
|
2013-09-18 16:16:53 +00:00
|
|
|
if (name2.empty()) {
|
|
|
|
|
name2 = v2->DebugString();
|
|
|
|
|
}
|
|
|
|
|
boolvar = MakeBoolVar(
|
|
|
|
|
StringPrintf("IsDifferentVar(%s, %s)", name1.c_str(), name2.c_str()));
|
|
|
|
|
AddConstraint(MakeIsDifferentCt(v1, v2, boolvar));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-10-10 15:23:20 +00:00
|
|
|
model_cache_->InsertExprExprExpression(boolvar, v1, v2,
|
|
|
|
|
ModelCache::EXPR_EXPR_IS_NOT_EQUAL);
|
2012-07-04 22:05:58 +00:00
|
|
|
return boolvar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsDifferentCt(IntExpr* const v1, IntExpr* const v2,
|
2012-07-04 22:05:58 +00:00
|
|
|
IntVar* b) {
|
|
|
|
|
CHECK_EQ(this, v1->solver());
|
|
|
|
|
CHECK_EQ(this, v2->solver());
|
|
|
|
|
if (v1->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsDifferentCstCt(v2, v1->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (v2->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsDifferentCstCt(v1, v2->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-09-05 16:42:49 +00:00
|
|
|
return RevAlloc(new IsDifferentCt(this, v1, v2, b));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2012-07-05 16:27:57 +00:00
|
|
|
IntVar* Solver::MakeIsLessOrEqualVar(IntExpr* const left,
|
|
|
|
|
IntExpr* const right) {
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, left->solver());
|
|
|
|
|
CHECK_EQ(this, right->solver());
|
|
|
|
|
if (left->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsGreaterOrEqualCstVar(right, left->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsLessOrEqualCstVar(left, right->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const cache = model_cache_->FindExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
|
|
|
|
|
if (cache != nullptr) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return cache->Var();
|
|
|
|
|
} else {
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name1 = left->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name1.empty()) {
|
2012-07-05 16:27:57 +00:00
|
|
|
name1 = left->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name2 = right->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name2.empty()) {
|
2012-07-05 16:27:57 +00:00
|
|
|
name2 = right->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
IntVar* const boolvar = MakeBoolVar(
|
|
|
|
|
StringPrintf("IsLessOrEqual(%s, %s)", name1.c_str(), name2.c_str()));
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
AddConstraint(RevAlloc(new IsLessOrEqualCt(this, left, right, boolvar)));
|
2012-07-05 16:27:57 +00:00
|
|
|
model_cache_->InsertExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
boolvar, left, right, ModelCache::EXPR_EXPR_IS_LESS_OR_EQUAL);
|
2012-07-04 22:05:58 +00:00
|
|
|
return boolvar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsLessOrEqualCt(IntExpr* const left,
|
|
|
|
|
IntExpr* const right, IntVar* const b) {
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, left->solver());
|
|
|
|
|
CHECK_EQ(this, right->solver());
|
|
|
|
|
if (left->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsGreaterOrEqualCstCt(right, left->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsLessOrEqualCstCt(left, right->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-09-05 16:42:49 +00:00
|
|
|
return RevAlloc(new IsLessOrEqualCt(this, left, right, b));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
IntVar* Solver::MakeIsLessVar(IntExpr* const left, IntExpr* const right) {
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, left->solver());
|
|
|
|
|
CHECK_EQ(this, right->solver());
|
|
|
|
|
if (left->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsGreaterCstVar(right, left->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsLessCstVar(left, right->Min());
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-07-05 16:27:57 +00:00
|
|
|
IntExpr* const cache = model_cache_->FindExprExprExpression(
|
2013-10-10 15:23:20 +00:00
|
|
|
left, right, ModelCache::EXPR_EXPR_IS_LESS);
|
|
|
|
|
if (cache != nullptr) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return cache->Var();
|
|
|
|
|
} else {
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name1 = left->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name1.empty()) {
|
2012-07-05 16:27:57 +00:00
|
|
|
name1 = left->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2013-12-16 10:24:42 +00:00
|
|
|
std::string name2 = right->name();
|
2012-07-04 22:05:58 +00:00
|
|
|
if (name2.empty()) {
|
2012-07-05 16:27:57 +00:00
|
|
|
name2 = right->DebugString();
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
IntVar* const boolvar = MakeBoolVar(
|
|
|
|
|
StringPrintf("IsLessOrEqual(%s, %s)", name1.c_str(), name2.c_str()));
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
AddConstraint(RevAlloc(new IsLessCt(this, left, right, boolvar)));
|
|
|
|
|
model_cache_->InsertExprExprExpression(boolvar, left, right,
|
|
|
|
|
ModelCache::EXPR_EXPR_IS_LESS);
|
2012-07-04 22:05:58 +00:00
|
|
|
return boolvar;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsLessCt(IntExpr* const left, IntExpr* const right,
|
|
|
|
|
IntVar* const b) {
|
2012-07-04 22:05:58 +00:00
|
|
|
CHECK_EQ(this, left->solver());
|
|
|
|
|
CHECK_EQ(this, right->solver());
|
|
|
|
|
if (left->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsGreaterCstCt(right, left->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
} else if (right->Bound()) {
|
2012-09-05 16:42:49 +00:00
|
|
|
return MakeIsLessCstCt(left, right->Min(), b);
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
2012-09-05 16:42:49 +00:00
|
|
|
return RevAlloc(new IsLessCt(this, left, right, b));
|
2012-07-04 22:05:58 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
IntVar* Solver::MakeIsGreaterOrEqualVar(IntExpr* const left,
|
|
|
|
|
IntExpr* const right) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return MakeIsLessOrEqualVar(right, left);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsGreaterOrEqualCt(IntExpr* const left,
|
|
|
|
|
IntExpr* const right,
|
|
|
|
|
IntVar* const b) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return MakeIsLessOrEqualCt(right, left, b);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
IntVar* Solver::MakeIsGreaterVar(IntExpr* const left, IntExpr* const right) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return MakeIsLessVar(right, left);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-10 15:23:20 +00:00
|
|
|
Constraint* Solver::MakeIsGreaterCt(IntExpr* const left, IntExpr* const right,
|
|
|
|
|
IntVar* const b) {
|
2012-07-04 22:05:58 +00:00
|
|
|
return MakeIsLessCt(right, left, b);
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-15 12:42:33 +00:00
|
|
|
} // namespace operations_research
|