pub struct RopePlan { /* private fields */ }Expand description
Per-layer RoPE-BASE variation — the sibling axis to MaskPlan, and
the one Gemma3 forced.
A family with two RoPE bases (Gemma3: rope_theta for global layers,
rope_local_base_freq for sliding ones) produces different table bytes per
variant, so — exactly like the mask — the Const must physically carry N of
them and the layer loop must select.
This is the criterion that separates it from SmolLm3’s per-layer RoPE gating, which needs nothing: variation in DATA needs a variant axis; variation in WHETHER-TO-APPLY does not. A skipping layer simply does not consume the shared tables; a differently-based layer needs different bytes.
§Shape, and an honest asymmetry with MaskPlan
n_variants == 1 mints [seq, rope_width] — exactly today’s shape, with
no slice and no reshape — so every single-base family’s graph is unchanged
(pinned by the *_held_decode_graph_has_not_grown node-count tests).
n_variants > 1 mints [n, seq, rope_width] and hoists the per-variant
views once before the layer loop. Unlike the mask — whose Const is already
rank-4, so a width-1 slice is directly usable — RoPE tables are rank-2, so
each variant costs a slice and a reshape. That cost is real and is named
here rather than presented as symmetric.
Implementations§
Source§impl RopePlan
impl RopePlan
Sourcepub fn single(base: f64, n_layers: usize) -> Self
pub fn single(base: f64, n_layers: usize) -> Self
The single-base plan — what every family except Gemma3 uses.
Sourcepub fn new(bases: Vec<f64>, per_layer: Vec<usize>) -> Result<Self>
pub fn new(bases: Vec<f64>, per_layer: Vec<usize>) -> Result<Self>
Validated at construction, like MaskPlan::new: an out-of-range
variant index would otherwise be a panic in the layer loop or, worse, a
layer silently roped at the wrong frequency.
Sourcepub fn per_layer_base(
n_layers: usize,
base_when_true: f64,
base_when_false: f64,
uses_first: impl Fn(usize) -> bool,
) -> Self
pub fn per_layer_base( n_layers: usize, base_when_true: f64, base_when_false: f64, uses_first: impl Fn(usize) -> bool, ) -> Self
Two-base per-layer selection, TOTAL by construction — the sibling of
MaskPlan::per_layer_window, and what Gemma3 uses: base_when_true is
its rope_local_base_freq (sliding layers), base_when_false its
rope_theta (full-causal layers).
Infallible for the same reason: a bool selector over exactly two
defined bases cannot index out of range, so decode_rope_plan needs no
Result and no expect.
⚠️ Collapses to a single base when the two are EQUAL — which is not a
micro-optimisation but a correctness-of-measurement matter: Gemma3’s
shipped fixtures set rope_local_base_freq == rope_theta, and a plan
that still reported 2 variants there would make the graph look
dual-base while every layer read identical bytes. Collapsing makes the
degeneracy visible in n_variants(), which is what the non-vacuity
assertions in Gemma3’s tests key on.
pub fn n_variants(&self) -> usize
pub fn n_layers(&self) -> usize
pub fn variant_for_layer(&self, layer_idx: usize) -> usize
Sourcepub fn mix_into(&self, h: &mut ShapeKeyHasher)
pub fn mix_into(&self, h: &mut ShapeKeyHasher)
Mix the plan’s structural content into a decode shape key: the
variant count and per-layer assignment wire the graph. The base values
are excluded for the same reason rope_base always was — they are data,
recomputed and rebound every token, so baking them would forfeit plan
reuse across a change already handled correctly.
Trait Implementations§
impl StructuralPartialEq for RopePlan
Auto Trait Implementations§
impl Freeze for RopePlan
impl RefUnwindSafe for RopePlan
impl Send for RopePlan
impl Sync for RopePlan
impl Unpin for RopePlan
impl UnsafeUnpin for RopePlan
impl UnwindSafe for RopePlan
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more