Exemplo n.º 1
0
    def set_reference(self, ref_info):
        """
        Sets or updates the reference pdf with the given parameter input info.

        ``ref_info`` should be a dict ``{parameter_name: [ref definition]}``, not
        ``{parameter_name: {"ref": [ref definition]}}``.

        When called after prior initialisation, not mentioning a parameter leaves
        its reference pdf unchanged, whereas explicitly setting ``ref: None`` sets
        the prior as the reference pdf.

        You can set different reference pdf's/values for different MPI processes,
        e.g. for fixing different starting points for parallel MCMC chains.
        """
        if not hasattr(self, "ref_pdf"):
            # Initialised with nan's in case ref==None: no ref -> uses prior
            self.ref_pdf = [np.nan] * self.d()
        unknown = set(ref_info).difference(self.params)
        if unknown:
            raise LoggedError(
                self.log,
                f"Cannot set reference pdf for parameter(s) {unknown}: "
                "not sampled parameters.")
        for i, p in enumerate(self.params):
            # The next if ensures correct behavious in "update call",
            # where not mentioning a parameter and making its ref None are different
            # (not changing vs setting to prior)
            if p not in ref_info:
                continue  # init: use prior; update: don't change
            ref = ref_info[p]
            # [number, number] interpreted as Gaussian
            if isinstance(ref, Sequence) and len(ref) == 2 and all(
                    isinstance(n, numbers.Number) for n in ref):
                ref = {"dist": "norm", "loc": ref[0], "scale": ref[1]}
            if isinstance(ref, numbers.Real):
                self.ref_pdf[i] = float(ref)
            elif isinstance(ref, Mapping):
                self.ref_pdf[i] = get_scipy_1d_pdf({p: ref})
            elif ref is None:
                # We only get here if explicit `param: None` mention!
                self.ref_pdf[i] = np.nan
            else:
                raise LoggedError(
                    self.log,
                    "'ref' for starting position should be None or a number"
                    ", a list of two numbers for normal mean and deviation,"
                    "or a dict with parameters for a scipy distribution.")
        # Re-set the pointlike-ref property
        if hasattr(self, "_ref_is_pointlike"):
            delattr(self, "_ref_is_pointlike")
        self.reference_is_pointlike
Exemplo n.º 2
0
    def __init__(self,
                 parameterization: Parameterization,
                 info_prior: Optional[PriorsDict] = None):
        """
        Initializes the prior and reference pdf's from the input information.
        """
        self.set_logger()
        self._parameterization = parameterization
        sampled_params_info = parameterization.sampled_params_info()
        # pdf: a list of independent components
        # in principle, separable: one per parameter
        self.params = []
        self.pdf = []
        self.ref_pdf = []
        self._ref_is_pointlike = True
        self._bounds = np.zeros((len(sampled_params_info), 2))
        for i, p in enumerate(sampled_params_info):
            self.params += [p]
            prior = sampled_params_info[p].get("prior")
            self.pdf += [get_scipy_1d_pdf({p: prior})]
            fast_logpdf = fast_logpdfs.get(self.pdf[-1].dist.name)
            if fast_logpdf:
                self.pdf[-1].logpdf = MethodType(fast_logpdf, self.pdf[-1])
            # Get the reference (1d) pdf
            ref = sampled_params_info[p].get("ref")
            # Cases: number, pdf (something, but not a number), nothing
            if isinstance(ref, Sequence) and len(ref) == 2 and all(
                    isinstance(n, numbers.Number) for n in ref):
                ref = {"dist": "norm", "loc": ref[0], "scale": ref[1]}
            if isinstance(ref, numbers.Real):
                self.ref_pdf += [float(ref)]
            elif isinstance(ref, Mapping):
                self.ref_pdf += [get_scipy_1d_pdf({p: ref})]
                self._ref_is_pointlike = False
            elif ref is None:
                self.ref_pdf += [np.nan]
                self._ref_is_pointlike = False
            else:
                raise LoggedError(
                    self.log,
                    "'ref' for starting position should be None or a number"
                    ", a list of two numbers for normal mean and deviation,"
                    "or a dict with parameters for a scipy distribution.")

            self._bounds[i] = [-np.inf, np.inf]
            try:
                self._bounds[i] = self.pdf[-1].interval(1)
            except AttributeError:
                raise LoggedError(
                    self.log, "No bounds defined for parameter '%s' "
                    "(maybe not a scipy 1d pdf).", p)
        self._uniform_indices = np.array([
            i for i, pdf in enumerate(self.pdf) if pdf.dist.name == 'uniform'
        ],
                                         dtype=int)
        self._non_uniform_indices = np.array([
            i for i in range(len(self.pdf)) if i not in self._uniform_indices
        ],
                                             dtype=int)
        self._non_uniform_logpdf = [
            self.pdf[i].logpdf for i in self._non_uniform_indices
        ]
        self._upper_limits = self._bounds[:, 1].copy()
        self._lower_limits = self._bounds[:, 0].copy()
        self._uniform_logp = -np.sum(
            np.log(self._upper_limits[self._uniform_indices] -
                   self._lower_limits[self._uniform_indices]))

        # Process the external prior(s):
        self.external = {}
        self.external_dependence = set()
        info_prior = info_prior or {}
        for name in info_prior:
            if name == prior_1d_name:
                raise LoggedError(
                    self.log, "The name '%s' is a reserved prior name. "
                    "Please use a different one.", prior_1d_name)
            self.log.debug("Loading external prior '%s' from: '%s'", name,
                           info_prior[name])
            logp = get_external_function(info_prior[name], name=name)

            argspec = getfullargspec(logp)
            known = set(parameterization.input_params())
            params = [p for p in argspec.args if p in known]
            params_without_default = set(
                argspec.args[:(len(argspec.args) -
                               len(argspec.defaults or []))])
            unknown = params_without_default - known
            if unknown:
                if unknown.intersection(parameterization.derived_params()):
                    err = (
                        "External prior '%s' has arguments %s that are output derived "
                        "parameters, Priors must be functions of input parameters. "
                        "Use a separate 'likelihood' for the prior if needed.")
                else:
                    err = (
                        "Some of the arguments of the external prior '%s' cannot be "
                        "found and don't have a default value either: %s")
                raise LoggedError(self.log, err, name, list(unknown))
            self.external_dependence.update(params)
            self.external[name] = ExternalPrior(logp=logp, params=params)
            self.mpi_warning(
                "External prior '%s' loaded. "
                "Mind that it might not be normalized!", name)

        parameterization.check_dropped(self.external_dependence)
Exemplo n.º 3
0
    def __init__(self, parameterization, info_prior=None):
        """
        Initializes the prior and reference pdf's from the input information.
        """
        self.set_logger()
        constant_params_info = parameterization.constant_params()
        sampled_params_info = parameterization.sampled_params_info()
        if not sampled_params_info:
            self.mpi_warning("No sampled parameters requested! "
                             "This will fail for non-mock samplers.")
        # pdf: a list of independent components
        # in principle, separable: one per parameter
        self.params = []
        self.pdf = []
        self.ref_pdf = []
        self._ref_is_pointlike = True
        self._bounds = np.zeros((len(sampled_params_info), 2))
        for i, p in enumerate(sampled_params_info):
            self.params += [p]
            prior = sampled_params_info[p].get(_prior)
            self.pdf += [get_scipy_1d_pdf({p: prior})]
            fast_logpdf = fast_logpdfs.get(self.pdf[-1].dist.name)
            if fast_logpdf:
                self.pdf[-1].logpdf = MethodType(fast_logpdf, self.pdf[-1])
            # Get the reference (1d) pdf
            ref = sampled_params_info[p].get(partag.ref)
            # Cases: number, pdf (something, but not a number), nothing
            if isinstance(ref, numbers.Real):
                self.ref_pdf += [float(ref)]
            elif ref is not None:
                self.ref_pdf += [get_scipy_1d_pdf({p: ref})]
                self._ref_is_pointlike = False
            else:
                self.ref_pdf += [np.nan]
                self._ref_is_pointlike = False
            self._bounds[i] = [-np.inf, np.inf]
            try:
                self._bounds[i] = self.pdf[-1].interval(1)
            except AttributeError:
                raise LoggedError(
                    self.log, "No bounds defined for parameter '%s' "
                    "(maybe not a scipy 1d pdf).", p)
        self._uniform_indices = np.array([
            i for i, pdf in enumerate(self.pdf) if pdf.dist.name == 'uniform'
        ],
                                         dtype=int)
        self._non_uniform_indices = np.array([
            i for i in range(len(self.pdf)) if i not in self._uniform_indices
        ],
                                             dtype=int)
        self._non_uniform_logpdf = [
            self.pdf[i].logpdf for i in self._non_uniform_indices
        ]
        self._upper_limits = self._bounds[:, 1].copy()
        self._lower_limits = self._bounds[:, 0].copy()
        self._uniform_logp = -np.sum(
            np.log(self._upper_limits[self._uniform_indices] -
                   self._lower_limits[self._uniform_indices]))

        # Process the external prior(s):
        self.external = {}
        for name in (info_prior if info_prior else {}):
            if name == _prior_1d_name:
                raise LoggedError(
                    self.log, "The name '%s' is a reserved prior name. "
                    "Please use a different one.", _prior_1d_name)
            self.log.debug("Loading external prior '%s' from: '%s'", name,
                           info_prior[name])
            opts = {"logp": get_external_function(info_prior[name], name=name)}
            self.external[name] = opts
            opts["argspec"] = (getfullargspec(opts["logp"]))
            opts["params"] = {
                p: list(sampled_params_info).index(p)
                for p in opts["argspec"].args if p in sampled_params_info
            }
            opts["constant_params"] = {
                p: constant_params_info[p]
                for p in opts["argspec"].args if p in constant_params_info
            }
            if (not (len(opts["params"]) + len(opts["constant_params"]))):
                raise LoggedError(
                    self.log,
                    "None of the arguments of the external prior '%s' "
                    "are known *fixed* or *sampled* parameters. "
                    "This prior recognizes: %r", name, opts["argspec"].args)
            params_without_default = opts["argspec"].args[:(
                len(opts["argspec"].args) -
                len(opts["argspec"].defaults or []))]
            if not all((p in opts["params"] or p in opts["constant_params"])
                       for p in params_without_default):
                raise LoggedError(
                    self.log,
                    "Some of the arguments of the external prior '%s' cannot "
                    "be found and don't have a default value either: %s", name,
                    list(
                        set(params_without_default).difference(
                            opts["params"]).difference(
                                opts["constant_params"])))
            self.mpi_warning(
                "External prior '%s' loaded. "
                "Mind that it might not be normalized!", name)
Exemplo n.º 4
0
 def __init__(self, parameterization, info_prior=None):
     """
     Initializes the prior and reference pdf's from the input information.
     """
     constant_params_info = parameterization.constant_params()
     sampled_params_info = parameterization.sampled_params_info()
     if not sampled_params_info:
         log.warning("No sampled parameters requested! "
                     "This will fail for non-mock samplers.")
     # pdf: a list of independent components
     # in principle, separable: one per parameter
     self.name = []
     self.pdf = []
     self.ref_pdf = []
     self._bounds = np.zeros((len(sampled_params_info), 2))
     for i, p in enumerate(sampled_params_info):
         self.name += [p]
         prior = sampled_params_info[p].get(_prior)
         self.pdf += [get_scipy_1d_pdf({p: prior})]
         fast_logpdf = fast_logpdfs.get(self.pdf[-1].dist.name)
         if fast_logpdf:
             self.pdf[-1].logpdf = MethodType(fast_logpdf, self.pdf[-1])
         # Get the reference (1d) pdf
         ref = sampled_params_info[p].get(_p_ref)
         # Cases: number, pdf (something, but not a number), nothing
         if isinstance(ref, numbers.Number):
             self.ref_pdf += [float(ref)]
         elif ref is not None:
             self.ref_pdf += [get_scipy_1d_pdf({p: ref})]
         else:
             self.ref_pdf += [np.nan]
         self._bounds[i] = [-np.inf, np.inf]
         try:
             self._bounds[i] = self.pdf[-1].interval(1)
         except AttributeError:
             log.error(
                 "No bounds defined for parameter '%s' "
                 "(maybe not a scipy 1d pdf).", p)
             raise HandledException
     # Process the external prior(s):
     self.external = odict()
     for name in (info_prior if info_prior else {}):
         if name == _prior_1d_name:
             log.error(
                 "The name '%s' is a reserved prior name. "
                 "Please use a different one.", _prior_1d_name)
             raise HandledException
         log.debug("Loading external prior '%s' from: '%s'", name,
                   info_prior[name])
         self.external[name] = ({
             "logp":
             get_external_function(info_prior[name], name=name)
         })
         self.external[name]["argspec"] = (getargspec(
             self.external[name]["logp"]))
         self.external[name]["params"] = {
             p: list(sampled_params_info).index(p)
             for p in self.external[name]["argspec"].args
             if p in sampled_params_info
         }
         self.external[name]["constant_params"] = {
             p: constant_params_info[p]
             for p in self.external[name]["argspec"].args
             if p in constant_params_info
         }
         if (not (len(self.external[name]["params"]) +
                  len(self.external[name]["constant_params"]))):
             log.error(
                 "None of the arguments of the external prior '%s' "
                 "are known *fixed* or *sampled* parameters. "
                 "This prior recognizes: %r", name,
                 self.external[name]["argspec"].args)
             raise HandledException
         params_without_default = self.external[name]["argspec"].args[:(
             len(self.external[name]["argspec"].args) -
             len(self.external[name]["argspec"].defaults or []))]
         if not all([(p in self.external[name]["params"]
                      or p in self.external[name]["constant_params"])
                     for p in params_without_default]):
             log.error(
                 "Some of the arguments of the external prior '%s' "
                 "cannot be found and don't have a default value either: %s",
                 name,
                 list(
                     set(params_without_default).difference(
                         self.external[name]["params"]).difference(
                             self.external[name]["constant_params"])))
             raise HandledException
         log.warning(
             "External prior '%s' loaded. "
             "Mind that it might not be normalized!", name)
Exemplo n.º 5
0
    def __init__(self,
                 parameterization: Parameterization,
                 info_prior: Optional[PriorsDict] = None):
        """
        Initializes the prior and reference pdf's from the input information.
        """
        self.set_logger()
        self._parameterization = parameterization
        sampled_params_info = parameterization.sampled_params_info()
        # pdf: a list of independent components
        # in principle, separable: one per parameter
        self.params = []
        self.pdf = []
        self._bounds = np.zeros((len(sampled_params_info), 2))
        for i, p in enumerate(sampled_params_info):
            self.params += [p]
            prior = sampled_params_info[p].get("prior")
            self.pdf += [get_scipy_1d_pdf({p: prior})]
            fast_logpdf = fast_logpdfs.get(self.pdf[-1].dist.name)
            if fast_logpdf:
                self.pdf[-1].logpdf = MethodType(fast_logpdf, self.pdf[-1])
            self._bounds[i] = [-np.inf, np.inf]
            try:
                self._bounds[i] = self.pdf[-1].interval(1)
            except AttributeError:
                raise LoggedError(
                    self.log, "No bounds defined for parameter '%s' "
                    "(maybe not a scipy 1d pdf).", p)
        self._uniform_indices = np.array([
            i for i, pdf in enumerate(self.pdf) if pdf.dist.name == 'uniform'
        ],
                                         dtype=int)
        self._non_uniform_indices = np.array([
            i for i in range(len(self.pdf)) if i not in self._uniform_indices
        ],
                                             dtype=int)
        self._non_uniform_logpdf = [
            self.pdf[i].logpdf for i in self._non_uniform_indices
        ]
        self._upper_limits = self._bounds[:, 1].copy()
        self._lower_limits = self._bounds[:, 0].copy()
        self._uniform_logp = -np.sum(
            np.log(self._upper_limits[self._uniform_indices] -
                   self._lower_limits[self._uniform_indices]))
        # Set the reference pdf's
        self.set_reference(
            {p: v.get("ref")
             for p, v in sampled_params_info.items()})
        # Process the external prior(s):
        self.external = {}
        self.external_dependence = set()
        info_prior = info_prior or {}
        for name in info_prior:
            if name == prior_1d_name:
                raise LoggedError(
                    self.log, "The name '%s' is a reserved prior name. "
                    "Please use a different one.", prior_1d_name)
            self.log.debug("Loading external prior '%s' from: '%s'", name,
                           info_prior[name])
            logp = get_external_function(info_prior[name], name=name)
            argspec = getfullargspec(logp)
            known = set(parameterization.input_params())
            params = [p for p in argspec.args if p in known]
            params_without_default = set(
                argspec.args[:(len(argspec.args) -
                               len(argspec.defaults or []))])
            unknown = params_without_default - known
            if unknown:
                if unknown.intersection(parameterization.derived_params()):
                    err = (
                        "External prior '%s' has arguments %s that are output derived "
                        "parameters, Priors must be functions of input parameters. "
                        "Use a separate 'likelihood' for the prior if needed.")
                else:
                    err = (
                        "Some of the arguments of the external prior '%s' cannot be "
                        "found and don't have a default value either: %s")
                raise LoggedError(self.log, err, name, list(unknown))
            self.external_dependence.update(params)
            self.external[name] = ExternalPrior(logp=logp, params=params)
            self.mpi_warning(
                "External prior '%s' loaded. "
                "Mind that it might not be normalized!", name)

        parameterization.check_dropped(self.external_dependence)