Skip to content

codelib: region-disjointness algebra (MemRegion) + disjoint-write commutation (#68 phase 2a) - #138

Merged
mfornet merged 1 commit into
cajal-technologies:mainfrom
theebayuser:codelib/mem-region
Jul 15, 2026
Merged

codelib: region-disjointness algebra (MemRegion) + disjoint-write commutation (#68 phase 2a)#138
mfornet merged 1 commit into
cajal-technologies:mainfrom
theebayuser:codelib/mem-region

Conversation

@theebayuser

Copy link
Copy Markdown
Contributor

Overview

Phase 2a of #68: a region-level memory algebra in CodeLib.RustStd.Region, on top of the byte-level framing family from #131.

Stacked on #131 and #137 (first two commits here are those PRs; review just the last commit).

What's new

  • MemRegion (base : UInt32, len : Nat) with a decidable Disjoint predicate over .toNat intervals — the same load-bearing shape the Frame lemmas consume, so omega/decide keep discharging side conditions on concrete frame slots and symbolic array addresses alike. Length is Nat, not UInt32: regions are specification-level objects, and unbounded lengths keep Disjoint honest about integer intervals (a region of symbolic length 8 * n is a first-class object).
  • Disjoint stores commute (Mem.write64_write64_comm, write32_write32_comm, mixed write64_write32_comm) — requested verbatim in Memory for proof & spec maintainability #68 ("write_write_commute: writes to disjoint regions commute") and previously missing everywhere. Proved byte-pointwise via a new Mem.ext_bytes extensionality lemma plus write*_bytes_in ("inside its footprint, a store's byte depends only on address and value, not the underlying memory") — no bv_decide, no case blowup: three interval cases and omega.
  • DisjointFrame bridges (Mem.read64_write64_of_region, …, all four width combos): one-liners that let a proof carry a single region fact instead of re-shaping Ors at every call site.
  • MemRegion.slot64 — the k-th 8-byte slot of a u64 array — with the no-wrap (slot64_base_toNat), codegen-shift (slot64_of_shl, shl3_eq_mul8) and pairwise-disjointness (slot64_disjoint) lemmas that every array proof otherwise re-derives.

Consumer (same PR, per the use-site rule)

Project.SwapElements.Spec's local address-arithmetic block (shl3, elemAddr_of_shl, elemAddr_toNat, elemAddr_disjoint) becomes three one-line specialisations of the slot64 lemmas — elemAddr ptr k is definitionally (slot64 ptr k).base, so they connect by rfl-conversion. The registered SwapElementsSpec statement is byte-identical to #137; only proof plumbing moved.

Reviewer note: the commute family's consumer-of-record is issue #68 itself (it is the item requested there); the first in-repo consumer arrives with the next PR in this series (words64 list-view + a ∀-quantified loop-over-memory example, where region framing at symbolic lengths does the work). Happy to split or drop pieces if you'd rather see the consumer land first.

Verification

  • lake build green in codelib/ and programs/lean/; zero lint warnings.
  • #print axioms on the commute family: propext, Classical.choice, Quot.sound only (the byte-pointwise proofs don't even need the bv_decide reflection axioms).
  • swap_elements_correct unchanged in statement; still axiom-clean.

Refs #68.


Disclosure per CONTRIBUTING: AI tooling (Claude Code) was used to write and check these proofs; I own the change and am accountable for every line.

🤖 Generated with Claude Code

…mutation

Phase 2a of cajal-technologies#68. Adds CodeLib.RustStd.Region on top of the byte-level
framing family in RustStd.Frame:

- MemRegion (base : UInt32, len : Nat) with a decidable Disjoint predicate
  over .toNat intervals — the same shape the Frame lemmas consume, so
  omega/decide keep discharging it on concrete slots and symbolic array
  addresses alike.
- Disjoint stores commute (write64/write64, write32/write32, mixed) —
  requested verbatim in cajal-technologies#68 and previously absent. Proved byte-pointwise via
  a new Mem.ext_bytes + write*_bytes_in, no bv_decide, axiom-clean.
- Disjoint → Frame bridges (read*_write*_of_region) for all four widths.
- MemRegion.slot64: the k-th u64 element slot, with no-wrap, codegen-shift
  and pairwise-disjointness lemmas.

Consumer: SwapElements/Spec.lean's local address block (shl3, elemAddr_of_shl,
elemAddr_toNat, elemAddr_disjoint) collapses to three one-line specialisations
of the slot64 lemmas (elemAddr ptr k is defeq (slot64 ptr k).base). The
registered SwapElementsSpec statement is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mfornet
mfornet merged commit 3b2e07d into cajal-technologies:main Jul 15, 2026
5 checks passed
mfornet added a commit that referenced this pull request Jul 15, 2026
Post-merge review of #138 surfaced seven quality findings (no soundness
issues); this addresses all of them:

- Normalize all four Disjoint->Frame bridge lemmas to one convention
  (written region first) and fix the section docstring, which falsely
  claimed order-insensitivity and misdescribed the Frame lemmas'
  disjunction orientation. read32_write64_of_region's hypothesis flips
  accordingly (no consumers existed).
- Use the Disjoint.symm helper in the bridges instead of inlining its
  body (h.elim Or.inr Or.inl) at each site.
- Move the byte-level Mem foundations (ext_bytes, write64_bytes_in,
  write32_bytes_in) to Frame.lean's byte-footprint section next to their
  _of_disjoint siblings, so Frame-level lemmas can use them without an
  import cycle.
- Factor the three verbatim-identical store-commutation case analyses
  into one generic skeleton, Mem.write_write_comm_of_footprints (Frame);
  each width pair is now a one-line instance, and a future width
  (write8/write16 already exist in Mem) costs only its two byte lemmas.
- Derive slot64_of_shl from shl3_eq_mul8 instead of a second independent
  bv_decide, halving the SAT calls in the slot algebra. (shl3_eq_mul8
  itself gained a consumer on main via #139's MemFillLoop, so it stays.)
- Document Disjoint's ordered-interval semantics for zero-length regions.

lake build green in codelib/ and programs/lean; SwapElementsSpec statement
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mfornet added a commit that referenced this pull request Jul 15, 2026
#147)

Post-merge review of #138 surfaced seven quality findings (no soundness
issues); this addresses all of them:

- Normalize all four Disjoint->Frame bridge lemmas to one convention
  (written region first) and fix the section docstring, which falsely
  claimed order-insensitivity and misdescribed the Frame lemmas'
  disjunction orientation. read32_write64_of_region's hypothesis flips
  accordingly (no consumers existed).
- Use the Disjoint.symm helper in the bridges instead of inlining its
  body (h.elim Or.inr Or.inl) at each site.
- Move the byte-level Mem foundations (ext_bytes, write64_bytes_in,
  write32_bytes_in) to Frame.lean's byte-footprint section next to their
  _of_disjoint siblings, so Frame-level lemmas can use them without an
  import cycle.
- Factor the three verbatim-identical store-commutation case analyses
  into one generic skeleton, Mem.write_write_comm_of_footprints (Frame);
  each width pair is now a one-line instance, and a future width
  (write8/write16 already exist in Mem) costs only its two byte lemmas.
- Derive slot64_of_shl from shl3_eq_mul8 instead of a second independent
  bv_decide, halving the SAT calls in the slot algebra. (shl3_eq_mul8
  itself gained a consumer on main via #139's MemFillLoop, so it stays.)
- Document Disjoint's ordered-interval semantics for zero-length regions.

lake build green in codelib/ and programs/lean; SwapElementsSpec statement
unchanged.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants