code wiki / (root) / nx_cosine_similarity.nx

nx_cosine_similarity.nx source

↩ module page · 165 lines · 6317 B

1// nx_cosine_similarity.nx -- signed Q10 cosine between two vectors. 2// 3// Universal vector-space similarity. Same primitive over any nx_int 4// feature vectors of equal length: image-feature embeddings (for the 5// "AI grows by ingesting image" textual-inversion roadmap), audio 6// MFCC frames, token frequency histograms, latent embeddings, 7// document term vectors, code AST-bag features. 8// 9// Math: 10// cos(theta) = dot(a, b) / (||a|| * ||b||) 11// dot(a, b) = sum a[i] * b[i] 12// ||a|| = sqrt(dot(a, a)) 13// 14// All math nx_int. Newton-Raphson integer sqrt (O(log n) iterations, 15// no f64). Output signed Q10 in [-Q, +Q]: 16// +Q = parallel (same direction) 17// 0 = orthogonal 18// -Q = anti-parallel (opposite direction) 19// 20// Sealed-enum bands (substrate dual-reading cardinal): 21// NX_COSINE_BAND_ANTIPARALLEL cos <= -921 (essentially -1) 22// NX_COSINE_BAND_OPPOSED cos < -307 23// NX_COSINE_BAND_ORTHOGONAL -307 <= cos <= +307 24// NX_COSINE_BAND_ALIGNED cos > +307 25// NX_COSINE_BAND_PARALLEL cos >= +921 26// 27// USE CASES (image-gen + general): 28// - concept-embedding lookup: incoming "new outfit" image -> feature 29// vector -> nearest concept in nishi-library concept store. 30// - prompt similarity over learned embeddings (next layer above 31// string-similarity). 32// - clustering: pairwise cosine grid + hierarchical merge. 33// - recommendation: user-liked-image features cosine-compared 34// against gallery features. 35// 36// EDGE CASES: 37// - empty vectors (n == 0) -> return 0 (orthogonal-by-vacuum) 38// - zero vector (norm == 0) -> return 0 (cosine undefined) 39// - length mismatch -> NX_COSINE_LENGTH_MISMATCH sentinel 40// 41// OVERFLOW NOTE: dot product accumulates n * max(|a_i| * |b_i|). 42// For n = 1024 and |a_i|, |b_i| <= Q10 = 1024, max dot = 1024 * 43// 1024 * 1024 ~ 1.07e9 << i64 ceiling. Larger vectors or wider 44// component ranges may require nx_int -> nx_i128 swap via nx_tier. 45// The substrate carries the dot-product magnitude implicitly via 46// the norm computation; under typical Q10 embedding ranges this is 47// fine. 48// 49// Idea-provenance (patent-clean): Salton 1971 SMART system + 50// Singhal 2001 modern IR survey + Newton-Raphson 1685 integer 51// sqrt. Re-derived from public research; no source code referenced. 52// 53// genealogy_id: salton_1971_smart + singhal_2001_modern_ir + 54// newton_raphson_1685 + bracewell_1965_fourier 55// lineage_id: cosine_similarity_q10_signed 56 57// nx_safety_envelope: 58// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 59// sil_target: SIL1 60// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 61// verdict: NOT_YET_EVALUATED 62 63import "nx_syscalls.nx" 64import "nx_tier.nx" 65 66const NX_COSINE_Q: nx_int = 1024 67const NX_COSINE_LENGTH_MISMATCH: nx_int = -2147483647 // sentinel 68 69// Sealed-enum bands 70const NX_COSINE_BAND_ANTIPARALLEL: nx_int = 0 71const NX_COSINE_BAND_OPPOSED: nx_int = 1 72const NX_COSINE_BAND_ORTHOGONAL: nx_int = 2 73const NX_COSINE_BAND_ALIGNED: nx_int = 3 74const NX_COSINE_BAND_PARALLEL: nx_int = 4 75const NX_COSINE_N_BANDS: nx_int = 5 76 77// ===== Newton-Raphson integer sqrt =================================== 78// 79// Returns floor(sqrt(n)) for n >= 0. Converges in O(log n) iterations. 80// Standard textbook integer-sqrt; bit-identical across architectures. 81 82func _cosine_isqrt(n: nx_int) -> nx_int { 83 if n < 0 { return 0 } 84 if n < 2 { return n } 85 var x: nx_int = n 86 var y: nx_int = (x + 1) / 2 87 while y < x { 88 x = y 89 y = (x + n / x) / 2 90 } 91 return x 92} 93 94// ===== Dot product =================================================== 95 96func _cosine_dot(a: *nx_int, b: *nx_int, n: nx_int) -> nx_int { 97 var sum: nx_int = 0 98 var i: nx_int = 0 99 while i < n { 100 sum = sum + a[i] * b[i] 101 i = i + 1 102 } 103 return sum 104} 105 106// ===== Public cosine ================================================= 107// 108// Computes signed Q10 cosine. Returns NX_COSINE_LENGTH_MISMATCH if 109// the two vectors have different lengths (caller's contract violation). 110// Returns 0 for any zero-vector or empty input. 111 112func nx_cosine_similarity(a: *nx_int, n_a: nx_int, b: *nx_int, n_b: nx_int) -> nx_int { 113 if n_a != n_b { return NX_COSINE_LENGTH_MISMATCH } 114 if n_a == 0 { return 0 } 115 116 let dot_ab: nx_int = _cosine_dot(a, b, n_a) 117 let norm_a_sq: nx_int = _cosine_dot(a, a, n_a) 118 let norm_b_sq: nx_int = _cosine_dot(b, b, n_a) 119 if norm_a_sq == 0 { return 0 } 120 if norm_b_sq == 0 { return 0 } 121 122 let norm_a: nx_int = _cosine_isqrt(norm_a_sq) 123 let norm_b: nx_int = _cosine_isqrt(norm_b_sq) 124 if norm_a == 0 { return 0 } 125 if norm_b == 0 { return 0 } 126 127 // cos_q10 = dot * Q / (norm_a * norm_b) 128 // For signed dot, the sign propagates through the division. 129 let denom: nx_int = norm_a * norm_b 130 if denom == 0 { return 0 } 131 var cos_q10: nx_int = (dot_ab * NX_COSINE_Q) / denom 132 133 // Clamp to [-Q, +Q] -- guards against accumulated rounding error 134 // in cases where ||a||*||b|| is slightly off floor(sqrt(...)). 135 if cos_q10 > NX_COSINE_Q { cos_q10 = NX_COSINE_Q } 136 if cos_q10 < (0 - NX_COSINE_Q) { cos_q10 = 0 - NX_COSINE_Q } 137 return cos_q10 138} 139 140// ===== Qualitative band classifier ================================== 141 142func nx_cosine_classify(cos_q10: nx_int) -> nx_int { 143 if cos_q10 <= (0 - 921) { return NX_COSINE_BAND_ANTIPARALLEL } 144 if cos_q10 < (0 - 307) { return NX_COSINE_BAND_OPPOSED } 145 if cos_q10 <= 307 { return NX_COSINE_BAND_ORTHOGONAL } 146 if cos_q10 < 921 { return NX_COSINE_BAND_ALIGNED } 147 return NX_COSINE_BAND_PARALLEL 148} 149 150func nx_cosine_band_is_valid(band: nx_int) -> nx_int { 151 if band < 0 { return 0 } 152 if band >= NX_COSINE_N_BANDS { return 0 } 153 return 1 154} 155 156// ===== Convenience: cosine distance = 1 - cosine_similarity ========= 157// 158// Distance in [0, 2*Q] for general vectors, [0, Q] for non-negative. 159// Useful when clustering algorithms want a non-negative dissimilarity. 160 161func nx_cosine_distance(a: *nx_int, n_a: nx_int, b: *nx_int, n_b: nx_int) -> nx_int { 162 let s: nx_int = nx_cosine_similarity(a, n_a, b, n_b) 163 if s == NX_COSINE_LENGTH_MISMATCH { return NX_COSINE_LENGTH_MISMATCH } 164 return NX_COSINE_Q - s 165}