Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions Ix/Aiur/Formal/Example.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
module
public import Ix.Aiur.Formal.ExampleMainSem

/-!
# Aiur Formal Verification — Example Proofs

Proves properties about the Aiur programs defined across two toplevels:
- `ExampleBase.lean`: `Pair`, `Expr`, `eval`, `swap` → `ExampleBaseSem.lean`
- `ExampleMain.lean`: `ExprList`, `list_sum`, `assert_eval`, `GList‹T›`,
`length‹T›`, `add_noise`, `use_unconstrained` → `ExampleMainSem.lean`

Demonstrates formal verification of generic types (§9), and the contrast
between constrained and unconstrained call semantics (§10).
-/

public section

open Aiur exampleBase exampleMain

-- ============================================================
-- 1. Eval is deterministic
-- ============================================================

theorem eval_deterministic {e : Expr} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : eval e v₁ P₁) (h₂ : eval e v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 _ _ ih₁ ih₂ =>
cases h₂ with
| path1 h₂a h₂b =>
show _ + _ = _ + _
congr 1
· exact ih₁ h₂a hP₁.1 hP₂.1
· exact ih₂ h₂b hP₁.2 hP₂.2
| path2 _ ih =>
cases h₂ with
| path2 h₂a =>
show (0 : G) - _ = (0 : G) - _
congr 1; exact ih h₂a hP₁ hP₂

-- ============================================================
-- 2. Eval is total
-- ============================================================

theorem eval_total (e : Expr) :
∃ (v : G) (P : Prop), eval e v P ∧ P := by
induction e with
| Lit n => exact ⟨n, True, .path0, trivial⟩
| Add a b iha ihb =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
obtain ⟨vb, Pb, hb, hPb⟩ := ihb
exact ⟨va + vb, Pa ∧ Pb, .path1 ha hb, hPa, hPb⟩
| Neg a iha =>
obtain ⟨va, Pa, ha, hPa⟩ := iha
exact ⟨(0 : G) - va, Pa, .path2 ha, hPa⟩

-- ============================================================
-- 3. Swap is an involution
-- ============================================================

theorem swap_involution {p q r : Pair} {P₁ P₂ : Prop}
(h₁ : swap p q P₁) (h₂ : swap q r P₂)
(_ : P₁) (_ : P₂) : r = p := by
cases h₁; cases h₂; rfl

-- ============================================================
-- 4. assert_eval semantics
-- ============================================================

theorem assert_eval_correct {e : Expr} {expected : G} {P : Prop}
(h : assert_eval e expected () P) (hP : P) :
∃ v Pv, eval e v Pv ∧ Pv ∧ v = expected := by
cases h with
| path0 h_eval => exact ⟨_, _, h_eval, hP.1, hP.2⟩

-- ============================================================
-- 5. list_sum is deterministic (uses eval_deterministic cross-toplevel)
-- ============================================================

theorem list_sum_deterministic {xs : ExprList} {v₁ v₂ : G} {P₁ P₂ : Prop}
(h₁ : list_sum xs v₁ P₁) (h₂ : list_sum xs v₂ P₂)
(hP₁ : P₁) (hP₂ : P₂) : v₁ = v₂ := by
induction h₁ generalizing v₂ P₂ with
| path0 => cases h₂; rfl
| path1 h₁e _ ih =>
cases h₂ with
| path1 h₂e h₂r =>
show _ + _ = _ + _
congr 1
· exact eval_deterministic h₁e h₂e hP₁.1 hP₂.1
· exact ih h₂r hP₁.2 hP₂.2

-- ============================================================
-- 6. Spec-based: eval matches a Lean function
-- ============================================================

def evalSpec : Expr → G
| .Lit n => n
| .Add a b => evalSpec a + evalSpec b
| .Neg a => (0 : G) - evalSpec a

theorem eval_sound {e : Expr} {v : G} {P : Prop}
(h : eval e v P) (hP : P) : v = evalSpec e := by
induction h with
| path0 => rfl
| path1 _ _ ih₁ ih₂ => simp only [evalSpec, ih₁ hP.1, ih₂ hP.2]
| path2 _ ih => simp only [evalSpec, ih hP]

-- ============================================================
-- 7. Mutual types: tree_sum / forest_sum match Lean specs
-- ============================================================

mutual
def treeSpec : Tree → G
| .Leaf n => n
| .Node n f => n + forestSpec f

def forestSpec : Forest → G
| .Empty => 0
| .Cons t rest => treeSpec t + forestSpec rest
end

mutual
def tree_sum_sound {t : Tree} {v : G} {P : Prop}
(h : tree_sum t v P) (hP : P) : v = treeSpec t := by
cases h with
| path0 => rfl
| path1 hf => simp only [treeSpec, forest_sum_sound hf hP]

def forest_sum_sound {f : Forest} {v : G} {P : Prop}
(h : forest_sum f v P) (hP : P) : v = forestSpec f := by
cases h with
| path0 => rfl
| path1 ht hf => simp only [forestSpec, tree_sum_sound ht hP.1, forest_sum_sound hf hP.2]
end

-- ============================================================
-- 8. Mutual recursion: is_even and is_odd constraints are exclusive
--
-- The path0 constraint (`G.eqZero n = 1`) and the path1 constraint
-- (`G.eqZero n = 0`) cannot both hold. This means path0 and path1
-- can never fire for the same `n`, which is what makes the mutual
-- semantic propositions deterministic.
-- ============================================================

theorem even_odd_path_exclusive {n : G}
(h0 : G.eqZero n = (1 : G)) (h1 : G.eqZero n = (0 : G)) : False :=
absurd (h0.symm.trans h1) G.one_ne_zero

theorem even_zero {n r : G} {P : Prop}
(h : is_even n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (1 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

theorem odd_zero {n r : G} {P : Prop}
(h : is_odd n r P) (hP : P) (hz : G.eqZero n = (1 : G)) :
r = (0 : G) := by
cases h with
| path0 => rfl
| path1 _ => exact (even_odd_path_exclusive hz hP.2).elim

-- ============================================================
-- 9. Generic types: length matches a Lean spec
-- ============================================================

def lengthSpec : GList α → G
| .Nil => 0
| .Cons _ rest => (1 : G) + lengthSpec rest

theorem length_sound {xs : GList α} {v : G} {P : Prop}
(h : length xs v P) (hP : P) : v = lengthSpec xs := by
induction h with
| path0 => rfl
| path1 _ ih => simp only [lengthSpec, ih hP]

-- ============================================================
-- 10. Unconstrained calls: nothing can be said about the result
--
-- `use_unconstrained x` produces `x + u0` where `u0` is universally
-- quantified, so the result can be ANY value of the form `x + _`.
-- We prove two things:
-- (a) The result is always of the form `x + something`.
-- (b) Unlike `add_noise` (constrained), we CANNOT show the result
-- is always `x + x`.
-- ============================================================

theorem use_unconstrained_form {x v : G} {P : Prop}
(h : use_unconstrained x v P) : ∃ y, v = x + y := by
cases h with
| path0 => exact ⟨_, rfl⟩

-- Contrast with the constrained version:
theorem add_noise_deterministic {x v : G} {P : Prop}
(h : add_noise x v P) : v = x + x := by
cases h with
| path0 => rfl

end
52 changes: 52 additions & 0 deletions Ix/Aiur/Formal/ExampleBase.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
module
public import Ix.Aiur.Meta
public import Ix.Aiur.Formal.GenSem

/-!
# Aiur Formal Verification — Example Base

Defines a small expression language with an evaluator.
`Example.lean` builds on this with composite types.
-/

open Aiur

def exampleBase := ⟦
type Pair = (G, G)

enum Expr {
Lit(G),
Add(&Expr, &Expr),
Neg(&Expr)
}

fn double_eval(e: Expr) -> G {
eval(e) + eval(e)
}

fn eval(e: Expr) -> G {
match e {
Expr.Lit(n) => n,
Expr.Add(&a, &b) => eval(a) + eval(b),
Expr.Neg(&a) => 0 - eval(a),
}
}

fn swap(p: Pair) -> Pair {
(proj(p, 1), proj(p, 0))
}

fn simplify_neg(e: Expr) -> Expr {
match e {
Expr.Neg(&inner) =>
match inner {
Expr.Neg(&x) => x,
Expr.Lit(n) => Expr.Lit(0 - n),
_ => e,
},
_ => e,
}
}

#aiur_gen exampleBase "ExampleBaseSem.lean" #
55 changes: 55 additions & 0 deletions Ix/Aiur/Formal/ExampleBaseSem.lean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
-- Auto-generated by #aiur_gen. Regenerate, don't edit.
module
public import Ix.Aiur.Goldilocks

public section

namespace exampleBase

open Aiur

-- ══════ Semantic types ══════

abbrev Pair := (G × G)

inductive Expr where
| Lit : G → Expr
| Add : Expr → Expr → Expr
| Neg : Expr → Expr

-- ══════ Semantic propositions ══════

inductive eval : Expr → G → Prop → Prop where
| path0 :
eval (Expr.Lit n) n True
| path1 :
eval a r0 P0 →
eval b r1 P1 →
eval (Expr.Add a b) (r0 + r1) (P0 ∧ P1)
| path2 :
eval a r0 P0 →
eval (Expr.Neg a) ((0 : G) - r0) (P0)

inductive swap : Pair → Pair → Prop → Prop where
| path0 :
swap p ((p).2, (p).1) True

inductive simplify_neg : Expr → Expr → Prop → Prop where
| path0 :
simplify_neg (Expr.Neg (Expr.Neg x)) x True
| path1 :
simplify_neg (Expr.Neg (Expr.Lit n)) (Expr.Lit ((0 : G) - n)) True
| path2 :
simplify_neg (Expr.Neg _) e True
| path3 :
simplify_neg _ e True

inductive double_eval : Expr → G → Prop → Prop where
| path0 :
eval e r0 P0 →
eval e r1 P1 →
double_eval e (r0 + r1) (P0 ∧ P1)

end exampleBase

end
Loading
Loading