Difference between DensityDist and Potential?

I’m currently using the Potential method to define my custom likelihood. However, I can also use Densitydist and I would like to know the difference. This thread on SO explains (if I understood correctly) CDP’s use as a way to use mock observations generated by a normal rather than having to specify actual observed data. I also briefly recall fonnesbeck mentioning that that pm.Potential does not get its own node within the graph. In Pymc2, it was used to constrain the likelihood.

My question is what is the difference between Potential and DensityDist? If there is a difference, how does it affect the sampling speed and results (if any)?

1 Like

A potential allows you to add an arbitrary term to the logp function, without adding new variables to the model. It is mostly a way to cheat your way around limitations of pymc3, where the current distributions don’t allow you to do what you want easily. An example of this are some forms of truncation or censoring that aren’t supported directly atm. If you can do what you want using a DensityDist, then that is usually the best way forward.

1 Like

There is also more information in the /examples/factor_potential.py, please see below:

In short, the official use case of pm.potential is comparable to increment_log_prob in Stan (I think in the new version you can just do _logp +=?), whereas pm.DensityDist is to build your own distribution (also fine if non-normalized and only up to a constant).

Correct me if I’m wrong but this sounds like potential serves as an added term to the logp. Kind of in software programming you have:

func(): doSomething();
subfunc(): super(func); dosomethingextra();

Where the potential is equal to the subfunc. If my likelihood in the model is defined as the Potential (with no other observed= fields anywhere else) then that is the entire likelihood right? sorry if that doesn’t make much sense, I have a basic sense of how samplers work (and mainly metropolis). What I want to ask is, are the two code the same?

with pm.Model():
    a = pm.Normal('a', mu=0, sd=1, observed=y)


with pm.Model():
    a = pm.Potential('a', pm.Normal.dist(mu=0, sd=1).logp(y))

They are mostly the same, and from the point of view of the sampler they are exactly the same.
The differ when you consider functions like sample_ppc, that ask for all observed variables (‘a’ in the first example, but none in the second)

I think in pm.sample_ppc you can specify the var - it might work also for pm.Potential

[EDIT]: @aseyboldt is right, if you use pm.potential you can not do sample_ppc

@junpenglao That shouldn’t work, Potentials don’t have a random method :slight_smile:

1 Like