def domainForObject(obj, ignoredProperties): """Construct a Domain for the given Scenic Object""" domains = {} for prop in obj.properties: if prop in ignoredProperties: continue value = getattr(obj, prop) if prop in normalizedProperties: value = coerce(value, normalizedProperties[prop]) # TODO improve this system... (need to get better type info in Scenic) if prop in specialDomainProperties and needsSampling(value): dom = specialDomainProperties[prop] else: dom = domainForValue(value) if dom is None: ty = underlyingType(value) print(f'WARNING: skipping property "{prop}" of unknown type {ty}') else: domains[prop] = dom # add type as additional property value = type(obj).__name__ dom = domainForValue(value) assert dom is not None assert 'type' not in domains domains['type'] = dom return Struct(domains)
def domainForValue(value): """Return a Domain for this type of Scenic value, when possible""" ty = underlyingType(value) if ty is float or ty is int: domain = scalarDomain elif ty is GTACarModel: domain = gtaModelDomain elif ty is WebotsCarModel: domain = webotsModelDomain elif ty is Color: domain = colorDomain elif canCoerceType(ty, Vector): domain = vectorDomain elif ty is str: # We can only handle strings when they come from a finite set of # possibilities; we heuristically detect that here. if isinstance(value, Options): domain = Categorical(*value.options) else: domain = None # we can't ensure the domain is finite else: domain = None # no corresponding Domain known if not needsSampling(value): # We can handle constants of unknown types, but when possible we # convert the value to a VerifAI type. value = convertToVerifaiType(value, strict=False) return Constant(value) return domain
def spaceForScenario(scenario, ignoredProperties): """Construct a FeatureSpace for the given Scenic Scenario.""" # create domains for objects assert scenario.egoObject is scenario.objects[0] doms = (domainForObject(obj, ignoredProperties) for obj in scenario.objects) objects = Struct({f'object{i}': dom for i, dom in enumerate(doms)}) # create domains for global parameters paramDoms = {} quotedParams = {} for param, value in scenario.params.items(): if param in ignoredParameters: continue dom = domainForValue(value) if dom is None: ty = underlyingType(value) print(f'WARNING: skipping param "{param}" of unknown type {ty}') else: if not param.isidentifier(): # munge quoted parameter names newparam = 'quoted_param' + str(len(quotedParams)) quotedParams[newparam] = param param = newparam paramDoms[param] = dom params = Struct(paramDoms) space = FeatureSpace({ 'objects': Feature(objects), 'params': Feature(params) }) return space, quotedParams
def Beyond(pos, offset, fromPt=None): pos = toVector(pos, 'specifier "beyond X by Y" with X not a vector') dType = underlyingType(offset) if dType is float or dType is int: offset = Vector(0, offset) elif dType is not Vector: raise RuntimeParseError('specifier "beyond X by Y" with Y not a number or vector') if fromPt is None: fromPt = ego() fromPt = toVector(fromPt, 'specifier "beyond X by Y from Z" with Z not a vector') lineOfSight = fromPt.angleTo(pos) return Specifier('position', pos.offsetRotated(lineOfSight, offset))
def leftSpecHelper(syntax, pos, dist, axis, toComponents, makeOffset): extras = set() dType = underlyingType(dist) if dType is float or dType is int: dx, dy = toComponents(dist) elif dType is Vector: dx, dy = dist else: raise RuntimeParseError(f'"{syntax} X by D" with D not a number or vector') if isinstance(pos, OrientedPoint): # TODO too strict? val = lambda self: pos.relativePosition(makeOffset(self, dx, dy)) new = DelayedArgument({axis}, val) extras.add('heading') else: pos = toVector(pos, f'specifier "{syntax} X" with X not a vector') val = lambda self: pos.offsetRotated(self.heading, makeOffset(self, dx, dy)) new = DelayedArgument({axis, 'heading'}, val) return Specifier('position', new, optionals=extras)
def convertToVerifaiType(value, strict=True): """Attempt to convert a Scenic value to a type known to Verifai""" ty = underlyingType(value) if ty is float or ty is int: return float(value) elif canCoerceType(ty, Vector): return tuple(coerce(value, Vector)) elif ty is GTACarModel: return value elif ty is WebotsCarModel: return value elif ty is CarColor: return value elif strict: # Unknown type, so give up if we're being strict raise RuntimeError( f'attempted to convert Scenic value {value} of unknown type {ty}') else: return value
def convertToVerifaiType(value, strict=True): """Attempt to convert a Scenic value to a type known to VerifAI""" ty = underlyingType(value) if ty is float or ty is int: return float(value) elif ty is list or ty is tuple: return tuple(convertToVerifaiType(e, strict=strict) for e in value) elif issubclass(ty, dict) and not needsSampling(value): return frozendict(value) elif ty is GTACarModel: return value elif ty is WebotsCarModel: return value elif ty is Color: return value elif canCoerceType(ty, Vector): return tuple(coerce(value, Vector)) elif strict: # Unknown type, so give up if we're being strict raise RuntimeError( f'attempted to convert Scenic value {value} of unknown type {ty}') else: return value
def Beyond(pos, offset, fromPt=None): """The 'beyond X by Y [from Z]' polymorphic specifier. Specifies 'position', with no dependencies. Allowed forms: beyond <vector> by <number> [from <vector>] beyond <vector> by <vector> [from <vector>] If the 'from <vector>' is omitted, the position of ego is used. """ pos = toVector(pos, 'specifier "beyond X by Y" with X not a vector') dType = underlyingType(offset) if dType is float or dType is int: offset = Vector(0, offset) elif dType is not Vector: raise RuntimeParseError('specifier "beyond X by Y" with Y not a number or vector') if fromPt is None: fromPt = ego() fromPt = toVector(fromPt, 'specifier "beyond X by Y from Z" with Z not a vector') lineOfSight = fromPt.angleTo(pos) return Specifier('position', pos.offsetRotated(lineOfSight, offset))
def spaceForScenario(scenario, ignoredProperties): """Construct a FeatureSpace for the given Scenic Scenario""" # create domains for objects assert scenario.egoObject is scenario.objects[0] doms = (domainForObject(obj, ignoredProperties) for obj in scenario.objects) objects = Struct({f'object{i}': dom for i, dom in enumerate(doms)}) # create domains for global parameters paramDoms = {} for param, value in scenario.params.items(): dom = domainForValue(value) if dom is None: ty = underlyingType(value) print(f'WARNING: skipping param "{param}" of unknown type {ty}') else: paramDoms[param] = dom params = Struct(paramDoms) return FeatureSpace({ 'objects': Feature(objects), 'params': Feature(params) })