Summary
UNU.RAN PINV initialization fails for some shifted continuous distributions, for example Normal(100, 2).
The failure is caused by an incorrect default center used during PINV initialization. For strongly shifted distributions, the default center may be far outside the numerically meaningful region of the density.
There is also a cleanup/lifetime bug: after unur_init() consumes the parameter handle, the wrapper may try to free the same UNUR_PAR handle again, which can turn a normal initialization error into free(): invalid pointer.
Reproducer
from pysatl_core.families.configuration import configure_families_register
from pysatl_core.families.registry import ParametricFamilyRegister
from pysatl_core.sampling.unuran.core.unuran_sampling_strategy import DefaultUnuranSamplingStrategy
def sample_normal(mu: float, sigma: float, n: int) -> None:
family = ParametricFamilyRegister.get("Normal")
distribution = family.distribution(
parametrization_name="meanStd",
sampling_strategy=DefaultUnuranSamplingStrategy(),
mu=mu,
sigma=sigma,
)
print(f"sampling Normal(mu={mu}, sigma={sigma})")
values = distribution.sample(n)
print("ok", len(values))
def main() -> None:
configure_families_register()
sample_normal(20.0, 1.0, 80)
sample_normal(100.0, 2.0, 80)
if __name__ == "__main__":
main()
Actual behavior
Sampling may fail for a shifted normal distribution such as Normal(mu=100.0, sigma=2.0).
The underlying UNU.RAN error is caused by PINV checking the density at the default center. For a strongly shifted normal distribution, the density at x = 0 underflows to zero or is effectively zero. PINV then fails with an error equivalent to:
Instead of reporting only a clean initialization error, the wrapper may additionally crash with:
Root cause
There are two related problems.
1. Incorrect PINV center
For continuous distributions, the UNU.RAN PINV configuration does not pass a suitable center.
As a result, UNU.RAN uses its default center, which is 0. This is invalid or numerically unstable for distributions whose mass is far away from zero.
For example, for Normal(100, 2), evaluating the PDF at 0 underflows or gives a value indistinguishable from zero, so PINV initialization fails.
The center should be set from the distribution mean when the mean is available.
2. Double-free of consumed parameter handle
After unur_init() succeeds or takes ownership of the UNUR_PAR parameter handle, the wrapper must not free that handle manually again.
Currently, the wrapper may free a consumed UNUR_PAR handle, which can produce:
This masks the original UNU.RAN initialization problem and makes debugging harder.
Expected behavior
The reproducer should successfully sample both distributions:
sample_normal(20.0, 1.0, 80)
sample_normal(100.0, 2.0, 80)
Expected output shape:
sampling Normal(mu=20.0, sigma=1.0)
ok 80
sampling Normal(mu=100.0, sigma=2.0)
ok 80
No invalid pointer crash should occur.
Proposed fix
- For continuous distributions using PINV, set the UNU.RAN center explicitly when a valid mean is available.
- The center should be configured after registering the required callbacks and before calling
unur_init().
- Avoid freeing a
UNUR_PAR handle after it has been consumed by unur_init().
- Make ownership transfer explicit in the wrapper code to prevent similar lifetime bugs.
Acceptance criteria
- The provided reproducer works for
Normal(20, 1) and Normal(100, 2).
- PINV receives a valid center for continuous distributions when the mean is available.
- The center is set after callback registration and before
unur_init().
UNUR_PAR ownership is handled correctly.
- No double-free occurs after
unur_init() consumes the parameter handle.
- A regression test is added for a strongly shifted normal distribution.
- Initialization errors remain readable and are not masked by memory-management crashes.
Summary
UNU.RAN PINV initialization fails for some shifted continuous distributions, for example
Normal(100, 2).The failure is caused by an incorrect default center used during PINV initialization. For strongly shifted distributions, the default center may be far outside the numerically meaningful region of the density.
There is also a cleanup/lifetime bug: after
unur_init()consumes the parameter handle, the wrapper may try to free the sameUNUR_PARhandle again, which can turn a normal initialization error intofree(): invalid pointer.Reproducer
Actual behavior
Sampling may fail for a shifted normal distribution such as
Normal(mu=100.0, sigma=2.0).The underlying UNU.RAN error is caused by PINV checking the density at the default center. For a strongly shifted normal distribution, the density at
x = 0underflows to zero or is effectively zero. PINV then fails with an error equivalent to:Instead of reporting only a clean initialization error, the wrapper may additionally crash with:
Root cause
There are two related problems.
1. Incorrect PINV center
For continuous distributions, the UNU.RAN PINV configuration does not pass a suitable
center.As a result, UNU.RAN uses its default center, which is
0. This is invalid or numerically unstable for distributions whose mass is far away from zero.For example, for
Normal(100, 2), evaluating the PDF at0underflows or gives a value indistinguishable from zero, so PINV initialization fails.The center should be set from the distribution mean when the mean is available.
2. Double-free of consumed parameter handle
After
unur_init()succeeds or takes ownership of theUNUR_PARparameter handle, the wrapper must not free that handle manually again.Currently, the wrapper may free a consumed
UNUR_PARhandle, which can produce:This masks the original UNU.RAN initialization problem and makes debugging harder.
Expected behavior
The reproducer should successfully sample both distributions:
Expected output shape:
No invalid pointer crash should occur.
Proposed fix
unur_init().UNUR_PARhandle after it has been consumed byunur_init().Acceptance criteria
Normal(20, 1)andNormal(100, 2).unur_init().UNUR_PARownership is handled correctly.unur_init()consumes the parameter handle.