Skip to content

Replace several Ops by OpFromGraph#2110

Merged
ricardoV94 merged 5 commits into
pymc-devs:mainfrom
ricardoV94:xlogx
May 5, 2026
Merged

Replace several Ops by OpFromGraph#2110
ricardoV94 merged 5 commits into
pymc-devs:mainfrom
ricardoV94:xlogx

Conversation

@ricardoV94
Copy link
Copy Markdown
Member

@ricardoV94 ricardoV94 commented May 3, 2026

Related to #1210

These Ops are needed to hide the inner graph for easier graph rewriting, or to control autodiff. There's no need to implement new primitives for this functionality. Removing primitive Ops makes maintaining multiple backends easier, and benefits from optimizations we do do the core primitives.

I had postponed softmax because it had a custom C kernel, but with the change from it being the default I think it's fine. Numba is doing the same thing it was doing before (but less code), and libraries that may prefer direct dispatch like JAX/PyTorch/MLX continue to do so.

I adde a new SymbolicOp subclass, much in line with the prototype SymbolicRandomVariable in PyMC. It has a method to build the inner graph on demant from input types, and a simpler interface than OFG (OFG is a bit too much already, so I didn't want to extend it further, we can reconsider this).

Next we could tackle #1221, which would allow us to still work with them as objects (needed for dispatching in PyMC), but allows us to have less real Ops, and to also inline, which can be great for memory optimization / rewrites. (E.g., a MvNormal L -> covariance -> L across the RV boundary doesn't get optimized now), plus memory opt and all that. That's left for another PR though

@ricardoV94 ricardoV94 force-pushed the xlogx branch 2 times, most recently from c538541 to f02d376 Compare May 4, 2026 08:23
@ricardoV94 ricardoV94 changed the title Replace several Ops by OFG Replace several Ops by OpFromGraph May 4, 2026
@ricardoV94 ricardoV94 force-pushed the xlogx branch 3 times, most recently from 8fd0886 to 6a5a28f Compare May 4, 2026 11:20
@ricardoV94 ricardoV94 marked this pull request as ready for review May 4, 2026 18:05
@ricardoV94 ricardoV94 requested a review from jessegrabowski May 4, 2026 18:05
Copy link
Copy Markdown
Member

@jessegrabowski jessegrabowski left a comment

Choose a reason for hiding this comment

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

very cool, seems to simplify things a lot.

If I understand well, this is new SymbolicTensorOp should be used in cases when I just want to "mark" a block of computation for rewrites to reason about jointly? What is the use-case for standard OpFromGraph after this?

Comment thread tests/tensor/test_special.py Outdated
np.testing.assert_allclose(gyv, 0.0)


def test_xlogy_as_xlogx():
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

probably don't need this one

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's good to confirm we're not being bitten by that repeated input in the inner graph gotcha.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

but the tests can certainly be merged

@ricardoV94
Copy link
Copy Markdown
Member Author

If I understand well, this is new SymbolicTensorOp should be used in cases when I just want to "mark" a block of computation for rewrites to reason about jointly? What is the use-case for standard OpFromGraph after this?

This is just syntactic sugar of top of OFG with nicer API imo. If you want it to work with different types (vector, matrix, etc) you give a generative function for it. The big difference is this function lives in the Op class, whereas before it used to be a distinct floating helper.

This is pretty much the thing that SymbolicRV evolved into, so it's the product of some learning of what's needed in practice.

As I said this could be merged into OFG (or one day replace OFG), but it already has so much complex API I didn't want to burden it even more.

@ricardoV94
Copy link
Copy Markdown
Member Author

If I understand well, this is new SymbolicTensorOp should be used in cases when I just want to "mark" a block of computation for rewrites to reason about jointly?

That and custom gradients. It's the reason why xlogy and xlogyp1 are not just helpers that build the forward graph

ricardoV94 added 5 commits May 5, 2026 15:22
Adds a `print_inner_graphs` parameter to `debugprint()` with three modes:
- "auto" (default): show inner graphs except for SymbolicOp
- True: show all inner graphs
- False: hide all inner graphs

This reduces noise when printing graphs that contain SymbolicOps,
whose inner graphs are implementation details rather than user logic.
@ricardoV94 ricardoV94 merged commit d74c6c2 into pymc-devs:main May 5, 2026
66 checks passed
@ricardoV94 ricardoV94 deleted the xlogx branch May 5, 2026 14:16
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.

BUG: UserWarning: Numba will use object mode to run XlogY0' Add option not to print inner graphs in debug_print

2 participants