Source code for pygacity.generate.pick

# Author: Cameron F. Abrams, <cfa22@drexel.edu>

"""
Picker and Stepper classes for parameter selection
"""

import numpy as np
from argparse import Namespace
from itertools import product

[docs] class Picker: """ Picker class for randomly selecting parameter values. """ def __init__(self, serial=0): self.rng = np.random.default_rng(serial) if serial != 0 else None
[docs] def pick_state(self, specs: dict) -> Namespace: """ Picks parameter values based on the provided specifications. Parameters ---------- specs : dict parameter specifications with picking rules Returns ------- Namespace namespace containing picked parameter values """ _pick_recursive(specs, self.rng) return Namespace(**specs)
[docs] class Stepper: """ Stepper class for iterating over parameter spaces. """ def __init__(self, specs: dict): _space_recursive(specs) self.space = Namespace(**specs) allv = [] for k in vars(self.space).values(): if not hasattr(k, '__len__'): allv.append([k]) else: allv.append(k) self.T = product(*allv) def __iter__(self): return self def __next__(self): try: t = next(self.T) resdict = {k: v for k, v in zip(vars(self.space).keys(), t)} return Namespace(**resdict) except: raise StopIteration
def _pick_recursive(specs: dict, rng: np.random.Generator | None): """ Recursively picks values in specs according to pick rules. - **between**: picks a random value between two limits - **pickfrom**/**from**: picks a random value from a given list """ if not type(specs) == dict: return for k, v in specs.items(): if type(v) == dict and 'pick' in v: pickrule = v['pick'] if rng == None: assert 'default' in v, f'Error: serial is 0 but no default for {k} is given' specs[k] = v['default'] else: if 'between' in pickrule: lims = pickrule['between'] r = rng.random() specs[k] = lims[0] + r * (lims[1] - lims[0]) if 'round' in pickrule: specs[k] = np.round(specs[k], pickrule['round']) elif 'pickfrom' in pickrule or 'from' in pickrule: domain = pickrule.get('pickfrom', pickrule.get('from', None)) if domain is None: raise ValueError('Pickrule expecting from or pickfrom') specs[k] = rng.choice(domain) if 'round' in pickrule: specs[k] = np.round(specs[k], pickrule['round']) else: raise Exception('Missing picking rule') if 'units' in v: specs[k] *= v['units'] else: _pick_recursive(v,rng) def _space_recursive(specs): if not type(specs) == dict: return for k, v in specs.items(): if type(v) == dict and 'pick' in v: pickrule = v['pick'] if 'between' in pickrule: lims = pickrule['between'] intervals = pickrule.get('intervals', 10) specs[k] = np.linspace(lims[0], lims[1], intervals) elif 'pickfrom' in pickrule: domain = pickrule['pickfrom'] specs[k] = np.array(domain) else: raise Exception('Missing picking rule') if 'units' in v: specs[k] *= v['units'] else: _space_recursive(v)