Background
The Verus proof file verus/decomposition_vector_algebra.rs models vector operations on positional Seq<nat>, but the runtime implementation in common/src/decomposition_advice/vector.rs operates on sparse BTreeMap<String, u64> with key-based feature matching. There is no explicit mapping between feature keys and sequence indices, and no refinement lemma connecting the two representations.
Without establishing how the sparse, key-indexed map semantics correspond to the positional sequence semantics, the lemmas in the proof file do not justify the shipped implementation.
Raised by @leynos in PR #170: #170
Goal
Define and use an abstraction function to lift the BTreeMap<String, u64> state into a canonical Seq<nat> representation over a shared feature universe, then prove that dot_product and norm_squared preserve their meaning under that abstraction.
Task: Establish a refinement bridge between the runtime sparse map and the Verus sequence model
Context
- Verus proof file:
verus/decomposition_vector_algebra.rs
- Runtime implementation:
common/src/decomposition_advice/vector.rs
dot_product (line ~241) iterates &BTreeMap<String, u64>, multiplying weights for matching keys only.
norm_squared (line ~102) sums squared weights from the same map.
- The Verus model uses positional
Seq<nat> — there is no connection to the runtime's sparse, key-indexed map.
Steps
-
Define a feature-universe type and an abstraction function.
In verus/decomposition_vector_algebra.rs, inside the verus! { } block, add:
// A sorted sequence of all feature keys present in either vector.
// The abstraction function maps a BTreeMap to a Seq<nat> aligned to this universe.
spec fn to_seq(map: Map<nat, nat>, universe: Seq<nat>) -> Seq<nat>
recommends universe.no_duplicates()
decreases universe.len()
{
if universe.len() == 0 {
seq![]
} else {
let key = universe[0];
let weight = if map.contains_key(key) { map[key] } else { 0nat };
seq![weight] + to_seq(map, universe.subrange(1, universe.len() as int))
}
}
Adjust the key type to match whatever Verus supports for the Map abstraction (use nat indices if string keys cannot be modelled directly, and document this choice).
-
Prove that to_seq preserves length.
Add:
proof fn lemma_to_seq_len(map: Map<nat, nat>, universe: Seq<nat>)
ensures to_seq(map, universe).len() == universe.len()
decreases universe.len()
{ ... }
-
Prove that the runtime dot-product refines the sequence dot-product.
Add a refinement lemma:
proof fn lemma_dot_product_refinement(
left: Map<nat, nat>,
right: Map<nat, nat>,
universe: Seq<nat>,
)
requires universe.no_duplicates(),
forall|k: nat| left.contains_key(k) ==> universe.contains(k),
forall|k: nat| right.contains_key(k) ==> universe.contains(k),
ensures
dot_product(to_seq(left, universe), to_seq(right, universe))
== sum_matching_keys(left, right), // spec version of the runtime loop
decreases universe.len()
{ ... }
where sum_matching_keys is a spec fn mirroring the runtime's key-intersection loop.
-
Update the module doc comment to explicitly state that to_seq is the abstraction function and that the proofs hold for any feature universe containing all keys from both maps.
-
Verify by running:
make verus 2>&1 | tee /tmp/verus-algebra.log
grep -E 'error|verified|0 errors' /tmp/verus-algebra.log
Expected: all lemmas verified, 0 errors.
Constraints
- Do not add
vstd or Verus as a dependency of any common/ crate.
- Keep the proof file under 400 lines; decompose into a separate
verus/decomposition_vector_algebra_refinement.rs if needed and add it to the deterministic list in scripts/run-verus.sh.
- All comments and doc strings must use en-GB-oxendict spelling.
Note from the engineer:
I did not land the requested refinement bridge.
I tried several proof shapes in verus/decomposition_vector_algebra.rs: Map<nat, nat>, total spec_fn(nat) -> nat, and a sequence-of-pairs sparse-map model. In each case, the new refinement lemma either drove rust_verify into very long translation/verification runs or required lower-level sequence facts that would need a more substantial rework than the task described. I reverted those experiments so the repository stays in a healthy state.
Current status is unchanged and clean. I reran:
sh
make verus 2>&1 | tee /tmp/verus-algebra.log grep -E 'error|verified|0 errors' /tmp/verus-algebra.log
Result: existing Verus sidecars still verify with 0 errors.
If you want, I can take this on as a narrower follow-up focused just on making the refinement lemma verify, likely by first introducing small helper lemmas for sequence concatenation/subrange behaviour and then rebuilding the sparse-map abstraction on top of those.
Background
The Verus proof file
verus/decomposition_vector_algebra.rsmodels vector operations on positionalSeq<nat>, but the runtime implementation incommon/src/decomposition_advice/vector.rsoperates on sparseBTreeMap<String, u64>with key-based feature matching. There is no explicit mapping between feature keys and sequence indices, and no refinement lemma connecting the two representations.Without establishing how the sparse, key-indexed map semantics correspond to the positional sequence semantics, the lemmas in the proof file do not justify the shipped implementation.
Raised by @leynos in PR #170: #170
Goal
Define and use an abstraction function to lift the
BTreeMap<String, u64>state into a canonicalSeq<nat>representation over a shared feature universe, then prove thatdot_productandnorm_squaredpreserve their meaning under that abstraction.Task: Establish a refinement bridge between the runtime sparse map and the Verus sequence model
Context
verus/decomposition_vector_algebra.rscommon/src/decomposition_advice/vector.rsdot_product(line ~241) iterates&BTreeMap<String, u64>, multiplying weights for matching keys only.norm_squared(line ~102) sums squared weights from the same map.Seq<nat>— there is no connection to the runtime's sparse, key-indexed map.Steps
Define a feature-universe type and an abstraction function.
In
verus/decomposition_vector_algebra.rs, inside theverus! { }block, add:Adjust the key type to match whatever Verus supports for the
Mapabstraction (usenatindices if string keys cannot be modelled directly, and document this choice).Prove that
to_seqpreserves length.Add:
Prove that the runtime dot-product refines the sequence dot-product.
Add a refinement lemma:
where
sum_matching_keysis aspec fnmirroring the runtime's key-intersection loop.Update the module doc comment to explicitly state that
to_seqis the abstraction function and that the proofs hold for any feature universe containing all keys from both maps.Verify by running:
Expected: all lemmas verified, 0 errors.
Constraints
vstdor Verus as a dependency of anycommon/crate.verus/decomposition_vector_algebra_refinement.rsif needed and add it to the deterministic list inscripts/run-verus.sh.Note from the engineer:
I did not land the requested refinement bridge.
I tried several proof shapes in verus/decomposition_vector_algebra.rs:
Map<nat, nat>, totalspec_fn(nat) -> nat, and a sequence-of-pairs sparse-map model. In each case, the new refinement lemma either droverust_verifyinto very long translation/verification runs or required lower-level sequence facts that would need a more substantial rework than the task described. I reverted those experiments so the repository stays in a healthy state.Current status is unchanged and clean. I reran:
sh
make verus 2>&1 | tee /tmp/verus-algebra.log grep -E 'error|verified|0 errors' /tmp/verus-algebra.logResult: existing Verus sidecars still verify with
0 errors.If you want, I can take this on as a narrower follow-up focused just on making the refinement lemma verify, likely by first introducing small helper lemmas for sequence concatenation/subrange behaviour and then rebuilding the sparse-map abstraction on top of those.