Concepts and terms¶
TrackGen builds many tracks (or gate sequences) at once, one per simulated environment, and then answers per-step questions about them inside your simulator. The whole library follows one data flow:
seeds [E]
│
▼
generator ── a pipeline of stages: generate a loop, resample, relax, build the road
│ band, check it (a spec, usually from a preset)
▼
result ───── Track or GateSequence: flat device arrays, valid[E], fail_mask[E]
│
▼
course ───── components: checkpoints, progress, collision, localization, props, yours
│
▼
your sim ─── binds its buffers, calls step() / reset(mask) / regenerate(mask=...)
The batch. Everything is batched over a fixed number E of envs.
Each env gets its own seed, and its own epoch that advances when it needs
a new track. The batch size, the device and the per-env capacity (N_max points
per track, max_gates slots per gate sequence) are fixed when the generator is built,
so every buffer is allocated once and keeps its address: a CUDA graph recorded over it
stays valid.
The generator. A TrackGenerator or GateGenerator runs a pipeline of
stages described by a spec. A preset builds the usual
spec from a few keywords; each stage takes typed Params, and its
dynamic fields hold one value per env, which you can change
between generations. Stages pass data to each other through
channels. One run of the pipeline over the batch is a
generation; construction runs the first one.
The result. A generation writes a Track (a road: centerline, borders, frames)
or a GateSequence (gate poses) as flat device arrays, [E * N_max] per point
and [E] per env. Every env passes through the pipeline’s checks: valid says
whether it passed, and the fail bits say which checks failed. An
invalid env stays in the batch until you regenerate it.
The course. A course drives one generator and its runtime components for the whole batch: it binds your simulator’s buffers (agent poses), steps every component (progress events, collision contacts), respawns envs on their course, and regenerates selected envs. All of it runs on the device, so you can record a whole sim step into your own CUDA graph (a capture); with conditional nodes, a masked regeneration with nothing to do is skipped on the device.
The Quickstart shows each step in code.
Glossary¶
- env¶
One slot of the batch, indexed
e = 0 .. E - 1: one track or one gate sequence, with its own seed and epoch, and the course one agent of your simulator drives. Every per-env array hasEentries.- E¶
- num_envs¶
The batch size: the number of envs a generator builds in every generation (
num_envs=in the presets and configs). It is fixed when the generator is built.- N_max¶
A
Track’s per-env point capacity (n_max=inpresets.track,N_maxinTrackGenConfig; 384 by default): every per-point array hasE * N_maxrows, and enveuses the firstcount[e]. A track that needs more points is cut short and marked invalid (fail bittruncation): keepN_max >= max perimeter / spacing + 1.- spacing¶
The distance between consecutive points of a track’s centerline: every track is resampled to a constant spacing (by default
0.6 * half_width). With N_max, it bounds the longest track a batch can hold.- size¶
A per-env multiplier of a course’s extent in the plane (the generator’s dynamic
sizefield, 1 by default, from 0.1 to 10): at size 2 a course is twice as large, with the same road width. Larger sizes need a larger N_max.- seed¶
A per-env
int32that, with the env’s epoch, determines its track or gate sequence.seeds=kgives envethe seedk + e; aPerEnvSeededRNGor an[E]int32array sets them one by one.- epoch¶
A per-env counter (
gen.seeds.epoch, 0 at construction).generate(advance=True)andregenerate(advance=True)add one to every env, or to the envs of a mask, so they get a new track from the same seed. For a given generator, the same(seed, epoch)always rebuilds the same output.- generation¶
One run of a generator’s pipeline over the whole batch: construction runs one, and so does every
generate()/regenerate()call (a masked one changes only the masked envs). The result’sgenerationfield holds the epoch each env was built at.- valid¶
valid[e]([E]int32, on every result and on a course’sStepResult) is 1 when envepassed every check of its pipeline, 0 when it did not (an invalid env).- fail bits¶
fail_mask[e]has one bit set per check envefailed (0 exactly when it is valid);result.fail_bitsmaps each check’s name to its bit, for a trackgenerator,turning,finite,thickness,w_floor,border,gradeandtruncation.- invalid env¶
An env with
valid[e] == 0. By default its geometry stays in the result, but every runtime utility answers for it as for an env with no track (off the road, no checkpoints, frozen progress). Gate rewards, observations and episode ends onvalid, and give the env a new course with a masked regeneration (Invalid envs).- preset¶
A function that builds a standard configuration from keyword arguments:
presets.trackandpresets.gatesreturn a spec,Course.trackandCourse.gatesbuild a course with the usual components.- spec¶
- PipelineSpec¶
The description, as data, of a generator’s pipeline: the batch (
E, device,N_max, …) and the ordered stages with their params. It is immutable; edit it into a new one (replace,insert_after,remove), save it withto_dict(), and build it withTrackGenerator(spec)orGateGenerator(spec).- stage¶
One step of a pipeline, selected by its kind and name (for example the
xpbdstage of kindrelax) and configured by its Params. Plugins can provide their own generators and stages (Writing a Generator).- Params¶
A stage’s typed parameters, a frozen dataclass per stage (for example the
beziergenerator’sBezierParams), checked when the generator is built. Each field is static (fixed for the generator’s lifetime) or dynamic.- dynamic field¶
A Params field the generator holds as a live
[E]device array, one value per env (gen.params[stage_id][field]): set it from the host or from your own kernels, or draw it per env withrandomize=, and the next generation uses the new values without rebuilding anything (Domain randomization and curricula). Changing a static field needs a new generator.- channel¶
A named device buffer that the stages of a pipeline pass to each other (for example
cl.xy, the centerline points while the track is being built). The pipeline allocates each channel once, when it is built.- component¶
A runtime piece that a course drives over the generator’s result: checkpoints, progress, collision, localization, props, or your own (Writing a Component). It refreshes on every new course, steps with your simulator and resets on respawn.
- course¶
A
Course: one generator plus its components, driven as one object for the whole batch (bind,step,reset,regenerate); see Courses. Also, in prose, the track or gate sequence one env’s agent drives.- capture¶
Recording device work into a CUDA graph instead of running it (
wp.ScopedCapture,torch.cuda.graph), to replay it later with one launch. Generator and course calls made while their stream is capturing are recorded into your graph; building a generator or a course inside a capture raises an error. Warp also records and replays captures on thecpudevice.- conditional node¶
A CUDA graph node that runs its body only when a value on the device says so. A masked regeneration recorded with one is skipped on the device when no env is masked; recorded without, it runs a full generation on every replay. It needs a capture Warp registered and CUDA 12.4 or newer in the driver and in Warp’s build (
wp.is_conditional_graph_supported()).