1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
//! QUBO context-selection spike (#10) — research only, never the default.
//!
//! Context selection under a token budget is a quadratic optimization: maximize
//! total salience while penalizing redundancy between co-selected items and
//! staying within budget. That is naturally a QUBO (quadratic unconstrained
//! binary optimization):
//!
//! ```text
//! minimize E(x) = -Σ φ_i x_i + α Σ_{i<j} sim_ij x_i x_j + β·overflow(x)
//! over x ∈ {0,1}^n
//! ```
//!
//! where `overflow` is the budget violation. QUBO is the form solved by quantum
//! annealers and their classical analogues (simulated annealing / simulated
//! bifurcation). This module provides a *deterministic* simulated-annealing
//! solver (seeded PRNG — no `getrandom`) plus a benchmark harness comparing it to
//! the production greedy knapsack on quality (φ captured) and tokens.
//!
//! IMPORTANT: this is a benchmark spike gated behind `LEAN_CTX_EXPERIMENTAL_QUBO`.
//! It never changes selection defaults; the greedy compiler remains in charge.
//! Promotion is conditional on a measurable win from the harness below.
use crate::core::entropy::jaccard_similarity;
/// Redundancy penalty weight in the QUBO objective.
const ALPHA: f64 = 0.5;
/// Budget-overflow penalty weight (per token over budget). Large so any feasible
/// solution dominates an infeasible one.
const BETA: f64 = 1.0;
/// Annealing iterations. Fixed for determinism and bounded cost.
const SA_ITERS: usize = 4000;
/// `true` when the experimental QUBO spike is enabled. Off by default — the
/// greedy selector stays the default selection path regardless.
pub fn is_enabled() -> bool {
matches!(
std::env::var("LEAN_CTX_EXPERIMENTAL_QUBO")
.ok()
.as_deref()
.map(str::trim),
Some("1" | "true" | "yes" | "on")
)
}
/// A candidate item for QUBO selection.
#[derive(Debug, Clone)]
pub struct QuboItem {
pub id: String,
pub phi: f64,
pub tokens: usize,
/// Content fingerprint for the pairwise redundancy term.
pub sketch: String,
}
/// Deterministic, reproducible PRNG (SplitMix64) — keeps the spike free of
/// `getrandom` so results are byte-stable across runs/machines.
struct SplitMix64(u64);
impl SplitMix64 {
fn new(seed: u64) -> Self {
Self(seed)
}
fn next_u64(&mut self) -> u64 {
self.0 = self.0.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.0;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
fn next_f64(&mut self) -> f64 {
(self.next_u64() >> 11) as f64 / ((1u64 << 53) as f64)
}
fn next_below(&mut self, bound: usize) -> usize {
if bound == 0 {
0
} else {
(self.next_u64() % bound as u64) as usize
}
}
}
/// Precomputed pairwise redundancy (upper triangle), so SA energy deltas are
/// cheap. `sim[i][j]` for `i < j`.
fn redundancy_matrix(items: &[QuboItem]) -> Vec<Vec<f64>> {
let n = items.len();
let mut sim = vec![vec![0.0; n]; n];
for i in 0..n {
for j in (i + 1)..n {
let s = jaccard_similarity(&items[i].sketch, &items[j].sketch);
sim[i][j] = s;
sim[j][i] = s;
}
}
sim
}
fn energy(items: &[QuboItem], sim: &[Vec<f64>], x: &[bool], budget: usize) -> f64 {
let mut e = 0.0;
let mut tokens = 0usize;
for i in 0..items.len() {
if !x[i] {
continue;
}
e -= items[i].phi;
tokens += items[i].tokens;
for j in (i + 1)..items.len() {
if x[j] {
e += ALPHA * sim[i][j];
}
}
}
let overflow = tokens.saturating_sub(budget) as f64;
e + BETA * overflow
}
/// Solve the selection QUBO with deterministic simulated annealing. Returns the
/// indices of selected items. Seeded by a stable hash of the problem so the
/// result is reproducible. Registers activity for `introspect cognition`.
pub fn select(items: &[QuboItem], budget: usize) -> Vec<usize> {
crate::core::introspect::tick("qubo_select");
let n = items.len();
if n == 0 {
return Vec::new();
}
let sim = redundancy_matrix(items);
// Start from the greedy feasible solution — a good basin for SA to refine.
let mut x = greedy_mask(items, budget);
let mut best = x.clone();
let mut best_e = energy(items, &sim, &x, budget);
let mut cur_e = best_e;
let mut rng = SplitMix64::new(problem_seed(items, budget));
for k in 0..SA_ITERS {
// Geometric temperature schedule from 1.0 → ~0.01.
let t = (1.0 - (k as f64 / SA_ITERS as f64)).mul_add(0.99, 0.01);
let i = rng.next_below(n);
x[i] = !x[i];
let new_e = energy(items, &sim, &x, budget);
let delta = new_e - cur_e;
if delta <= 0.0 || rng.next_f64() < (-delta / t).exp() {
cur_e = new_e;
if new_e < best_e {
best_e = new_e;
best.clone_from(&x);
}
} else {
x[i] = !x[i]; // reject: revert
}
}
best.iter()
.enumerate()
.filter_map(|(i, &on)| on.then_some(i))
.collect()
}
/// Greedy feasible selection (efficiency = φ/token, descending) used both as the
/// SA seed and as the benchmark baseline (mirrors the production compiler).
fn greedy_mask(items: &[QuboItem], budget: usize) -> Vec<bool> {
let mut order: Vec<usize> = (0..items.len()).collect();
order.sort_by(|&a, &b| {
let ea = items[a].phi / items[a].tokens.max(1) as f64;
let eb = items[b].phi / items[b].tokens.max(1) as f64;
eb.partial_cmp(&ea)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| items[a].id.cmp(&items[b].id))
});
let mut mask = vec![false; items.len()];
let mut used = 0usize;
for i in order {
if used + items[i].tokens <= budget {
mask[i] = true;
used += items[i].tokens;
}
}
mask
}
/// Stable per-problem seed so SA is reproducible.
fn problem_seed(items: &[QuboItem], budget: usize) -> u64 {
let mut h = budget as u64;
for it in items {
h ^= it.id.bytes().fold(1469598103934665603u64, |acc, b| {
(acc ^ u64::from(b)).wrapping_mul(1099511628211)
});
h = h.wrapping_mul(0x100000001b3).wrapping_add(it.tokens as u64);
}
h
}
/// Result of a QUBO-vs-greedy benchmark run.
#[derive(Debug, Clone)]
pub struct BenchReport {
pub items: usize,
pub budget: usize,
pub greedy_phi: f64,
pub greedy_tokens: usize,
pub qubo_phi: f64,
pub qubo_tokens: usize,
}
impl BenchReport {
/// Total φ captured, relative gain of QUBO over greedy (can be negative).
pub fn phi_gain_pct(&self) -> f64 {
if self.greedy_phi <= 0.0 {
return 0.0;
}
(self.qubo_phi - self.greedy_phi) / self.greedy_phi * 100.0
}
pub fn format(&self) -> String {
format!(
"QUBO spike (experimental, greedy stays default)\n\
items={} budget={}\n\
greedy: phi={:.3} tokens={}\n\
qubo: phi={:.3} tokens={}\n\
phi gain: {:+.1}%",
self.items,
self.budget,
self.greedy_phi,
self.greedy_tokens,
self.qubo_phi,
self.qubo_tokens,
self.phi_gain_pct(),
)
}
}
fn captured(items: &[QuboItem], idx: &[usize]) -> (f64, usize) {
idx.iter().fold((0.0, 0usize), |(p, t), &i| {
(p + items[i].phi, t + items[i].tokens)
})
}
/// Run the QUBO-vs-greedy benchmark on a problem. Pure and deterministic.
pub fn benchmark(items: &[QuboItem], budget: usize) -> BenchReport {
let greedy: Vec<usize> = greedy_mask(items, budget)
.iter()
.enumerate()
.filter_map(|(i, &on)| on.then_some(i))
.collect();
let qubo = select(items, budget);
let (greedy_phi, greedy_tokens) = captured(items, &greedy);
let (qubo_phi, qubo_tokens) = captured(items, &qubo);
BenchReport {
items: items.len(),
budget,
greedy_phi,
greedy_tokens,
qubo_phi,
qubo_tokens,
}
}
/// A deterministic synthetic problem for the CLI harness: clusters of redundant
/// items plus unique high-φ items, so QUBO's redundancy awareness can show.
pub fn synthetic_problem() -> (Vec<QuboItem>, usize) {
let mut items = Vec::new();
// Three near-duplicate clusters (same sketch) of medium φ.
for cluster in 0..3 {
for k in 0..3 {
items.push(QuboItem {
id: format!("dup{cluster}_{k}"),
phi: 0.6,
tokens: 300,
sketch: format!("cluster {cluster} shared redundant content body"),
});
}
}
// Unique high-φ items with genuinely distinct content (no shared words, so
// the redundancy term reflects only the intended duplicate clusters).
let unique_sketches = [
"kepler orbital mechanics ellipse perihelion",
"ribosome translation codon peptide synthesis",
"byzantine consensus quorum fault tolerance",
"monsoon humidity evaporation precipitation cycle",
];
for (u, sketch) in unique_sketches.iter().enumerate() {
items.push(QuboItem {
id: format!("uniq{u}"),
phi: 0.8,
tokens: 300,
sketch: (*sketch).to_string(),
});
}
(items, 1500)
}
#[cfg(test)]
mod tests {
use super::*;
fn items() -> Vec<QuboItem> {
synthetic_problem().0
}
#[test]
fn disabled_by_default() {
// Spike must be opt-in; greedy stays default. Serialize env access through
// the shared test lock so this never races other env-reading tests.
let _lock = crate::core::data_dir::test_env_lock();
crate::test_env::remove_var("LEAN_CTX_EXPERIMENTAL_QUBO");
assert!(!is_enabled());
}
#[test]
fn selection_respects_budget() {
let it = items();
let budget = 1500;
let sel = select(&it, budget);
let (_, tokens) = captured(&it, &sel);
assert!(tokens <= budget, "QUBO must not exceed budget: {tokens}");
}
#[test]
fn selection_is_deterministic() {
// Determinism contract (#498): seeded SA → identical selection each run.
let it = items();
let a = select(&it, 1500);
let b = select(&it, 1500);
assert_eq!(a, b, "seeded SA must be reproducible");
}
#[test]
fn benchmark_runs_and_reports() {
let (it, budget) = synthetic_problem();
let report = benchmark(&it, budget);
assert_eq!(report.items, it.len());
assert!(report.greedy_phi > 0.0);
assert!(report.qubo_phi > 0.0);
// Both stay within budget.
assert!(report.greedy_tokens <= budget);
assert!(report.qubo_tokens <= budget);
// Report formats without panicking.
assert!(report.format().contains("QUBO spike"));
}
#[test]
fn empty_problem_selects_nothing() {
assert!(select(&[], 1000).is_empty());
}
}