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

[ARITH] Revamp IntSet #3272

Merged
merged 10 commits into from
Jun 13, 2019
Merged

[ARITH] Revamp IntSet #3272

merged 10 commits into from
Jun 13, 2019

Conversation

tqchen
Copy link
Member

@tqchen tqchen commented Jun 1, 2019

Part of #2588

This PR revamps IntSet infrastructure to use the new Analyzer API.

  • Keep IntervalSet, remove StrideSet for now as it is not used.
  • Make IntSetAnalzyer as a sub-analyzer
  • Adapt the existing API(no API change so far, will do in subsequent PRs)
  • Add testcases

@tqchen
Copy link
Member Author

tqchen commented Jun 1, 2019

@libaax93
Copy link

libaax93 commented Jun 1, 2019

hello there..

@tqchen
Copy link
Member Author

tqchen commented Jun 4, 2019

ping reviewers

@@ -77,6 +78,7 @@ bool Analyzer::CanProveGreaterEqual(const Expr& expr, int64_t lower_bound) {
return ptr->value > lower_bound;
}
auto bd = this->const_int_bound(this->rewrite_simplify(expr));
LOG(INFO) << bd;
Copy link
Contributor

Choose a reason for hiding this comment

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

remove it or make it more informative.

Expr max_value = min(a->max_value, b->max_value);
Expr min_value = max(a->min_value, b->min_value);
if ((max_value.type().is_int() || max_value.type().is_uint()) &&
(min_value.type().is_int() || max_value.type().is_uint()) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(min_value.type().is_int() || max_value.type().is_uint()) &&
(min_value.type().is_int() || min_value.type().is_uint()) &&

if (a->IsEmpty()) return a;
if (b->IsEmpty()) return b;
if (a->IsSinglePoint()) {
// assert !b->IsSinglePoint();
Copy link
Contributor

Choose a reason for hiding this comment

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

remove comment

@tqchen
Copy link
Member Author

tqchen commented Jun 7, 2019

Thanks, @wweic for catching the problems. @sgrechanik-h @kazum @sxjscience please take another look if you have time

Copy link
Contributor

@wweic wweic left a comment

Choose a reason for hiding this comment

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

lgtm. just some typos.

include/tvm/arithmetic.h Outdated Show resolved Hide resolved
include/tvm/arithmetic.h Outdated Show resolved Hide resolved
include/tvm/arithmetic.h Outdated Show resolved Hide resolved
include/tvm/arithmetic.h Outdated Show resolved Hide resolved
return IntervalSet::make(e2, e1);
} else if (a.is_bounded()) {
if (b->IsSinglePoint()) {
if (is_zero(b->min_value)) return IntervalSet::SinglePoint(b->min_value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just return b since it is {0}?

if (is_zero(divisor)) {
LOG(FATAL) << "Modular by zero in CombineInterval Mod";
}
return IntervalSet::make(make_zero(divisor.type()), divisor - 1);
if (analyzer->CanProveGreaterEqual(divisor, 0)) {
return IntervalSet(make_zero(divisor.type()), divisor - 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

For truncated division a % b may be negative when b > 0 if a < 0, so I guess additional condition on a is required.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tqchen I understand that this may be quite difficult to fix right now, but I think that at least some kind of warning must be issued when a cannot be proved to be non-negative, like this:

LOG(WARNING) << "The expression " << a << " is assumed to be non-negative";

IntervalSet a,
IntervalSet b) {
if (a->IsSinglePoint() && b->IsSinglePoint()) {
return IntervalSet::SinglePoint(a->min_value % b->min_value);
Copy link
Contributor

Choose a reason for hiding this comment

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

% -> max

IntervalSet a,
IntervalSet b) {
if (a->IsSinglePoint() && b->IsSinglePoint()) {
return IntervalSet::SinglePoint(a->min_value % b->min_value);
Copy link
Contributor

Choose a reason for hiding this comment

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

% -> min

IntSet false_set = this->Eval(op->false_value);
return Union({false_set, true_set});

IntervalSet VisitExpr_(const Select* op) final {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need the same thing for if_then_else?

Copy link
Member Author

Choose a reason for hiding this comment

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

unlikely we will use if_then_else for indices

* \brief Symbolic interval set.
*
* \note We intentionally keep the internal of IntSet private,
as we anticipate that
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment looks unfinished

/*! \return whether interval represent nothing */
bool IsEmpty() const {
// during computations, either extreme could occur.
return is_pos_inf(min_value) || is_neg_inf(max_value);
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 we also try something like CanProve(min_value > max_value)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Was handled in the simplification logic of intersect, but could debate where we should add it

Copy link
Contributor

Choose a reason for hiding this comment

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

Such an empty set may also be created directly with a constructor, so it may be worth adding the check into the constructor. However this may be a rare case, so I don't insist.

LOG(WARNING) << "Return Everything in CombineInterval Mul";
return IntSet::everything();
DLOG(WARNING) << "Return Everything in CombineInterval Mul";
return IntervalSet::Everything();
Copy link
Contributor

@derisavi derisavi Jun 10, 2019

Choose a reason for hiding this comment

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

Seems to me that we are not handling this case: b is not a single point but we can still prove it's always non-negative or always non-positive.

The same statement applies to Combine<Div> and possibly Combine<Mod> below.

Copy link
Member Author

Choose a reason for hiding this comment

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

true, pushing for this direction might involve more thoughts(and related use-cases) let us do it in a follow up

Copy link
Contributor

Choose a reason for hiding this comment

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

fine with me to do it a follow-up. Regarding use-cases: It's sometimes hard to come up with a realistic use-case. On the other hand, when there is a missed opt opportunity, it will be time-consuming to find out that it was because of a missed rule in some fundamental infra like this.

In summary, I suggest to do it in a follow-up without worrying about a real use-case.


IntervalSet VisitExpr_(const Select* op) final {
IntervalSet true_set = this->Eval(op->true_value);
IntervalSet false_set = this->Eval(op->false_value);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible to evaluate op->true_value and op->false_value under the contexts of op->condition and NOT op->condition respectively?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we might, but need to put more thoughts into this, and check if there is any particular usecase of interest

Copy link
Contributor

Choose a reason for hiding this comment

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

I can think of this use case: message passing during InferBound where we have Select or if_then_else in the lambda expression (e.g., padding in conv, maxpool, etc.)

@tqchen
Copy link
Member Author

tqchen commented Jun 10, 2019

Thanks, @sgrechanik-h @derisavi for helpful comments! please take another look when you have time.


// Range related code
inline bool ProveEqual(Expr lhs, Expr rhs) {
return is_zero(ir::Simplify(lhs - rhs));
Copy link
Contributor

Choose a reason for hiding this comment

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

By the way, I guess ir::Simplify is the Halide simplifier. Can it be replaced we the new rewrite or canonical simplifiers in this file?

Copy link
Member Author

Choose a reason for hiding this comment

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

will do that in a follow up PR

@tqchen tqchen merged commit 153417a into apache:master Jun 13, 2019
@tqchen
Copy link
Member Author

tqchen commented Jun 13, 2019

Thanks, @derisavi @sgrechanik-h @wweic @Hzfengsy . this PR is now merged. Let us address the remaining comments in the subsequent PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants