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
}
|