Skip to content

Commit

Permalink
Latex utilities for leanblueprint
Browse files Browse the repository at this point in the history
  • Loading branch information
metinersin committed Aug 11, 2024
1 parent 3245ade commit f4e5e3f
Showing 1 changed file with 315 additions and 0 deletions.
315 changes: 315 additions & 0 deletions AutoBlueprint/Latex/Basic.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
-- import Mathlib.ModelTheory.Basic
import Mathlib.Tactic.Linarith

section

def ite_lt [LT α] {x y : α} {flag : Prop} [Decidable flag] {z : α} (h₁ : x < z) (h₂ : y < z)
: (if flag then x else y) < z := by
by_cases hf : flag <;> {simp only [hf]; assumption}

private def parse_line? (line : String) (field : String) : Option String :=
let line := line.trim
if line.startsWith ("\\" ++ field ++ "{") && line.endsWith "}" then
let value := String.mk line.data.toArray[field.length + 2:line.length - 1].toArray.toList
if value.length > 0 then some value else none
else none

private def parse_first_line? (line : String) : Option String :=
parse_line? line "begin"

private def parse_last_line? (line : String) : Option String :=
parse_line? line "end"

private def parse_label? (line : String) : Option String :=
parse_line? line "label"

private def parse_name? (line : String) : Option String :=
parse_line? line "lean"

private def parse_uses? (line : String) : Option (List String) :=
let content := parse_line? line "uses"
match content with
| none => none
| some content =>
let lst := List.map String.trim (content.splitOn ",")
some lst

private def parse_content (lines : List String) : String :=
String.intercalate "\n" (lines.filter (fun line => ¬ line.startsWith "\\"))

private def split_environments? (s : String) : Option (String × String) :=
let lines := List.map String.trim (s.splitOn "\n")
let begins := List.findIdxs (fun line => not (parse_first_line? line).isNone) lines
let ends := List.findIdxs (fun line => not (parse_last_line? line).isNone) lines
match hb : begins.length, he : ends.length with
| 2, 2 =>
let begin₁ := begins[0]
let end₁ := ends[0]
let begin₂ := begins[1]
let end₂ := ends[1]
some ⟨String.intercalate "\n" (lines.toArray[begin₁:end₁ + 1].toArray.toList),
String.intercalate "\n" (lines.toArray[begin₂:end₂ + 1].toArray.toList)⟩
| _, _ => none


end

structure EnvironmentWithoutProof where
type : String
leanok : Bool
uses : List String
content : String

namespace EnvironmentWithoutProof --region

instance : ToString EnvironmentWithoutProof where
toString env :=
"\\begin{" ++ env.type ++ "}\n" ++
(if env.leanok then "\\leanok\n" else "") ++
"\\uses{" ++ (String.intercalate ", " env.uses) ++ "}\n" ++
env.content ++ "\n" ++
"\\end{" ++ env.type ++ "}\n"

def parse? (s : String) : Option EnvironmentWithoutProof :=
let lines := List.map String.trim (s.splitOn "\n")
let len := lines.length
match h : len with
| 0 | 1 | 2 => none
| n + 3 =>
let type_first? := parse_first_line? lines[0]
let type_last? := parse_last_line? lines[len - 1]
match type_first?, type_last? with
| _, none | none, _ => none
| some type, some type' =>
if type ≠ type' then none else
let leanok := lines[1] == "\\leanok"
let uses_idx := if leanok then 2 else 1
let uses? := parse_uses? (lines[uses_idx]'(by apply ite_lt <;> linarith))
match uses? with
| none => none
| some uses =>
let content := parse_content lines
some {type := type, leanok := leanok, uses := uses, content := content}

end EnvironmentWithoutProof --end

structure ProofEnvironment where
leanok : Bool
uses : List String
content : String

def EnvironmentWithoutProof.toProofEnvironment {env : EnvironmentWithoutProof} (_ : env.type = "proof")
: ProofEnvironment :=
{leanok := env.leanok, uses := env.uses, content := env.content}

namespace ProofEnvironment --region

def toEnvironmentWithoutProof (env : ProofEnvironment) : EnvironmentWithoutProof :=
{env with type := "proof"}

instance : Coe ProofEnvironment EnvironmentWithoutProof where
coe env := env.toEnvironmentWithoutProof

instance : ToString ProofEnvironment where
toString env := toString (env : EnvironmentWithoutProof)

def parse? (s : String) : Option ProofEnvironment :=
let env? := EnvironmentWithoutProof.parse? s
match env? with
| none => none
| some env =>
if h : env.type ≠ "proof" then none else
some $ env.toProofEnvironment (by push_neg at h; exact h)

end ProofEnvironment --end

structure EnvironmentWithProof where
type : String
label : String
name : String
leanok : Bool
uses : List String
content : String
proof : ProofEnvironment

namespace EnvironmentWithProof --region

instance : ToString EnvironmentWithProof where
toString env :=
"\\begin{" ++ env.type ++ "}\n" ++
"\\label{" ++ env.label ++ "}\n" ++
"\\lean{" ++ env.name ++ "}\n" ++
(if env.leanok then "\\leanok\n" else "") ++
"\\uses{" ++ (String.intercalate ", " env.uses) ++ "}\n" ++
env.content ++ "\n" ++
"\\end{" ++ env.type ++ "}\n" ++
toString env.proof

def parse? (s : String) : Option EnvironmentWithProof :=
let s? := split_environments? s
match s? with
| none => none
| some (s₁, s₂) =>
let lines := List.map String.trim (s₁.splitOn "\n")
let len := lines.length
match h : len with
| 0 | 1 | 2 | 3 | 4 => none
| n + 5 =>
let type_first? := parse_first_line? lines[0]
let type_last? := parse_last_line? lines[len - 1]
match type_first?, type_last? with
| _, none | none, _ => none
| some type, some type' =>
if type ≠ type' then none else
let label? := parse_label? lines[1]
match label? with
| none => none
| some label =>
let name? := parse_name? lines[2]
match name? with
| none => none
| some name =>
let leanok := lines[3] == "\\leanok"
let uses_idx := if leanok then 4 else 3
let uses? := parse_uses? (lines[uses_idx]'(by apply ite_lt <;> linarith))
match uses? with
| none => none
| some uses =>
let content := parse_content lines
let proof? := ProofEnvironment.parse? s₂
match proof? with
| none => none
| some proof =>
some {type := type, label := label, name := name, leanok := leanok,
uses := uses, content := content, proof := proof}

end EnvironmentWithProof --end

structure TheoremEnvironment where
label : String
name : String
leanok : Bool
uses : List String
content : String
proof : ProofEnvironment

def EnvironmentWithProof.toTheoremEnvironment {env : EnvironmentWithProof} (_ : env.type = "theorem")
: TheoremEnvironment :=
{label := env.label, name := env.name, leanok := env.leanok,
uses := env.uses, content := env.content, proof := env.proof}

namespace TheoremEnvironment --region

def toEnvironmentWithProof (env : TheoremEnvironment) : EnvironmentWithProof :=
{env with type := "theorem"}

instance : Coe TheoremEnvironment EnvironmentWithProof where
coe := toEnvironmentWithProof

instance : ToString TheoremEnvironment where
toString env := toString (env : EnvironmentWithProof)

def parse? (s : String) : Option TheoremEnvironment :=
let env? := EnvironmentWithProof.parse? s
match env? with
| none => none
| some env =>
if h : env.type ≠ "theorem" then none else
some $ env.toTheoremEnvironment (by push_neg at h; exact h)

end TheoremEnvironment --end

structure LemmaEnvironment where
label : String
name : String
leanok : Bool
uses : List String
content : String
proof : ProofEnvironment

def EnvironmentWithProof.toLemmaEnvironment {env : EnvironmentWithProof} (_ : env.type = "lemma")
: LemmaEnvironment :=
{label := env.label, name := env.name, leanok := env.leanok,
uses := env.uses, content := env.content, proof := env.proof}

namespace LemmaEnvironment --region

def toEnvironmentWithProof (env : LemmaEnvironment) : EnvironmentWithProof :=
{env with type := "theorem"}

instance : Coe LemmaEnvironment EnvironmentWithProof where
coe env := env.toEnvironmentWithProof

instance : ToString LemmaEnvironment where
toString env := toString (env : EnvironmentWithProof)

def parse? (s : String) : Option LemmaEnvironment :=
let env? := EnvironmentWithProof.parse? s
match env? with
| none => none
| some env =>
if h : env.type ≠ "lemma" then none else
some $ env.toLemmaEnvironment (by push_neg at h; exact h)

end LemmaEnvironment --end

namespace BlueprintLatex.Test --region

def env₁ : ProofEnvironment where
leanok := false
uses := ["thm:merhaba"]
content := "This is a proof."

def env₂ : TheoremEnvironment where
label := "thm:current_theorem"
name := "FirstOrder.Language.mytheorem"
leanok := true
uses := ["thm:old-theorem", "lem:old-lemma", "def:old-definition"]
content := "This is a very important theorem."
proof := env₁

#eval env₁
#eval env₂

open EnvironmentWithoutProof

def test_parse_line? : IO Unit := do
let line := "\\begin{merhaba}"
IO.println (parse_line? line "begin")

def test_parse₁? : IO Unit := do
let stream ← IO.FS.Handle.mk "proof.tex" IO.FS.Mode.read
let s ← stream.readToEnd
let env? := parse? s
match env? with
| none => IO.println "No environment found"
| some env =>
IO.println $ "type: " ++ env.type
IO.println $ "leanok: " ++ reprStr env.leanok
IO.println $ "uses: " ++ env.uses.toString
IO.println $ "content: " ++ env.content

def test_splitEnvironment? : IO Unit := do
let stream ← IO.FS.Handle.mk "theorem.tex" IO.FS.Mode.read
let s ← stream.readToEnd
let envs? := split_environments? s
match envs? with
| none => IO.println "No environments found"
| some (env₁, env₂) => do
IO.println env₁
IO.println env₂

def test_parse?_theorem : IO Unit := do
let stream ← IO.FS.Handle.mk "theorem.tex" IO.FS.Mode.read
let s ← stream.readToEnd
let env? := TheoremEnvironment.parse? s
match env? with
| none => IO.println "No theorem found"
| some env => IO.println env

#eval test_parse_line?
#eval test_parse₁?
#eval test_splitEnvironment?
#eval test_parse?_theorem

end BlueprintLatex.Test --end

0 comments on commit f4e5e3f

Please sign in to comment.