sbi-dev / sbi-dev/sbi

Make the `proposal` argument types explicit

Open
#2,011 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature request
Dominant language
Python
Stars
864
Forks
259
Avg merge
4d 3h
Merged PRs (30d)
5

Description

What problem does this solve?

While reading the MCMC code I kept hitting proposal: Any, first in
mcmc_posterior.py:50.
It took me a while to figure out what a proposal has to implement, and the
answer depends on where it is used:

The trainer side already writes the contract down as Optional[Union[Distribution, NeuralPosterior]] (_contracts.py:176, :202).

I would like to add a Proposal Protocol in sbi/sbi_types.py, next to SampleProposal and CustomPrior, that captures sample() and log_prob(), and use it for the sampler functions, with the existing union in check_if_proposal_has_default_x. CustomPrior already describes those two methods, so reusing or renaming it is fine with me if you prefer not to add another type.

One thing I could not decide on my own: MCMCPosterior.to() needs to(), which neither base class declares. Should the protocol include to, should NeuralPosterior declare to and log_prob, or should those calls stay as they are?

The pyright config disables the argument and attribute checks, so I am not proposing this for CI coverage. I just think the signatures should tell a reader what a proposal is. No runtime behavior changes.

Proposed solution

I would like to add a Proposal Protocol in sbi/sbi_types.py, next to SampleProposal and CustomPrior, that captures sample() and log_prob(), and use it for the sampler functions, with the existing union in check_if_proposal_has_default_x. CustomPrior already describes those two methods, so reusing or renaming it is fine with me if you prefer not to add another type.

class Proposal(Protocol):
    """Anything that can be drawn from and scored, e.g. a prior or a posterior."""

    def sample(self, sample_shape, /) -> Tensor: ...
    def log_prob(self, value, /) -> Tensor: ...

The parameters are positional-only so that both NeuralPosterior.log_prob(theta) and Distribution.log_prob(value) satisfy the protocol.
One thing I could not decide on my own: MCMCPosterior.to() needs to(), which neither base class declares. Should the protocol include to, should NeuralPosterior declare to and log_prob, or should those calls stay as they are?

This is type annotations only. No runtime behavior changes.

Alternatives you considered

No response

Additional context

No response

Contribution
  • [ x ] I would like to work on this myself.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in sbi/sbi_types.py, then inspect the proposal annotations in the listed sampler, posterior, and trainer files, especially the existing CustomPrior contract and the calls to to(). Run the referenced rejection_sampling_test.py tests and review the affected signatures; done means the proposal types communicate the required interfaces without changing runtime behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
developer-experience
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.