Skip to main content

microscope_memory/
viz.rs

1//! Visualization export for Microscope Memory.
2//!
3//! ZERO JSON. Pure binary. mmap-ready.
4//! Format: VIZ1 + block_count:u32 + blocks:[VizBlock] + edge_count:u32 + edges:[u32;3]
5
6use crate::hebbian::HebbianState;
7use crate::mirror::MirrorState;
8use crate::reader::MicroscopeReader;
9use crate::thought_graph::ThoughtGraphState;
10use std::io::Write;
11use std::path::Path;
12
13/// Packed visualization block (32 bytes).
14#[repr(C, packed)]
15#[derive(Clone, Copy)]
16pub struct VizBlock {
17    pub x: f32,
18    pub y: f32,
19    pub z: f32,
20    pub dx: f32,
21    pub dy: f32,
22    pub dz: f32,
23    pub energy: f32,
24    pub layer_id: u8,
25    pub depth: u8,
26    pub flags: u8,
27    pub padding: u8,
28}
29
30/// Export the full state as a raw binary buffer (VIZ1).
31pub fn export_binary_snapshot(
32    reader: &MicroscopeReader,
33    hebb: &HebbianState,
34    mirror: &MirrorState,
35    thought_graph: &ThoughtGraphState,
36) -> Vec<u8> {
37    let block_count = reader.block_count;
38    let mut buf = Vec::with_capacity(12 + block_count * 32 + 200 * 12 + 5000);
39
40    // Header (4 bytes magic + 4 bytes block_count)
41    buf.extend_from_slice(b"VIZ1");
42    buf.extend_from_slice(&(block_count as u32).to_le_bytes());
43
44    // Blocks (Zero-copy loop)
45    for i in 0..block_count {
46        let h = reader.header(i);
47        let energy = hebb.energy(i);
48        let (dx, dy, dz) = if i < hebb.activations.len() {
49            let rec = &hebb.activations[i];
50            (rec.drift_x, rec.drift_y, rec.drift_z)
51        } else {
52            (0.0, 0.0, 0.0)
53        };
54
55        let mirror_boost = mirror.boost_for(i as u32);
56        let flags = if mirror_boost > 0.5 { 1 } else { 0 };
57
58        let vb = VizBlock {
59            x: h.x,
60            y: h.y,
61            z: h.z,
62            dx,
63            dy,
64            dz,
65            energy,
66            layer_id: h.layer_id,
67            depth: h.depth,
68            flags,
69            padding: 0,
70        };
71
72        let bytes: [u8; 32] = unsafe { std::mem::transmute(vb) };
73        buf.extend_from_slice(&bytes);
74    }
75
76    // ThoughtGraph Nodes (recent 100)
77    let recent_nodes = if thought_graph.nodes.len() > 100 {
78        &thought_graph.nodes[thought_graph.nodes.len() - 100..]
79    } else {
80        &thought_graph.nodes
81    };
82    buf.extend_from_slice(&(recent_nodes.len() as u32).to_le_bytes());
83    for n in recent_nodes {
84        buf.extend_from_slice(&n.query_hash.to_le_bytes());
85        buf.extend_from_slice(&n.timestamp_ms.to_le_bytes());
86        buf.extend_from_slice(&(n.result_count as u32).to_le_bytes());
87        buf.push(n.dominant_layer);
88        buf.push(n.centroid_hash);
89        buf.extend_from_slice(&[0u8; 2]); // padding to 24 bytes
90    }
91
92    // Patterns (top 20)
93    let top_patterns = thought_graph.top_patterns(20);
94    buf.extend_from_slice(&(top_patterns.len() as u32).to_le_bytes());
95    for p in top_patterns {
96        buf.extend_from_slice(&p.id.to_le_bytes());
97        buf.extend_from_slice(&p.frequency.to_le_bytes());
98        buf.extend_from_slice(&p.strength.to_le_bytes());
99        buf.extend_from_slice(&(p.sequence.len() as u8).to_le_bytes());
100        for &h in p.sequence.iter().take(5) {
101            buf.extend_from_slice(&h.to_le_bytes());
102        }
103        for _ in p.sequence.len()..5 {
104            buf.extend_from_slice(&0u64.to_le_bytes());
105        }
106    }
107
108    // Edges (top 200 strongest)
109    let mut pairs: Vec<_> = hebb.coactivations.values().collect();
110    pairs.sort_by(|a, b| b.count.cmp(&a.count));
111    pairs.truncate(200);
112
113    buf.extend_from_slice(&(pairs.len() as u32).to_le_bytes());
114    for p in pairs {
115        buf.extend_from_slice(&p.block_a.to_le_bytes());
116        buf.extend_from_slice(&p.block_b.to_le_bytes());
117        buf.extend_from_slice(&p.count.to_le_bytes());
118    }
119
120    buf
121}
122
123pub fn export_to_file(
124    _output_dir: &Path,
125    reader: &MicroscopeReader,
126    hebb: &HebbianState,
127    mirror: &MirrorState,
128    thought_graph: &ThoughtGraphState,
129    dest: &Path,
130) -> Result<(), String> {
131    let buf = export_binary_snapshot(reader, hebb, mirror, thought_graph);
132    let mut file = std::fs::File::create(dest).map_err(|e| format!("create viz file: {}", e))?;
133    file.write_all(&buf)
134        .map_err(|e| format!("write viz file: {}", e))
135}
136pub fn export_density_map(
137    _hebb: &HebbianState,
138    _headers: &[(f32, f32, f32)],
139    _grid: u16,
140) -> Vec<u8> {
141    vec![]
142}
143pub fn layer_heatmap(
144    _hebb: &HebbianState,
145    _reader: &MicroscopeReader,
146) -> std::collections::HashMap<String, f32> {
147    std::collections::HashMap::new()
148}