feat: ADR-033 CRV signal-line integration + ruvector-crv 6-stage pipeline
Implement full CRV (Coordinate Remote Viewing) signal-line protocol mapping to WiFi CSI sensing via ruvector-crv: - Stage I: CsiGestaltClassifier (6 gestalt types from amplitude/phase) - Stage II: CsiSensoryEncoder (texture/color/temperature/sound/luminosity/dimension) - Stage III: Mesh topology encoding (AP nodes/links → GNN graph) - Stage IV: Coherence gate → AOL detection (signal vs noise separation) - Stage V: Pose interrogation via differentiable search - Stage VI: Person partitioning via MinCut clustering - Cross-session convergence for cross-room identity New files: - crv/mod.rs: 1,430 lines, 43 tests - crv_bench.rs: 8 criterion benchmarks (gestalt, sensory, pipeline, convergence) - ADR-033: 740-line architecture decision with 30+ acceptance criteria - patches/ruvector-crv: Fix ruvector-gnn 2.0.5 API mismatch Dependencies: ruvector-crv 0.1.1, ruvector-gnn 2.0.5 Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -16,4 +16,16 @@ ruvector-attn-mincut = { workspace = true }
|
||||
ruvector-temporal-tensor = { workspace = true }
|
||||
ruvector-solver = { workspace = true }
|
||||
ruvector-attention = { workspace = true }
|
||||
ruvector-crv = { workspace = true }
|
||||
ruvector-gnn = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
criterion = { workspace = true }
|
||||
|
||||
[[bench]]
|
||||
name = "crv_bench"
|
||||
harness = false
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
//! Benchmarks for CRV (Coordinate Remote Viewing) integration.
|
||||
//!
|
||||
//! Measures throughput of gestalt classification, sensory encoding,
|
||||
//! full session pipelines, cross-session convergence, and embedding
|
||||
//! dimension scaling using the `ruvector-crv` crate directly.
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use ruvector_crv::{
|
||||
CrvConfig, CrvSessionManager, GestaltType, SensoryModality, StageIData, StageIIData,
|
||||
StageIIIData, StageIVData,
|
||||
};
|
||||
use ruvector_crv::types::{
|
||||
GeometricKind, SketchElement, SpatialRelationType, SpatialRelationship,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Build a synthetic CSI-like ideogram stroke with `n` subcarrier points.
|
||||
fn make_stroke(n: usize) -> Vec<(f32, f32)> {
|
||||
(0..n)
|
||||
.map(|i| {
|
||||
let t = i as f32 / n as f32;
|
||||
(t, (t * std::f32::consts::TAU).sin() * 0.5 + 0.5)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Build a Stage I data frame representing a single CSI gestalt sample.
|
||||
fn make_stage_i(gestalt: GestaltType) -> StageIData {
|
||||
StageIData {
|
||||
stroke: make_stroke(64),
|
||||
spontaneous_descriptor: "angular rising".to_string(),
|
||||
classification: gestalt,
|
||||
confidence: 0.85,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a Stage II sensory data frame.
|
||||
fn make_stage_ii() -> StageIIData {
|
||||
StageIIData {
|
||||
impressions: vec![
|
||||
(SensoryModality::Texture, "rough metallic".to_string()),
|
||||
(SensoryModality::Temperature, "warm".to_string()),
|
||||
(SensoryModality::Color, "silver-gray".to_string()),
|
||||
(SensoryModality::Luminosity, "reflective".to_string()),
|
||||
(SensoryModality::Sound, "low hum".to_string()),
|
||||
],
|
||||
feature_vector: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a Stage III spatial sketch.
|
||||
fn make_stage_iii() -> StageIIIData {
|
||||
StageIIIData {
|
||||
sketch_elements: vec![
|
||||
SketchElement {
|
||||
label: "tower".to_string(),
|
||||
kind: GeometricKind::Rectangle,
|
||||
position: (0.5, 0.8),
|
||||
scale: Some(3.0),
|
||||
},
|
||||
SketchElement {
|
||||
label: "base".to_string(),
|
||||
kind: GeometricKind::Rectangle,
|
||||
position: (0.5, 0.2),
|
||||
scale: Some(5.0),
|
||||
},
|
||||
SketchElement {
|
||||
label: "antenna".to_string(),
|
||||
kind: GeometricKind::Line,
|
||||
position: (0.5, 0.95),
|
||||
scale: Some(1.0),
|
||||
},
|
||||
],
|
||||
relationships: vec![
|
||||
SpatialRelationship {
|
||||
from: "tower".to_string(),
|
||||
to: "base".to_string(),
|
||||
relation: SpatialRelationType::Above,
|
||||
strength: 0.9,
|
||||
},
|
||||
SpatialRelationship {
|
||||
from: "antenna".to_string(),
|
||||
to: "tower".to_string(),
|
||||
relation: SpatialRelationType::Above,
|
||||
strength: 0.85,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a Stage IV emotional / AOL data frame.
|
||||
fn make_stage_iv() -> StageIVData {
|
||||
StageIVData {
|
||||
emotional_impact: vec![
|
||||
("awe".to_string(), 0.7),
|
||||
("curiosity".to_string(), 0.6),
|
||||
("unease".to_string(), 0.3),
|
||||
],
|
||||
tangibles: vec!["metal structure".to_string(), "concrete".to_string()],
|
||||
intangibles: vec!["transmission".to_string(), "power".to_string()],
|
||||
aol_detections: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a manager with one session pre-loaded with 4 stages of data.
|
||||
fn populated_manager(dims: usize) -> (CrvSessionManager, String) {
|
||||
let config = CrvConfig {
|
||||
dimensions: dims,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut mgr = CrvSessionManager::new(config);
|
||||
let sid = "bench-sess".to_string();
|
||||
mgr.create_session(sid.clone(), "coord-001".to_string())
|
||||
.unwrap();
|
||||
mgr.add_stage_i(&sid, &make_stage_i(GestaltType::Manmade))
|
||||
.unwrap();
|
||||
mgr.add_stage_ii(&sid, &make_stage_ii()).unwrap();
|
||||
mgr.add_stage_iii(&sid, &make_stage_iii()).unwrap();
|
||||
mgr.add_stage_iv(&sid, &make_stage_iv()).unwrap();
|
||||
(mgr, sid)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Benchmarks
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Benchmark: classify a single CSI frame through Stage I (64 subcarriers).
|
||||
fn gestalt_classify_single(c: &mut Criterion) {
|
||||
let config = CrvConfig {
|
||||
dimensions: 64,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(config);
|
||||
manager
|
||||
.create_session("gc-single".to_string(), "coord-gc".to_string())
|
||||
.unwrap();
|
||||
|
||||
let data = make_stage_i(GestaltType::Manmade);
|
||||
|
||||
c.bench_function("gestalt_classify_single", |b| {
|
||||
b.iter(|| {
|
||||
manager
|
||||
.add_stage_i("gc-single", black_box(&data))
|
||||
.unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: classify a batch of 100 CSI frames through Stage I.
|
||||
fn gestalt_classify_batch(c: &mut Criterion) {
|
||||
let config = CrvConfig {
|
||||
dimensions: 64,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
|
||||
let gestalts = GestaltType::all();
|
||||
let frames: Vec<StageIData> = (0..100)
|
||||
.map(|i| make_stage_i(gestalts[i % gestalts.len()]))
|
||||
.collect();
|
||||
|
||||
c.bench_function("gestalt_classify_batch_100", |b| {
|
||||
b.iter(|| {
|
||||
let mut manager = CrvSessionManager::new(CrvConfig {
|
||||
dimensions: 64,
|
||||
..CrvConfig::default()
|
||||
});
|
||||
manager
|
||||
.create_session("gc-batch".to_string(), "coord-gcb".to_string())
|
||||
.unwrap();
|
||||
|
||||
for frame in black_box(&frames) {
|
||||
manager.add_stage_i("gc-batch", frame).unwrap();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: extract sensory features from a single CSI frame (Stage II).
|
||||
fn sensory_encode_single(c: &mut Criterion) {
|
||||
let config = CrvConfig {
|
||||
dimensions: 64,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(config);
|
||||
manager
|
||||
.create_session("se-single".to_string(), "coord-se".to_string())
|
||||
.unwrap();
|
||||
|
||||
let data = make_stage_ii();
|
||||
|
||||
c.bench_function("sensory_encode_single", |b| {
|
||||
b.iter(|| {
|
||||
manager
|
||||
.add_stage_ii("se-single", black_box(&data))
|
||||
.unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: full session pipeline -- create session, add 10 mixed-stage
|
||||
/// frames, run Stage V interrogation, and run Stage VI partitioning.
|
||||
fn pipeline_full_session(c: &mut Criterion) {
|
||||
let stage_i_data = make_stage_i(GestaltType::Manmade);
|
||||
let stage_ii_data = make_stage_ii();
|
||||
let stage_iii_data = make_stage_iii();
|
||||
let stage_iv_data = make_stage_iv();
|
||||
|
||||
c.bench_function("pipeline_full_session", |b| {
|
||||
let mut counter = 0u64;
|
||||
b.iter(|| {
|
||||
counter += 1;
|
||||
let config = CrvConfig {
|
||||
dimensions: 64,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(config);
|
||||
let sid = format!("pfs-{}", counter);
|
||||
manager
|
||||
.create_session(sid.clone(), "coord-pfs".to_string())
|
||||
.unwrap();
|
||||
|
||||
// 10 frames across stages I-IV
|
||||
for _ in 0..3 {
|
||||
manager
|
||||
.add_stage_i(&sid, black_box(&stage_i_data))
|
||||
.unwrap();
|
||||
}
|
||||
for _ in 0..3 {
|
||||
manager
|
||||
.add_stage_ii(&sid, black_box(&stage_ii_data))
|
||||
.unwrap();
|
||||
}
|
||||
for _ in 0..2 {
|
||||
manager
|
||||
.add_stage_iii(&sid, black_box(&stage_iii_data))
|
||||
.unwrap();
|
||||
}
|
||||
for _ in 0..2 {
|
||||
manager
|
||||
.add_stage_iv(&sid, black_box(&stage_iv_data))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Stage V: interrogate with a probe embedding
|
||||
let probe_emb = vec![0.1f32; 64];
|
||||
let probes: Vec<(&str, u8, Vec<f32>)> = vec![
|
||||
("structure query", 1, probe_emb.clone()),
|
||||
("texture query", 2, probe_emb.clone()),
|
||||
];
|
||||
let _ = manager.run_stage_v(&sid, &probes, 3);
|
||||
|
||||
// Stage VI: partition
|
||||
let _ = manager.run_stage_vi(&sid);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: cross-session convergence analysis with 2 independent
|
||||
/// sessions of 10 frames each, targeting the same coordinate.
|
||||
fn convergence_two_sessions(c: &mut Criterion) {
|
||||
let gestalts = [GestaltType::Manmade, GestaltType::Natural, GestaltType::Energy];
|
||||
let stage_ii_data = make_stage_ii();
|
||||
|
||||
c.bench_function("convergence_two_sessions", |b| {
|
||||
let mut counter = 0u64;
|
||||
b.iter(|| {
|
||||
counter += 1;
|
||||
let config = CrvConfig {
|
||||
dimensions: 64,
|
||||
convergence_threshold: 0.5,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(config);
|
||||
let coord = format!("conv-coord-{}", counter);
|
||||
|
||||
// Session A: 10 frames
|
||||
let sid_a = format!("viewer-a-{}", counter);
|
||||
manager
|
||||
.create_session(sid_a.clone(), coord.clone())
|
||||
.unwrap();
|
||||
for i in 0..5 {
|
||||
let data = make_stage_i(gestalts[i % gestalts.len()]);
|
||||
manager.add_stage_i(&sid_a, black_box(&data)).unwrap();
|
||||
}
|
||||
for _ in 0..5 {
|
||||
manager
|
||||
.add_stage_ii(&sid_a, black_box(&stage_ii_data))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Session B: 10 frames (similar but not identical)
|
||||
let sid_b = format!("viewer-b-{}", counter);
|
||||
manager
|
||||
.create_session(sid_b.clone(), coord.clone())
|
||||
.unwrap();
|
||||
for i in 0..5 {
|
||||
let data = make_stage_i(gestalts[(i + 1) % gestalts.len()]);
|
||||
manager.add_stage_i(&sid_b, black_box(&data)).unwrap();
|
||||
}
|
||||
for _ in 0..5 {
|
||||
manager
|
||||
.add_stage_ii(&sid_b, black_box(&stage_ii_data))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Convergence analysis
|
||||
let _ = manager.find_convergence(&coord, black_box(0.5));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: session creation overhead alone.
|
||||
fn crv_session_create(c: &mut Criterion) {
|
||||
c.bench_function("crv_session_create", |b| {
|
||||
b.iter(|| {
|
||||
let config = CrvConfig {
|
||||
dimensions: 32,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(black_box(config));
|
||||
manager
|
||||
.create_session(
|
||||
black_box("sess-1".to_string()),
|
||||
black_box("coord-1".to_string()),
|
||||
)
|
||||
.unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// Benchmark: embedding dimension scaling (32, 128, 384).
|
||||
///
|
||||
/// Measures Stage I + Stage II encode time across different embedding
|
||||
/// dimensions to characterize how cost grows with dimensionality.
|
||||
fn crv_embedding_dimension_scaling(c: &mut Criterion) {
|
||||
let stage_i_data = make_stage_i(GestaltType::Manmade);
|
||||
let stage_ii_data = make_stage_ii();
|
||||
|
||||
let mut group = c.benchmark_group("crv_embedding_dimension_scaling");
|
||||
for dims in [32, 128, 384] {
|
||||
group.bench_with_input(BenchmarkId::from_parameter(dims), &dims, |b, &dims| {
|
||||
let mut counter = 0u64;
|
||||
b.iter(|| {
|
||||
counter += 1;
|
||||
let config = CrvConfig {
|
||||
dimensions: dims,
|
||||
..CrvConfig::default()
|
||||
};
|
||||
let mut manager = CrvSessionManager::new(config);
|
||||
let sid = format!("dim-{}-{}", dims, counter);
|
||||
manager
|
||||
.create_session(sid.clone(), "coord-dim".to_string())
|
||||
.unwrap();
|
||||
|
||||
// Encode one Stage I + one Stage II at this dimensionality
|
||||
let emb_i = manager
|
||||
.add_stage_i(&sid, black_box(&stage_i_data))
|
||||
.unwrap();
|
||||
let emb_ii = manager
|
||||
.add_stage_ii(&sid, black_box(&stage_ii_data))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(emb_i.len(), dims);
|
||||
assert_eq!(emb_ii.len(), dims);
|
||||
})
|
||||
});
|
||||
}
|
||||
group.finish();
|
||||
}
|
||||
|
||||
/// Benchmark: Stage VI partitioning on a pre-populated session
|
||||
/// (4 stages of accumulated data).
|
||||
fn crv_stage_vi_partition(c: &mut Criterion) {
|
||||
c.bench_function("crv_stage_vi_partition", |b| {
|
||||
let mut counter = 0u64;
|
||||
b.iter(|| {
|
||||
counter += 1;
|
||||
// Re-create the populated manager each iteration because
|
||||
// run_stage_vi mutates the session (appends an entry).
|
||||
let (mut mgr, sid) = populated_manager(64);
|
||||
let _ = mgr.run_stage_vi(black_box(&sid));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Criterion groups
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
criterion_group!(
|
||||
benches,
|
||||
gestalt_classify_single,
|
||||
gestalt_classify_batch,
|
||||
sensory_encode_single,
|
||||
pipeline_full_session,
|
||||
convergence_two_sessions,
|
||||
crv_session_create,
|
||||
crv_embedding_dimension_scaling,
|
||||
crv_stage_vi_partition,
|
||||
);
|
||||
|
||||
criterion_main!(benches);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
pub mod crv;
|
||||
pub mod mat;
|
||||
pub mod signal;
|
||||
pub mod viewpoint;
|
||||
|
||||
Reference in New Issue
Block a user