1use alloc::vec::Vec;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct EngramGeometry {
12 pub slots: usize,
14 pub sub_dim: usize,
16 pub num_tables: usize,
18 pub conv_taps: usize,
20 pub conv_dilation: usize,
22 pub orders: Vec<usize>,
24 pub sites: Vec<usize>,
26}
27
28impl EngramGeometry {
29 pub fn heads(&self) -> usize {
31 if self.orders.is_empty() {
32 0
33 } else {
34 self.num_tables / self.orders.len()
35 }
36 }
37
38 pub fn fetched_dim(&self) -> usize {
40 self.num_tables * self.sub_dim
41 }
42
43 pub fn window(&self) -> usize {
46 if self.sites.is_empty() {
47 0
48 } else {
49 self.conv_taps * self.conv_dilation
50 }
51 }
52
53 pub fn site_of_layer(&self, layer: usize) -> Option<usize> {
55 self.sites.iter().position(|&l| l == layer)
56 }
57}
58
59#[derive(Debug, Clone, PartialEq)]
61pub struct V2Config {
62 pub vocab_size: usize,
63 pub d_model: usize,
64 pub num_heads: usize,
65 pub num_kv_heads: usize,
66 pub num_layers: usize,
67 pub head_dim: usize,
68 pub max_seq_len: usize,
69 pub hada_n: usize,
71 pub mhc_lanes: usize,
72 pub rope_theta: f32,
73 pub kv_window: usize,
75 pub engram: EngramGeometry,
76}
77
78impl V2Config {
79 pub fn attn_dim(&self) -> usize {
81 self.num_heads * self.head_dim
82 }
83
84 pub fn kv_dim(&self) -> usize {
86 self.num_kv_heads * self.head_dim
87 }
88
89 pub fn kv_repeat(&self) -> usize {
91 self.num_heads / self.num_kv_heads
92 }
93
94 pub fn mhc_width(&self) -> usize {
96 self.mhc_lanes * self.d_model
97 }
98
99 pub fn active_lane(&self, layer: usize) -> usize {
102 layer % self.mhc_lanes
103 }
104
105 pub fn pre_off(&self, layer: usize, lane: usize) -> f32 {
107 if lane == self.active_lane(layer) {
108 4.0
109 } else {
110 -4.0
111 }
112 }
113
114 pub fn post_off(&self, layer: usize, lane: usize) -> f32 {
116 if lane == self.active_lane(layer) {
117 0.0
118 } else {
119 -4.0
120 }
121 }
122
123 pub fn validate(&self) -> Result<(), &'static str> {
124 if self.num_heads == 0 || self.num_kv_heads == 0 {
125 return Err("head counts must be non-zero");
126 }
127 if !self.num_heads.is_multiple_of(self.num_kv_heads) {
128 return Err("num_heads must be divisible by num_kv_heads");
129 }
130 if self.head_dim == 0 || !self.head_dim.is_multiple_of(2) {
131 return Err("head_dim must be even (RoPE rotates half-splits)");
132 }
133 if self.d_model == 0 || self.mhc_lanes == 0 || self.num_layers == 0 {
134 return Err("d_model, mhc_lanes and num_layers must be non-zero");
135 }
136 if !self.hada_n.is_power_of_two() || self.hada_n < self.d_model {
137 return Err("hada_n must be a power of two at or above d_model");
138 }
139 if self.vocab_size == 0 || self.max_seq_len == 0 {
140 return Err("vocab_size and max_seq_len must be non-zero");
141 }
142 if !self.engram.sites.is_empty() {
143 let e = &self.engram;
144 if e.orders.is_empty() || e.num_tables == 0 || e.sub_dim == 0 || e.slots == 0 {
145 return Err("engram geometry incomplete");
146 }
147 if !e.num_tables.is_multiple_of(e.orders.len()) {
148 return Err("num_tables must be divisible by the order count");
149 }
150 if e.sites.iter().any(|&l| l >= self.num_layers) {
151 return Err("engram site beyond num_layers");
152 }
153 if e.fetched_dim() != self.d_model {
154 return Err("engram fetched_dim must equal d_model");
157 }
158 }
159 Ok(())
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use alloc::vec;
167
168 fn cfg() -> V2Config {
169 V2Config {
170 vocab_size: 8192,
171 d_model: 512,
172 num_heads: 8,
173 num_kv_heads: 4,
174 num_layers: 27,
175 head_dim: 64,
176 max_seq_len: 2048,
177 hada_n: 512,
178 mhc_lanes: 4,
179 rope_theta: 100000.0,
180 kv_window: 256,
181 engram: EngramGeometry {
182 slots: 8192,
183 sub_dim: 128,
184 num_tables: 4,
185 conv_taps: 4,
186 conv_dilation: 3,
187 orders: vec![2, 3],
188 sites: vec![2, 15],
189 },
190 }
191 }
192
193 #[test]
194 fn shipped_geometry_validates() {
195 let c = cfg();
196 assert_eq!(c.validate(), Ok(()));
197 assert_eq!(c.attn_dim(), 512);
198 assert_eq!(c.kv_dim(), 256);
199 assert_eq!(c.kv_repeat(), 2);
200 assert_eq!(c.mhc_width(), 2048);
201 assert_eq!(c.engram.heads(), 2);
202 assert_eq!(c.engram.fetched_dim(), 512);
203 assert_eq!(c.engram.window(), 12);
204 assert_eq!(c.engram.site_of_layer(2), Some(0));
205 assert_eq!(c.engram.site_of_layer(15), Some(1));
206 assert_eq!(c.engram.site_of_layer(3), None);
207 }
208
209 #[test]
211 fn mhc_lane_offsets_match_reference_formulas() {
212 let c = cfg();
213 for layer in 0..c.num_layers {
214 for lane in 0..c.mhc_lanes {
215 let onehot = f32::from(lane == layer % c.mhc_lanes);
216 assert_eq!(c.pre_off(layer, lane), 8.0 * onehot - 4.0);
217 assert_eq!(c.post_off(layer, lane), -4.0 * (1.0 - onehot));
218 }
219 }
220 }
221
222 #[test]
223 fn validate_rejects_broken_geometry() {
224 let mut c = cfg();
225 c.num_kv_heads = 3;
226 assert!(c.validate().is_err());
227
228 let mut c = cfg();
229 c.head_dim = 63;
230 assert!(c.validate().is_err());
231
232 let mut c = cfg();
233 c.hada_n = 256; assert!(c.validate().is_err());
235
236 let mut c = cfg();
237 c.engram.sites = vec![2, 99];
238 assert!(c.validate().is_err());
239
240 let mut c = cfg();
241 c.engram.sub_dim = 64; assert!(c.validate().is_err());
243 }
244}