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

[Relay] Algebraic data types #2442

Merged
merged 61 commits into from
Feb 16, 2019
Merged

Conversation

slyubomirsky
Copy link
Contributor

@slyubomirsky slyubomirsky commented Jan 16, 2019

This is a rather large set of changes that will implement algebraic data types for Relay, outlined in #2175.

Note that most of this code was first written and prototyped by @MarisaKirisame . However, besides reviewing the extensive changes, there also needs to be greater test coverage and integration of ADTs into other parts of Relay (we especially anticipate changes to type unification).

Still to be done:

  • Decide on overall design/naming for ADTs
  • Decide on what should be the contents of the prelude (default ADTs) and document it
  • Fix remaining empty cases (e.g., codegen) and bugs (e.g., interpreter test for add)
  • Add test cases for ADTs in various parts of code base, esp. for interpreter

@slyubomirsky
Copy link
Contributor Author

slyubomirsky commented Jan 16, 2019

@MarisaKirisame @tqchen What would be reasonable overrides for visit_match() and visit_constructor() in python/tvm/relay/backend/graph_runtime_codegen.py? I'm unfamiliar with that code and pylint is complaining about missing overrides there. There is probably functionality to fill in for generating code for ADTs in that case

@@ -548,10 +622,23 @@ Expr TypeInferencer::Infer(Expr expr) {
return resolved_expr;
}

struct AllCheckTypePopulated : ExprVisitor {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do we need this check, by the way? Was it a problem before?

Copy link
Contributor

Choose a reason for hiding this comment

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

I forgot whether problem exist before, but this is a good postcondition we should check neverthless.

@@ -172,6 +172,20 @@ def name_hint(self):
name = self.vid.name_hint
return name

def __call__(self, *args):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Much of the ADT code assumed that the call operator for vars was overridden, so I added this to make those work. Is there a general position on operator overriding in the Python bindings? Is an override like this alright to have?

@@ -283,6 +283,12 @@ def visit_call(self, call):
def visit_op(self, _):
raise Exception("can not compile op in non-eta expanded form")

def visit_constructor(self, _):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MarisaKirisame @tqchen I am not familiar with this section of the codebase so I would need some pointers on what code should be generated for the ADT cases (tagging you because git blame showed you wrote most of this file)

Copy link
Contributor

Choose a reason for hiding this comment

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

we do not support codegen for adt. this just add more descriptive error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, I guess

Copy link
Member

Choose a reason for hiding this comment

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

It is impossible to run ADT using code on graph runtime. We should use the same error in all these cases making it clear we can not execute them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Understood, I'll change the error message.

@slyubomirsky
Copy link
Contributor Author

I think I've changed my mind about changing the names of GlobalTypeVar and TypeCall: it's probably better to keep the design general should we choose to add more features to our type system. For now, kind-checking can be used to ensure that these are only used for ADTs.

@slyubomirsky slyubomirsky changed the title [Relay][WIP] Algebraic data types [Relay] Algebraic data types Jan 23, 2019
@slyubomirsky
Copy link
Contributor Author

slyubomirsky commented Jan 23, 2019

I've reorganized and documented the prelude. Right now it only has some very basic list functions (granted, very many common functions can be implemented from folds). We should decide on a fuller picture of what to have in the prelude. Anything besides lists? What other list functions? Etc.

@MarisaKirisame
Copy link
Contributor

@slyubomirsky can you keep both nat and tree in extra.py, which basically fill them in prelude?
I need them for other testing as well.

@slyubomirsky
Copy link
Contributor Author

slyubomirsky commented Jan 23, 2019

Alright

e: Now they're back

@slyubomirsky slyubomirsky force-pushed the relay-adt branch 2 times, most recently from 86b1ea8 to 430b27d Compare January 28, 2019 21:51
@slyubomirsky
Copy link
Contributor Author

@jroesch should there be an ADT counterpart to ModuleNode::FromExpr()? I'm not sure what the use case for that would be and would appreciate any clarification.

@jroesch
Copy link
Member

jroesch commented Feb 1, 2019

@slyubomirsky I don't think so. My current feeling is we should get consensus on this code, merge and follow up.

@jroesch
Copy link
Member

jroesch commented Feb 1, 2019

@zhiics @wweic @icemelon9 could some subset of you guys review this?

Copy link
Member

@jroesch jroesch left a comment

Choose a reason for hiding this comment

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

Overall looks good to me, just a few small things and then I think we should push to merge.

@@ -106,6 +122,51 @@ def __init__(self, var, kind=Kind.Type):
self.__init_handle_by_constructor__(_make.TypeVar, var, kind)


@register_relay_node
class GlobalTypeVar(Type):
Copy link
Member

Choose a reason for hiding this comment

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

I think we should probably use a different name then GlobalTypeVar because it sounds like its a type variable and not a name, maybe we could just use TypeName? I'll mull it over.

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 wasn't sure about the name either but think global type var is possibly a good choice because we can use it for other things down the line potentially.

*
* \return List of free vars, in the PostDFS order visited by expr.
*/
tvm::Array<TypeVar> FreeTypeVars(const Expr& expr);
tvm::Array<TypeVar> FreeTypeVars(const Expr& expr, const Module& mod);
Copy link
Member

Choose a reason for hiding this comment

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

Why do we now need the module on all these functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For ADTs, we need to know if there are type vars in the definitions

Copy link
Member

Choose a reason for hiding this comment

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

Why is that? can you illustrate an example for me?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A constructor can contain type vars that are bound only in the type data. If someone uses the wrong type var in a constructor (i.e., one that is not bound in the type data), the FreeVars pass can catch that.

Might be a pain to have to pass the module for just this marginal case, though.

python/tvm/relay/ty.py Outdated Show resolved Hide resolved
include/tvm/relay/adt.h Outdated Show resolved Hide resolved
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. Some cosmetic comments.

include/tvm/relay/adt.h Outdated Show resolved Hide resolved
include/tvm/relay/adt.h Outdated Show resolved Hide resolved
python/tvm/relay/adt.py Outdated Show resolved Hide resolved
k = _ty.GlobalTypeVar(k)
if not isinstance(k, _ty.GlobalTypeVar):
raise TypeError("Expect type_definitions to be Dict[GlobalTypeVar, Type]")
type_definitions = mapped_type_defs
Copy link
Contributor

Choose a reason for hiding this comment

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

type_definitions = {}, no need to define mapped_type_defs

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would we not want to define it?

Copy link
Contributor

Choose a reason for hiding this comment

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

sorry I missed this reply. If I read correctly, lint 40 to line 44 does not change mapped_type_defs, what's the effect of the block actually?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, now I understand what you meant. I will change it, the block is supposed to set the map (that was an accidental omission).

include/tvm/relay/adt.h Outdated Show resolved Hide resolved
src/relay/pass/kind_check.cc Outdated Show resolved Hide resolved
src/relay/pass/kind_check.cc Outdated Show resolved Hide resolved
src/relay/pass/type_infer.cc Outdated Show resolved Hide resolved
@ZihengJiang ZihengJiang merged commit 2ae3124 into apache:master Feb 16, 2019
libing4752 pushed a commit to libing4752/tvm that referenced this pull request Feb 18, 2019
* First pass on ADTs

* Add doc string for tag field

* Visit constructors in TypeVisitor for TypeData

* Add to description of type call

* Add type call to type solving and unification

* Make type mutator for typecall consistent with others (only create new node if there's a change)

* Ensure kindchecking can handle type calls and typedata

* Fix bad nesting in module constructor

* Correctly construct call in typecall test

* Add call override for ordinary vars (do we want this?)

* Remove generalization hack from type inference because it was breaking ADT constructors

* Check that there are no free type vars in exprs after inferring type

* Free var checks need module because of ADT constructors

* Typecall test can't have unbound type var, make it global

* Uncomment tmap test and remove comments about failing to infer ret type; those work now

* Put in dummy visits for ADTs in graph runtime codegen to placate pylint

* Fix Relay type infer test module constructor

* Mark override for TypeCallNode in type solver

* Ensure free vars check treats patern vars as bound

* Run interpreter in more ADT test cases

* Refactor kind check to return the kind, like typechecking

* Fix invalid typecall in test

* Add kind check to type inference, do not use nulls in func_type_annotation()!

* Redundant whitespace

* Make TypeData a separate kind

* Make ADT handles a separate kind too, document calling convention better

* Remove nats and tree from prelude, move to test, document prelude

* Restore and document nat and tree to prelude, add more tree tests

* Add alpha equality tests for match cases, fix variable binding bug

* Add more kind check tests for ADTs

* Add more tests for finding free or bound vars in match exprs

* Add unification tests for type call

* Update main() for alpha equality tests

* Add simple type inference test cases for match exprs and ADT constructors

* Add more ADT interpreter tests

* Allow incomplete types when typechecking match cases

* Type inference for pattern vars should use the type annotation if it's there

* Two more specific test cases for ADT matching

* Add option ADT to prelude

* Fix broken reference to kind enum

* Fix rebase snags

* Do not attach checked types to constructors

* More docstrings for module fields

* Use proper wrapper for indexing into module type data

* checked_type for constructors is not populated

* Expand type call docstring

* Rename PatternConstructor con field

* Use error reporter for pattern constructor case

* Condense error reporting in kind check, use error reporter

* Expand docstrings and rename ADT fields

* Rename 'option' ADT to 'optional' for consistency with Python

* Add various list iterators and utility functions to prelude

* Add smoke tests for new iterators in prelude

* Add concat to prelude

* Add smoke test for concat

* Correct docstrings in prelude

* Ensure that type defs are written in module initialization

* Various requested renamings

* Correct rebase snags

* Add kind check tests for ref types

* Update the main() for kind checking tests
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
* First pass on ADTs

* Add doc string for tag field

* Visit constructors in TypeVisitor for TypeData

* Add to description of type call

* Add type call to type solving and unification

* Make type mutator for typecall consistent with others (only create new node if there's a change)

* Ensure kindchecking can handle type calls and typedata

* Fix bad nesting in module constructor

* Correctly construct call in typecall test

* Add call override for ordinary vars (do we want this?)

* Remove generalization hack from type inference because it was breaking ADT constructors

* Check that there are no free type vars in exprs after inferring type

* Free var checks need module because of ADT constructors

* Typecall test can't have unbound type var, make it global

* Uncomment tmap test and remove comments about failing to infer ret type; those work now

* Put in dummy visits for ADTs in graph runtime codegen to placate pylint

* Fix Relay type infer test module constructor

* Mark override for TypeCallNode in type solver

* Ensure free vars check treats patern vars as bound

* Run interpreter in more ADT test cases

* Refactor kind check to return the kind, like typechecking

* Fix invalid typecall in test

* Add kind check to type inference, do not use nulls in func_type_annotation()!

* Redundant whitespace

* Make TypeData a separate kind

* Make ADT handles a separate kind too, document calling convention better

* Remove nats and tree from prelude, move to test, document prelude

* Restore and document nat and tree to prelude, add more tree tests

* Add alpha equality tests for match cases, fix variable binding bug

* Add more kind check tests for ADTs

* Add more tests for finding free or bound vars in match exprs

* Add unification tests for type call

* Update main() for alpha equality tests

* Add simple type inference test cases for match exprs and ADT constructors

* Add more ADT interpreter tests

* Allow incomplete types when typechecking match cases

* Type inference for pattern vars should use the type annotation if it's there

* Two more specific test cases for ADT matching

* Add option ADT to prelude

* Fix broken reference to kind enum

* Fix rebase snags

* Do not attach checked types to constructors

* More docstrings for module fields

* Use proper wrapper for indexing into module type data

* checked_type for constructors is not populated

* Expand type call docstring

* Rename PatternConstructor con field

* Use error reporter for pattern constructor case

* Condense error reporting in kind check, use error reporter

* Expand docstrings and rename ADT fields

* Rename 'option' ADT to 'optional' for consistency with Python

* Add various list iterators and utility functions to prelude

* Add smoke tests for new iterators in prelude

* Add concat to prelude

* Add smoke test for concat

* Correct docstrings in prelude

* Ensure that type defs are written in module initialization

* Various requested renamings

* Correct rebase snags

* Add kind check tests for ref types

* Update the main() for kind checking tests
wweic pushed a commit to neo-ai/tvm that referenced this pull request Feb 20, 2019
* First pass on ADTs

* Add doc string for tag field

* Visit constructors in TypeVisitor for TypeData

* Add to description of type call

* Add type call to type solving and unification

* Make type mutator for typecall consistent with others (only create new node if there's a change)

* Ensure kindchecking can handle type calls and typedata

* Fix bad nesting in module constructor

* Correctly construct call in typecall test

* Add call override for ordinary vars (do we want this?)

* Remove generalization hack from type inference because it was breaking ADT constructors

* Check that there are no free type vars in exprs after inferring type

* Free var checks need module because of ADT constructors

* Typecall test can't have unbound type var, make it global

* Uncomment tmap test and remove comments about failing to infer ret type; those work now

* Put in dummy visits for ADTs in graph runtime codegen to placate pylint

* Fix Relay type infer test module constructor

* Mark override for TypeCallNode in type solver

* Ensure free vars check treats patern vars as bound

* Run interpreter in more ADT test cases

* Refactor kind check to return the kind, like typechecking

* Fix invalid typecall in test

* Add kind check to type inference, do not use nulls in func_type_annotation()!

* Redundant whitespace

* Make TypeData a separate kind

* Make ADT handles a separate kind too, document calling convention better

* Remove nats and tree from prelude, move to test, document prelude

* Restore and document nat and tree to prelude, add more tree tests

* Add alpha equality tests for match cases, fix variable binding bug

* Add more kind check tests for ADTs

* Add more tests for finding free or bound vars in match exprs

* Add unification tests for type call

* Update main() for alpha equality tests

* Add simple type inference test cases for match exprs and ADT constructors

* Add more ADT interpreter tests

* Allow incomplete types when typechecking match cases

* Type inference for pattern vars should use the type annotation if it's there

* Two more specific test cases for ADT matching

* Add option ADT to prelude

* Fix broken reference to kind enum

* Fix rebase snags

* Do not attach checked types to constructors

* More docstrings for module fields

* Use proper wrapper for indexing into module type data

* checked_type for constructors is not populated

* Expand type call docstring

* Rename PatternConstructor con field

* Use error reporter for pattern constructor case

* Condense error reporting in kind check, use error reporter

* Expand docstrings and rename ADT fields

* Rename 'option' ADT to 'optional' for consistency with Python

* Add various list iterators and utility functions to prelude

* Add smoke tests for new iterators in prelude

* Add concat to prelude

* Add smoke test for concat

* Correct docstrings in prelude

* Ensure that type defs are written in module initialization

* Various requested renamings

* Correct rebase snags

* Add kind check tests for ref types

* Update the main() for kind checking tests
@yzhliu yzhliu mentioned this pull request Mar 2, 2019
28 tasks
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.

7 participants