-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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][RFC] Resolve cyclic dependency in Closure #4143
Comments
I also think that we should employ a cycle detector in tvm - this method can only eliminate a certain class of cycle, but there will be more as relay program grow more complex. #3423 |
@MarisaKirisame thanks for taking a stab at this. I can understand the problem, but it would be great if you could give some examples about the solution so that everyone is on the same page Ideally we want a simple enough solution that can remain stable for a while/ |
i can see the code, but still it would be great if you can add an example explaining the data structure, and how it could fix the problem :) It would also be great to discuss if we need to specifically produce different types of closure in runtime and if we could canonicalize so we only need one runtime closure |
I am confused. Coming from a PL perspective, this is obvious. I am not bragging, but everyone have different perspective, and from my perspective I suffer from curse of knowledge. We can only keep RecClosure and have its binding = nullptr for non recursive one. |
Of course it is not a curse :)It is gives you merit to educate others and makes these ideas more accessible :) I can understand what is going on in the code(via indirection) but it is also worthwhile to discuss if we can keep the closure design as minimum and discuss the choices(multiple variations of closure or the more generic one, which is more complex ), especially when it comes to the recursive support. |
@tqchen it is possible to merge the two in one and use nullptr, however the design of mutual recursion will require each recclosure to keep both a vector of closure, and index (so it cannot be merged). Hence, I think they should be seprated. It is indeed ugly, but the principled approach to dealing with this is to employ a cycle detector alongside the shared_ptr. |
The solution is in fact not obvious even from a PL perspective. Xavier Leroy, famous for his work on OCaml, outlines multiple closure representations including their handling of recursive and mutually recursive functions. |
I assume this is no longer active. |
see #4139 .
Currently, relay evaluate a function to a closure. It contain both the code of the function, and a mapping of every free variable inside that function, to the value of the free variable. when a closure is invoked, that mapping is used for the free variable. This is needed because the default approach, looking up the value from the environment (also known as dynamic binding), is buggy and will cause incorrect evaluation.
However, when a recursive closure is created, the mapping will contain value of every free variable - including the recursive function, and, subsequently, the closure itself!
I propose to add the following value, a RecValue, and a RecTable.
A RecValue is a shared_ptr of a RecTable, and a size_t index.
A RecTable is a vector of Closure.
Additionally, every closure will now have a Map<Variable, size_t> mapping, which store value of mutually recursive variable
The text was updated successfully, but these errors were encountered: