New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhanced simplification rules for Div by a positive constant #2346
Conversation
Adding original reviewers @yzhliu @sgrechanik-h |
src/arithmetic/canonical.cc
Outdated
} | ||
} else { | ||
// If we can prove that non_divisible part lies within [0, coeff), then | ||
// that will be our r |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest to be more clear, 'that' -> 'non_divisible itself'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/arithmetic/canonical.cc
Outdated
non_divisible->base -= div_result * value; | ||
divisible->base /= value; | ||
divisible->base += div_result; | ||
for (auto &e : divisible->elem) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto& e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
// TODO(derisavi) : fix this bug. The following can be done only for Euclidean division/mod. | ||
// Therefore, it's only valid when truncated division/mod is equivalent to Euclidean one, | ||
// that is, if and only if a and v are | ||
// both negative or both positive or a is divisible by v. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, to fix, we need to first define tvm's mod operator where a and v have contrary sign?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the comment a bit more to make it more understandable.
AFAIK, TVM's semantics of div and mod is known for all signs of a and v; it's the same semantics used in C++11, i.e., div result is truncated toward zero and a%v = a - v*(a/v)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, so in my understanding, the current implement is incorrect given "a and v are of different signs and a is not divisible by v", right? Does it require large effort to fix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. It's incorrect now.
Fixing it should be straightforward. It requires new unit testcases, and possibly, reviewing some of the existing ones. I think it should be done in a separate PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah it makes sense, suggest to mark it FIXME then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
bool IntSet::can_prove_non_negative() const { | ||
if (const IntervalSet* s_int = (*this).as<IntervalSet>()) { | ||
// Any reason why we should or should not use can_prove() to implement | ||
// these functions? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess can_prove
may be more general when the boundary contains free variables (something like abs(n)
). Not sure if it really is. I would vote for using can_prove
here after checking that it doesn't lead to regressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only downside of using can_prove
I can think of is increase in compile time. Let's see what @tqchen has to say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tqchen would you please comment on the can_prove()
stuff?
Also @sgrechanik-h please help to review.
// TODO(derisavi) : fix this bug. The following can be done only for Euclidean division/mod. | ||
// Therefore, it's only valid when truncated division/mod is equivalent to Euclidean one, | ||
// that is, if and only if a and v are | ||
// both negative or both positive or a is divisible by v. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, so in my understanding, the current implement is incorrect given "a and v are of different signs and a is not divisible by v", right? Does it require large effort to fix?
/*! \return Whether the set is proved to be bigger than or equal to 0 */ | ||
bool can_prove_non_positive() const; | ||
/*! \return Whether the set is proved to be smaller than or equal to 0 */ | ||
bool can_prove_non_negative() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the comments for these two functions be swapped?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thanks for catching it. Fixed now.
// (in Euclidean division) | ||
// returns pair (q, r) if such detection is successful | ||
// returns empty vector otherwise. | ||
// Assumes that coeff is a constant integer | ||
std::vector<ComExpr> TryLinearEquation(const ComExpr& a, | ||
const Expr& coeff) { | ||
Type type = coeff.type(); | ||
int64_t value = GetConstIntValue(coeff); | ||
if (value < 0) return {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be <=
instead of <
? I fear that the compiler might crash when value == 0
and I'm not sure if there is a test for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had assumed that value cannot be zero here but it's better to check than assume. so I added a CHECK_NE(value, 0)
. Let me know please if that doesn't address your concern.
src/arithmetic/canonical.cc
Outdated
int64_t non_divisible_const = GetConstIntValue(non_divisible_res); | ||
if (numerator_is_non_neg || non_divisible_const == 0) { | ||
non_divisible_is_simplified = true; | ||
div_result = non_divisible_const / value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some doubts for the case when non_divisible_const < 0
. Could you check if there exists a test case for this or try to add a test case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch! With the above code we simplify (8x - 17) / 8
to x - 2
(assuming 8x-17>= 0). Correct answer is x-3
.
I modified the code, added comments and a new testcase.
Thanks @derisavi @sgrechanik-h Let's merge this and follow up fixing |
…2346) * Enhanced simplification rules for Div by a positive constant * Fixed my last commit to correctly interpret TVM's division as truncated division * Fixed implemenation of IntSet::can_prove_non_positive() * addressed comments by @yzhliu * addressed comments by @sgrechanik-h * addressed more comments by @yzhliu
…2346) * Enhanced simplification rules for Div by a positive constant * Fixed my last commit to correctly interpret TVM's division as truncated division * Fixed implemenation of IntSet::can_prove_non_positive() * addressed comments by @yzhliu * addressed comments by @sgrechanik-h * addressed more comments by @yzhliu
…2346) * Enhanced simplification rules for Div by a positive constant * Fixed my last commit to correctly interpret TVM's division as truncated division * Fixed implemenation of IntSet::can_prove_non_positive() * addressed comments by @yzhliu * addressed comments by @sgrechanik-h * addressed more comments by @yzhliu
…2346) * Enhanced simplification rules for Div by a positive constant * Fixed my last commit to correctly interpret TVM's division as truncated division * Fixed implemenation of IntSet::can_prove_non_positive() * addressed comments by @yzhliu * addressed comments by @sgrechanik-h * addressed more comments by @yzhliu
This resolves #2308. This is a continuation of pull request #2310 which I closed by mistakenly removing its remote branch. Please continue the discussion here.