Implementation:Pyro ppl Pyro SineBivariateVonMises
| Knowledge Sources | |
|---|---|
| Domains | Probability_Distributions, Directional_Statistics |
| Last Updated | 2026-02-09 09:00 GMT |
Overview
A unimodal distribution for two dependent circular random variables on the 2-torus, implementing the Sine model of the bivariate von Mises distribution.
Description
The SineBivariateVonMises distribution models the joint distribution of two dependent angles on the product of circles (S^1 x S^1). The density is given by:
C^{-1} exp(kappa_1 cos(x1 - mu_1) + kappa_2 cos(x2 - mu_2) + rho sin(x1 - mu_1) sin(x2 - mu_2))
where C is a normalizing constant computed using modified Bessel functions of the first kind.
The distribution is parameterized by:
- phi_loc and psi_loc -- location parameters for the two angles
- phi_concentration and psi_concentration -- concentration parameters (kappa_1 and kappa_2)
- correlation -- the direct correlation parameter (rho), or equivalently weighted_correlation which sets rho as
weighted_corr * sqrt(kappa_1 * kappa_2)
This is a submodel of the full bivariate von Mises distribution, known as the Sine Distribution in directional statistics (Mardia et al., 2007). It is particularly useful for modeling coupled angles such as torsion angles (phi, psi) in peptide chains for protein structure prediction.
The sampling algorithm follows Kent, Ganeiber, and Mardia (2018) using an Angular Central Gaussian envelope method with accept-reject sampling. The normalizing constant is computed via a series expansion using log-binomial coefficients and modified Bessel functions, remaining accurate for concentrations up to 10,000.
Important considerations:
- The distribution becomes bimodal when
rho^2 / (kappa_1 * kappa_2) -> 1, which causes sampling efficiency to degrade. Use the weighted_correlation parameter with a prior that avoids this regime. - The correlation and weighted_correlation parameters are mutually exclusive.
- Compatible with SVI as a likelihood but not for latent variables.
- The event shape is always
[2], representing the two angles.
Usage
Use this distribution for modeling pairs of dependent circular variables, especially for protein torsion angle modeling. Inference should be performed with NUTS or HMC using priors that keep the distribution unimodal. For SVI, use this as a likelihood only.
Code Reference
Source Location
- Repository: Pyro
- File: pyro/distributions/sine_bivariate_von_mises.py
Signature
class SineBivariateVonMises(TorchDistribution):
arg_constraints = {
"phi_loc": constraints.real,
"psi_loc": constraints.real,
"phi_concentration": constraints.positive,
"psi_concentration": constraints.positive,
"correlation": constraints.real,
}
support = constraints.independent(constraints.real, 1)
max_sample_iter = 1000
def __init__(
self,
phi_loc,
psi_loc,
phi_concentration,
psi_concentration,
correlation=None,
weighted_correlation=None,
validate_args=None,
)
Import
from pyro.distributions import SineBivariateVonMises
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| phi_loc | torch.Tensor | Yes | Location parameter for the first angle (phi). |
| psi_loc | torch.Tensor | Yes | Location parameter for the second angle (psi). |
| phi_concentration | torch.Tensor | Yes | Concentration parameter (kappa_1) for the first angle. Must be positive and at most 10,000. |
| psi_concentration | torch.Tensor | Yes | Concentration parameter (kappa_2) for the second angle. Must be positive and at most 10,000. |
| correlation | torch.Tensor or None | No | Direct correlation parameter (rho). Mutually exclusive with weighted_correlation. Exactly one must be provided. |
| weighted_correlation | torch.Tensor or None | No | Weighted correlation in [-1, 1], sets rho = weighted_corr * sqrt(kappa_1 * kappa_2). Mutually exclusive with correlation.
|
| validate_args | bool or None | No | Whether to enable argument validation. |
Outputs
| Name | Type | Description |
|---|---|---|
| sample | torch.Tensor | Samples of shape sample_shape + batch_shape + (2,), where the last dimension contains (phi, psi) angles in [-pi, pi).
|
| log_prob | torch.Tensor | Log probability density of shape sample_shape + batch_shape.
|
| mean | torch.Tensor | The mean direction (phi_loc, psi_loc) stacked along the last dimension.
|
| norm_const | torch.Tensor | Log normalizing constant, computed lazily. |
Usage Examples
Basic Usage with Direct Correlation
import torch
from pyro.distributions import SineBivariateVonMises
dist = SineBivariateVonMises(
phi_loc=torch.tensor(0.0),
psi_loc=torch.tensor(0.0),
phi_concentration=torch.tensor(5.0),
psi_concentration=torch.tensor(5.0),
correlation=torch.tensor(2.0),
)
# Sample angle pairs
samples = dist.sample(torch.Size([1000]))
print(samples.shape) # torch.Size([1000, 2])
# Compute log probability
log_p = dist.log_prob(samples)
print(log_p.shape) # torch.Size([1000])
Using Weighted Correlation for Stable Sampling
import torch
from pyro.distributions import SineBivariateVonMises
# Use weighted_correlation to avoid bimodality
dist = SineBivariateVonMises(
phi_loc=torch.tensor(1.0),
psi_loc=torch.tensor(-1.0),
phi_concentration=torch.tensor(10.0),
psi_concentration=torch.tensor(10.0),
weighted_correlation=torch.tensor(0.5),
)
samples = dist.sample(torch.Size([500]))
Batched Distribution
import torch
from pyro.distributions import SineBivariateVonMises
# Batch of 3 distributions
dist = SineBivariateVonMises(
phi_loc=torch.zeros(3),
psi_loc=torch.zeros(3),
phi_concentration=torch.tensor([2.0, 5.0, 10.0]),
psi_concentration=torch.tensor([2.0, 5.0, 10.0]),
correlation=torch.tensor([0.5, 1.0, 1.5]),
)
samples = dist.sample()
print(samples.shape) # torch.Size([3, 2])