Ejemplo n.º 1
0
def RelativeTo(X, Y):
	"""The 'X relative to Y' polymorphic operator.

	Allowed forms:
		F relative to G (with at least one a field, the other a field or heading)
		<vector> relative to <oriented point> (and vice versa)
		<vector> relative to <vector>
		<heading> relative to <heading>
	"""
	xf, yf = isA(X, VectorField), isA(Y, VectorField)
	if xf or yf:
		if xf and yf and X.valueType != Y.valueType:
			raise RuntimeParseError('"X relative to Y" with X, Y fields of different types')
		fieldType = X.valueType if xf else Y.valueType
		error = '"X relative to Y" with field and value of different types'
		def helper(context):
			pos = context.position.toVector()
			xp = X[pos] if xf else toType(X, fieldType, error)
			yp = Y[pos] if yf else toType(Y, fieldType, error)
			return xp + yp
		return DelayedArgument({'position'}, helper)
	else:
		if isinstance(X, OrientedPoint):	# TODO too strict?
			if isinstance(Y, OrientedPoint):
				raise RuntimeParseError('"X relative to Y" with X, Y both oriented points')
			Y = toVector(Y, '"X relative to Y" with X an oriented point but Y not a vector')
			return X.relativize(Y)
		elif isinstance(Y, OrientedPoint):
			X = toVector(X, '"X relative to Y" with Y an oriented point but X not a vector')
			return Y.relativize(X)
		else:
			X = toTypes(X, (Vector, float), '"X relative to Y" with X neither a vector nor scalar')
			Y = toTypes(Y, (Vector, float), '"X relative to Y" with Y neither a vector nor scalar')
			return evaluateRequiringEqualTypes(lambda: X + Y, X, Y,
											   '"X relative to Y" with vector and scalar')
Ejemplo n.º 2
0
    def __init__(self, opts):
        if isinstance(opts, dict):
            options, weights = [], []
            for opt, prob in opts.items():
                if not isinstance(prob, (float, int)):
                    raise RuntimeParseError(
                        f'discrete distribution weight {prob}'
                        ' is not a constant number')
                if prob < 0:
                    raise RuntimeParseError(
                        f'discrete distribution weight {prob} is negative')
                if prob == 0:
                    continue
                options.append(opt)
                weights.append(prob)
            self.optWeights = dict(zip(options, weights))
        else:
            weights = None
            options = tuple(opts)
            self.optWeights = None
        if len(options) == 0:
            raise RuntimeParseError(
                'tried to make discrete distribution over empty domain!')

        index = self.makeSelector(len(options) - 1, weights)
        super().__init__(index, options)
Ejemplo n.º 3
0
def makeRequirement(ty, reqID, req, line):
	if evaluatingRequirement:
		raise RuntimeParseError(f'tried to use "{ty.value}" inside a requirement')
	elif currentBehavior is not None:
		raise RuntimeParseError(f'"{ty.value}" inside a behavior on line {line}')
	elif currentSimulation is not None:
		currentScenario._addDynamicRequirement(ty, req, line)
	else:	# requirement being defined at compile time
		currentScenario._addRequirement(ty, reqID, req, line, 1)
Ejemplo n.º 4
0
def mutate(*objects):		# TODO update syntax
	"""Function implementing the mutate statement."""
	if evaluatingRequirement:
		raise RuntimeParseError('used mutate statement inside a requirement')
	if len(objects) == 0:
		objects = currentScenario._objects
	for obj in objects:
		if not isinstance(obj, Object):
			raise RuntimeParseError('"mutate X" with X not an object')
		obj.mutationEnabled = True
Ejemplo n.º 5
0
def param(*quotedParams, **params):
	"""Function implementing the param statement."""
	if evaluatingRequirement:
		raise RuntimeParseError('tried to create a global parameter inside a requirement')
	elif currentSimulation is not None:
		raise RuntimeParseError('tried to create a global parameter during a simulation')
	for name, value in params.items():
		if name not in lockedParameters:
			_globalParameters[name] = toDistribution(value)
	assert len(quotedParams) % 2 == 0, quotedParams
	it = iter(quotedParams)
	for name, value in zip(it, it):
		if name not in lockedParameters:
			_globalParameters[name] = toDistribution(value)
Ejemplo n.º 6
0
def registerObject(obj):
	"""Add a Scenic object to the global list of created objects.

	This is called by the Object constructor.
	"""
	if evaluatingRequirement:
		raise RuntimeParseError('tried to create an object inside a requirement')
	elif currentBehavior is not None:
		raise RuntimeParseError('tried to create an object inside a behavior')
	elif activity > 0 or currentScenario:
		assert not evaluatingRequirement
		assert isinstance(obj, _Constructible)
		currentScenario._registerObject(obj)
		if currentSimulation:
			currentSimulation.createObject(obj)
Ejemplo n.º 7
0
    def _invokeSubBehavior(self, agent, subs, modifier=None):
        if modifier:
            if modifier.name == 'for':  # do X for Y [seconds | steps]
                timeLimit = modifier.value
                if not isinstance(timeLimit, (float, int)):
                    raise RuntimeParseError('"do X for Y" with Y not a number')
                assert modifier.terminator in (None, 'seconds', 'steps')
                if modifier.terminator != 'steps':
                    timeLimit /= veneer.currentSimulation.timestep
                startTime = veneer.currentSimulation.currentTime
                condition = lambda: veneer.currentSimulation.currentTime - startTime >= timeLimit
            elif modifier.name == 'until':  # do X until Y
                condition = modifier.value
            else:
                raise RuntimeError(
                    f'internal parsing error: impossible modifier {modifier}')

            def body(behavior, agent):
                yield from self._invokeInner(agent, subs)

            handler = lambda behavior, agent: BlockConclusion.ABORT
            yield from runTryInterrupt(self, agent, body, [condition],
                                       [handler])
        else:
            yield from self._invokeInner(agent, subs)
Ejemplo n.º 8
0
    def _start(self):
        assert self._prepared

        # Compute time limit now that we know the simulation timestep
        self._elapsedTime = 0
        self._timeLimitInSteps = self._timeLimit
        if self._timeLimitIsInSeconds:
            self._timeLimitInSteps /= veneer.currentSimulation.timestep

        veneer.startScenario(self)
        with veneer.executeInScenario(self):
            # Start compose block
            if self._compose is not None:
                if not inspect.isgeneratorfunction(self._compose):
                    from scenic.syntax.translator import composeBlock
                    raise RuntimeParseError(
                        f'"{composeBlock}" does not invoke any scenarios')
                self._runningIterator = self._compose()

            # Initialize behavior coroutines of agents
            for agent in self._agents:
                assert isinstance(agent.behavior, Behavior), agent.behavior
                agent.behavior.start(agent)
            # Initialize monitor coroutines
            for monitor in self._monitors:
                monitor.start()
Ejemplo n.º 9
0
def wrapStarredValue(value, lineno):
	if isinstance(value, TupleDistribution) or not needsSampling(value):
		return value
	elif isinstance(value, Distribution):
		return [StarredDistribution(value, lineno)]
	else:
		raise RuntimeParseError(f'iterable unpacking cannot be applied to {value}')
Ejemplo n.º 10
0
Archivo: veneer.py Proyecto: t27/Scenic
def model(namespace, modelName):
    global loadingModel
    if loadingModel:
        raise RuntimeParseError(
            f'Scenic world model itself uses the "model" statement')
    if lockedModel is not None:
        modelName = lockedModel
    try:
        loadingModel = True
        module = importlib.import_module(modelName)
    except ModuleNotFoundError as e:
        if e.name == modelName:
            raise InvalidScenarioError(
                f'could not import world model {modelName}') from None
        else:
            raise
    finally:
        loadingModel = False
    names = module.__dict__.get('__all__', None)
    if names is not None:
        for name in names:
            namespace[name] = getattr(module, name)
    else:
        for name, value in module.__dict__.items():
            if not name.startswith('_'):
                namespace[name] = value
Ejemplo n.º 11
0
def require(reqID, req, line, prob=1):
	"""Function implementing the require statement."""
	if evaluatingRequirement:
		raise RuntimeParseError('tried to create a requirement inside a requirement')
	if currentSimulation is not None:	# requirement being evaluated at runtime
		if prob >= 1 or random.random() <= prob:
			result = req()
			assert not needsSampling(result)
			if needsLazyEvaluation(result):
				raise RuntimeParseError(f'requirement on line {line} uses value'
										' undefined outside of object definition')
			if not result:
				raise RejectSimulationException(f'requirement on line {line}')
	else:	# requirement being defined at compile time
		currentScenario._addRequirement(requirements.RequirementType.require,
                                        reqID, req, line, prob)
Ejemplo n.º 12
0
def coerceToAny(thing, types, error):
	"""Coerce something into any of the given types, printing an error if impossible."""
	for ty in types:
		if canCoerce(thing, ty):
			return coerce(thing, ty, error)
	from scenic.syntax.veneer import verbosePrint
	verbosePrint(f'Failed to coerce {thing} of type {underlyingType(thing)} to {types}',
	             file=sys.stderr)
	raise RuntimeParseError(error)
Ejemplo n.º 13
0
def ego(obj=None):
	"""Function implementing loads and stores to the 'ego' pseudo-variable.

	The translator calls this with no arguments for loads, and with the source
	value for stores.
	"""
	egoObject = currentScenario._ego
	if obj is None:
		if egoObject is None:
			raise RuntimeParseError('referred to ego object not yet assigned')
	elif not isinstance(obj, Object):
		raise RuntimeParseError('tried to make non-object the ego object')
	else:
		currentScenario._ego = obj
		for scenario in runningScenarios:
			if scenario._ego is None:
				scenario._ego = obj
	return egoObject
Ejemplo n.º 14
0
 def dfs(spec):
     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)
Ejemplo n.º 15
0
def Follow(F, X, D):
	"""The 'follow <field> from <vector> for <number>' operator."""
	if not isinstance(F, VectorField):
		raise RuntimeParseError('"follow F from X for D" with F not a vector field')
	X = toVector(X, '"follow F from X for D" with X not a vector')
	D = toScalar(D, '"follow F from X for D" with D not a number')
	pos = F.followFrom(X, D)
	heading = F[pos]
	return OrientedPoint(position=pos, heading=heading)
Ejemplo n.º 16
0
    def __init__(self, *args, **kwargs):
        self.args = tuple(toDistribution(arg) for arg in args)
        self.kwargs = {
            name: toDistribution(arg)
            for name, arg in kwargs.items()
        }
        if not inspect.isgeneratorfunction(self.makeGenerator):
            raise RuntimeParseError(
                f'{self} does not take any actions'
                ' (perhaps you forgot to use "take" or "do"?)')

        # Validate arguments to the behavior
        sig = inspect.signature(self.makeGenerator)
        try:
            sig.bind(None, *args, **kwargs)
        except TypeError as e:
            raise RuntimeParseError(str(e)) from e
        Samplable.__init__(self,
                           itertools.chain(self.args, self.kwargs.values()))
        Invocable.__init__(self)
Ejemplo n.º 17
0
 def _invokeInner(self, agent, subs):
     assert len(subs) == 1
     sub = subs[0]
     if not isinstance(sub, Behavior):
         raise RuntimeParseError(f'expected a behavior, got {sub}')
     sub.start(agent)
     with veneer.executeInBehavior(sub):
         try:
             yield from sub._runningIterator
         finally:
             sub.stop()
Ejemplo n.º 18
0
def VisibleFrom(base):
	"""The 'visible from <Point>' specifier.

	Specifies 'position', with no dependencies.

	This uses the given object's 'visibleRegion' property, and so correctly
	handles the view regions of Points, OrientedPoints, and Objects.
	"""
	if not isinstance(base, Point):
		raise RuntimeParseError('specifier "visible from O" with O not a Point')
	return Specifier('position', Region.uniformPointIn(base.visibleRegion))
Ejemplo n.º 19
0
 def __init__(self, prop, value, deps=None, optionals={}, internal=False):
     self.property = prop
     self.value = toDelayedArgument(value, internal)
     if deps is None:
         deps = set()
     deps |= requiredProperties(value)
     if prop in deps:
         raise RuntimeParseError(
             f'specifier for property {prop} depends on itself')
     self.requiredProperties = deps
     self.optionals = optionals
Ejemplo n.º 20
0
def ApparentHeading(X, Y=None):
	"""The 'apparent heading of <oriented point> [from <vector>]' operator.

	If the 'from <vector>' is omitted, the position of ego is used.
	"""
	if not isinstance(X, OrientedPoint):
		raise RuntimeParseError('"apparent heading of X from Y" with X not an OrientedPoint')
	if Y is None:
		Y = ego()
	Y = toVector(Y, '"relative heading of X from Y" with Y not a vector')
	return apparentHeadingAtPoint(X.position, X.heading, Y)
Ejemplo n.º 21
0
def evaluateRequiringEqualTypes(func, thingA, thingB, typeError='type mismatch'):
	"""Evaluate the func, assuming thingA and thingB have the same type.

	If func produces a lazy value, it should not have any required properties beyond
	those of thingA and thingB."""
	if not needsLazyEvaluation(thingA) and not needsLazyEvaluation(thingB):
		if underlyingType(thingA) is not underlyingType(thingB):
			raise RuntimeParseError(typeError)
		return func()
	else:
		# cannot check the types now; create proxy object to check types after evaluation
		return TypeEqualityChecker(func, thingA, thingB, typeError)
Ejemplo n.º 22
0
	def sampleGiven(self, value):
		val = value[self.dist]
		suffix = None
		if self.coercer:
			if canCoerceType(type(val), self.valueType):
				try:
					return self.coercer(val)
				except CoercionFailure as e:
					suffix = f' ({e.args[0]})'
		elif isinstance(val, self.valueType):
			return val
		if suffix is None:
			suffix = f' (expected {self.valueType.__name__}, got {type(val).__name__})'
		raise RuntimeParseError(self.errorMessage + suffix, self.loc)
Ejemplo n.º 23
0
def CanSee(X, Y):
	"""The 'X can see Y' polymorphic operator.

	Allowed forms:
		<point> can see <object>
		<point> can see <vector>
	"""
	if not isinstance(X, Point):
		raise RuntimeParseError('"X can see Y" with X not a Point')
	if isinstance(Y, Point):
		return X.canSee(Y)
	else:
		Y = toVector(Y, '"X can see Y" with Y not a vector')
		return X.visibleRegion.containsPoint(Y)
Ejemplo n.º 24
0
    def __init__(self, requiredProperties, attributes, value):
        self.requiredProperties = set(requiredProperties)
        self.value = value

        def enabled(thing, default):
            if thing in attributes:
                attributes.remove(thing)
                return True
            else:
                return default

        self.isAdditive = enabled('additive', False)
        self.isDynamic = enabled('dynamic', False)
        for attr in attributes:
            raise RuntimeParseError(f'unknown property attribute "{attr}"')
Ejemplo n.º 25
0
def leftSpecHelper(syntax, pos, dist, axis, toComponents, makeOffset):
	extras = set()
	if canCoerce(dist, float):
		dx, dy = toComponents(coerce(dist, float))
	elif canCoerce(dist, Vector):
		dx, dy = coerce(dist, Vector)
	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.relativize(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)
Ejemplo n.º 26
0
 def _invokeInner(self, agent, subs):
     for sub in subs:
         if not isinstance(sub, DynamicScenario):
             raise RuntimeParseError(f'expected a scenario, got {sub}')
         sub._prepare()
         sub._start()
     self._subScenarios = list(subs)
     while True:
         newSubs = []
         for sub in self._subScenarios:
             terminationReason = sub._step()
             if isinstance(terminationReason, EndSimulationAction):
                 yield terminationReason
             elif terminationReason is None:
                 newSubs.append(sub)
         self._subScenarios = newSubs
         if not newSubs:
             return
         yield None
Ejemplo n.º 27
0
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))
Ejemplo n.º 28
0
def Following(field, dist, fromPt=None):
	"""The 'following F [from X] for D' specifier.

	Specifies 'position', and optionally 'heading', with no dependencies.

	Allowed forms:
		following <field> [from <vector>] for <number>

	If the 'from <vector>' is omitted, the position of ego is used.
	"""
	if fromPt is None:
		fromPt = ego()
	else:
		dist, fromPt = fromPt, dist
	if not isinstance(field, VectorField):
		raise RuntimeParseError('"following F" specifier with F not a vector field')
	fromPt = toVector(fromPt, '"following F from X for D" with X not a vector')
	dist = toScalar(dist, '"following F for D" with D not a number')
	pos = field.followFrom(fromPt, dist)
	heading = field[pos]
	val = OrientedVector.make(pos, heading)
	return Specifier('position', val, optionals={'heading'})
Ejemplo n.º 29
0
def coerce(thing, ty, error='wrong type'):
    """Coerce something into the given type."""
    assert canCoerce(thing, ty), (thing, ty)

    import scenic.syntax.veneer as veneer  # TODO improve?
    realType = ty
    if ty is float:
        coercer = coerceToFloat
    elif ty is Heading:
        coercer = coerceToHeading
        ty = numbers.Real
        realType = float
    elif ty is Vector:
        coercer = coerceToVector
    elif ty is veneer.Behavior:
        coercer = coerceToBehavior
    else:
        coercer = None

    if isinstance(thing, Distribution):
        vt = thing.valueType
        if typing.get_origin(vt) is typing.Union:
            possibleTypes = typing.get_args(vt)
        else:
            possibleTypes = (vt, )
        if all(issubclass(possible, ty) for possible in possibleTypes):
            return thing  # no coercion necessary
        else:
            return TypecheckedDistribution(thing,
                                           realType,
                                           error,
                                           coercer=coercer)
    elif coercer:
        try:
            return coercer(thing)
        except CoercionFailure as e:
            raise RuntimeParseError(f'{error} ({e.args[0]})') from None
    else:
        return thing
Ejemplo n.º 30
0
 def __init__(self, region=everywhere):
     if needsSampling(region):
         raise RuntimeParseError('workspace region must be fixed')
     super().__init__('workspace', orientation=region.orientation)
     self.region = region