-
-
Notifications
You must be signed in to change notification settings - Fork 148
Feature implementations: Make Variable and Graph generic to support possible symbolic differentiation #293
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
base: main
Are you sure you want to change the base?
Conversation
Hi :) Could you provide an example of how this would be used in contrast to the current implementation ? Cheers ! |
For sure!
and
But we are not there yet. I stopped the PR here, to have a discussion about current and next directions I am taking, and to stop the PR becoming too long to review. In this PR I only made the container structs generic. To have symbolic derivatives, we would further support a Variable which puts and assembles necessary derivatives nodes on the graph in a process similar to the current accumulate. the resultant Thanks |
This would be cool, however I suspect it will achieve what Enyzme does, which is making it's way into nightly soon I think. |
Absolutely enzyme will be great. I havent used it myself but have been looking forward to it for a while. I would say we are not reinventing the wheel here
Once enzyme is rolled out, I would be very glad to integrate it where we can. I imagine it would be quite fun to do some typing gymnastics with date/putcall/exercise rule stuff. |
I'd be very curious if you can come up with an example where Enzyme can't eliminate dead code, do you have a concrete one in mind? Edit: In case that you literally meant your small example above, I've implemented it here (in C, since our rust explorer is just getting updated) https://fwd.gymni.ch/ApN1pK We have double square(double x, double y) { return x * y; }
double dsquare(double x, double y) {
// d(y*x)/dy, so y is active (implicit default), x is const.
return x * __enzyme_autodiff((void *)square, enzyme_const, x, y);
} If you add define dso_local double @dsquare(double noundef %0, double %1) local_unnamed_addr #0 !dbg !30 {
call void @llvm.dbg.value(metadata double %0, metadata !31, metadata !DIExpression()), !dbg !32
call void @llvm.dbg.value(metadata double poison, metadata !33, metadata !DIExpression()), !dbg !32
%3 = fmul double %0, %0, !dbg !34
ret double %3, !dbg !35
} so it returns |
Hi @ZuseZ4 thanks for your comment, your work on integrating enzyme will be a game-changer for me. |
Ah, I think I see what you mean. The problem here is that whether it can be NaN will (in more complex cases) at some point be optimization dependent, e.g. in Debug mode your LLVM-IR will be much more complex due to the lack of optimizations, so Enzyme might also generate code where y is used (even if it cancels itself out). Also in the Rust frontend, you can't ask the backend like LLVM if something will be optimized out, that would require something like Reflection which Rust doesn't have right now. What you can do though is asking cargo to emit the IR of your functions and scan either the debug info (poison for y), or whether an argument is noundef. It's a bit hacky, but you can probably get something through a build script to work, that's the closest to reflection what we have. All in all you can do the same in Rust as in C++ in this case. Also, I assume this is just to have a nice design. If an argument ends up being unused (like here) it won't be moved/copied around, so you as a user/dev don't have to try to optimize the function argument away, LLVM already does that for you for free. |
Hi @avhz . Thanks for writing and open sourcing this project.
I would like to add symbolic differentiation capabilities to the autodiff subcrate.
There are a couple of rust-autodiff packages out there but none look as actively maintained as your package.
My end goal here is to have a procedural macro for compile-time autodiffed code generation, so that I can have autodiff without a on-heap computation graph.
This PR just extends a bunch of generic typing to the Graph/Vertex/Variable structs to support the possibility of putting expressions to Graphs. I'd be glad to hear your thoughts!