def toTypes(thing, types, typeError='wrong type'): """Convert something to any of the given types, printing an error if impossible.""" if needs_lazy_evaluation(thing): # cannot check the type now; create proxy object to check type after evaluation return TypeChecker(thing, types, typeError) else: return coerce(thing, types, typeError)
def dependencies(self) -> List: cls = self.__class__ init_params = list(signature(cls.__init__).parameters.keys())[1:] current_vals = [self.__getattribute__(p) for p in init_params] return [ cv for cv in current_vals if needs_sampling(cv) or needs_lazy_evaluation(cv) ]
def helper(self, *args, **kwargs): from probRobScene.core.sampling import needs_sampling if any(needs_sampling(arg) for arg in itertools.chain(args, kwargs.values())): return VectorMethodDistribution(method, self, args, kwargs) elif any(needs_lazy_evaluation(arg) for arg in itertools.chain(args, kwargs.values())): # see analogous comment in distributionFunction return makeDelayedFunctionCall(helper, (self,) + args, kwargs) else: return method(self, *args, **kwargs)
def handler2(self, *args): if needs_sampling(self): return VectorOperatorDistribution(op, self, args) elif any(needs_sampling(arg) for arg in args): return VectorMethodDistribution(method, self, args, {}) elif any(needs_lazy_evaluation(arg) for arg in args): # see analogous comment in distributionFunction return makeDelayedFunctionCall(handler2, args, {}) else: return method(self, *args)
def helper(self, *args, **kwargs): args = tuple(to_distribution(arg) for arg in args) kwargs = {name: to_distribution(arg) for name, arg in kwargs.items()} if any( needs_sampling(arg) for arg in itertools.chain(args, kwargs.values())): return MethodDistribution(method, self, args, kwargs) elif any( needs_lazy_evaluation(arg) for arg in itertools.chain(args, kwargs.values())): # see analogous comment in distributionFunction return makeDelayedFunctionCall(helper, (self, ) + args, kwargs) else: return method(self, *args, **kwargs)
def to_distribution(val): """Wrap Python data types with Distributions, if necessary. For example, tuples containing Samplables need to be converted into TupleDistributions in order to keep track of dependencies properly.""" if isinstance(val, (tuple, list)): coords = [to_distribution(c) for c in val] if any(needs_sampling(c) or needs_lazy_evaluation(c) for c in coords): if isinstance(val, tuple) and hasattr(val, '_fields'): # namedtuple builder = type(val)._make else: builder = type(val) return TupleDistribution(*coords, builder=builder) return val
def helper(*args, **kwargs): args = tuple(to_distribution(arg) for arg in args) kwargs = {name: to_distribution(arg) for name, arg in kwargs.items()} if any( needs_sampling(arg) for arg in itertools.chain(args, kwargs.values())): return FunctionDistribution(method, args, kwargs, support) elif any( needs_lazy_evaluation(arg) for arg in itertools.chain(args, kwargs.values())): # recursively call this helper (not the original function), since the delayed # arguments may evaluate to distributions, in which case we'll have to make a # FunctionDistribution return makeDelayedFunctionCall(helper, args, kwargs) else: return method(*args, **kwargs)
def generate(self, max_iterations=2000, verbosity=0, feedback=None): active_reqs = [ req for req, prob in self.requirements if random.random() <= prob ] sample, iterations = rejection_sample(self.objects, self.dependencies, self.workspace, active_reqs, max_iterations, verbosity) # obtained a valid sample; assemble a scene from it sampled_objects = tuple(sample[obj] for obj in self.objects) sampled_params = {} for param, value in self.params.items(): sampled_value = sample[value] if isinstance(value, Samplable) else value assert not needs_lazy_evaluation(sampled_value) sampled_params[param] = sampled_value scene = Scene(self.workspace, sampled_objects, sampled_params) return scene, iterations
def dependencies(self) -> List: return [x for x in (self.obj, *self.args, *self.kwargs.values()) if needs_sampling(x) or needs_lazy_evaluation(x)]
def __init__(self, *args, **kwargs): self._conditioned = self # Validate specifiers name = type(self).__name__ defs = self.defaults() specifiers = list(args) + [Specifier(p, v) for p, v in kwargs.items()] properties = group_by(specifiers, lambda s: s.property) for p, specs in properties.items(): if len(specs) == 1: properties[p] = specs[0] else: spec_vals = [s.value for s in specs] regs = [sv.region for sv in spec_vals] # r1 = spec_vals[0].region # r2 = spec_vals[1].region delayed_intersection = makeDelayedFunctionCall( intersect_distribution, regs, {}) intersect_spec = Specifier(p, delayed_intersection) properties[p] = intersect_spec specifiers.append(intersect_spec) for s in specs: specifiers.remove(s) # else: # raise RuntimeParseError(f'property "{p}" of {name} specified twice (non combinable)') # TODO: dealing with duplicates part using intersections optionals = collections.defaultdict(list) for s in specifiers: relevant_opts = [o for o in s.optionals if o in defs] for opt in relevant_opts: optionals[opt].append(s) # Decide which optionals to use optionals_for_spec = collections.defaultdict(set) for opt, specs in optionals.items(): if opt in properties: continue # optionals do not override a primary specification if len(specs) > 1: raise RuntimeParseError( f'property "{opt}" of {name} specified twice (optionally)') assert len(specs) == 1 spec = specs[0] properties[opt] = spec optionals_for_spec[spec].add(opt) # Add any default specifiers needed for prop in filter(lambda x: x not in properties, defs): specifiers.append(defs[prop]) properties[prop] = defs[prop] # Topologically sort specifiers order = [] seen, done = set(), set() def dfs(spec: Specifier): if spec in done: return elif spec in seen: raise RuntimeParseError( f'specifier for property {spec.property} ' 'depends on itself') seen.add(spec) for dep in spec.requiredProperties: child = properties.get(dep) if child is None: raise RuntimeParseError( f'property {dep} required by ' f'specifier {spec} is not specified') else: dfs(child) order.append(spec) done.add(spec) for spec in specifiers: dfs(spec) assert len(order) == len(specifiers) # Evaluate and apply specifiers for spec in order: v = probRobScene.core.distributions.to_distribution( evaluate_in(spec.value, self)) assert not needs_lazy_evaluation(v) setattr(self, spec.property, v) for opt in optionals_for_spec[spec]: assert opt in spec.optionals setattr(self, opt, getattr(v, opt)) # Set up dependencies self.properties = set(properties)
def withProperties(cls, props): assert all(reqProp in props for reqProp in cls.defaults()) assert all(not needs_lazy_evaluation(val) for val in props.values()) specs = (Specifier(prop, val) for prop, val in props.items()) return cls(*specs)