Pipelines and presets¶
The track and gate pipelines as ordered lists of stages: the
spec types, the presets, the planner and the Program it
builds, and the Params of the built-in stages. Generating tracks and gates shows how to use them;
Pipeline stages describes the default stages and the planner.
TrackGenerator(spec) builds the spec it is given, usually from presets.track; TrackGenerator(config) builds the spec of
legacy.to_pipeline_spec with
build(). GateGenerator does the same with
presets.gates (a spec whose
BatchSpec.max_gates is set) and legacy.to_gate_pipeline_spec. track_gen.pipeline is a
subpackage outside track_gen.__all__: import it explicitly (import track_gen
does not import it).
The track and gate pipelines as data.
A PipelineSpec lists the stages of the track pipeline in order
(StageRef: kind, name, params) over one BatchSpec. build() plans
it (every channel a stage reads has an earlier writer, every channel is allocated once,
each stage’s scratch is namespaced, validity stages get their fail bits), runs each
stage’s build once and returns a Program: a GraphRunner launchable
whose enqueue runs the stages in order, recordable into a caller’s CUDA graph like
TrackGenerator.generate; a pipeline with HOST stages runs in Segment s
(its HOST stages eagerly, the rest from graphs). presets.track
builds the default track spec with one argument per replaceable stage, and
TrackGenerator(spec) runs any spec.
The relax, width, elevation and validity stages come from
track_gen.plugin.registry (TrackGen’s built-ins and third-party plugins); the
others (resample, frames, offset, lift) are TrackGen’s built-ins.
BUILTIN_FAIL_BITS names the valid.fail bits of the built-in checks.
A gate pipeline (BatchSpec.max_gates set; presets.gates, GateGenerator(spec)) builds a Program whose
result is a GateSequence: a gate generator’s anchors (or a track generator’s
stations), an order stage, the sphere solve, an elevation stage (the track ones,
rewired to the gates), the lift, tangents, frames and validity.gate_default
(GATE_FAIL_BITS).
build(spec, out=...) (and the facades’ out=) writes into a
caller-owned result, a view of a larger one included
(mixed batches); randomize.uniform stages (presets.track(randomize=...)) draw
dynamic params per env in the graph; generator="external" ingests caller-provided
centerlines through Program.inputs (InputInfo), loaded with
load_centerlines().
Producer documents the generator surface a Course drives
(result, layout, enqueue(ctx, *, advance, mask), and optional members): a
Program implements it, and so can a third-party producer (e.g. a mixed batch of
generators writing views of one result; MixedBatch itself is not shipped).
This package is public API under the package’s deprecation policy (a deprecated name
warns and keeps working through 0.x; see API reference). import track_gen
does not import it.
Specs¶
- class StageRef[source]¶
Bases:
objectOne stage slot of a
PipelineSpec.- params¶
The stage’s Params instance, a mapping of its fields (frozen here, coerced and validated by
build), orNonefor its defaults (the generator:Params.from_legacyof a default config).- Type:
Any
- id¶
The slot id (default:
kind). Two stages of one kind need explicit ids. Must not contain"/"(it namespaces the stage’s scratch and salts).- Type:
str | None
- ports¶
local port -> channelrewiring, applied to the stage’s read and write ports.
- capacity¶
The (centerline) generator’s
{"raw": num_points}: the DEFAULT raw point count (num_points, 256 when absent), which a Stage generator’s ownStage.capacity()overrides.buildrejects any other key, and any capacity on another stage (a gate generator’s capacity is itsStage.capacity()).
- __init__(kind, name, params=None, id=None, ports=<factory>, capacity=<factory>)¶
- classmethod __new__(*args, **kwargs)¶
- class BatchSpec[source]¶
Bases:
objectThe batch every stage shares.
- n_max¶
Per-env point capacity of the centerline channels (
N_max); in a gate pipeline, read only by a centerline sub-pipeline (stations).- Type:
- closed¶
Closed loops: a bool,
True(closed=Falseis refused bybuildin 0.x, naming the stages that support closed loops only; every Layout the planner builds carries it).- Type:
- on_invalid¶
What an invalid env (
fail_mask != 0) leaves in theTrack:"keep"(default: its computed geometry,valid = 0) or"poison"(count = 0, NaN geometry,length = winding = 0, so every utility’s degeneratecount < 3path fires;fail_maskandtruncatedare kept). A gate pipeline:count = 0, every per-gate field NaN,valid = 0(fail_maskkept).- Type:
- max_gates¶
Nonefor a track pipeline (the result is aTrack); an int>= 2makes it a gate pipeline (e.g.gates()), whose result is aGateSequenceofmax_gatesslots per env.- Type:
int | None
- __init__(num_envs, device, n_max, closed=True, scale=1.0, on_invalid='keep', max_gates=None)¶
- classmethod __new__(*args, **kwargs)¶
- class PipelineSpec[source]¶
Bases:
objectA pipeline: the
BatchSpecand the ordered stage slots.The editing operations return a NEW spec; they only check that an anchor id exists (
ValueErrorlisting the ids). Everything else is validated bytrack_gen.pipeline.build().- stages¶
The ordered
StageRefslots: the generator first (preceded only by its own randomizers,randomize.uniformstages drawing its dynamic params).- Type:
- require_caller_capturable¶
Refuse, at build (
PlanErrornaming them), anyCaptureClass.HOSTstage: the Program is then recordable into a caller’s capture as a whole. DefaultFalse(HOST stages run eagerly between the graph launches of the rest; a caller capture of such a Program raisesNotCapturableError).- Type:
- replace(stage_id, ref)[source]¶
Put
refin slotstage_id;refkeeps the slot’s id when its ownidisNone.- Parameters:
- Return type:
- insert_before(stage_id, ref)[source]¶
Insert
refright before slotstage_id.- Parameters:
- Return type:
- with_randomize(randomize)[source]¶
This spec with per-env uniform draws of DYNAMIC float32 params: each a
randomize.uniformstage (id"randomize.<stage>.<field>") inserted right before the stage it draws.The helper behind
presets.track(randomize=)/presets.gates(randomize=), for a spec built any other way, e.g. from a config:from track_gen import (GateGenConfig, GateGenerator, PerEnvSeededRNG, TrackGenConfig, TrackGenerator) from track_gen.pipeline import legacy E, d = 64, "cuda:0" rng = PerEnvSeededRNG(seeds=0, num_envs=E, device=d) cfg = TrackGenConfig(num_envs=E, device=d, z_profile="uniform", z_max=0.6) spec = legacy.to_pipeline_spec(cfg).with_randomize( {"generator.rad": (0.1, 0.35), "elevation.z_max": (0.2, 0.6)}) gen = TrackGenerator(spec, rng) # a GateGenConfig: its gate spec, then GateGenerator gcfg = GateGenConfig(num_envs=E, device=d, generator="polar") spec = legacy.to_gate_pipeline_spec(gcfg).with_randomize( {"generator.polar_radial_jitter": (0.2, 0.8)}) gen = GateGenerator(spec, rng)
A field the spec already randomizes is refused, not replaced: to change a draw range (e.g. at a curriculum phase), replace that randomizer,
spec.replace("randomize.generator.rad", StageRef("randomize", "uniform", {"stage": "generator", "field": "rad", "lo": 0.1, "hi": 0.4})), or write its livelo/hi(gen.params["randomize.generator.rad"].set("hi", 0.4)).- Parameters:
randomize –
{"<stage id>.<field>": (lo, hi)}(the key split at its LAST dot) or a sequence ofStageRef("randomize", "uniform", {...});Nonereturns this spec. The course size is"generator.size"(the track generators butexternal, the bezier / hull gate generators) or"normalize.size"(the polar / voronoi / checkpoint gate pipelines), the bar width"gate_frames.gate_width".- Raises:
ValueError – a malformed key, a target stage the spec does not have (lists the stage ids), or a field (or a stage id) the spec already has a randomizer for.
TypeError – a range that is not a
(lo, hi)pair, or a sequence item that is not aStageRef("randomize", ...).
- Return type:
The field’s rules (dynamic, float32, the range inside its declared bounds, the cross-field rules) are checked by
track_gen.pipeline.build().
- to_dict()[source]¶
The spec as JSON data (
"format": "track_gen.pipeline/2"): Params become{field: value}(tuples as lists, enums as their values);"require_caller_capturable": trueonly when it is set.- Return type:
- classmethod from_dict(data)[source]¶
Read
to_dict()data back (params stay mappings;buildcoerces them). No registry is needed.track_gen.pipeline/1data (written by earlier releases) is migrated, with oneDeprecationWarning: thehalf_widthparams ofrelax.xpbd/offset.default/validity.defaultare dropped (each must equal the width stage’shalf_width, elseValueError), every width stage between the first relax and the first frames stage moves to just before that relax, and arelax.xpbdwithout a width stage before it (arelaxed_stationsgate spec in format /1) getswidth.constantwith that half-width. Withwidth.constant(or no width stage) the migrated spec builds the outputs of the /1 spec byte for byte; another width stage now runs before relax and is read per point by XPBD and the offset, so its outputs change (the warning says so). A width stage after the first frames stage of a spec whoserelax.xpbdhas no width before it (an earlier width stage readingcl.kappa) is refused withValueError: it cannot be both the width XPBD reads and a stage after frames.- Parameters:
data (Mapping)
- Return type:
Presets¶
Preset pipelines: track() builds the default track
PipelineSpec and
gates() the default gate one, with one argument per replaceable stage.
track() reads the registry only for what shapes the stage list (the generator’s
provides, and whether a width stage’s Params has a half_width field); an
unknown name is not an error there: it fails at track_gen.pipeline.build() (or
TrackGenerator construction) with the registry’s message. gates() reads the
registry for the generator (its kind, provides, orderings, preferred and
attributes) and the stations stage’s Params.
A stage is selected as a name ("xpbd"), a (name, params) pair (params: a
Params instance, a mapping of its fields, or None for its defaults) or a
StageRef of the slot’s kind; a plugin’s stage is selected
the same way, by its registered name (relax="acme.taubin"). Edit the result with the
PipelineSpec operations:
from track_gen import TrackGenerator
from track_gen.pipeline import StageRef, presets
spec = presets.track(num_envs=64, device="cuda:0",
relax=("xpbd", {"relax_iters": 40}),
elevation=StageRef("elevation", "noise",
{"z_min": -0.3, "z_max": 0.3,
"z_noise_amplitude": 0.2}))
spec = spec.with_randomize({"generator.rad": (0.2, 0.4)})
gen = TrackGenerator(spec)
- track(*, num_envs, device, n_max=384, scale=1.0, size=1.0, generator='bezier', generator_params=None, num_points=256, half_width=0.1, spacing=None, relax='auto', width='constant', elevation='flat', checks=('default',), on_invalid='keep', z_base=0.0, registry=None, randomize=None)[source]¶
The track pipeline: generator -> resample -> width -> relax -> uniform resample -> frames -> offset -> elevation -> checks -> lift (the width runs before relax:
cl.half_widthis the per-point half-width XPBD, the offset and validity read).presets.track(num_envs=E, device=d)has the stages of the specTrackGenerator(TrackGenConfig(num_envs=E, device=d))builds, and the generators produce byte-identical Tracks (the two specs do not compare equal: the preset’s stages carry plain values or no params where the config’s carry Params instances).A generator that
providesattributes has the stage computing them dropped:"z"(itsraw.zis carried tocl.z): no elevation stage,lift.elevated;"half_width"(raw.half_width->cl.half_width): no width stage.- Parameters:
num_envs (int) –
E.device (str) – The Warp device.
n_max (int) – Per-env point capacity (
N_max).scale (float) –
TrackGenConfig.scale.size (float) – The INITIAL per-env course size: the generator’s dynamic
size(generator.size;TrackGenConfig.size), a multiplier applied where the generator appliesscale(the plan view only: widths and z are absolute).1.0(default) adds nothing to the spec. A generator that declares nosize(external) raisesValueError, as does asizein its params too. Per-env values:gen.params["generator"],randomize={"generator.size": (lo, hi)}. Size up withn_max.generator (str | StageRef) – A registered generator name, or a
StageRef("generator", ...)(then pass its params inside it).generator_params – The generator’s params (a Params instance or a mapping;
None: its defaults).num_points (int) – The generator’s default raw point count (
capacity["raw"]).half_width (float) – The track half-width: the value of a width stage whose Params has a
half_widthfield (width.constant, or a plugin’s), unless its params set it, and the default spacing. A width stage without the field (width.from_channel) or a generator that provides its width takes its width elsewhere: then an explicithalf_widthother than 0.1 with an explicitspacingreaches nothing and raisesValueError.spacing (float | None) – The constant-spacing step (default
0.6 * half_width).relax (str | tuple | StageRef | None) – The
relaxstage (None:relax.none)."auto"(default): the generator’spreferred["relax"]("none"forgenerator/external: ingested geometry is not moved), else"xpbd"(every built-in generator: unchanged output). An explicit name overrides it (relax can repair ingested tracks).width (str | tuple | StageRef) – The
widthstage (runs before relax).elevation (str | tuple | StageRef | None) – The
elevationstage (None:elevation.flat). The lift islift.flatforelevation.flat, elselift.elevated.checks (Sequence[str | tuple | StageRef]) – The
validitystages, in order: a sequence of selections whose first is"default"(validity.default; plugin checks follow it). The first one’s id is"validity"; each further one’s is itsStageRef.idor its name.on_invalid (str) –
"keep"(default) or"poison"(BatchSpec.on_invalid).z_base (float) – The altitude of the flat lift (
elevation.flat; the flatTrackGenConfig.z_base). Another elevation takes its altitude from its own params, so a nonzeroz_basewith it raisesValueError.registry – The plugin registry the generator’s
providesand a width stage’s Params are looked up in (defaulttrack_gen.plugin.registry; an unknown name is reported bybuild).randomize – Per-env uniform draws of DYNAMIC float32 params:
{"<stage id>.<field>": (lo, hi)}(e.g.{"generator.rad": (0.1, 0.35)}or{"generator.polar_radial_jitter": (0.2, 0.8), "elevation.z_max": (0.2, 0.6)}(with a non-flat elevation) on the built-ins’ dynamic knobs,{"generator.amp": (0.05, 0.35)}for a plugin generator’s,{"width.scale": (0.8, 1.2)}withwidth.from_channel) or a sequence ofStageRef("randomize", "uniform", {...}). Each becomes arandomize.uniformstage (id"randomize.<stage>.<field>") inserted right before its target (with_randomize()). The range must lie inside the field’s declared bounds; a static knob is refused at build (listing the pipeline’s drawable fields).
- Raises:
ValueError – an invalid selection (wrong StageRef kind,
width=None,checksnot starting with"default", a duplicate check id, an unknownon_invalid,generator_paramswith a generator StageRef, params setting ahalf_widthother thanhalf_width,elevation.flatparams setting a non-zeroz_base, a width other than the default, a non-flat elevation or a non-zeroz_basefor a generator that provides them, ahalf_widththat reaches no stage).TypeError – a selection of another type, or
checksgiven as one selection instead of a sequence.
- Return type:
- gates(*, num_envs, device, generator='bezier', generator_params=None, source='auto', gates=None, max_gates=None, min_gates=4, order=None, stations=None, gate_radius=0.025, gate_solve_iters=8, gate_width=0.0, gate_align='yaw_only', elevation='flat', z_base=0.0, z_valid_grade=0.0, checks=('gate_default',), scale=1.0, size=1.0, on_invalid='keep', n_max=384, num_points=256, half_width=0.1, spacing=None, relax='auto', width='constant', spacing_metric='xy', elevation_on=None, registry=None, randomize=None)[source]¶
The gate pipeline: generator -> order -> [normalize] -> gate_relax -> [gate_arclen -> elevation] -> lift -> tangents -> gate_frames -> checks.
presets.gates(num_envs=E, device=d)equals the spec ofGateGenerator(GateGenConfig(num_envs=E, device=d))(same stages, equal params; byte-identical GateSequences).The generator is either a gate generator (
source="anchors": a registeredgate_generator, whose anchors theorderstage orders), or any track generator (source="stations":gatesstations at equal arc length on its raw loop;"relaxed_stations": on the relaxed centerline, after the track pipeline’s resample and relax stages).source="auto"picks"anchors"for a name registered as a gate generator (the built-in names are both: anchors win), else"stations". A generator thatprovidesper-anchor attributes has the stages computing them dropped (z: gate_arclen and elevation;tangent: tangents;half_size+roll:gate_frames.posed;validity.gate_defaultchecks the bars of every env that has one, whatever itscheck_crossing).- Parameters:
num_envs (int) –
E.device (str) – The Warp device.
generator (str | StageRef) – A gate generator or track generator name, or a
StageRefof kind"gate_generator"/"generator".generator_params – The generator’s params (
None: its defaults).source (str) –
"auto","anchors","stations"or"relaxed_stations".gates (int | None) – The station count of a centerline source (default 12; it fills the
gatesfield of the stations stage’s params when they do not set it).max_gates (int | None) –
BatchSpec.max_gates(default: 32 for anchors, the station count for stations).min_gates (int) –
validity.gate_default’s fewest real gates.order (str | tuple | StageRef | None) – The
orderstage (default: the generator’spreferred["order"]when it accepts it, else"ccw"when it accepts it, else the first order it accepts;"raw"for stations).stations (str | tuple | StageRef | None) – The
stationsstage (defaultstations.raw/stations.relaxedwith{"gates": gates}).gate_radius (float) – The sphere solve (
gate_relax.spheres, orgate_relax.nonewithout iterations or radius) and the spacing check.gate_solve_iters (int) – The sphere solve (
gate_relax.spheres, orgate_relax.nonewithout iterations or radius) and the spacing check.gate_width (float) – The FULL bar width (
half_size = 0.5 * gate_width).gate_align (str) –
"yaw_only"or"full_tangent".elevation (str | tuple | StageRef | None) – The
elevationstage (None: flat), its ports rewired to the gates by the planner.z_base (float) – The altitude of every real gate with
elevation.flat(itsz_base;GateGenConfig.z_base). Another elevation takes its altitude from its own params, so a nonzeroz_basewith it (or with a generator that providesz) raisesValueError.z_valid_grade (float) – The validity grade cap (0: off).
checks (Sequence[str | tuple | StageRef]) – The
validitystages:"gate_default"first, plugin checks after.validity.gate_defaultgetsmin_gates,gate_radius,gate_widthandz_valid_gradeunless its params set them (a Params instance is taken as is). Itsgate_widthandcheck_crossingare inert (the bars of every env that has one are checked); posed gates still getcheck_crossing="always", filled only so that existing posed specs stay identical.scale (float) –
BatchSpec.scale.size (float) – The INITIAL per-env course size (
GateGenConfig.size), routed to the stage that holds it:normalize.sizefor a gate generator re-normalized bynormalize.extent(polar/voronoi/checkpoint; also one that declares asizeof its own, which the normalization erases), elsegenerator.sizefor a gate generator that declares it (bezier/hull) and for a stations source’s track generator.1.0(default) adds nothing to the spec; a generator with neither raisesValueError, as does asizein its params too.on_invalid (str) –
"keep"or"poison".n_max (int) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.num_points (int) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.half_width (float) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.spacing (float | None) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.relax (str | tuple | StageRef | None) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.width (str | tuple | StageRef) – The centerline sub-pipeline of a stations source (as
track();relax="auto": the generator’spreferred["relax"], else"xpbd"): astationssource readsn_maxandnum_points, arelaxed_stationssource all six; setting one that the source does not read raisesValueError.spacing_metric (str) –
"xy"(default: the stations are equally spaced in plan view) or"xyz"(in 3D arc length: the loop needs its altitude, from a generator that provideszor an elevation run on the relaxed centerline;ValueErrorwhen the loop has none). Filled into the stations stage’s params (a stations source only).elevation_on (str | None) – Where the elevation runs for
source="relaxed_stations":"gates"(the gates’ own profile, after the order) or"centerline"(on the relaxed centerline, before the stations, whose altitude the gates then carry by index). Default:"centerline"for"xyz","gates"for"xy". An explicit value with a generator that providesz(no elevation runs) raisesValueError.registry – The plugin registry the generator is looked up in (default
track_gen.plugin.registry).randomize – Per-env uniform draws of DYNAMIC float32 params, as
track()(e.g.{"generator.polar_radial_jitter": (0.2, 0.8)}on the polar gate generator,{"elevation.z_noise_amplitude": (0.1, 0.6)}with an open window such aselevation=("noise", {"z_min": -0.5, "z_max": 0.5})(the default[0, 0]window clamps every hill away), or{"generator.m": (3.0, 9.0)}for a plugin gate generator’s dynamicm): each arandomize.uniformstage inserted right before its target.
- Raises:
ValueError – an unknown generator name, an invalid selection or argument (
gates=with an anchors source,gates=and a stations selection setting another count,order=with a legacy gate generator, an explicit elevation,z_baseorgate_widthfor a generator that provides them, a nonzeroz_basewith another elevation than flat, a centerline argument the source does not read,validity.gate_defaultparams setting anothergate_radius/gate_width,gate_align,on_invalid).TypeError – a selection of another type.
track_gen.plugin.PluginLoadError – the generator belongs to a quarantined plugin.
- Return type:
- StageSel¶
The type of a preset’s stage keyword: a stage name, a
(name, params)pair, aStageRef, orNone.
From a configuration¶
TrackGenConfig / GateGenConfig <-> PipelineSpec: the default stage lists.
to_pipeline_spec() is what TrackGenerator(config) builds, and
to_gate_pipeline_spec() what GateGenerator(config) builds: the default track
and gate stage lists, with each stage’s params read from the config’s flat fields. A
config keeps the outputs it had before the pipeline existed, launch for launch.
- to_pipeline_spec(config, *, registry=None)[source]¶
The default
PipelineSpecof aTrackGenConfig.Ids, in order:
generator,resample(resample.constant_spacing),width(width.constant, before relax),relax(relax.<relax_solver>, orrelax.nonewhenrelax_enable=False),uniform(resample.uniform),frames,offset,elevation(elevation.<z_profile>),validityandlift(lift.flaton the flat profile, elselift.elevated). A generator that provides"z"has no elevation (lift.elevated), one that provides"half_width"no width stage. Each stage’s params are its Params class’sfrom_legacy(config)(the flat field names); the generator’s are its resolvedgenerator_params.relax_solverandz_profilename any stage registered underrelax/elevation; ahalf_widthfield of their Params isconfig.half_width(the stages with the field share the nominal width).- Parameters:
config – A
TrackGenConfig.registry – The plugin registry the generator,
relax_solverandz_profileare resolved through (defaulttrack_gen.plugin.registry).
- Raises:
TypeError –
configis aGateGenConfig(useto_gate_pipeline_spec()).ValueError – an unknown or oracle-only
relax_solver, an unknownz_profile,smooth_finish=True(asTrackGenerator), the generator’s params are invalid, a non-flatz_profile/ non-zeroz_basefor a generator that providesz, or asizeother than 1 for a generator that declares nosize(or whose Params do not map it).track_gen.plugin.PluginLoadError –
relax_solver/z_profilenames a stage of a quarantined plugin.
- Return type:
- to_gate_pipeline_spec(config, *, registry=None)[source]¶
The default gate
PipelineSpecof aGateGenConfig(whatGateGenerator(config)builds).Ids, in order:
generator(gate_generator.<generator>),order(order.<gate_ordering>;gate_ordering=Noneis the generator’s default order,stages.gates._default_order: itspreferred["order"]when it accepts it, else"ccw"when it accepts it, else the first order it accepts;"ccw"for the five built-ins),normalize(normalize.extent, for a generator whosepreferred["normalize"]is"extent": polar, checkpoint, voronoi), thecarry_<attr>of each attribute the generator provides,gate_relax(gate_relax.spheres, orgate_relax.nonewhengate_solve_iters == 0or the float322 * gate_radiusis 0),gate_arclen(unless the profile is flat),elevation(elevation.<z_profile>; both dropped when the generator providesz),lift(lift.gates),tangents(tangents.central, dropped when it providestangent),gate_framesandvalidity(validity.gate_default). A legacyGateGeneratorSpecorders its own gates: no order / normalize stage; it reads the resolved name from its run config (neverNone).BatchSpec(n_max=384, max_gates=config.max_gates, scale=config.scale).- Raises:
ValueError – an unknown generator,
gate_ordering(not a registered order, or not one the generator supports) orz_profile;min_gates/max_gatesincompatible with the generator’s capacity; an explicitz_profile/z_base/gate_widthfor a generator that provides them; invalid generator params; an elevation plugin whoseParams.from_legacyreads a fieldGateGenConfiglacks; asizeother than 1 no stage applies (a gate generator withoutsizeand nonormalize.extent: e.g. a legacy spec).track_gen.plugin.PluginLoadError – a name of a quarantined plugin.
- Return type:
- generator_config(spec)[source]¶
The
TrackGenConfigbuildbinds the generator with: the batch (num_envs,device,N_max,scale),num_points = capacity.get("raw", 256)andgenerator_paramsfrom the generator’sStageRef. Enough for the built-ins and Stage generators; aGeneratorSpecthat reads other config fields needsTrackGenerator.- Parameters:
spec (PipelineSpec)
- gate_generator_config(spec, *, registry=None)[source]¶
The
GateGenConfigof a gate pipeline: whatbuildbinds a gate generator with, andGateGenerator._configfor any gate spec. The batch (num_envs,device,max_gates,scale), the generator name and params (a centerline source:generator_params=None, its params live in its own binding),min_gates(validity.gate_default’s, clamped tomax_gates),gate_ordering(the order stage’s name; a legacy generator:"ccw"if it supports it, else its first ordering),gate_width/gate_radius/gate_solve_iters/gate_align/z_valid_grade/z_profilefrom their stages; other fields default. A legacyGateGeneratorSpecin a PipelineSpec sees only these fields.- Parameters:
spec (PipelineSpec)
Planner and Program¶
- build(spec, *, registry=None, seeds=None, out=None, stream=None, prepare=True)[source]¶
Plan, allocate and bind
spec; return itsProgram.The generator (the first stage) is resolved through
registryexactly as the facades resolveconfig.generator: a centerline generator (kind="generator") with the configtrack_gen.pipeline.legacy.generator_config()derives from the spec, a gate generator (kind="gate_generator") withtrack_gen.pipeline.legacy.gate_generator_config(). The open-kind stages (relax/width/elevation/validity/order/stations) are resolved throughregistrytoo (the class is captured at build: later registry edits never change a built Program); the others come from TrackGen’s built-in catalogue.spec.batch.max_gatesselects the result: aTrack(None) or aGateSequence.- Parameters:
spec (PipelineSpec) – The
PipelineSpec.registry – The plugin registry (default
track_gen.plugin.registry).seeds – A
SeedState, or anythingSeedStateaccepts (None, an int, an[E]int32wp.array, aPerEnvSeededRNG).out – Optional pre-allocated
Track(GateSequence) to write into (every field checked;generationandfail_maskmay beNone).stream – Optional default
wp.Streamof the Program.prepare (bool) – Run the warm-up generation (
Program.prepare()) before returning (otherwise the firstProgram.run()does).
- Raises:
PlanError – an invalid spec (see Pipeline stages), incl. an unknown relax / width / elevation / validity / order / stations name (the registry’s message) and a HOST stage under
PipelineSpec.require_caller_capturable.ValueError – invalid params (the stage’s own message), an unknown generator (the registry’s message), an
out=orseedsmismatch.TypeError – params or
seedsof the wrong type.track_gen.plugin.PluginLoadError – a stage named explicitly is provided by a quarantined plugin.
track_gen.exec.CaptureError – called inside a capture (before allocating).
- class Program[source]¶
Bases:
objectA built pipeline: every buffer allocated once, every stage’s
enqueuebound.Created by
track_gen.pipeline.build()(never directly). AGraphRunnerlaunchable:run()records into a caller’s capture, replays the Program’s own graph on CUDA, or runs eagerly, exactly asTrackGenerator.generatedoes.One generation (
enqueue()) is:[seeds.advance(mask)]-> the effective seeds (seed) -> the dynamic-parameter / input latch -> [masked: hold the unmasked envs’ result rows] -> every stage in order (EVERY env) -> the commit (masked: restore the unmasked envs; derivevalid;on_invalid="poison") ->result.generation <- epoch(masked envs only, with a mask). It allocates nothing and never host-syncs, except inside its HOST stages (theirctx.host()readbacks, uploads and waits on the call’s stream). Seetrack_gen.stages.commitfor what the commit costs (nothing for an unmasked generation of the default pipeline). The result is aTrack, or aGateSequencefor a gate pipeline (BatchSpec.max_gatesset).A Program whose stages include
CaptureClass.HOSTones is split intosegments(consecutive stages of equal host-ness): outside a capture its HOST segments run eagerly and every other segment replays its own graph on CUDA (enqueue_segment()); a caller’s capture refuses it before any launch (NotCapturableErrornaminghost_stage_ids).- __init__(*, _token=None, spec, layout, binding, result, seeds, seed, inputs, params, pairs, enqueues, versions, scratch, stage_ids, kinds, gen_scratch, stream=None, owner=None, commit=None, fail_bits=None, fail_owner=None, capture_classes=None, segments=None, on_invalid='keep', writers=None, ports=None, attributes=None, input_info=None)[source]¶
- Parameters:
on_invalid (str)
- Return type:
None
- property spec: PipelineSpec¶
The resolved spec, in which every
StageRef.paramsis the stage’s Params instance (the generator’s resolved Params;Nonefor a legacy spec without one).
- property layout¶
The result’s
Layout, whosestrideisN_maxfor a track andmax_gatesfor a gate pipeline (each stage was built with the layout of its own point domain).
- property device¶
The
wp.Device.
- property result: Track¶
the
GateSequence) every generation writes: the same instance, with the same array addresses, for the Program’s lifetime.- Type:
The
Track(a gate pipeline
- property seed: wp.array¶
The
[E]int32 effective seed (channel"seed"), written by the prologue of every generation; stages read it asStageBuilder.seed.
- property inputs: Mapping¶
The persistent device inputs,
"regen_mask"([E]int32, zeroed) and every input a stage declared (StageBuilder.input). Stable pointers.Latched inputs (
per="env") are snapshotted at the start of a generation, so a write takes effect for the envs the next generation regenerates. Unlatched inputs (per="raw", e.g. an ingestion generator’scenterline.*) are read DURING the generation: write them on the generation’s stream (or order the streams with events).input_infotells them apart.
- property input_info: Mapping[str, InputInfo]¶
name -> InputInfoof every entry ofinputs(its dtype,per, length, declaring stage, and whether it is LATCHED at the start of a generation or read during it).
- property params: ParamTable¶
Runtime parameters keyed by stage id (live
[E]arrays of the dynamic fields). The dynamic fields of the built-ins are the generators’ shape knobs (rad,handle_clamp_frac,hull_displacement, the polar, voronoi and checkpoint knobs), the elevation stages’z_min/z_max/z_max_step/z_noise_amplitude,width.from_channel’sscale/lo/hiand arandomize.uniformstage’slo/hi(see Dynamic fields); every other field is static (setraisesKeyError; build a new generator to change it). A field drawn by arandomize.*stage maps to its drawn array (written every generation by the randomizer;setraises).
- property capture_class: CaptureClass¶
The largest of the generator’s and every stage’s
CaptureClass(Stage.capture_classof its params; a legacy spec:STATIC, orHOSTwithcapturable=False):STATIC,BOUNDED(an iterative stage; still recordable into a caller’s capture) orHOST(seesegments). The built-in stages are STATIC.
- property segments: tuple[Segment, ...]¶
maximal runs of consecutive stages of equal host-ness (one segment unless some stage is HOST). Outside a capture each HOST segment runs eagerly and every other segment replays its own graph on CUDA.
- Type:
The Program’s
Segments
- property host_stage_ids: tuple[str, ...]¶
the Program is recordable into a caller’s capture).
- Type:
The ids of the
CaptureClass.HOSTstages (()
- property fail_bits: Mapping[str, int]¶
the built-in checks’ (
BUILTIN_FAIL_BITS, bits 0-7; a gate pipeline:GATE_FAIL_BITS, bits 0-5) then each plugin validity stage’s (16, 17, … in pipeline order).Track.fail_bits/GateSequence.fail_bitsis the same mapping.- Type:
name -> bitof everyvalid.failbit, in assignment order
- property channels: Mapping[str, tuple[str, ...]]¶
channel -> ids of the stages that write it, in order ("seed":("<prologue>",)), the carriers’ implicit writes included (a resample writing theclimage of a generator’s raw attribute).
- property attributes: Mapping[str, AttributeInfo]¶
key -> AttributeInfoof every per-point attribute the result exports (Track.attributes/GateSequence.attributes): the source of truth for what reached the result (gate attributes are best effort). Empty when no stage exports one.
- property capturable: bool¶
Whether the Program may be recorded into a caller’s capture (it has no HOST stage).
- property legacy_stream: bool¶
Whether the generator is a legacy-ABI spec (launches on Warp’s current stream; see
GraphRunner).
- property runner: GraphRunner¶
The
GraphRunnerthat runs the Program.
- property prepared: bool¶
Whether
prepare()ran (one real generation outside any capture;build(..., prepare=True)and the facades run it). Part of thetrack_gen.pipeline.Producersurface.
- property default_stream: wp.Stream | None¶
The stream calls run on when they pass no
stream=and no ambient scope applies (build(..., stream=), the facades’stream=;None: resolved pertrack_gen.exec). Part of thetrack_gen.pipeline.Producersurface.
- property graph: wp.Graph | None¶
The Program’s own CUDA graph for a plain
run()(Noneon CPU, for a Program with HOST stages, whose capturable segments get one graph each, and before the first such CUDA call).
- segment_graphs(key=None)[source]¶
The per-segment CUDA graphs of a Program with HOST stages (its own graph, cut at each HOST segment), one per segment in order (
Noneat a HOST segment), for the graph keykey(None: a plainrun();(True, mask.ptr or 0)foradvance=True);Nonebefore the first such CUDA call outside a capture, on CPU, and for a Program without HOST stages (seegraph).- Return type:
tuple | None
- enqueue(ctx, *, advance=False, mask=None)[source]¶
Launch one generation on
ctxand returnresult.No allocation, no branch on device data, and no host sync except inside the HOST stages (their
ctx.host()operations wait onctx’s stream). Withmaskthe prologue, the commit and thegenerationwrite cover the masked envs only: every other env’sTrackrows end the generation bit for bit as they were (validatemaskfirst, asrun()does). They are held, recomputed by the stages and restored within the generation, all onctx’s stream: work ordered after the generation on that stream (or after an event recorded on it) never sees the recomputed rows, a reader on another stream without such a dependency can (seetrack_gen.stages.commit).- Parameters:
ctx (LaunchContext) – The
LaunchContextto emit on.advance (bool) – Bump
seeds.epochfirst (every env, or wheremask[e] != 0).mask (wp.array | None) – Optional
[E]int32 mask.
- Return type:
An iterative (
BOUNDED) stage runs its full iteration bound when called eagerly on CUDA (its own CUDA graph skips converged windows on device). A legacy-ABI generator (legacy_stream) launches on Warp’s current stream: whenctx’s stream is another one, the generation runs on the current stream, ordered after and beforectx’s with events (asGraphRunnerdoes).- Raises:
track_gen.exec.NotCapturableError – the Program has HOST stages and
ctxis capturing (or a CPU graph capture is open on the device); raised before any launch.track_gen.exec.LegacyPluginStreamError – a legacy-ABI generator and
ctxis capturing a stream that is not Warp’s current stream.track_gen.exec.CaptureError –
ctxis capturing andprepare()has not run (the first launches would load modules inside the capture).
- Parameters:
ctx (LaunchContext)
advance (bool)
mask (wp.array | None)
- Return type:
- enqueue_segment(i, ctx, *, advance=False, mask=None)[source]¶
Launch segment
iof one generation onctx(seesegments) and returnresult. Segment 0 opens with the prologue (advance, the effective seeds, the latch, the masked hold), the last one closes with the commit and thegenerationwrite;enqueue()runs every segment in order. A segment that is not HOST may be recorded into a caller’s capture once the Program is prepared (e.g. record the capturable tail, run the HOST head eagerly).One generation is every segment, in order, on one stream, with the SAME
advanceandmask(a recorded segment keeps the arguments it was recorded with: run the eager segments with those). This is not checked: a replayed segment runs no Python, so the Program cannot see which arguments it had. Mixing arguments, running segments out of order or skipping one leaves the result undefined.A legacy-ABI generator (
legacy_stream) lives in segment 0 and launches on Warp’s current stream: there, segment 0 follows the rule ofenqueue().- Raises:
IndexError – no segment
i.track_gen.exec.NotCapturableError – segment
iis HOST andctxis capturing (or a CPU graph capture is open on the device).track_gen.exec.LegacyPluginStreamError – segment 0 holds a legacy-ABI generator and
ctxis capturing a stream that is not Warp’s current stream.track_gen.exec.CaptureError –
ctxis capturing andprepare()has not run.
- Parameters:
i (int)
ctx (LaunchContext)
advance (bool)
mask (wp.array | None)
- Return type:
- prepare()[source]¶
Run one real generation outside any capture and wait for it (the warm-up: loads every kernel the hot path uses).
build(..., prepare=True)calls it.- Raises:
track_gen.exec.CaptureError – a capture is open (see
GraphRunner).- Return type:
None
- run(*, stream=None, sync=False, advance=False, mask=None, policy='auto')[source]¶
Run one generation under the
GraphRunnerpolicy (record into a caller’s capture, replay the Program’s own graph on CUDA, or eager) and returnresult. A Program built withprepare=Falserunsprepare()first (outside a capture; inside one it raisesCaptureError).- Parameters:
stream – Optional
wp.Stream(or"torch").sync (bool) – Block the host until the generation finished (never while recording).
advance (bool) – Bump the epoch first (see
TrackGenerator.generate).mask (wp.array | None) – Optional
[E]int32 mask of the envs to advance; requiresadvance=True.policy (str) –
"auto"or"eager"(never builds the Program’s own CUDA graph).
- Raises:
ValueError – an invalid
mask.track_gen.exec.NotCapturableError – recording a Program with HOST stages (also one built with
prepare=False), before any launch.track_gen.exec.CaptureError – recording a Program that was never prepared.
- Return type:
- tap(channel, *, after=None)[source]¶
The working buffer of
channel: its final version, or the version visible right after stageafter(what the stages after it read).Read-only by contract: never write it. Stable for the Program’s lifetime; it holds the last generation’s values once that generation completed on its stream. Every env is recomputed each generation; the final version of a channel the
Trackexports (track.*,cl.winding,cl.truncated,valid.fail, andcl.arclen2/cl.length2under a flat lift) IS theTrack’s array, so it holds the committed values (after a masked regeneration: an unmasked env’s previous track; withon_invalid="poison": the poisoned rows). One exception:track.validisTrack.validonly whenvalidity.defaultis the last writer ofvalid.fail. After a plugin check the commit derivesTrack.validfromvalid.fail, andtap("track.valid")isvalidity.default’s own 0/1 flag, which ignores the later checks (and poison): readTrack.valid, ortap("valid.fail") == 0.tap("seed")is the effective seed.
- class Producer[source]¶
Bases:
ProtocolThe generator surface
track_gen.course.Coursedrives (documentation only: the library duck-types it and neverisinstance-checks it).TrackGenerator/GateGenerator(through theirprogram) and a builtProgramimplement it; a third-party producer (e.g. a mixed batch of several generators writing views of one result) implements the required members, and the optional ones it needs.Required:
result: the result every generation writes (aTrack, aGateSequenceor another result the components read), the same instance with the same array addresses for the producer’s lifetime; itsvalid(when present) isStepResult.valid.layout: the result’sLayout(num_envs, the stride, the device).enqueue(ctx, *, advance=False, mask=None): one generation onctx(aLaunchContext), allocation-free and host-sync free. Withadvance: bump each env’s epoch first (every env, or the masked ones). Withmask([E]int32, read on device): the unmasked envs’ result rows end the generation bit for bit as they were (a masked commit), and an all-zero mask is an exact no-op. It may run inside a CUDA conditional-node body (the course’s masked regeneration): kernels, fills and device-to-device copies onctx’s stream only.
Optional (read when present):
seeds: itsSeedState(course.seeds;Course.generate(seeds=)sets owned seeds through it).capture_class: aCaptureClass(defaultSTATIC);HOSTruns eagerly outside a capture and is refused inside one (NotCapturableError).preparedandprepare(): an unprepared producer is prepared first (its own warm-up, loading every moduleenqueueuses). Without them, the producer must have loaded every module itsenqueueuses before it reaches a Course (e.g. one realenqueueat its construction).default_stream: the course’s default stream whenCourse(..., stream=)is not given.capacityandbounds(name -> numbermappings): the static capacities (max_loop_length) and declared bounds (size_hi) a plan would give, read byComponentContext.for_producerbefore the plan.inputsandinput_info: its persistent device inputs (listed, never bound by the course: write them in place).
- property result: object¶
The result that every generation writes (the same instance, with the same array addresses, for the producer’s lifetime).
- enqueue(ctx, *, advance=False, mask=None)[source]¶
Enqueue one generation on
ctx: allocation-free and host-sync free; withadvance, bump the epochs first; withmask, leave the unmasked envs’ rows bit for bit as they were (see the class docstring).- Parameters:
ctx (LaunchContext)
advance (bool)
mask (wp.array | None)
- Return type:
- __init__(*args, **kwargs)¶
- class Segment[source]¶
Bases:
objectOne segment of a
Program(planner rule 6): a maximal run of consecutive stages of one kind, HOST (run eagerly every call) or capturable (STATIC / BOUNDED: replayed from the Program’s own graph outside a capture).- index¶
The segment’s position (0 opens with the seed prologue, the last one closes with the commit).
- Type:
- capture_class¶
CaptureClass.HOST, or the largest of its stages’ classes (STATIC/BOUNDED).
- __init__(index, capture_class, stage_ids)¶
- Parameters:
index (int)
capture_class (CaptureClass)
- Return type:
None
- class AttributeInfo[source]¶
Bases:
objectOne exported per-point attribute of a
Program(Program.attributes): whatTrack.attributes[key]/GateSequence.attributes[key]holds.- channel¶
The result-domain channel whose final version is the array (
"cl.acme.surface_id","gates.acme.tag").- Type:
- interp¶
The carry policy its generator declared (
"linear","nearest","previous","angle"),Nonefor an attribute carried by index only or written by a stage on the result’s points.- Type:
str | None
- padding¶
The value past
count[e]: NaN for floats (every vector component),-1for int32.- Type:
- __init__(key, channel, dtype, interp, padding, domain)¶
- classmethod __new__(*args, **kwargs)¶
- class InputInfo[source]¶
Bases:
objectOne persistent device input of a
Program(Program.input_info): whatProgram.inputs[name]is and how a generation reads it.- name¶
The input’s name (
"regen_mask", a stage’sStageBuilder.inputname;"centerline.xy", … for an ingestion generator).- Type:
- latched¶
True: snapshotted (latched) at the start of every generation for the envs it regenerates, like a dynamic param (a write takes effect at the next generation);False: read DURING the generation (aper="raw"input,"regen_mask"), so a writer must be stream-ordered with the generation (the same stream, or events).- Type:
- __init__(name, dtype, per, length, latched, stage_id)¶
- classmethod __new__(*args, **kwargs)¶
- exception PlanError[source]¶
Bases:
ValueErrorA pipeline spec the planner refuses; raised before anything is allocated, except for the build-time rules checked right after a stage’s
build(its declared write ports, its fail bits, a plugin channel’s dtype).
Fail bits¶
The bits of fail_mask, the fail bits that say why an env is not
valid.
- BUILTIN_FAIL_BITS: Mapping[str, int]¶
The
valid.failbits of TrackGen’s built-in checks, a read-only mapping:{"generator": 0, "turning": 1, "finite": 2, "thickness": 3, "w_floor": 4, "border": 5, "grade": 6, "truncation": 7}. Bits 8 to 15 are reserved for future built-in checks, 16 to 30 are assigned to plugin checks byStageBuilder.fail_bit(), and bit 31 is never used.Program.fail_bitsandTrack.fail_bitsextend it with the plugin checks of a pipeline; see Fail bits.
- GATE_FAIL_BITS: Mapping[str, int]¶
The
valid.failbits ofvalidity.gate_default, the gate pipeline’s built-in check, a read-only mapping:{"count": 0, "finite": 1, "tangent": 2, "spacing": 3, "crossing": 4, "grade": 5}. Bits 6 to 15 are reserved, 16 to 30 go to plugin checks as for tracks.Program.fail_bitsandGateSequence.fail_bitsextend it with the plugin checks of a gate pipeline; see Gate fail bits.
Ingestion¶
Loading your own centerlines into a generator that declares the centerline.* inputs,
such as the built-in external; see Ingesting your own centerlines.
- load_centerlines(target, xy, *, count=None, z=None, half_width=None, attributes=None, envs=None, stream=None)[source]¶
Load centerlines into a generator’s
centerline.*inputs (cold, blocking).The rows reach the device inputs the generator reads (
program.inputs): every generation after this call (on the generator’s stream) ingests them; a masked regeneration (generate(advance=True, mask=m)) rebuilds only the masked envs, so load new rows for those envs (envs=) before it.- Parameters:
target – A
TrackGenerator,GateGeneratororProgramwhose generator declares thecenterline.*inputs (generator="external").xy – The plan-view points of each env:
[E', m, 2](every rowmpoints),[E' * N, 2](N= the raw capacity,num_points), or a sequence ofE'arrays[m_e, 2](E': the number of loaded envs). A closed loop: the last point connects to the first (do not repeat it).count – Optional
[E']real point counts (default: each row’s length); a row longer than its count is cut.z – The altitude of each point, as
xywithout its last axis: required when the generator was builtwith_z, refused otherwise.half_width – The half-width of each point, alike;
> 0. In the data’s units, like the pipeline’sspacing. Required withwith_half_width.attributes –
{key: rows}for the ingested attributes ((key, dtype, interp)ofExternalParams.attributes): every one is required, with values of its kind (integers forint32, real numbers otherwise).envs – The env indices of the rows (default: every env, in order).
stream – The stream of the upload. Default: resolved like
generate’s (an ambientLaunchContext.scope, the generator’s constructorstream=, torch’s capture stream, Warp’s current stream, in that order), so it is ordered after in-flight generations on that stream. Inside a scope on another stream than the generator’s, or after agenerate(stream=t), passstream=(or order the streams with events).
- Return type:
None
The sizing check (with a
resample.constant_spacingstage): each env’s closed perimeterL(3D withz) must needfloor(L / spacing) + 1 <= n_maxpoints at the pipeline’s spacing, and at least 3: setspacing/n_max(presets.track(spacing=..., n_max=...)), or rescale the data. Exact without relax (theexternaldefault); a close pre-check with relax on (the devicetruncatedbit stays authoritative).- Raises:
TypeError – a target without a Program; an input of the wrong type.
ValueError – a generator without
centerline.xy; a shape / env-count mismatch;countoutside[3, N]; a non-finite point, altitude or half-width; a half-width<= 0; values of the wrong kind (non-numeric data; non-integer or out-of-range data for anint32attribute); an input the generator was not built with; an input it WAS built with left out (z=forwith_z,half_width=forwith_half_width, each ingested attribute: every per-point input is loaded with the rows); an unknown attribute; the sizing check.track_gen.exec.CaptureError – called inside a capture (before any work).
- Return type:
None
Built-in stage parameters¶
Each built-in stage’s Params. Most keep the TrackGenConfig /
GateGenConfig field names (their from_legacy copies the flat values, see
Pipeline stages); these take more: width.from_channel (see
Width), the stations stages (see 3D station spacing),
randomize.uniform (see Per-env randomization: randomize=), the external generator (see
Ingesting your own centerlines), and normalize.extent, whose one field is the per-env
size of the polar, voronoi and checkpoint gate generators (key
normalize.size, set by GateGenConfig.size; see Course size: size). A
dynamic field of these classes is a live per-env array (Domain randomization and curricula).
Params classes of the built-in track and gate stages.
Like the built-in generators’ Params, every class
keeps the FLAT TrackGenConfig field names and from_legacy(config) copies the flat
values (no casts), except WidthFromChannelParams (dynamic scale / lo /
hi) and StationsParams (gates, spacing_metric), which have no
TrackGenConfig counterpart. Every field is static except width.from_channel’s and
the elevation profiles’ altitude window and shape knobs (z_min / z_max of
elevation.uniform / random_walk / noise, z_max_step and
z_noise_amplitude; per-env arrays, latched each generation, read by the
warp_zprofile twins), normalize.extent’s size and gate_frames.default’s
gate_width (the course size of the polar / voronoi / checkpoint gate generators and
the per-env bar width; validity.gate_default’s gate_width / check_crossing
are inert: it checks the bars of every env per env).
The stage hands its Params instance (or, for elevation, a namespace built from its
static view) to the legacy wrappers as their config
argument, so the same values reach the same float() / int() conversions and the
launches are unchanged.
validate() re-runs the TrackGenConfig.__post_init__ rules of the class’s own
fields with the same messages: a spec made from a TrackGenConfig always passes; the
rules exist for hand-built specs. The stage Params map the fields a config HAS
(from_legacy of a GateGenConfig leaves z_control_points and
check_crossing at their class defaults).
- class WidthFromChannelParams[source]¶
Bases:
Paramswidth.from_channel:cl.half_width = clamp(scale * src, lo, hi)from a float32 per-point channel the user wires (StageRef.ports={"src": "cl.<pkg>.<name>"}, e.g. the carried image of a generator’sraw.<pkg>.<name>). A NaN source point stays NaN (and fails the width floor).lodefaults to 0: a source that pinches beloww_floorfails validity bit 4 instead of being clamped away.lo <= hiis checked at build; a run-timehibelowloclamps tolo(the kernel usesmax(hi, lo)as the upper bound).- __init__(*, scale=1.0, lo=0.0, hi=1000000000.0)¶
- classmethod __new__(*args, **kwargs)¶
- class StationsParams[source]¶
stations.raw/stations.relaxed:gatesanchors at equal arc length along a centerline loop: plan-view (spacing_metric="xy") or 3D ("xyz", which needs the loop’s altitude: a generator that providesz, or an elevation run on the relaxed centerline).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, gates=12, spacing_metric='xy')¶
- classmethod __new__(*args, **kwargs)¶
- class NormalizeExtentParams[source]¶
normalize.extent: the per-env size of the normalized gate layout (GateGenConfig.sizefor the polar / voronoi / checkpoint gate generators).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- classmethod __new__(*args, **kwargs)¶
Randomizers¶
randomize.uniform: per-env uniform draws of another stage’s DYNAMIC param, in the
graph (curriculum and domain randomization).
A randomizer is an ordinary STATIC stage of kind randomize (built-in only in 0.x),
listed right BEFORE the stage whose field it draws (only the generator’s randomizers may
precede the generator): every generation it writes u * (hi - lo) + lo per env into
the target field’s array, keyed by the env’s effective seed and its own salt, so the
draws are deterministic per (seed, epoch), differ across envs, are redrawn by
advance=True (every replay of a caller graph) and reach the target in the SAME
generation. Its lo / hi are dynamic (a curriculum writes them, in its own graph
too). A drawn field is a single UNLATCHED array owned by the randomizer
(params[stage][field] observes it; set raises). The drawable fields are the
dynamic float32 fields of the pipeline: the built-in generators’ shape knobs and the
elevation profiles’ window / grade / amplitude (e.g. "generator.rad",
"generator.polar_radial_jitter", "elevation.z_max"; the course size,
"generator.size" on every built-in track generator but external and on the
bezier / hull gate generators, "normalize.size" on the polar / voronoi / checkpoint
gate pipelines, and "gate_frames.gate_width"), plugin Params’ and
width.from_channel’s scale / lo / hi. An int32 dynamic field (bezier
/ hull’s min_num_points) is not drawable in 0.x. The initial range must lie inside
the field’s declared bounds (compared in float32) and the draws are clamped to them. A
knob bezier’s style_sampling draws (its *_range set) is not drawable (set the
range to None): style_sampling’s rad_range / handle_clamp_frac_range are
superseded by randomize={"generator.rad": ..., "generator.handle_clamp_frac": ...}
(different random streams, same distributions).
- class RandomizeUniform[source]¶
Bases:
Stagerandomize.uniform(see the module docstring).- __init__()¶
- classmethod __new__(*args, **kwargs)¶
The external generator¶
generator/external: ingest caller-provided centerlines.
A centerline generator Stage (kind="generator", name="external") that reads the
raw closed centerline of every env from device inputs the caller fills
(Program.inputs, stable pointers; track_gen.pipeline.load_centerlines() loads
numpy data outside the hot path, or the caller’s own graph writes them on the
generation’s stream), so a centerline from elsewhere (a dataset, a learned model, a
hand-drawn track) runs through the standard pipeline (resample, width, frames, offset,
validity, gates through stations, …). Built only from the public plugin surface:
StageBuilder.input(per="raw"),
Stage.declare, Stage.seeded = False and
Stage.preferred = {"relax": "none"} (presets.track(relax="auto") runs no relax:
the ingested geometry is not moved; pass relax="xpbd" to repair it).
Inputs (N = the raw capacity, presets.track(num_points=N)):
centerline.xy:[E * N]vec2f, UNLATCHED (read during the generation); initial value: a circle of radius0.6 * scaleper env (a fresh generator yields valid tracks at the defaultscale/half_width/spacing; with settings in the data’s units the placeholder is too small for the spacing: load centerlines before the first generation);centerline.count:[E]int32, LATCHED like every per-env input; the real point count of each row (initialN);centerline.z(with_z):[E * N]float32, the altitude (providesz);centerline.half_width(with_half_width):[E * N]float32, the half-width (provideshalf_width; initial0.1 * scale, a placeholder);centerline.<pkg>.<name>per ingested attribute:[E * N]of its dtype, carried with itsinterpand exported asTrack.attributes["<pkg>.<name>"].
Per generation: each input is copied first (the snapshot the pipeline consumes), padded
past count[e] with the row’s last real point (exact: the padding slots are
zero-length segments, so the resample sees the count[e]-point loop), then the
validity is computed on the COPIES: gen.valid[e] = 1 iff 3 <= count[e] <= N,
the first count[e] points are finite and, when present, z is finite and
half_width finite and > 0 (else fail bit 0, "generator"; poisoned with
on_invalid="poison").
No per-env size: the ingested geometry is taken as given (a size
would scale it about the data’s own origin while its altitude, half-width and attributes
stay, and load_centerlines()’ host sizing check could not see
it). Scale centerline.xy in your own graph; generator.size (a randomizer,
set("size"), a flat TrackGenConfig.size other than 1) raises with that hint.
- class External[source]¶
Bases:
Stagegenerator/external(see the module docstring).- Params¶
alias of
ExternalParams
- capture: ClassVar[CaptureClass] = 0¶
- classmethod declare(params)[source]¶
(writes, provides)for these params:raw.xyandgen.validalways;raw.zandprovideszwithwith_z;raw.half_widthandprovideshalf_widthwithwith_half_width; oneraw.<key>per declared attribute (seetrack_gen.plugin.Stage.declare()).
- build(b, p)[source]¶
Allocate everything through
b, ONCE, and returnenqueue(ctx).enqueueemits onlyctx.launch/ctx.copy/ctx.fill/ctx.bounded_loop/track_gen.opswork: no allocation, no host sync, no branch on device data or onctx.capturing(aHOSTstage reaches the host throughctx.host()).
The other built-in stages¶
Their fields keep the TrackGenConfig / GateGenConfig names, and from_legacy
reads them from a config.
- class ConstantSpacingParams[source]¶
resample.constant_spacing: arc-length resample of the raw loop to a constant step, padded toN_max.- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- classmethod __new__(*args, **kwargs)¶
- class ElevationFlatParams[source]¶
elevation.flat: every real point atz_base. On a gate pipeline it fillsgates.zwithz_base(GateGenConfig.z_base); on a track it must stay 0 (the flat lift addspresets.track(z_base=...)).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- classmethod __new__(*args, **kwargs)¶
- class ElevationNoiseParams[source]¶
elevation.noise: periodic harmonic noise aroundz_base(z_min/z_max/z_noise_amplitudedynamic: the difficulty knob isz_noise_amplitudein a wide, symmetric window).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, z_base=0.0, z_min=0.0, z_max=0.0, z_noise_amplitude=0.0, z_noise_harmonics=3)¶
- classmethod __new__(*args, **kwargs)¶
- class ElevationRandomWalkParams[source]¶
elevation.random_walk: a grade-capped random walk over the knots (z_min/z_max/z_max_stepdynamic: the difficulty knob isz_max_stepin a wide window).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, z_base=0.0, z_min=0.0, z_max=0.0, z_max_step=0.0, z_control_points=10)¶
- classmethod __new__(*args, **kwargs)¶
- class ElevationUniformParams[source]¶
elevation.uniform: i.i.d. knot altitudes in[z_min, z_max](z_min/z_maxdynamic: the difficulty knob isz_maxwithz_minfixed).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, z_min=0.0, z_max=0.0, z_control_points=10)¶
- classmethod __new__(*args, **kwargs)¶
- class GateFramesParams[source]¶
gate_frames.default: the gate frames,half_size = 0.5 * gate_width(gate_widthis dynamic: the initial value of a per-env width).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, gate_width=0.0, gate_align='yaw_only')¶
- classmethod __new__(*args, **kwargs)¶
- class GateFramesPosedParams[source]¶
gate_frames.posed: the gate frames of a generator that provides per-gatehalf_sizeandroll.- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- classmethod __new__(*args, **kwargs)¶
- class GateRelaxParams[source]¶
gate_relax.spheres: separate overlapping gate spheres (plan view) to a centre distance of2 * gate_radius, for at mostgate_solve_iterssweeps.- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, gate_radius=0.025, gate_solve_iters=8)¶
- classmethod __new__(*args, **kwargs)¶
- class GateValidityParams[source]¶
validity.gate_default: the fused per-env gate validity check. The bar-crossing check runs per env on every env with a non-zero bar, sogate_widthandcheck_crossingare INERT (kept so specs and dicts load; agate_widthother than its default 0 must still equalgate_frames’ initial width; removed in 1.0).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names, for the fields
cfg(aTrackGenConfigor aGateGenConfig) has; the others keep their class defaults.
- __init__(*, min_gates=4, gate_radius=0.025, gate_width=0.0, z_valid_grade=0.0, check_crossing='width')¶
- classmethod __new__(*args, **kwargs)¶
- class LiftFlatParams[source]¶
lift.flat: the constant altitude of every point.- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- classmethod __new__(*args, **kwargs)¶
- class OffsetParams[source]¶
offset.default: the outer / inner borders atcl.half_width(the per-point half-width channel the width stage writes).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- __init__()¶
- Return type:
None
- classmethod __new__(*args, **kwargs)¶
- class ValidityParams[source]¶
validity.default: the fused per-env validity gate (the thickness and width floor checks readcl.half_width).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- __init__(*, turning_tol=0.1, w_floor=0.001, relax_tol=0.02, z_valid_grade=0.0, validity_border_check=False)¶
- classmethod __new__(*args, **kwargs)¶
- class WidthConstantParams[source]¶
width.constant: one half-width for every point.- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- classmethod __new__(*args, **kwargs)¶
- class XpbdParams[source]¶
relax.xpbd: the XPBD relaxation (band / rest length setup + solve). The half-width iscl.half_width(the width stage runs before relax).- classmethod from_legacy(cfg)¶
An instance holding the values of the config fields of the same names (every field of this class is a flat
TrackGenConfig/GateGenConfigfield), uncast.
- __init__(*, relax_band=None, relax_iters=50, relax_margin=0.15, relax_sep_relax=1.0, relax_spc_relax=1.0, relax_bend_relax=1.5, relax_sep_every=20, relax_sep_cache_slots=16, relax_sep_cache_skin=0.5, relax_accel='chebyshev', relax_cheby_rho=0.98, relax_cheby_gamma=0.9, relax_cheby_start=8, relax_smooth_passes=5, relax_smooth_spacing_iters=10)¶
- Parameters:
relax_band (int | None)
relax_iters (int)
relax_margin (float)
relax_sep_relax (float)
relax_spc_relax (float)
relax_bend_relax (float)
relax_sep_every (int)
relax_sep_cache_slots (int)
relax_sep_cache_skin (float)
relax_accel (str)
relax_cheby_rho (float)
relax_cheby_gamma (float)
relax_cheby_start (int)
relax_smooth_passes (int)
relax_smooth_spacing_iters (int)
- Return type:
None
- classmethod __new__(*args, **kwargs)¶