Skip to content

virgil.priors

Priors that are invariant measures but not plain numpyro distributions: the isotropic orientation priors, uniform in cos i (orbit inclination) and in sin(lat) (a position on a sphere). Locations take Uniform, scales take LogUniform, and longitudes and nodes are uniform in their angles. See Which priors? for the full table and the reasons. hierarchical_scales draws a set of scales, such as one error scale per epoch, from a log-normal population with log-uniform hyperpriors, for use as noise= terms tied to the parameters.

Priors that are invariant measures but not plain numpyro priors.

The Haar measure on rotations is uniform in the direction of an axis on the sphere, which is not uniform in the angles virgil uses: IsotropicInclination (density ∝ sin i, so cos i is uniform) is the prior on an orbit's inclination in degrees, and IsotropicLatitude (density ∝ cos lat) that of a position on a sphere, in radians. Longitudes and nodes are uniform in their angles, so Uniform is right for them. hierarchical_scales gives a population of scale factors. All are numpyro distributions that work in the priors of fit and numpyro_model; the isotropic priors optimize in their flat coordinate (see which priors).

IsotropicInclination

Bases: _InverseCDFPrior

The inclination of an isotropically oriented axis: density ∝ sin i.

The density is sin(i) / (cos(low) - cos(high)) on [low, high], so cos i is uniform; this is the default prior on inc. Uniform(0, 180) is not isotropic (it favours face-on orbits).

Parameters:

Name Type Description Default
low float

Bounds in degrees, the unit of inc in virgil (0 to 180). Defaults: the full range.

0.0
high float

Bounds in degrees, the unit of inc in virgil (0 to 180). Defaults: the full range.

0.0
Notes

Use the full range when the data distinguish i from 180 - i (astrometry, closure phases). Use IsotropicInclination(0, 90) when only |cos i| is identifiable, as with radial velocities alone.

Examples:

>>> import jax
>>> from virgil.priors import IsotropicInclination
>>> prior = IsotropicInclination(0.0, 90.0)
>>> samples = prior.sample(jax.random.key(0), (1000,))
>>> bool(((samples >= 0.0) & (samples <= 90.0)).all())
True

mean property

__init__(low=0.0, high=180.0, *, validate_args=None)

icdf(q)

Quantile function: cos i is uniform, inverted near the nearer pole.

cdf(value)

log_prob(value)

IsotropicLatitude

Bases: _InverseCDFPrior

The latitude of an isotropically placed point: density ∝ cos(lat).

A point uniform on the sphere has sin(lat) uniform, so its latitude has density cos(lat) / (sin(high) - sin(low)). Use it for the position of a star spot (harmonix's lat argument), together with Uniform(-pi, pi) for the longitude.

Parameters:

Name Type Description Default
low float

Bounds in radians, the unit harmonix's ylm_spot uses. Defaults: -pi/2 to pi/2, the whole sphere. Convert degrees with numpy.deg2rad; the values sampled are then in radians too.

-pi / 2
high float

Bounds in radians, the unit harmonix's ylm_spot uses. Defaults: -pi/2 to pi/2, the whole sphere. Convert degrees with numpy.deg2rad; the values sampled are then in radians too.

-pi / 2

Examples:

>>> import jax
>>> from virgil.priors import IsotropicLatitude
>>> samples = IsotropicLatitude().sample(jax.random.key(0), (1000,))
>>> bool((abs(samples) <= 3.1416 / 2).all())
True

mean property

__init__(low=-np.pi / 2, high=np.pi / 2, *, validate_args=None)

icdf(q)

cdf(value)

log_prob(value)

PopulationScale dataclass

Member index of a log-normal population of scales.

Called with the dict of sampled values, it returns the member's scale s_k; see hierarchical_scales. In the centred form log_prior is the population density, which numpyro_model and fit add once per member used as a noise term. It is a frozen dataclass, so equal members compare (and hash) equal: repeated fits do not recompile.

name instance-attribute

index instance-attribute

centred = True class-attribute instance-attribute

__init__(name, index, centred=True)

__call__(values)

log_prior(values)

The member's population log density (zero when non-centred, where the standard normal prior on z_k carries it).

curvature_rows(values)

Mean and normalizer curvature rows of the centred population prior.

hierarchical_scales(name, n, median=None, spread=None, centred=True)

n positive scales drawn from a log-normal population.

log s_k is normal about log(median) with standard deviation spread; both are sampled, with log-uniform priors. Use it for nuisances that differ between epochs but share an instrument, passed as noise terms (one dict per dataset, in order). Use every member: an unused centred member has an improper flat prior. When to centre: hierarchical scales.

Parameters:

Name Type Description Default
name str

Prefix of the parameters "<name>_median", "<name>_spread" and the length-n "<name>_log" (centred) or "<name>_z".

required
n int

Number of scales, e.g. the number of epochs.

required
median Distribution

Prior on the population median (default LogUniform(0.1, 10), for error scales whose neutral value is 1).

None
spread Distribution

Prior on the standard deviation of log s (default LogUniform(0.01, 1): from 1% to a factor of e).

None
centred bool

Sample log s_k (default) or a standard normal z_k with s_k = median exp(spread z_k).

True

Returns:

Name Type Description
priors dict

The three priors, to merge into a priors dict.

scales list of PopulationScale

One callable per member, each mapping the sampled values to s_k.

Examples:

>>> import numpyro.distributions as dist
>>> from virgil.priors import hierarchical_scales
>>> priors, scales = hierarchical_scales("cp_scale", 3)
>>> sorted(priors)
['cp_scale_log', 'cp_scale_median', 'cp_scale_spread']
>>> noise = [{"phi_scale": s} for s in scales]
>>> values = {"cp_scale_median": 2.0, "cp_scale_spread": 0.5,
...           "cp_scale_log": np.log(np.array([1.0, 2.0, 4.0]))}
>>> round(float(scales[1](values)), 6)
2.0