For a line-rate stream sensor, how do you choose between simulating a nondeterministic acceptor per symbol and determinising it ahead of time?
answer
- three strategies, same language
- work per symbol against table memory
- the bound is not the forecast
- who chooses the input decides it
- keep simulation as the fallback floor
basics
~20 sTrade per-symbol work against memory. Simulation costs work proportional to the live state set but needs only that set; full determinisation costs one table lookup but up to 2^n states. Building subsets on demand splits the difference at the price of a bounded cache.
solid answer
~50 sThere are three strategies and they differ in **where the cost lands**. Simulating the nondeterministic machine carries the live subset and updates it each symbol: memory is `n` bits, per-symbol work is proportional to the live set and its outgoing edges, and nothing can blow up. Determinising **up front** gives one table lookup per symbol — the flattest latency you can get — but the table can reach `2^n` states, and for some machines it simply cannot be built. Determinising **lazily**, materialising each subset the first time input reaches it, pays the construction cost only for subsets that really occur; steady-state traffic usually touches few. The judgement calls are: can you bound the table for the machines you actually generate, is the per-symbol variance of simulation acceptable at line rate, and — if lazy — what is the cache ceiling and what happens when adversarial input keeps forcing fresh subsets.
go deeper
Recall that the same language can be matched by carrying a set of live states or by a precomputed table, and that the choice is about speed and memory, not correctness.
Explain the three strategies concretely: what each costs per symbol, what each holds in memory, and why all three accept identical strings.
Show the operational instinct — measure the reachable subset count, bound the cache, and keep direct simulation as the fallback so an overflow degrades rather than fails.
Commit to a default and name the assumption it rests on: table size for the real catalogue, the percentile the latency budget is written against, and whether an adversary can steer the input.
## Three strategies, one language All three accept exactly the same strings. The choice is purely about resource placement, which is what makes it a design decision rather than a correctness one. 1. **Simulate.** Keep the live subset explicitly. Per symbol: union the successors of every live state, close under epsilon moves, test for an accepting member. 2. **Determinise eagerly.** Run the subset construction to completion before any traffic arrives, then match with one table lookup per symbol. 3. **Determinise lazily.** Start with only the initial subset. On a symbol with no row yet, compute the successor subset once, store it, and continue. Subsets that traffic never reaches are never built. | | Simulate | Eager table | Lazy table | |---|---|---|---| | Build cost before traffic | none | full construction, up to `2^n` subsets | none | | Per-symbol work | proportional to live set and edges | one lookup | one lookup, plus a construction step on a miss | | Memory | `n` bits of live set | table for every reachable subset | table for the subsets traffic actually reaches | | Worst case | predictable, bounded | table may be unbuildable | cache growth or thrash under hostile input | | Latency shape | steady, higher | flat and lowest | flat once warm, spikes on misses | ## The questions that actually decide it **How big can the table get for the machines you generate?** The `2^n` figure is a bound, not a forecast: the construction builds only reachable subsets, and for ordinary machines that is a small number. If your machines are generated from a fixed catalogue, measure the reachable subset count for the real catalogue and you may find the eager table is a few thousand rows, which settles the argument. If machines are supplied by users, you cannot measure in advance and must assume the worst. **What does the latency budget care about — the mean or the tail?** At line rate the tail usually wins. Simulation has a *higher but steady* per-symbol cost. An eager table has the flattest cost of the three. A lazy table has the eager cost once warm, with a spike whenever it misses. If your budget is expressed as a high percentile, a warm lazy table and an eager table look alike, and simulation's steady overhead may still be acceptable while a cold lazy table's spikes are not. **Who chooses the input?** This is the question that most often flips the decision. Lazy construction's memory is driven by the *subsets the input reaches*, so an adversary who can steer the stream can walk it through fresh subsets on purpose, forcing either unbounded growth or constant eviction and rebuilding. That turns an amortised win into a sustained cost exactly when you least want it. **What happens when the ceiling is hit?** A lazy strategy needs an answer, decided up front: - **Evict and rebuild** — bounded memory, but a thrashing workload pays construction repeatedly; - **Fall back to simulation** — the subset is always computable directly, so correctness is never at risk and the degradation is a slowdown rather than a failure; - **Reject the machine at build time** — refuse to accept a machine whose bound you cannot meet. The second is usually the right default: simulation is the floor that every other strategy is an optimisation over, so keeping it available makes the cache a pure performance device. ## A defensible default For a sensor at line rate over machines you generate yourself: **measure the reachable subset count, and if the eager table fits your memory budget with headroom, build it up front.** The flat per-symbol cost is worth real money and the failure mode is a build-time error rather than a production surprise. Move to lazy construction when the catalogue is large enough that most subsets are never touched, and pair it with a hard cache ceiling and a simulation fallback. Choose pure simulation when machines arrive from outside your control, when memory is the scarce resource, or when predictability matters more than the last few nanoseconds per symbol. ## What a good answer sounds like The weak version argues abstractly for "the fastest one". The strong version names the measurement that would settle it — reachable subsets for the real catalogue, the percentile the budget is written against, and who controls the input — then commits to a default and states the fallback for when the assumption behind it breaks.
- What single measurement would most change your recommendation here?The number of reachable subsets for the machines actually in the catalogue. The `2^n` bound is worst case, and real machines often determinise to a few thousand subsets. If the eager table fits with headroom, the flat per-symbol cost makes it the obvious default and the rest of the argument is moot.
- Why is simulation the right fallback for a lazy strategy rather than a failure mode?The live subset can always be computed directly from the nondeterministic machine, so falling back is correct by construction and needs no extra state. It converts a cache overflow into a slowdown instead of an error, which keeps the cache a pure optimisation rather than something the system's correctness depends on.
- How does control over the input change the decision?Lazy construction's memory is driven by which subsets the stream reaches, so an input chosen adversarially can keep forcing fresh ones and turn an amortised win into constant construction and eviction. When the input is untrusted, prefer a bounded eager table if it fits, or plain simulation if it does not.
saying these in an interview costs you the question
- Argues from the 2^n bound without measuring reachable subsets
- Treats simulation as incorrect or approximate rather than merely slower
- Adds a lazy cache with no ceiling and no eviction policy
- Ignores who controls the input when sizing a lazy cache
- Optimises the mean per-symbol cost when the budget is a tail percentile
- Assumes determinisation changes which strings are accepted