diff --git a/README.md b/README.md index 22110b0..3ca685e 100644 --- a/README.md +++ b/README.md @@ -379,6 +379,25 @@ MIYAGI_TEST_GPU_LAYERS=0 \ cargo test --no-default-features --test model_backend ``` +### Building on Windows (MSVC) + +Miyagi builds and runs on Windows (validated on Windows 11, Rust +`x86_64-pc-windows-msvc`, against mainline llama.cpp b10054 with an RTX 4090). +Notes: + +- With Visual Studio 18 installed, the `cmake` crate requests the + "Visual Studio 18 2026" generator, which needs CMake ≥ 4.3 on `PATH` + (VS's bundled CMake works). +- For `--features cuda` with a VS version newer than your CUDA toolkit's VS + integration, use the Ninja generator inside a `vcvars64` environment of a VS + version the toolkit supports, e.g.: + + ```bat + call "...\BuildTools\VC\Auxiliary\Build\vcvars64.bat" + set CMAKE_GENERATOR=Ninja + cargo build --release --features cuda + ``` + ## Compatibility and Boundaries - Miyagi supports descriptor-driven Qwen/Bonsai MLP mapping for two-dimensional diff --git a/src/architecture.rs b/src/architecture.rs index d9e0e02..f36a86d 100644 --- a/src/architecture.rs +++ b/src/architecture.rs @@ -96,11 +96,24 @@ impl TensorInfo { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct ArchitectureMap { + // Tuple keys cannot be JSON map keys ("key must be a string"); emit the + // tensor list instead — each TensorInfo already carries layer+projection. + #[serde(serialize_with = "serialize_tensor_map")] tensors: BTreeMap<(usize, Projection), TensorInfo>, layer_count: usize, signature: String, } +fn serialize_tensor_map( + tensors: &BTreeMap<(usize, Projection), TensorInfo>, + serializer: S, +) -> std::result::Result +where + S: serde::Serializer, +{ + serializer.collect_seq(tensors.values()) +} + impl ArchitectureMap { pub fn discover(descriptors: &[TensorDescriptor]) -> Result { let mut tensors = BTreeMap::new(); @@ -295,4 +308,34 @@ mod tests { "\"down_proj\"" ); } + + #[test] + fn architecture_map_json_serializes_tensors_as_array() { + let mut descriptors = Vec::new(); + for layer in 0..2 { + descriptors.push(descriptor( + &format!("blk.{layer}.ffn_gate.weight"), + 4096, + 12288, + )); + descriptors.push(descriptor( + &format!("blk.{layer}.ffn_up.weight"), + 4096, + 12288, + )); + descriptors.push(descriptor( + &format!("blk.{layer}.ffn_down.weight"), + 12288, + 4096, + )); + } + let map = ArchitectureMap::discover(&descriptors).unwrap(); + let value = serde_json::to_value(&map).expect("JSON serialize must not fail on tuple keys"); + let tensors = value + .get("tensors") + .and_then(|t| t.as_array()) + .expect("tensors must serialize as a JSON array"); + assert_eq!(tensors.len(), 6); + assert!(tensors.iter().all(|t| t.get("layer").is_some() && t.get("projection").is_some())); + } }