1use crate::solvers::linear_algebra::{FixedLanczosEigensolver, Matrix4x4, Vector4};
2use crate::solvers::{SolverConfig, SolverResult, SolverState, SolversError};
3use crate::{q_hash, NQuin};
4
5pub const MANIFOLD_HEAD_PREDICATE: u64 = q_hash("q42:manifold10d:head");
6pub const MANIFOLD_TAIL_PREDICATE: u64 = q_hash("q42:manifold10d:tail");
7pub const MANIFOLD_THRESHOLD_HOLDS: u64 = q_hash("q42:manifold10d:threshold-holds");
8pub const MANIFOLD_THRESHOLD_MISS: u64 = q_hash("q42:manifold10d:threshold-miss");
9
10pub const MANIFOLD_ATOM_COHERENT: u64 = q_hash("q42:manifold10d:coherent");
11pub const MANIFOLD_ATOM_RECURRENT: u64 = q_hash("q42:manifold10d:recurrent");
12pub const MANIFOLD_ATOM_DENSE: u64 = q_hash("q42:manifold10d:dense");
13pub const MANIFOLD_ATOM_CURVED: u64 = q_hash("q42:manifold10d:curved");
14pub const MANIFOLD_ATOM_STABLE: u64 = q_hash("q42:manifold10d:stable-topology");
15pub const MANIFOLD_ASP_ATOMS: [u64; 5] = [
16 MANIFOLD_ATOM_COHERENT,
17 MANIFOLD_ATOM_RECURRENT,
18 MANIFOLD_ATOM_DENSE,
19 MANIFOLD_ATOM_CURVED,
20 MANIFOLD_ATOM_STABLE,
21];
22
23#[repr(C)]
27#[derive(Clone, Copy, Debug, Default, PartialEq)]
28pub struct ManifoldCoordinate10D {
29 pub scale: f32,
30 pub attention_depth: f32,
31 pub epistemic_weight: f32,
32 pub topological_spin: f32,
33 pub temporal_decay: f32,
34 pub entropy_bias: f32,
35 pub spatial_phase: f32,
36 pub recurrence_frequency: f32,
37 pub density_threshold: f32,
38 pub manifold_curvature: f32,
39}
40
41impl ManifoldCoordinate10D {
42 pub const DIMENSIONS: usize = 10;
43
44 pub fn as_f32_array(&self) -> [f32; Self::DIMENSIONS] {
46 [
47 self.scale,
48 self.attention_depth,
49 self.epistemic_weight,
50 self.topological_spin,
51 self.temporal_decay,
52 self.entropy_bias,
53 self.spatial_phase,
54 self.recurrence_frequency,
55 self.density_threshold,
56 self.manifold_curvature,
57 ]
58 }
59
60 pub fn from_p64_bytes(bytes: &[u8]) -> Result<Self, String> {
62 if bytes.len() < 40 {
63 return Err("p64: truncated 10D manifold coordinate".to_string());
64 }
65 let value = |index: usize| {
66 let start = index * 4;
67 f32::from_le_bytes(bytes[start..start + 4].try_into().unwrap())
68 };
69 let coordinate = Self {
70 scale: value(0),
71 attention_depth: value(1),
72 epistemic_weight: value(2),
73 topological_spin: value(3),
74 temporal_decay: value(4),
75 entropy_bias: value(5),
76 spatial_phase: value(6),
77 recurrence_frequency: value(7),
78 density_threshold: value(8),
79 manifold_curvature: value(9),
80 };
81 if coordinate
82 .as_f32_array()
83 .iter()
84 .any(|value| !value.is_finite())
85 {
86 return Err("p64: non-finite 10D manifold coordinate".to_string());
87 }
88 Ok(coordinate)
89 }
90
91 pub fn as_array(&self) -> [f64; 10] {
93 [
94 self.scale as f64,
95 self.attention_depth as f64,
96 self.epistemic_weight as f64,
97 self.topological_spin as f64,
98 self.temporal_decay as f64,
99 self.entropy_bias as f64,
100 self.spatial_phase as f64,
101 self.recurrence_frequency as f64,
102 self.density_threshold as f64,
103 self.manifold_curvature as f64,
104 ]
105 }
106
107 pub fn from_sequential_layer(layer: u32, total_layers: u32) -> Self {
109 let max_l = total_layers.max(1) as f32;
110 let l = layer as f32;
111 let depth = l / max_l;
112 Self {
113 scale: depth,
114 attention_depth: 1.0 - depth,
115 epistemic_weight: 1.0,
116 topological_spin: (depth * std::f32::consts::PI).sin(),
117 temporal_decay: 0.1,
118 entropy_bias: 0.5,
119 spatial_phase: (depth * std::f32::consts::TAU).cos(),
120 recurrence_frequency: 1.0,
121 density_threshold: 0.8,
122 manifold_curvature: 0.0,
123 }
124 }
125}
126
127#[repr(u8)]
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum ManifoldDimension {
130 Scale = 0,
131 AttentionDepth = 1,
132 EpistemicWeight = 2,
133 TopologicalSpin = 3,
134 TemporalDecay = 4,
135 EntropyBias = 5,
136 SpatialPhase = 6,
137 RecurrenceFrequency = 7,
138 DensityThreshold = 8,
139 ManifoldCurvature = 9,
140}
141
142impl ManifoldDimension {
143 pub fn from_u8(value: u8) -> Option<Self> {
144 Some(match value {
145 0 => Self::Scale,
146 1 => Self::AttentionDepth,
147 2 => Self::EpistemicWeight,
148 3 => Self::TopologicalSpin,
149 4 => Self::TemporalDecay,
150 5 => Self::EntropyBias,
151 6 => Self::SpatialPhase,
152 7 => Self::RecurrenceFrequency,
153 8 => Self::DensityThreshold,
154 9 => Self::ManifoldCurvature,
155 _ => return None,
156 })
157 }
158
159 pub fn value(self, coordinate: &ManifoldCoordinate10D) -> f32 {
160 coordinate.as_f32_array()[self as usize]
161 }
162}
163
164#[repr(C)]
165#[derive(Clone, Copy, Debug, Default, PartialEq)]
166pub struct ManifoldState10D {
167 pub state_id: u64,
169 pub timestamp: u64,
170 pub coordinate: ManifoldCoordinate10D,
171}
172
173#[inline]
174fn pack_f32_pair(low: f32, high: f32) -> u64 {
175 low.to_bits() as u64 | ((high.to_bits() as u64) << 32)
176}
177
178#[inline]
179fn unpack_f32_pair(value: u64) -> (f32, f32) {
180 (
181 f32::from_bits(value as u32),
182 f32::from_bits((value >> 32) as u32),
183 )
184}
185
186#[inline]
187fn quin_with_parity(
188 subject: u64,
189 predicate: u64,
190 object: u64,
191 context: u64,
192 metadata: u64,
193) -> NQuin {
194 NQuin {
195 subject,
196 predicate,
197 object,
198 context,
199 metadata,
200 parity: subject ^ predicate ^ object ^ context,
201 }
202}
203
204pub fn encode_manifold_state(state: &ManifoldState10D, out: &mut [NQuin; 2]) {
212 let d = state.coordinate.as_f32_array();
213 out[0] = quin_with_parity(
214 state.state_id,
215 MANIFOLD_HEAD_PREDICATE,
216 pack_f32_pair(d[0], d[1]),
217 pack_f32_pair(d[2], d[3]),
218 pack_f32_pair(d[4], d[5]),
219 );
220 out[1] = quin_with_parity(
221 state.state_id,
222 MANIFOLD_TAIL_PREDICATE,
223 pack_f32_pair(d[6], d[7]),
224 pack_f32_pair(d[8], d[9]),
225 state.timestamp,
226 );
227}
228
229pub fn decode_manifold_state(head: &NQuin, tail: &NQuin) -> Option<ManifoldState10D> {
230 if head.subject != tail.subject
231 || head.predicate != MANIFOLD_HEAD_PREDICATE
232 || tail.predicate != MANIFOLD_TAIL_PREDICATE
233 || head.parity != head.subject ^ head.predicate ^ head.object ^ head.context
234 || tail.parity != tail.subject ^ tail.predicate ^ tail.object ^ tail.context
235 {
236 return None;
237 }
238 let (d0, d1) = unpack_f32_pair(head.object);
239 let (d2, d3) = unpack_f32_pair(head.context);
240 let (d4, d5) = unpack_f32_pair(head.metadata);
241 let (d6, d7) = unpack_f32_pair(tail.object);
242 let (d8, d9) = unpack_f32_pair(tail.context);
243 let coordinate = ManifoldCoordinate10D {
244 scale: d0,
245 attention_depth: d1,
246 epistemic_weight: d2,
247 topological_spin: d3,
248 temporal_decay: d4,
249 entropy_bias: d5,
250 spatial_phase: d6,
251 recurrence_frequency: d7,
252 density_threshold: d8,
253 manifold_curvature: d9,
254 };
255 if coordinate
256 .as_f32_array()
257 .iter()
258 .any(|value| !value.is_finite())
259 {
260 return None;
261 }
262 Some(ManifoldState10D {
263 state_id: head.subject,
264 timestamp: tail.metadata,
265 coordinate,
266 })
267}
268
269pub fn collect_manifold_states(quins: &[NQuin], out: &mut [ManifoldState10D]) -> usize {
272 let mut count = 0usize;
273 for head in quins {
274 if head.predicate != MANIFOLD_HEAD_PREDICATE || count == out.len() {
275 continue;
276 }
277 let Some(tail) = quins.iter().find(|candidate| {
278 candidate.subject == head.subject && candidate.predicate == MANIFOLD_TAIL_PREDICATE
279 }) else {
280 continue;
281 };
282 if let Some(state) = decode_manifold_state(head, tail) {
283 out[count] = state;
284 count += 1;
285 }
286 }
287 for index in 1..count {
289 let state = out[index];
290 let mut cursor = index;
291 while cursor > 0 && out[cursor - 1].timestamp > state.timestamp {
292 out[cursor] = out[cursor - 1];
293 cursor -= 1;
294 }
295 out[cursor] = state;
296 }
297 count
298}
299
300pub fn project_manifold_ltl_trace(
304 states: &[ManifoldState10D],
305 dimension: ManifoldDimension,
306 threshold: f32,
307 at_least: bool,
308 out: &mut [NQuin],
309) -> usize {
310 let count = states.len().min(out.len());
311 for (target, state) in out[..count].iter_mut().zip(states) {
312 let value = dimension.value(&state.coordinate);
313 let holds = if at_least {
314 value >= threshold
315 } else {
316 value <= threshold
317 };
318 *target = quin_with_parity(
319 state.state_id,
320 if holds {
321 MANIFOLD_THRESHOLD_HOLDS
322 } else {
323 MANIFOLD_THRESHOLD_MISS
324 },
325 value.to_bits() as u64,
326 dimension as u64,
327 state.timestamp,
328 );
329 }
330 count
331}
332
333pub fn evaluate_manifold_answer_sets(states: &[ManifoldState10D], out: &mut [u64]) -> usize {
336 use crate::modalities::asp::{compute_answer_sets, AspRule};
337
338 let mut facts = [false; 4];
339 for state in states {
340 let coordinate = &state.coordinate;
341 facts[0] |= coordinate.epistemic_weight >= coordinate.entropy_bias;
342 facts[1] |= coordinate.recurrence_frequency > coordinate.temporal_decay;
343 facts[2] |= coordinate.scale >= coordinate.density_threshold;
344 facts[3] |= coordinate.manifold_curvature.abs() > 0.25;
345 }
346
347 let mut rules = [AspRule::fact(0); 5];
348 let mut rule_count = 0usize;
349 for (present, atom) in facts.iter().zip(MANIFOLD_ASP_ATOMS.iter().take(4)) {
350 if *present {
351 rules[rule_count] = AspRule::fact(*atom);
352 rule_count += 1;
353 }
354 }
355 rules[rule_count] = AspRule::new(
357 MANIFOLD_ATOM_STABLE,
358 &[MANIFOLD_ATOM_COHERENT, MANIFOLD_ATOM_RECURRENT],
359 &[MANIFOLD_ATOM_CURVED],
360 );
361 rule_count += 1;
362 compute_answer_sets(&MANIFOLD_ASP_ATOMS, &rules[..rule_count], out)
363}
364
365pub fn project_10d_to_quaternion(parameters: &[f64; 10]) -> SolverResult<Vector4> {
368 let mut matrix = Matrix4x4::zero();
370 matrix.set(0, 0, parameters[0]);
371 matrix.set(0, 1, parameters[1]);
372 matrix.set(0, 2, parameters[2]);
373 matrix.set(0, 3, parameters[3]);
374
375 matrix.set(1, 0, parameters[1]);
376 matrix.set(1, 1, parameters[4]);
377 matrix.set(1, 2, parameters[5]);
378 matrix.set(1, 3, parameters[6]);
379
380 matrix.set(2, 0, parameters[2]);
381 matrix.set(2, 1, parameters[5]);
382 matrix.set(2, 2, parameters[7]);
383 matrix.set(2, 3, parameters[8]);
384
385 matrix.set(3, 0, parameters[3]);
386 matrix.set(3, 1, parameters[6]);
387 matrix.set(3, 2, parameters[8]);
388 matrix.set(3, 3, parameters[9]);
389
390 let mut solver = FixedLanczosEigensolver {
391 iteration: 0,
392 alpha: [0.0; 100],
393 beta: [0.0; 100],
394 vectors: [Vector4::zero(); 3],
395 eigenvalues: [0.0; 4],
396 config: SolverConfig::default(),
397 solver_state: SolverState::default(),
398 };
399
400 match solver.solve_smallest_eigenvector(&matrix) {
402 Ok(vec) => Ok(vec),
403 Err(e) => Err(e),
404 }
405}
406
407impl FixedLanczosEigensolver {
408 pub fn solve_smallest_eigenvector(&mut self, matrix: &Matrix4x4) -> SolverResult<Vector4> {
411 let mut v = Vector4 {
416 data: [1.0, 0.5, 0.25, 0.125],
417 };
418
419 let mut max_row_sum = 0.0;
420 for i in 0..4 {
421 let mut sum = 0.0;
422 for j in 0..4 {
423 sum += matrix.data[i][j].abs();
424 }
425 if sum > max_row_sum {
426 max_row_sum = sum;
427 }
428 }
429 let c = max_row_sum + 1.0; for _ in 0..self.config.max_iterations {
432 let mut shifted_matrix = Matrix4x4::zero();
433 for i in 0..4 {
434 for j in 0..4 {
435 if i == j {
436 shifted_matrix.set(i, j, c - matrix.get(i, j));
437 } else {
438 shifted_matrix.set(i, j, -matrix.get(i, j));
439 }
440 }
441 }
442
443 let mut next_v = shifted_matrix.multiply_vector(&v);
444
445 let norm = (next_v.data[0].powi(2)
447 + next_v.data[1].powi(2)
448 + next_v.data[2].powi(2)
449 + next_v.data[3].powi(2))
450 .sqrt();
451
452 if norm == 0.0 {
453 return Err(SolversError::SingularMatrix);
454 }
455
456 next_v.data[0] /= norm;
457 next_v.data[1] /= norm;
458 next_v.data[2] /= norm;
459 next_v.data[3] /= norm;
460
461 let mut diff = 0.0;
463 for i in 0..4 {
464 diff += (next_v.data[i] - v.data[i]).abs();
465 }
466
467 v = next_v;
468 self.iteration += 1;
469
470 if diff < self.config.tolerance {
471 self.solver_state.converged = true;
472 return Ok(v);
473 }
474 }
475
476 Err(SolversError::ConvergenceFailed)
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483 use crate::modalities::asp::atom_index;
484 use crate::modalities::temporal_ltl::{evaluate_ltl_trace, LtlFormula};
485
486 fn state(id: u64, timestamp: u64, scale: f32, curvature: f32) -> ManifoldState10D {
487 let mut coordinate = ManifoldCoordinate10D::from_sequential_layer(timestamp as u32, 10);
488 coordinate.scale = scale;
489 coordinate.density_threshold = 0.5;
490 coordinate.manifold_curvature = curvature;
491 ManifoldState10D {
492 state_id: id,
493 timestamp,
494 coordinate,
495 }
496 }
497
498 #[test]
499 fn two_quin_encoding_round_trips_and_sorts() {
500 let older = state(10, 1, 0.7, 0.0);
501 let newer = state(20, 2, 0.8, 0.0);
502 let mut older_pair = [NQuin::default(); 2];
503 let mut newer_pair = [NQuin::default(); 2];
504 encode_manifold_state(&older, &mut older_pair);
505 encode_manifold_state(&newer, &mut newer_pair);
506 assert_eq!(
507 decode_manifold_state(&older_pair[0], &older_pair[1]),
508 Some(older)
509 );
510
511 let arena_order = [newer_pair[1], older_pair[0], newer_pair[0], older_pair[1]];
512 let mut decoded = [ManifoldState10D::default(); 2];
513 let count = collect_manifold_states(&arena_order, &mut decoded);
514 assert_eq!(count, 2);
515 assert_eq!(decoded[0], older);
516 assert_eq!(decoded[1], newer);
517 }
518
519 #[test]
520 fn manifold_projection_drives_existing_ltl_evaluator() {
521 let states = [state(1, 1, 0.6, 0.0), state(2, 2, 0.9, 0.0)];
522 let mut trace = [NQuin::default(); 2];
523 let count =
524 project_manifold_ltl_trace(&states, ManifoldDimension::Scale, 0.5, true, &mut trace);
525 assert!(evaluate_ltl_trace(
526 &trace[..count],
527 &LtlFormula::Globally(MANIFOLD_THRESHOLD_HOLDS)
528 ));
529
530 let count =
531 project_manifold_ltl_trace(&states, ManifoldDimension::Scale, 0.8, true, &mut trace);
532 assert!(!evaluate_ltl_trace(
533 &trace[..count],
534 &LtlFormula::Globally(MANIFOLD_THRESHOLD_HOLDS)
535 ));
536 assert!(evaluate_ltl_trace(
537 &trace[..count],
538 &LtlFormula::Finally(MANIFOLD_THRESHOLD_HOLDS)
539 ));
540 }
541
542 #[test]
543 fn manifold_topology_drives_real_answer_set_semantics() {
544 let states = [state(1, 1, 0.7, 0.0), state(2, 2, 0.8, 0.0)];
545 let mut models = [0u64; 8];
546 let count = evaluate_manifold_answer_sets(&states, &mut models);
547 assert_eq!(count, 1);
548 let stable_index = atom_index(&MANIFOLD_ASP_ATOMS, MANIFOLD_ATOM_STABLE).unwrap();
549 assert_ne!(models[0] & (1u64 << stable_index), 0);
550
551 let curved = [state(3, 3, 0.8, 0.75)];
552 let count = evaluate_manifold_answer_sets(&curved, &mut models);
553 assert_eq!(count, 1);
554 assert_eq!(models[0] & (1u64 << stable_index), 0);
555 }
556}