File size: 5,519 Bytes
224e773 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | use hyperkitty_core::Glyph;
use hyperkitty_qra::next_glyph;
/// Result of QRA tensor dispatch
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QRADispatchResult {
pub current: Glyph,
pub previous: Glyph,
pub next: Glyph,
pub is_absorber: bool,
pub is_valid: bool,
}
impl QRADispatchResult {
pub fn new(current: Glyph, previous: Glyph) -> Self {
let next = next_glyph(current, previous);
let is_absorber = next.is_absorber();
let is_valid = true;
QRADispatchResult {
current,
previous,
next,
is_absorber,
is_valid,
}
}
}
/// QRA Dispatcher — deterministic routing via Q[current][previous]
pub struct QRADispatcher;
impl QRADispatcher {
/// Dispatch via QRA tensor lookup
/// Returns next glyph deterministically from Q[current][previous]
pub fn dispatch(current: Glyph, previous: Glyph) -> hyperkitty_core::Result<QRADispatchResult> {
if !Self::is_valid_pair(current, previous) {
return Err(hyperkitty_core::Error::ParseError(
format!("invalid glyph pair: {:?}, {:?}", current, previous),
));
}
Ok(QRADispatchResult::new(current, previous))
}
/// Batch dispatch multiple (current, previous) pairs
pub fn dispatch_batch(
pairs: Vec<(Glyph, Glyph)>,
) -> hyperkitty_core::Result<Vec<QRADispatchResult>> {
if pairs.is_empty() {
return Err(hyperkitty_core::Error::NoValidRoutes);
}
let mut results = Vec::new();
for (current, previous) in pairs {
if Self::is_valid_pair(current, previous) {
results.push(QRADispatchResult::new(current, previous));
}
}
if results.is_empty() {
return Err(hyperkitty_core::Error::ParseError(
"no valid glyph pairs".to_string(),
));
}
Ok(results)
}
/// Validate that a (current, previous) pair can be dispatched
fn is_valid_pair(current: Glyph, _previous: Glyph) -> bool {
// Valid glyph indices are 0-5
current.index() < 6
}
/// Route to convergence — evolve until absorber state reached
/// Returns sequence of states
pub fn route_to_convergence(start: Glyph) -> hyperkitty_core::Result<Vec<Glyph>> {
let mut states = vec![start];
let mut current = start;
let mut previous = Glyph::Lambda; // identity
// Limit iterations to detect cycles
const MAX_ITERATIONS: usize = 100;
for _ in 0..MAX_ITERATIONS {
if current.is_absorber() {
break;
}
let result = Self::dispatch(current, previous)?;
states.push(result.next);
previous = current;
current = result.next;
}
Ok(states)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_qra_dispatch_pi_gamma() {
let result = QRADispatcher::dispatch(Glyph::Pi, Glyph::Gamma);
assert!(result.is_ok());
let disp = result.unwrap();
assert_eq!(disp.current, Glyph::Pi);
assert_eq!(disp.previous, Glyph::Gamma);
assert!(disp.is_valid);
}
#[test]
fn test_qra_dispatch_deterministic() {
let r1 = QRADispatcher::dispatch(Glyph::Delta, Glyph::Pi).unwrap();
let r2 = QRADispatcher::dispatch(Glyph::Delta, Glyph::Pi).unwrap();
assert_eq!(r1.next, r2.next);
}
#[test]
fn test_qra_dispatch_all_valid_pairs() {
for c in Glyph::all() {
for p in Glyph::all() {
let result = QRADispatcher::dispatch(c, p);
assert!(result.is_ok());
}
}
}
#[test]
fn test_qra_dispatch_batch() {
let pairs = vec![
(Glyph::Pi, Glyph::Gamma),
(Glyph::Gamma, Glyph::Delta),
(Glyph::Delta, Glyph::Omega),
];
let result = QRADispatcher::dispatch_batch(pairs);
assert!(result.is_ok());
let results = result.unwrap();
assert_eq!(results.len(), 3);
}
#[test]
fn test_qra_dispatch_batch_empty() {
let result = QRADispatcher::dispatch_batch(vec![]);
assert!(result.is_err());
}
#[test]
fn test_qra_route_to_convergence_pi_gamma_delta() {
let result = QRADispatcher::route_to_convergence(Glyph::Pi);
assert!(result.is_ok());
let states = result.unwrap();
assert!(!states.is_empty());
assert_eq!(states[0], Glyph::Pi);
// Should converge to absorber (Omega)
assert!(states.last().unwrap().is_absorber());
}
#[test]
fn test_qra_identity_law() {
// Q[Lambda][j] = j for all j
let lambda = Glyph::Lambda;
for j in Glyph::all() {
let result = QRADispatcher::dispatch(lambda, j).unwrap();
// Identity row returns the previous glyph
assert_eq!(result.next, j);
}
}
#[test]
fn test_qra_absorber_law() {
// Q[Omega][j] = Omega for all j
let omega = Glyph::Omega;
for j in Glyph::all() {
let result = QRADispatcher::dispatch(omega, j).unwrap();
assert!(result.next.is_absorber());
}
}
#[test]
fn test_qra_dispatch_result_valid() {
let result = QRADispatcher::dispatch(Glyph::Pi, Glyph::Gamma).unwrap();
assert!(result.is_valid);
}
}
|