From cf8cc886c2cb5de8c9cfc3fceeae9a8ddad8f42d Mon Sep 17 00:00:00 2001
From: Colm Talbot <colm.talbot@ligo.org>
Date: Mon, 14 May 2018 12:09:25 +1000
Subject: [PATCH] update prob methods to allow more generic usage

---
 tupak/prior.py | 58 ++++++++++++++++++++------------------------------
 1 file changed, 23 insertions(+), 35 deletions(-)

diff --git a/tupak/prior.py b/tupak/prior.py
index 8eb15c937..bdce5908b 100644
--- a/tupak/prior.py
+++ b/tupak/prior.py
@@ -132,10 +132,8 @@ class Uniform(Prior):
 
     def prob(self, val):
         """Return the prior probability of val"""
-        if (self.minimum < val) & (val < self.maximum):
-            return 1 / self.support
-        else:
-            return 0
+        in_prior = (val >= self.minimum) & (val <= self.maximum)
+        return 1 / self.support * in_prior
 
 
 class DeltaFunction(Prior):
@@ -181,14 +179,12 @@ class PowerLaw(Prior):
 
     def prob(self, val):
         """Return the prior probability of val"""
-        if (val > self.minimum) and (val < self.maximum):
-            if self.alpha == -1:
-                return 1 / val / np.log(self.maximum / self.minimum)
-            else:
-                return val ** self.alpha * (1 + self.alpha) / (self.maximum ** (1 + self.alpha)
-                                                               - self.minimum ** (1 + self.alpha))
+        in_prior = (val >= self.minimum) & (val <= self.maximum)
+        if self.alpha == -1:
+            return np.nan_to_num(1 / val / np.log(self.maximum / self.minimum)) * in_prior
         else:
-            return 0
+            return np.nan_to_num(val ** self.alpha * (1 + self.alpha) / (self.maximum ** (1 + self.alpha)
+                                                                         - self.minimum ** (1 + self.alpha))) * in_prior
 
 
 class Cosine(Prior):
@@ -205,13 +201,10 @@ class Cosine(Prior):
         Prior.test_valid_for_rescaling(val)
         return np.arcsin(-1 + val * 2)
 
-    @staticmethod
-    def prob(val):
+    def prob(self, val):
         """Return the prior probability of val, defined over [-pi/2, pi/2]"""
-        if (val > np.minimum) and (val < np.maximum):
-            return np.cos(val) / 2
-        else:
-            return 0
+        in_prior = (val >= self.minimum) & (val <= self.maximum)
+        return np.cos(val) / 2 * in_prior
 
 
 class Sine(Prior):
@@ -226,15 +219,12 @@ class Sine(Prior):
         This maps to the inverse CDF. This has been analytically solved for this case.
         """
         Prior.test_valid_for_rescaling(val)
-        return np.arccos(-1 + val * 2)
+        return np.arccos(1 - val * 2)
 
-    @staticmethod
-    def prob(val):
+    def prob(self, val):
         """Return the prior probability of val, defined over [0, pi]"""
-        if (val > 0) and (val < np.pi):
-            return np.sin(val) / 2
-        else:
-            return 0
+        in_prior = (val >= self.minimum) & (val <= self.maximum)
+        return np.sin(val) / 2 * in_prior
 
 
 class Gaussian(Prior):
@@ -290,11 +280,9 @@ class TruncatedGaussian(Prior):
 
     def prob(self, val):
         """Return the prior probability of val"""
-        if (val > self.minimum) & (val < self.maximum):
-            return np.exp(-(self.mu - val) ** 2 / (2 * self.sigma ** 2)) / (
-                        2 * np.pi) ** 0.5 / self.sigma / self.normalisation
-        else:
-            return 0
+        in_prior = (val >= self.minimum) & (val <= self.maximum)
+        return np.exp(-(self.mu - val) ** 2 / (2 * self.sigma ** 2)) / (
+                    2 * np.pi) ** 0.5 / self.sigma / self.normalisation * in_prior
 
 
 class Interped(Prior):
@@ -302,6 +290,7 @@ class Interped(Prior):
     def __init__(self, xx, yy, minimum=None, maximum=None, name=None, latex_label=None):
         """Initialise object from arrays of x and y=p(x)"""
         Prior.__init__(self, name, latex_label)
+        all_interpolated = interp1d(x=xx, y=yy, bounds_error=False, fill_value=0)
         if minimum is None or minimum < min(xx):
             self.minimum = min(xx)
         else:
@@ -310,22 +299,21 @@ class Interped(Prior):
             self.maximum = max(xx)
         else:
             self.maximum = maximum
-        self.xx = xx[(xx > self.minimum) & (xx < self.maximum)]
-        self.yy = yy[(xx > self.minimum) & (xx < self.maximum)]
+        self.xx = np.linspace(self.minimum, self.maximum, len(xx))
+        self.yy = all_interpolated(self.xx)
         if np.trapz(self.yy, self.xx) != 1:
             logging.info('Supplied PDF is not normalised, normalising.')
         self.yy /= np.trapz(self.yy, self.xx)
         self.YY = cumtrapz(self.yy, self.xx, initial=0)
+        # Need last element of cumulative distribution to be exactly one.
+        self.YY[-1] = 1
         self.probability_density = interp1d(x=self.xx, y=self.yy, bounds_error=False, fill_value=0)
         self.cumulative_distribution = interp1d(x=self.xx, y=self.YY, bounds_error=False, fill_value=0)
         self.inverse_cumulative_distribution = interp1d(x=self.YY, y=self.xx, bounds_error=True)
 
     def prob(self, val):
         """Return the prior probability of val"""
-        if (val > self.minimum) & (val < self.maximum):
-            return self.probability_density(val)
-        else:
-            return 0
+        return self.probability_density(val)
 
     def rescale(self, val):
         """
-- 
GitLab