def _ensure_fieldarray(params): """Ensures the given params are a ``FieldArray``. Parameters ---------- params : dict, FieldArray, numpy.record, or numpy.ndarray If the given object is a dict, it will be converted to a FieldArray. Returns ------- params : FieldArray The given values as a FieldArray. return_atomic : bool Whether or not functions run on the parameters should be returned as atomic types or not. """ if isinstance(params, dict): return_atomic = not any( isinstance(val, numpy.ndarray) for val in params.values()) params = FieldArray.from_kwargs(**params) elif isinstance(params, numpy.record): return_atomic = True params = FieldArray.from_records(tuple(params), names=params.dtype.names) elif isinstance(params, numpy.ndarray): return_atomic = False params = params.view(type=FieldArray) elif isinstance(params, FieldArray): return_atomic = False else: raise ValueError("params must be either dict, FieldArray, " "record, or structured array") return params, return_atomic
def rvs(self, size=1): """ Rejection samples the parameter space. """ # create output FieldArray dtype = [(arg, float) for arg in self.variable_args] out = FieldArray(size, dtype=dtype) # loop until enough samples accepted remaining = size ndraw = size while remaining: # scratch space for evaluating constraints scratch = FieldArray(ndraw, dtype=dtype) for dist in self.distributions: # drawing samples from the distributions is generally faster # then evaluating constrants, so we'll always draw the full # size, even if that gives us more points than we need draw = dist.rvs(size=ndraw) for param in dist.params: scratch[param] = draw[param] # apply any constraints keep = self.contains(scratch) nkeep = keep.sum() kmin = size - remaining kmax = min(nkeep, remaining) out[kmin:kmin + kmax] = scratch[keep][:kmax] remaining = max(0, remaining - nkeep) # to try to speed up next go around, we'll increase the draw # size by the fraction of values that were kept, but cap at 1e6 ndraw = int(min(1e6, ndraw * numpy.ceil(ndraw / (nkeep + 1.)))) return out
def _ensure_fieldarray(params): """Ensures the given params are a ``FieldArray``. Parameters ---------- params : dict, FieldArray, numpy.record, or numpy.ndarray If the given object is a dict, it will be converted to a FieldArray. Returns ------- FieldArray The given values as a FieldArray. """ if isinstance(params, dict): return FieldArray.from_kwargs(**params) elif isinstance(params, numpy.record): return FieldArray.from_records(tuple(params), names=params.dtype.names) elif isinstance(params, numpy.ndarray): return params.view(type=FieldArray) elif isinstance(params, FieldArray): return params else: raise ValueError("params must be either dict, FieldArray, " "record, or structured array")
def parse_known_args(self, args=None, namespace=None): """Parse args method to handle input-file dependent arguments.""" # run parse args once to make sure the name space is populated with # the input files. We'll turn off raising NoInputFileErrors on this # pass self.no_input_file_err = True self._unset_required() opts, extra_opts = super(ResultsArgumentParser, self).parse_known_args(args, namespace) # now do it again self.no_input_file_err = False self._reset_required() opts, extra_opts = super(ResultsArgumentParser, self).parse_known_args(args, opts) # populate the parameters option if it wasn't specified if opts.parameters is None or opts.parameters == ['*']: parameters = get_common_parameters(opts.input_file, collection=self.defaultparams) # now call parse parameters action to re-populate the namespace self.actions['parameters'](self, opts, parameters) # check if we're being greedy or not elif '*' in opts.parameters: # remove the * from the parameters and the labels opts.parameters = [p for p in opts.parameters if p != '*'] opts.parameters_labels.pop('*', None) # add the rest of the parameters not used all_params = get_common_parameters(opts.input_file, collection=self.defaultparams) # extract the used parameters from the parameters option used_params = FieldArray.parse_parameters(opts.parameters, all_params) add_params = set(all_params) - set(used_params) # repopulate the name space with the additional parameters if add_params: opts.parameters += list(add_params) # update the labels opts.parameters_labels.update({p: p for p in add_params}) # parse the sampler-specific options and check for any unknowns unknown = [] for fn in opts.input_file: fp = loadfile(fn, 'r') sampler_parser, _ = fp.extra_args_parser(skip_args=self.skip_args) if sampler_parser is not None: opts, still_unknown = sampler_parser.parse_known_args( extra_opts, namespace=opts) unknown.append(set(still_unknown)) # the intersection of the unknowns are options not understood by # any of the files if len(unknown) > 0: unknown = set.intersection(*unknown) return opts, list(unknown)
def __init__(self, variable_args, *distributions, **kwargs): # store the names of the parameters defined in the distributions self.variable_args = tuple(variable_args) # store the distributions self.distributions = distributions # store the constraints on the parameters defined inside the # distributions list self._constraints = kwargs["constraints"] \ if "constraints" in kwargs.keys() else [] # store kwargs self.kwargs = kwargs # check that all of the supplied parameters are described by the given # distributions distparams = set() for dist in distributions: distparams.update(set(dist.params)) varset = set(self.variable_args) missing_params = distparams - varset if missing_params: raise ValueError("provided variable_args do not include " "parameters %s" % (','.join(missing_params)) + " which are " "required by the provided distributions") extra_params = varset - distparams if extra_params: raise ValueError("variable_args %s " % (','.join(extra_params)) + "are not in any of the provided distributions") # if there are constraints then find the renormalization factor # since a constraint will cut out part of the space # do this by random sampling the full space and find the percent # of samples rejected n_test_samples = kwargs["n_test_samples"] \ if "n_test_samples" in kwargs else int(1e6) if self._constraints: logging.info("Renormalizing distribution for constraints") # draw samples samples = {} for dist in self.distributions: draw = dist.rvs(n_test_samples) for param in dist.params: samples[param] = draw[param] samples = FieldArray.from_kwargs(**samples) # evaluate constraints result = self.contains(samples) # set new scaling factor for prior to be # the fraction of acceptances in random sampling of entire space self._pdf_scale = result.sum() / float(n_test_samples) if self._pdf_scale == 0.0: raise ValueError( "None of the random draws for pdf " "renormalization satisfied the constraints. " " You can try increasing the 'n_test_samples' keyword.") else: self._pdf_scale = 1.0 # since Distributions will return logpdf we keep the scale factor # in log scale as well for self.__call__ self._logpdf_scale = numpy.log(self._pdf_scale)