Beispiel #1
0
 def validate(self):
     """Make some simple static checks for inconsistent built-in requirements."""
     objects = self.objects
     staticVisibility = not needsSampling(self.egoObject.visibleRegion)
     staticBounds = [self.hasStaticBounds(obj) for obj in objects]
     for i in range(len(objects)):
         oi = objects[i]
         # skip objects with unknown positions or bounding boxes
         if not staticBounds[i]:
             continue
         # Require object to be contained in the workspace/valid region
         container = self.containerOfObject(oi)
         if not needsSampling(container) and not container.containsObject(
                 oi):
             raise InvalidScenarioError(
                 f'Object at {oi.position} does not fit in container')
         # Require object to be visible from the ego object
         if staticVisibility and oi.requireVisible is True and oi is not self.egoObject:
             if not self.egoObject.canSee(oi):
                 raise InvalidScenarioError(
                     f'Object at {oi.position} is not visible from ego')
         # Require object to not intersect another object
         for j in range(i):
             oj = objects[j]
             if not staticBounds[j]:
                 continue
             if oi.intersects(oj):
                 raise InvalidScenarioError(
                     f'Object at {oi.position} intersects'
                     f' object at {oj.position}')
Beispiel #2
0
	def __init__(self, center, radius, resolution=32):
		super().__init__('Circle', center, radius)
		self.center = center.toVector()
		self.radius = radius
		self.circumcircle = (self.center, self.radius)

		if not (needsSampling(self.center) or needsSampling(self.radius)):
			ctr = shapely.geometry.Point(self.center)
			self.polygon = ctr.buffer(self.radius, resolution=resolution)
Beispiel #3
0
 def handler2(self, *args):
     if needsSampling(self):
         return VectorOperatorDistribution(op, self, args)
     elif any(needsSampling(arg) for arg in args):
         return VectorMethodDistribution(method, self, args, {})
     elif any(needsLazyEvaluation(arg) for arg in args):
         # see analogous comment in distributionFunction
         return makeDelayedFunctionCall(handler2, args, {})
     else:
         return method(self, *args)
Beispiel #4
0
		def helper(*args):
			if needsSampling(instance):
				return VectorOperatorDistribution(op, instance, args)
			elif any(needsSampling(arg) for arg in args):
				return VectorMethodDistribution(method, instance, args, {})
			elif any(needsLazyEvaluation(arg) for arg in args):
				# see analogous comment in distributionFunction
				return makeDelayedFunctionCall(helper, args, {})
			else:
				return wrapped(*args)
Beispiel #5
0
		def evaluator():
			result = req()
			assert not needsSampling(result)
			if needsLazyEvaluation(result):
				raise InvalidScenarioError(f'requirement on line {line} uses value'
				                           ' undefined outside of object definition')
			return result
Beispiel #6
0
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
Beispiel #7
0
	def __init__(self, points=None, polygon=None, orientation=None):
		super().__init__('Polygon', orientation=orientation)
		if polygon is None and points is None:
			raise RuntimeError('must specify points or polygon for PolygonalRegion')
		if polygon is None:
			points = tuple(points)
			if len(points) == 0:
				raise RuntimeError('tried to create PolygonalRegion from empty point list!')
			for point in points:
				if needsSampling(point):
					raise RuntimeError('only fixed PolygonalRegions are supported')
			self.points = points
			polygon = shapely.geometry.Polygon(points)

		if isinstance(polygon, shapely.geometry.Polygon):
			self.polygons = shapely.geometry.MultiPolygon([polygon])
		elif isinstance(polygon, shapely.geometry.MultiPolygon):
			self.polygons = polygon
		else:
			raise RuntimeError(f'tried to create PolygonalRegion from non-polygon {polygon}')
		if not self.polygons.is_valid:
			raise RuntimeError('tried to create PolygonalRegion with '
			                   f'invalid polygon {self.polygons}')

		if points is None and len(self.polygons) == 1 and len(self.polygons[0].interiors) == 0:
			self.points = tuple(self.polygons[0].exterior.coords[:-1])

		triangles = []
		for polygon in self.polygons:
			triangles.extend(triangulatePolygon(polygon))
		self.trianglesAndBounds = tuple((tri, tri.bounds) for tri in triangles)
		areas = (triangle.area for triangle in triangles)
		self.cumulativeTriangleAreas = tuple(itertools.accumulate(areas))
Beispiel #8
0
def constructScenarioFrom(namespace):
    """Build a Scenario object from an executed Scenic module."""
    # Extract ego object
    if namespace['_egoObject'] is None:
        raise InvalidScenarioError('did not specify ego object')

    # Extract workspace, if one is specified
    if 'workspace' in namespace:
        workspace = namespace['workspace']
        if not isinstance(workspace, Workspace):
            raise InvalidScenarioError(
                f'workspace {workspace} is not a Workspace')
        if needsSampling(workspace):
            raise InvalidScenarioError('workspace must be a fixed region')
        if needsLazyEvaluation(workspace):
            raise InvalidScenarioError('workspace uses value undefined '
                                       'outside of object definition')
    else:
        workspace = None

    # Create Scenario object
    scenario = Scenario(workspace, namespace['_objects'],
                        namespace['_egoObject'], namespace['_params'],
                        namespace['_externalParams'],
                        namespace['_requirements'],
                        namespace['_requirementDeps'])

    # Prune infeasible parts of the space
    if usePruning:
        pruning.prune(scenario, verbosity=verbosity)

    return scenario
Beispiel #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}')
Beispiel #10
0
def constructScenarioFrom(namespace):
    # extract ego object
    if namespace['_egoObject'] is None:
        raise InvalidScenarioError('did not specify ego object')

    # extract workspace, if one is specified
    if 'workspace' in namespace:
        workspace = namespace['workspace']
        if not isinstance(workspace, Workspace):
            raise InvalidScenarioError(
                f'workspace {workspace} is not a Workspace')
        if needsSampling(workspace):
            raise InvalidScenarioError('workspace must be a fixed region')
        if needsLazyEvaluation(workspace):
            raise InvalidScenarioError('workspace uses value undefined '
                                       'outside of object definition')
    else:
        workspace = None

    scenario = Scenario(workspace, namespace['_objects'],
                        namespace['_egoObject'], namespace['_params'],
                        namespace['_requirements'],
                        namespace['_requirementDeps'])

    if usePruning:
        pruning.prune(scenario, verbosity=verbosity)

    return scenario
Beispiel #11
0
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)
Beispiel #12
0
 def getConstantPolygon(self):
     assert not any(
         needsSampling(c) or needsLazyEvaluation(c) for c in self.corners)
     # TODO refactor???
     corners = [(x, y)
                for x, y in self.corners]  # convert Vectors to tuples
     return shapely.geometry.Polygon(corners)
Beispiel #13
0
    def uniformPoint(self):
        """Sample a uniformly-random point in this `Region`.

		Can only be called on fixed Regions with no random parameters.
		"""
        assert not needsSampling(self)
        return self.uniformPointInner()
Beispiel #14
0
 def handler2(self, *args, **kwargs):
     if any(
             needsSampling(arg)
             for arg in itertools.chain(args, kwargs.values())):
         return MethodDistribution(method, self, args, kwargs)
     else:
         return method(self, *args, **kwargs)
Beispiel #15
0
	def helper(self, *args, **kwargs):
		if any(needsSampling(arg) for arg in itertools.chain(args, kwargs.values())):
			return VectorMethodDistribution(method, self, args, kwargs)
		elif any(needsLazyEvaluation(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)
Beispiel #16
0
	def __init__(self, name, points, kdTree=None, orientation=None, tolerance=1e-6):
		super().__init__(name, orientation=orientation)
		self.points = tuple(points)
		for point in self.points:
			if needsSampling(point):
				raise RuntimeError('only fixed PointSetRegions are supported')
		self.kdTree = scipy.spatial.cKDTree(self.points) if kdTree is None else kdTree
		self.orientation = orientation
		self.tolerance = tolerance
Beispiel #17
0
 def polygon(self):
     position, heading, hw, hh = self.position, self.heading, self.hw, self.hh
     if any(
             needsSampling(c) or needsLazyEvaluation(c)
             for c in (position, heading, hw, hh)):
         return None  # can only convert fixed Regions to Polygons
     corners = RotatedRectangle.makeCorners(position.x, position.y, heading,
                                            hw, hh)
     return shapely.geometry.Polygon(corners)
Beispiel #18
0
def toPolygon(thing):
    if needsSampling(thing):
        return None
    if hasattr(thing, 'polygon'):
        return thing.polygon
    if hasattr(thing, 'polygons'):
        return thing.polygons
    if hasattr(thing, 'lineString'):
        return thing.lineString
    return None
Beispiel #19
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)
Beispiel #20
0
    def compile(self, namespace, scenario, syntax=None):
        """Create a closure testing the requirement in the correct runtime state.

        While we're at it, determine whether the requirement implies any relations
        we can use for pruning, and gather all of its dependencies.
        """
        bindings, ego, line = self.bindings, self.egoObject, self.line
        condition = self.condition

        # Check whether requirement implies any relations used for pruning
        if self.ty.constrainsSampling and syntax:
            relations.inferRelationsFrom(syntax, bindings, ego, line)

        # Gather dependencies of the requirement
        deps = set()
        for value in bindings.values():
            if needsSampling(value):
                deps.add(value)
            if needsLazyEvaluation(value):
                raise InvalidScenarioError(
                    f'requirement on line {line} uses value {value}'
                    ' undefined outside of object definition')
        if ego is not None:
            assert isinstance(ego, Samplable)
            deps.add(ego)

        # Construct closure
        def closure(values):
            global evaluatingRequirement, currentScenario
            # rebind any names referring to sampled objects
            for name, value in bindings.items():
                if value in values:
                    namespace[name] = values[value]
            # rebind ego object, which can be referred to implicitly
            boundEgo = None if ego is None else values[ego]
            # evaluate requirement condition, reporting errors on the correct line
            import scenic.syntax.veneer as veneer
            with veneer.executeInRequirement(scenario, boundEgo):
                result = condition()
                assert not needsSampling(result)
                if needsLazyEvaluation(result):
                    raise InvalidScenarioError(
                        f'requirement on line {line} uses value'
                        ' undefined outside of object definition')
            return result

        return CompiledRequirement(self, closure, deps)
Beispiel #21
0
 def closure(values):
     global evaluatingRequirement, currentScenario
     # rebind any names referring to sampled objects
     for name, value in bindings.items():
         if value in values:
             namespace[name] = values[value]
     # rebind ego object, which can be referred to implicitly
     boundEgo = None if ego is None else values[ego]
     # evaluate requirement condition, reporting errors on the correct line
     import scenic.syntax.veneer as veneer
     with veneer.executeInRequirement(scenario, boundEgo):
         result = condition()
         assert not needsSampling(result)
         if needsLazyEvaluation(result):
             raise InvalidScenarioError(
                 f'requirement on line {line} uses value'
                 ' undefined outside of object definition')
     return result
Beispiel #22
0
    def _toScenario(self, namespace):
        assert self._prepared

        if self._ego is None and self._compose is None:
            msg = 'did not specify ego object'
            modScenarios = namespace['_scenarios']
            if self._dummyNamespace and len(modScenarios) == 1:
                if modScenarios[0]._requiresArguments():
                    msg += (
                        '\n(Note: this Scenic file contains a modular scenario, but it\n'
                        'cannot be used as the top-level scenario since it requires\n'
                        'arguments; so the whole file is being used as a top-level\n'
                        'scenario and needs an ego object.)')
                else:
                    msg += (
                        '\n(Note: this Scenic file contains a modular scenario, but also\n'
                        'other code; so the whole file is being used as a top-level\n'
                        'scenario and needs an ego object.)')
            raise InvalidScenarioError(msg)

        # Extract workspace, if one is specified
        if 'workspace' in namespace:
            workspace = namespace['workspace']
            if not isinstance(workspace, Workspace):
                raise InvalidScenarioError(
                    f'workspace {workspace} is not a Workspace')
            if needsSampling(workspace):
                raise InvalidScenarioError('workspace must be a fixed region')
            if needsLazyEvaluation(workspace):
                raise InvalidScenarioError('workspace uses value undefined '
                                           'outside of object definition')
        else:
            workspace = None

        from scenic.core.scenarios import Scenario
        scenario = Scenario(workspace, self._simulatorFactory, self._objects,
                            self._ego, self._globalParameters,
                            self._externalParameters, self._requirements,
                            self._requirementDeps, self._monitors,
                            self._behaviorNamespaces,
                            self)  # TODO unify these!
        return scenario
Beispiel #23
0
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
Beispiel #24
0
	def __init__(self, center, radius, heading, angle, resolution=32):
		super().__init__('Sector', center, radius, heading, angle)
		self.center = center.toVector()
		self.radius = radius
		self.heading = heading
		self.angle = angle
		r = (radius / 2) * cos(angle / 2)
		self.circumcircle = (self.center.offsetRadially(r, heading), r)

		if not any(needsSampling(x) for x in (self.center, radius, heading, angle)):
			ctr = shapely.geometry.Point(self.center)
			circle = ctr.buffer(self.radius, resolution=resolution)
			if angle >= math.tau - 0.001:
				self.polygon = circle
			else:
				mask = shapely.geometry.Polygon([
				    self.center,
				    self.center.offsetRadially(radius, heading + angle/2),
				    self.center.offsetRadially(2*radius, heading),
				    self.center.offsetRadially(radius, heading - angle/2)
				])
				self.polygon = circle & mask
Beispiel #25
0
 def closure(values):
     # rebind any names referring to sampled objects
     for name, value in bindings.items():
         if value in values:
             namespace[name] = values[value]
     # rebind ego object, which can be referred to implicitly
     if ego is not None:
         veneer.egoObject = values[ego]
     # evaluate requirement condition, reporting errors on the correct line
     try:
         veneer.evaluatingRequirement = True
         result = req()
         assert not needsSampling(result)
         if needsLazyEvaluation(result):
             raise RuntimeParseError(
                 f'requirement on line {line} uses value'
                 ' undefined outside of object definition')
         return result
     except RuntimeParseError as e:
         cause = e if showInternalBacktrace else None
         raise InterpreterParseError(e, line) from cause
     finally:
         veneer.evaluatingRequirement = False
Beispiel #26
0
    def show(self, workspace, plt, highlight=False):
        if needsSampling(self):
            raise RuntimeError('tried to show() symbolic Object')
        pos = self.position
        mpos = workspace.langToMapCoords(pos)

        if highlight:
            # Circle around object
            rad = 1.5 * max(self.width, self.height)
            c = plt.Circle(mpos, rad, color='g', fill=False)
            plt.gca().add_artist(c)
            # View cone
            ha = self.viewAngle / 2.0
            camera = self.position.offsetRotated(self.heading,
                                                 self.cameraOffset)
            cpos = workspace.langToMapCoords(camera)
            for angle in (-ha, ha):
                p = camera.offsetRadially(20, self.heading + angle)
                edge = [cpos, workspace.langToMapCoords(p)]
                x, y = zip(*edge)
                plt.plot(x, y, 'b:')

        corners = [
            workspace.langToMapCoords(corner) for corner in self.corners
        ]
        x, y = zip(*corners)
        color = self.color if hasattr(self, 'color') else (1, 0, 0)
        plt.fill(x, y, color=color)
        #plt.plot(x + (x[0],), y + (y[0],), color="g", linewidth=1)

        frontMid = averageVectors(corners[0], corners[1])
        baseTriangle = [frontMid, corners[2], corners[3]]
        triangle = [averageVectors(p, mpos, weight=0.5) for p in baseTriangle]
        x, y = zip(*triangle)
        plt.fill(x, y, "w")
        plt.plot(x + (x[0], ), y + (y[0], ), color="k", linewidth=1)
Beispiel #27
0
 def polygon(self):
     if any(
             needsSampling(c) or needsLazyEvaluation(c)
             for c in self.corners):
         return None  # can only convert fixed Regions to Polygons
     return self.getConstantPolygon()
Beispiel #28
0
    def generate(self, maxIterations=2000, verbosity=0, feedback=None):
        """Sample a `Scene` from this scenario.

		Args:
			maxIterations (int): Maximum number of rejection sampling iterations.
			verbosity (int): Verbosity level.
			feedback (float): Feedback to pass to external samplers doing active sampling.
				See :mod:`scenic.core.external_params`.

		Returns:
			A pair with the sampled `Scene` and the number of iterations used.

		Raises:
			`RejectionException`: if no valid sample is found in **maxIterations** iterations.
		"""
        objects = self.objects

        # choose which custom requirements will be enforced for this sample
        activeReqs = [
            req for req in self.initialRequirements
            if random.random() <= req.prob
        ]

        # do rejection sampling until requirements are satisfied
        rejection = True
        iterations = 0
        while rejection is not None:
            if iterations > 0:  # rejected the last sample
                if verbosity >= 2:
                    print(
                        f'  Rejected sample {iterations} because of: {rejection}'
                    )
                if self.externalSampler is not None:
                    feedback = self.externalSampler.rejectionFeedback
            if iterations >= maxIterations:
                raise RejectionException(
                    f'failed to generate scenario in {iterations} iterations')
            iterations += 1
            try:
                if self.externalSampler is not None:
                    self.externalSampler.sample(feedback)
                sample = Samplable.sampleAll(self.dependencies)
            except RejectionException as e:
                rejection = e
                continue
            rejection = None
            ego = sample[self.egoObject]
            # Normalize types of some built-in properties
            for obj in objects:
                sampledObj = sample[obj]
                assert not needsSampling(sampledObj)
                # position, heading
                assert isinstance(sampledObj.position, Vector)
                sampledObj.heading = float(sampledObj.heading)
                # behavior
                behavior = sampledObj.behavior
                if behavior is not None and not isinstance(
                        behavior, veneer.Behavior):
                    raise InvalidScenarioError(
                        f'behavior {behavior} of Object {obj} is not a behavior'
                    )

            # Check built-in requirements
            for i in range(len(objects)):
                vi = sample[objects[i]]
                # Require object to be contained in the workspace/valid region
                container = self.containerOfObject(vi)
                if not container.containsObject(vi):
                    rejection = 'object containment'
                    break
                # Require object to be visible from the ego object
                if vi.requireVisible and vi is not ego and not ego.canSee(vi):
                    rejection = 'object visibility'
                    break
                # Require object to not intersect another object
                for j in range(i):
                    vj = sample[objects[j]]
                    if vi.intersects(vj):
                        rejection = 'object intersection'
                        break
                if rejection is not None:
                    break
            if rejection is not None:
                continue
            # Check user-specified requirements
            for req in activeReqs:
                if not req.satisfiedBy(sample):
                    rejection = f'user-specified requirement (line {req.line})'
                    break

        # obtained a valid sample; assemble a scene from it
        sampledObjects = tuple(sample[obj] for obj in objects)
        sampledParams = {}
        for param, value in self.params.items():
            sampledValue = sample[value]
            assert not needsLazyEvaluation(sampledValue)
            sampledParams[param] = sampledValue
        sampledNamespaces = {}
        for modName, namespace in self.behaviorNamespaces.items():
            sampledNamespace = {
                name: sample[value]
                for name, value in namespace.items()
            }
            sampledNamespaces[modName] = (namespace, sampledNamespace,
                                          namespace.copy())
        alwaysReqs = (veneer.BoundRequirement(req, sample)
                      for req in self.alwaysRequirements)
        terminationConds = (veneer.BoundRequirement(req, sample)
                            for req in self.terminationConditions)
        termSimulationConds = (veneer.BoundRequirement(req, sample)
                               for req in self.terminateSimulationConditions)
        scene = Scene(self.workspace, sampledObjects, ego, sampledParams,
                      alwaysReqs, terminationConds, termSimulationConds,
                      self.monitors, sampledNamespaces, self.dynamicScenario)
        return scene, iterations
Beispiel #29
0
 def hasStaticBounds(self, obj):
     if needsSampling(obj.position):
         return False
     if any(needsSampling(corner) for corner in obj.corners):
         return False
     return True
Beispiel #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