Skip to content
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

Merged
merged 6 commits into from Jan 4, 2019

Conversation

derisavi
Copy link
Contributor

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.

  • In addition to the case in which we can prove the non_divisible part is within range [0, coeff), we also handle the case where non_divisible part is a constant.
  • Tried to clarify the comments
  • added a unit testcase

@derisavi derisavi changed the title Master2 Enhanced simplification rules for Div by a positive constant Dec 27, 2018
@derisavi
Copy link
Contributor Author

Adding original reviewers @yzhliu @sgrechanik-h

}
} else {
// If we can prove that non_divisible part lies within [0, coeff), then
// that will be our r
Copy link
Member

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'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

non_divisible->base -= div_result * value;
divisible->base /= value;
divisible->base += div_result;
for (auto &e : divisible->elem) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto& e

Copy link
Contributor Author

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.
Copy link
Member

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?

Copy link
Contributor Author

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)

Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Member

@yzhliu yzhliu left a 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.
Copy link
Member

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;
Copy link
Contributor

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?

Copy link
Contributor Author

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 {};
Copy link
Contributor

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.

Copy link
Contributor Author

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.

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;
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@yzhliu yzhliu merged commit a5eb445 into apache:master Jan 4, 2019
@yzhliu
Copy link
Member

yzhliu commented Jan 4, 2019

Thanks @derisavi @sgrechanik-h Let's merge this and follow up fixing mod later. Would you mind open an issue to track? @derisavi

zhiics pushed a commit to zhiics/tvm that referenced this pull request Jan 7, 2019
…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
FrozenGene pushed a commit to FrozenGene/tvm that referenced this pull request Jan 10, 2019
…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
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
…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
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
…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
@derisavi derisavi deleted the master2 branch April 16, 2019 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ARITH] Enhance CanonicalSimplify((241+48x)/16)
3 participants