-
Notifications
You must be signed in to change notification settings - Fork 193
feat(Query): query complexity framework with sorting examples #401
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8be8d07
e50c8b0
79d77de
c1e3323
ddab6f0
08decfa
a2b4782
54bb351
7ee16a0
cc806f0
a732ed8
2cee489
3e7edf2
4789639
afcfd57
30a7905
4e3d80c
9f3df4d
6db1fde
a9485da
6fef51f
f479c93
5e2a2f6
6b78316
4fab097
8097c61
87e7ded
3f71048
57856b7
53c2ef3
b712d16
1eeb2d8
7370fc6
df70978
275d827
e9cb648
7f4010e
d04ca73
e7c8bde
a8e9f3d
4ca216d
30cf281
a145ded
6761169
c6e1add
e07de01
cf9f1f5
56c98a5
1fb24e1
3fc5afd
7ece1dd
883edfd
7327006
de06cdf
b46a156
3bf2acb
3b93bad
2dc7d9f
391cab0
6fdf909
c3067db
40ea780
79c29f8
f257485
1cc3324
36e098c
2a83ed9
a2e9050
8727846
57b1c35
46d7d92
693c2c5
cd51b93
901c0ce
877cf1a
239b7ad
398c22b
8547036
09c565a
6a904b2
aee6621
dad82a1
0bd0e2a
b5e94ca
f6d8269
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| /- | ||
| Copyright (c) 2026 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Kim Morrison | ||
| -/ | ||
| module | ||
|
|
||
| public import Cslib.Algorithms.Lean.Query.FreeM | ||
|
|
||
| /-! # Arithmetic Queries and Complex Multiplication | ||
|
|
||
| A simple example showing how to use `FreeM.cost` with variable/parametrized query costs. | ||
|
|
||
| `ArithQuery α` supports addition, subtraction, and multiplication, each with | ||
| independently parametrized costs. Complex number multiplication provides a toy example | ||
| where two algorithms (naive and Gauss's trick) trade multiplications for additions, | ||
| and the optimal choice depends on the cost ratio. | ||
| -/ | ||
|
|
||
| public section | ||
|
|
||
| namespace Cslib.Query | ||
|
|
||
| /-- Arithmetic queries: addition, subtraction, and multiplication. -/ | ||
| inductive ArithQuery (α : Type) : Type → Type where | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You want a zero and one for completeness. Also if it is just an illustrative example, it belongs in the tests folder (see my PR).
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think a |
||
| | add (a b : α) : ArithQuery α α | ||
| | sub (a b : α) : ArithQuery α α | ||
| | mul (a b : α) : ArithQuery α α | ||
|
|
||
| namespace ArithQuery | ||
|
|
||
| /-- Lift `ArithQuery.add a b` into a `FreeM` that returns the sum. -/ | ||
| abbrev doAdd (a b : α) : FreeM (ArithQuery α) α := FreeM.lift (.add a b) | ||
| /-- Lift `ArithQuery.sub a b` into a `FreeM` that returns the difference. -/ | ||
| abbrev doSub (a b : α) : FreeM (ArithQuery α) α := FreeM.lift (.sub a b) | ||
| /-- Lift `ArithQuery.mul a b` into a `FreeM` that returns the product. -/ | ||
| abbrev doMul (a b : α) : FreeM (ArithQuery α) α := FreeM.lift (.mul a b) | ||
|
|
||
| /-- An honest oracle interprets arithmetic queries using the actual ring operations. -/ | ||
| @[expose] def honest [Add α] [Sub α] [Mul α] {ι : Type} : ArithQuery α ι → ι | ||
| | .add a b => a + b | ||
| | .sub a b => a - b | ||
| | .mul a b => a * b | ||
|
|
||
| /-- Weighted cost model for arithmetic queries. Subtraction costs the same as addition | ||
| (both are linear-time on bignums). -/ | ||
| @[expose] def weight (c_add c_mul : Nat) {ι : Type} : ArithQuery α ι → Nat | ||
| | .add _ _ => c_add | ||
| | .sub _ _ => c_add | ||
| | .mul _ _ => c_mul | ||
|
|
||
| end ArithQuery | ||
|
|
||
| /-- Naive complex multiplication: `(a + bi)(c + di) = (ac - bd) + (ad + bc)i`. | ||
| Uses 4 multiplications, 1 subtraction, 1 addition. -/ | ||
| @[expose] def complexMulNaive (a b c d : α) : FreeM (ArithQuery α) (α × α) := do | ||
| let ac ← ArithQuery.doMul a c | ||
| let bd ← ArithQuery.doMul b d | ||
| let ad ← ArithQuery.doMul a d | ||
| let bc ← ArithQuery.doMul b c | ||
| let real ← ArithQuery.doSub ac bd | ||
| let imag ← ArithQuery.doAdd ad bc | ||
| return (real, imag) | ||
|
|
||
| /-- Gauss's trick for complex multiplication: computes `(a+b)(c+d)` to save one | ||
| multiplication, at the cost of extra additions and subtractions. | ||
| Uses 3 multiplications, 2 subtractions, 3 additions. -/ | ||
| @[expose] def complexMulGauss (a b c d : α) : FreeM (ArithQuery α) (α × α) := do | ||
| let ac ← ArithQuery.doMul a c | ||
| let bd ← ArithQuery.doMul b d | ||
| let apb ← ArithQuery.doAdd a b | ||
| let cpd ← ArithQuery.doAdd c d | ||
| let abcd ← ArithQuery.doMul apb cpd | ||
| let real ← ArithQuery.doSub ac bd | ||
| let imag ← ArithQuery.doSub abcd (← ArithQuery.doAdd ac bd) | ||
| return (real, imag) | ||
|
|
||
| end Cslib.Query | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| /- | ||
| Copyright (c) 2026 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Kim Morrison | ||
| -/ | ||
| module | ||
|
|
||
| public import Cslib.Algorithms.Lean.Query.Arith.Defs | ||
| import Mathlib.Tactic.Ring | ||
| public import Mathlib.Algebra.Ring.Defs | ||
|
|
||
| /-! # Complex Multiplication: Correctness and Cost Analysis | ||
|
|
||
| A simple example showing how to use `FreeM.cost` with variable/parametrized query costs. | ||
|
|
||
| We prove that both `complexMulNaive` and `complexMulGauss` correctly compute | ||
| complex multiplication when given an honest oracle, and compute their exact | ||
| costs under a parametric weight function. The cost theorems hold for *any* oracle | ||
| (not just honest ones), because both algorithms are straight-line (no branching | ||
| on query results). | ||
| -/ | ||
|
|
||
| open Cslib.Query | ||
|
|
||
| public section | ||
|
|
||
| namespace Cslib.Query | ||
|
|
||
| variable {α : Type} | ||
|
|
||
| /-! ## Correctness -/ | ||
|
|
||
| theorem complexMulNaive_eval_honest [Add α] [Sub α] [Mul α] (a b c d : α) : | ||
| (complexMulNaive a b c d).eval ArithQuery.honest = (a * c - b * d, a * d + b * c) := by | ||
| simp [complexMulNaive, ArithQuery.doMul, ArithQuery.doSub, ArithQuery.doAdd, ArithQuery.honest] | ||
|
|
||
| theorem complexMulGauss_eval_honest [CommRing α] (a b c d : α) : | ||
| (complexMulGauss a b c d).eval ArithQuery.honest = (a * c - b * d, a * d + b * c) := by | ||
| simp [complexMulGauss, ArithQuery.doMul, ArithQuery.doSub, ArithQuery.doAdd, ArithQuery.honest] | ||
| ring | ||
|
|
||
| /-! ## Exact cost counts -/ | ||
|
|
||
| theorem complexMulNaive_cost (oracle : {ι : Type} → ArithQuery α ι → ι) | ||
| (c_add c_mul : Nat) (a b c d : α) : | ||
| (complexMulNaive a b c d).cost oracle (ArithQuery.weight c_add c_mul) = | ||
| 4 * c_mul + 2 * c_add := by | ||
| simp [complexMulNaive, ArithQuery.doMul, ArithQuery.doSub, ArithQuery.doAdd, ArithQuery.weight] | ||
| omega | ||
|
|
||
| theorem complexMulGauss_cost (oracle : {ι : Type} → ArithQuery α ι → ι) | ||
| (c_add c_mul : Nat) (a b c d : α) : | ||
| (complexMulGauss a b c d).cost oracle (ArithQuery.weight c_add c_mul) = | ||
| 3 * c_mul + 5 * c_add := by | ||
| simp [complexMulGauss, ArithQuery.doMul, ArithQuery.doSub, ArithQuery.doAdd, ArithQuery.weight] | ||
| omega | ||
|
|
||
| /-! ## Crossover: Gauss beats naive when multiplication costs at least 3× addition -/ | ||
|
|
||
| theorem gauss_le_naive (oracle : {ι : Type} → ArithQuery α ι → ι) | ||
| (c_add c_mul : Nat) (a b c d : α) (h : 3 * c_add ≤ c_mul) : | ||
| (complexMulGauss a b c d).cost oracle (ArithQuery.weight c_add c_mul) ≤ | ||
| (complexMulNaive a b c d).cost oracle (ArithQuery.weight c_add c_mul) := by | ||
| rw [complexMulGauss_cost, complexMulNaive_cost] | ||
| omega | ||
|
|
||
| theorem gauss_le_naive_iff (oracle : {ι : Type} → ArithQuery α ι → ι) | ||
| (c_add c_mul : Nat) (a b c d : α) : | ||
| (complexMulGauss a b c d).cost oracle (ArithQuery.weight c_add c_mul) ≤ | ||
| (complexMulNaive a b c d).cost oracle (ArithQuery.weight c_add c_mul) ↔ | ||
| 3 * c_add ≤ c_mul := by | ||
| rw [complexMulGauss_cost, complexMulNaive_cost] | ||
| omega | ||
|
|
||
| end Cslib.Query |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /- | ||
| Copyright (c) 2026 Lean FRO, LLC. All rights reserved. | ||
| Released under Apache 2.0 license as described in the file LICENSE. | ||
| Authors: Sebastian Graf, Kim Morrison, Shreyas Srinivas | ||
| -/ | ||
| module | ||
|
|
||
| public import Cslib.Algorithms.Lean.Query.FreeM | ||
| public import Mathlib.Order.Monotone.Defs | ||
|
|
||
| /-! # Upper and Lower Bounds for Query Complexity | ||
|
|
||
| Definitions of upper and lower bounds on the number of queries a program makes, | ||
| quantified over oracles. | ||
| -/ | ||
|
|
||
| public section | ||
|
|
||
| namespace Cslib.Query | ||
|
|
||
| universe u v w | ||
|
|
||
| variable {α : Type w} {Q : Type u → Type v} {β : Type u} | ||
|
|
||
| /-- Upper bound: for all oracles, inputs of size ≤ n make at most `bound n` queries. -/ | ||
| @[expose] def UpperBound (prog : α → FreeM Q β) | ||
| (size : α → Nat) (bound : Nat → Nat) : Prop := | ||
| ∀ (oracle : {ι : Type u} → Q ι → ι) (n : Nat) (x : α), | ||
| size x ≤ n → (prog x).countQueries oracle ≤ bound n | ||
|
|
||
| /-- Lower bound: for every size n, there exists an input of size at most n and an oracle | ||
| making the program perform ≥ `bound n` queries. -/ | ||
| @[expose] def LowerBound (prog : α → FreeM Q β) | ||
| (size : α → Nat) (bound : Nat → Nat) : Prop := | ||
| ∀ (n : Nat), ∃ (x : α), size x ≤ n ∧ | ||
| ∃ (oracle : {ι : Type u} → Q ι → ι), bound n ≤ (prog x).countQueries oracle | ||
|
|
||
| /-- To prove an `UpperBound` with a monotone bound function, it suffices to bound the | ||
| query count of each input by `bound` at its own size. -/ | ||
| theorem UpperBound.of_pointwise {prog : α → FreeM Q β} {size : α → Nat} {bound : Nat → Nat} | ||
| (hmono : Monotone bound) | ||
| (h : ∀ (oracle : {ι : Type u} → Q ι → ι) (x : α), | ||
| (prog x).countQueries oracle ≤ bound (size x)) : | ||
| UpperBound prog size bound := | ||
| fun oracle _n x hx => (h oracle x).trans (hmono hx) | ||
|
|
||
| /-- A lower bound for a program never exceeds an upper bound for the same program and | ||
| size function. -/ | ||
| theorem LowerBound.le_upperBound {prog : α → FreeM Q β} {size : α → Nat} {l u : Nat → Nat} | ||
| (hl : LowerBound prog size l) (hu : UpperBound prog size u) (n : Nat) : l n ≤ u n := by | ||
| obtain ⟨x, hx, oracle, hbound⟩ := hl n | ||
| exact hbound.trans (hu oracle n x hx) | ||
|
|
||
| end Cslib.Query |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the Arith Prog from my CslibTests files?