Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
ef9d735
Initial simulator stepping implementation.
Eric-Vin Nov 7, 2024
a452067
Added stepped simulation test.
Eric-Vin Nov 7, 2024
1cd2aa6
Work on OpenScenarioXML Export.
Eric-Vin Nov 17, 2025
8c056c2
Initial OpenScenarioXML export implementation.
Eric-Vin Nov 18, 2025
048d3f0
Tidying up
Eric-Vin Nov 19, 2025
07e773b
Scene sampling parallelization prototype.
Eric-Vin Nov 20, 2025
99f4ac0
Scene sampling parallelization.
Eric-Vin Nov 21, 2025
6ff049a
Fixed coordinate system
Eric-Vin Nov 25, 2025
0b45e3d
Updated dependencies and fixed wheelbase offset
Eric-Vin Nov 25, 2025
cf3c647
Simulation parallelization
Eric-Vin Dec 2, 2025
8ecd602
Added pedestrians to OpenScenarioXML export
Eric-Vin Dec 16, 2025
349727f
Added documentation for setSeed.
Eric-Vin Dec 25, 2025
335b437
Added documentation and tests for simulation parallelization.
Eric-Vin Dec 25, 2025
e5048b4
Merge branch 'main' into ScenicParallelization
Eric-Vin Dec 25, 2025
61e61b8
Merge branch 'main' into SimulatorStepping
Eric-Vin Dec 25, 2025
9689729
xMerge branch 'SimulatorStepping' into ScenicParallelization
Eric-Vin Dec 26, 2025
f673bb4
Minor documentation and test additions.
Eric-Vin Apr 18, 2026
24e5ee9
Simplified test.
Eric-Vin Apr 18, 2026
8685fac
Merge branch 'main' into OpenScenarioXML
Eric-Vin May 28, 2026
5e2b7e3
XOSC export improvements, fixes, and test.
Eric-Vin May 29, 2026
743cf43
Fixed metadrive import?
Eric-Vin May 29, 2026
992be25
Tweaked Metadrive real_time default.
Eric-Vin May 29, 2026
15c729a
Added documentation
Eric-Vin May 29, 2026
ab311ca
Minor fixes.
Eric-Vin May 29, 2026
54a2a5e
Fixed blank line
Eric-Vin May 29, 2026
25fe1a1
Another blank line?
Eric-Vin May 29, 2026
518c308
Fix scenariogeneration link
Eric-Vin May 29, 2026
96b3ee1
Fixed link
Eric-Vin May 29, 2026
f9557b5
Added support for parallel behaviors.
Eric-Vin May 30, 2026
2c1551d
Naming tweak.
Eric-Vin May 30, 2026
28f7c77
Small fix.
Eric-Vin May 30, 2026
2e62dc8
Consolidate PID controller code
Eric-Vin May 30, 2026
04003e1
Initial pure pursuit implementation and reorginization.
Eric-Vin Jun 1, 2026
6d802b2
Progress on controllers
Eric-Vin Jun 22, 2026
5678af3
Added minimum distance operator. (pending final name)
Eric-Vin Jun 25, 2026
12f60bb
fix `terminate when` and `record` statements in subscenarios
dfremont Jun 26, 2026
b163047
Added fix for lane order in backwards LaneGroups.
Eric-Vin Jul 6, 2026
4d6abc2
Additional controller tweaks.
Eric-Vin Jul 6, 2026
cdfef5b
Added followFromTrajectory method.
Eric-Vin Jul 6, 2026
9b5243e
Fix docs building.
Eric-Vin Jul 6, 2026
5924262
Added setOrientation functionality to driving domain
Eric-Vin Jul 6, 2026
ebc20b1
Added python floor to pairwise test.
Eric-Vin Jul 6, 2026
2887b04
Prepare for `apparent heading to` syntax.
Eric-Vin Jul 6, 2026
6c89a4a
Added `apparent heading to X from Y` operator.
Eric-Vin Jul 7, 2026
d2cd9e3
Added documentation.
Eric-Vin Jul 7, 2026
7bc9cbc
Added logic for dynamically rebuilding parser on changes.
Eric-Vin Jul 7, 2026
0e8e936
followFrom and followFromTrajectory now attempt to coerce pos to a ve…
Eric-Vin Jul 8, 2026
b9b1570
Added centerlines field to networks
Eric-Vin Jul 8, 2026
513299c
Renamed centerlineRegion
Eric-Vin Jul 8, 2026
6e53653
Added additional tests.
Eric-Vin Jul 8, 2026
502ebab
Added tests for imported record, require monitor, and terminate state…
Eric-Vin Jul 9, 2026
f4987c0
Partial fixes
Eric-Vin Jul 9, 2026
ef61631
Driving behaviors cleanup and work on behaviors for walking actors.
Eric-Vin Jul 10, 2026
1a129a1
Working obstacle avoidance in walking behavior.
Eric-Vin Jul 10, 2026
0215e81
Pedestrian WalkTo polish.
Eric-Vin Jul 10, 2026
bcb7d98
Fixed setWalkingSpeed.
Eric-Vin Jul 11, 2026
b36fd58
Clean lines in WalkTo
Eric-Vin Jul 11, 2026
ac71f71
More line cleaning.
Eric-Vin Jul 11, 2026
c7a0983
More cleaning.
Eric-Vin Jul 11, 2026
51594ec
More cleanup
Eric-Vin Jul 11, 2026
d1f4288
Additional cleanup
Eric-Vin Jul 11, 2026
e2d44f2
Cleanup.
Eric-Vin Jul 11, 2026
ddee669
Added polyline level substring method.
Eric-Vin Jul 13, 2026
d990704
Improved pedestrian walking behavior.
Eric-Vin Jul 13, 2026
4f934d8
Merge branch 'MinimumDistanceOperator' into EricSummer2026
Eric-Vin Jul 13, 2026
db51e2c
Further walk behavior fix.
Eric-Vin Jul 13, 2026
dca2629
Fix grammar checksum
Eric-Vin Jul 13, 2026
59db4e2
Further improvements to pedestrian walking.
Eric-Vin Jul 14, 2026
c92a1e0
Increased pedestrian behavior replanning frequency.
Eric-Vin Jul 14, 2026
418d6ee
Further improvements to walking behavior.
Eric-Vin Jul 14, 2026
73e5a90
Further walking behavior improvements.
Eric-Vin Jul 14, 2026
5dcb3d8
Debugging
Eric-Vin Jul 14, 2026
353781b
More debug.
Eric-Vin Jul 14, 2026
7bf53b8
Debug.
Eric-Vin Jul 14, 2026
6fa347a
More debug.
Eric-Vin Jul 14, 2026
c826005
Added erosion factor to walk behavior to smooth return to path.
Eric-Vin Jul 14, 2026
1ae16df
Fixed aspect ratio on debug plot.
Eric-Vin Jul 14, 2026
5888ac0
Added debug prints.
Eric-Vin Jul 14, 2026
ed4545a
Remove debug visualization.
Eric-Vin Jul 14, 2026
1563c4c
Walking tweaks.
Eric-Vin Jul 14, 2026
69142e6
Lookahead time now scales with replan time.
Eric-Vin Jul 14, 2026
187ecf7
Split out lookahead time into its own param.
Eric-Vin Jul 14, 2026
419b685
Fix typo.
Eric-Vin Jul 14, 2026
fa33b13
Debug
Eric-Vin Jul 14, 2026
3502d3c
Fix typo.
Eric-Vin Jul 14, 2026
0963b5f
Debug
Eric-Vin Jul 14, 2026
42d3998
More debug.
Eric-Vin Jul 14, 2026
429385b
More debug
Eric-Vin Jul 14, 2026
60065d3
Remove debug.
Eric-Vin Jul 14, 2026
bb59d3d
Much improved walking behavior.
Eric-Vin Jul 15, 2026
102baa2
Cleanup
Eric-Vin Jul 15, 2026
8cd98d1
Default modifications.
Eric-Vin Jul 15, 2026
1fd127d
Weird bug with buffer size.
Eric-Vin Jul 15, 2026
ed71d69
Debug
Eric-Vin Jul 15, 2026
de5f1e2
Debug.
Eric-Vin Jul 15, 2026
1c43be8
Debug.
Eric-Vin Jul 15, 2026
6e7bd1e
Debug.
Eric-Vin Jul 15, 2026
6815416
More debug.
Eric-Vin Jul 15, 2026
a6875b6
Remove debug.
Eric-Vin Jul 15, 2026
e580993
Re-add debug.
Eric-Vin Jul 15, 2026
51bceb5
More debug.
Eric-Vin Jul 15, 2026
dbb0b8b
More debug.
Eric-Vin Jul 15, 2026
aaedddb
More debug.
Eric-Vin Jul 15, 2026
8af29fd
debug
Eric-Vin Jul 15, 2026
27d4f3a
Fixed bug.
Eric-Vin Jul 15, 2026
211a706
Remove debug and tweaked params.
Eric-Vin Jul 15, 2026
68b37d5
Added assertion
Eric-Vin Jul 15, 2026
b6ea999
Slightly increased vehicle buffer amount.
Eric-Vin Jul 15, 2026
24961b5
Add show2D to dynamicScenario.
Eric-Vin Jul 16, 2026
99ec36d
Tweaks.
Eric-Vin Jul 16, 2026
fbc9ae5
Added center property to region
Eric-Vin Jul 16, 2026
998a299
Fix.
Eric-Vin Jul 16, 2026
2b82b2d
Rename center to midpoint to avoid conflict with center.
Eric-Vin Jul 16, 2026
66f24aa
Partial progress on terminate after changes.
Eric-Vin Jul 17, 2026
77789ce
Merge remote-tracking branch 'origin/fix_subscenarios' into EricSumme…
Eric-Vin Jul 17, 2026
8ab487a
Inheritence almost fully working, modulo some questions of scenario s…
Eric-Vin Jul 17, 2026
5d36fe8
New closestPointTo function
Eric-Vin Jul 17, 2026
6d2fdf6
Properly coerce to shapely point in closestPointTo
Eric-Vin Jul 17, 2026
950c89b
fix `record ... to` statement
dfremont Jul 19, 2026
fdf7a94
Merge remote-tracking branch 'origin/fix_subscenarios' into EricSumme…
Eric-Vin Jul 20, 2026
79965e9
Merge branch 'main' into ScenicParallelization
Eric-Vin Jul 21, 2026
786e48f
Merge branch 'main' into ScenicParallelization
Eric-Vin Jul 21, 2026
069bec8
Simulation cleanup fix and tests.
Eric-Vin Jul 21, 2026
b50a7e3
Merge branch 'ScenicParallelization' into EricSummer2026Test
Eric-Vin Jul 21, 2026
f0a75b4
Merge fixes.
Eric-Vin Jul 21, 2026
4092c51
Experimental Optunal external sampler support.
Eric-Vin Jul 24, 2026
783549e
Fix import issue?
Eric-Vin Jul 24, 2026
1acda62
Another import issue?
Eric-Vin Jul 24, 2026
ac2fd55
Added missing module.
Eric-Vin Jul 24, 2026
c08b509
Fixed random dependencies in external sampler
Eric-Vin Jul 24, 2026
4c2a708
Added external sampler support for Uniform star dists.
Eric-Vin Jul 24, 2026
a519d71
Dusabled translation case due to Optuna limitation.
Eric-Vin Jul 24, 2026
69362d5
More fixes.
Eric-Vin Jul 24, 2026
105933b
Fix typo.
Eric-Vin Jul 24, 2026
ae93966
Debug.
Eric-Vin Jul 24, 2026
4d69556
More debug.
Eric-Vin Jul 24, 2026
b954a43
Attempt fix.
Eric-Vin Jul 24, 2026
12652aa
Fixed leak.
Eric-Vin Jul 24, 2026
f73fdb7
Remove breakpoint.
Eric-Vin Jul 24, 2026
34098b1
Attempting to fix optuna multivariate.
Eric-Vin Jul 24, 2026
979fee4
Options now use Optuna categorical
Eric-Vin Jul 27, 2026
916b64b
Remove breakpoint.
Eric-Vin Jul 27, 2026
4a4740a
Properly use sampled value in Optuna names.
Eric-Vin Jul 27, 2026
cefd7ec
Polygon sampling improvements.
Eric-Vin Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ dmypy.json

*.cproject

# generated parser
# generated parser and checksum
src/scenic/syntax/parser.py
src/scenic/syntax/.parser_checksum

# generated media/output
simulation.gif
Expand Down
20 changes: 18 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ the sampled values for all the global parameters and objects in the scene from t

.. testcode::

import random, scenic
random.seed(12345)
import scenic
scenic.setSeed(12345)
scenario = scenic.scenarioFromString('ego = new Object with foo Range(0, 5)')
scene, numIterations = scenario.generate()
print(f'ego has foo = {scene.egoObject.foo}')
Expand All @@ -40,6 +40,13 @@ the sampled values for all the global parameters and objects in the scene from t

ego has foo = 2.083099362726706

Utilities
---------

Scenic provides top level utility functions for functions like setting Scenic's random seed.

.. autofunction:: scenic.setSeed

Running Dynamic Simulations
---------------------------

Expand Down Expand Up @@ -173,6 +180,15 @@ it to the replay, but this greatly increases the size of the encoded simulation.
can return to one later for further analysis), but it is not guaranteed to be
compatible across major versions of Scenic.

.. _xosc_export:

OpenScenarioXML Export
----------------------

Scenic provides experimental support for exporting completed simulations via `toOpenScenario`.
This function currently only supports cars and pedestrians, and may be subject to breaking changes
in the future.

.. seealso:: If you get exceptions or unexpected behavior when using the API, Scenic provides various debugging features: see :ref:`debugging`.

.. rubric:: Footnotes
Expand Down
2 changes: 2 additions & 0 deletions docs/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ General Scenario Control
(although :mod:`random` and :mod:`numpy.random` should not be used in place of
Scenic's own sampling constructs in Scenic code).

The seed can be set programatically using `scenic.setSeed`.

.. option:: --scenario <scenario>

If the given Scenic file defines multiple scenarios, select which one to run.
Expand Down
7 changes: 3 additions & 4 deletions docs/reference/dynamic_scenarios.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ In detail, a single time step of a dynamic simulation is executed according to t
If the block executes a :keyword:`require` statement with a false condition, reject the simulation.
If it executes :keyword:`terminate` or :keyword:`terminate simulation`, or finishes executing, go to step (e) below to stop the scenario.

e. If the scenario is stopping for one of the reasons above, first recursively stop any sub-scenarios it is running, then revert the effects of any :keyword:`override` statements it executed.
e. If the scenario is stopping for one of the reasons above, save the values of any :keyword:`record final` statements in the scenario, recursively stop any sub-scenarios it is running, then revert the effects of any :keyword:`override` statements it executed.
Next, check if any of its :term:`temporal requirements` were not satisfied: if so, reject the simulation.
Otherwise, the scenario returns to its parent scenario if it was invoked using :keyword:`do`; if it was the top-level scenario, or if it executed :keyword:`terminate simulation`, we set a flag indicating the top-level scenario has terminated.
(We do not terminate immediately since we still need to check monitors in the next step.)

2. Save the values of all :keyword:`record` statements, as well as :keyword:`record initial` statements if it is time step 0.
2. Save the values of all :keyword:`record` statements in currently-running scenarios, as well as :keyword:`record initial` statements for scenarios which have just started.

3. Run each :term:`monitor` instantiated in the currently-running scenarios for one time step (i.e. resume it until it executes :keyword:`wait`).
If it executes a :keyword:`require` statement with a false condition, reject the simulation.
Expand Down Expand Up @@ -66,8 +66,7 @@ In detail, a single time step of a dynamic simulation is executed according to t

9. Update every :term:`dynamic property` of every object to its current value in the simulator.

10. If the simulation is stopping for one of the reasons above, first check if any of the :term:`temporal requirements` of any remaining scenarios were not satisfied: if so, reject the simulation.
Otherwise, save the values of any :keyword:`record final` statements.
10. If the simulation is stopping for one of the reasons above, stop any remaining scenarios as in step (1e) above (including checking :term:`temporal requirements` and saving the values of :keyword:`record final` statements).


.. rubric:: Footnotes
Expand Down
23 changes: 23 additions & 0 deletions docs/reference/operators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,27 @@ apparent heading of *OrientedPoint* [from *vector*]
---------------------------------------------------
The apparent heading of the OrientedPoint, with respect to the line of sight from ego (or the position provided with the optional from vector)

.. _apparent heading to {vector} [from {OrientedPoint}]:

apparent heading to *vector* [from *OrientedPoint*]
---------------------------------------------------
The apparent heading to the vector, with respect to the line of sight from ego (or the OrientedPoint provided with the optional from OrientedPoint)

.. _distance [from {vector}] to {vector}:
.. _distance from:

distance [from *vector*] to *vector*
-------------------------------------
The distance to the given position from ego (or the position provided with the optional from vector)

.. _minimum distance [from {Object}] to {Object}:
.. _minimum distance from:

minimum distance [from *Object*] to *Object*
--------------------------------------------
The minimum distance to the given Object from ego (or the Object provided with the optional from Object). Unlike :ref:`distance from`, this operator takes into account the Objects' shapes, sizes, etc...


.. _angle [from {vector}] to {vector}:

angle [from *vector* ] to *vector*
Expand Down Expand Up @@ -75,6 +89,15 @@ Whether an `Object`/`Region` intersects another `Object`/`Region`, i.e. whether

When working with 2D regions, it can be useful to check intersection with the :term:`footprint` of a region, e.g. when checking whether a car intersects a given lane. In this case, one would write :scenic:`car intersects lane.footprint` instead of :scenic:`car intersects lane`. For more details, see :term:`footprint`.

.. _{vector} (ahead of | behind | left of | right of) {region}:

*vector* (ahead of | behind | left of | right of) *OrientedPoint*
-----------------------------------------------------------------
Whether a vector is to a respective side of an `OrientedPoint` (i.e. within +- ~90 degrees from that direction), accounting for the heading of the `OrientedPoint`. These operators are convenient shorthand for comparing :sampref:`apparent heading to {vector} [from {OrientedPoint}]` to a range of values.

Note: For vectors very close to a boundary point (i.e. an apparent heading to the vector in (89.99, 90.01) or (-89.99, -90.01) for "ahead of" and "behind"), both operators will resolve to False.

Example: If an `OrientedPoint` had an apparent heading to a vector of 45 degrees, it would be both "ahead of" and "left of" the `OrientedPoint` but not "behind" or "right of".

Orientation Operators
=====================
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/statements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ The default mutation system adds Gaussian noise to the :prop:`position` and :pro
record [initial | final] *value* [as *name*]
----------------------------------------------
Record the value of an expression during each simulation.
The value can be recorded at the start of the simulation (``initial``), at the end of the simulation (``final``), or at every time step (if neither ``initial`` nor ``final`` is specified).
The value can be recorded at the start of the scenario (``initial``), at the end of the scenario (``final``), or at every time step during the scenario (if neither ``initial`` nor ``final`` is specified).
The recorded values are available in the ``records`` dictionary of `SimulationResult`: its keys are the given names of the records (or synthesized names if not provided), and the corresponding values are either the value of the recorded expression or a tuple giving its value at each time step as appropriate.
For debugging, the records can also be printed out using the :option:`--show-records` command-line option.

Expand Down
5 changes: 4 additions & 1 deletion docs/simulators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ See the individual entries for details on each interface's capabilities and how
While Scenic aims to support multiple Python versions, some simulators may have more limited compatibility.
Be sure to check the documentation of each simulator to confirm which Python versions are supported.

.. note::
Scenic also supports outputing data in formats that may be imported into other simulators and tools (e.g. :ref:`xosc_export`).
For more details, see :ref:`serialization`.

.. contents:: List of Simulators
:local:

Expand Down Expand Up @@ -163,7 +167,6 @@ This interface is part of the VerifAI toolkit; documentation and examples can be

.. _VerifAI repository: https://github.com/BerkeleyLearnVerify/VerifAI


Deprecated
==========

Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies = [
"networkx >= 2.6",
"numpy >= 1.24",
"opencv-python ~= 4.5",
"optuna ~= 4.0",
"pegen >= 0.3.0",
"pillow >= 9.1",
'pygame-ce >= 2.5.7, <3; python_version >= "3.10"',
Expand All @@ -60,6 +61,9 @@ metadrive = [
"metadrive-simulator >= 0.4.3",
"sumolib >= 1.21.0",
]
openscenario = [
"scenariogeneration"
]
test = [ # minimum dependencies for running tests (used for tox virtualenvs)
"pytest >= 7.0.0",
"pytest-cov >= 3.0.0",
Expand All @@ -68,6 +72,7 @@ test = [ # minimum dependencies for running tests (used for tox virtualenvs)
test-full = [ # like 'test' but adds dependencies for optional features
"scenic[test]", # all dependencies from 'test' extra above
"scenic[guideways]", # for running guideways modules
"scenic[openscenario]",
"astor >= 0.8.1",
'carla >= 0.9.12; python_version <= "3.12" and (platform_system == "Linux" or platform_system == "Windows")',
"dill",
Expand Down
1 change: 1 addition & 0 deletions src/scenic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import scenic.core.errors as _errors
from scenic.core.errors import setDebuggingOptions
from scenic.core.utils import setSeed
from scenic.syntax.translator import scenarioFromFile, scenarioFromString

_errors.showInternalBacktrace = False # see comment in errors module
Expand Down
3 changes: 1 addition & 2 deletions src/scenic/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,7 @@
if args.verbosity >= 1:
print(f"Using random seed = {args.seed}")

random.seed(args.seed)
numpy.random.seed(args.seed)
scenic.setSeed(args.seed)

# Load scenario from file
if args.verbosity >= 1:
Expand Down
17 changes: 16 additions & 1 deletion src/scenic/core/distributions.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ def __init__(self, dependencies):
props.update(requiredProperties(dep))
super().__init__(props, deps)
self._conditioned = self # version (partially) conditioned on requirements
self._conditionTarget = False

@staticmethod
def sampleAll(quantities):
Expand Down Expand Up @@ -172,6 +173,8 @@ def deserializeValue(self, serializer, values):

def conditionTo(self, value):
"""Condition this value to another value with the same conditional distribution."""
assert not self._conditionTarget, "Attempted to double condition!"
value._conditionTarget = True
assert isinstance(value, Samplable)
self._conditioned = value

Expand All @@ -182,6 +185,17 @@ def evaluateIn(self, context):
assert all(not needsLazyEvaluation(dep) for dep in value._dependencies)
return value

def recursiveDependencies(self):
self = self._conditioned
deps = set(
itertools.chain.from_iterable(
dep.recursiveDependencies() for dep in self._dependencies
)
)
if isinstance(self, Distribution) and not self._deterministic:
deps.add(self)
return deps


class ConstantSamplable(Samplable):
"""A samplable which always evaluates to a constant value.
Expand Down Expand Up @@ -1076,6 +1090,7 @@ def cdf(mean, stddev, x):
return (1 + math.erf((x - mean) / (sqrt2 * stddev))) / 2

@staticmethod
@distributionFunction
def cdfinv(mean, stddev, x):
import scipy # slow import not often needed

Expand Down Expand Up @@ -1271,7 +1286,7 @@ def supportInterval(self):

def __repr__(self):
weights = self.weights
if all(weight == weights[0] for weight in weights):
if not weights or all(weight == weights[0] for weight in weights):
return f"DiscreteRange({self.low!r}, {self.high!r})"
else:
return f"DiscreteRange({self.low!r}, {self.high!r}, {self.weights})"
Expand Down
37 changes: 29 additions & 8 deletions src/scenic/core/dynamics/behaviors.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def alarmHandler(signum, frame):
try:
actions = self._runningIterator.send(None)
except StopIteration:
actions = () # behavior ended early
return None
return actions

def _stop(self, reason=None):
Expand All @@ -124,18 +124,39 @@ def _isFinished(self):
def _invokeInner(self, agent, subs):
import scenic.syntax.veneer as veneer

assert len(subs) == 1
sub = subs[0]
if not isinstance(sub, Behavior):
raise TypeError(f"expected a behavior, got {sub}")
sub._start(agent)
with veneer.executeInBehavior(sub):
# Validate all inner behaviors
for sub in subs:
if not isinstance(sub, Behavior):
raise TypeError(f"expected a behavior, got {sub}")
sub._start(agent)

# Create a generator for each inner behavior that yields the appropriate actions, cleaning up when done.
def make_inner_generator(sub):
try:
yield from sub._runningIterator
while sub._isRunning:
actions = sub._step()
if actions is None:
return
yield actions
finally:
if sub._isRunning:
sub._stop()

inner_generators = [make_inner_generator(sub) for sub in subs]

# Yield from a generator that zips all the inner generators together without padding, until all inner generators have terminated.
while True:
try:
raw_actions_list = next(itertools.zip_longest(*inner_generators))
yield tuple(
filter(
lambda x: x is not None,
itertools.chain.from_iterable(raw_actions_list),
)
)
except StopIteration:
return

def __repr__(self):
items = itertools.chain(
(repr(arg) for arg in self._args),
Expand Down
Loading
Loading