better bound positive modulo

This commit is contained in:
lperron@google.com
2012-09-06 19:20:40 +00:00
parent 82d36fde0d
commit 433768e7a7
3 changed files with 43 additions and 18 deletions

View File

@@ -2193,6 +2193,21 @@ template <class T> bool AreAllBoundOrNull(const std::vector<IntVar*>& vars,
}
return true;
}
inline int64 PosIntDivUp(int64 e, int64 v) {
if (e >= 0) {
return (e + v - 1) / v;
} else {
return -(-e / v);
}
}
inline int64 PosIntDivDown(int64 e, int64 v) {
if (e >= 0) {
return e / v;
} else {
return (e - v + 1) / v;
}
}
} // namespace operations_research
#endif // OR_TOOLS_CONSTRAINT_SOLVER_CONSTRAINT_SOLVERI_H_

View File

@@ -952,13 +952,38 @@ class PositiveBoundModulo : public Constraint {
virtual ~PositiveBoundModulo() {}
virtual void Post() {
Solver* const s = solver();
IntVar* const d = s->MakeIntVar(0, x_->Max());
s->AddConstraint(s->MakeEquality(x_, s->MakeProd(mod_, d)->Var()));
Demon* const demon =
MakeConstraintDemon0(solver(),
this,
&PositiveBoundModulo::PropagateRange,
"PropagateRange");
x_->WhenRange(demon);
mod_->WhenRange(demon);
}
virtual void InitialPropagate() {
mod_->RemoveValue(0);
PropagateRange();
}
virtual void PropagateRange() {
int64 x_min = x_->Min();
int64 x_max = x_->Max();
const int64 mod_min = mod_->Min();
const int64 mod_max = mod_->Max();
// Propagate from product to x_;
x_->SetRange(x_min / mod_max * mod_min, x_max / mod_min * mod_max);
// Propagate from x_ to product.
x_min = x_->Min();
x_max = x_->Max();
const int64 div_max = x_max / mod_min;
const int64 div_min = x_min / mod_max;
mod_->SetRange(div_max != 0 ? PosIntDivUp(x_min, div_max) : 1,
div_min != 0 ? PosIntDivDown(x_max, div_min) : mod_max);
const int64 new_div_min = PosIntDivUp(x_min, mod_max);
const int64 new_div_max = PosIntDivDown(x_max, mod_min);
x_->SetRange(new_div_min * mod_min, (new_div_max + 1) * mod_max - 1);
mod_->SetRange(x_min / (new_div_max + 1) + 1, x_max / new_div_min);
}
virtual string DebugString() const {

View File

@@ -2789,21 +2789,6 @@ string OppIntVar::DebugString() const {
// ----- Utility functions -----
int64 PosIntDivUp(int64 e, int64 v) {
if (e >= 0) {
return (e + v - 1) / v;
} else {
return -(-e / v);
}
}
int64 PosIntDivDown(int64 e, int64 v) {
if (e >= 0) {
return e / v;
} else {
return (e - v + 1) / v;
}
}
// x * c variable, optimized case
class TimesCstIntVar : public IntVar {