Hi, I was trying to setup a custom probability. Unfortunately I couldn’t find an up-to-date version of the guide, so I approximately followed the source code of the continuous distributions.
Here it is the model:
class VarianceGammaRV(RandomVariable):
# https://arxiv.org/pdf/2303.05615.pdf eq 2.20
name: str = "variance_gamma"
ndim_supp: int = 0
ndims_params: List[int] = [0, 0, 0, 0]
dtype: str = "floatX"
@classmethod
def rng_fn(
cls,
rng: np.random.RandomState,
r: np.ndarray,
theta: np.ndarray,
sigma: np.ndarray,
mu: np.ndarray,
size: Tuple[int, ...],
) -> np.ndarray:
v0 = np.sqrt(theta**2+sigma**2)
v1 = 1/(v0 + theta)
v2 = 1/(v0 - theta)
s1 = scipy.stats.gamma.rvs(r/2, v1, random_state=rng, size=size)
s2 = scipy.stats.gamma.rvs(r/2, v2, random_state=rng, size=size)
return (mu + s1 - s2)
class VarianceGamma(Continuous):
rv_op = variance_gamma
@classmethod
def dist(cls, r, theta, sigma, mu, *args, **kwargs):
r = pt.as_tensor_variable(floatX(r))
theta = pt.as_tensor_variable(floatX(theta))
sigma = pt.as_tensor_variable(floatX(sigma))
mu = pt.as_tensor_variable(floatX(mu))
return super().dist([r, theta, sigma, mu], *args, **kwargs)
def logp(value, r, theta, sigma, mu):
x = value - mu
sigma2 = sigma**2
abs_x = pt.abs(x)
s = pt.sqrt(theta**2 + sigma2)
v1 = -pt.log(sigma*pt.sqrt(np.pi))-gammaln(r/2)
v2 = theta*x/sigma2
v3 = (r-1)/2*pt.log(abs_x/(2*s))
alpha = (r-1.0)/2.0
v40 = - s*abs_x/sigma2 - 1.0/2.0*pt.log(np.pi/(2.0*s*abs_x/sigma2))
v4 = pt.switch(pt.abs(alpha)>0.0,pt.log(np.pi/2.0*(pt.iv(-alpha, s*abs_x/sigma2) - pt.iv(alpha, s*abs_x/sigma2))/pt.sin(alpha*np.pi)), v40 )
# v4 = scipy.special.kv(alpha, s*abs_x/sigma2)
res = v1 + v2 + v3 + v4
return check_parameters(
res,
r > 0,
sigma > 0,
msg="r > 0, sigma > 0",
)
The distribution seems to properly work, I both get reasonable random variables and pdf. However when I try and compute the trace I get
File ~/.local/lib/python3.11/site-packages/pymc/backends/ndarray.py:125, in NDArray._get_sampler_stats(self, varname, sampler_idx, burn, thin)
122 def _get_sampler_stats(
123 self, varname: str, sampler_idx: int, burn: int, thin: int
124 ) -> np.ndarray:
--> 125 return self._stats[sampler_idx][varname][burn::thin]
KeyError: 'tune'
I guess it has something to do with RandomVariable (maybe I should use ScipyRandomVariable, but it’s not here to me how I am supposed to handle loc/scale parameters).
Thanks!