Custom Priors
Define your own log-density via two prefix forms: expression: and table:. Use them anywhere a prior string is accepted: random-effect hyperparameters, likelihood hyperparameters, or group-correlation hyperparameters.
Two Forms in One Place
| Form | Use when | Density at \(\theta\) |
|---|---|---|
expression:<code> |
You can write the log-density as a single mathematical expression. | Evaluated symbolically at runtime, using the variable theta on the internal scale. |
table: x1 ... xn | l1 ... ln |
You have the log-density tabulated on a grid (simulation, conjugate analysis, etc.). | Linear interpolation between the supplied knots (xi, li). |
Both forms are passed straight through to the C engine. pyinla does not validate the inner content (it cannot, generally); the grammar limits below come from the engine itself.
The expression: Form
The C engine has a single-expression evaluator, not a full R interpreter. Your expression must:
- Use the variable name
theta(the value on the internal scale; for iid that is the log-precision). - Return one scalar value: the log-density \(\log \pi(\theta)\).
- Be a single expression: no statements, no blocks, no conditionals.
Verified Working Forms
| Pattern | Example |
|---|---|
| Polynomial / quadratic | -theta * theta / 2 |
| Shifted normal | -(theta - 2) * (theta - 2) / 2 |
| Absolute value (Laplace) | -abs(theta) |
| Constant (improper flat) | 0 |
| Mixed math + exp | -0.00005 * exp(theta) + theta |
| Trig + log | log(cos(theta/4)^2 + 0.1) - 0.5*theta^2 |
| Standard math functions | log, exp, sqrt, abs, sin, cos, tan, ^ |
| Arithmetic operators | + - * / ^ |
Not Supported
| Pattern | Why |
|---|---|
if (theta < 0) -theta^2 else -theta^2 / 4 |
No conditionals or comparison operators. |
{ s <- exp(theta); -log(s) - s } |
No multi-statement blocks or local assignments. |
| Calls to user-defined R functions | Only the engine's built-in math functions are recognised. |
Workaround: Smooth Instead of Piecewise
If you need a mixture or piecewise feel, build it as a smooth log-sum-exp:
# Mixture of two Gaussians as a smooth log-density
'hyper': [{'prior':
'expression: log( 0.5*exp(-theta*theta/2) + 0.5*exp(-(theta-3)*(theta-3)/2) )'}]If you genuinely need step changes or piecewise definitions, switch to table:.
The table: Form
Pass a grid of theta values and the corresponding log pi(theta) values, separated by |:
'hyper': [{'prior': 'table: -3 -1 1 3 | -4.5 -1.1 -1.1 -4.5'}]- Left of the
|: the \(\theta\) grid values (n of them, ideally sorted). - Right of the
|: the log-density at each grid point. - The C engine interpolates linearly between knots.
- Outside the grid range the prior is treated as undefined (very low log-density).
- The
|separator is optional; any non-numeric token is silently dropped during parsing.
Building a Table from Your Own Log-Density
import numpy as np
grid = np.linspace(-8, 8, 101)
logp = -0.5 * grid**2 # standard normal on theta
spec = 'table: ' + ' '.join(map(str, grid)) + ' | ' + ' '.join(map(str, logp))
'hyper': [{'prior': spec}]Where You Can Use These Forms
Both prefix forms are accepted in every place pyinla takes a prior string:
- Random-effect hyperparameters:
'hyper': [{'prior': 'expression: ...'}]on any latent model entry. - Likelihood hyperparameters:
control['family']['hyper']. - Group-correlation hyperparameters:
control.group['hyper'].
pyinla's safety layer recognises the prefix and passes the whole string through unchanged; the C engine does the actual evaluation. Whatever the engine accepts, pyinla accepts.