|
| 1 | +//! #13 Convergent & Divergent Thinking — oscillate between exploration and exploitation. |
| 2 | +//! Science: Guilford (1967), Kanerva (2009), Sutton & Barto (2018). |
| 3 | +
|
| 4 | +use super::super::bgz17_bridge::Base17; |
| 5 | + |
| 6 | +pub fn oscillate(query: &Base17, corpus: &[Base17], rounds: usize) -> (Base17, Vec<f32>) { |
| 7 | + let mut current = query.clone(); |
| 8 | + let mut ratios = Vec::new(); |
| 9 | + for round in 0..rounds { |
| 10 | + if round % 2 == 0 { |
| 11 | + // Diverge: bundle with farthest neighbors (mean of distant items) |
| 12 | + let mut farthest: Vec<(u32, usize)> = corpus.iter().enumerate() |
| 13 | + .map(|(i, c)| (current.l1(c), i)).collect(); |
| 14 | + farthest.sort_by(|a, b| b.0.cmp(&a.0)); |
| 15 | + let top5: Vec<&Base17> = farthest.iter().take(5).map(|(_, i)| &corpus[*i]).collect(); |
| 16 | + current = bundle_base17(&top5, ¤t); |
| 17 | + ratios.push(1.0); |
| 18 | + } else { |
| 19 | + // Converge: snap to nearest |
| 20 | + let mut best_dist = u32::MAX; |
| 21 | + let mut best = current.clone(); |
| 22 | + for c in corpus { |
| 23 | + let d = current.l1(c); |
| 24 | + if d < best_dist && d > 0 { best_dist = d; best = c.clone(); } |
| 25 | + } |
| 26 | + current = best; |
| 27 | + ratios.push(0.0); |
| 28 | + } |
| 29 | + } |
| 30 | + (current, ratios) |
| 31 | +} |
| 32 | + |
| 33 | +fn bundle_base17(items: &[&Base17], seed: &Base17) -> Base17 { |
| 34 | + let n = items.len() as i32 + 1; |
| 35 | + let mut dims = [0i32; 17]; |
| 36 | + for d in 0..17 { dims[d] += seed.dims[d] as i32; } |
| 37 | + for item in items { for d in 0..17 { dims[d] += item.dims[d] as i32; } } |
| 38 | + let mut result = [0i16; 17]; |
| 39 | + for d in 0..17 { result[d] = (dims[d] / n) as i16; } |
| 40 | + Base17 { dims: result } |
| 41 | +} |
| 42 | + |
| 43 | +#[cfg(test)] |
| 44 | +mod tests { |
| 45 | + use super::*; |
| 46 | + #[test] |
| 47 | + fn test_oscillate() { |
| 48 | + let query = Base17 { dims: [100; 17] }; |
| 49 | + let corpus: Vec<Base17> = (0..20).map(|i| { let mut d = [0i16; 17]; d[0] = (i*50) as i16; Base17 { dims: d } }).collect(); |
| 50 | + let (result, ratios) = oscillate(&query, &corpus, 4); |
| 51 | + assert_eq!(ratios.len(), 4); |
| 52 | + assert_eq!(ratios[0], 1.0); // diverge |
| 53 | + assert_eq!(ratios[1], 0.0); // converge |
| 54 | + } |
| 55 | +} |
0 commit comments