Evacuation Simulation as the Fitness Function: GPU Generative Design with NVIDIA Warp

GD–AI Loop 2.0 · Lab Notes #6
In the previous post our GPU generative-design pipeline scored evacuation with a travel-distance formula. This time the genetic algorithm's fitness function runs a crowd evacuation simulation — dozens of people queuing and slowing down in the exit stairs — as an NVIDIA Warp kernel on the GPU. The buildings it picks changed. Then we varied the site shape 320 ways and tested again whether machine learning can propose designs for unseen sites.
Oct 25, 2026 (updated Nov 1–2; English edition and CPU vs GPU benchmark Nov 6) · Previous: Lab Notes #5, "80 million buildings in 42 minutes"
Update, Nov 6, 2026 — the crowd model in this post has been replaced. The experiments below used the v1 crowd model: one person per 1.5 m cell (so at most 0.44 persons/m²), one-cell doors, single-file stairs, 42–62 people per building and no validation. Lab Notes #8 (rewritten) replaces it with a continuous agent model (the collision-free speed model used by JuPedSim) with SFPE door and stair limits, checked against the IMO MSC.1/Circ.1533 test cases, SFPE and JuPedSim. Re-measured with that model, the simulation-objective GA still finds a building at least 5% faster in 14 of 18 multi-storey conditions when everyone starts at once, but only in 6 of 18 with a realistic pre-movement time (§3.2). Every other number in this post, including the CPU-vs-GPU benchmark, refers to the v1 model.
This post is a record from a simplified 1.5 m grid testbed of 13 × 16 cells. All sites and programs are hypothetical, and what we confirmed here holds inside this testbed. Which real design questions this could serve, and how, is covered separately in the next post (Lab Notes #7).
· We moved the crowd evacuation simulation (1 s time step, departure delays, speed differences, slowdown in exit stairs, switching stairs after seeing the queue) to an NVIDIA Warp kernel: one GPU thread = one simulation — against the CPU reference, completion time, occupant count and even the second-by-second curve match exactly for 1,808 designs, and all 6,334 designs run in 2.2 s. On one NVIDIA GB10 the kernel runs 59,733–452,601 simulations per second, 815–945× the single-process Python reference and 61–71× with 20 CPU processes.
· When we switched the pipeline's objective from "maximum travel distance" to "crowd evacuation time", two-stair designs rose from 2% to 34% (post-hoc check: this testbed originally had no exit-separation rule, so in 113 of the simulation-objective GA's 233 two-stair designs the two stairs are adjacent — counting only stairs at least 1 cell apart, 1% → 18%), and in 14 of 18 two- and three-floor conditions the fastest building became 8–40% faster (verified with random numbers the GA never saw). The price is corridor area. When we added a rule that keeps the two stairs apart in the form of real codes (the half-diagonal rule) and reran (preregistered), the two-stair share remained at distance 0% vs simulation 14% · 14%, but the conditions that got at least 5% faster fell from 14 to 10 · 11 / 18 (3.1).
· We fed 320 site shapes (4 families) × road side × 3 programs = 960 conditions into the same pipeline (36 minutes, 20,947 non-dominated designs, every simulation run recorded). On narrow sites (buildable area under 70 cells) two exit stairs rarely fit, and evacuation drops a full step slower.
· A test of proposing designs for unseen sites (preregistered v4): once the site changed, the validity rate of nearest-neighbor reuse collapsed from 21.7% to 3.6%, but learning (CVAE) did worse, at 0.2%. The fourth "learning not justified" under the preset criteria.
· So what if learning is used as the GA's starting point (preregistered v5)? Starting from the CVAE was worse even than starting at random, and a newly built "learned validity filter" also failed to beat starting from neighbors' designs — the fifth "learning not justified". Instead, an initial population of 256 designs taken from the 8 nearest sites beats 20 generations (5,376 evaluations) of a randomly started GA.
· So we fixed the default procedure for a new site as a "GPU GA warm-started from neighbors' designs" and chose among 288 neighbor rules on validation sites — switching to no road-side penalty and 16 neighbors gave a 22% improvement on unseen sites (the current rule ranked 199th of 288). 1.4 s per new polygon.
· To win on an unseen shape family (L-shaped) as well, instead of comparing sites with each other, we placed the ground floor of existing designs directly on the new site and filled the initial population with designs that "fit" — a 25% improvement on L-shapes (where the previous rule had shown no difference), and 25% on unseen sites too. Against a randomly started GA: −75% on unseen sites · −53% on L-shapes.
· For narrow sites with no fitting design, we tested 7 fallback rules such as "half random" under preregistration — the more randomness mixed in, the worse (hard validation 0.85 → half random 0.92 → all random 1.93), and on a new narrow-site test none beat the current rule, so the current rule stays. Where no rule could solve it, the problem was area (135 conditions with buildable area under 58 cells: 0 valid designs).
· So we tested, under preregistration, a pre-check that decides before the GA "does this program fit?" and, if not, proposes a program that does (menu of 9 · 120 new sites × 9 = 1,080 conditions). The classifier separated well (AUC 0.987, 5.6 ms per site), but "does not fit" precision was 93.8% (criterion 95%) and proposal hit rate 89.9% (criterion 90%), so it was not adopted. In post-hoc exploration, whenever the packing check — which tries placing the rooms and stairs — said "does not fit", there were 0 exceptions among 752 conditions — the starting point for the next preregistration.

Figure 1. Same site, same 10-room, 3-floor program, same genetic algorithm — only the evacuation objective differs. Left: the fastest building found when evacuation is scored with the travel-distance formula (one exit stair). Right: the fastest building found when every candidate is scored by a crowd evacuation simulation on the GPU (two exit stairs, side by side). Orange dots = people at t = 90 s. Full evacuation: 268 s vs 169 s (mean of 32 random seeds the GA never saw).

1. Two questions left by the last post

In Lab Notes #5 we ran the crowd evacuation for all 6,334 designs and found that the rank correlation between the travel-distance formula (the walking distance from the farthest point in a room to the outside) and the simulated crowd evacuation time was 0.86. Broadly right, but designs with the same distance differed by more than 100 seconds, and most of the difference came from three-floor buildings where people crowd into a single exit stair. First question: if the pipeline picks designs by simulation instead of the formula, will it pick different buildings?

The second question is about AI. "An AI that proposes a design given conditions" was the third "learning not justified" under the preset criteria. Changing north orientation and gate left which designs satisfy the rules unchanged, so a retrieval that simply takes the answer of a neighboring condition won. Then, under conditions that change validity itself — site shape and road side — would learning become necessary?

Where this sits. GPU agent-based simulation is not new — FLAME GPU runs large agent models on NVIDIA GPUs. Generative floor-plan design is not new either — ArchiGAN chained conditional GANs to draw apartment plans. And GPU evaluation inside a multi-objective search is how AutoDMP explores chip macro placements. What we did not find, in a survey of 84 NVIDIA technical blog posts on Warp, optimization and AI physics, is a crowd evacuation simulation running inside a building-layout optimizer, so that the simulation decides which building gets chosen. That is what this post measures — on a deliberately small testbed.

2. Crowd simulation on the GPU — three fixes to the "implementation", not the "model"

The crowd simulation works cell by cell. Occupants (half the number of room cells, 1 person / 4.5 m²) depart between 0 and 40 s, walk at different speeds of 0.8–1.5 m/s, slow to 0.6× in exit stairs, and every 3 s re-choose their stair or exit by looking at "distance + queue length within a 3-cell radius". People closest to an exit move first, one at a time. We left this model as it was and changed only the implementation, in three places, so that the GPU threads move the same people in the same way as the CPU.

  1. Random numbers — numpy random values are tied to "the order in which they are drawn", so the GPU cannot reproduce them. We replaced them with a 32-bit hash that mixes (design seed, person, time, purpose). Who moves at which second is now determined independently of order.
  2. Order — node numbering and neighbor order follow a fixed grid order (floor · row · column / down · up · right · left / stair). When several cells are at the same distance, which goes first is the same on CPU and GPU.
  3. Probability comparisons as integers — comparisons such as "move probability = speed/1.5 × 0.6 in a stair" were turned into integer inequalities in units of 1/224. This prevents the GPU's fused multiply-add (FMA) from changing the last digit and flipping a decision.

Figure 2. One generation of the GPU generative-design loop. Decoding, daylight, crowd evacuation and non-dominated ranking are NVIDIA Warp kernels (k_build, k_daylight, k_crowd, k_front); a thread owns one design, or one (design, random seed) pair in the crowd simulation.

The crowd simulation is a single Warp kernel, k_crowd, written in Python and JIT-compiled to CUDA by Warp. Each thread takes one (design, random seed) pair, builds that design's walking graph in its own slice of preallocated arrays, computes breadth-first distance fields to the exits and stairs, places the occupants with the counter-based hash, and steps 1 s at a time until everyone is out. Threads never talk to each other, so a batch of 16,384 runs is 16,384 independent loops; the price is memory, because every thread carries its own copy of the graph, distance fields and agent arrays. A simplified skeleton (helper names shortened; the real kernel writes them out inline):

import warp as wp

@wp.kernel
def k_crowd(design_of: wp.array(dtype=wp.int32), seeds: wp.array(dtype=wp.int32),
            # ... per-design grids, doors and stairs + per-thread scratch arrays ...
            out: wp.array2d(dtype=wp.int32)):
    t = wp.tid()                     # one thread = one (design, random seed) run
    b = design_of[t]
    seed = seeds[t]
    if info[b, 5] != 0:              # invalid design: nothing to simulate
        return
    build_graph(t, b)                # room cells, corridors, stair landings and flights
    bfs_fields(t)                    # distances to each exit, and to each stair per floor
    n = place_occupants(t, b, seed)  # half of each room's cells, picked by a hash
    remaining = n
    tt = int(0)
    while remaining > 0 and tt < max_steps:     # 1 s per step
        tt = tt + 1
        if tt % 3 == 1:
            choose_targets(t)        # distance + queue length within 3 cells
        sort_by_exit_distance(t)     # people nearest an exit move first
        remaining = move_one_step(t, seed, tt)  # delay, speed, stair slowdown as
                                                # integer tests in units of 1/2**24
    out[t, 0] = tt                   # evacuation time (s)

# one launch evaluates every (design, seed) pair of a generation
wp.launch(k_crowd, dim=n_designs * n_seeds, inputs=[...])
1,808
designs checked against the CPU reference — 0 mismatches in completion time, occupant count and 900-second curve
600
node and edge sets compared with the original graph (v1) — 0 mismatches
2.2 s
crowd simulation (GPU) of all 6,334 designs from the previous post
60k–480k
simulations per second (12 rooms / 3 floors to 4 rooms / 1 floor, while sharing the GPU with other jobs)

Since the implementation changed, we also checked whether "it is the same model". Rerunning the 6,334 designs with the new implementation gives a mean evacuation time of 174.9 s (previously 174.8 s) and a rank correlation of 0.927 with the previous results — the same as rerunning the old implementation with only the random numbers changed (0.926). The new implementation is just another sample of the same model.

Figure 3. Crowd evacuation simulations per second on one NVIDIA GB10 — same machine, same designs, same random seeds (benchmark added for this English edition, Nov 6, 2026). CPU = the plain-Python reference used to validate the kernel, on 1 and 20 processes of the 20-core Arm CPU. GPU = the Warp kernel at three batch sizes, median of 3 timed runs after warm-up, including the copy of results back to the host.

How fast is "fast"? On one NVIDIA GB10 the Warp kernel peaks at 452,601 simulations per second for 4 rooms / 1 floor and 59,733 for 12 rooms / 3 floors — 815–945× the single-process Python reference and 61–71× the same reference on 20 processes (Figure 3). Throughput peaks at a batch of 16,384 and dips slightly at 131,072. For every program the 1,200 evacuation times measured on both sides were identical. Two caveats: the CPU side is the reference we used to check correctness, not a tuned CPU code, so the ratio overstates what an optimized CPU implementation would give; and the GPU was shared with other jobs, as it was for the throughput figures above.

3. Experiment A — change only the objective, and the GA adds a second exit stair

Keeping the site and gate as they were, we changed only the pipeline's first objective from "maximum travel distance (formula)" to "crowd evacuation time (simulation, mean over 4 common random numbers)". The other objectives (corridor area · winter-solstice sunlight hours · gate-to-entrance distance) and the GA size (4,096 × 40 generations) are the same. 10 room/floor combinations × 2 north orientations = 20 conditions, 164 s in total.

A fair comparison needs one precaution. The simulation-objective GA optimizes evacuation time measured with 4 random seeds, so it can pick buildings that happen to be "lucky" on those 4. So we re-measured the non-dominated designs of both GAs with 32 random seeds the GA never saw.

Figure 4. 10 rooms / 3 floors · north 0°. Top = the fastest building chosen by the distance-objective GA (one exit stair); middle = the fastest building chosen by the simulation-objective GA (two exit stairs placed side by side); orange dots = people at 90 s (same random numbers). Bottom = remaining-occupant curves (median over 32 new seeds and 10–90% band). The simulation design actually has a 3 m longer maximum travel distance (39 vs 36 m), but full evacuation goes from 268 s → 169 s.

The upper building in Figure 4 has one exit stair. At 90 s, 8 people on floor 2 and 12 on floor 3 are still on their floors (in the corridor in front of the stair and in the room next to it), and 8 are descending in single file inside the stair. At the same moment, the lower building has only 1 person on floor 2 and 6 on floor 3 left on their floors, and 18 are descending, split across the two stairs — the stairs take in more people, earlier. The travel-distance formula only looks at "how far the farthest person walks", so it cannot see this queue. The simulation-objective GA placed the two stairs side by side, effectively creating a stair twice as wide. Walking distance went up, but the queue splits in half.

Figure 5. Left — in each of the 20 conditions, the building among the non-dominated designs that empties fastest (mean over 32 new seeds). Gray = distance objective, blue = simulation objective, labels on the right = change and that building's number of exit stairs. Right — all non-dominated designs for 10 rooms / 3 floors, north 0°: triangles (two exit stairs) cluster one tier lower on the evacuation-time axis.

What we measuredDistance-objective GA (v5)Simulation-objective GA (v6)
Share of two-stair designs among non-dominated designs (mean over 18 two- and three-floor conditions)2%34%
Conditions where the fastest building has two exit stairs4 / 1814 / 18
Change in evacuation time of the fastest building (2 and 3 floors)14 conditions −8 to −40% · 3 conditions within ±4% · 1 condition +28%
One-floor buildings (no exit stair)±2% — no difference
(Post-hoc check) Two-stair non-dominated designs whose two stairs are adjacent3 / 7113 / 233
(Post-hoc check) Share counting only designs whose two stairs are at least 1 cell (1.5 m) apart (mean over 18 conditions)1%18%
(Post-hoc check) Conditions where the fastest building has two stairs at least 1 cell apart2 / 188 / 18
(Post-hoc check) The two rows above, counting only stairs at least 3 cells (4.5 m) apartunder 1% · 0 / 188% · 4 / 18

We report the exceptions as they are. At 8 rooms / 2 floors, north 180°, the simulation-objective GA was actually 28% slower. The distance-objective GA happened to find one two-stair design, but the simulation-objective GA never found that region and converged to one stair. The remaining 3 conditions with no improvement (the two 10-room / 2-floor conditions, and 12 rooms / 3 floors at 0°) are also all cases where the simulation-objective GA did not find a two-stair design. This variation remains because the GA was run only once per condition. Also, the fastest building the simulation-objective GA measured with "its own 4 seeds" became slower in 16 of 20 conditions when re-measured with new seeds (median +5.6%, maximum +12.5%). Across all non-dominated designs the median is +1.4%, so this is the winner's curse: "pick what looks best and you also pick its luck". That is why every comparison in this post is based on the 32 new seeds.

(Post-hoc check) Are those "two exit stairs" two separated stairs? This testbed originally had no rule on the distance between two stairs. In the examples of the next post (#7), most two-stair designs came out with the stairs adjacent, so we reopened all non-dominated designs in this post with the same decoder (this check came after seeing the results, so it is a reported item, not a basis for the conclusions). Of the simulation-objective GA's 233 two-stair designs, 113 (48%) had the two stairs adjacent (sharing an edge: 107 · touching only at a corner: 6). Of the remaining 120, 68 also have a gap of only 1–2 cells (1.5–3 m). The design in Figure 4 is one of the adjacent ones. So the "two exit stairs" in this post must not be read as evidence of "two independent egress routes" in practice. The crowd simulation has no scenario in which one stair is blocked, so what the pipeline saw was the stairs' capacity to take in people and the splitting of queues. The rising trend remains — counting only stairs at least 1 cell (1.5 m) apart, the share goes 1% → 18%, and the conditions where the fastest building has two separated stairs go 2 → 8 / 18. But if "separated" means 3 cells (4.5 m) or more, it becomes under 1% → 8% and 0 → 4 / 18, less than half the size. What happens when an exit-separation rule is added was checked in a preregistered experiment in 3.1 below.

Figure 6. (Post-hoc check) ① Gap between the two stairs in two-stair non-dominated designs — Experiment A simulation objective, 233 designs · Experiment B site sweep, 4,957 designs. Adjacent: 48% and 36% respectively. ② The simulation-objective GA design in Figure 4 (floor 1) — the two stairs are adjacent. ③ The fastest of the designs with separated stairs under the same condition. This is an example from one condition. Gap = the larger of the horizontal and vertical counts of empty cells between the two stairs.

Lesson — the formula is not wrong; there is something it cannot see. Maximum travel distance is the answer for "walking alone", and stair queues only form when people crowd in. The moment the simulation goes into the objective, the pipeline picks a different kind of building — one that "adds a second exit stair and uses more corridor". This is a choice made possible because the GPU made simulation cheap (evaluating 168,000 buildings per condition with 4 crowd simulation runs per valid design, 3–13 s per condition).

3.1 (Preregistered additional experiment) What if the two stairs must be at least "half the diagonal" apart?

The question left by the post-hoc check above can be answered by experiment. Practice has a rule on the distance between two stairs. In a building that must provide two or more direct exit stairs, the straight-line distance between the two stair entrances must be at least half the maximum diagonal of the building plan (Korea's building egress/fire-compartment regulation and the US IBC (exit separation, IBC 1007.1.1) use the same "half-diagonal" form; relaxations such as sprinklers were not included). In this testbed, the "main entrance–emergency exit separation" rule already performs a calculation of the same form, so we attached one more instance of the same formula to the stairs — a two-stair design is invalid if the straight-line distance between the two stair doors is less than half the diagonal of the rectangle enclosing the ground floor. The GA is not prevented from escaping to a single stair. In real codes the rule applies when a second stair is mandatory, but in this testbed the second stair is optional, so the rule applies the moment it is chosen — stricter than practice.

First, how strict this criterion is. Of the 233 two-stair designs produced by this post's simulation-objective GA, only 5 satisfy the rule (the distance between the two stair doors is, at the median, 40% of the required distance). The adjacent designs are not the only problem; most separated designs also fall well short of "half the diagonal".

Apart from the rule, this is Experiment A as before (18 two- and three-floor conditions · 4,096 × 40 generations · 4 objectives · validation with 32 new seeds). To filter out the luck of a single GA run we ran two seeds, and the decision rules were written down before running. Two gates were also passed — rerunning without the rule and with the same seed reproduces this post's results in all 18 conditions, and reopening the 1,771 non-dominated designs of the rule-enforcing GAs with the CPU decoder gives 0 stair-count mismatches · 0 rule violations (the rule-free reproduction was checked only on the simulation-objective side; the original distance-objective results were produced by different run code). Six batches, 108 GA runs, 24 minutes on one server GPU.

What we measured (18 two- and three-floor conditions · seed 1 · 2)Distance objective + ruleSimulation objective + ruleReference: no rule (table above)
Share of two-stair designs among non-dominated designs (condition mean)0% · 0%14% · 14%2% → 34%
Conditions where the fastest building has two exit stairs0 · 0 / 1810 · 11 / 184 → 14 / 18
Conditions where the fastest building is at least 5% faster than the distance objective10 · 11 / 18 (median reduction 15% · 20%)14 / 18 (26%)
Conditions where the balanced default design (balance point of the four objectives) has two exit stairs0 · 00 · 0simulation 10 · 13 / 18
Corridor area of the balanced default design (median)42.8 · 42.8 m²47.2 · 43.9 m²simulation 48.4 · 49.5 m²
Share of new individuals in the last generation whose two-stair genes violate the rule1% · 0%3% · 2%simulation 41% · 32% (had the rule existed)
Cost of the rule — the simulation-objective GA's fastest building vs no rule (median)+4% · +9% (median seed-to-seed variation of the same GA: 2%)—

Figure 7. (Preregistered) Experiment A rerun with the exit-separation rule (distance between the two stair doors ≥ half the diagonal of the rectangle circumscribing the ground floor). ① For each of the 18 conditions, how many % faster the fastest building is than with the distance objective — gray = this post's rule-free result, blue = rule · seed 1 (filled) · seed 2 (open circle), dashed line = decision threshold 5%. ② Share of two-stair designs among non-dominated designs. ③④ 10 rooms / 3 floors · north 0° (same condition as Figure 4) — the fastest building of the simulation-objective GA with the rule. Seed 1 did not find a two-stair design, so it has one stair (264 s); seed 2 has its two stair doors 12.9 m apart (at least half of the 21.3 m diagonal), 172 s — this design was also the fastest in the rule-free seed 2 run (a design that satisfied the rule from the start).

Read with the decision rules fixed in advance, the results are as follows.

  • The simulation objective's gain "shrinks". Conditions where the fastest building is at least 5% faster than with the distance objective went 14 → 10 · 11 / 18, and the median reduction 26% → 15% · 20%. The threshold for "remains" was 12 or more for both seeds.
  • The two-stair preference "remains". Under the rule, the distance-objective GA produced not a single two-stair design (0%), while the simulation-objective GA produced 14% · 14%. That is, however, less than half of the rule-free figure (34%).
  • The rule has a cost. The simulation-objective GA's fastest building became slower than without the rule by a median of 4% · 9% (larger than the 2% seed-to-seed variation of the same GA).

The distance-objective GA also paid for the rule. Compared with the original rule-free distance-objective GA, the fastest building became 32–40% slower for both seeds in 4 conditions (6 rooms / 2 floors 180° · 8 rooms / 2 floors 180° · 8 rooms / 3 floors 0° · 8 rooms / 3 floors 180°). These 4 are exactly the conditions where the original distance-objective GA's fastest building had two stairs (gap between the two stairs 0–2 cells). So the comparison above is a comparison "when both obey the rule".

The following are reported items broken down after seeing the results (not a basis for the verdict). The lost share came from the larger buildings. In the 8 conditions with 4 or 6 rooms, the simulation objective was at least 16% faster in all 8 for both seeds, and the fastest buildings all had two separated stairs. In the 10 conditions with 8 or more rooms, only 2 · 3 were at least 5% faster, and those 5 are all conditions where only one seed found a two-stair design satisfying the rule (in no condition did both seeds find one). At least in these 5, such a design exists, but a single GA run did not find it reliably — in the last generation of the conditions with 8 or more rooms, the share of newly created individuals with two-stair genes fell from 25% · 15% without the rule to under 1% · 2% under the rule. The remaining 5 ended with one stair for both seeds, and of these the two 10-room / 2-floor conditions had no two-stair design among the non-dominated designs even without the rule. Even where such a design was found, the cost of the rule remains — comparing those 5 cases with the same seed's rule-free results, they are 0% · 0% · +9% · +10% · +35% slower (the two 0% cases were designs that already satisfied the rule without it).

Corridors. The corridor area of the balanced default design, a preregistered reported item, actually decreased slightly on the simulation-objective side (median 48.4 · 49.5 → 47.2 · 43.9 m²). Under the rule, all default designs have one stair (without the rule, 10 · 13 / 18 had two). Broken down after seeing the results, the rule-satisfying two-stair designs themselves have a median corridor area 48 m² larger than the one-stair designs in the same condition (median over the 21 condition–seed pairs where both types exist). Designs with two separated stairs sit at the "fastest" end and do not reach the balance point of the four objectives.

Summary — by the decision rules fixed in advance, the simulation objective's gain shrinks (14 → 10 · 11 / 18), the two-stair preference remains (distance 0% vs simulation 14% · 14%), and the rule has a cost (+4% · +9%). So this post's conclusion did not come only from "putting the stairs side by side" — even with the two stairs at least half the diagonal apart, the simulation-objective GA produces two-stair designs that the distance-objective GA never produces. Broken down after seeing the results, the gain is concentrated in the 4- and 6-room programs (8 / 8 for both seeds); with 8 or more rooms there are many conditions where a single GA run did not reliably find such a design; and designs with two separated stairs use more corridor than one-stair designs in the same condition. And this crowd simulation still has no scenario in which one stair is blocked — the gain of two separated stairs, too, does not measure "being able to get out even if one stair is blocked". Scope: one base site · 18 conditions · 2 seeds · a simple crowd model. The site sweep (Experiment B) is reported as run, without the rule.

3.2 Re-measured with the validated model (added Nov 6, 2026)

We took the final non-dominated designs of both GAs in all 20 conditions (948 designs) and ran each 10 times with the new model — once with everyone starting at the alarm, as hydraulic hand calculations assume, and once with a lognormal pre-movement time (30–120 s, 1st–99th percentile). The table compares the fastest building of each GA.

Everyone starts at onceWith pre-movement
Multi-storey conditions where the simulation-objective GA is ≥ 5% faster14 / 186 / 18
… where it is slower24
Range of the difference-33% to +41%-2% to +14%

The two-stair share among non-dominated designs is 2% (distance objective) vs 34% (simulation objective). With a realistic pre-movement time the gain shrinks to a median of +3% (vs +19% when everyone starts at once). The queues do not go away — the densest spot reaches 4 persons/m² in both cases — but the last occupant starts a median 128 s after the alarm and the building is empty 25 s later, so the end time follows the slowest starter. The new model also blocks stairs: a two-stair design keeps a second way down, a one-stair design has none.

Figure 8. Experiment A re-measured with the validated crowd model of Lab Notes #8 (everyone starts at once, 10 runs per design). Fastest design of each GA per condition; the label is the simulation-objective GA's gain.

4. Experiment B — 320 site shapes, 960 conditions

The v3 learning test failed because "the conditions did not change validity". So we built conditions that clearly do change validity. Within the same 13 × 16 grid: site polygons in 4 families (rectangle · chamfered · L-shaped · trapezoid), 80 each; the road on one of four sides; and the gate a single cell on the road-side edge. Sites are 100–198 cells, and the buildable area (the site shrunk by 1 cell) is 60–144 cells. Three programs — 6 rooms / 2 floors · 8 rooms / 3 floors · 10 rooms / 3 floors — with north fixed at 0°.

We fixed one gene. The entrance-position gene was originally "the index into the list of edge cells of the buildable area", but the list was in row order, so when the site changed, the same number pointed somewhere unrelated. We changed the list to "angle order as seen from the centroid of the area", so that 0.25 means "near the north edge" on any site. The GPU pipeline with swappable sites was also checked against the CPU — 24 sites × 3 programs × 400 genomes = 28,800, all matching down to the stage at which each one fails.

960
conditions (320 sites × 3 programs) · GA 2,048 × 30 generations per condition, 2.3 s on average
36 min
60.95 million building evaluations + 4 crowd simulation runs per valid design
20,947
non-dominated designs (872 conditions) — 0 mismatches on CPU recomputation of a 300-design sample
43 s
crowd curves · per-room sunlight · grid images recorded for all 20,947 designs

Figure 9. 16 of the 320 sites (4 per family) and the ground-floor plan of each site's 8-room / 3-floor default design (balanced design). Gray band = road, green diamond = gate. One trapezoid site with the "road on the north" had no valid design.

Figure 10. Left — share of sites where at least one valid design was found. 10 rooms / 3 floors is possible only on 73% of L-shaped and 66% of trapezoid sites. Middle — evacuation time of the fastest-emptying design per condition (dot = one site). It splits into an upper and a lower band: one stair and two stairs. Right — for 8 rooms / 3 floors, buildable cell count vs that evacuation time; color = number of exit stairs in the fastest design.

The two bands in Figure 10 are the key observation of Experiment B. On narrow sites with a buildable area under 70 cells, the fastest design has two exit stairs in only 0–4% of cases (by program); at 90 cells or more it is 86–99%. For 8 rooms / 3 floors, the median evacuation time of the fastest design is 223 s with one stair and 153 s with two. As sites get narrower, evacuation does not slow down gradually; it drops a full step at the threshold where a second stair no longer fits. (Post-hoc check — these "two exit stairs" also include adjacent designs. Of the site sweep's 4,957 two-stair non-dominated designs, 1,784 (36%) are adjacent, and of the 110 sites (8 rooms / 3 floors, buildable area 90 cells or more) where the fastest design has two stairs, 42 are adjacent (26 are at least 3 cells apart). There is no basis for reading this threshold as a threshold for "two independent egress routes" — what can be said goes only as far as a threshold of "room for a second stair". The rerun with the exit-separation rule was done only in Experiment A — 3.1.)

Figure 11. The genome of the 8-room / 3-floor default design of L-shaped site 160, inserted unchanged into the 5 most similar sites (overlap 0.81–0.85). The decoder pulls it to "the nearest legal position" each time, but only 1 of the 5 is valid — in the others, upper-floor rooms do not sit on the ground floor (support/adjacency rules) or there is no place for a door.

Figure 11 previews the next section. In v3, the answer of a neighboring condition stayed valid even when north orientation and gate changed. When the site changes, it does not. Even on "twin sites" with an overlap above 0.8, most become invalid.

Figure 12. Crowd evacuation curves of all 20,947 non-dominated designs from the site sweep (share still in the building, median and 10–90% band). The first 50 s are the same regardless of stair count; after 50 s, when people start crowding into the stairs, the two-stair side empties faster.

While building this record we caught one more defect. In the first version of Figure 12, the median of the two-stair curve rose again partway through. "Remaining occupants" cannot increase. The cause was that the GPU curve buffer was reused many times without being cleared — after an evacuation finished, values from the previous design remained in the slots. The earlier check had passed because it was the first call and the buffer was empty. After the fix, a 300-design sample checked against the CPU over all 900 slots had 0 mismatches, and among the 20,947 designs there were 0 curves that rose again. This defect was only in the curves and did not affect evacuation times (which are written fresh every time).

5. AI facing unseen sites — setup v4

The question is the same as in v3. Given a new condition, can we propose good designs with few evaluations (256), and does that require learning? The difference is that the condition is "an unseen site". While the site sweep was running, before running any learning or comparison method even once, we fixed the decision criteria in a document (preregistration document v4). The document stated in advance: "nearest-neighbor reuse will weaken; we do not know whether the CVAE will win".

  • Ground truth: the non-dominated designs the GPU GA found for that site and program. Metric: IGD+ (lower is better; 2.0 if there is no valid proposal). Proposals were also evaluated with the same pipeline and the same random numbers.
  • Comparison: R0 random · R1 reuse of the answers of the single most similar training site · R3 alternately pooling the answers of 8 similar sites (new in v4) · R2 small GA · L1 CVAE (site mask · buildable mask · road side · gate position → genome).
  • Splits: (a) 20% of the sites (64) held out entirely for testing — unseen sites · (b) all 80 L-shaped sites for testing — an unseen shape family.

Figure 13. Proposal quality by budget (left, lower is better) and validity rate (right). Solid = unseen sites, dashed = the unseen L-shape family. Dark green (pooling 8 neighbors) is best, and blue (CVAE) is almost the same as random (gray).

Budget 256R0 randomR1 1 neighborR3 8 neighborsR2 small GAL1 CVAEL1 − best non-learning (95% interval)Verdict
Unseen sites · 180 conditions1.831.080.881.791.90+1.02 [+0.65, +1.27]"learning not justified"
Unseen L-shapes · 212 conditions1.911.451.371.861.96+0.59 [+0.49, +0.70]"no generalization"
Validity rate (unseen sites)0.1%3.6%4.1%0.9%0.2%R1 in v3 (north/gate conditions): 21.7%

Half of the prediction was right. When the site changed, the validity rate of nearest-neighbor reuse collapsed from v3's 21.7% to 3.6%. Test conditions with no valid proposal at all were 34% for R1, and 63% in the L-shape family. But learning did not fill that gap. The CVAE produced no valid proposal in 93% of conditions (97% for L-shapes), almost the same as random. On the surface this looks like v3. The CVAE tends to produce the "middle" of good designs (confirmed in v3), while the decoder's "can place / cannot place" boundary is sharp, and this time it lies in a different place for each site. Whether the cause is the number of training sites (256) or the model architecture (an MLP on flattened masks) was not tested separately this time — we do not know yet.

Four preregistrations (v1 evaluation surrogate · v2 behavioral-simulation surrogate · v3 conditions → design · v4 unseen site → design) all ended in "learning not justified". In this testbed, the "AI slot" is taken by retrieval (the answers of 8 similar sites) + GPU GA. For one new site, a GA of 2,048 × 30 generations takes 2.3 s on average, and that result is itself the "ground truth" of this test. To win, learning would have to be that good for less than 2.3 s, and it could not even get past validity.

Time: proposal generation R3 0.13 ms · CVAE 0.5 ms · small GA 28 ms (median per condition). CVAE training 12–17 s per program.

6. Learning as the "GA starting point" — setup v5

The v4 CVAE could not produce "ready-to-use designs" for unseen sites. So let us lower its role. If learning fills only the GA's initial population and the GA does the rest, does the number of evaluations needed to reach the same quality drop? Again we fixed the decision criteria before running the methods (preregistration document v5).

  • Test GA: 256 individuals × 20 generations (5,376 evaluations = 8.5% of the site sweep's reference GA budget). The random numbers for selection, crossover and mutation were kept identical across methods, and only the initial population differed. Primary metric = IGD+ at generation 10 (2,816 evaluations) (against all valid designs found up to that point).
  • Four ways to fill the initial population of 256: C0 random (an ordinary GA) · W3 the answers of 8 similar sites (v4's R3, non-learning) · WL CVAE samples (v4's L1, learning) · WF learned validity filter (new in v5, learning) — on the training sites, 100,000–130,000 "neighbor answer + random" genomes are run through the pipeline to create valid/invalid labels and train a classifier; on the test sites it picks the top 256 by "probability of being valid" from 4,096 candidates. Since what blocked learning in v4 was "validity", this method targets it head on.
  • Decision: if either WL or WF is at least 10% lower than the best non-learning method (C0 · W3) at generation 10, and the upper bound of the 97.5% interval of the paired difference (Bonferroni, for two methods) is < 0, then "learning justified".

Figure 14. Left — progress of GAs that differ only in their starting point (x-axis = number of evaluations). Solid = 180 unseen-site conditions, dashed = 212 unseen L-shape conditions; mean of per-condition IGD+ capped at 2.0 ("no valid design"). Middle — per-condition comparison at generation 10; above the diagonal = the learned starting point is worse. Right — validity rate of the initial population of 256.

Generation 10 (2,816 evaluations)C0 randomW3 8 neighborsWL CVAEWF learned filterVerdict
Unseen sites · preregistered metric (mean)1.230.731.410.69WF −5%, 97.5% interval [−0.49, +0.20] → "learning not justified"
Unseen sites · capped at 2.0 (post hoc)1.230.521.280.69WF 31% worse than W3
Unseen L-shapes · preregistered metric1.490.961.641.03"no generalization"
Initial-population validity rate (unseen sites)0.2%4.1%0.2%2.4%
Reached IGD+ ≤ 0.5 within 20 generations (unseen sites)43%82%40%77%

Here is why the table has two rows. After seeing the results, we found a few conditions where IGD+ far exceeds 2.0 (maximum 28.4). This is a property of the metric: when one objective's range in the reference non-dominated set is very narrow, the normalized value becomes large. On unseen sites, 3 such conditions fell on the W3 side and pulled W3's mean up from 0.52 to 0.73, which is why the preregistered metric made it look as if "WF is 5% better". Capping per-condition values at 2.0, the same value as "no valid design", WF is 31% worse than W3 (per condition, WF is better in 46 and worse in 115). This analysis is post hoc and was not used for the verdict, and the verdict is the same either way. We also recomputed the v3 and v4 results the same way, and their verdicts were unchanged.

In summary:

  • Starting from the CVAE was worse even than random (1.41 vs 1.23; on L-shapes, worse in 64 conditions and better in 32). It cannot provide valid starting points, and its samples may also not spread as widely as random ones (not tested separately).
  • The learned validity filter (WF) raised the starting validity rate from random's 0.2% to 2.4%, but fell short of W3 (4.1%), which uses the 8 neighbors' answers as they are. Even though all the original neighbor answers were among the 4,096 candidates, the classifier picked less valid ones instead.
  • The real winner is the non-learning starting point. On unseen sites, W3's initial population (256 evaluations) is already better than 20 generations (5,376 evaluations) of a randomly started GA (2.0-capped mean 0.73 vs 0.94). In the L-shape family it also catches up by generation 3 (1,024 evaluations).

Time: one GA run (5,376 evaluations + crowd simulation of valid designs) median 0.2–1.1 s (longer with more valid designs, since there are more crowd simulation runs). Training cost: CVAE 7–13 s; filter about 4–5 s for 100,000–130,000 labeling evaluations + about 4–5 s of training (per program).

7. Standard procedure for a new site — a GPU GA warm-started from neighbors' designs

We fixed the conclusion of v5 as a procedure. When a new site comes in, fill the initial population of 256 with the non-dominated answers of existing sites with similar shapes for the same program, and run the GPU GA for 20 generations. What remains is the rule: "how many similar sites, chosen how, filled how". No learning was used; we only refined the rule. But to avoid tuning to the test sites, we set the order in advance (neighbor-rule tuning protocol): choose on validation sites split off from the training sites (52 sites, 142 conditions), and check only once on the test sites.

  • 288 candidates: 4 distances (site overlap + road-side penalty (current) · site overlap only · buildable-area overlap + road · centroid-aligned overlap + road) × 2 gene-transfer options (translating the stair and room preference points of neighbor answers by the centroid difference of the two sites) × 6 neighbor counts (1–32) × 2 fill orders (alternating · nearest site first) × 3 jitter levels.
  • Stage 1: evaluate only the initial population (256 evaluations) for all 288 and keep the top 6 → Stage 2: run the GA for 20 generations with those 6 + the current rule + random → choose the one lowest at generation 10 → Stage 3: compare it with the current rule on the test sites. The metric is per-condition IGD+ capped at 2.0, as in the v5 post-hoc note.

Figure 15. Left — Stage 1, quality of the initial population alone (lower is better) by number of neighbors k. Green (site overlap only) is lowest, and the current rule (dark green solid) sits toward the top. Middle — Stage 2 GA progress (orange = selected rule, dark green = current). Right — Stage 3 test.

Changing the rule one step at a time (validation sites, initial population only)IGD+ (capped at 2.0)
Current W3 — site overlap + road penalty · 8 neighbors · alternating · σ 0.050.82
+ remove road-side penalty0.61
+ shift neighbor-answer genes by the centroid difference0.57
+ 16 neighbors0.56
+ fill from the nearest site's answers first = selected rule0.53

Most of the improvement came from removing the road-side penalty. The current rule added 0.5 to the distance when the road side differed, pushing out sites with more similar shapes. We take this to be because which designs are valid is determined by site shape, while gate position enters only one objective, "gate-to-entrance distance". Raising only the neighbor count to 16 was actually worse when changed alone (0.85) — the benefit of more neighbors appeared only once the distance was right. Among the 288, the current rule ranked 199th.

Test (once)Generation 0Generation 10Generation 20Initial-population validitySelected − current (generation 10, 95% interval)
180 unseen-site conditions · selected / current / random0.57 / 0.73 / 1.760.41 / 0.52 / 1.230.33 / 0.42 / 0.946.8% / 4.1% / 0.2%−0.11 [−0.18, −0.05] · better 99 · worse 64
212 unseen L-shape conditions1.20 / 1.36 / 1.890.91 / 0.95 / 1.470.66 / 0.77 / 1.211.3% / 0.9% / 0.0%−0.04 [−0.12, +0.05] · better 72 · worse 87

It passed the adoption rule fixed in advance (upper bound of the paired-difference interval < 0 on unseen sites), so we made the selected rule the new default. On unseen sites it improved by 22% at generation 10. On the unseen L-shape family the difference is small and the interval crosses 0. This seems to be because when the shape family itself is new, even the "nearest sites" are not that near (in v4, the median overlap with the nearest site was 0.83 for unseen sites and 0.79 for L-shapes). As a check, the 784 progress curves of the current rule and random rerun in Stage 3 were identical to the v5 curves in every generation.

Figure 16. The standard-procedure tool newsite --pts "1,2;14,1;15,11;3,12" --road 0 --N 8 --F 3 — the result for a single new polygon not in the site list. Top = 8 of the 16 existing sites with the closest shapes; bottom = the balanced default design produced in 1.4 s (two exit stairs, evacuation 161 s). The same GA started at random gives 4 non-dominated designs, with a fastest evacuation of 227 s.

The tool is used in two ways. For a site in the site list, --site N (that site's own answers are excluded from the neighbors); for a new site, --pts vertices · --road road side (if the gate is omitted, it goes at the middle of the road side). We note the limits too. Existing answers for the same program are required; for an unseen program (room count · floor count) there are no neighbors, and it becomes the same as a random start.

8. An unseen shape family — choosing "designs", not sites

The Section 7 rule improved unseen sites by 22%, but on the unseen L-shape family the difference was not significant (0.91 vs 0.95). Since the L-shapes had already been used for testing once, this time we used them only for the final test and did not look at them during selection. Instead, among the other three families (rectangle · chamfered · trapezoid), we ran three validations, each holding out one entire family as the "unseen shape" (20 sites per family). The procedure was fixed in a document in advance (shape-family distance protocol).

  • 12 candidates: current (site overlap · 16 neighbors) · centroid-aligned overlap (overlap after aligning the centroids of the two buildable areas) · maximum overlap (overlap after shifting within ±3 cells to maximize it, with the genes shifted by the same amount) · shape features (cell count · bounding rectangle · fill ratio · "number of positions that fit" for each room and stair size), each with 8 · 16 · 32 neighbors, plus 2 variants of footprint fit.
  • Footprint fit does not compare sites with each other. It shifts the ground floor (rooms · corridor · stairs) of each existing design onto the new site by the centroid difference and measures what % of it falls inside the new buildable area. The initial population is filled with the 256 designs with the highest ratio (ties broken by closest site overlap).

Figure 17. Existing designs' ground floors placed on unseen L-shaped site 160. Blue = inside the buildable area, red = outside. The designs the current rule picks first (the designs of the most similar site, 246) stick out by a little over 20% of the ground floor into the empty corner of the L. The new rule picks designs from a site of another family (38) that fit entirely. Right = fit distribution of the initial population of 256 (mean 0.84 vs 0.97).

Figure 18. Left — Stage 1 (initial population only, mean of 3 leave-one-family-out folds, dots = per fold). Middle — Stage 2 GA. Right — Stage 3 test (solid = L-shapes, dashed = unseen sites).

Stage 1 separated the order clearly: footprint fit (0.35) < maximum overlap (0.38) < centroid-aligned overlap (0.39) < current site overlap (0.52) < shape features (0.54–0.57). Distances that consider "how far the site must move to overlap" beat "how much the site overlaps in place", and placing the designs directly is best of all. Shape features summarized as numbers were actually worse than the current rule. In Stage 2 (20 GA generations), footprint fit was again lowest (generation 10: 0.289 · centroid-aligned 0.298 · maximum overlap 0.315 · current 0.377), and became the candidate rule.

Test (once)Generation 0Generation 10Generation 20Initial-population validityNew − current (generation 10, 95% interval)
212 unseen L-shape conditions · new / current0.86 / 1.200.68 / 0.910.50 / 0.665.3% / 1.3%−0.23 [−0.30, −0.16] · better 137 · worse 28
180 unseen-site conditions · new / current0.37 / 0.570.31 / 0.410.26 / 0.3314.7% / 6.8%−0.10 [−0.16, −0.05] · better 122 · worse 42

It passed both adoption rules (upper bound of the interval < 0 on L-shapes, and no worse on unseen sites), so we made footprint fit the new default. It improved by 25% on L-shapes and by 25% on unseen sites as well. Again, the 392 curves from rerunning the current rule were all identical to the Section 7 values (modifying the module left the existing rule's results unchanged).

Cumulative change in IGD+ at generation 10Random startv5 8 neighborsSection 7 ruleSection 8 footprint fit
Unseen sites (180)1.230.520.410.31
Unseen L-shapes (212)1.470.950.910.68

Figure 19. The standard tool rerun with the new rule (the same new polygon as Figure 16). Top = existing designs whose ground floor fits entirely (the initial population of 256 came from 40 sites). 21 non-dominated designs (15 with the Section 7 rule). On this one site, however, the fastest evacuation was 178 s, slower than with the Section 7 rule (161 s).

We also found one limit. When we drew in a narrow L-shape by hand (vertices 1,1;15,1;15,6;8,6;8,12;1,12, 8 rooms / 3 floors), there was not a single existing design whose ground floor fit entirely (median fit 0.82). In this case the GA started with the new rule found no valid design in 20 generations, while the random start found 1. What to fill the initial population with when no fitting design exists was tested in Section 9. On site 17 there were 26 non-dominated designs (Section 7 rule 8 · v5 rule 2 · random 0).

9. Narrow sites with no fitting design — does mixing in randomness help?

The Section 8 rule first picks existing designs whose ground floor fits "entirely". If there are none, the initial population is filled with designs that stick out a little. Of the existing 960 conditions, 143 had 0 neighbor designs that fit entirely, and 257 had 8 or fewer. Is it better to mix in randomness in such cases? We fixed 7 fallback rules, the selection method and the adoption criteria in a document in advance (narrow-site fallback protocol) and tested them.

  • Candidates: R0 current (top 256 by fit) · R1 half random · R2 one-quarter random · R3 only the entirely fitting designs + the rest random · R4 only ≥95% fit + the rest random · R5 half random only when fewer than 64 fit entirely · R6 fill by jittering only the entirely fitting designs. Baseline C0 = all random.
  • Selection: on the sites other than those reserved for testing (L-shapes · unseen sites), 84 "hard" conditions with 8 or fewer entirely fitting neighbor designs, and 60 ordinary conditions. Rules that get more than 0.02 worse than the current rule on the ordinary conditions are excluded.
  • Test 1 (once): 100 newly generated narrow sites (25 each of narrow L-shaped · narrow long rectangle · steep trapezoid · U-shaped, buildable area 40–80 cells) × 3 programs = 300 conditions. Compared on the 86 conditions where the same reference GA as in the site sweep (2,048 × 30 generations) found a valid design. Test 2: whether there is any loss on the Section 8 test conditions.

Figure 20. ① Selection (generation 10; dark = 84 hard conditions · light = 60 ordinary conditions). ② GA curves on the 86 new narrow-site conditions. ③ Conditions where at least one valid design was found within 20 generations — dark = the 86 conditions where the reference GA found a solution, light = the 214 conditions where even the reference GA found none (exploration outside the preregistration). ④ Share of conditions where the reference GA found a valid design, by buildable cell count (solid = the 320 existing sites, dashed = the 100 new narrow sites).

The result pointed one way. The more randomness mixed in, the worse — at generation 10 of the hard validation: current 0.85, one-quarter random 0.84, half random 0.92, only entirely fitting designs plus random 1.33, all random 1.93. We picked the lowest, R2 (one-quarter random), and tested it once on the new narrow sites, but it was actually higher than the current rule (0.84 vs 0.82, difference +0.03, 95% interval [−0.05, +0.11]). It did not meet the adoption criterion (upper bound of the interval < 0), so the default stays as the current rule (footprint-fit order). On ordinary sites they were nearly the same (unseen sites +0.01 · L-shapes −0.00).

Test 1 — 86 new narrow-site conditionsGeneration 0Generation 10Generation 20Initial-population validityValid design within 20 generations
R0 current (top by fit)1.040.820.593.2%90%
R2 one-quarter random (1st in validation)1.070.840.632.9%87%
C0 all random2.001.621.300.0%49%

Even designs that do not fit entirely mostly carry structure such as the positions of the stairs and rooms. So they seem to start much closer than random genomes (conditions where a valid design was found: 90% vs 49%). Mixing in randomness amounts to throwing away part of that starting point. That R3, which kept "only the entirely fitting designs", was the worst after all random points the same way.

The real problem lay elsewhere. In 214 of the 300 conditions, even the reference GA (random start, 63,488 evaluations) found no valid design at all. When we ran the three rules on these conditions (exploration outside the preregistration), valid designs were found within 20 generations in only 4 (current) · 5 (R2) · 2 (random) of the 214. This is not a problem a starting rule can solve. As Figure 20 ④ shows, the cause was area. Among the new narrow sites, on the 45 sites (135 conditions) with a buildable area under 58 cells (about 130 m²) no program had a valid design, and at the same area, narrow shapes were harder (6 rooms / 2 floors at 72–80 cells: existing sites 78/78 · new narrow sites 15/18). On 57 of the 100 narrow sites, none of the three programs had a valid design. What such sites need is not a different starting point but a notice that "this program does not fit". Of the 86 sites where 10 rooms / 3 floors failed, 29 had valid designs for 6 rooms / 2 floors or 8 rooms / 3 floors.

10. Before running the GA — "does this program fit on this site?"

We turned the conclusion of Section 9 into a tool. Before the GA runs, it looks only at the site shape and the program and answers "fits / does not fit / uncertain (confirm with the GA)". If the program does not fit, it proposes a program that does fit on the same site. Again, the candidates, selection method and adoption criteria were fixed in advance (program pre-check protocol).

  • Program menu of 9: 4 rooms / 1 floor · 4 rooms / 2 floors · 6 rooms / 2 floors · 6 rooms / 3 floors · 8 rooms / 2 floors · 8 rooms / 3 floors · 10 rooms / 2 floors · 10 rooms / 3 floors · 12 rooms / 3 floors.
  • Inputs:
    • Buildable cell count and site cell count, the largest inscribed rectangle, and the number of positions that fit for each room size.
    • Room area of the largest floor and the "buildable / required area" ratio.
    • Packing check: backtracking that tries to place the rooms and stairs of the largest floor in the buildable area without overlap.
  • 5 candidates: per-program area threshold · area ratio · logistic regression · logistic + packing check · boosted trees. One was chosen by site-level cross-validation on 420 existing sites, and the "does not fit" and "fits" thresholds were each set for 97% precision.
  • Test (once): 120 newly generated sites (15 each of the 4 existing families + 4 narrow families) × 9 = 1,080 conditions.
    • Ground truth "fits" = at least one of the following three found a valid design: the reference GA (2,048 × 30 generations) · a GA with a different seed · a GA warm-started from neighbors' designs.
    • Adoption criteria: precision of "does not fit" and of "fits" each 95% or more, and a decision rate of 60% or more. Proposal hit rate 90% or more.

Figure 21. ① AUC by candidate (open dot = cross-validation on training sites, filled dot = new test sites). ② Three-way verdicts and ground truth for the 1,080 test conditions. ③ By site family (hatched = wrong verdict). ④ The 9-cell menu for three test sites — color = verdict, ○/× = ground truth, thick border = request and proposal. ⑤ Proposal hit rate and room loss. The blue bottom row (⑥–⑧) is exploration after seeing the test and is not a basis for adoption.

The classifier separated well. All five candidates had an AUC of 0.96–0.99. As preregistered, among the candidates within 0.01 of the best (boosting, 0.992) we chose the simplest, logistic regression, and on the test it reached 0.987, higher than the area threshold (+0.015, 95% interval [0.005, 0.027]). Judging the 9 menu items for one site takes 5.6 ms. But it narrowly missed two of the criteria.

1,080 test conditionsConditionsGround truth: fitsPrecisionAdoption criterion
Verdict "fits"57255997.7%95% or more — pass
Uncertain → confirm with GA5732—
Verdict "does not fit"4512893.8%95% or more — fail
Decision rate (fits + does not fit)1,02394.7%60% or more — pass
Proposal (when "does not fit")32629389.9%90% or more — fail

So the pre-check was not added to the new-site tool. The tool contains only the hook-up code, which turns on only when a verdict adopted through a test exists. It is currently off. Of the 28 wrong "does not fit" verdicts, 18 came from narrow L-shaped and U-shaped sites — shapes with an empty corner. The 33 missed proposals were concentrated in steep trapezoids and U-shapes.

After the test we looked into the errors (exploration outside the preregistration, bottom row of Figure 21).

  • When the packing check said "does not fit", there were no exceptions.
    • Conditions where the rooms and stairs of the largest floor could not be placed without overlap: 476 in training · 276 in testing. In these 752 conditions a valid design never appeared. The same held for the test conditions on which three confirmation searches were run.
    • Because room sizes are fixed in this pipeline, this check appears to be a necessary condition.
    • All 28 wrong "does not fit" verdicts came from conditions that passed this check. Splitting the 451 "does not fit" verdicts, the 273 that failed the packing check had 100% precision, and the 178 that passed had 84%.
    • The chosen logistic regression was a candidate that does not use the packing check (it was within 0.01 of the candidate with the packing check, so the simpler one was chosen).
  • Part of it was a stricter ground truth. In 8 of the 28 errors, a valid design appeared only in the second or third search. Measured with the same definition as the training ground truth (one GA run), "does not fit" precision would have been 95.6%.
  • Splitting into two stages passes all three criteria on the same test.
    • Rule: "does not fit" only on packing-check failure · "fits" when the check passes and the score is at or above the threshold · everything else goes to the GA.
    • Result: 276 "does not fit" at 100% precision · 570 "fits" at 98.1% · decision rate 78%.
    • This rule was built after seeing the test, so it is not adopted. It must be preregistered again with new test sites.
  • Why proposals miss. Choosing "the program with the most rooms among those judged to fit" made proposals prone to sitting on the decision boundary (median score of missed proposals 0.71, of correct proposals 0.94). Raising the score floor to 0.8 brings the hit rate to 94.8%. In exchange, the room loss of correct proposals rises from 0.43 to 0.88 rooms, and "none" increases from 125 to 160 cases.
Same idea, other domains. Sections 6–8 test the same logic as a PhysicsNeMo CFD study, where a neural operator predicts a steady-state flow field that warm-starts a lattice-Boltzmann solver and cuts convergence time by up to 50%: learning provides the starting point and the solver does the rest. In this testbed the best starting point did not come from a learned model but from retrieval — neighbors' designs, then designs whose ground floor fits the new site. Experiment B is also, in effect, simulation-generated training data: 960 conditions, 20,947 non-dominated designs and every simulation run recorded, in 36 minutes on one GPU. Here, four preregistered tests found that learning on it was not justified — evaluation is cheap and similar answers are plentiful. That is the condition to check before reaching for a model.

11. What we learned

  1. The objective changes the "kind" of design. The travel-distance formula cannot see stair queues, so it almost never picks two exit stairs (2%). With the crowd simulation in the objective that rose to 34%, and the fastest evacuation of two- and three-floor buildings mostly got 8–40% faster. This is a choice made possible because the GPU made simulation cheap. However, with no exit-separation rule, nearly half of those two-stair designs (113/233) have the two stairs adjacent, and the crowd simulation also has no scenario in which one stair is blocked — they must not be read as evidence of "two independent egress routes" (post-hoc check in Section 3). Even with a rule keeping the two stairs at least "half the diagonal" apart, the two-stair preference remained (distance 0% vs simulation 14% · 14%), but the gain shrank (14 → 10 · 11 / 18) — the preregistered verdict of 3.1. Broken down after seeing the results, the gain is concentrated in the 4- and 6-room programs.
  2. A stochastic simulation can also be ported to match the CPU "exactly". Keep the model and change only the random numbers (counter hash) · order (fixed grid) · comparisons (integers). And whether the changed implementation is the same model is checked statistically against "the old implementation rerun with only the seed changed".
  3. The figure is the final check. Even after every numerical check had passed, a single figure in which "remaining occupants increase again" exposed the buffer-reuse defect.
  4. Pick what looks best and you also pick its luck. The best design chosen with 4 seeds was a median 5.6% slower on new seeds. Compare with random numbers the GA never saw.
  5. Under conditions that change validity, retrieval weakened — but learning was weaker still. The CVAE in this setup could not cross the deterministic decoder's "can place / cannot place" boundary (whether the cause is data volume or model architecture is not yet known).
  6. Even with learning's role lowered to the "starting point", the neighbors' answers win. An initial population from the answers of 8 neighbors beats 20 generations of a randomly started GA, and even a learned filter aimed squarely at validity could not beat it. Five preregistrations point the same way — in this testbed, "retrieving the answers to similar problems" is cheaper and stronger than learning.
  7. When refining a procedure, "what counts as near" comes first. More than the neighbor count or the fill order, removing a single road penalty so that "sites with similar shapes" were picked correctly accounted for most of the improvement. The current rule ranked 199th of 288.
  8. "Does that design fit this site?" rather than "do the sites look alike?" What won on an unseen shape family was not a site-to-site distance but footprint fit — placing existing designs' ground floors directly on the new site. Shape features summarized as numbers were actually worse.
  9. An "almost fitting" starting point beats random. When no fitting design existed, mixing in randomness made things worse. And the narrow sites that no rule could solve had an area problem, not a starting-point problem — what is needed then is not a different start but a verdict that "this program does not fit".
  10. Do not mix proofs and estimates of "it cannot". When the check that actually tries placing the rooms and stairs said "it cannot", there were no exceptions in 752 conditions. All of the learned verdict's wrong "cannot" cases came from places that passed this check. It seems right to leave the provable side to rules and use learning to separate "likely to fit" from "uncertain". And even a narrow miss, like 93.8% vs 95%, is still a miss.
  11. The metric is part of the preregistration too. A few conditions with a narrow normalization range could flip the mean. From the next preregistration on, a cap (2.0) or a range floor goes into the primary metric.

Next

  • Next post #7 — directions for practice: early-stage plan review that evaluates evacuation with crowd simulation · new sites started from past designs · an instant answer to "does this program fit?" · criteria for deciding where to use AI
  • Lab Notes #8 — simulation to AI training, in pictures: the same crowd simulation staged in NVIDIA Omniverse, and a U-Net trained on the 20,947 simulated designs of the site sweep to predict where people queue
  • (Done — Sections 7, 8, 9, 10) Fixed the default procedure for new sites → footprint fit: unseen sites −25% · unseen L-shapes −25% · 7 fallback rules for narrow sites did not beat the current rule (current rule kept) · the pre-GA pre-check narrowly missed its criteria and was not adopted
  • A second preregistration of the pre-check — "does not fit" = packing-check failure (proof) · "fits" = learned score, with the proposal score floor chosen on training sites, tested once on new test sites
  • Where learning will be tested again — the starting point for conditions with no neighbor answers (entirely new programs or site sizes), or learning "next-generation proposals" inside the GA
  • Learning inside the decoder — filtering proposals with a validity classifier, or learning "site → layout map" from grid images (already recorded) and refining with the decoder
  • Stair width and count as genes (currently 1–2); a rule for two independent egress routes and the exit-separation rule in the site sweep (Experiment B) as well — tried in Experiment A (3.1); a way for the GA to reliably find rule-satisfying two-stair designs in large buildings

Reproducibility

Every number in this post is read from run logs written by the scripts, not copied by hand. Every test marked "preregistered" had its decision rule written down before the run, and results that came after looking at the data are labeled post hoc. The GPU kernels were checked against the CPU reference implementation: 1,808 designs for the crowd simulation, 28,800 decoder steps for changing sites, and 1,200 runs per program in the benchmark. The code is not public yet. All sites, programs and rules are hypothetical.

Resources

댓글

이 블로그의 인기 게시물

Structural Analysis Workflow with Dynamo and Robot

Dynamo with the Gemini Vision API test(Nano Banana)

Geometry test 0506 stair and routing