nanograv / enterprise

ENTERPRISE (Enhanced Numerical Toolbox Enabling a Robust PulsaR Inference SuitE) is a pulsar timing analysis code, aimed at noise analysis, gravitational-wave searches, and timing model analysis.
https://enterprise.readthedocs.io
MIT License
65 stars 67 forks source link

add prior initialization parameters to Parameter objects #308

Closed paulthebaker closed 2 years ago

paulthebaker commented 2 years ago

When using a LinearExp prior for log-amplitude in an UL run, it is often helpful to propose moves by drawing from a uniform distribution. This helps access to very low log-amplitudes. enterprise_extensions automatically adds a whole bunch of proposals like this when using enterprise_extensions.sampler.setup_sampler(). All of the ranges for these proposals are hardcoded. This is bad.

A better way would be for e_e to pull the prior range directly from the Parameter object. Currently, the initialization options passed to the parameter class factories are used to setup static methods for _prior and _sampler, but are then inaccessible. At initialization we could setup members of the Parameter object to store properties like Uniform.pmin or Normal.mu.

The complication is hyperparameters. I think the solution can be setup recursively, leading to something like this:

>>> X = Normal(mu=0, sigma=1)
>>> Y = Normal(mu=Uniform(pmin=-1, pmax=1), sigma=1)

[instantiate parameters as part of signals ...]

>>> X.mu
0

>>> Y.mu  # output object __repr__()
Ymean:Uniform(pmin=-1, pmax=1)

>>> Y.mu.pmin
-1

This would allow e_e to construct uniform log-amplitude proposals directly from the properties of the model parameters, rather than relying on user input or guessing.

vallis commented 2 years ago

Hmm... Not sure we should fix this on a special-case basis. Those parameters are already available:

>>> p = parameter.Uniform(pmin=1,pmax=2)
>>> p1 = p('p1')
>>> p1.prior._defaults
{'pmin': 1, 'pmax': 2}

Maybe there should be a standard way to get default parameters from Function objects.

By the way, if the limits are defined hierarchically (from other Parameters), I'm not sure you want to sample from those ranges—it may break detailed balance again.

paulthebaker commented 2 years ago

The existence of this means we don't need to change anything! The _defaults property of Function isn't well documented anywhere, it's exactly what is needed. Now that I know what I'm looking for, I found it right away. I was looking in Parameter and it's subclasses.

As for hyper-parameters, I was just hoping to access the default range in a similar way for completeness. I'm not sure exactly what the use case is, but I think this means it's already possible. I agree about the sampling of hierarchical parameters.

Currently the description of _defaults and other properties of many enterprise objects is in # comments, rather than """ docstrings. This made finding what I was looking for harder.