Skip to content

Conversation

zasdfgbnm
Copy link
Collaborator

@zasdfgbnm zasdfgbnm commented Dec 16, 2022

This PR implements prove::isPositive, prove::isNonNegative and improve prove::isNonZero. This PR also added a new pass eliminateTrivialPredicate to simplify compare with zero. I don't the eliminateTrivialPredicate will be super important to simplify predicates that we generate, but it is super helpful for me to write unit tests to check if these proves works as expected.

The proves prove::isPositive, prove::isNonNegative, and prove::isNonZero are very important for expression simplification because many rules require sign compatibility check:

// J) Distributivity of % over +:
//    If compatible_sign(a, b), then (a + b) % c = (a % c + b % c) % c
// K) Distributivity of % over *:
//    If compatible_sign(a, b), then (a * b) % c = (a % c * b % c) % c
// Q) If compatible_sign(a, b) and -|c| < a % c + b % c < |c|, then
//    (a+b)/c = a/c + b/c

@zasdfgbnm zasdfgbnm marked this pull request as draft December 16, 2022 20:18
@zasdfgbnm zasdfgbnm marked this pull request as ready for review December 16, 2022 20:26
@zasdfgbnm zasdfgbnm requested a review from naoyam December 16, 2022 20:36

bool NamedScalar::isTensorSize() const {
static const std::regex r(R"(T\d+\.size\[\d+\])");
return std::regex_match(name(), r);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would be fine, but why don't we add static methods to create tensor size and stride named scalars and explicitly tag them as such? That seems more robust than the string-based pattern match.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I generally agree, but I prefer to keep NamedScalar string only. We could have new subclasses of Val for values that has special meaning, for example class TensorAttribute : public Val. And I believe a good place to do this refactor is at #2282, where I need to access the .data of a global tensor.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, that would be better, and it should have a dependency connection to the tensor itself. I just don't like the string matching-based approach as it seems backward.

}
} else if (auto bop = dynamic_cast<BinaryOp*>(value->definition())) {
auto op = bop->getBinaryOpType();
if (op == BinaryOpType::Mod || op == BinaryOpType::Div ||
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are only these ops considered here? Why not, e.g., BinaryOpType::Add?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because Add and Mul are already flattened as FlattenedAssocCommOp, so we will not see BinaryOp with Add and Mul here.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Where is the fattening done? Does this function assume the value parameter is flattened?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Flatten is done before running any other passes:

auto simplified = assoc_comm::flatten(value);

So all other passes assumes the input value already flattened.

Copy link
Collaborator

Choose a reason for hiding this comment

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

OK, thanks. Could you mention that as a comment? Probably obvious to you, but it would have been definitely a helpful comment for me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, thanks. Could you mention that as a comment? Probably obvious to you, but it would have been definitely a helpful comment for me.

Oh, sorry, missed this comment. Will add to #2275

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added in dbe16cd

op == BinaryOpType::Eq && prove::isNonZero(bop->lhs(), var_info)) {
return IrBuilder::newConstant(false, DataType::Bool);
}
} else if (bop->lhs()->isZeroInt()) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Looks like the block below is mostly a duplicate of the above block. Would be great if refactored.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can not think of a more readable way to refactor this. This is like implementing a table lookup using if statements. Different branches will look similar, but each with some small modifications. To me, the most straightforward way to implement this is to just list them all.

@zasdfgbnm zasdfgbnm requested a review from naoyam January 17, 2023 00:40
Copy link
Collaborator

@naoyam naoyam left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for answering the questions.

@zasdfgbnm zasdfgbnm merged commit b0febfe into devel Jan 17, 2023
@zasdfgbnm zasdfgbnm deleted the compatible-sign-check branch January 17, 2023 23:58
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.

2 participants