Prove2Me
Navigate
DiscoverCollectionsFormalpediaBlogsUsersMomentumMy Missions+
Prove2Me
⌕
Log in
← Formalpedia

Algo2Lean execution, mutable heap and transcript definitions

Definition
Algo2Lean

by lunjia · Oct 10, 2026 · Mathlib 0df444a (Lean v4.33.1)

algo2leanalgorithmsclrsdata-structuresrunning-timetextbook

The common runtime semantics includes mathematical integer-indexed sequences, mutable objects and typed collections, allocation counters, and named natural-number clocks. A configuration carries a current frame, suspended caller frames, heap and return state. Reaches describes finite sequences of small steps; transcript validity checks the corresponding finite observations.

Generated source functions expose Call, Run, Returns and cost views over this shared semantics. A reusable call preserves its arbitrary suspended caller context while permitting the heap effects specified by its contract. Named ticks are explicit source events; generated transitions do not automatically count as runtime ticks.

<!-- algo2lean-provenance-v0.1.4 -->

Algo2Lean provenance and reproduction. These definitions target Algo2Lean v0.1.4, using the compiler source at public commit 0f79d5e4242e6477531c9ee4410409f5b1c92f76, and Lean 4.33.1. The versioned compiler location is Algo2Lean v0.1.4. Compile all supplied .algo files and imports to reproduce the raw generated definitions. Release publication and exact website parity require their separately recorded checks; this metadata alone does not assert them. Prove2Me imports and declaration packaging are mechanically adapted, with original hashes, compiler-reported source ranges, and adaptations recorded in transplant provenance. Exact reproduction does not prove the compiler correct.

Definition code
import Std

set_option autoImplicit true
set_option backward.isDefEq.respectTransparency false
set_option backward.defeqAttrib.useBackward true



set_option backward.isDefEq.respectTransparency false
set_option backward.defeqAttrib.useBackward true

-- Copyright 2026 Lunjia Hu and contributors.
-- SPDX-License-Identifier: Apache-2.0

/-

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-/

namespace Algo2LeanCore

universe u v w

/-- A suspended caller remembers its local frame and where to put the result. -/
abbrev Stack (Frame : Type v) (Result : Type w) := List (Result → Frame)

/-- Heap snapshots preserve object identities and historical contents. -/
inductive Config (Heap : Type u) (Frame : Type v) (Result : Type w) where
  | active (heap : Heap) (frame : Frame) (stack : Stack Frame Result)
  | done (heap : Heap) (result : Result)

variable {Heap : Type u} {Frame : Type v} {Result : Type w}

def Config.heap : Config Heap Frame Result → Heap
  | .active heap _ _ => heap
  | .done heap _ => heap

/-- The suspended callers; completed top-level executions have no callers. -/
def Config.stack : Config Heap Frame Result → Stack Frame Result
  | .active _ _ stack => stack
  | .done _ _ => []

def start (heap : Heap) (frame : Frame) : Config Heap Frame Result :=
  .active heap frame []

def resumeConfig (heap : Heap) (result : Result) (stack : Stack Frame Result) :
    Config Heap Frame Result :=
  match stack with
  | [] => .done heap result
  | resume :: rest => .active heap (resume result) rest

/-- Every state has at most one successor under the supplied transition relation. -/
def Deterministic {State : Type u} (step : State → State → Prop) : Prop :=
  ∀ {a b c}, step a b → step a c → b = c

/-- A terminal configuration has no next transition. -/
def Terminal {State : Type u} (step : State → State → Prop) (state : State) : Prop :=
  ∀ next, ¬ step state next

/-- A finite transcript includes its initial and final states, and may stop at
    any state. In particular, validity does not require a completed call. -/
inductive Valid {State : Type u} (step : State → State → Prop) :
    State → List State → State → Prop where
  | single (state) : Valid step state [state] state
  | cons : step before after → Valid step after rest final →
      Valid step before (before :: rest) final

namespace Valid

variable {State : Type u} {step nextProperty : State → State → Prop}

theorem nonempty (h : Valid step initial states final) : states ≠ [] := by
  cases h <;> simp

/-- Endpoint properties can be read from any theorem about transcript members. -/
theorem final_mem (valid : Valid step initial states final) : final ∈ states := by
  induction valid with
  | single => simp
  | cons _ _ ih => exact List.mem_cons_of_mem _ ih

/-- Every local transition property lifts to an arbitrary valid transcript. -/
theorem lift (h : Valid step initial states final)
    (localProperty : ∀ a b, step a b → nextProperty a b) :
    Valid nextProperty initial states final := by
  induction h with
  | single => exact .single _
  | cons transition _ ih => exact .cons (localProperty _ _ transition) ih

/-- Reuse a local preservation theorem without constructing a transcript. -/
theorem invariant (h : Valid step initial states final) (property : State → Prop)
    (atStart : property initial)
    (preserve : ∀ a b, step a b → property a → property b) : property final := by
  induction h with
  | single => exact atStart
  | cons transition _ ih => exact ih (preserve _ _ transition atStart)

theorem all_states (h : Valid step initial states final) (property : State → Prop)
    (atStart : property initial)
    (preserve : ∀ a b, step a b → property a → property b) :
    ∀ state ∈ states, property state := by
  induction h with
  | single => simpa using atStart
  | cons transition _ ih =>
    intro state member
    rcases List.mem_cons.mp member with same | later
    · simpa [same] using atStart
    · exact ih (preserve _ _ transition atStart) state later

/-- Concatenation keeps the shared endpoint once. -/
theorem append (first : Valid step a xs b) (second : Valid step b ys c) :
    Valid step a (xs.dropLast ++ ys) c := by
  induction first with
  | single => simpa using second
  | @cons before after rest final transition tail ih =>
    have split : (before :: rest).dropLast = before :: rest.dropLast := by
      cases rest with
      | nil => exact (tail.nonempty rfl).elim
      | cons head rest => simp
    simpa [split] using Valid.cons transition (ih second)

/-- Deterministic completed runs agree, regardless of their transcript witnesses. -/
theorem eq_of_terminal (deterministic : Deterministic step)
    (first : Valid step a xs b) (second : Valid step a ys c)
    (atFirst : Terminal step b) (atSecond : Terminal step c) : b = c := by
  induction first generalizing ys c with
  | single =>
    cases second with
    | single => rfl
    | cons transition => exact False.elim (atFirst _ transition)
  | cons transition _ inductionHypothesis =>
    cases second with
    | single => exact False.elim (atSecond _ transition)
    | cons other tail =>
      cases deterministic transition other
      exact inductionHypothesis tail atFirst atSecond

end Valid

/-- Reachability is a view of explicit transcript validity, not another
    execution relation. The existential witness need not be computed in proofs. -/
def Reaches {State : Type u} (step : State → State → Prop) (a b : State) : Prop :=
  ∃ transcript, Valid step a transcript b

namespace Reaches

variable {State : Type u} {step : State → State → Prop}

theorem refl (state : State) : Reaches step state state := ⟨[state], .single _⟩

theorem single (transition : step a b) : Reaches step a b :=
  ⟨[a, b], .cons transition (.single _)⟩

theorem trans (first : Reaches step a b) (second : Reaches step b c) : Reaches step a c := by
  obtain ⟨xs, first⟩ := first
  obtain ⟨ys, second⟩ := second
  exact ⟨xs.dropLast ++ ys, first.append second⟩

/-- Extend an execution segment by one local transition at its beginning. -/
theorem prepend (transition : step a b) (rest : Reaches step b c) : Reaches step a c :=
  (single transition).trans rest

/-- Turn a constructed result into a theorem about every completed execution. -/
theorem eq_of_terminal (deterministic : Deterministic step)
    (first : Reaches step a b) (second : Reaches step a c)
    (atFirst : Terminal step b) (atSecond : Terminal step c) : b = c := by
  obtain ⟨_, first⟩ := first
  obtain ⟨_, second⟩ := second
  exact Valid.eq_of_terminal (step := step) deterministic first second atFirst atSecond

theorem invariant (run : Reaches step a b) (property : State → Prop)
    (atStart : property a)
    (preserve : ∀ before after, step before after → property before → property after) : property b := by
  obtain ⟨_, transcript⟩ := run
  exact transcript.invariant property atStart preserve

end Reaches

/-- A function summary can be reused under any suspended caller stack. -/
def Summary (step : Config Heap Frame Result → Config Heap Frame Result → Prop)
    (heap : Heap) (frame : Frame) (heap' : Heap) (result : Result) : Prop :=
  ∀ stack, Reaches step (.active heap frame stack) (resumeConfig heap' result stack)

theorem Summary.root (summary : Summary step heap frame heap' result) :
    Reaches step (start heap frame) (.done heap' result) := by
  simpa [start, resumeConfig] using summary []

end Algo2LeanCore

/- Integer sequences are mathematical objects, addressed by stable identities. -/
namespace Algo2LeanGenerated

abbrev Seq := Int → Int
abbrev SeqRef := Nat
abbrev ObjectRef := Nat
/-- One identity space for typed collections; additional collection kinds can share it. -/
abbrev CollectionRef := Nat
/-- Independent named counters for user-selected algorithmic operations. -/
abbrev Clocks := String → Nat

/-- A cost specification that charges just one named counter. -/
def Clocks.single (name : String) (amount : Nat) : Clocks :=
  fun clock => if clock = name then amount else 0

/-- Combine cost specifications pointwise, including overlapping counters. -/
def Clocks.add (first second : Clocks) : Clocks :=
  fun clock => first clock + second clock

/-- Stored field values. A missing field is distinct from an initialized `None`. -/
inductive ObjectValue where
  | intValue (value : Int)
  | boolValue (value : Bool)
  | seqValue (value : SeqRef)
  | collectionValue (value : CollectionRef)
  | objectValue (value : ObjectRef)
  | noneValue
  deriving DecidableEq

def ObjectValue.asInt : ObjectValue → Option Int
  | .intValue value => some value
  | _ => none

def ObjectValue.asBool : ObjectValue → Option Bool
  | .boolValue value => some value
  | _ => none

def ObjectValue.asSeq : ObjectValue → Option SeqRef
  | .seqValue value => some value
  | _ => none

def ObjectValue.asCollection : ObjectValue → Option CollectionRef
  | .collectionValue value => some value
  | _ => none

def ObjectValue.asObject : ObjectValue → Option ObjectRef
  | .objectValue value => some value
  | _ => none

def ObjectValue.asNone : ObjectValue → Option Unit
  | .noneValue => some ()
  | _ => none

def ObjectValue.asNullableObject : ObjectValue → Option (Option ObjectRef)
  | .objectValue value => some (some value)
  | .noneValue => some none
  | _ => none

structure Object where
  className : String
  fields : String → Option ObjectValue := fun _ => none

/-- Collection payloads keep identities separate from their contents. The element
    type is a source type tag, checked before reading a typed sequence. -/
inductive Collection where
  | sequence (elementType : String) (values : Int → ObjectValue)

structure Heap where
  nextRef : Nat := 0
  store : SeqRef → Seq := fun _ _ => 0
  nextObject : Nat := 0
  objects : ObjectRef → Option Object := fun _ => none
  clocks : Clocks := fun _ => 0
  nextCollection : Nat := 0
  collections : CollectionRef → Option Collection := fun _ => none

/-- Observe a counter locally, without assuming reachability or a transcript. -/
def clock {Frame Result : Type} (state : Algo2LeanCore.Config Heap Frame Result)
    (name : String) : Nat := state.heap.clocks name

/-- One source `tick` increases exactly one shared counter by a natural amount. -/
def Heap.tick (h : Heap) (name : String) (amount : Nat := 1) : Heap :=
  { h with clocks := fun clock => if clock = name then h.clocks clock + amount else h.clocks clock }

/-- Counts accrued between two heap snapshots, including nested calls. -/
def Heap.cost (initial final : Heap) : Clocks :=
  fun clock => final.clocks clock - initial.clocks clock

/-- Describe a segment's aggregate clock effect without changing program data.
    This proof helper does not add a source operation or a transition rule. -/
def Heap.charge (h : Heap) (costs : Clocks) : Heap :=
  { h with clocks := Clocks.add h.clocks costs }

@[simp] theorem Heap.charge_zero (h : Heap) :
    h.charge (fun _ => 0) = h := by
  have unchanged : Clocks.add h.clocks (fun _ => 0) = h.clocks := by
    funext clock
    simp [Clocks.add]
  simp [charge, unchanged]

@[simp] theorem Heap.clocks_charge (h : Heap) (costs : Clocks) (name : String) :
    (h.charge costs).clocks name = h.clocks name + costs name := rfl

/-- Aggregated segment costs compose by pointwise addition. -/
theorem Heap.charge_add (h : Heap) (first second : Clocks) :
    (h.charge first).charge second = h.charge (Clocks.add first second) := by
  simp only [charge]
  congr 1
  funext clock
  simp [Clocks.add, Nat.add_assoc]

theorem Heap.charge_single (h : Heap) (name : String) (amount : Nat) :
    h.charge (Clocks.single name amount) = h.tick name amount := by
  simp only [charge, tick]
  congr 1
  funext clock
  by_cases same : clock = name <;> simp [Clocks.add, Clocks.single, same]

/-- Prepend one concrete tick to an abstract segment cost. -/
theorem Heap.tick_charge (h : Heap) (name : String) (amount : Nat) (costs : Clocks) :
    (h.tick name amount).charge costs =
      h.charge (Clocks.add (Clocks.single name amount) costs) := by
  rw [← charge_single, charge_add]

@[simp] theorem Heap.cost_charge (h : Heap) (costs : Clocks) :
    cost h (h.charge costs) = costs := by
  funext clock
  simp [cost]

@[simp] theorem Heap.clocks_tick_same (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).clocks name = h.clocks name + amount := by simp [tick]

@[simp] theorem Heap.clocks_tick_other (h : Heap) (name clock : String)
    (different : clock ≠ name) (amount : Nat := 1) :
    (h.tick name amount).clocks clock = h.clocks clock := by simp [tick, different]

theorem Heap.clocks_le_tick (h : Heap) (name clock : String) (amount : Nat := 1) :
    h.clocks clock ≤ (h.tick name amount).clocks clock := by
  by_cases same : clock = name <;> simp [tick, same]

@[simp] theorem Heap.tick_zero (h : Heap) (name : String) :
    h.tick name 0 = h := by simp [tick]

/-- Combine adjacent increments of one counter. -/
theorem Heap.tick_add (h : Heap) (name : String) (a b : Nat) :
    (h.tick name a).tick name b = h.tick name (a + b) := by
  simp only [tick]
  congr 1
  funext clock
  by_cases same : clock = name <;> simp [same, Nat.add_assoc]

/-- Counter updates commute, so independent call costs can be regrouped. -/
theorem Heap.tick_comm (h : Heap) (first second : String) (a b : Nat) :
    (h.tick first a).tick second b = (h.tick second b).tick first a := by
  simp only [tick]
  congr 1
  funext clock
  by_cases one : clock = first <;> by_cases two : clock = second <;>
    simp_all [Nat.add_right_comm]

@[simp] theorem Heap.tick_store (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).store = h.store := rfl

@[simp] theorem Heap.tick_nextRef (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).nextRef = h.nextRef := rfl

@[simp] theorem Heap.tick_objects (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).objects = h.objects := rfl

@[simp] theorem Heap.tick_nextObject (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).nextObject = h.nextObject := rfl

@[simp] theorem Heap.cost_self (h : Heap) (clock : String) :
    cost h h clock = 0 := by simp [cost]

@[simp] theorem Heap.cost_tick_same (h : Heap) (name : String) (amount : Nat := 1) :
    cost h (h.tick name amount) name = amount := by simp [cost]

@[simp] theorem Heap.cost_tick_other (h : Heap) (name clock : String)
    (different : clock ≠ name) (amount : Nat := 1) :
    cost h (h.tick name amount) clock = 0 := by simp [cost, different]

/-- Consecutive execution segments add their costs. The premises rule out
    truncated subtraction between arbitrary, unrelated heap snapshots. -/
theorem Heap.cost_add (initial middle final : Heap) (clock : String)
    (first : initial.clocks clock ≤ middle.clocks clock)
    (second : middle.clocks clock ≤ final.clocks clock) :
    cost initial final clock = cost initial middle clock + cost middle final clock := by
  simp only [cost]
  omega

def Heap.read (h : Heap) (ref : SeqRef) (index : Int) : Int := h.store ref index

@[simp] theorem Heap.read_tick (h : Heap) (name : String) (amount : Nat)
    (ref : SeqRef) (index : Int) :
    (h.tick name amount).read ref index = h.read ref index := rfl

@[simp] theorem Heap.read_charge (h : Heap) (costs : Clocks)
    (ref : SeqRef) (index : Int) :
    (h.charge costs).read ref index = h.read ref index := rfl

@[simp] theorem Heap.charge_nextRef (h : Heap) (costs : Clocks) :
    (h.charge costs).nextRef = h.nextRef := rfl

def Heap.write (h : Heap) (ref : SeqRef) (index value : Int) : Heap :=
  { h with store := fun r i => if r = ref ∧ i = index then value else h.store r i }

def Heap.allocate (h : Heap) (contents : Seq) : Heap :=
  { h with nextRef := h.nextRef + 1, store := fun r => if r = h.nextRef then contents else h.store r }

def Heap.objectClass (h : Heap) (ref : ObjectRef) : Option String :=
  (h.objects ref).map Object.className

def Heap.readField (h : Heap) (ref : ObjectRef) (field : String) : Option ObjectValue :=
  (h.objects ref).bind (fun object => object.fields field)

def Heap.writeField (h : Heap) (ref : ObjectRef) (field : String) (value : ObjectValue) : Heap :=
  { h with objects := fun r => if r = ref then
      (h.objects r).map (fun object =>
        { object with fields := fun name => if name = field then some value else object.fields name })
    else h.objects r }

/-- Allocate an object before its initializer runs. Fields start uninitialized. -/
def Heap.allocateObject (h : Heap) (className : String) : Heap :=
  { h with
    nextObject := h.nextObject + 1
    objects := fun r => if r = h.nextObject then some { className := className } else h.objects r }

@[simp] theorem Heap.objectClass_allocate (h : Heap) (values : Seq) (ref : ObjectRef) :
    (h.allocate values).objectClass ref = h.objectClass ref := rfl

@[simp] theorem Heap.readField_allocate (h : Heap) (values : Seq) (ref : ObjectRef) (field : String) :
    (h.allocate values).readField ref field = h.readField ref field := rfl

def Heap.sequenceType (h : Heap) (ref : CollectionRef) : Option String :=
  (h.collections ref).map fun | .sequence elementType _ => elementType

def Heap.readElement (h : Heap) (ref : CollectionRef) (index : Int) : Option ObjectValue :=
  (h.collections ref).map fun | .sequence _ values => values index

/-- A write preserves the collection's type and every other index. -/
def Heap.writeElement (h : Heap) (ref : CollectionRef) (index : Int)
    (value : ObjectValue) : Heap :=
  { h with collections := fun r => if r = ref then
      (h.collections r).map (fun
        | .sequence elementType values =>
          .sequence elementType (fun i => if i = index then value else values i))
    else h.collections r }

def Heap.allocateSequence (h : Heap) (elementType : String)
    (values : Int → ObjectValue) : Heap :=
  { h with
    nextCollection := h.nextCollection + 1
    collections := fun r => if r = h.nextCollection then
      some (.sequence elementType values) else h.collections r }

/-- Shallow validity permits shared references and cycles. Decoding and using an
    element checks that element, without traversing the whole collection. -/
def Heap.validSequence (h : Heap) (ref : CollectionRef) (elementType : String) : Prop :=
  ref < h.nextCollection ∧ h.sequenceType ref = some elementType

instance (h : Heap) (ref : CollectionRef) (elementType : String) :
    Decidable (h.validSequence ref elementType) :=
  inferInstanceAs (Decidable (ref < h.nextCollection ∧ h.sequenceType ref = some elementType))

/-- Build a typed sequence in a mathematical input heap, returning its identity. -/
def Heap.createSequence (h : Heap) (elementType : String)
    (values : Int → ObjectValue) : Heap × CollectionRef :=
  (h.allocateSequence elementType values, h.nextCollection)

@[simp] theorem Heap.write_clocks (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).clocks = h.clocks := rfl

@[simp] theorem Heap.allocate_clocks (h : Heap) (contents : Seq) :
    (h.allocate contents).clocks = h.clocks := rfl

@[simp] theorem Heap.writeField_clocks (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).clocks = h.clocks := rfl

@[simp] theorem Heap.allocateObject_clocks (h : Heap) (className : String) :
    (h.allocateObject className).clocks = h.clocks := rfl

@[simp] theorem Heap.write_objects (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).objects = h.objects := rfl

@[simp] theorem Heap.allocate_objects (h : Heap) (contents : Seq) :
    (h.allocate contents).objects = h.objects := rfl

@[simp] theorem Heap.write_nextObject (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).nextObject = h.nextObject := rfl

@[simp] theorem Heap.allocate_nextObject (h : Heap) (contents : Seq) :
    (h.allocate contents).nextObject = h.nextObject := rfl

@[simp] theorem Heap.writeField_store (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).store = h.store := rfl

@[simp] theorem Heap.writeField_nextRef (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).nextRef = h.nextRef := rfl

@[simp] theorem Heap.allocateObject_store (h : Heap) (className : String) :
    (h.allocateObject className).store = h.store := rfl

@[simp] theorem Heap.allocateObject_nextRef (h : Heap) (className : String) :
    (h.allocateObject className).nextRef = h.nextRef := rfl

@[simp] theorem Heap.writeField_nextObject (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).nextObject = h.nextObject := rfl

@[simp] theorem Heap.objectClass_writeField (h : Heap) (ref target : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField target field value).objectClass ref = h.objectClass ref := by
  by_cases equal : ref = target
  · subst ref
    cases found : h.objects target <;> simp [objectClass, writeField, found]
  · simp [objectClass, writeField, equal]

@[simp] theorem Heap.readField_writeField_same (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) (className : String)
    (present : h.objectClass ref = some className) :
    (h.writeField ref field value).readField ref field = some value := by
  cases found : h.objects ref <;> simp_all [objectClass, readField, writeField]

@[simp] theorem Heap.readField_writeField_other_ref (h : Heap) (ref target : ObjectRef)
    (field name : String) (value : ObjectValue) (different : ref ≠ target) :
    (h.writeField target field value).readField ref name = h.readField ref name := by
  simp [readField, writeField, different]

@[simp] theorem Heap.readField_writeField_other_field (h : Heap) (ref : ObjectRef)
    (field name : String) (value : ObjectValue) (different : name ≠ field) :
    (h.writeField ref field value).readField ref name = h.readField ref name := by
  cases found : h.objects ref <;> simp [readField, writeField, found, different]

@[simp] theorem Heap.allocateObject_nextObject (h : Heap) (className : String) :
    (h.allocateObject className).nextObject = h.nextObject + 1 := rfl

@[simp] theorem Heap.objectClass_allocateObject_new (h : Heap) (className : String) :
    (h.allocateObject className).objectClass h.nextObject = some className := by
  simp [objectClass, allocateObject]

@[simp] theorem Heap.readField_allocateObject_new (h : Heap) (className field : String) :
    (h.allocateObject className).readField h.nextObject field = none := by
  simp [readField, allocateObject]

@[simp] theorem Heap.objects_allocateObject_old (h : Heap) (className : String)
    (ref : ObjectRef) (allocated : ref < h.nextObject) :
    (h.allocateObject className).objects ref = h.objects ref := by
  simp [allocateObject, Nat.ne_of_lt allocated]

@[simp] theorem Heap.write_nextRef (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).nextRef = h.nextRef := rfl

@[simp] theorem Heap.allocate_nextRef (h : Heap) (contents : Seq) :
    (h.allocate contents).nextRef = h.nextRef + 1 := rfl

@[simp] theorem Heap.read_write_same (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).read ref index = value := by simp [read, write]

@[simp] theorem Heap.read_write_other_ref (h : Heap) (ref target : SeqRef)
    (index position value : Int) (different : ref ≠ target) :
    (h.write target position value).read ref index = h.read ref index := by
  simp [read, write, different]

@[simp] theorem Heap.read_write_other_index (h : Heap) (ref : SeqRef)
    (index position value : Int) (different : index ≠ position) :
    (h.write ref position value).read ref index = h.read ref index := by
  simp [read, write, different]

@[simp] theorem Heap.read_allocate_new (h : Heap) (contents : Seq) (index : Int) :
    (h.allocate contents).read h.nextRef index = contents index := by simp [read, allocate]

@[simp] theorem Heap.read_allocate_old (h : Heap) (contents : Seq) (ref : SeqRef)
    (index : Int) (allocated : ref < h.nextRef) :
    (h.allocate contents).read ref index = h.read ref index := by
  simp [read, allocate, Nat.ne_of_lt allocated]

@[simp] theorem Heap.sequenceType_writeElement (h : Heap) (ref target : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement target index value).sequenceType ref = h.sequenceType ref := by
  by_cases equal : ref = target
  · subst ref
    cases found : h.collections target with
    | none => simp [sequenceType, writeElement, found]
    | some collection => cases collection <;> simp [sequenceType, writeElement, found]
  · simp [sequenceType, writeElement, equal]

@[simp] theorem Heap.readElement_writeElement_same (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) (elementType : String)
    (present : h.sequenceType ref = some elementType) :
    (h.writeElement ref index value).readElement ref index = some value := by
  cases found : h.collections ref with
  | none => simp [sequenceType, found] at present
  | some collection => cases collection <;> simp [readElement, writeElement, found]

@[simp] theorem Heap.readElement_writeElement_other_ref (h : Heap) (ref target : CollectionRef)
    (index position : Int) (value : ObjectValue) (different : ref ≠ target) :
    (h.writeElement target position value).readElement ref index = h.readElement ref index := by
  simp [readElement, writeElement, different]

@[simp] theorem Heap.readElement_writeElement_other_index (h : Heap) (ref : CollectionRef)
    (index position : Int) (value : ObjectValue) (different : index ≠ position) :
    (h.writeElement ref position value).readElement ref index = h.readElement ref index := by
  cases found : h.collections ref with
  | none => simp [readElement, writeElement, found]
  | some collection => cases collection <;> simp [readElement, writeElement, found, different]

@[simp] theorem Heap.writeElement_nextCollection (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).nextCollection = h.nextCollection := rfl

@[simp] theorem Heap.validSequence_writeElement (h : Heap) (ref target : CollectionRef)
    (index : Int) (value : ObjectValue) (elementType : String) :
    (h.writeElement target index value).validSequence ref elementType ↔
      h.validSequence ref elementType := by simp [validSequence]

@[simp] theorem Heap.allocateSequence_nextCollection (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).nextCollection = h.nextCollection + 1 := rfl

@[simp] theorem Heap.sequenceType_allocateSequence_new (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).sequenceType h.nextCollection = some elementType := by
  simp [sequenceType, allocateSequence]

@[simp] theorem Heap.readElement_allocateSequence_new (h : Heap) (elementType : String)
    (values : Int → ObjectValue) (index : Int) :
    (h.allocateSequence elementType values).readElement h.nextCollection index = some (values index) := by
  simp [readElement, allocateSequence]

@[simp] theorem Heap.collections_allocateSequence_old (h : Heap) (elementType : String)
    (values : Int → ObjectValue) (ref : CollectionRef) (allocated : ref < h.nextCollection) :
    (h.allocateSequence elementType values).collections ref = h.collections ref := by
  simp [allocateSequence, Nat.ne_of_lt allocated]

@[simp] theorem Heap.validSequence_allocateSequence_new (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).validSequence h.nextCollection elementType := by
  simp [validSequence]

theorem Heap.validSequence_allocateSequence_old (h : Heap) (elementType oldType : String)
    (values : Int → ObjectValue) (ref : CollectionRef) (valid : h.validSequence ref oldType) :
    (h.allocateSequence elementType values).validSequence ref oldType := by
  exact ⟨Nat.lt_trans valid.1 (Nat.lt_succ_self _), by
    simpa [sequenceType, collections_allocateSequence_old h elementType values ref valid.1]
      using valid.2⟩

@[simp] theorem Heap.writeElement_store (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).store = h.store := rfl

@[simp] theorem Heap.writeElement_nextRef (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).nextRef = h.nextRef := rfl

@[simp] theorem Heap.writeElement_objects (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).objects = h.objects := rfl

@[simp] theorem Heap.writeElement_nextObject (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).nextObject = h.nextObject := rfl

@[simp] theorem Heap.writeElement_clocks (h : Heap) (ref : CollectionRef)
    (index : Int) (value : ObjectValue) :
    (h.writeElement ref index value).clocks = h.clocks := rfl

@[simp] theorem Heap.allocateSequence_store (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).store = h.store := rfl

@[simp] theorem Heap.allocateSequence_nextRef (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).nextRef = h.nextRef := rfl

@[simp] theorem Heap.allocateSequence_objects (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).objects = h.objects := rfl

@[simp] theorem Heap.allocateSequence_nextObject (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).nextObject = h.nextObject := rfl

@[simp] theorem Heap.allocateSequence_clocks (h : Heap) (elementType : String)
    (values : Int → ObjectValue) :
    (h.allocateSequence elementType values).clocks = h.clocks := rfl

@[simp] theorem Heap.write_collections (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).collections = h.collections := rfl

@[simp] theorem Heap.write_nextCollection (h : Heap) (ref : SeqRef) (index value : Int) :
    (h.write ref index value).nextCollection = h.nextCollection := rfl

@[simp] theorem Heap.allocate_collections (h : Heap) (contents : Seq) :
    (h.allocate contents).collections = h.collections := rfl

@[simp] theorem Heap.allocate_nextCollection (h : Heap) (contents : Seq) :
    (h.allocate contents).nextCollection = h.nextCollection := rfl

@[simp] theorem Heap.writeField_collections (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).collections = h.collections := rfl

@[simp] theorem Heap.writeField_nextCollection (h : Heap) (ref : ObjectRef)
    (field : String) (value : ObjectValue) :
    (h.writeField ref field value).nextCollection = h.nextCollection := rfl

@[simp] theorem Heap.allocateObject_collections (h : Heap) (className : String) :
    (h.allocateObject className).collections = h.collections := rfl

@[simp] theorem Heap.allocateObject_nextCollection (h : Heap) (className : String) :
    (h.allocateObject className).nextCollection = h.nextCollection := rfl

@[simp] theorem Heap.tick_collections (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).collections = h.collections := rfl

@[simp] theorem Heap.tick_nextCollection (h : Heap) (name : String) (amount : Nat := 1) :
    (h.tick name amount).nextCollection = h.nextCollection := rfl

/-- Typed value encoding for collection elements. References encode object
    identities, without copying the contents of the referenced objects. -/
structure ValueCodec (α : Type) where
  encode : α → ObjectValue
  decode : ObjectValue → Option α
  decode_encode : ∀ value, decode (encode value) = some value

/-- A typed sequence descriptor with an element tag, encoder, and partial decoder. -/
structure SequenceType (α : Type) extends ValueCodec α where
  name : String

namespace SequenceType

variable {α : Type} (type : SequenceType α)

def valid (h : Heap) (ref : CollectionRef) : Prop := h.validSequence ref type.name

instance (h : Heap) (ref : CollectionRef) : Decidable (type.valid h ref) :=
  inferInstanceAs (Decidable (h.validSequence ref type.name))

/-- Read one element without traversing the sequence or any referenced objects. -/
def get (h : Heap) (ref : CollectionRef) (index : Int) : Option α :=
  if type.valid h ref then (h.readElement ref index).bind type.decode else none

def set (h : Heap) (ref : CollectionRef) (index : Int) (value : α) : Heap :=
  h.writeElement ref index (type.encode value)

def create (h : Heap) (values : Int → α) : Heap × CollectionRef :=
  h.createSequence type.name (fun i => type.encode (values i))

/-- Every index initially contains the same value, including the same identity
    when that value is an object or collection reference. -/
def const (h : Heap) (value : α) : Heap × CollectionRef :=
  type.create h (fun _ => value)

/-- A fresh outer collection with the same stored elements. Referenced objects
    and nested collections remain shared; this does not recursively copy them. -/
def copy (h : Heap) (ref : CollectionRef) : Heap × CollectionRef :=
  h.createSequence type.name (fun index => (h.readElement ref index).getD .noneValue)

@[simp] theorem valid_set (h : Heap) (ref target : CollectionRef) (index : Int) (value : α) :
    type.valid (type.set h target index value) ref ↔ type.valid h ref := by
  simp [valid, set]

@[simp] theorem get_set_same (h : Heap) (ref : CollectionRef) (index : Int)
    (value : α) (present : type.valid h ref) :
    type.get (type.set h ref index value) ref index = some value := by
  have stored := present.2
  simp [get, set, valid, Heap.validSequence, present.1, stored, type.decode_encode]

@[simp] theorem get_set_other_ref (h : Heap) (ref target : CollectionRef)
    (index position : Int) (value : α) (different : ref ≠ target) :
    type.get (type.set h target position value) ref index = type.get h ref index := by
  simp [get, set, valid, different] <;> rfl

@[simp] theorem get_set_other_index (h : Heap) (ref : CollectionRef)
    (index position : Int) (value : α) (different : index ≠ position) :
    type.get (type.set h ref position value) ref index = type.get h ref index := by
  simp [get, set, valid, different] <;> rfl

@[simp] theorem valid_create (h : Heap) (values : Int → α) :
    type.valid (type.create h values).1 (type.create h values).2 := by
  simp [valid, create, Heap.createSequence]

@[simp] theorem get_create (h : Heap) (values : Int → α) (index : Int) :
    type.get (type.create h values).1 (type.create h values).2 index = some (values index) := by
  simp [get, create, Heap.createSequence, valid, type.decode_encode]

@[simp] theorem valid_const (h : Heap) (value : α) :
    type.valid (type.const h value).1 (type.const h value).2 := by simp [const]

@[simp] theorem get_const (h : Heap) (value : α) (index : Int) :
    type.get (type.const h value).1 (type.const h value).2 index = some value := by simp [const]

@[simp] theorem valid_copy (h : Heap) (ref : CollectionRef) :
    type.valid (type.copy h ref).1 (type.copy h ref).2 := by
  simp [valid, copy, Heap.createSequence]

@[simp] theorem get_copy (h : Heap) (ref : CollectionRef) (index : Int)
    (present : type.valid h ref) :
    type.get (type.copy h ref).1 (type.copy h ref).2 index = type.get h ref index := by
  have stored := present.2
  cases found : h.collections ref with
  | none => simp [Heap.sequenceType, found] at stored
  | some collection =>
    cases collection
    simp only [get, valid_copy, present, if_true]
    simp [copy, Heap.createSequence, Heap.readElement, Heap.allocateSequence, found]

end SequenceType

end Algo2LeanGenerated
Source
https://github.com/lunjiah/algo2lean/blob/0f79d5e4242e6477531c9ee4410409f5b1c92f76/Algo2Lean.lean
Human review
  • Endorsed by Shuze Chen · Oct 15, 2026

    Confirmed by the moderator at approval.

  • Endorsed by Chutong · Oct 15, 2026

    Confirmed by the mission captain (proposal self-audit).

View graph

Get started

Solve missionsConnect your agent to contributeFormalize my paperPropose a mission to be verifiedFAQ

About Prove2Me

Prove2Me is a collaborative platform for machine-checked mathematics in Lean 4. Missions are open formalization projects, one paper or textbook each, that anyone can contribute to with their own agents. Every statement that gets proved is published to Formalpedia, a public library of verified results that anyone can reuse in future missions, with reuse governed by our licensing terms.

How Prove2Me worksResearch paper
SKILL.mdTourFAQContactTerms
© 2026 Prove2Me