1use std::cmp::Ordering;
2use std::collections::BinaryHeap;
3use std::sync::Arc;
4
5use rustc_hash::{FxHashMap, FxHashSet};
6
7use crate::config::limits::UTILITY;
8use crate::config::selection::selection;
9use crate::interval::IntervalIndex;
10use crate::types::{Fragment, FragmentId};
11use crate::utility::needs::InformationNeed;
12use crate::utility::scoring::{
13 UtilityState, apply_fragment, compute_density, marginal_gain, utility_value,
14};
15
16const SENTINEL_TOKEN_COUNT: u32 = 1_000_000_000;
17
18fn selection_cost(selected: &[Fragment]) -> u32 {
22 selected.iter().map(|f| f.token_count).sum()
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum SelectionReason {
27 TopK,
28 NoCandidates,
29 BudgetExhausted,
30 NoUtility,
31 StoppedByTau,
32 BestSingleton,
33}
34
35impl SelectionReason {
36 pub fn as_str(&self) -> &'static str {
37 match self {
38 Self::TopK => "topk",
39 Self::NoCandidates => "no_candidates",
40 Self::BudgetExhausted => "budget_exhausted",
41 Self::NoUtility => "no_utility",
42 Self::StoppedByTau => "stopped_by_tau",
43 Self::BestSingleton => "best_singleton",
44 }
45 }
46}
47
48pub struct SelectionResult {
49 pub selected: Vec<Fragment>,
50 pub reason: SelectionReason,
51 pub used_tokens: u32,
52 pub utility: f64,
53 pub greedy_iters: usize,
58 pub stopping_certificate: f64,
63}
64
65struct HeapEntry {
66 neg_density: f64,
67 frag_id: FragmentId,
68 version: u32,
69}
70
71impl PartialEq for HeapEntry {
72 fn eq(&self, other: &Self) -> bool {
73 self.neg_density.to_bits() == other.neg_density.to_bits() && self.frag_id == other.frag_id
74 }
75}
76
77impl Eq for HeapEntry {}
78
79impl PartialOrd for HeapEntry {
80 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
81 Some(self.cmp(other))
82 }
83}
84
85impl Ord for HeapEntry {
86 fn cmp(&self, other: &Self) -> Ordering {
87 other
88 .neg_density
89 .total_cmp(&self.neg_density)
90 .then_with(|| other.frag_id.cmp(&self.frag_id))
91 }
92}
93
94struct SelectionState {
95 selected: Vec<Fragment>,
96 selected_ids: IntervalIndex,
97 remaining_budget: u32,
98 utility_state: UtilityState,
99}
100
101fn drop_redundant_signatures(candidates: &[Fragment], budget: u32) -> Vec<Fragment> {
102 let mut full_token_by_loc: FxHashMap<(Arc<str>, u32), u32> = FxHashMap::default();
103 for f in candidates {
104 if !f.kind.is_signature() {
105 full_token_by_loc
114 .entry((f.id.path.clone(), f.start_line()))
115 .and_modify(|t| *t = (*t).max(f.token_count))
116 .or_insert(f.token_count);
117 }
118 }
119 candidates
120 .iter()
121 .filter(|f| {
122 if !f.kind.is_signature() {
123 return true;
124 }
125 let key = (f.id.path.clone(), f.start_line());
126 full_token_by_loc
127 .get(&key)
128 .copied()
129 .unwrap_or(SENTINEL_TOKEN_COUNT)
130 > budget
131 })
132 .cloned()
133 .collect()
134}
135
136fn compute_r_cap(
137 rel: &FxHashMap<FragmentId, f64>,
138 core_ids: Option<&FxHashSet<FragmentId>>,
139) -> f64 {
140 let values: Vec<f64> = rel
141 .iter()
142 .filter(|(fid, v)| **v > 0.0 && core_ids.map_or(true, |c| !c.contains(*fid)))
143 .map(|(_, v)| *v)
144 .collect();
145
146 if values.len() < 2 {
147 return if let Some(&v) = values.first() {
148 v.max(selection().r_cap_min)
149 } else {
150 1.0
151 };
152 }
153
154 let mut sorted = values.clone();
155 sorted.sort_by(|a, b| a.total_cmp(b));
156 let mid = sorted.len() / 2;
157 let med = if sorted.len() % 2 == 0 {
158 (sorted[mid - 1] + sorted[mid]) / 2.0
159 } else {
160 sorted[mid]
161 };
162
163 let mean: f64 = values.iter().sum::<f64>() / values.len() as f64;
164 let variance: f64 =
165 values.iter().map(|v| (v - mean).powi(2)).sum::<f64>() / (values.len() - 1) as f64;
166 let std = variance.sqrt();
167
168 (med + UTILITY.r_cap_sigma * std).max(1e-9)
169}
170
171fn build_signature_lookup(
172 fragments: &[Fragment],
173 core_fragments: &[Fragment],
174 core_excerpts: Option<&FxHashMap<FragmentId, Fragment>>,
175) -> FxHashMap<FragmentId, Fragment> {
176 let mut sig_by_loc: FxHashMap<(Arc<str>, u32), Fragment> = FxHashMap::default();
177 for f in fragments {
178 if f.kind.is_signature() {
179 sig_by_loc.insert((f.id.path.clone(), f.start_line()), f.clone());
180 }
181 }
182 let mut sig_lookup = FxHashMap::default();
183 for cf in core_fragments {
184 let key = (cf.id.path.clone(), cf.start_line());
185 if let Some(sig) = sig_by_loc.get(&key) {
186 sig_lookup.insert(cf.id.clone(), sig.clone());
187 continue;
188 }
189 if let Some(excerpt) = core_excerpts.and_then(|e| e.get(&cf.id)) {
193 sig_lookup.insert(cf.id.clone(), excerpt.clone());
194 }
195 }
196 sig_lookup
197}
198
199fn select_core_fragments(
200 core_fragments: &[Fragment],
201 rel: &FxHashMap<FragmentId, f64>,
202 needs: &[InformationNeed],
203 state: &mut SelectionState,
204 budget_tokens: u32,
205 sig_lookup: &FxHashMap<FragmentId, Fragment>,
206 core_excerpts: Option<&FxHashMap<FragmentId, Fragment>>,
207) -> FxHashSet<FragmentId> {
208 let mut satisfied: FxHashSet<FragmentId> = FxHashSet::default();
213 let sel_cfg = selection();
214 let core_budget = (budget_tokens as f64 * sel_cfg.core_budget_fraction) as u32;
215 let file_ceiling = (budget_tokens as f64 * sel_cfg.per_file_budget_fraction) as u32;
219 let mut file_spent: FxHashMap<Arc<str>, u32> = FxHashMap::default();
220 let mut core_used = 0u32;
224
225 let mut sorted_core: Vec<&Fragment> = core_fragments.iter().collect();
226 sorted_core.sort_by(|a, b| {
227 let ra = rel.get(&a.id).copied().unwrap_or(0.0);
228 let rb = rel.get(&b.id).copied().unwrap_or(0.0);
229 rb.total_cmp(&ra)
230 });
231
232 let place_fragment = |frag: &Fragment,
233 core_used: &mut u32,
234 state: &mut SelectionState,
235 rel_score: f64,
236 file_spent: &mut FxHashMap<Arc<str>, u32>| {
237 state.selected.push(frag.clone());
238 state.selected_ids.add_id(&frag.id);
239 state.remaining_budget = state.remaining_budget.saturating_sub(frag.token_count);
240 *core_used += frag.token_count;
241 *file_spent.entry(frag.id.path.clone()).or_insert(0) += frag.token_count;
242 apply_fragment(frag, rel_score, needs, &mut state.utility_state);
243 };
244
245 let mut skipped: Vec<(FragmentId, &Fragment)> = Vec::new();
248 for frag in &sorted_core {
249 let core_id = frag.id.clone();
255 let frag: &Fragment = core_excerpts
256 .and_then(|e| e.get(&frag.id))
257 .filter(|excerpt| crate::excerpt::is_downshift_worthwhile(frag, excerpt))
258 .unwrap_or(frag);
259 if state.selected_ids.is_superset_of(frag) {
260 satisfied.insert(core_id);
261 continue;
262 }
263 let spent = file_spent.get(&frag.id.path).copied().unwrap_or(0);
264 let over_file_ceiling = spent > 0 && spent + frag.token_count > file_ceiling;
265 if core_used + frag.token_count > core_budget || over_file_ceiling {
266 if let Some(sig) = sig_lookup.get(&core_id) {
267 let sig_over_ceiling = spent > 0 && spent + sig.token_count > file_ceiling;
272 if !state.selected_ids.contains(&sig.id)
273 && core_used + sig.token_count <= core_budget
274 && !sig_over_ceiling
275 {
276 let rel_score = rel.get(&core_id).copied().unwrap_or(0.0);
277 place_fragment(sig, &mut core_used, state, rel_score, &mut file_spent);
278 satisfied.insert(core_id);
279 continue;
280 }
281 }
282 skipped.push((core_id, frag));
283 continue;
284 }
285
286 let rel_score = rel.get(&core_id).copied().unwrap_or(0.0);
287 place_fragment(frag, &mut core_used, state, rel_score, &mut file_spent);
288 satisfied.insert(core_id);
289 }
290
291 if !skipped.is_empty() {
297 skipped.sort_by(|(_, a), (_, b)| a.token_count.cmp(&b.token_count));
298 for (core_id, frag) in skipped {
299 if state.remaining_budget == 0 {
300 break;
301 }
302 if state.selected_ids.is_superset_of(frag) {
303 satisfied.insert(core_id);
304 continue;
305 }
306 let rel_score = rel.get(&core_id).copied().unwrap_or(0.0);
307 if frag.token_count <= state.remaining_budget {
308 place_fragment(frag, &mut core_used, state, rel_score, &mut file_spent);
309 satisfied.insert(core_id);
310 } else if let Some(sig) = sig_lookup.get(&core_id) {
311 if !state.selected_ids.contains(&sig.id)
312 && sig.token_count <= state.remaining_budget
313 {
314 place_fragment(sig, &mut core_used, state, rel_score, &mut file_spent);
315 satisfied.insert(core_id);
316 }
317 }
318 }
319 }
320
321 satisfied
322}
323
324fn build_initial_heap(
325 candidates: &[Fragment],
326 rel: &FxHashMap<FragmentId, f64>,
327 needs: &[InformationNeed],
328 state: &UtilityState,
329 id_to_frag: &mut FxHashMap<FragmentId, Fragment>,
330) -> BinaryHeap<HeapEntry> {
331 let mut heap = BinaryHeap::new();
332 for frag in candidates {
333 if frag.token_count > 0 {
334 let density = compute_density(
335 frag,
336 rel.get(&frag.id).copied().unwrap_or(0.0),
337 needs,
338 state,
339 );
340 heap.push(HeapEntry {
341 neg_density: -density,
342 frag_id: frag.id.clone(),
343 version: 0,
344 });
345 id_to_frag.insert(frag.id.clone(), frag.clone());
346 }
347 }
348 heap
349}
350
351fn find_best_candidate_heap(
352 heap: &mut BinaryHeap<HeapEntry>,
353 current_version: u32,
354 id_to_frag: &FxHashMap<FragmentId, Fragment>,
355 selected_ids: &IntervalIndex,
356 remaining_budget: u32,
357 rel: &FxHashMap<FragmentId, f64>,
358 needs: &[InformationNeed],
359 state: &UtilityState,
360) -> (Option<Fragment>, f64, u32) {
361 let cv = current_version;
362 while let Some(entry) = heap.pop() {
363 let frag = match id_to_frag.get(&entry.frag_id) {
364 Some(f) => f,
365 None => continue,
366 };
367 if frag.token_count > remaining_budget {
368 continue;
369 }
370 if selected_ids.overlaps(frag) {
371 continue;
372 }
373 if entry.version < cv {
374 let new_density = compute_density(
375 frag,
376 rel.get(&frag.id).copied().unwrap_or(0.0),
377 needs,
378 state,
379 );
380 heap.push(HeapEntry {
381 neg_density: -new_density,
382 frag_id: frag.id.clone(),
383 version: cv,
384 });
385 continue;
386 }
387 let actual_density = -entry.neg_density;
388 if actual_density <= 0.0 {
389 return (None, 0.0, cv);
390 }
391 return (Some(frag.clone()), actual_density, cv + 1);
392 }
393 (None, 0.0, cv)
394}
395
396fn find_best_singleton(
397 non_core: &[Fragment],
398 base_selected_ids: &IntervalIndex,
399 base_budget: u32,
400 rel: &FxHashMap<FragmentId, f64>,
401 needs: &[InformationNeed],
402 base_state: &UtilityState,
403) -> (Option<Fragment>, f64) {
404 let mut best_singleton = None;
405 let mut best_gain = 0.0;
406 for f in non_core {
407 if f.token_count > base_budget {
408 continue;
409 }
410 if base_selected_ids.overlaps(f) {
411 continue;
412 }
413 let gain = marginal_gain(f, rel.get(&f.id).copied().unwrap_or(0.0), needs, base_state);
414 if gain > best_gain {
415 best_gain = gain;
416 best_singleton = Some(f.clone());
417 }
418 }
419 (best_singleton, best_gain)
420}
421
422fn find_best_singleton_full_set(
434 fragments: &[Fragment],
435 budget_tokens: u32,
436 rel: &FxHashMap<FragmentId, f64>,
437 needs: &[InformationNeed],
438 empty_state: &UtilityState,
439) -> (Option<Fragment>, f64) {
440 let mut best = None;
441 let mut best_gain = 0.0;
442 for f in fragments {
443 if f.token_count == 0 || f.token_count > budget_tokens {
444 continue;
445 }
446 let gain = marginal_gain(
447 f,
448 rel.get(&f.id).copied().unwrap_or(0.0),
449 needs,
450 empty_state,
451 );
452 if gain > best_gain {
453 best_gain = gain;
454 best = Some(f.clone());
455 }
456 }
457 (best, best_gain)
458}
459
460fn init_selection_state(
461 core_ids: &FxHashSet<FragmentId>,
462 rel: &FxHashMap<FragmentId, f64>,
463 budget_tokens: u32,
464 file_importance: Option<&FxHashMap<Arc<str>, f64>>,
465) -> SelectionState {
466 let mut utility_state = UtilityState::default();
467 utility_state.r_cap = compute_r_cap(rel, Some(core_ids));
468 utility_state.changed_dirs = core_ids
469 .iter()
470 .filter_map(|cid| {
471 std::path::Path::new(cid.path.as_ref())
472 .parent()
473 .map(|p| p.to_path_buf())
474 })
475 .collect();
476 if let Some(fi) = file_importance {
477 utility_state.file_importance.clone_from(fi);
478 }
479 SelectionState {
480 selected: Vec::new(),
481 selected_ids: IntervalIndex::new(),
482 remaining_budget: budget_tokens,
483 utility_state,
484 }
485}
486
487#[allow(clippy::too_many_arguments)]
488fn run_greedy_loop_heap(
489 heap: &mut BinaryHeap<HeapEntry>,
490 id_to_frag: &FxHashMap<FragmentId, Fragment>,
491 state: &mut SelectionState,
492 rel: &FxHashMap<FragmentId, f64>,
493 needs: &[InformationNeed],
494 tau: f64,
495 _initial_budget: u32,
496 admissible_files: Option<&FxHashSet<Arc<str>>>,
497) -> (usize, f64, usize) {
498 let mut current_version = 0u32;
499 let mut peak_density: f64 = 0.0;
500 let mut loop_iters: usize = 0;
501 let mut open_files: FxHashSet<Arc<str>> =
507 state.selected.iter().map(|f| f.id.path.clone()).collect();
508 let file_ceiling = (_initial_budget as f64 * selection().per_file_budget_fraction) as u32;
514 let mut file_spent: FxHashMap<Arc<str>, u32> = FxHashMap::default();
515 for f in &state.selected {
516 *file_spent.entry(f.id.path.clone()).or_insert(0) += f.token_count;
517 }
518 let mut deferred: Vec<HeapEntry> = Vec::new();
519 let mut ceiling_active = true;
520
521 loop {
522 while !heap.is_empty() && state.remaining_budget > 0 {
523 loop_iters += 1;
524 let (best_frag, best_density, new_version) = find_best_candidate_heap(
525 heap,
526 current_version,
527 id_to_frag,
528 &state.selected_ids,
529 state.remaining_budget,
530 rel,
531 needs,
532 &state.utility_state,
533 );
534 current_version = new_version;
535
536 let best_frag = match best_frag {
537 Some(f) => f,
538 None => break,
539 };
540 if best_density <= 0.0 {
541 break;
542 }
543
544 if let Some(admissible) = admissible_files {
545 if !open_files.contains(&best_frag.id.path)
546 && !admissible.contains(&best_frag.id.path)
547 {
548 continue;
549 }
550 }
551
552 if ceiling_active {
553 let spent = file_spent.get(&best_frag.id.path).copied().unwrap_or(0);
554 if spent > 0 && spent + best_frag.token_count > file_ceiling {
555 deferred.push(HeapEntry {
556 neg_density: -best_density,
557 frag_id: best_frag.id.clone(),
558 version: current_version,
559 });
560 continue;
561 }
562 }
563
564 if best_density > peak_density {
565 peak_density = best_density;
566 } else if peak_density > 0.0 && best_density < tau * peak_density {
567 break;
568 }
569
570 open_files.insert(best_frag.id.path.clone());
571 *file_spent.entry(best_frag.id.path.clone()).or_insert(0) += best_frag.token_count;
572 state.selected.push(best_frag.clone());
573 state.selected_ids.add_id(&best_frag.id);
574 state.remaining_budget = state.remaining_budget.saturating_sub(best_frag.token_count);
575 let rel_score = rel.get(&best_frag.id).copied().unwrap_or(0.0);
576 apply_fragment(&best_frag, rel_score, needs, &mut state.utility_state);
577 }
578
579 if ceiling_active && !deferred.is_empty() && state.remaining_budget > 0 {
580 ceiling_active = false;
581 for e in deferred.drain(..) {
582 heap.push(e);
583 }
584 continue;
585 }
586 break;
587 }
588
589 let threshold = tau * peak_density;
590 (state.selected.len(), threshold, loop_iters)
591}
592
593fn setup_and_select_core(
594 fragments: &[Fragment],
595 core_ids: &FxHashSet<FragmentId>,
596 rel: &FxHashMap<FragmentId, f64>,
597 needs: &[InformationNeed],
598 budget_tokens: u32,
599 file_importance: Option<&FxHashMap<Arc<str>, f64>>,
600 core_excerpts: Option<&FxHashMap<FragmentId, Fragment>>,
601) -> (SelectionState, Vec<Fragment>, Vec<Fragment>, bool) {
602 let mut core_fragments: Vec<Fragment> = fragments
603 .iter()
604 .filter(|f| core_ids.contains(&f.id))
605 .cloned()
606 .collect();
607 core_fragments.sort_by(|a, b| {
608 let ta = if a.token_count > 0 {
609 a.token_count
610 } else {
611 SENTINEL_TOKEN_COUNT
612 };
613 let tb = if b.token_count > 0 {
614 b.token_count
615 } else {
616 SENTINEL_TOKEN_COUNT
617 };
618 ta.cmp(&tb)
619 .then(a.line_count().cmp(&b.line_count()))
620 .then(a.start_line().cmp(&b.start_line()))
621 });
622
623 let non_core_fragments: Vec<Fragment> = fragments
624 .iter()
625 .filter(|f| !core_ids.contains(&f.id))
626 .cloned()
627 .collect();
628
629 let sig_lookup = build_signature_lookup(fragments, &core_fragments, core_excerpts);
630 let mut state = init_selection_state(core_ids, rel, budget_tokens, file_importance);
631 let satisfied_core_ids = select_core_fragments(
632 &core_fragments,
633 rel,
634 needs,
635 &mut state,
636 budget_tokens,
637 &sig_lookup,
638 core_excerpts,
639 );
640
641 let skipped_core: Vec<FragmentId> = core_ids
646 .iter()
647 .filter(|id| !satisfied_core_ids.contains(*id))
648 .cloned()
649 .collect();
650
651 let mut non_core_with_skipped = non_core_fragments;
652 if !skipped_core.is_empty() {
653 let skipped_set: FxHashSet<FragmentId> = skipped_core.into_iter().collect();
654 for cf in &core_fragments {
655 if skipped_set.contains(&cf.id) {
656 non_core_with_skipped.push(cf.clone());
657 }
658 }
659 }
660
661 let should_return_early = state.remaining_budget == 0;
662 let selected_copy = state.selected.clone();
663 (
664 state,
665 non_core_with_skipped,
666 selected_copy,
667 should_return_early,
668 )
669}
670
671pub fn lazy_greedy_select(
672 fragments: Vec<Fragment>,
673 core_ids: &FxHashSet<FragmentId>,
674 rel: &FxHashMap<FragmentId, f64>,
675 needs: &[InformationNeed],
676 budget_tokens: u32,
677 tau: f64,
678 file_importance: Option<&FxHashMap<Arc<str>, f64>>,
679 core_excerpts: Option<&FxHashMap<FragmentId, Fragment>>,
680 admissible_files: Option<&FxHashSet<Arc<str>>>,
681) -> SelectionResult {
682 if fragments.is_empty() {
683 return SelectionResult {
684 selected: Vec::new(),
685 reason: SelectionReason::NoCandidates,
686 used_tokens: 0,
687 utility: 0.0,
688 greedy_iters: 0,
689 stopping_certificate: 0.0,
690 };
691 }
692
693 let (mut state, non_core_fragments, _selected_core, should_return_early) =
694 setup_and_select_core(
695 &fragments,
696 core_ids,
697 rel,
698 needs,
699 budget_tokens,
700 file_importance,
701 core_excerpts,
702 );
703
704 if should_return_early {
705 let used = budget_tokens - state.remaining_budget;
706 return SelectionResult {
707 selected: state.selected,
708 reason: SelectionReason::BudgetExhausted,
709 used_tokens: used,
710 utility: utility_value(&state.utility_state),
711 greedy_iters: 0,
712 stopping_certificate: 0.0,
713 };
714 }
715
716 let base_state = state.utility_state.copy();
717 let base_selected = state.selected.clone();
718 let base_budget = state.remaining_budget;
719
720 let candidates: Vec<Fragment> = non_core_fragments
721 .iter()
722 .filter(|f| !state.selected_ids.overlaps(f))
723 .cloned()
724 .collect();
725 let candidates = drop_redundant_signatures(&candidates, state.remaining_budget);
726
727 let mut id_to_frag: FxHashMap<FragmentId, Fragment> = FxHashMap::default();
728 let mut heap = build_initial_heap(
729 &candidates,
730 rel,
731 needs,
732 &state.utility_state,
733 &mut id_to_frag,
734 );
735
736 let (_, threshold, greedy_iters) = run_greedy_loop_heap(
737 &mut heap,
738 &id_to_frag,
739 &mut state,
740 rel,
741 needs,
742 tau,
743 budget_tokens,
744 admissible_files,
745 );
746
747 let greedy_utility = utility_value(&state.utility_state);
748
749 let mut base_selected_ids = IntervalIndex::new();
750 for f in &base_selected {
751 base_selected_ids.add_id(&f.id);
752 }
753
754 let (best_singleton, best_gain) = find_best_singleton(
755 &non_core_fragments,
756 &base_selected_ids,
757 base_budget,
758 rel,
759 needs,
760 &base_state,
761 );
762
763 let empty_state = init_selection_state(core_ids, rel, budget_tokens, file_importance);
764 let (full_singleton, full_singleton_gain) = find_best_singleton_full_set(
765 &fragments,
766 budget_tokens,
767 rel,
768 needs,
769 &empty_state.utility_state,
770 );
771
772 let mut best_alt_utility = greedy_utility;
773 let mut best_alt: Option<(u32, Vec<Fragment>)> = None;
774
775 if let Some(ref singleton) = best_singleton {
776 let u = utility_value(&base_state) + best_gain;
777 if u > best_alt_utility {
778 best_alt_utility = u;
779 let mut sel = base_selected.clone();
780 sel.push(singleton.clone());
781 best_alt = Some((selection_cost(&sel), sel));
782 }
783 }
784
785 if let Some(ref full) = full_singleton {
786 let u = utility_value(&empty_state.utility_state) + full_singleton_gain;
787 let already_selected = base_selected.iter().any(|f| f.id == full.id);
807 if u > best_alt_utility && full.token_count <= base_budget && !already_selected {
808 best_alt_utility = u;
809 let mut sel = base_selected.clone();
810 sel.push(full.clone());
811 best_alt = Some((selection_cost(&sel), sel));
812 }
813 }
814
815 if let Some((used, sel)) = best_alt {
816 return SelectionResult {
817 selected: sel,
818 reason: SelectionReason::BestSingleton,
819 used_tokens: used,
820 utility: best_alt_utility,
821 greedy_iters,
822 stopping_certificate: 0.0,
823 };
824 }
825
826 let used = budget_tokens - state.remaining_budget;
827 let reason = if state.remaining_budget == 0 {
828 SelectionReason::BudgetExhausted
829 } else if greedy_utility <= 0.0 {
830 SelectionReason::NoUtility
831 } else if state.selected.is_empty() || state.selected.len() == base_selected.len() {
832 SelectionReason::NoCandidates
833 } else if threshold > 0.0 && !heap.is_empty() {
834 SelectionReason::StoppedByTau
835 } else {
836 SelectionReason::NoCandidates
837 };
838
839 let stopping_certificate = if matches!(reason, SelectionReason::StoppedByTau) {
840 threshold * f64::from(state.remaining_budget)
841 } else {
842 0.0
843 };
844
845 SelectionResult {
846 selected: state.selected,
847 reason,
848 used_tokens: used,
849 utility: greedy_utility,
850 greedy_iters,
851 stopping_certificate,
852 }
853}
854
855#[cfg(test)]
856mod tests {
857 use super::*;
858 use crate::types::FragmentKind;
859
860 fn frag(path: &str, start: u32, end: u32, kind: FragmentKind, tokens: u32) -> Fragment {
861 let mut identifiers = FxHashSet::default();
862 identifiers.insert(format!("sym_{path}_{start}"));
863 Fragment {
864 id: FragmentId::new(Arc::from(path), start, end),
865 kind,
866 content: Arc::from(format!("// {path}:{start}-{end}\n")),
867 identifiers,
868 token_count: tokens,
869 symbol_name: Some(format!("sym_{start}")),
870 }
871 }
872
873 fn rel_map(frags: &[Fragment], score: f64) -> FxHashMap<FragmentId, f64> {
874 frags.iter().map(|f| (f.id.clone(), score)).collect()
875 }
876
877 fn cost_of(selected: &[Fragment]) -> u32 {
878 selected.iter().map(|f| f.token_count).sum()
879 }
880
881 #[test]
886 fn selection_never_exceeds_the_budget() {
887 let frags: Vec<Fragment> = (0..12)
888 .map(|i| {
889 frag(
890 "a.rs",
891 1 + i * 50,
892 40 + i * 50,
893 FragmentKind::Function,
894 30 + i * 17,
895 )
896 })
897 .collect();
898 let core: FxHashSet<FragmentId> = std::iter::once(frags[0].id.clone()).collect();
899 let rel = rel_map(&frags, 0.7);
900
901 for budget in [1u32, 7, 30, 31, 60, 200, 1_000] {
902 let result = lazy_greedy_select(
903 frags.clone(),
904 &core,
905 &rel,
906 &[],
907 budget,
908 0.12,
909 None,
910 None,
911 None,
912 );
913 assert!(
914 cost_of(&result.selected) <= budget,
915 "budget {budget} overrun: cost {} via {:?}",
916 cost_of(&result.selected),
917 result.reason
918 );
919 assert!(
920 result.used_tokens <= budget,
921 "reported used_tokens {} exceeds budget {budget}",
922 result.used_tokens
923 );
924 }
925 }
926
927 #[test]
933 fn reported_used_tokens_always_equals_the_cost_of_the_returned_selection() {
934 let shapes: Vec<Vec<Fragment>> = vec![
935 vec![
936 frag("changed.rs", 1, 8, FragmentKind::Function, 20),
937 frag("other.rs", 1, 400, FragmentKind::Class, 900),
938 frag("other.rs", 500, 520, FragmentKind::Function, 40),
939 ],
940 vec![frag("changed.rs", 1, 200, FragmentKind::Class, 400)],
943 (0..6)
944 .map(|i| {
945 frag(
946 "a.rs",
947 1 + i * 20,
948 10 + i * 20,
949 FragmentKind::Function,
950 20 + i * 60,
951 )
952 })
953 .collect(),
954 ];
955
956 for frags in shapes {
957 let core: FxHashSet<FragmentId> = std::iter::once(frags[0].id.clone()).collect();
958 let rel = rel_map(&frags, 0.8);
959 for budget in [50u32, 120, 460, 1_000, 5_000] {
960 let result = lazy_greedy_select(
961 frags.clone(),
962 &core,
963 &rel,
964 &[],
965 budget,
966 0.12,
967 None,
968 None,
969 None,
970 );
971 assert_eq!(
972 result.used_tokens,
973 cost_of(&result.selected),
974 "reason {:?} at budget {budget}: reported {} but selection costs {}",
975 result.reason,
976 result.used_tokens,
977 cost_of(&result.selected)
978 );
979 }
980 }
981 }
982
983 #[test]
987 fn a_mostly_unchanged_core_is_placed_as_its_excerpt() {
988 let core = frag("script.sh", 1, 122, FragmentKind::Chunk, 600);
989 let excerpt = frag("script.sh", 58, 64, FragmentKind::Excerpt, 40);
990 let core_ids: FxHashSet<FragmentId> = std::iter::once(core.id.clone()).collect();
991 let rel = rel_map(&[core.clone()], 1.0);
992 let mut excerpts: FxHashMap<FragmentId, Fragment> = FxHashMap::default();
993 excerpts.insert(core.id.clone(), excerpt.clone());
994
995 let result = lazy_greedy_select(
996 vec![core.clone()],
997 &core_ids,
998 &rel,
999 &[],
1000 8_000,
1001 0.12,
1002 None,
1003 Some(&excerpts),
1004 None,
1005 );
1006
1007 let ids: Vec<String> = result
1008 .selected
1009 .iter()
1010 .map(|f| format!("{}:{}-{}", f.id.path, f.id.start_line, f.id.end_line))
1011 .collect();
1012 assert!(
1013 result.selected.iter().any(|f| f.id == excerpt.id),
1014 "core was not downshifted to its excerpt: {ids:?}"
1015 );
1016 assert!(
1017 !result.selected.iter().any(|f| f.id == core.id),
1018 "the full core was emitted alongside the excerpt: {ids:?}"
1019 );
1020 }
1021
1022 #[test]
1023 fn selected_fragments_never_overlap_and_are_never_duplicated() {
1024 let frags: Vec<Fragment> = (0..8)
1025 .map(|i| frag("a.rs", 1 + i * 10, 12 + i * 10, FragmentKind::Function, 25))
1026 .collect();
1027 let core: FxHashSet<FragmentId> = std::iter::once(frags[0].id.clone()).collect();
1028 let rel = rel_map(&frags, 0.9);
1029 let result = lazy_greedy_select(frags, &core, &rel, &[], 400, 0.12, None, None, None);
1030
1031 let ids: FxHashSet<FragmentId> = result.selected.iter().map(|f| f.id.clone()).collect();
1032 assert_eq!(
1033 ids.len(),
1034 result.selected.len(),
1035 "duplicate fragment selected"
1036 );
1037 }
1038
1039 #[test]
1043 fn a_winning_singleton_never_evicts_the_core_selection() {
1044 let core_frag = frag("changed.rs", 1, 8, FragmentKind::Function, 20);
1047 let heavy = frag("other.rs", 1, 400, FragmentKind::Class, 900);
1048 let filler = frag("other.rs", 500, 520, FragmentKind::Function, 40);
1049 let frags = vec![core_frag.clone(), heavy.clone(), filler];
1050
1051 let core: FxHashSet<FragmentId> = std::iter::once(core_frag.id.clone()).collect();
1052 let mut rel = FxHashMap::default();
1053 rel.insert(core_frag.id.clone(), 0.05);
1054 rel.insert(heavy.id.clone(), 1.0);
1055 rel.insert(frags[2].id.clone(), 0.1);
1056
1057 let result = lazy_greedy_select(frags, &core, &rel, &[], 2_000, 0.12, None, None, None);
1058 assert!(
1059 result.selected.iter().any(|f| core.contains(&f.id)),
1060 "no core fragment survived; reason was {:?}",
1061 result.reason
1062 );
1063 assert!(cost_of(&result.selected) <= 2_000);
1064 }
1065
1066 #[test]
1067 fn empty_ground_set_reports_no_candidates() {
1068 let result = lazy_greedy_select(
1069 Vec::new(),
1070 &FxHashSet::default(),
1071 &FxHashMap::default(),
1072 &[],
1073 1_000,
1074 0.12,
1075 None,
1076 None,
1077 None,
1078 );
1079 assert!(result.selected.is_empty());
1080 assert_eq!(result.reason, SelectionReason::NoCandidates);
1081 assert_eq!(result.used_tokens, 0);
1082 }
1083
1084 #[test]
1088 fn drop_redundant_signatures_is_independent_of_candidate_order() {
1089 let header = frag("a.rs", 10, 12, FragmentKind::Definition, 40);
1090 let whole = frag("a.rs", 10, 300, FragmentKind::Class, 4_000);
1091 let stub = frag("a.rs", 10, 11, FragmentKind::ClassSignature, 15);
1092
1093 let forward =
1094 drop_redundant_signatures(&[header.clone(), whole.clone(), stub.clone()], 500);
1095 let backward = drop_redundant_signatures(&[whole, header, stub], 500);
1096
1097 let kinds = |v: &[Fragment]| -> Vec<FragmentKind> { v.iter().map(|f| f.kind).collect() };
1098 assert!(
1099 kinds(&forward).contains(&FragmentKind::ClassSignature),
1100 "the stub for an unaffordable class was dropped: {:?}",
1101 kinds(&forward)
1102 );
1103 let mut a: Vec<FragmentKind> = kinds(&forward);
1104 let mut b: Vec<FragmentKind> = kinds(&backward);
1105 a.sort_by_key(|k| format!("{k:?}"));
1106 b.sort_by_key(|k| format!("{k:?}"));
1107 assert_eq!(a, b, "verdict depended on candidate order");
1108 }
1109
1110 #[test]
1111 fn drop_redundant_signatures_removes_a_stub_whose_full_fragment_fits() {
1112 let whole = frag("a.rs", 10, 40, FragmentKind::Class, 100);
1113 let stub = frag("a.rs", 10, 11, FragmentKind::ClassSignature, 15);
1114 let kept = drop_redundant_signatures(&[whole, stub], 500);
1115 assert!(
1116 !kept.iter().any(|f| f.kind.is_signature()),
1117 "stub survived even though the full fragment fits the budget"
1118 );
1119 }
1120 #[test]
1127 fn tau_stops_the_greedy_loop_before_the_budget_is_spent() {
1128 let frags: Vec<Fragment> = (0..6)
1131 .map(|i| {
1132 frag(
1133 "a.rs",
1134 1 + i * 20,
1135 10 + i * 20,
1136 FragmentKind::Function,
1137 20 + i * i * 120,
1138 )
1139 })
1140 .collect();
1141 let core: FxHashSet<FragmentId> = std::iter::once(frags[0].id.clone()).collect();
1142 let mut rel = FxHashMap::default();
1143 for (i, f) in frags.iter().enumerate() {
1147 rel.insert(f.id.clone(), 0.25f64.powi(i as i32).max(1e-6));
1148 }
1149
1150 let budget = 10_000;
1151 let default_tau = lazy_greedy_select(
1152 frags.clone(),
1153 &core,
1154 &rel,
1155 &[],
1156 budget,
1157 crate::config::limits::DEFAULT_STOPPING_THRESHOLD,
1158 None,
1159 None,
1160 None,
1161 );
1162 let no_tau = lazy_greedy_select(frags, &core, &rel, &[], budget, 0.0, None, None, None);
1163
1164 assert_eq!(
1165 default_tau.reason,
1166 SelectionReason::StoppedByTau,
1167 "the adaptive stop did not fire at the shipped default"
1168 );
1169 assert!(
1170 default_tau.selected.len() < no_tau.selected.len(),
1171 "tau={} selected {} fragments, same as tau=0.0 — the rule is inert",
1172 crate::config::limits::DEFAULT_STOPPING_THRESHOLD,
1173 default_tau.selected.len()
1174 );
1175 assert!(
1176 default_tau.used_tokens < no_tau.used_tokens,
1177 "the stop saved no budget: {} vs {}",
1178 default_tau.used_tokens,
1179 no_tau.used_tokens
1180 );
1181 assert!(
1182 default_tau.stopping_certificate > 0.0,
1183 "StoppedByTau must carry a positive certificate"
1184 );
1185 assert_eq!(
1186 no_tau.stopping_certificate, 0.0,
1187 "tau=0.0 cannot produce a stopping certificate"
1188 );
1189 }
1190
1191 #[test]
1195 fn per_file_ceiling_blocks_monopoly_but_releases_leftovers() {
1196 let mut frags: Vec<Fragment> = (0..20)
1198 .map(|i| {
1199 frag(
1200 "blob.json",
1201 i * 10 + 1,
1202 i * 10 + 9,
1203 FragmentKind::Chunk,
1204 100,
1205 )
1206 })
1207 .collect();
1208 frags.push(frag("a.rs", 1, 9, FragmentKind::Function, 100));
1209 frags.push(frag("b.rs", 1, 9, FragmentKind::Function, 100));
1210 let core: FxHashSet<FragmentId> = FxHashSet::default();
1211 let mut rel: FxHashMap<FragmentId, f64> = FxHashMap::default();
1212 for f in &frags {
1214 let w = if f.id.path.as_ref() == "blob.json" {
1215 1.0
1216 } else {
1217 0.5
1218 };
1219 rel.insert(f.id.clone(), w);
1220 }
1221 let budget = 1_000u32; let result = lazy_greedy_select(
1223 frags.clone(),
1224 &core,
1225 &rel,
1226 &[],
1227 budget,
1228 0.0,
1229 None,
1230 None,
1231 None,
1232 );
1233 let by_file =
1234 |sel: &Vec<Fragment>, p: &str| sel.iter().filter(|f| f.id.path.as_ref() == p).count();
1235 assert!(
1236 by_file(&result.selected, "a.rs") == 1 && by_file(&result.selected, "b.rs") == 1,
1237 "small files must not be crowded out: {:?}",
1238 result
1239 .selected
1240 .iter()
1241 .map(|f| f.id.path.to_string())
1242 .collect::<Vec<_>>()
1243 );
1244 assert!(
1245 by_file(&result.selected, "blob.json") >= 5,
1246 "leftover budget must flow back to the blob once competitors are served"
1247 );
1248
1249 run_lone_file_check(budget, &rel);
1250 }
1251
1252 #[test]
1256 fn signature_stubs_honor_the_per_file_ceiling() {
1257 let budget = 1_000u32;
1258 let mut cores: Vec<Fragment> = vec![frag("blob.rs", 1, 90, FragmentKind::Function, 240)];
1259 for i in 1..8 {
1260 cores.push(frag(
1261 "blob.rs",
1262 1 + i * 100,
1263 90 + i * 100,
1264 FragmentKind::Function,
1265 400,
1266 ));
1267 }
1268 cores.push(frag("b.rs", 1, 50, FragmentKind::Function, 200));
1269 let sig_lookup: FxHashMap<FragmentId, Fragment> = cores
1270 .iter()
1271 .filter(|c| c.id.path.as_ref() == "blob.rs")
1272 .map(|c| {
1273 let mut sig = frag(
1274 "blob.rs",
1275 c.start_line(),
1276 c.start_line(),
1277 FragmentKind::FunctionSignature,
1278 30,
1279 );
1280 sig.id = FragmentId::new(c.id.path.clone(), c.start_line(), c.start_line());
1281 (c.id.clone(), sig)
1282 })
1283 .collect();
1284 let mut rel: FxHashMap<FragmentId, f64> = FxHashMap::default();
1285 for c in &cores {
1286 let w = if c.id.path.as_ref() == "blob.rs" {
1287 1.0
1288 } else {
1289 0.5
1290 };
1291 rel.insert(c.id.clone(), w);
1292 }
1293 let core_ids: FxHashSet<FragmentId> = cores.iter().map(|c| c.id.clone()).collect();
1294 let mut state = init_selection_state(&core_ids, &rel, budget, None);
1295 select_core_fragments(&cores, &rel, &[], &mut state, budget, &sig_lookup, None);
1296
1297 let first_b = state
1298 .selected
1299 .iter()
1300 .position(|f| f.id.path.as_ref() == "b.rs")
1301 .expect("the competitor core must be selected");
1302 let stubs_before_b = state.selected[..first_b]
1303 .iter()
1304 .filter(|f| f.kind.is_signature())
1305 .count();
1306 assert_eq!(
1307 stubs_before_b, 0,
1308 "a file at its ceiling placed {stubs_before_b} signature stubs before the competitor got its seat"
1309 );
1310 }
1311
1312 fn run_lone_file_check(budget: u32, rel: &FxHashMap<FragmentId, f64>) {
1313 let lone: Vec<Fragment> = (0..20)
1315 .map(|i| {
1316 frag(
1317 "blob.json",
1318 i * 10 + 1,
1319 i * 10 + 9,
1320 FragmentKind::Chunk,
1321 100,
1322 )
1323 })
1324 .collect();
1325 let core: FxHashSet<FragmentId> = FxHashSet::default();
1326 let result = lazy_greedy_select(lone, &core, rel, &[], budget, 0.0, None, None, None);
1327 assert!(
1328 result.selected.len() >= 9,
1329 "single-file selection stranded budget: {} fragments",
1330 result.selected.len()
1331 );
1332 }
1333}