Skip to main content

qualia_core_db/tensor/
q42_integration.rs

1//! Q42 volume integration for the 10D tensor system.
2//!
3//! This module keeps runtime tensor storage and query execution zero-heap by
4//! requiring callers to supply backing slices and output buffers.
5
6use core::ops::ControlFlow;
7
8use super::Tensor10D;
9use crate::NQuin;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum TensorVolumeError {
14    MismatchedStorage,
15    StorageCapacityExceeded,
16    OutputBufferFull,
17}
18
19/// Tensor metadata that can be stored alongside NQuin data.
20#[repr(C)]
21#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
22pub struct TensorMetadata {
23    /// 10D tensor coordinates for this NQuin.
24    pub tensor: Tensor10D,
25    /// Whether this NQuin has associated tensor data.
26    pub has_tensor: bool,
27    /// Tensor data version.
28    pub tensor_version: u32,
29}
30
31impl Default for TensorMetadata {
32    fn default() -> Self {
33        Self {
34            tensor: Tensor10D::default(),
35            has_tensor: false,
36            tensor_version: 1,
37        }
38    }
39}
40
41impl TensorMetadata {
42    /// Create tensor metadata from NQuin and tensor coordinates.
43    pub fn from_nquin_and_tensor(_nquin: &NQuin, tensor: Tensor10D) -> Self {
44        Self {
45            tensor,
46            has_tensor: true,
47            tensor_version: 1,
48        }
49    }
50
51    /// Create tensor metadata from NQuin only (no tensor coordinates yet).
52    pub fn from_nquin_only(_nquin: &NQuin) -> Self {
53        Self {
54            tensor: Tensor10D::default(),
55            has_tensor: false,
56            tensor_version: 1,
57        }
58    }
59}
60
61/// Lightweight entry view used by zero-heap query APIs.
62#[derive(Debug, Clone, Copy)]
63pub struct TensorizedEntry<'a> {
64    pub nquin: &'a NQuin,
65    pub metadata: &'a TensorMetadata,
66}
67
68/// Convert NQuin to Tensor10D using semantic mapping.
69impl Tensor10D {
70    /// Convert NQuin to Tensor10D using semantic mapping.
71    pub fn from_nquin(nquin: &NQuin) -> Self {
72        let q = Self::extract_quantum_context(nquin);
73        let v = Self::extract_topological_class(nquin);
74        let w = Self::extract_manifold_index(nquin);
75        let (x, y, z) = Self::extract_semantic_coordinates(nquin);
76        let t = Self::extract_temporal_state(nquin);
77        let (alpha, mu, sigma) = Self::extract_spectral_payload(nquin);
78
79        Tensor10D::new(q, v, w, x, y, z, t, alpha, mu, sigma)
80    }
81
82    /// Extract quantum context from NQuin metadata.
83    fn extract_quantum_context(_nquin: &NQuin) -> f32 {
84        0.0
85    }
86
87    /// Extract topological class from NQuin context.
88    fn extract_topological_class(_nquin: &NQuin) -> f32 {
89        0.0
90    }
91
92    /// Extract manifold index from NQuin context.
93    fn extract_manifold_index(_nquin: &NQuin) -> f32 {
94        0.0
95    }
96
97    /// Extract semantic coordinates from NQuin object field.
98    fn extract_semantic_coordinates(nquin: &NQuin) -> (f32, f32, f32) {
99        super::bake_pipeline::semantic_xyz_from_nquin(nquin)
100    }
101
102    /// Extract temporal state from NQuin metadata Lamport clock.
103    fn extract_temporal_state(nquin: &NQuin) -> f32 {
104        let clock = nquin.metadata >> 32;
105        clock as f32
106    }
107
108    /// Extract spectral payload from NQuin metadata.
109    fn extract_spectral_payload(nquin: &NQuin) -> (f32, f32, f32) {
110        let payload = nquin.metadata & 0xFFFF_FFFF;
111        let alpha = (payload & 0xFF) as f32 / 255.0;
112        let mu = ((payload >> 8) & 0xFF) as f32 / 255.0;
113        let sigma = ((payload >> 16) & 0xFF) as f32 / 255.0;
114        (alpha, mu, sigma)
115    }
116}
117
118/// Volume-level tensor configuration.
119#[repr(C)]
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct TensorVolumeConfig {
122    /// Enable 10D tensor operations.
123    pub tensor_enabled: bool,
124    /// Default manifold index for new NQuins.
125    pub default_manifold: f32,
126    /// Default topological class for new NQuins.
127    pub default_topology: f32,
128    /// Tensor version for this volume.
129    pub tensor_version: u32,
130}
131
132impl Default for TensorVolumeConfig {
133    fn default() -> Self {
134        Self {
135            tensor_enabled: true,
136            default_manifold: 0.0,
137            default_topology: 0.0,
138            tensor_version: 1,
139        }
140    }
141}
142
143/// Zero-heap tensor volume backed by caller-owned storage.
144pub struct Q42TensorVolume<'a> {
145    nquins: &'a mut [NQuin],
146    tensor_metadata: &'a mut [TensorMetadata],
147    len: usize,
148    volume_config: TensorVolumeConfig,
149}
150
151/// Immutable zero-heap tensor query view.
152#[derive(Debug)]
153pub struct Q42TensorView<'a> {
154    nquins: &'a [NQuin],
155    tensor_metadata: &'a [TensorMetadata],
156    volume_config: &'a TensorVolumeConfig,
157}
158
159impl<'a> Q42TensorVolume<'a> {
160    /// Create a new tensor volume over caller-supplied storage.
161    pub fn new(
162        nquins: &'a mut [NQuin],
163        tensor_metadata: &'a mut [TensorMetadata],
164    ) -> Result<Self, TensorVolumeError> {
165        Self::with_config(nquins, tensor_metadata, TensorVolumeConfig::default())
166    }
167
168    /// Create a new tensor volume with specific configuration.
169    pub fn with_config(
170        nquins: &'a mut [NQuin],
171        tensor_metadata: &'a mut [TensorMetadata],
172        config: TensorVolumeConfig,
173    ) -> Result<Self, TensorVolumeError> {
174        if nquins.len() != tensor_metadata.len() {
175            return Err(TensorVolumeError::MismatchedStorage);
176        }
177
178        Ok(Self {
179            nquins,
180            tensor_metadata,
181            len: 0,
182            volume_config: config,
183        })
184    }
185
186    /// Borrow this volume as a zero-heap query view.
187    pub fn as_view(&self) -> Q42TensorView<'_> {
188        Q42TensorView {
189            nquins: &self.nquins[..self.len],
190            tensor_metadata: &self.tensor_metadata[..self.len],
191            volume_config: &self.volume_config,
192        }
193    }
194
195    /// Add an NQuin to the volume with tensor coordinates.
196    pub fn add_nquin_with_tensor(
197        &mut self,
198        nquin: NQuin,
199        tensor: Tensor10D,
200    ) -> Result<usize, TensorVolumeError> {
201        if self.len >= self.nquins.len() {
202            return Err(TensorVolumeError::StorageCapacityExceeded);
203        }
204
205        self.nquins[self.len] = nquin;
206        self.tensor_metadata[self.len] =
207            TensorMetadata::from_nquin_and_tensor(&self.nquins[self.len], tensor);
208        self.len += 1;
209        Ok(self.len)
210    }
211
212    /// Add an NQuin to the volume without tensor coordinates.
213    pub fn add_nquin(&mut self, nquin: NQuin) -> Result<usize, TensorVolumeError> {
214        if self.len >= self.nquins.len() {
215            return Err(TensorVolumeError::StorageCapacityExceeded);
216        }
217
218        self.nquins[self.len] = nquin;
219        self.tensor_metadata[self.len] = TensorMetadata::from_nquin_only(&self.nquins[self.len]);
220        self.len += 1;
221        Ok(self.len)
222    }
223
224    /// Reset the used prefix and scrub old entries.
225    pub fn clear(&mut self) {
226        for index in 0..self.len {
227            self.nquins[index] = NQuin::default();
228            self.tensor_metadata[index] = TensorMetadata::default();
229        }
230        self.len = 0;
231    }
232
233    /// Get tensor metadata for an NQuin by index.
234    pub fn get_tensor_metadata(&self, index: usize) -> Option<&TensorMetadata> {
235        self.tensor_metadata.get(index).filter(|_| index < self.len)
236    }
237
238    pub fn config(&self) -> &TensorVolumeConfig {
239        &self.volume_config
240    }
241
242    pub fn update_config(&mut self, config: TensorVolumeConfig) {
243        self.volume_config = config;
244    }
245
246    pub fn len(&self) -> usize {
247        self.len
248    }
249
250    pub fn capacity(&self) -> usize {
251        self.nquins.len()
252    }
253
254    pub fn is_empty(&self) -> bool {
255        self.len == 0
256    }
257
258    pub fn tensor_count(&self) -> usize {
259        self.as_view().tensor_count()
260    }
261
262    pub fn get_tensorized_nquins_into<'b>(
263        &'b self,
264        out: &mut [TensorizedEntry<'b>],
265    ) -> Result<usize, TensorVolumeError> {
266        self.as_view().get_tensorized_nquins_into(out)
267    }
268
269    pub fn visit_tensorized_nquins<F>(&self, on_entry: F) -> Result<(), TensorVolumeError>
270    where
271        F: FnMut(TensorizedEntry<'_>) -> ControlFlow<()>,
272    {
273        self.as_view().visit_tensorized_nquins(on_entry)
274    }
275
276    pub fn tensor_search_into(
277        &self,
278        query: &Tensor10D,
279        max_distance: f32,
280        out: &mut [usize],
281    ) -> Result<usize, TensorVolumeError> {
282        self.as_view().tensor_search_into(query, max_distance, out)
283    }
284
285    pub fn visit_tensor_search<F>(
286        &self,
287        query: &Tensor10D,
288        max_distance: f32,
289        on_match: F,
290    ) -> Result<(), TensorVolumeError>
291    where
292        F: FnMut(usize) -> ControlFlow<()>,
293    {
294        self.as_view()
295            .visit_tensor_search(query, max_distance, on_match)
296    }
297
298    pub fn temporal_query_into(
299        &self,
300        target_t: f32,
301        tolerance: f32,
302        out: &mut [usize],
303    ) -> Result<usize, TensorVolumeError> {
304        self.as_view().temporal_query_into(target_t, tolerance, out)
305    }
306
307    pub fn visit_temporal_query<F>(
308        &self,
309        target_t: f32,
310        tolerance: f32,
311        on_match: F,
312    ) -> Result<(), TensorVolumeError>
313    where
314        F: FnMut(usize) -> ControlFlow<()>,
315    {
316        self.as_view()
317            .visit_temporal_query(target_t, tolerance, on_match)
318    }
319
320    pub fn manifold_query_into(
321        &self,
322        target_w: f32,
323        max_distance: f32,
324        out: &mut [usize],
325    ) -> Result<usize, TensorVolumeError> {
326        self.as_view()
327            .manifold_query_into(target_w, max_distance, out)
328    }
329
330    pub fn visit_manifold_query<F>(
331        &self,
332        target_w: f32,
333        max_distance: f32,
334        on_match: F,
335    ) -> Result<(), TensorVolumeError>
336    where
337        F: FnMut(usize) -> ControlFlow<()>,
338    {
339        self.as_view()
340            .visit_manifold_query(target_w, max_distance, on_match)
341    }
342}
343
344impl<'a> Q42TensorView<'a> {
345    pub fn new(
346        nquins: &'a [NQuin],
347        tensor_metadata: &'a [TensorMetadata],
348        volume_config: &'a TensorVolumeConfig,
349    ) -> Result<Self, TensorVolumeError> {
350        if nquins.len() != tensor_metadata.len() {
351            return Err(TensorVolumeError::MismatchedStorage);
352        }
353
354        Ok(Self {
355            nquins,
356            tensor_metadata,
357            volume_config,
358        })
359    }
360
361    pub fn config(&self) -> &'a TensorVolumeConfig {
362        self.volume_config
363    }
364
365    pub fn len(&self) -> usize {
366        self.nquins.len()
367    }
368
369    pub fn is_empty(&self) -> bool {
370        self.nquins.is_empty()
371    }
372
373    pub fn tensor_count(&self) -> usize {
374        self.tensor_metadata.iter().filter(|m| m.has_tensor).count()
375    }
376
377    pub fn get_tensorized_nquins_into(
378        &self,
379        out: &mut [TensorizedEntry<'a>],
380    ) -> Result<usize, TensorVolumeError> {
381        let mut written = 0;
382
383        self.visit_tensorized_nquins(|entry| {
384            if written >= out.len() {
385                return ControlFlow::Break(());
386            }
387
388            out[written] = entry;
389            written += 1;
390            ControlFlow::Continue(())
391        })?;
392
393        if written < self.tensor_count() {
394            return Err(TensorVolumeError::OutputBufferFull);
395        }
396
397        Ok(written)
398    }
399
400    pub fn visit_tensorized_nquins<F>(&self, mut on_entry: F) -> Result<(), TensorVolumeError>
401    where
402        F: FnMut(TensorizedEntry<'a>) -> ControlFlow<()>,
403    {
404        for (nquin, metadata) in self.nquins.iter().zip(self.tensor_metadata.iter()) {
405            if !metadata.has_tensor {
406                continue;
407            }
408
409            if let ControlFlow::Break(()) = on_entry(TensorizedEntry { nquin, metadata }) {
410                break;
411            }
412        }
413
414        Ok(())
415    }
416
417    pub fn tensor_search_into(
418        &self,
419        query: &Tensor10D,
420        max_distance: f32,
421        out: &mut [usize],
422    ) -> Result<usize, TensorVolumeError> {
423        self.collect_matching_indices_into(out, |metadata| {
424            metadata.has_tensor && query.full_distance(&metadata.tensor) <= max_distance
425        })
426    }
427
428    pub fn visit_tensor_search<F>(
429        &self,
430        query: &Tensor10D,
431        max_distance: f32,
432        mut on_match: F,
433    ) -> Result<(), TensorVolumeError>
434    where
435        F: FnMut(usize) -> ControlFlow<()>,
436    {
437        for (index, metadata) in self.tensor_metadata.iter().enumerate() {
438            if metadata.has_tensor && query.full_distance(&metadata.tensor) <= max_distance {
439                if let ControlFlow::Break(()) = on_match(index) {
440                    break;
441                }
442            }
443        }
444
445        Ok(())
446    }
447
448    pub fn temporal_query_into(
449        &self,
450        target_t: f32,
451        tolerance: f32,
452        out: &mut [usize],
453    ) -> Result<usize, TensorVolumeError> {
454        self.collect_matching_indices_into(out, |metadata| {
455            metadata.has_tensor && (metadata.tensor.t - target_t).abs() <= tolerance
456        })
457    }
458
459    pub fn visit_temporal_query<F>(
460        &self,
461        target_t: f32,
462        tolerance: f32,
463        mut on_match: F,
464    ) -> Result<(), TensorVolumeError>
465    where
466        F: FnMut(usize) -> ControlFlow<()>,
467    {
468        for (index, metadata) in self.tensor_metadata.iter().enumerate() {
469            if metadata.has_tensor && (metadata.tensor.t - target_t).abs() <= tolerance {
470                if let ControlFlow::Break(()) = on_match(index) {
471                    break;
472                }
473            }
474        }
475
476        Ok(())
477    }
478
479    pub fn manifold_query_into(
480        &self,
481        target_w: f32,
482        max_distance: f32,
483        out: &mut [usize],
484    ) -> Result<usize, TensorVolumeError> {
485        self.collect_matching_indices_into(out, |metadata| {
486            manifold_matches(metadata, target_w, max_distance)
487        })
488    }
489
490    pub fn visit_manifold_query<F>(
491        &self,
492        target_w: f32,
493        max_distance: f32,
494        mut on_match: F,
495    ) -> Result<(), TensorVolumeError>
496    where
497        F: FnMut(usize) -> ControlFlow<()>,
498    {
499        for (index, metadata) in self.tensor_metadata.iter().enumerate() {
500            if manifold_matches(metadata, target_w, max_distance) {
501                if let ControlFlow::Break(()) = on_match(index) {
502                    break;
503                }
504            }
505        }
506
507        Ok(())
508    }
509
510    fn collect_matching_indices_into<F>(
511        &self,
512        out: &mut [usize],
513        mut predicate: F,
514    ) -> Result<usize, TensorVolumeError>
515    where
516        F: FnMut(&TensorMetadata) -> bool,
517    {
518        let mut written = 0;
519
520        for (index, metadata) in self.tensor_metadata.iter().enumerate() {
521            if !predicate(metadata) {
522                continue;
523            }
524
525            if written >= out.len() {
526                return Err(TensorVolumeError::OutputBufferFull);
527            }
528
529            out[written] = index;
530            written += 1;
531        }
532
533        Ok(written)
534    }
535}
536
537fn manifold_matches(metadata: &TensorMetadata, target_w: f32, max_distance: f32) -> bool {
538    if !metadata.has_tensor {
539        return false;
540    }
541
542    let w_diff = (metadata.tensor.w - target_w).abs();
543    if w_diff > 0.1 {
544        return false;
545    }
546
547    let query = Tensor10D::new(
548        0.0,
549        metadata.tensor.v,
550        target_w,
551        metadata.tensor.x,
552        metadata.tensor.y,
553        metadata.tensor.z,
554        metadata.tensor.t,
555        metadata.tensor.alpha,
556        metadata.tensor.mu,
557        metadata.tensor.sigma,
558    );
559
560    query.spatial_distance(&metadata.tensor) <= max_distance
561}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566
567    #[test]
568    fn test_tensor_volume_creation() {
569        let mut nquins = [NQuin::default(); 4];
570        let mut metadata = [TensorMetadata::default(); 4];
571        let volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
572        assert!(volume.is_empty());
573        assert_eq!(volume.len(), 0);
574        assert_eq!(volume.capacity(), 4);
575    }
576
577    #[test]
578    fn test_add_nquin_with_tensor() {
579        let mut nquins = [NQuin::default(); 2];
580        let mut metadata = [TensorMetadata::default(); 2];
581        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
582
583        let nquin = create_test_nquin(1);
584        let tensor = Tensor10D::new(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.8, 0.5, 0.3);
585        volume.add_nquin_with_tensor(nquin, tensor).unwrap();
586
587        assert_eq!(volume.len(), 1);
588        assert_eq!(volume.tensor_count(), 1);
589        assert!(volume.get_tensor_metadata(0).unwrap().has_tensor);
590    }
591
592    #[test]
593    fn test_add_nquin_without_tensor() {
594        let mut nquins = [NQuin::default(); 2];
595        let mut metadata = [TensorMetadata::default(); 2];
596        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
597
598        volume.add_nquin(create_test_nquin(2)).unwrap();
599
600        assert_eq!(volume.len(), 1);
601        assert_eq!(volume.tensor_count(), 0);
602        assert!(!volume.get_tensor_metadata(0).unwrap().has_tensor);
603    }
604
605    #[test]
606    fn test_storage_capacity_is_bounded() {
607        let mut nquins = [NQuin::default(); 1];
608        let mut metadata = [TensorMetadata::default(); 1];
609        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
610
611        volume.add_nquin(create_test_nquin(1)).unwrap();
612        let result = volume.add_nquin(create_test_nquin(2));
613
614        assert_eq!(result, Err(TensorVolumeError::StorageCapacityExceeded));
615    }
616
617    #[test]
618    fn test_tensor_search_into() {
619        let mut nquins = [NQuin::default(); 8];
620        let mut metadata = [TensorMetadata::default(); 8];
621        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
622        seed_linear_tensor_points(&mut volume);
623
624        let query = Tensor10D::new(0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 2.0, 1.0, 0.0, 0.0);
625        let mut out = [usize::MAX; 2];
626        let written = volume.tensor_search_into(&query, 0.5, &mut out).unwrap();
627
628        assert_eq!(written, 1);
629        assert_eq!(out[0], 2);
630    }
631
632    #[test]
633    fn test_tensor_search_into_reports_overflow() {
634        let mut nquins = [NQuin::default(); 4];
635        let mut metadata = [TensorMetadata::default(); 4];
636        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
637
638        for i in 0..3 {
639            let tensor = Tensor10D::new(0.0, 0.0, 0.0, i as f32, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
640            volume
641                .add_nquin_with_tensor(create_test_nquin(i), tensor)
642                .unwrap();
643        }
644
645        let query = Tensor10D::new(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
646        let mut out = [usize::MAX; 1];
647        let result = volume.tensor_search_into(&query, 1.5, &mut out);
648
649        assert_eq!(result, Err(TensorVolumeError::OutputBufferFull));
650    }
651
652    #[test]
653    fn test_temporal_query_into() {
654        let mut nquins = [NQuin::default(); 8];
655        let mut metadata = [TensorMetadata::default(); 8];
656        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
657
658        for i in 0..5 {
659            let tensor = Tensor10D::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, i as f32, 1.0, 0.0, 0.0);
660            volume
661                .add_nquin_with_tensor(create_test_nquin(i), tensor)
662                .unwrap();
663        }
664
665        let mut out = [usize::MAX; 1];
666        let written = volume.temporal_query_into(2.0, 0.1, &mut out).unwrap();
667
668        assert_eq!(written, 1);
669        assert_eq!(out[0], 2);
670    }
671
672    #[test]
673    fn test_manifold_query_into_reports_overflow() {
674        let mut nquins = [NQuin::default(); 8];
675        let mut metadata = [TensorMetadata::default(); 8];
676        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
677
678        for i in 0..5 {
679            let w = (i % 3) as f32;
680            let tensor = Tensor10D::new(0.0, 0.0, w, i as f32, i as f32, 0.0, 0.0, 1.0, 0.0, 0.0);
681            volume
682                .add_nquin_with_tensor(create_test_nquin(i), tensor)
683                .unwrap();
684        }
685
686        let mut out = [usize::MAX; 1];
687        let result = volume.manifold_query_into(1.0, 5.0, &mut out);
688
689        assert_eq!(result, Err(TensorVolumeError::OutputBufferFull));
690    }
691
692    #[test]
693    fn test_get_tensorized_nquins_into() {
694        let mut nquins = [NQuin::default(); 4];
695        let mut metadata = [TensorMetadata::default(); 4];
696        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
697        let placeholder_nquin = NQuin::default();
698        let placeholder_metadata = TensorMetadata::default();
699
700        volume.add_nquin(create_test_nquin(0)).unwrap();
701        volume
702            .add_nquin_with_tensor(
703                create_test_nquin(1),
704                Tensor10D::new(0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0),
705            )
706            .unwrap();
707
708        let mut out = [TensorizedEntry {
709            nquin: &placeholder_nquin,
710            metadata: &placeholder_metadata,
711        }; 1];
712        let written = volume.get_tensorized_nquins_into(&mut out).unwrap();
713
714        assert_eq!(written, 1);
715        assert_eq!(out[0].nquin.subject, 1);
716        assert!(out[0].metadata.has_tensor);
717    }
718
719    #[test]
720    fn test_visit_tensor_search_stops_when_callback_breaks() {
721        let mut nquins = [NQuin::default(); 8];
722        let mut metadata = [TensorMetadata::default(); 8];
723        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
724
725        for i in 0..4 {
726            let tensor = Tensor10D::new(0.0, 0.0, 0.0, i as f32, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
727            volume
728                .add_nquin_with_tensor(create_test_nquin(i), tensor)
729                .unwrap();
730        }
731
732        let query = Tensor10D::new(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
733        let mut first_hit = usize::MAX;
734        let mut count = 0usize;
735        volume
736            .visit_tensor_search(&query, 3.0, |index| {
737                first_hit = index;
738                count += 1;
739                ControlFlow::Break(())
740            })
741            .unwrap();
742
743        assert_eq!(count, 1);
744        assert_eq!(first_hit, 0);
745    }
746
747    #[test]
748    fn test_clear_scrubs_used_prefix() {
749        let mut nquins = [NQuin::default(); 2];
750        let mut metadata = [TensorMetadata::default(); 2];
751        let mut volume = Q42TensorVolume::new(&mut nquins, &mut metadata).unwrap();
752
753        volume
754            .add_nquin_with_tensor(
755                create_test_nquin(7),
756                Tensor10D::new(0.0, 0.0, 0.0, 7.0, 7.0, 0.0, 7.0, 1.0, 0.0, 0.0),
757            )
758            .unwrap();
759        volume.clear();
760
761        assert_eq!(volume.len(), 0);
762        assert_eq!(volume.nquins[0], NQuin::default());
763        assert_eq!(volume.tensor_metadata[0], TensorMetadata::default());
764    }
765
766    #[test]
767    fn test_q42_tensor_view_rejects_mismatched_storage() {
768        let nquins = [create_test_nquin(1)];
769        let metadata = [TensorMetadata::default(), TensorMetadata::default()];
770        let config = TensorVolumeConfig::default();
771
772        let result = Q42TensorView::new(&nquins, &metadata, &config);
773
774        assert!(matches!(result, Err(TensorVolumeError::MismatchedStorage)));
775    }
776
777    fn seed_linear_tensor_points(volume: &mut Q42TensorVolume<'_>) {
778        for i in 0..5 {
779            let tensor = Tensor10D::new(
780                0.0, 0.0, 0.0, i as f32, i as f32, 0.0, i as f32, 1.0, 0.0, 0.0,
781            );
782            volume
783                .add_nquin_with_tensor(create_test_nquin(i), tensor)
784                .unwrap();
785        }
786    }
787
788    fn create_test_nquin(id: u64) -> NQuin {
789        NQuin {
790            subject: id,
791            predicate: id,
792            object: id,
793            context: id,
794            metadata: (id << 32) | id,
795            parity: 0,
796        }
797    }
798}