Skip to content

simple functional queue from Okasaki#558

Open
c-cube wants to merge 8 commits into
leanprover:mainfrom
c-cube:c-cube/functionalQueue
Open

simple functional queue from Okasaki#558
c-cube wants to merge 8 commits into
leanprover:mainfrom
c-cube:c-cube/functionalQueue

Conversation

@c-cube
Copy link
Copy Markdown

@c-cube c-cube commented May 11, 2026

Hi, this is my first attempt at contributing Lean code.

I dug out the old Okasaki, and started off with the simple queue. This should
contain a correctness proof, a complexity proof, and a mapping to a ghost list
of elements. TimeM doesn't seem to be enough for amortized complexity so
I added a module for that, and I also removed the ZeroAdd typeclass constraint
because \N doesn't implement it(!).

AI disclosure: all code is mine, but I had some assistance from GLM 5.1 to
tidy up proof terms and get unstuck.

@c-cube c-cube force-pushed the c-cube/functionalQueue branch from b7c4a9c to a3c0424 Compare May 11, 2026 02:50
Comment thread Cslib/Algorithms/Lean/FunctionalQueue/FunctionalQueue.lean

/-- Physicist method: a potential (lower bound on savings) defined on a
data structure -/
class Potential α where
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, potential function arguments do not require non-negativity of the potential.

| pop =>
simp only [Amortized.Op.applyOp, applyOp, potential]
cases h_front : q.front <;> (rw [Raw.pop, h_front] at ⊢; grind [Raw.rebalance])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amortized cost is nice, but not immediately usable. To provide a good API for users, can you add a theorem about the total cost of a sequence of m operations on the queue of n elements? This should be at most 2m+n.

following Okasaki, chapter 5 -/
def amortizedCost {α o : Type*} [Op α o] [Potential α] (x : α) (op : o) : ℕ :=
(Op.applyOp x op).time + Potential.potential (Op.applyOp x op).ret - Potential.potential x

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some theorems/APIs about amortized cost imply that the total cost would be nice to have.

class Potential α where
/-- non-negative potential. Initial potential should be 0.
[Okasaki, *Purely Functional Data Structures*, 1996][okasaki1996] -/
potential : α → Nat
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic type is better. I wouldn't use Nat, as some applications may use real numbers. In some cases, we allow negative numbers.

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