Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
321
crates/ruvector-nervous-system-wasm/tests/web.rs
Normal file
321
crates/ruvector-nervous-system-wasm/tests/web.rs
Normal file
@@ -0,0 +1,321 @@
|
||||
//! Web tests for ruvector-nervous-system-wasm
|
||||
//!
|
||||
//! Run with: wasm-pack test --headless --chrome
|
||||
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
use ruvector_nervous_system_wasm::*;
|
||||
|
||||
// ============================================================================
|
||||
// BTSP Tests
|
||||
// ============================================================================
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_btsp_synapse_creation() {
|
||||
let synapse = BTSPSynapse::new(0.5, 2000.0).expect("Should create synapse");
|
||||
assert!((synapse.weight() - 0.5).abs() < 0.001);
|
||||
assert!((synapse.eligibility_trace()).abs() < 0.001);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_btsp_synapse_invalid_weight() {
|
||||
let result = BTSPSynapse::new(-0.1, 2000.0);
|
||||
assert!(result.is_err());
|
||||
|
||||
let result = BTSPSynapse::new(1.1, 2000.0);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_btsp_layer_forward() {
|
||||
let layer = BTSPLayer::new(10, 2000.0);
|
||||
let input = vec![0.1; 10];
|
||||
let output = layer.forward(&input).expect("Should compute forward");
|
||||
assert!(output >= 0.0);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_btsp_one_shot_learning() {
|
||||
let mut layer = BTSPLayer::new(50, 2000.0);
|
||||
let pattern = vec![0.1; 50];
|
||||
let target = 0.8;
|
||||
|
||||
layer
|
||||
.one_shot_associate(&pattern, target)
|
||||
.expect("Should learn");
|
||||
|
||||
let output = layer.forward(&pattern).expect("Should compute forward");
|
||||
// One-shot learning should get close to target
|
||||
assert!(
|
||||
(output - target).abs() < 0.5,
|
||||
"Output: {}, Target: {}",
|
||||
output,
|
||||
target
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_btsp_associative_memory() {
|
||||
let mut memory = BTSPAssociativeMemory::new(10, 5);
|
||||
|
||||
let key = vec![0.5; 10];
|
||||
let value = vec![0.1, 0.2, 0.3, 0.4, 0.5];
|
||||
|
||||
memory.store_one_shot(&key, &value).expect("Should store");
|
||||
|
||||
let retrieved = memory.retrieve(&key).expect("Should retrieve");
|
||||
assert_eq!(retrieved.length(), 5);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HDC Tests
|
||||
// ============================================================================
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_random_vector() {
|
||||
let v = Hypervector::random();
|
||||
let count = v.popcount();
|
||||
|
||||
// Random vector should have ~50% bits set
|
||||
assert!(count > 4500 && count < 5500, "Popcount: {}", count);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_from_seed_deterministic() {
|
||||
let v1 = Hypervector::from_seed(42);
|
||||
let v2 = Hypervector::from_seed(42);
|
||||
|
||||
let sim = v1.similarity(&v2);
|
||||
assert!((sim - 1.0).abs() < 0.001, "Similarity should be 1.0");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_bind_commutative() {
|
||||
let a = Hypervector::random();
|
||||
let b = Hypervector::random();
|
||||
|
||||
let ab = a.bind(&b);
|
||||
let ba = b.bind(&a);
|
||||
|
||||
let sim = ab.similarity(&ba);
|
||||
assert!((sim - 1.0).abs() < 0.001, "Binding should be commutative");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_bind_self_inverse() {
|
||||
let a = Hypervector::random();
|
||||
let b = Hypervector::random();
|
||||
|
||||
let bound = a.bind(&b);
|
||||
let unbound = bound.bind(&b);
|
||||
|
||||
let sim = a.similarity(&unbound);
|
||||
assert!((sim - 1.0).abs() < 0.001, "Bind should be self-inverse");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_similarity_bounds() {
|
||||
let a = Hypervector::random();
|
||||
let b = Hypervector::random();
|
||||
|
||||
let sim = a.similarity(&b);
|
||||
assert!(
|
||||
sim >= -1.0 && sim <= 1.0,
|
||||
"Similarity out of bounds: {}",
|
||||
sim
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_memory_store_retrieve() {
|
||||
let mut memory = HdcMemory::new();
|
||||
|
||||
let apple = Hypervector::random();
|
||||
memory.store("apple", apple.clone());
|
||||
|
||||
assert!(memory.has("apple"));
|
||||
assert!(!memory.has("orange"));
|
||||
|
||||
let retrieved = memory.get("apple");
|
||||
assert!(retrieved.is_some());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_hdc_bundle_3() {
|
||||
let a = Hypervector::random();
|
||||
let b = Hypervector::random();
|
||||
let c = Hypervector::random();
|
||||
|
||||
let bundled = Hypervector::bundle_3(&a, &b, &c);
|
||||
|
||||
// Bundled should be similar to all inputs
|
||||
assert!(bundled.similarity(&a) > 0.3, "Should be similar to a");
|
||||
assert!(bundled.similarity(&b) > 0.3, "Should be similar to b");
|
||||
assert!(bundled.similarity(&c) > 0.3, "Should be similar to c");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// WTA Tests
|
||||
// ============================================================================
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_wta_basic_competition() {
|
||||
let mut wta = WTALayer::new(5, 0.5, 0.8).expect("Should create WTA");
|
||||
|
||||
let inputs = vec![0.1, 0.3, 0.9, 0.2, 0.4];
|
||||
let winner = wta.compete(&inputs).expect("Should compete");
|
||||
|
||||
assert_eq!(winner, 2, "Highest activation should win");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_wta_threshold() {
|
||||
let mut wta = WTALayer::new(5, 0.95, 0.8).expect("Should create WTA");
|
||||
|
||||
let inputs = vec![0.1, 0.3, 0.9, 0.2, 0.4];
|
||||
let winner = wta.compete(&inputs).expect("Should compete");
|
||||
|
||||
assert_eq!(winner, -1, "No neuron should exceed threshold");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_wta_soft_competition() {
|
||||
let mut wta = WTALayer::new(5, 0.5, 0.8).expect("Should create WTA");
|
||||
|
||||
let inputs = vec![0.1, 0.3, 0.9, 0.2, 0.4];
|
||||
let activations = wta.compete_soft(&inputs).expect("Should compete soft");
|
||||
|
||||
// Sum should be ~1.0
|
||||
let mut sum = 0.0;
|
||||
for i in 0..activations.length() {
|
||||
sum += activations.get_index(i);
|
||||
}
|
||||
assert!((sum - 1.0).abs() < 0.01, "Activations should sum to 1.0");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_kwta_basic() {
|
||||
let kwta = KWTALayer::new(10, 3).expect("Should create K-WTA");
|
||||
|
||||
let inputs: Vec<f32> = (0..10).map(|i| i as f32).collect();
|
||||
let winners = kwta.select(&inputs).expect("Should select");
|
||||
|
||||
assert_eq!(winners.length(), 3);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_kwta_sparse_activations() {
|
||||
let kwta = KWTALayer::new(10, 3).expect("Should create K-WTA");
|
||||
|
||||
let inputs: Vec<f32> = (0..10).map(|i| i as f32).collect();
|
||||
let sparse = kwta
|
||||
.sparse_activations(&inputs)
|
||||
.expect("Should create sparse");
|
||||
|
||||
assert_eq!(sparse.length(), 10);
|
||||
|
||||
// Count non-zero elements
|
||||
let mut non_zero = 0;
|
||||
for i in 0..sparse.length() {
|
||||
if sparse.get_index(i) != 0.0 {
|
||||
non_zero += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(non_zero, 3, "Should have exactly k non-zero elements");
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Global Workspace Tests
|
||||
// ============================================================================
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_workspace_creation() {
|
||||
let workspace = GlobalWorkspace::new(7);
|
||||
|
||||
assert_eq!(workspace.capacity(), 7);
|
||||
assert_eq!(workspace.len(), 0);
|
||||
assert!(workspace.is_empty());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_workspace_broadcast() {
|
||||
let mut workspace = GlobalWorkspace::new(3);
|
||||
|
||||
let content = vec![1.0, 2.0, 3.0];
|
||||
let item = WorkspaceItem::new(&content, 0.8, 1, 0);
|
||||
|
||||
let accepted = workspace.broadcast(item);
|
||||
assert!(accepted, "Should accept item");
|
||||
assert_eq!(workspace.len(), 1);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_workspace_capacity_limit() {
|
||||
let mut workspace = GlobalWorkspace::new(2);
|
||||
|
||||
// Fill workspace
|
||||
for i in 0..2 {
|
||||
let item = WorkspaceItem::new(&[1.0], 0.9, i as u16, 0);
|
||||
assert!(workspace.broadcast(item), "Should accept item {}", i);
|
||||
}
|
||||
|
||||
assert!(workspace.is_full());
|
||||
|
||||
// Try to add weak item - should fail
|
||||
let weak_item = WorkspaceItem::new(&[1.0], 0.5, 99, 0);
|
||||
let accepted = workspace.broadcast(weak_item);
|
||||
assert!(!accepted, "Should reject weak item");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_workspace_competition() {
|
||||
let mut workspace = GlobalWorkspace::with_threshold(3, 0.2);
|
||||
workspace.set_decay_rate(0.5);
|
||||
|
||||
let item = WorkspaceItem::new(&[1.0], 0.3, 0, 0);
|
||||
workspace.broadcast(item);
|
||||
|
||||
assert_eq!(workspace.len(), 1);
|
||||
|
||||
// After competition, salience = 0.3 * 0.5 = 0.15 < 0.2 threshold
|
||||
workspace.compete();
|
||||
|
||||
assert_eq!(workspace.len(), 0, "Item should be pruned");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_workspace_item_decay() {
|
||||
let mut item = WorkspaceItem::with_decay(&[1.0], 0.8, 1, 0, 0.9, 1000);
|
||||
|
||||
item.apply_decay(1.0);
|
||||
assert!(
|
||||
(item.salience() - 0.72).abs() < 0.01,
|
||||
"Salience should decay"
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Integration Tests
|
||||
// ============================================================================
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_version_info() {
|
||||
let v = version();
|
||||
assert!(!v.is_empty());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_available_mechanisms() {
|
||||
let mechanisms = available_mechanisms();
|
||||
assert!(!mechanisms.is_null());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_performance_targets() {
|
||||
let targets = performance_targets();
|
||||
assert!(!targets.is_null());
|
||||
}
|
||||
Reference in New Issue
Block a user