Feb 2026 – May 2026
AI · SWELast edited
Compositional Analysis for Safety Specifications
This project extends compositional statistical model checking for autonomous vehicles from Markovian to non-Markovian safety specifications.
The core idea is to augment simulation states with DFA states that encode the temporal logic of the specification, then propagate the DFA distribution across primitive scenario traces. This makes it possible to verify safety properties that depend on the history of events (not just the current state) while preserving the compositional structure that keeps large-scale verification tractable.
Affiliation
UC Berkeley
Report
- Manuscript
Keywords
- Compositional Analysis
- Statistical Model Checking
- DFA
- Automata Theory
- Markov Chains
- Python
- VerifAI
- MetaDrive
- CARLA
- Webots
- Scenic
▸ Deepdive
Introduction
This project extends VerifAI’s compositional statistical model checking (SMC) from Markovian to non-Markovian safety specifications, and adds a Scenic frontend so that composite driving scenarios written in standard Scenic source can be analyzed end-to-end. Compositional analysis decomposes a long simulation into short primitive scenarios whose traces are generated in parallel and stitched together via importance sampling at handoff boundaries; the contribution here is representing each safety property as a deterministic finite automaton (DFA) and propagating a distribution over DFA states across those handoffs so that history-dependent properties, “stop at most once at a tollgate,” “once the vehicle exceeds 15 m/s it must never drop below 6.5 m/s”, fall inside the compositional framework. On the MetaDrive simulator and on a Scenic intersection benchmark, the framework recovers monolithic estimates to within statistical error while achieving a 4–7× wall-clock speedup.
This was a joint course project for EECS 219C (Formal Methods: Specification, Verification, and Synthesis) at UC Berkeley, Spring 2026, with Abhi Pomalapally. Abhi led the VerifAI backend (DFA-augmented state-distribution propagation, the rejection-conditioning fix in check_with_dfa, and the MetaDrive evaluation); I led the Scenic frontend (the recursive DAG parser over containers, composition statements, and weighted invocations, and the linearization that feeds the backend); Abhi also handled the end-to-end Scenic → MetaDrive integration.
Problem Definition
Primitive and composite scenarios. Let denote a finite set of primitive scenarios. Each primitive induces a Markov decision process with shared state space , action space , transition kernel , and initial state . Under the system policy, yields traces distributed according to some trace distribution . A composite scenario is built from primitives via three composition operators, mirroring Scenic’s do, do choose, and do shuffle clauses:
- sequential composition , which runs to its terminal state and then from that state;
- probabilistic choice , which executes with probability ;
- shuffle , which executes the ‘s in a uniformly random order.
Specifications and satisfaction probability. A specification is given by a deterministic finite automaton together with a labeling function . A trace satisfies , written , iff the run given by ends in an accepting state, . The quantity of interest is
We call Markovian if depends only on the terminal state , and non-Markovian otherwise.
The compositional non-Markovian analysis problem. Given a composite scenario over primitives , a non-Markovian specification given by , and a per-primitive simulation budget of traces, produce an estimate of with a confidence half-width at level (so that holds with probability at least ), using only the primitive trace sets for .
Why the problem is hard. The restriction to primitive traces is what makes the problem useful, primitives are short, can be simulated in parallel, and need not be re-run when changes, and also what makes it technically nontrivial. First, since may be non-Markovian, depends on the full trace rather than its terminal state, which rules out the Markovian compositional estimator of Yalcinkaya et al. (RV 2023). Second, in , the state distribution at the end of generally differs from the initial-state distribution of when is simulated as a primitive, so naively concatenating primitive traces yields a biased estimate of unless this mismatch is explicitly corrected.
Approach
Given a composite Scenic program and a non-Markovian specification , the framework returns in four stages: (i) recursively parse the Scenic source into a composition graph over primitives ; (ii) simulate traces per primitive in parallel; (iii) walk the graph, propagating a distribution over DFA states and correcting trace-distribution mismatch with kernel-density importance sampling; (iv) aggregate sibling branches by operator (product for sequential, weighted mixture for choose, permutation average for shuffle).

.scenic, the DFA safety spec , and per-primitive trace pools . The frontend parses the source into a linearized composition ; the backend propagates the DFA-state distribution left-to-right conditioned on acceptance, with a KDE reweight at each boundary, producing .Scenic Frontend
Scenic’s composition vocabulary (do, do choose, do shuffle, and nested scenario blocks) maps directly onto the sequential, probabilistic-choice, and shuffle operators above, so a Scenic program already carries the compositional decomposition the analysis needs. The challenge is that composition in Scenic nests arbitrarily: a compose block can invoke another scenario whose body has further choose or shuffle clauses, and nested choose weights combine multiplicatively along invocation paths. For example, with is the three-way distribution , not the two-way obtained by reading the outer choose in isolation. A flat parse loses this structure; recovering requires a recursive traversal of the Scenic abstract syntax tree (AST) that preserves operator semantics and propagates weights across invocation boundaries.

choose (left) and its extracted composition DAG (right). All three node kinds ( containers, statements, invocations) and all three edge kinds (contains, invokes, next) are exercised.The composite scenario is represented as a directed acyclic graph with partitioned into three node kinds. contains one container node per scenario or behavior definition; contains one statement node per do, do choose, or do shuffle clause, each carrying its operator label; contains one invocation node per call site, each carrying a target identifier and (under choose) a positive weight. Edges fall into three kinds: contains (a container to each of its statements), invokes (a statement to its invocations and each invocation to its target), and next (between sibling statements inside a container, encoding sequential order).
The DAG is then linearized into a list of CompositionStep values, where
Sequential statements concatenate their children’s step lists; choose produces a single step that flattens the child step lists into a distribution by multiplying weights along the invocation path; shuffle over children yields the permutation step lists with uniform weight .
VerifAI Backend
The backend extends VerifAI’s compositional analysis engine from the Markovian estimator of Yalcinkaya et al. to DFA safety specifications. A new automaton_specification class in VerifAI wraps the dfa library to represent a safety property as with labeling , and extends the engine to consume it. It takes the linearized composition from the frontend, where each is either a primitive name (sequential step) or a weighted dictionary (random choice), along with the per-primitive trace pools and entry/exit features (e.g., position, speed), and returns estimating over the composite distribution.

stopped_twice is absorbing rejecting.Three challenges shape the algorithm.
Non-Markovian satisfaction. The Markovian estimator labels each trace by ; DFA satisfaction instead depends on the full labeled sequence and on the entry state. We maintain a distribution over DFA entry states, conditioned across primitives on acceptance, and label each trace by
The accept-conditioning is essential: advancing over all step- traces (including ones already in absorbing rejecting states) deflates both and , so underestimates the truth. We therefore compute the full sequence in a forward pass over before the main estimation loop, so each step uses the correct pre-step distribution.
Handoff distribution mismatch. Each primitive is simulated standalone, so its entry distribution over differs from its predecessor’s exit distribution; naive concatenation is biased. We correct with self-normalized importance sampling: fit a Gaussian KDE to step ‘s accepting-exit features and to step ‘s entry features , with
The per-step estimate is the self-normalized IS-weighted mean . Near-disjoint supports collapse the weights, which we mitigate by prewarming primitives so successive supports overlap, and by monitoring effective sample size.
Random-choice composition. A step branches all three machinery components:
where is the per-branch IS estimate from a shared and is its accept-conditioned successor. When step fits its source KDE, accepting-exit features are pooled across branches with weights , so the mixture mass is faithful rather than implicitly uniform.
Aggregation
The chain rule
justifies multiplying per-step estimates into the composite estimate, with per-step Hoeffding bounds (using the effective sample size of the importance weights) propagated as
A union bound over the per-step events with ensures the composite estimate holds at overall confidence .
Results
We evaluate accuracy and efficiency against the monolithic SMC baseline (which simulates each composite as a single chained Scenic scenario) on three sets of scenarios in MetaDrive.
Accuracy at matched trace budget
Set A consists of five sequential composites over the primitives Straight, Intersection, Curve, evaluated under two DFAs: (rejects after the third near-stop) and (at most one near-stop). At a matched trace budget, the two estimators agree within Hoeffding intervals on every pair.
wait state before three consecutive slow steps is a violation; from wait₃, one more slow step returns to moving (the tollgate is cleared). violated is absorbing rejecting.| Composite | () | () | () | () |
|---|---|---|---|---|
| SX | ||||
| SXS | ||||
| SC | ||||
| SCS | ||||
| SCX |
Set B is the five-step wander composite , yielding distinct execution paths over four leaf primitives. Under (rejects after the second hard brake), the compositional estimate agrees with , with well inside both Hoeffding intervals. The same Set B primitive trace pool was additionally evaluated against seven further DFAs (including non-Markovian properties like rise_then_fall, k_consec_slow, at_most_one_brake) at ~1 s of post-hoc Python each, illustrating that compositional analysis decouples specifications from simulation.
Compositional point estimates land slightly above the monolithic baseline on Set A across all five composites, but the gap is within Hoeffding error in every row and shows no trend with composite length. This is evidence that the accept-conditioning fix in the backend is removing the dominant source of compositional drift, since residual multiplicative bias from un-conditioned rejection mass would grow with the number of primitives.
Efficiency at matched wall-clock budget
Set C is the two-step approach-then-turn composite , evaluated under the Markovian safe_under_max spec to isolate the wall-clock comparison. Each method runs one continuous simulation up to and records per-primitive trace counts every .

safe_under_max DFA. Left: vs. wall-clock budget , log-log. Past the simulator startup window the compositional curve sits strictly below the monolithic curve, with a log-log offset ranging from 4× at to 7× at . Right: with band as a function of . The two point estimates agree within their confidence intervals throughout, so the precision advantage is not bought through bias.Reading the wall-clock ratio at fixed target precision off the left panel yields ≈ 4× at and ≈ 7× at . Two structural advantages drive this. First, the compositional pipeline spawns one parallel worker per primitive ( together with the three turning branches, four workers in total), while the monolithic pipeline runs a single worker on the chained behavior. Second, each primitive trace covers only one composition step and is therefore a factor of two shorter than a chained composite trace under matched horizons. A third structural advantage, trace-pool reuse across composites sharing the same primitives, is not exercised in this single-composite sweep but would compound the gap on a corpus of composites built from overlapping primitive sets.
Future Work
The framework as it stands handles flat safety DFAs, automata with an absorbing rejecting state where, once acceptance is lost, it cannot be recovered. The natural next step is bounded liveness via complementation: on finite traces of length , a bounded-liveness property such as “the vehicle must exceed at some point” equals , where is the flat safety property “the vehicle never exceeds within the trace.” Appendix B of the report validates this empirically on a 4-way intersection composite ( vs monolithic ), confirming the trick is sound when the negation is itself a flat safety DFA. This works because the DFA has only two states and bad is absorbing, so collapses to Markovian on the raw simulation state.
The trick does not generalize beyond the bounded-reachability fragment. Bounded-response (“within steps of , observe ”), bounded-sequenced-reachability, bounded-persistence, and bounded-recurrence all negate to formulas with nested temporal operators rather than flat safety DFAs, and so cannot be reduced to a single absorbing-reject monitor. Compositional treatment of those classes requires either a product construction across multiple “live” DFA regions or, in the unbounded case, reasoning about infinite-suffix acceptance. A near-term path that stays within the present machinery is bounded response, which is expressible as a finite-window safety DFA and captures a large fraction of practical AV requirements without leaving the absorbing-reject framework.
Two further directions follow naturally. The current implementation lives as an extension of CompositionalAnalysisEngine; upstreaming the DFA monitor and Scenic parser into VerifAI proper would expose them to the existing falsifier pipeline. And the boundary-distribution overlap that compositional estimation requires is currently tuned by hand (spawn-distance and initial-speed calibration on Set A, randomized cruise prewarm on Set B); a diagnostic based on per-handoff effective sample size, paired with an automatic spawn/prewarm adjustment, would remove the manual calibration step and make the framework usable on new primitive libraries without per-scenario tuning.