@@ -63,10 +63,9 @@ class Prior:
6363 If ``True``, the probability density will be rescaled
6464 accordingly and the sample is generated from the truncated
6565 distribution.
66- If ``False``, the probability density will not account for the
67- bounds, but any parameter samples outside the bounds will be set to
68- the value of the closest bound. In this case, the PDF might not match
69- the sample.
66+ If ``False``, the probability density will not be rescaled
67+ accordingly, but the sample will be generated from the truncated
68+ distribution.
7069 """
7170
7271 def __init__ (
@@ -99,7 +98,7 @@ def __init__(
9998 self ._transformation = transformation
10099 self ._bounds_truncate = bounds_truncate
101100
102- truncation = bounds if bounds_truncate else None
101+ truncation = bounds
103102 if truncation is not None :
104103 # for uniform, we don't want to implement truncation and just
105104 # adapt the distribution parameters
@@ -179,27 +178,14 @@ def sample(self, shape=None) -> np.ndarray:
179178 :return: A sample from the distribution.
180179 """
181180 raw_sample = self .distribution .sample (shape )
182- return self ._clip_to_bounds ( self . _scale_sample (raw_sample ) )
181+ return self ._scale_sample (raw_sample )
183182
184183 def _scale_sample (self , sample ):
185184 """Scale the sample to the parameter space"""
186185 # we also need to scale parameterScale* distributions, because
187186 # internally, they are handled as (unscaled) log-distributions
188187 return scale (sample , self .transformation )
189188
190- def _clip_to_bounds (self , x ) -> np .ndarray | float :
191- """Clip `x` values to bounds.
192-
193- :param x: The values to clip. Assumed to be on the parameter scale.
194- """
195- if self .bounds is None or self ._bounds_truncate :
196- return x
197-
198- return np .maximum (
199- np .minimum (self .ub_scaled , x ),
200- self .lb_scaled ,
201- )
202-
203189 @property
204190 def lb_scaled (self ) -> float :
205191 """The lower bound on the parameter scale."""
@@ -215,8 +201,8 @@ def pdf(self, x) -> np.ndarray | float:
215201
216202 :param x: The value at which to evaluate the PDF.
217203 ``x`` is assumed to be on the parameter scale.
218- :return: The value of the PDF at ``x``. Note that the PDF does
219- currently not account for the clipping at the bounds .
204+ :return: The value of the PDF at ``x``. ``x`` is assumed to be on the
205+ parameter scale .
220206 """
221207 x = unscale (x , self .transformation )
222208
@@ -239,7 +225,27 @@ def neglogprior(self, x) -> np.ndarray | float:
239225 ``x`` is assumed to be on the parameter scale.
240226 :return: The negative log-prior at ``x``.
241227 """
242- return - np .log (self .pdf (x ))
228+ # FIXME: the prior is always defined on linear scale
229+ if self ._bounds_truncate :
230+ # the truncation is handled by the distribution
231+ return - np .log (self .pdf (x ))
232+
233+ # we want to evaluate the prior on the untruncated distribution
234+ x = unscale (x , self .transformation )
235+
236+ # scale the PDF to the parameter scale
237+ if self .transformation == C .LIN :
238+ coeff = 1
239+ elif self .transformation == C .LOG10 :
240+ coeff = x * np .log (10 )
241+ elif self .transformation == C .LOG :
242+ coeff = x
243+ else :
244+ raise ValueError (f"Unknown transformation: { self .transformation } " )
245+
246+ return - np .log (
247+ self .distribution ._pdf_transformed_untruncated (x ) * coeff
248+ )
243249
244250 @staticmethod
245251 def from_par_dict (
0 commit comments