diff --git a/src/constraint_solver/expr_array.cc b/src/constraint_solver/expr_array.cc index eb0cbb376e..e2477130cc 100644 --- a/src/constraint_solver/expr_array.cc +++ b/src/constraint_solver/expr_array.cc @@ -61,7 +61,8 @@ class TreeArrayConstraint : public CastConstraint { target_var_->DebugString().c_str()); } - void AcceptInternal(const std::string& name, ModelVisitor* const visitor) const { + void AcceptInternal(const std::string& name, + ModelVisitor* const visitor) const { visitor->BeginVisitConstraint(name, this); visitor->VisitIntegerVariableArrayArgument(ModelVisitor::kVarsArgument, vars_); @@ -1155,7 +1156,8 @@ class SumBooleanLessOrEqualToOne : public BaseSumBooleanConstraint { class SumBooleanGreaterOrEqualToOne : public BaseSumBooleanConstraint { public: - SumBooleanGreaterOrEqualToOne(Solver* const s, const std::vector& vars); + SumBooleanGreaterOrEqualToOne(Solver* const s, + const std::vector& vars); virtual ~SumBooleanGreaterOrEqualToOne() {} virtual void Post(); @@ -1485,7 +1487,8 @@ struct Container { // If keep_inside is true, the constant will be added back into the // scalprod as IntConst(1) * constant. int64 SortBothChangeConstant(std::vector* const vars, - std::vector* const coefs, bool keep_inside) { + std::vector* const coefs, + bool keep_inside) { CHECK(vars != nullptr); CHECK(coefs != nullptr); if (vars->empty()) { @@ -1521,7 +1524,8 @@ int64 SortBothChangeConstant(std::vector* const vars, class BooleanScalProdLessConstant : public Constraint { public: BooleanScalProdLessConstant(Solver* const s, const std::vector& vars, - const std::vector& coefs, int64 upper_bound) + const std::vector& coefs, + int64 upper_bound) : Constraint(s), vars_(vars), coefs_(coefs), @@ -1626,8 +1630,10 @@ class BooleanScalProdLessConstant : public Constraint { class PositiveBooleanScalProdEqVar : public CastConstraint { public: - PositiveBooleanScalProdEqVar(Solver* const s, const std::vector& vars, - const std::vector& coefs, IntVar* const var) + PositiveBooleanScalProdEqVar(Solver* const s, + const std::vector& vars, + const std::vector& coefs, + IntVar* const var) : CastConstraint(s, var), vars_(vars), coefs_(coefs), @@ -1870,7 +1876,8 @@ class PositiveBooleanScalProd : public BaseIntExpr { class PositiveBooleanScalProdEqCst : public Constraint { public: - PositiveBooleanScalProdEqCst(Solver* const s, const std::vector& vars, + PositiveBooleanScalProdEqCst(Solver* const s, + const std::vector& vars, const std::vector& coefs, int64 constant) : Constraint(s), vars_(vars), @@ -1922,6 +1929,7 @@ class PositiveBooleanScalProdEqCst : public Constraint { } first_unbound_backward_.SetValue(solver(), last_unbound); } + CheckGcd(); } virtual void InitialPropagate() { @@ -1955,11 +1963,35 @@ class PositiveBooleanScalProdEqCst : public Constraint { Propagate(); } + void CheckGcd() { + bool first = true; + int64 rhs = constant_; + int64 gcd = 0; + for (int i = 0; i < vars_.size(); ++i) { + const int64 coeff = coefs_[i]; + if (coeff == 0) continue; + if (vars_[i]->Bound()) { + rhs -= vars_[i]->Min() * coefs_[i]; + } else if (first) { + gcd = coeff; + first = false; + } else { + gcd = MathUtil::GCD64(gcd, coeff); + } + if (gcd == 1) { + return; + } + } + if (!first && rhs % gcd != 0) { + solver()->Fail(); + } + } + virtual std::string DebugString() const { - return StringPrintf("PositiveBooleanScalProd([%s], [%s]) == %" GG_LL_FORMAT - "d", - JoinDebugStringPtr(vars_, ", ").c_str(), - strings::Join(coefs_, ", ").c_str(), constant_); + return StringPrintf( + "PositiveBooleanScalProd([%s], [%s]) == %" GG_LL_FORMAT "d", + JoinDebugStringPtr(vars_, ", ").c_str(), + strings::Join(coefs_, ", ").c_str(), constant_); } void Accept(ModelVisitor* const visitor) const { @@ -2159,8 +2191,9 @@ class ExprLinearizer : public ModelParser { const std::vector& cp_vars = Top()->FindIntegerVariableArrayArgumentOrDie( ModelVisitor::kVarsArgument); - const std::vector& cp_coefficients = Top()->FindIntegerArrayArgumentOrDie( - ModelVisitor::kCoefficientsArgument); + const std::vector& cp_coefficients = + Top()->FindIntegerArrayArgumentOrDie( + ModelVisitor::kCoefficientsArgument); CHECK_EQ(cp_vars.size(), cp_coefficients.size()); for (int i = 0; i < cp_vars.size(); ++i) { const int64 coefficient = cp_coefficients[i]; @@ -2255,8 +2288,9 @@ class ExprLinearizer : public ModelParser { // ----- Factory functions ----- void DeepLinearize(Solver* const solver, const std::vector& pre_vars, - const std::vector& pre_coefs, std::vector* vars, - std::vector* coefs, int64* constant) { + const std::vector& pre_coefs, + std::vector* vars, std::vector* coefs, + int64* constant) { CHECK(solver != nullptr); CHECK(vars != nullptr); CHECK(coefs != nullptr); @@ -2300,7 +2334,8 @@ void DeepLinearize(Solver* const solver, const std::vector& pre_vars, Constraint* MakeScalProdEqualityFct(Solver* const solver, const std::vector& pre_vars, - const std::vector& pre_coefs, int64 cst) { + const std::vector& pre_coefs, + int64 cst) { int64 constant = 0; std::vector vars; std::vector coefs; @@ -2665,8 +2700,8 @@ IntExpr* MakeSumArrayAux(Solver* const solver, const std::vector& vars, solver->AddConstraint( solver->RevAlloc(new SumConstraint(solver, vars, sum_var))); } - solver->Cache()->InsertVarArrayExpression(sum_var, vars, - ModelCache::VAR_ARRAY_SUM); + solver->Cache() + ->InsertVarArrayExpression(sum_var, vars, ModelCache::VAR_ARRAY_SUM); return solver->MakeSum(sum_var, constant); } } @@ -2718,9 +2753,9 @@ IntExpr* MakeScalProdAux(Solver* solver, const std::vector& vars, if (AreAllPositive(coefs)) { if (vars.size() > 8) { return solver->MakeSum( - solver->RegisterIntExpr( - solver->RevAlloc(new PositiveBooleanScalProd( - solver, vars, coefs)))->Var(), + solver->RegisterIntExpr(solver->RevAlloc( + new PositiveBooleanScalProd(solver, vars, coefs))) + ->Var(), constant); } else { return solver->MakeSum( @@ -2980,7 +3015,8 @@ Constraint* Solver::MakeMaxEquality(const std::vector& vars, } } -Constraint* Solver::MakeSumLessOrEqual(const std::vector& vars, int64 cst) { +Constraint* Solver::MakeSumLessOrEqual(const std::vector& vars, + int64 cst) { const int size = vars.size(); if (cst == 1LL && AreAllBooleans(vars) && size > 2) { return RevAlloc(new SumBooleanLessOrEqualToOne(this, vars)); @@ -2999,7 +3035,8 @@ Constraint* Solver::MakeSumGreaterOrEqual(const std::vector& vars, } } -Constraint* Solver::MakeSumEquality(const std::vector& vars, int64 cst) { +Constraint* Solver::MakeSumEquality(const std::vector& vars, + int64 cst) { const int size = vars.size(); if (size == 0) { return cst == 0 ? MakeTrueConstraint() : MakeFalseConstraint(); @@ -3092,16 +3129,16 @@ Constraint* Solver::MakeScalProdGreaterOrEqual(const std::vector& vars, return MakeScalProdGreaterOrEqualFct(this, vars, ToInt64Vector(coeffs), cst); } -Constraint* Solver::MakeScalProdLessOrEqual(const std::vector& vars, - const std::vector& coefficients, - int64 cst) { +Constraint* Solver::MakeScalProdLessOrEqual( + const std::vector& vars, const std::vector& coefficients, + int64 cst) { DCHECK_EQ(vars.size(), coefficients.size()); return MakeScalProdLessOrEqualFct(this, vars, coefficients, cst); } -Constraint* Solver::MakeScalProdLessOrEqual(const std::vector& vars, - const std::vector& coefficients, - int64 cst) { +Constraint* Solver::MakeScalProdLessOrEqual( + const std::vector& vars, const std::vector& coefficients, + int64 cst) { DCHECK_EQ(vars.size(), coefficients.size()); return MakeScalProdLessOrEqualFct(this, vars, ToInt64Vector(coefficients), cst);