1use crate::profile::{
28 AxisCtx, AxisProfile, EchoProfile, FlowProfile, MagnitudeProfile, ObservationProfile,
29 SeamProfile, SpectralProfile, StressProfile,
30};
31use crate::supertoken::{Role, SuperContext, SuperToken};
32use crate::token::Token;
33
34pub struct Window<P: AxisProfile> {
43 capacity: usize,
44 back: Vec<P>,
45 back_fold: P,
46 front: Vec<P>,
47}
48
49impl<P: AxisProfile> Window<P> {
50 #[must_use]
52 pub fn new(capacity: usize) -> Self {
53 let capacity = capacity.max(1);
54 Window {
55 capacity,
56 back: Vec::with_capacity(capacity),
57 back_fold: P::identity(),
58 front: Vec::with_capacity(capacity),
59 }
60 }
61
62 #[must_use]
64 pub fn len(&self) -> usize {
65 self.front.len() + self.back.len()
66 }
67
68 #[must_use]
70 pub fn is_empty(&self) -> bool {
71 self.len() == 0
72 }
73
74 pub fn push(&mut self, value: P) {
76 if self.len() == self.capacity {
77 self.pop();
78 }
79 self.back_fold = self.back_fold.combine(&value);
80 self.back.push(value);
81 }
82
83 fn pop(&mut self) {
85 if self.front.is_empty() {
86 let mut suffix = P::identity();
87 for value in self.back.iter().rev() {
88 suffix = value.combine(&suffix);
89 self.front.push(suffix.clone());
90 }
91 self.back.clear();
92 self.back_fold = P::identity();
93 }
94 self.front.pop();
95 }
96
97 #[must_use]
99 pub fn fold(&self) -> P {
100 match self.front.last() {
101 Some(older) => older.combine(&self.back_fold),
102 None => self.back_fold.clone(),
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialEq)]
114pub struct WindowProfile {
115 pub magnitude: MagnitudeProfile,
117 pub stress: StressProfile,
119 pub spectral: SpectralProfile,
121 pub echo: EchoProfile,
123 pub observation: ObservationProfile,
125 pub seam: SeamProfile,
127 pub flow: FlowProfile,
129}
130
131impl AxisProfile for WindowProfile {
132 fn identity() -> Self {
133 WindowProfile {
134 magnitude: MagnitudeProfile::identity(),
135 stress: StressProfile::identity(),
136 spectral: SpectralProfile::identity(),
137 echo: EchoProfile::identity(),
138 observation: ObservationProfile::identity(),
139 seam: SeamProfile::identity(),
140 flow: FlowProfile::identity(),
141 }
142 }
143
144 fn combine(&self, other: &Self) -> Self {
145 WindowProfile {
146 magnitude: self.magnitude.combine(&other.magnitude),
147 stress: self.stress.combine(&other.stress),
148 spectral: self.spectral.combine(&other.spectral),
149 echo: self.echo.combine(&other.echo),
150 observation: self.observation.combine(&other.observation),
151 seam: self.seam.combine(&other.seam),
152 flow: self.flow.combine(&other.flow),
153 }
154 }
155
156 fn of_token(idx: usize, tok: &Token, ctx: &AxisCtx<'_>) -> Self {
157 WindowProfile {
158 magnitude: MagnitudeProfile::of_token(idx, tok, ctx),
159 stress: StressProfile::of_token(idx, tok, ctx),
160 spectral: SpectralProfile::of_token(idx, tok, ctx),
161 echo: EchoProfile::of_token(idx, tok, ctx),
162 observation: ObservationProfile::of_token(idx, tok, ctx),
163 seam: SeamProfile::of_token(idx, tok, ctx),
164 flow: FlowProfile::of_token(idx, tok, ctx),
165 }
166 }
167}
168
169#[derive(Clone, Copy, Debug)]
171pub struct ContextConfig {
172 pub token_window: usize,
175 pub unit_window: usize,
177}
178
179impl Default for ContextConfig {
180 fn default() -> Self {
181 let token_window = crate::observation::ObservationConfig::default().window;
186 ContextConfig { token_window, unit_window: (token_window / 4).max(1) }
187 }
188}
189
190#[derive(Clone, Copy, Debug, PartialEq, Eq)]
200pub struct Agreement {
201 pub role: Role,
204 pub regime: Option<i32>,
206 pub shape: Option<i32>,
208 pub seam: Option<i32>,
210}
211
212#[derive(Clone, Debug, Default)]
214pub struct ContextField {
215 pub at_token: Vec<WindowProfile>,
218 pub of_unit: Vec<WindowProfile>,
220 pub at_unit: Vec<WindowProfile>,
222 pub agreement: Vec<Agreement>,
224}
225
226impl ContextField {
227 #[must_use]
235 pub fn alignment(&self) -> (f32, f32, f32) {
236 let n = self.agreement.len();
237 if n == 0 {
238 return (0.0, 0.0, 0.0);
239 }
240 let modal_share = |offset: fn(&Agreement) -> Option<i32>| {
241 let mut counts: std::collections::HashMap<(u32, i32), u32> =
242 std::collections::HashMap::new();
243 for a in &self.agreement {
244 if let Some(o) = offset(a) {
245 *counts.entry((a.role.code(), o)).or_insert(0) += 1;
246 }
247 }
248 let mut modal: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
249 for (&(role, _), &c) in &counts {
250 let m = modal.entry(role).or_insert(0);
251 *m = (*m).max(c);
252 }
253 modal.values().sum::<u32>() as f32 / n as f32
254 };
255 (modal_share(|a| a.regime), modal_share(|a| a.shape), modal_share(|a| a.seam))
256 }
257}
258
259#[must_use]
266pub fn fold_windows(
267 toks: &[Token],
268 ctx: &AxisCtx<'_>,
269 supers: &SuperContext,
270 cfg: &ContextConfig,
271) -> ContextField {
272 fold_range(toks, ctx, supers, cfg, 0..toks.len(), 0)
273}
274
275const FOLD_MIN_LEAF_TOKENS: usize = 1024;
280
281#[must_use]
290pub fn fold_windows_parallel(
291 toks: &[Token],
292 ctx: &AxisCtx<'_>,
293 supers: &SuperContext,
294 cfg: &ContextConfig,
295) -> ContextField {
296 use flynnel::JobPlan;
297 use flynnel::sched::par_iter::for_each_chunk_indexed_min_leaf;
298
299 let cores = std::thread::available_parallelism().map_or(1, std::num::NonZero::get);
300 let n_units = supers.units.len();
301 let units_per_chunk = n_units.div_ceil(cores * 4).max(1);
302 let mut chunks: Vec<(usize, usize)> = Vec::new();
306 let mut u = 0usize;
307 while u < n_units {
308 let tok_lo = first_token(toks, supers, u);
309 chunks.push((u, tok_lo));
310 let mut v = u + 1;
311 while v < n_units
312 && (v - u < units_per_chunk || first_token(toks, supers, v) - tok_lo < FOLD_MIN_LEAF_TOKENS)
313 {
314 v += 1;
315 }
316 u = v;
317 }
318 if chunks.len() <= 1 || cores <= 1 {
319 return fold_windows(toks, ctx, supers, cfg);
320 }
321 let bounds: Vec<(usize, usize, usize)> = chunks
322 .iter()
323 .enumerate()
324 .map(|(k, &(unit_lo, tok_lo))| {
325 let tok_hi = chunks.get(k + 1).map_or(toks.len(), |&(_, t)| t);
326 (unit_lo, tok_lo, tok_hi)
327 })
328 .collect();
329 let mut parts: Vec<ContextField> = bounds.iter().map(|_| ContextField::default()).collect();
330 let plan = JobPlan::new(0, bounds.len() as u32)
335 .with_leaf_shape(flynnel::LeafShape::Streaming);
336 for_each_chunk_indexed_min_leaf(&plan, &mut parts, 1, |start, slots| {
337 for (i, slot) in slots.iter_mut().enumerate() {
338 let (unit_lo, tok_lo, tok_hi) = bounds[start + i];
339 *slot = fold_range(toks, ctx, supers, cfg, tok_lo..tok_hi, unit_lo);
340 }
341 });
342 let lead = bounds.first().map_or(0, |b| b.1);
345 let mut out = ContextField {
346 at_token: Vec::with_capacity(toks.len()),
347 of_unit: Vec::with_capacity(n_units),
348 at_unit: Vec::with_capacity(n_units),
349 agreement: Vec::new(),
350 };
351 out.at_token.extend(std::iter::repeat_n(WindowProfile::identity(), lead));
352 for part in parts {
353 out.at_token.extend(part.at_token);
354 out.of_unit.extend(part.of_unit);
355 out.at_unit.extend(part.at_unit);
356 }
357 out
358}
359
360fn first_token(toks: &[Token], supers: &SuperContext, u: usize) -> usize {
362 toks.partition_point(|t| t.start() < supers.units[u].start)
363}
364
365fn fold_range(
370 toks: &[Token],
371 ctx: &AxisCtx<'_>,
372 supers: &SuperContext,
373 cfg: &ContextConfig,
374 tokens: std::ops::Range<usize>,
375 unit_lo: usize,
376) -> ContextField {
377 let mut window: Window<WindowProfile> = Window::new(cfg.token_window);
378 let seed: Vec<usize> = (0..tokens.start)
381 .rev()
382 .filter(|&i| toks[i].is_significant())
383 .take(cfg.token_window)
384 .collect();
385 for &i in seed.iter().rev() {
386 window.push(WindowProfile::of_token(i, &toks[i], ctx));
387 }
388 let mut current = window.fold();
389 let mut unit_window: Window<WindowProfile> = Window::new(cfg.unit_window);
393 for u in unit_lo.saturating_sub(cfg.unit_window)..unit_lo {
394 let lo = first_token(toks, supers, u);
395 let hi = first_token(toks, supers, u + 1);
396 let reading = (lo..hi)
397 .filter(|&i| toks[i].is_significant() && supers.index_of(i) == Some(u))
398 .fold(WindowProfile::identity(), |acc, i| acc.combine(&WindowProfile::of_token(i, &toks[i], ctx)));
399 unit_window.push(reading);
400 }
401 let mut at_token: Vec<WindowProfile> = Vec::with_capacity(tokens.len());
402 let mut of_unit: Vec<WindowProfile> = Vec::new();
403 let mut at_unit: Vec<WindowProfile> = Vec::new();
404 let mut unit_fold = WindowProfile::identity();
405 let mut open_unit: Option<usize> = None;
406 let close_unit = |unit_fold: &mut WindowProfile,
407 of_unit: &mut Vec<WindowProfile>,
408 at_unit: &mut Vec<WindowProfile>,
409 unit_window: &mut Window<WindowProfile>| {
410 let reading = std::mem::replace(unit_fold, WindowProfile::identity());
411 unit_window.push(reading.clone());
412 of_unit.push(reading);
413 at_unit.push(unit_window.fold());
414 };
415 for i in tokens {
416 let tok = &toks[i];
417 if tok.is_significant() {
418 let reading = WindowProfile::of_token(i, tok, ctx);
419 window.push(reading.clone());
420 current = window.fold();
421 match (supers.index_of(i), open_unit) {
422 (Some(u), Some(open)) if u == open => {
423 unit_fold = unit_fold.combine(&reading);
424 }
425 (Some(u), open) => {
426 if open.is_some() {
427 close_unit(&mut unit_fold, &mut of_unit, &mut at_unit, &mut unit_window);
428 }
429 open_unit = Some(u);
430 unit_fold = reading;
431 }
432 (None, Some(_)) => {
433 close_unit(&mut unit_fold, &mut of_unit, &mut at_unit, &mut unit_window);
434 open_unit = None;
435 }
436 (None, None) => {}
437 }
438 }
439 at_token.push(current.clone());
440 }
441 if open_unit.is_some() {
442 close_unit(&mut unit_fold, &mut of_unit, &mut at_unit, &mut unit_window);
443 }
444 ContextField { at_token, of_unit, at_unit, agreement: Vec::new() }
445}
446
447#[must_use]
456pub fn agreement(
457 units: &[SuperToken],
458 toks: &[Token],
459 regime_cuts: &[usize],
460 shape_cuts: &[usize],
461 seam_cuts: &[usize],
462) -> Vec<Agreement> {
463 let starts: Vec<usize> =
466 toks.iter().filter(|t| t.is_significant()).map(Token::start).collect();
467 let sig_index = |byte: usize| starts.partition_point(|&s| s <= byte).saturating_sub(1);
468 let place = |cuts: &[usize]| -> Vec<usize> { cuts.iter().map(|&c| sig_index(c)).collect() };
469 let (regime, shape, seam) = (place(regime_cuts), place(shape_cuts), place(seam_cuts));
470 let nearest = |placed: &[usize], at: usize| -> Option<i32> {
471 if placed.is_empty() {
472 return None;
473 }
474 let i = placed.partition_point(|&p| p < at);
475 let after = placed.get(i).map(|&p| p as i64 - at as i64);
476 let before = i.checked_sub(1).map(|j| placed[j] as i64 - at as i64);
477 let offset = match (before, after) {
478 (Some(b), Some(a)) => if a.abs() < b.abs() { a } else { b },
479 (Some(b), None) => b,
480 (None, Some(a)) => a,
481 (None, None) => return None,
482 };
483 Some(offset.clamp(i64::from(i32::MIN), i64::from(i32::MAX)) as i32)
484 };
485 units
486 .iter()
487 .map(|u| {
488 let at = sig_index(u.start);
489 Agreement {
490 role: u.role,
491 regime: nearest(®ime, at),
492 shape: nearest(&shape, at),
493 seam: nearest(&seam, at),
494 }
495 })
496 .collect()
497}
498
499#[derive(Clone, Debug, PartialEq)]
507pub struct RelationReading {
508 pub enclosing: WindowProfile,
511 pub echoing: WindowProfile,
514 pub regime: WindowProfile,
517 pub phase: WindowProfile,
521}
522
523#[derive(Clone, Debug, Default)]
525pub struct RelationContext {
526 pub at_token: Vec<RelationReading>,
529 pub phase_of: Vec<u16>,
533 pub value_history: Vec<WindowProfile>,
539 pub period: Option<u16>,
542}
543
544impl Default for RelationReading {
545 fn default() -> Self {
546 RelationReading {
547 enclosing: WindowProfile::identity(),
548 echoing: WindowProfile::identity(),
549 regime: WindowProfile::identity(),
550 phase: WindowProfile::identity(),
551 }
552 }
553}
554
555#[must_use]
564pub fn relate(
565 toks: &[Token],
566 ctx: &AxisCtx<'_>,
567 regime_cuts: &[usize],
568 echo: &crate::echo::EchoField,
569 period: Option<u16>,
570) -> RelationContext {
571 use crate::token::TokenKind;
572
573 let n = toks.len();
574 let readings = token_readings(toks, ctx);
575 let mut at_token: Vec<RelationReading> = Vec::with_capacity(n);
576 let mut phase_of: Vec<u16> = vec![u16::MAX; n];
577 let mut value_history: Vec<WindowProfile> = vec![WindowProfile::identity(); n];
578 let mut enclosure: Vec<WindowProfile> = Vec::new();
581 let mut heads: Vec<bool> = Vec::new();
582 let mut echo_fold: Vec<WindowProfile> = vec![WindowProfile::identity(); n];
587 let mut operand_of: Vec<Option<usize>> = vec![None; n];
588 let starts: Vec<usize> = toks.iter().map(Token::start).collect();
589 let mut regime = WindowProfile::identity();
590 let mut next_cut = regime_cuts.partition_point(|&c| c == 0);
591 let p = period.map_or(0, usize::from);
592 let mut phase_fold: Vec<WindowProfile> = vec![WindowProfile::identity(); p];
593 let mut sig_index = 0usize;
594 let mut current = RelationReading::default();
595 let mut last_sig: Option<usize> = None;
596 for (i, tok) in toks.iter().enumerate() {
597 let prev_sig = last_sig;
600 if matches!(tok.kind, TokenKind::Close(_)) && heads.pop().is_some() {
601 enclosure.pop();
602 }
603 if tok.is_significant() {
604 let reading = &readings[i];
605 if tok.kind == TokenKind::Punct
608 && matches!(&ctx.bytes[tok.span()], b"=" | b":")
609 && let Some(l) = prev_sig
610 && let Some(r) = (i + 1..n).find(|&j| toks[j].is_significant())
611 {
612 operand_of[l] = Some(r);
613 }
614 while next_cut < regime_cuts.len() && regime_cuts[next_cut] <= tok.start() {
617 regime = WindowProfile::identity();
618 next_cut += 1;
619 }
620 let regime_before = regime.clone();
621 regime = regime.combine(reading);
622 let frame = echo.frames.get(i);
623 let echoing = match frame.and_then(|f| f.back_lag) {
624 Some(lag) => {
625 let prev = starts.partition_point(|&s| s < tok.start() - lag.get() as usize);
626 let fold = echo_fold[prev].combine(&readings[prev]);
627 echo_fold[i] = fold.clone();
628 let bound = &value_history[prev];
629 value_history[i] = match operand_of[prev] {
630 Some(r) => bound.combine(&readings[r]),
631 None => bound.clone(),
632 };
633 fold
634 }
635 None => WindowProfile::identity(),
636 };
637 let phase = if p > 0 {
638 let k = sig_index % p;
639 phase_of[i] = k as u16;
640 let before = phase_fold[k].clone();
641 phase_fold[k] = before.combine(reading);
642 before
643 } else {
644 WindowProfile::identity()
645 };
646 sig_index += 1;
647 current = RelationReading {
648 enclosing: enclosure.last().cloned().unwrap_or_else(WindowProfile::identity),
649 echoing,
650 regime: regime_before,
651 phase,
652 };
653 last_sig = Some(i);
654 }
655 if matches!(tok.kind, TokenKind::Open(_)) {
656 let head = prev_sig.filter(|&j| matches!(toks[j].kind, TokenKind::Word));
659 let below = enclosure.last().cloned().unwrap_or_else(WindowProfile::identity);
660 enclosure.push(match head {
661 Some(h) => below.combine(&readings[h]),
662 None => below,
663 });
664 heads.push(true);
665 }
666 at_token.push(current.clone());
667 }
668 RelationContext { at_token, phase_of, value_history, period }
669}
670
671fn token_readings(toks: &[Token], ctx: &AxisCtx<'_>) -> Vec<WindowProfile> {
674 use flynnel::JobPlan;
675 use flynnel::sched::par_iter::for_each_chunk_indexed_min_leaf;
676
677 let mut readings: Vec<WindowProfile> = vec![WindowProfile::identity(); toks.len()];
678 let cores = std::thread::available_parallelism().map_or(1, std::num::NonZero::get);
679 let min_leaf = toks.len().div_ceil(cores * 4).max(FOLD_MIN_LEAF_TOKENS);
680 let plan = JobPlan::new(0, toks.len() as u32)
681 .with_leaf_shape(flynnel::LeafShape::Streaming);
682 for_each_chunk_indexed_min_leaf(&plan, &mut readings, min_leaf, |start, slots| {
683 for (k, slot) in slots.iter_mut().enumerate() {
684 let i = start + k;
685 if toks[i].is_significant() {
686 *slot = WindowProfile::of_token(i, &toks[i], ctx);
687 }
688 }
689 });
690 readings
691}
692
693#[must_use]
695pub fn relate_bytes(bytes: &[u8]) -> RelationContext {
696 let toks = crate::lexer::lex(bytes);
697 let spectral = crate::spectral::analyze(bytes);
698 let stress = crate::stress::analyze(&toks, bytes);
699 let echo = crate::echo::analyze(&toks, bytes);
700 let ctx = AxisCtx {
701 spectral: Some(&spectral),
702 stress: Some(&stress),
703 echo: Some(&echo),
704 ..AxisCtx::new(bytes)
705 };
706 relate(&toks, &ctx, &spectral.boundaries, &echo, record_period(&toks, bytes))
707}
708
709pub const PHASE_MAX_PERIOD: u16 = 32;
712
713pub const PERIOD_LIFT_FLOOR: f32 = 1.4;
732
733#[must_use]
751pub fn record_period(toks: &[Token], bytes: &[u8]) -> Option<u16> {
752 gated_lag(&period_symbols(toks, bytes))
753}
754
755fn gated_lag(symbols: &[u32]) -> Option<u16> {
758 let (lag, share) = best_lag(symbols)?;
759 let chance = chance_of(symbols);
760 if chance <= 0.0 {
763 return Some(lag);
764 }
765 (share / chance >= PERIOD_LIFT_FLOOR).then_some(lag)
766}
767
768#[must_use]
790pub fn unit_record_period(units: &[crate::supertoken::SuperToken]) -> Option<u16> {
791 let symbols = unit_symbols(units);
792 if symbols.len() > 1 && symbols.iter().all(|s| *s == symbols[0]) {
799 return Some(1);
800 }
801 gated_lag(&symbols)
802}
803
804fn unit_symbols(units: &[crate::supertoken::SuperToken]) -> Vec<u32> {
811 units
812 .iter()
813 .map(|u| {
814 let len = u.end.saturating_sub(u.start).max(1);
815 u.role.code() * 8 + len.ilog2().min(7)
816 })
817 .collect()
818}
819
820fn period_symbols(toks: &[Token], bytes: &[u8]) -> Vec<u32> {
822 toks.iter()
823 .filter(|t| t.is_significant())
824 .map(|t| crate::shape::shape_class(t.kind, &bytes[t.span()]))
825 .collect()
826}
827
828fn best_lag(symbols: &[u32]) -> Option<(u16, f32)> {
839 let n = symbols.len();
840 let mut best: Option<(u16, f32)> = None;
841 for lag in 2..=usize::from(PHASE_MAX_PERIOD) {
842 if lag * 2 > n {
843 break;
844 }
845 let matches = symbols.iter().zip(&symbols[lag..]).filter(|(a, b)| a == b).count();
846 let share = matches as f32 / (n - lag) as f32;
847 if share >= crate::spectral::PERIOD_FLOOR && best.is_none_or(|(_, b)| share > b) {
848 best = Some((lag as u16, share));
849 }
850 }
851 best
852}
853
854fn chance_of(symbols: &[u32]) -> f32 {
857 let n = symbols.len();
858 if n == 0 {
859 return 0.0;
860 }
861 let mut sorted = symbols.to_vec();
862 sorted.sort_unstable();
863 let mut chance = 0.0f64;
864 let mut run = 0usize;
865 for i in 0..n {
866 run += 1;
867 if i + 1 == n || sorted[i] != sorted[i + 1] {
868 let p = run as f64 / n as f64;
869 chance += p * p;
870 run = 0;
871 }
872 }
873 chance as f32
874}
875
876#[must_use]
890pub fn record_period_share(toks: &[Token], bytes: &[u8]) -> Option<(u16, f32)> {
891 best_lag(&period_symbols(toks, bytes))
892}
893
894#[must_use]
905pub fn record_period_chance(toks: &[Token], bytes: &[u8]) -> f32 {
906 chance_of(&period_symbols(toks, bytes))
907}
908
909#[must_use]
923pub fn record_period_profile(toks: &[Token], bytes: &[u8]) -> (f32, Vec<(u16, f32)>) {
924 period_profile_of(&period_symbols(toks, bytes))
925}
926
927#[must_use]
932pub fn live_periods(toks: &[Token], bytes: &[u8]) -> Vec<u16> {
933 live_lags(&period_symbols(toks, bytes))
934}
935
936fn live_lags(symbols: &[u32]) -> Vec<u16> {
937 let (chance, profile) = period_profile_of(symbols);
938 let mut live: Vec<(u16, f32)> = profile
939 .into_iter()
940 .filter(|&(_, share)| {
941 share >= crate::spectral::PERIOD_FLOOR && (chance <= 0.0 || share / chance >= PERIOD_LIFT_FLOOR)
942 })
943 .collect();
944 live.sort_by(|a, b| b.1.total_cmp(&a.1).then(a.0.cmp(&b.0)));
945 live.into_iter().map(|(lag, _)| lag).collect()
946}
947
948#[must_use]
960pub fn period_profile_of(symbols: &[u32]) -> (f32, Vec<(u16, f32)>) {
961 let n = symbols.len();
962 let mut out = Vec::new();
963 for lag in 2..=usize::from(PHASE_MAX_PERIOD) {
964 if lag * 2 > n {
965 break;
966 }
967 let matches = symbols.iter().zip(&symbols[lag..]).filter(|(a, b)| a == b).count();
968 out.push((lag as u16, matches as f32 / (n - lag) as f32));
969 }
970 (chance_of(symbols), out)
971}
972
973#[must_use]
977pub fn analyze(bytes: &[u8]) -> ContextField {
978 analyze_with(bytes, &ContextConfig::default())
979}
980
981#[must_use]
983pub fn analyze_with(bytes: &[u8], cfg: &ContextConfig) -> ContextField {
984 let toks = crate::lexer::lex(bytes);
985 let spectral = crate::spectral::analyze(bytes);
986 let stress = crate::stress::analyze(&toks, bytes);
987 let echo = crate::echo::analyze(&toks, bytes);
988 let observation = crate::observation::analyze(bytes);
995 let seam_field = crate::seam::analyze(bytes);
996 let flow = crate::flow::analyze(&toks, bytes, crate::flow::Signal::Magnitude);
1000 let ctx = AxisCtx {
1001 spectral: Some(&spectral),
1002 stress: Some(&stress),
1003 echo: Some(&echo),
1004 observation: Some(&observation),
1005 seam: Some(&seam_field),
1006 flow: Some(&flow),
1007 ..AxisCtx::new(bytes)
1008 };
1009 let supers = SuperContext::build(&toks, bytes);
1010 let mut field = fold_windows_parallel(&toks, &ctx, &supers, cfg);
1011 let shape = crate::shape::analyze(&toks, bytes);
1012 let seam_cuts = crate::seam::analyze_tokens(&toks, &crate::seam::SeamConfig::default());
1013 field.agreement =
1014 agreement(&supers.units, &toks, &spectral.boundaries, &shape.boundaries, &seam_cuts);
1015 field
1016}
1017
1018#[cfg(test)]
1019mod tests {
1020 use super::*;
1021 use crate::profile::fold_tokens;
1022
1023 #[test]
1024 fn two_row_shapes_are_both_live_and_the_first_live_period_is_the_record_period() {
1025 let text = format!("{}{}", "k = 1 ;\n".repeat(150), "k = 1 , 2 ;\n".repeat(150));
1026 let toks = crate::lexer::lex(text.as_bytes());
1027 let live = live_periods(&toks, text.as_bytes());
1028 assert!(live.contains(&4) && live.contains(&6), "both row shapes repeat: {live:?}");
1029 assert_eq!(live.first().copied(), record_period(&toks, text.as_bytes()), "{live:?}");
1030 let prose = "the cat sat on a mat while it rained and then it stopped\n".repeat(3);
1031 let toks = crate::lexer::lex(prose.as_bytes());
1032 assert_eq!(live_periods(&toks, prose.as_bytes()).first().copied(), record_period(&toks, prose.as_bytes()));
1033 }
1034
1035 fn close(a: f32, b: f32) -> bool {
1036 (a - b).abs() <= 1e-4 * a.abs().max(b.abs()).max(1.0)
1037 }
1038
1039 fn same_reading(a: &WindowProfile, b: &WindowProfile) -> bool {
1040 close(a.magnitude.sum, b.magnitude.sum)
1041 && close(a.magnitude.sumsq, b.magnitude.sumsq)
1042 && a.magnitude.max == b.magnitude.max
1043 && a.magnitude.count == b.magnitude.count
1044 && a.stress == b.stress
1045 && close(a.spectral.entropy_sum, b.spectral.entropy_sum)
1046 && a.spectral.count == b.spectral.count
1047 && a.spectral.period == b.spectral.period
1048 && a.echo == b.echo
1049 && close(a.observation.anticausal_sum, b.observation.anticausal_sum)
1050 && a.observation.count == b.observation.count
1051 && close(a.seam.fwd_sum, b.seam.fwd_sum)
1052 && a.seam.cuts == b.seam.cuts
1053 && a.flow.reversals == b.flow.reversals
1054 && a.flow.count == b.flow.count
1055 }
1056
1057 #[test]
1062 fn the_rolling_context_reads_the_fields_it_builds() {
1063 let bytes = corpus(120);
1064 let field = analyze(&bytes);
1065 assert!(!field.at_token.is_empty(), "the corpus folds to something");
1066
1067 let any = |f: fn(&WindowProfile) -> bool| field.at_token.iter().any(f);
1068 assert!(any(|w| w.observation.anticausal_sum > 0.0), "the future vantage arrived");
1069 assert!(any(|w| w.observation.centered_sum > 0.0), "the centered vantage arrived");
1070 assert!(any(|w| w.seam.fwd_sum > 0.0), "the boundary-after signal arrived");
1071 assert!(any(|w| w.seam.cuts > 0), "the stream is cut somewhere");
1072 assert!(any(|w| w.flow.count > 0), "the dynamics reading arrived");
1073
1074 assert!(!field.at_unit.is_empty(), "the corpus has units");
1076 assert!(
1077 field.at_unit.iter().any(|u| u.observation.anticausal_sum > 0.0),
1078 "the future vantage reaches the unit rung, not only the token one"
1079 );
1080 }
1081
1082 fn corpus(statements: usize) -> Vec<u8> {
1083 let mut s = String::new();
1084 for i in 0..statements {
1085 match i % 4 {
1086 0 => s.push_str(&format!("let value_{i} = {} ;\n", i * 37)),
1087 1 => s.push_str(&format!("call_{i}(alpha, beta, {i}) ;\n")),
1088 2 => s.push_str(&format!("key_{i}: item_{i}, item_{}, item_{} ;\n", i + 1, i + 2)),
1089 _ => s.push_str(&format!("if (cond_{i}) {{ do_{i}(x) ; }}\n")),
1090 }
1091 }
1092 s.into_bytes()
1093 }
1094
1095 #[test]
1096 fn the_window_fold_is_the_direct_fold_at_every_position() {
1097 let bytes = corpus(60);
1098 let toks = crate::lexer::lex(&bytes);
1099 let spectral = crate::spectral::analyze(&bytes);
1100 let stress = crate::stress::analyze(&toks, &bytes);
1101 let echo = crate::echo::analyze(&toks, &bytes);
1102 let ctx =
1103 AxisCtx {
1104 spectral: Some(&spectral),
1105 stress: Some(&stress),
1106 echo: Some(&echo),
1107 ..AxisCtx::new(&bytes)
1108 };
1109 let supers = SuperContext::build(&toks, &bytes);
1110 for w in [1usize, 2, 3, 7, 32, 1000] {
1111 let cfg = ContextConfig { token_window: w, unit_window: 3 };
1112 let field = fold_windows(&toks, &ctx, &supers, &cfg);
1113 let sig: Vec<usize> = (0..toks.len()).filter(|&i| toks[i].is_significant()).collect();
1114 for (k, &i) in sig.iter().enumerate() {
1115 let lo = k + 1 - w.min(k + 1);
1116 let direct = sig[lo..=k].iter().fold(WindowProfile::identity(), |acc, &j| {
1118 acc.combine(&WindowProfile::of_token(j, &toks[j], &ctx))
1119 });
1120 assert!(
1121 same_reading(&field.at_token[i], &direct),
1122 "window {w} at token {i}: {:?} vs {:?}",
1123 field.at_token[i],
1124 direct
1125 );
1126 }
1127 }
1128 }
1129
1130 #[test]
1131 fn a_units_reading_is_the_fold_of_its_tokens_and_the_unit_window_folds_them() {
1132 let bytes = corpus(40);
1133 let toks = crate::lexer::lex(&bytes);
1134 let ctx = AxisCtx::new(&bytes);
1135 let supers = SuperContext::build(&toks, &bytes);
1136 let cfg = ContextConfig { token_window: 8, unit_window: 3 };
1137 let field = fold_windows(&toks, &ctx, &supers, &cfg);
1138 assert_eq!(field.of_unit.len(), supers.units.len());
1139 for (u, unit) in supers.units.iter().enumerate() {
1140 let members: Vec<Token> = toks
1141 .iter()
1142 .enumerate()
1143 .filter(|(i, t)| t.is_significant() && supers.index_of(*i) == Some(u))
1144 .map(|(_, t)| *t)
1145 .collect();
1146 assert!(!members.is_empty(), "unit {u} {unit:?} holds tokens");
1147 let direct: WindowProfile = fold_tokens(0, &members, &ctx);
1148 assert!(same_reading(&field.of_unit[u], &direct), "unit {u}");
1151 let lo = u + 1 - cfg.unit_window.min(u + 1);
1152 let windowed = crate::profile::fold_profiles(&field.of_unit[lo..=u]);
1153 assert!(same_reading(&field.at_unit[u], &windowed), "unit window at {u}");
1154 }
1155 }
1156
1157 #[test]
1158 fn the_window_profile_is_a_monoid() {
1159 let bytes = b"alpha 12 (beta 3456) gamma alpha";
1160 let toks = crate::lexer::lex(bytes);
1161 let ctx = AxisCtx::new(bytes);
1162 let a = WindowProfile::of_token(0, &toks[0], &ctx);
1163 let b = WindowProfile::of_token(2, &toks[2], &ctx);
1164 let c = WindowProfile::of_token(4, &toks[4], &ctx);
1165 assert_eq!(WindowProfile::identity().combine(&a), a);
1166 assert_eq!(a.combine(&WindowProfile::identity()), a);
1167 assert!(same_reading(&a.combine(&b).combine(&c), &a.combine(&b.combine(&c))));
1168 }
1169
1170 #[test]
1171 fn the_grains_agree_on_structure_and_not_on_a_shuffled_stream() {
1172 let bytes = corpus(400);
1178 let real = analyze(&bytes);
1179 let toks = crate::lexer::lex(&bytes);
1180 let mut sig: Vec<&[u8]> = toks
1181 .iter()
1182 .filter(|t| t.is_significant())
1183 .map(|t| &bytes[t.span()])
1184 .collect();
1185 let mut x = 0x9e37_79b9_7f4a_7c15u64;
1186 for i in (1..sig.len()).rev() {
1187 x = x.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1_442_695_040_888_963_407);
1188 sig.swap(i, (x >> 33) as usize % (i + 1));
1189 }
1190 let shuffled: Vec<u8> = sig.join(&b' ');
1191 let null = analyze(&shuffled);
1192 let (_, _, r_seam) = real.alignment();
1193 let (_, _, n_seam) = null.alignment();
1194 assert!(real.agreement.len() > 100 && null.agreement.len() > 100, "enough units on both");
1195 assert!(
1203 r_seam > n_seam * 1.5 && r_seam > 0.6,
1204 "seam offset concentration by role: real {r_seam:.3} vs shuffled {n_seam:.3}"
1205 );
1206 }
1207
1208 #[test]
1209 fn the_parallel_fold_reads_what_the_serial_fold_reads() {
1210 let bytes = corpus(3000);
1212 let toks = crate::lexer::lex(&bytes);
1213 let spectral = crate::spectral::analyze(&bytes);
1214 let stress = crate::stress::analyze(&toks, &bytes);
1215 let echo = crate::echo::analyze(&toks, &bytes);
1216 let ctx =
1217 AxisCtx {
1218 spectral: Some(&spectral),
1219 stress: Some(&stress),
1220 echo: Some(&echo),
1221 ..AxisCtx::new(&bytes)
1222 };
1223 let supers = SuperContext::build(&toks, &bytes);
1224 let cfg = ContextConfig::default();
1225 let serial = fold_windows(&toks, &ctx, &supers, &cfg);
1226 let parallel = fold_windows_parallel(&toks, &ctx, &supers, &cfg);
1227 assert_eq!(parallel.at_token.len(), serial.at_token.len());
1228 assert_eq!(parallel.of_unit.len(), serial.of_unit.len());
1229 assert_eq!(parallel.at_unit.len(), serial.at_unit.len());
1230 for (i, (p, s)) in parallel.at_token.iter().zip(&serial.at_token).enumerate() {
1231 assert!(same_reading(p, s), "token {i}: {p:?} vs {s:?}");
1232 }
1233 for (u, (p, s)) in parallel.of_unit.iter().zip(&serial.of_unit).enumerate() {
1234 assert!(same_reading(p, s), "unit {u}");
1235 }
1236 for (u, (p, s)) in parallel.at_unit.iter().zip(&serial.at_unit).enumerate() {
1237 assert!(same_reading(p, s), "unit window {u}");
1238 }
1239 }
1240
1241 #[test]
1242 fn each_relation_fold_is_the_direct_fold_over_what_the_relation_names() {
1243 let bytes = corpus(300);
1244 let toks = crate::lexer::lex(&bytes);
1245 let spectral = crate::spectral::analyze(&bytes);
1246 let stress = crate::stress::analyze(&toks, &bytes);
1247 let echo = crate::echo::analyze(&toks, &bytes);
1248 let ctx =
1249 AxisCtx {
1250 spectral: Some(&spectral),
1251 stress: Some(&stress),
1252 echo: Some(&echo),
1253 ..AxisCtx::new(&bytes)
1254 };
1255 let period = record_period(&toks, &bytes);
1259 assert_eq!(period, None, "no record repeats within the search");
1260 let rel = relate(&toks, &ctx, &spectral.boundaries, &echo, period);
1261 let relation = crate::relation::analyze(&toks, &bytes);
1262 let reading = |i: usize| WindowProfile::of_token(i, &toks[i], &ctx);
1263 let fold = |ix: &[usize]| ix.iter().fold(WindowProfile::identity(), |a, &j| a.combine(&reading(j)));
1264 let sig: Vec<usize> = (0..toks.len()).filter(|&i| toks[i].is_significant()).collect();
1265 let mut echoes_seen = 0usize;
1266 let mut enclosed_seen = 0usize;
1267 for (k, &i) in sig.iter().enumerate() {
1268 let r = &rel.at_token[i];
1269 let heads = &relation.frames[i].enclosure;
1271 if !heads.is_empty() {
1272 enclosed_seen += 1;
1273 }
1274 assert!(same_reading(&r.enclosing, &fold(heads)), "enclosure at {i}");
1275 let text = &bytes[toks[i].span()];
1277 let earlier: Vec<usize> = sig[..k]
1278 .iter()
1279 .copied()
1280 .filter(|&j| echo.frames[j].keyed && &bytes[toks[j].span()] == text)
1281 .collect();
1282 if echo.frames[i].keyed {
1283 if !earlier.is_empty() {
1284 echoes_seen += 1;
1285 }
1286 assert!(same_reading(&r.echoing, &fold(&earlier)), "echo at {i}");
1287 }
1288 let cut = spectral.boundaries.partition_point(|&c| c <= toks[i].start());
1290 let since = cut.checked_sub(1).map_or(0, |c| spectral.boundaries[c]);
1291 let members: Vec<usize> =
1292 sig[..k].iter().copied().filter(|&j| toks[j].start() >= since).collect();
1293 assert!(same_reading(&r.regime, &fold(&members)), "regime at {i}");
1294 assert_eq!(r.phase, WindowProfile::identity(), "no period, no phase fold at {i}");
1295 assert_eq!(rel.phase_of[i], u16::MAX, "no period, no phase at {i}");
1296 }
1297 assert!(echoes_seen > 100 && enclosed_seen > 100, "the relations were exercised");
1298 }
1299
1300 #[test]
1301 fn the_phase_fold_is_the_direct_fold_over_the_column() {
1302 let mut rows = String::new();
1304 for i in 0..300 {
1305 rows.push_str(&format!("r{i} , {} , x{} ;\n", i * 3, i % 4));
1306 }
1307 let bytes = rows.as_bytes();
1308 let toks = crate::lexer::lex(bytes);
1309 let period = record_period(&toks, bytes);
1310 assert_eq!(period, Some(6), "the row is the period");
1311 let echo = crate::echo::analyze(&toks, bytes);
1312 let ctx = AxisCtx::new(bytes);
1313 let rel = relate(&toks, &ctx, &[], &echo, period);
1314 let reading = |i: usize| WindowProfile::of_token(i, &toks[i], &ctx);
1315 let sig: Vec<usize> = (0..toks.len()).filter(|&i| toks[i].is_significant()).collect();
1316 for (k, &i) in sig.iter().enumerate() {
1317 let same_phase = (0..k).filter(|&m| m % 6 == k % 6).map(|m| sig[m]).fold(
1318 WindowProfile::identity(),
1319 |a, j| a.combine(&reading(j)),
1320 );
1321 assert!(same_reading(&rel.at_token[i].phase, &same_phase), "phase fold at {i}");
1322 assert_eq!(rel.phase_of[i], (k % 6) as u16, "phase at {i}");
1323 }
1324 }
1325
1326 fn log_corpus(lines: usize) -> Vec<u8> {
1329 let mut s = String::new();
1330 for i in 0..lines {
1331 match i % 3 {
1332 0 => s.push_str(&format!("svc_{} latency = {} ms ;\n", i % 7, 90 + (i * 37) % 21)),
1333 1 => s.push_str(&format!("svc_{} size = {} ;\n", i % 7, 1_000_000 + i)),
1334 _ => s.push_str(&format!("state: {} ;\n", if i % 2 == 0 { "ready" } else { "busy" })),
1335 }
1336 }
1337 s.into_bytes()
1338 }
1339
1340 #[test]
1341 fn the_value_history_is_the_fold_over_what_earlier_occurrences_bound() {
1342 let bytes = log_corpus(200);
1343 let toks = crate::lexer::lex(&bytes);
1344 let echo = crate::echo::analyze(&toks, &bytes);
1345 let ctx = AxisCtx::new(&bytes);
1346 let rel = relate(&toks, &ctx, &[], &echo, None);
1347 let reading = |i: usize| WindowProfile::of_token(i, &toks[i], &ctx);
1348 let next_sig = |i: usize| (i + 1..toks.len()).find(|&j| toks[j].is_significant());
1349 let bound_by = |j: usize| -> Option<usize> {
1352 let op = next_sig(j)?;
1353 let t = &toks[op];
1354 (t.kind == crate::token::TokenKind::Punct && matches!(&bytes[t.span()], b"=" | b":"))
1355 .then(|| next_sig(op))
1356 .flatten()
1357 };
1358 let mut histories_seen = 0usize;
1359 for i in 0..toks.len() {
1360 if !echo.frames[i].keyed {
1361 continue;
1362 }
1363 let text = &bytes[toks[i].span()];
1364 let values: Vec<usize> = (0..i)
1365 .filter(|&j| echo.frames[j].keyed && &bytes[toks[j].span()] == text)
1366 .filter_map(bound_by)
1367 .collect();
1368 if !values.is_empty() {
1369 histories_seen += 1;
1370 }
1371 let direct = values.iter().fold(WindowProfile::identity(), |a, &v| a.combine(&reading(v)));
1372 assert!(same_reading(&rel.value_history[i], &direct), "value history at {i}");
1373 }
1374 assert!(histories_seen > 100, "keys were bound more than once: {histories_seen}");
1375 }
1376
1377 #[test]
1378 fn a_window_of_one_reads_the_token_alone() {
1379 let bytes = b"alpha 12 beta 3456";
1380 let toks = crate::lexer::lex(bytes);
1381 let ctx = AxisCtx::new(bytes);
1382 let supers = SuperContext::build(&toks, bytes);
1383 let field = fold_windows(&toks, &ctx, &supers, &ContextConfig { token_window: 1, unit_window: 1 });
1384 for (i, t) in toks.iter().enumerate() {
1385 if t.is_significant() {
1386 assert_eq!(field.at_token[i].magnitude.count, 1, "token {i}");
1387 }
1388 }
1389 assert_eq!(field.at_token[1], field.at_token[0]);
1391 }
1392}