Esempio n. 1
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
Esempio n. 2
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}')
Esempio n. 3
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
Esempio n. 4
0
    def forParameters(params, globalParams):
        """Create an `ExternalSampler` given the sets of external and global parameters.

		The scenario may explicitly select an external sampler by assigning the global
		parameter ``externalSampler`` to a subclass of `ExternalSampler`. Otherwise, a
		`VerifaiSampler` is used by default.

		Args:
			params (tuple): Tuple listing each `ExternalParameter`.
			globalParams (dict): Dictionary of global parameters for the `Scenario`.
			  Note that the values of these parameters may be instances of `Distribution`!

		Returns:
			An `ExternalSampler` configured for the given parameters.
		"""
        if len(params) > 0:
            externalSampler = globalParams.get('externalSampler',
                                               VerifaiSampler)
            if not issubclass(externalSampler, ExternalSampler):
                raise InvalidScenarioError(
                    f'externalSampler type {externalSampler}'
                    ' not subclass of ExternalSampler')
            return externalSampler(params, globalParams)
        else:
            return None
Esempio n. 5
0
def pruneContainment(scenario, verbosity):
    """Prune based on the requirement that individual Objects fit within their container.

    Specifically, if O is positioned uniformly in region B and has container C, then we
    can instead pick a position uniformly in their intersection. If we can also lower
    bound the radius of O, then we can first erode C by that distance.
    """
    for obj in scenario.objects:
        base = matchInRegion(obj.position)
        if base is None:                    # match objects positioned uniformly in a Region
            continue
        if isinstance(base, regions.EmptyRegion):
            raise InvalidScenarioError(f'Object {obj} placed in empty region')
        basePoly = regions.toPolygon(base)
        if basePoly is None:                # to prune, the Region must be polygonal
            continue
        if basePoly.is_empty:
            raise InvalidScenarioError(f'Object {obj} placed in empty region')
        container = scenario.containerOfObject(obj)
        containerPoly = regions.toPolygon(container)
        if containerPoly is None:           # the object's container must also be polygonal
            return None
        minRadius, _ = supportInterval(obj.inradius)
        if minRadius is not None:           # if we can lower bound the radius, erode the container
            containerPoly = containerPoly.buffer(-minRadius)
        elif base is container:
            continue
        newBasePoly = basePoly & containerPoly      # restrict the base Region to the container
        if newBasePoly.is_empty:
            raise InvalidScenarioError(f'Object {obj} does not fit in container')
        if verbosity >= 1:
            if basePoly.area > 0:
                ratio = newBasePoly.area / basePoly.area
            else:
                ratio = newBasePoly.length / basePoly.length
            percent = 100 * (1.0 - ratio)
            print(f'    Region containment constraint pruned {percent:.1f}% of space.')
        newBase = regions.regionFromShapelyObject(newBasePoly, orientation=base.orientation)
        newPos = regions.Region.uniformPointIn(newBase)
        obj.position.conditionTo(newPos)
Esempio n. 6
0
def inferDistanceRelations(matcher, reqNode, ego, line):
    """Infer bounds on distances from a requirement."""
    distMatcher = lambda node: matcher.matchUnaryFunction('DistanceFrom', node)
    allBounds = matcher.matchBounds(reqNode, distMatcher)
    for target, bounds in allBounds.items():
        if not isinstance(target, Object):
            continue
        assert target is not ego
        if ego is None:
            raise InvalidScenarioError('distance w.r.t. unassigned ego on line {line}')
        lower, upper = bounds
        if lower < 0:
            lower = 0
            if upper == float('inf'):
                continue    # skip trivial bounds
        rel = DistanceRelation(target, lower, upper)
        ego._relations.append(rel)
        conv = DistanceRelation(ego, lower, upper)
        target._relations.append(conv)
Esempio n. 7
0
def inferRelativeHeadingRelations(matcher, reqNode, ego, line):
    """Infer bounds on relative headings from a requirement."""
    rhMatcher = lambda node: matcher.matchUnaryFunction('RelativeHeading', node)
    allBounds = matcher.matchBounds(reqNode, rhMatcher)
    for target, bounds in allBounds.items():
        if not isinstance(target, Object):
            continue
        assert target is not ego
        if ego is None:
            raise InvalidScenarioError('relative heading w.r.t. unassigned ego on line {line}')
        lower, upper = bounds
        if lower < -math.pi:
            lower = -math.pi
        if upper > math.pi:
            upper = math.pi
        if lower == -math.pi and upper == math.pi:
            continue    # skip trivial bounds
        rel = RelativeHeadingRelation(target, lower, upper)
        ego._relations.append(rel)
        conv = RelativeHeadingRelation(ego, -upper, -lower)
        target._relations.append(conv)
Esempio n. 8
0
def storeScenarioStateIn(namespace, requirementSyntax, lineMap, filename):
    """Post-process an executed Scenic module, extracting state from the veneer."""
    # Extract created Objects
    namespace['_objects'] = tuple(veneer.allObjects)
    namespace['_egoObject'] = veneer.egoObject

    # Extract global parameters
    namespace['_params'] = veneer.globalParameters
    for name, value in veneer.globalParameters.items():
        if needsLazyEvaluation(value):
            raise InvalidScenarioError(
                f'parameter {name} uses value {value}'
                ' undefined outside of object definition')

    # Extract external parameters
    namespace['_externalParams'] = tuple(veneer.externalParameters)

    # Extract requirements, scan for relations used for pruning, and create closures
    requirements = veneer.pendingRequirements
    finalReqs = veneer.inheritedReqs
    requirementDeps = set(
    )  # things needing to be sampled to evaluate the requirements
    namespace['_requirements'] = finalReqs
    namespace['_requirementDeps'] = requirementDeps

    def makeClosure(req, bindings, ego, line):
        """Create a closure testing the requirement in the correct runtime state."""
        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

        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 = executePythonFunction(evaluator, lineMap, filename)
            finally:
                veneer.evaluatingRequirement = False
            return result

        return closure

    for reqID, (req, bindings, ego, line, prob) in requirements.items():
        # Check whether requirement implies any relations used for pruning
        reqNode = requirementSyntax[reqID]
        relations.inferRelationsFrom(reqNode, bindings, ego, line, lineMap)
        # Gather dependencies of the requirement
        for value in bindings.values():
            if needsSampling(value):
                requirementDeps.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)
            requirementDeps.add(ego)
        # Construct closure
        finalReqs.append((makeClosure(req, bindings, ego, line), prob))