Repository: gammapy/gammapy
Pull request #5648 (2024-12-18 17:26:37)

Adding inverse_cdf to existing priors
Splitting the sampler PR #5643 into smaller chunks with what concerns the Priors here for simplicity.

**Description**

Samplers usually benefit from LogUniform priors for the normalization for example.
`inverse_cdf` is needed for the Nested Sampling algorithm to perform random uniform sampling from [0, 1].
So all priors (uniform, gaussian, or LogUniform) need a function to transform from min, max to  [0, 1] (i.e. the inverse_cdf).



This pull request moves what existed in #5643 into this PR.
Todo list: 
- Add the inverse_cdf for the Gaussian prior
- Add tests for the inverse_cdf
- Add tests for the LogUnifom
- Update doc concerning priors with these new functions and priors


Patch:
diff --git a/gammapy/modeling/models/prior.py b/gammapy/modeling/models/prior.py
index 5e94cc7bd..c09d9158e 100644
--- a/gammapy/modeling/models/prior.py
+++ b/gammapy/modeling/models/prior.py
@@ -4,6 +4,7 @@
 import logging
 import numpy as np
 import astropy.units as u
+from scipy.stats import norm, uniform
 from gammapy.modeling import PriorParameter, PriorParameters
 from .core import ModelBase
 
@@ -156,6 +157,11 @@ class GaussianPrior(Prior):
         """Evaluate the Gaussian prior."""
         return ((value - mu) / sigma) ** 2
 
+    def _inverse_cdf(self, value):
+        """Return inverse CDF for prior."""
+        rv = norm(self.mu.value, self.sigma.value)
+        return rv.ppf(value)
+
 
 class UniformPrior(Prior):
     """Uniform Prior.
@@ -185,3 +191,8 @@ class UniformPrior(Prior):
             return 0.0
         else:
             return 1.0
+
+    def _inverse_cdf(self, value):
+        """Return inverse CDF for prior."""
+        rv = uniform(self.min.value, self.max.value - self.min.value)
+        return rv.ppf(value)


Test patch:
diff --git a/gammapy/modeling/models/tests/test_prior.py b/gammapy/modeling/models/tests/test_prior.py
index ddb5462e4..25e1d6a15 100644
--- a/gammapy/modeling/models/tests/test_prior.py
+++ b/gammapy/modeling/models/tests/test_prior.py
@@ -1,5 +1,6 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 import pytest
+import numpy as np
 from numpy.testing import assert_allclose
 import astropy.units as u
 from gammapy.modeling.models import PRIOR_REGISTRY, GaussianPrior, Model, UniformPrior
@@ -12,13 +13,17 @@ TEST_PRIORS = [
         val_at_0=16.0,
         val_at_1=9.0,
         val_with_weight_2=32.0,
+        inverse_cdf_at_0=-np.inf,
+        inverse_cdf_at_1=np.inf,
     ),
     dict(
         name="uni",
-        model=UniformPrior(min=0.0),
+        model=UniformPrior(min=0.0, max=10),
         val_at_0=1.0,
         val_at_1=0.0,
         val_with_weight_2=2.0,
+        inverse_cdf_at_0=0.0,
+        inverse_cdf_at_1=10.0,
     ),
 ]
 
@@ -38,6 +43,11 @@ def test_priors(prior):
     value_0_weight = model(0.0 * u.Unit(""))
     assert_allclose(value_0_weight, prior["val_with_weight_2"], rtol=1e-7)
 
+    value_0 = model._inverse_cdf(0.0)
+    value_1 = model._inverse_cdf(1.0)
+    assert_allclose(value_0, prior["inverse_cdf_at_0"], rtol=1e-7)
+    assert_allclose(value_1, prior["inverse_cdf_at_1"], rtol=1e-7)
+
 
 def test_to_from_dict():
     prior = TEST_PRIORS[1]