mcyakar's picture
deploy: VectorHD 0.2.10 (source ff79722)
5e84645
Raw
History Blame Contribute Delete
3 kB
//! Deserialization of the test-vector files written by `scripts/export_spike_vectors.py`.
//!
//! Field-for-field with the exporter. Nothing here computes; see `coverage`, `energy`, `gradient`.
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub type Pt = [f64; 2];
#[derive(Debug, Deserialize)]
pub struct Edge {
pub id: i64,
#[allow(dead_code)]
pub node_a: i64,
#[allow(dead_code)]
pub node_b: i64,
pub left_label: i64,
pub right_label: i64,
/// True when neither side is the exterior face — exactly `geometry_gradient`'s filter.
pub interior: bool,
/// One inner Vec per cubic, each holding `flatten_samples` fixed-t sampled points.
pub cubics: Vec<Vec<Pt>>,
}
#[derive(Debug, Deserialize)]
pub struct Face {
pub label: i64,
/// Each loop is an ordered list of `[edge_id, direction]` darts (direction is +1 / -1).
pub loops: Vec<Vec<[i64; 2]>>,
}
#[derive(Debug, Deserialize)]
pub struct Golden {
pub e_data: f64,
pub coverage_checksums: HashMap<String, Checksum>,
pub coverage_samples: Vec<CoverageSample>,
pub vertex_gradients: Vec<GradientSample>,
}
#[derive(Debug, Deserialize, Serialize, Clone, Copy)]
pub struct Checksum {
pub sum: f64,
pub sumsq: f64,
}
#[derive(Debug, Deserialize)]
pub struct CoverageSample {
pub label: i64,
pub row: usize,
pub col: usize,
pub value: f64,
}
#[derive(Debug, Deserialize)]
pub struct GradientSample {
pub edge: i64,
pub cubic: usize,
pub vertex: usize,
pub gx: f64,
pub gy: f64,
}
#[derive(Debug, Deserialize)]
pub struct Vectors {
pub name: String,
pub kind: String,
pub seed: u64,
pub width: usize,
pub height: usize,
pub background: f64,
pub l0: f64,
pub colors255: HashMap<String, [f64; 3]>,
pub edges: Vec<Edge>,
pub faces: Vec<Face>,
pub target_u8: Vec<u8>,
pub golden: Golden,
}
impl Vectors {
pub fn edge_by_id(&self) -> HashMap<i64, &Edge> {
self.edges.iter().map(|e| (e.id, e)).collect()
}
/// `target = clip(u8 / 255, 0, 1)`, matching `refine_graph_analytic`. u8/255 is always in
/// range, so the clip is a no-op here and is omitted rather than faked.
pub fn target(&self) -> Vec<f64> {
self.target_u8.iter().map(|&b| b as f64 / 255.0).collect()
}
/// Per-label RGB in [0,1]: `clip(colors/255, 0, 1)`, as both `render` and `geometry_gradient`
/// do. The clip is real here — VarPro colors can land outside [0,255].
pub fn colors01(&self) -> HashMap<i64, [f64; 3]> {
self.colors255
.iter()
.map(|(k, v)| {
let lb: i64 = k.parse().expect("label key must be an integer");
let c = [
(v[0] / 255.0).clamp(0.0, 1.0),
(v[1] / 255.0).clamp(0.0, 1.0),
(v[2] / 255.0).clamp(0.0, 1.0),
];
(lb, c)
})
.collect()
}
}