MCPcopy Create free account
hub / github.com/argumentcomputer/ix / decide_sharing

Function decide_sharing

crates/ixon/src/sharing.rs:578–627  ·  view source on GitHub ↗

Decide which subterms to share based on profitability. Sharing is profitable when: `(N - 1) * term_size > N * share_ref_size` where N is usage count, term_size is effective size, and share_ref_size is the size of a Share(idx) reference at the current index. Optimized from O(k×n) to O(n log n) by pre-sorting candidates.

(
  info_map: &HashMap<blake3::Hash, SubtermInfo>,
  topo_order: &[blake3::Hash],
)

Source from the content-addressed store, hash-verified

576/// Optimized from O(k×n) to O(n log n) by pre-sorting candidates.
577pub fn decide_sharing(
578 info_map: &FxHashMap<blake3::Hash, SubtermInfo>,
579 topo_order: &[blake3::Hash],
580) -> IndexSet<blake3::Hash> {
581 let effective_sizes = compute_effective_sizes(info_map, topo_order);
582
583 // Pre-filter and sort candidates by potential savings (assuming minimal ref_size=1)
584 // This gives us a stable ordering since relative savings don't change as ref_size grows
585 let mut candidates: Vec<_> = info_map
586 .iter()
587 .filter(|(_, info)| info.usage_count >= 2)
588 .filter_map(|(hash, info)| {
589 let term_size = *effective_sizes.get(hash)?;
590 let n = info.usage_count;
591 // Potential savings assuming ref_size = 1 (minimum)
592 let potential = (n as isize - 1) * (term_size as isize) - (n as isize);
593 if potential > 0 { Some((*hash, term_size, n)) } else { None }
594 })
595 .collect();
596
597 // Sort by decreasing gross benefit, with hash bytes as tie-breaker for determinism
598 candidates.sort_unstable_by(|a, b| {
599 let gross_a = (a.2 as isize - 1) * (a.1 as isize);
600 let gross_b = (b.2 as isize - 1) * (b.1 as isize);
601 match gross_b.cmp(&gross_a) {
602 std::cmp::Ordering::Equal => a.0.as_bytes().cmp(b.0.as_bytes()),
603 other => other,
604 }
605 });
606
607 let mut shared: IndexSet<blake3::Hash> = IndexSet::new();
608
609 // Process ALL candidates - don't break early!
610 // The early-break was incorrect: ref_size growth affects candidates differently
611 // based on their usage count. A high-usage small term may become unprofitable
612 // while a low-usage large term remains profitable.
613 for (hash, term_size, usage_count) in candidates {
614 let next_idx = shared.len();
615 let next_ref_size =
616 Tag4::new(Expr::FLAG_SHARE, next_idx as u64).encoded_size();
617 let n = usage_count as isize;
618 let savings = (n - 1) * (term_size as isize) - n * (next_ref_size as isize);
619
620 if savings > 0 {
621 shared.insert(hash);
622 }
623 }
624
625 shared
626}
627
628/// Rewrite expressions to use Share(idx) references for shared subterms.
629///
630/// Returns the rewritten expressions and the sharing vector.

Callers 7

apply_sharing_with_statsFunction · 0.85
rs_analyze_sharing_countFunction · 0.85
rs_run_sharing_analysisFunction · 0.85
test_early_break_bugFunction · 0.85
test_build_sharing_vecFunction · 0.85

Calls 8

compute_effective_sizesFunction · 0.85
as_bytesMethod · 0.80
encoded_sizeMethod · 0.80
iterMethod · 0.45
getMethod · 0.45
cmpMethod · 0.45
lenMethod · 0.45
insertMethod · 0.45

Tested by 3

test_early_break_bugFunction · 0.68
test_build_sharing_vecFunction · 0.68