Skip to content

Make basic INLA interface and simple marginalisation routine #533

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

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

Michal-Novomestsky
Copy link
Contributor

@Michal-Novomestsky Michal-Novomestsky commented Jul 2, 2025

Addresses #532 and #344.

Relies on pymc-devs/pytensor#1582 and pymc-devs/pymc#7895.

Currently uses a closed-form solution for a specific case (nested normals) while awaiting pymc-devs/pytensor#1550

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Comment on lines +589 to +592
else:
dependent_rvs_dim_connections = [
(None,),
]
Copy link
Contributor Author

@Michal-Novomestsky Michal-Novomestsky Aug 12, 2025

Choose a reason for hiding this comment

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

I believe this is redundant in INLA and is only necessary for Discrete marginal stuff (and thus it is fine to define this as None). Please correct me if I'm wrong.

Copy link
Member

Choose a reason for hiding this comment

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

Yes I think in the refactor WIP PR the base marginalRV class doesn't have this property

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In lines 613-619, marginalization_op is defined consistently regardless of the MarginalRV it's built from. For compactness, I think it's fine to set it to None through this else block rather than having a seperate marginalize_constructor line?

marginalization_op = marginalize_constructor(
    inputs=inner_inputs,
    outputs=inner_outputs,
    dims_connections=dependent_rvs_dim_connections,
    dims=dims,
    **marginalize_kwargs,
)

Comment on lines +428 to +430
d = 3 # 10000 # TODO pull this from x.shape (or similar) somehow
rng = np.random.default_rng(12345)
x0 = pytensor.graph.replace.graph_replace(x0, {marginalized_vv: rng.random(d)})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not within the scope of this PR, but is there a nice (i.e. pytensor-native) way to specify an RNG vector of shape (d,) without np.random? I believe that rng.random(d) crashes when we set d = marginalized_vv.shape[0] because marginalized_vv is a pt tensor, so it's unhappy with d being something symbolic rather than an int. For now I've worked around it by hardcoding d.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If it's a one-liner fix, I'll include that in this PR of course.

Copy link
Member

Choose a reason for hiding this comment

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

pt.random.uniform(size=x0.shape)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Throws the following:

ValueError: Random variables detected in the logp graph: {uniform_rv{"(),()->()"}.out, uniform_rv{"(),()->()"}.out}.
This can happen when mixing variables from different models, or when CustomDist logp or Interval transform functions reference nonlocal variables.

Copy link
Member

Choose a reason for hiding this comment

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

That's correct the logp is now technically a stochastic function. We can allow it to be as is but perhaps better not to add randomness? Can we have a reasonable deterministic starting point?

Comment on lines +589 to +592
else:
dependent_rvs_dim_connections = [
(None,),
]
Copy link
Member

Choose a reason for hiding this comment

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

Yes I think in the refactor WIP PR the base marginalRV class doesn't have this property

@Michal-Novomestsky Michal-Novomestsky force-pushed the implement-pmx.fit-option-for-INLA-+-marginalisation-routine branch from 398979a to c6010f3 Compare August 12, 2025 11:05
@Michal-Novomestsky Michal-Novomestsky force-pushed the implement-pmx.fit-option-for-INLA-+-marginalisation-routine branch from dad163c to a473e87 Compare August 12, 2025 11:12
@Michal-Novomestsky
Copy link
Contributor Author

@maresb, @zaxtax suggested that I reach out to you about the Docs not being built. Do you have any ideas why it's failing? Thanks!

@Michal-Novomestsky
Copy link
Contributor Author

pre-commit.ci autofix

Comment on lines +26 to +30
# Check if latent field is Gaussian
if not isinstance(x.owner.op, MvNormal):
raise ValueError(
f"Latent field {x} is not instance of MvNormal. Has distribution {x.owner.op}."
)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we relax this to a warning @theorashid?

@maresb
Copy link
Collaborator

maresb commented Aug 13, 2025

@maresb, @zaxtax suggested that I reach out to you about the Docs not being built. Do you have any ideas why it's failing? Thanks!

Hey @Michal-Novomestsky, thanks for all your work here! I recently returned from travel so I'm just now catching up on my backlog.

I assume you're asking why the Read the Docs workflow is failing? Opening the CI logs and expanding the line with the error displays the following stack trace:

File "/home/docs/checkouts/readthedocs.org/user_builds/pymc-extras/envs/533/lib/python3.11/site-packages/pymc_extras/model/marginal/distributions.py", line 11, in
from pymc.distributions.multivariate import _precision_mv_normal_logp
ImportError: cannot import name '_precision_mv_normal_logp' from 'pymc.distributions.multivariate' (/home/docs/checkouts/readthedocs.org/user_builds/pymc-extras/envs/533/lib/python3.11/site-packages/pymc/distributions/multivariate.py)

Is this helpful?

@Michal-Novomestsky
Copy link
Contributor Author

Michal-Novomestsky commented Aug 13, 2025

I assume you're asking why the Read the Docs workflow is failing? Opening the CI logs and expanding the line with the error displays the following stack trace:

File "/home/docs/checkouts/readthedocs.org/user_builds/pymc-extras/envs/533/lib/python3.11/site-packages/pymc_extras/model/marginal/distributions.py", line 11, in
from pymc.distributions.multivariate import _precision_mv_normal_logp
ImportError: cannot import name '_precision_mv_normal_logp' from 'pymc.distributions.multivariate' (/home/docs/checkouts/readthedocs.org/user_builds/pymc-extras/envs/533/lib/python3.11/site-packages/pymc/distributions/multivariate.py)

Is this helpful?

@maresb Ah yep that makes sense - this PR is dependent on two other PRs in PyMC and Pytensor respectively, so it (and the rest of the unittests) are failing because those haven't been merged yet. Thanks for the help!

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.

4 participants