@@ -1721,4 +1721,183 @@ mod tests {
17211721 "NARS revision should improve over best single: {:.1}% vs {:.1}%" ,
17221722 revised_accuracy * 100.0 , best_single_acc * 100.0 ) ;
17231723 }
1724+ #[ test]
1725+ #[ ignore]
1726+ fn test_hotspot_8x8_grid_bundling ( ) {
1727+ // 8×8 grid of 8×8 cells. For each 1/3 intersection, find the 4 hottest
1728+ // neighboring cells (by gradient energy), bundle their features.
1729+
1730+ let bytes = match std:: fs:: read ( "/tmp/tiny_imagenet_labeled.bin" ) {
1731+ Ok ( b) => b,
1732+ Err ( _) => { eprintln ! ( "SKIP: /tmp/tiny_imagenet_labeled.bin not found" ) ; return ; }
1733+ } ;
1734+
1735+ let n = u32:: from_le_bytes ( [ bytes[ 0 ] , bytes[ 1 ] , bytes[ 2 ] , bytes[ 3 ] ] ) as usize ;
1736+ let d = u32:: from_le_bytes ( [ bytes[ 4 ] , bytes[ 5 ] , bytes[ 6 ] , bytes[ 7 ] ] ) as usize ;
1737+ let n_classes = u32:: from_le_bytes ( [ bytes[ 8 ] , bytes[ 9 ] , bytes[ 10 ] , bytes[ 11 ] ] ) as usize ;
1738+ let mut labels = Vec :: with_capacity ( n) ;
1739+ for i in 0 ..n {
1740+ let off = 12 + i * 4 ;
1741+ labels. push ( u32:: from_le_bytes ( [ bytes[ off] , bytes[ off+1 ] , bytes[ off+2 ] , bytes[ off+3 ] ] ) as usize ) ;
1742+ }
1743+ let pixel_start = 12 + n * 4 ;
1744+ let img_w = 64usize ; let img_h = 64usize ; let ch = 3usize ;
1745+ let n_use = n. min ( 200 ) ;
1746+
1747+ let pixel = |img : usize , r : usize , c : usize , channel : usize | -> f64 {
1748+ let off = pixel_start + ( img * d + r * img_w * ch + c * ch + channel) * 4 ;
1749+ f32:: from_le_bytes ( [ bytes[ off] , bytes[ off+1 ] , bytes[ off+2 ] , bytes[ off+3 ] ] ) as f64
1750+ } ;
1751+ let luma = |img : usize , r : usize , c : usize | -> f64 {
1752+ 0.299 * pixel ( img, r, c, 0 ) + 0.587 * pixel ( img, r, c, 1 ) + 0.114 * pixel ( img, r, c, 2 )
1753+ } ;
1754+
1755+ let cell_size = 8usize ; // 8×8 cells
1756+ let grid_w = img_w / cell_size; // 8 cells wide
1757+ let grid_h = img_h / cell_size; // 8 cells tall
1758+ let cell_feat_d = cell_size * cell_size * ch; // 192 features per cell
1759+
1760+ // 1/3 intersections in cell coordinates
1761+ let intersections_cell = [
1762+ ( grid_h / 3 , grid_w / 3 ) , // ~(2,2)
1763+ ( grid_h / 3 , 2 * grid_w / 3 ) , // ~(2,5)
1764+ ( 2 * grid_h / 3 , grid_w / 3 ) , // ~(5,2)
1765+ ( 2 * grid_h / 3 , 2 * grid_w / 3 ) , // ~(5,5)
1766+ ] ;
1767+
1768+ // For each image: for each intersection, find 4 hottest neighboring cells, bundle
1769+ let mut features: Vec < Vec < f64 > > = Vec :: with_capacity ( n_use) ;
1770+
1771+ for img in 0 ..n_use {
1772+ let mut img_features = Vec :: new ( ) ;
1773+
1774+ // Compute gradient energy for each cell
1775+ let mut cell_energy = vec ! [ vec![ 0.0f64 ; grid_w] ; grid_h] ;
1776+ for gr in 0 ..grid_h {
1777+ for gc in 0 ..grid_w {
1778+ let mut energy = 0.0f64 ;
1779+ let r0 = gr * cell_size;
1780+ let c0 = gc * cell_size;
1781+ for r in r0..( r0 + cell_size) {
1782+ for c in c0..( c0 + cell_size) {
1783+ if r > 0 && r < img_h-1 && c > 0 && c < img_w-1 {
1784+ let dx = luma ( img, r, c+1 ) - luma ( img, r, c. saturating_sub ( 1 ) ) ;
1785+ let dy = luma ( img, r+1 , c) - luma ( img, r. saturating_sub ( 1 ) , c) ;
1786+ energy += ( dx* dx + dy* dy) . sqrt ( ) ;
1787+ }
1788+ }
1789+ }
1790+ cell_energy[ gr] [ gc] = energy;
1791+ }
1792+ }
1793+
1794+ // For each intersection, get 4 hottest neighboring cells (2×2 around intersection)
1795+ for & ( ir, ic) in & intersections_cell {
1796+ // Candidate cells: the 4 cells around the intersection point
1797+ let mut candidates: Vec < ( usize , usize , f64 ) > = Vec :: new ( ) ;
1798+ for dr in 0 ..2usize {
1799+ for dc in 0 ..2usize {
1800+ let gr = ( ir + dr) . min ( grid_h - 1 ) ;
1801+ let gc = ( ic + dc) . min ( grid_w - 1 ) ;
1802+ candidates. push ( ( gr, gc, cell_energy[ gr] [ gc] ) ) ;
1803+ }
1804+ }
1805+ // Sort by energy (hottest first) — but we take all 4 for bundling
1806+ candidates. sort_by ( |a, b| b. 2 . partial_cmp ( & a. 2 ) . unwrap ( ) ) ;
1807+
1808+ // Bundle: average the 4 cell feature vectors (majority vote analog for f64)
1809+ let mut bundle = vec ! [ 0.0f64 ; cell_feat_d] ;
1810+ for & ( gr, gc, _) in & candidates {
1811+ let r0 = gr * cell_size;
1812+ let c0 = gc * cell_size;
1813+ let mut idx = 0 ;
1814+ for r in r0..( r0 + cell_size) {
1815+ for c in c0..( c0 + cell_size) {
1816+ for channel in 0 ..ch {
1817+ bundle[ idx] += pixel ( img, r, c, channel) ;
1818+ idx += 1 ;
1819+ }
1820+ }
1821+ }
1822+ }
1823+ // Normalize bundle (mean of 4 cells)
1824+ for v in bundle. iter_mut ( ) { * v /= 4.0 ; }
1825+ img_features. extend_from_slice ( & bundle) ;
1826+ }
1827+
1828+ features. push ( img_features) ;
1829+ }
1830+
1831+ let feat_d = features[ 0 ] . len ( ) ; // 4 intersections × 192 = 768
1832+
1833+ // Build archetypes and classify
1834+ let mut archetypes = vec ! [ vec![ 0.0 ; feat_d] ; n_classes] ;
1835+ let mut counts = vec ! [ 0usize ; n_classes] ;
1836+ for ( i, & l) in labels[ ..n_use] . iter ( ) . enumerate ( ) {
1837+ for j in 0 ..feat_d { archetypes[ l] [ j] += features[ i] [ j] ; }
1838+ counts[ l] += 1 ;
1839+ }
1840+ for c in 0 ..n_classes {
1841+ if counts[ c] > 0 { for j in 0 ..feat_d { archetypes[ c] [ j] /= counts[ c] as f64 ; } }
1842+ }
1843+
1844+ let mut correct = 0usize ;
1845+ for ( i, & true_label) in labels[ ..n_use] . iter ( ) . enumerate ( ) {
1846+ let mut best_c = 0 ;
1847+ let mut best_d = f64:: MAX ;
1848+ for c in 0 ..n_classes {
1849+ if counts[ c] == 0 { continue ; }
1850+ let dist: f64 = features[ i] . iter ( ) . zip ( & archetypes[ c] )
1851+ . map ( |( a, b) | ( a-b) * ( a-b) ) . sum :: < f64 > ( ) . sqrt ( ) ;
1852+ if dist < best_d { best_d = dist; best_c = c; }
1853+ }
1854+ if best_c == true_label { correct += 1 ; }
1855+ }
1856+ let accuracy = correct as f64 / n_use as f64 ;
1857+
1858+ // Also: golden-step compressed
1859+ let base_dim = 17 ; let golden_step = 11 ;
1860+ let compress = |v : & [ f64 ] | -> Vec < f64 > {
1861+ let fd = v. len ( ) ;
1862+ let n_oct = ( fd + base_dim - 1 ) / base_dim;
1863+ let mut sum = vec ! [ 0.0f64 ; base_dim] ;
1864+ let mut cnt = vec ! [ 0u32 ; base_dim] ;
1865+ for oct in 0 ..n_oct {
1866+ for bi in 0 ..base_dim {
1867+ let dim = oct * base_dim + ( ( bi * golden_step) % base_dim) ;
1868+ if dim < fd { sum[ bi] += v[ dim] ; cnt[ bi] += 1 ; }
1869+ }
1870+ }
1871+ sum. iter ( ) . zip ( & cnt) . map ( |( & s, & c) | if c > 0 { s / c as f64 } else { 0.0 } ) . collect ( )
1872+ } ;
1873+ let c_arch: Vec < Vec < f64 > > = archetypes. iter ( ) . map ( |a| compress ( a) ) . collect ( ) ;
1874+ let c_feat: Vec < Vec < f64 > > = features. iter ( ) . map ( |f| compress ( f) ) . collect ( ) ;
1875+ let mut correct_c = 0 ;
1876+ for ( i, & tl) in labels[ ..n_use] . iter ( ) . enumerate ( ) {
1877+ let mut best_c = 0 ; let mut best_d = f64:: MAX ;
1878+ for c in 0 ..n_classes {
1879+ if counts[ c] == 0 { continue ; }
1880+ let dist: f64 = c_feat[ i] . iter ( ) . zip ( & c_arch[ c] ) . map ( |( a, b) |( a-b) * ( a-b) ) . sum :: < f64 > ( ) . sqrt ( ) ;
1881+ if dist < best_d { best_d = dist; best_c = c; }
1882+ }
1883+ if best_c == tl { correct_c += 1 ; }
1884+ }
1885+ let acc_c = correct_c as f64 / n_use as f64 ;
1886+
1887+ eprintln ! ( "=== 8×8 Grid Hotspot Bundling ===" ) ;
1888+ eprintln ! ( " {} images, {} classes" , n_use, n_classes) ;
1889+ eprintln ! ( " Cell size: {}×{}, Grid: {}×{}" , cell_size, cell_size, grid_w, grid_h) ;
1890+ eprintln ! ( " Features: 4 intersections × 4 hot cells bundled × {}D = {}D" , cell_feat_d, feat_d) ;
1891+ eprintln ! ( ) ;
1892+ eprintln ! ( " Hotspot bundle 768D: {:.1}% ({}/{})" , accuracy * 100.0 , correct, n_use) ;
1893+ eprintln ! ( " Compressed 17D (34B): {:.1}% ({}/{})" , acc_c * 100.0 , correct_c, n_use) ;
1894+ eprintln ! ( " Random baseline: {:.1}%" , 100.0 / n_classes as f64 ) ;
1895+ eprintln ! ( ) ;
1896+ eprintln ! ( " Compare all 768D approaches:" ) ;
1897+ eprintln ! ( " Grid lines: 29.8% (4 full scan lines)" ) ;
1898+ eprintln ! ( " Hotspot bundles: {:.1}% (4×4 hot cells at 1/3 points)" , accuracy * 100.0 ) ;
1899+ eprintln ! ( " Centroid focus (432D): 50.5% (single best intersection patch)" ) ;
1900+
1901+ assert ! ( accuracy > 1.0 / n_classes as f64 , "should beat random" ) ;
1902+ }
17241903}
0 commit comments