File size: 3,696 Bytes
be99550
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
//! BioPhys Neural ๊ฐ€์ค‘์น˜ ํŒŒ์ผ(.bpsn) ํŒŒ์„œ
//! ํŒŒ์ผ ๊ตฌ์กฐ: [๋งค์ง(8B)][์ด๋ฆ„๊ธธ์ด(4B)][์ด๋ฆ„(NB)][๊ฐ€์ค‘์น˜(0x55AA ํŒจํ„ด)]

use std::path::Path;
use std::fs;

/// BPSN ํŒŒ์ผ ๋งค์ง ๋„˜๋ฒ„
const BPSN_MAGIC: &[u8] = b"BPSN4.0_";

/// ํŒŒ์‹ฑ๋œ BioPhys ๋‡Œ ๋ชจ๋ธ
#[derive(Debug, Clone)]
pub struct BpsnModel {
    pub name:         String,
    pub weights:      Vec<u32>,   // 2-bit ํŒจํ‚น ๊ฐ€์ค‘์น˜ (uint32 = 16์ฟผํฌ)
    pub weight_count: usize,
    pub size_mb:      f32,
}

impl BpsnModel {
    /// .bpsn ํŒŒ์ผ ๋กœ๋”ฉ ๋ฐ ํŒŒ์‹ฑ
    pub fn load(path: &Path) -> Result<Self, String> {
        let bytes = fs::read(path)
            .map_err(|e| format!("ํŒŒ์ผ ์ฝ๊ธฐ ์‹คํŒจ: {}", e))?;

        // ๋งค์ง ๋„˜๋ฒ„ ๊ฒ€์ฆ
        if bytes.len() < 12 || &bytes[0..8] != BPSN_MAGIC {
            return Err(format!("์œ ํšจํ•˜์ง€ ์•Š์€ BPSN ํŒŒ์ผ: {:?}", path));
        }

        // ๋ชจ๋ธ๋ช… ๊ธธ์ด (bytes[8..12] = u32 LE)
        let name_len = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as usize;

        // ๋ชจ๋ธ๋ช… ํŒŒ์‹ฑ
        let name_start = 12;
        let name_end   = (name_start + name_len).min(bytes.len());
        let name = String::from_utf8_lossy(&bytes[name_start..name_end])
            .trim_end_matches('\0')
            .to_string();

        // ๊ฐ€์ค‘์น˜ ๋ฐ์ดํ„ฐ (์ด๋ฆ„ ์ดํ›„ ๋‚˜๋จธ์ง€ ์ „๋ถ€)
        let weight_start = name_start + name_len;
        let weight_bytes = &bytes[weight_start..];

        // u8 โ†’ u32 ํŒจํ‚น (4๋ฐ”์ดํŠธ = 1 ์ฟผํฌ ํŒจํ‚ท = 16๊ฐœ 2-bit ๊ฐ€์ค‘์น˜)
        let weights: Vec<u32> = weight_bytes
            .chunks(4)
            .filter(|c| c.len() == 4)
            .map(|c| u32::from_le_bytes([c[0], c[1], c[2], c[3]]))
            .collect();

        let weight_count = weights.len();
        let size_mb = bytes.len() as f32 / 1024.0 / 1024.0;

        Ok(BpsnModel { name, weights, weight_count, size_mb })
    }

    /// ๊ฐ€์ค‘์น˜๋ฅผ ๋ฐ”์ดํŠธ ์Šฌ๋ผ์ด์Šค๋กœ ๋ฐ˜ํ™˜ (GPU ์—…๋กœ๋“œ์šฉ)
    pub fn weights_as_bytes(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(
                self.weights.as_ptr() as *const u8,
                self.weights.len() * 4,
            )
        }
    }

    /// ์ดˆ๋ˆ ๊ณต๋ช… ์—ฐ์‚ฐ (CPU ํด๋ฐฑ)
    pub fn superstring_spin(&self, input_idx: usize, wave: u32) -> f32 {
        if input_idx >= self.weights.len() { return 0.0; }
        let quark = self.weights[input_idx] ^ wave;
        quark.count_ones() as f32 * 1.414
    }

    /// ๋ชจ๋ธ ์š”์•ฝ ์ถœ๋ ฅ
    pub fn summary(&self) {
        println!("  ๐Ÿ“ฆ [BPSN] ๋ชจ๋ธ: {}", self.name);
        println!("  ๐Ÿ“ฆ       ๊ฐ€์ค‘์น˜ ํŒจํ‚ท: {}๊ฐœ ({}ร—16 = {}๊ฐœ ์ฟผํฌ)",
            self.weight_count,
            self.weight_count,
            self.weight_count * 16);
        println!("  ๐Ÿ“ฆ       ํŒŒ์ผ ํฌ๊ธฐ: {:.3}MB", self.size_mb);
        println!("  ๐Ÿ“ฆ       ์ƒ˜ํ”Œ[0]: 0x{:08X} ({:08b}...)",
            self.weights.get(0).copied().unwrap_or(0),
            self.weights.get(0).copied().unwrap_or(0));
    }
}

/// ๋ชจ๋“  .bpsn ๋ชจ๋ธ ์ผ๊ด„ ๋กœ๋”ฉ
pub fn load_all_brains(dir: &Path) -> Vec<BpsnModel> {
    let mut models = Vec::new();
    let pattern = dir.join("*_8state.bpsn");

    if let Ok(entries) = fs::read_dir(dir) {
        for entry in entries.flatten() {
            let p = entry.path();
            if p.extension().map(|e| e == "bpsn").unwrap_or(false) {
                match BpsnModel::load(&p) {
                    Ok(m)  => { println!("  โœ… ๋กœ๋”ฉ ์™„๋ฃŒ: {}", m.name); models.push(m); },
                    Err(e) => println!("  โŒ ๋กœ๋”ฉ ์‹คํŒจ: {} โ†’ {}", p.display(), e),
                }
            }
        }
    }
    models
}