import RegexDeriv.Std.Linter.DetectClassical import RegexDeriv.Std.Lists namespace Language open List -- Definitions def Lang (α: Type): Type := List α -> Prop def emptyset : Lang α := fun _ => False def universal {α: Type} : Lang α := fun _ => True def emptystr {α: Type} : Lang α := fun xs => xs = [] def char {α: Type} (x : α): Lang α := fun xs => xs = [x] def pred {α: Type} (p : α -> Prop): Lang α := fun xs => ∃ x, xs = [x] /\ p x def any {α: Type}: Lang α := fun xs => ∃ x, xs = [x] -- onlyif is used as an and to make derive char not require an if statement -- (derive (char c) a) w <-> (onlyif (a = c) emptystr) def onlyif {α: Type} (cond : Prop) (R : Lang α) : Lang α := fun xs => cond /\ R xs def or {α: Type} (P : Lang α) (Q : Lang α) : Lang α := fun xs => P xs \/ Q xs def and {α: Type} (P : Lang α) (Q : Lang α) : Lang α := fun xs => P xs /\ Q xs def concat {α: Type} (P : Lang α) (Q : Lang α) : Lang α := fun (xs : List α) => ∃ (xs1 : List α) (xs2 : List α), P xs1 /\ Q xs2 /\ xs = (xs1 ++ xs2) inductive star {α: Type} (R: Lang α): Lang α where | zero: star R [] | more: ∀ (x: α) (xs1 xs2 xs: List α), xs = (x::xs1) ++ xs2 -> R (x::xs1) -> star R xs2 -> star R xs def not {α: Type} (R: Lang α): Lang α := fun xs => (Not (R xs)) -- attribute [simp] allows these definitions to be unfolded when using the simp tactic. attribute [simp] universal emptyset emptystr char onlyif or and concat example: Lang α := universal example: Lang α := emptystr example: Lang α := (or emptystr universal) example: Lang α := (and emptystr universal) example: Lang α := emptyset example: Lang α := (star emptyset) example: Lang Char := char 'a' example: Lang Char := char 'b' example: Lang Char := (or (char 'a') emptyset) example: Lang Char := (and (char 'a') (char 'b')) example: Lang Nat := (and (char 1) (char 2)) example: Lang Nat := (onlyif True (char 2)) example: Lang Nat := (concat (char 1) (char 2)) def null {α: Type} (R: Lang α): Prop := R [] def derives {α: Type} (R: Lang α) (xs: List α): Lang α := λ ys => R (xs ++ ys) def derive {α: Type} (R: Lang α) (x: α): Lang α := derives R [x] def derive' {α: Type} (R: Lang α) (x: α): Lang α := fun (xs: List α) => R (x :: xs) attribute [simp] null derive derives derive' theorem derive_is_derive' {α: Type} (R: Lang α) (x: α): derive R x = derive' R x := rfl theorem derives_empty_list {α: Type} (R: Lang α): derives R [] = R := rfl theorem derives_strings {α: Type} (R: Lang α) (xs ys: List α): derives R (xs ++ ys) = derives (derives R xs) ys := match xs with | [] => rfl | (x :: xs) => derives_strings (derive R x) xs ys theorem derives_step {α: Type} (R: Lang α) (x: α) (xs: List α): derives R (x :: xs) = derives (derive R x) xs := by simp only [derive] rw [<- derives_strings] congr theorem null_derives {α: Type} (R: Lang α) (xs: List α): (null ∘ derives R) xs = R xs := by unfold derives unfold null simp only [Function.comp_apply] simp only [append_nil] theorem validate {α: Type} (R: Lang α) (xs: List α): null (derives R xs) = R xs := by unfold derives unfold null simp only [append_nil] theorem derives_foldl (R: Lang α) (xs: List α): (derives R) xs = (List.foldl derive R) xs := by revert R induction xs with | nil => unfold derives simp only [nil_append, foldl_nil, implies_true] | cons x xs ih => simp intro R rw [derives_step] rw [ih (derive R x)] simp only [derive] -- Theorems: null theorem null_emptyset {α: Type}: @null α emptyset = False := rfl theorem null_iff_emptyset {α: Type}: @null α emptyset <-> False := by rw [null_emptyset] theorem not_null_if_emptyset {α: Type}: @null α emptyset -> False := null_iff_emptyset.mp theorem null_universal {α: Type}: @null α universal = True := rfl theorem null_iff_emptystr {α: Type}: @null α emptystr <-> True := Iff.intro (fun _ => True.intro) (fun _ => rfl) theorem null_if_emptystr {α: Type}: @null α emptystr := rfl theorem null_emptystr {α: Type}: @null α emptystr = True := by rw [null_iff_emptystr] theorem null_iff_any {α: Type}: @null α any <-> False := Iff.intro nofun nofun theorem not_null_if_any {α: Type}: @null α any -> False := nofun theorem null_any {α: Type}: @null α any = False := by rw [null_iff_any] theorem null_iff_char {α: Type} {c: α}: null (char c) <-> False := Iff.intro nofun nofun theorem not_null_if_char {α: Type} {c: α}: null (char c) -> False := nofun theorem null_char {α: Type} {c: α}: null (char c) = False := by rw [null_iff_char] theorem null_iff_pred {α: Type} {p: α -> Prop}: null (pred p) <-> False := Iff.intro nofun nofun theorem not_null_if_pred {α: Type} {p: α -> Prop}: null (pred p) -> False := nofun theorem null_pred {α: Type} {p: α -> Prop}: null (pred p) = False := by rw [null_iff_pred] theorem null_or {α: Type} {P Q: Lang α}: null (or P Q) = ((null P) \/ (null Q)) := rfl theorem null_iff_or {α: Type} {P Q: Lang α}: null (or P Q) <-> ((null P) \/ (null Q)) := by rw [null_or] theorem null_and {α: Type} {P Q: Lang α}: null (and P Q) = ((null P) /\ (null Q)) := rfl theorem null_iff_concat {α: Type} {P Q: Lang α}: null (concat P Q) <-> ((null P) /\ (null Q)) := by refine Iff.intro ?toFun ?invFun case toFun => intro ⟨x, y, hx, hy, hxy⟩ simp only [nil_eq, append_eq_nil_iff] at hxy simp only [hxy] at hx hy exact ⟨hx, hy⟩ case invFun => exact fun ⟨x, y⟩ => ⟨[], [], x, y, rfl⟩ theorem null_concat {α: Type} {P Q: Lang α}: null (concat P Q) = ((null P) /\ (null Q)) := by rw [null_iff_concat] theorem null_if_star {α: Type} {R: Lang α}: null (star R) := star.zero theorem null_iff_star {α: Type} {R: Lang α}: null (star R) <-> True := Iff.intro (fun _ => True.intro) (fun _ => star.zero) theorem null_star {α: Type} {R: Lang α}: null (star R) = True := by rw [null_iff_star] theorem null_not {α: Type} {R: Lang α}: null (not R) = null (Not ∘ R) := rfl theorem null_iff_not {α: Type} {R: Lang α}: null (not R) <-> null (Not ∘ R) := by rw [null_not] -- Theorems: derive theorem derive_emptyset {α: Type} {a: α}: (derive emptyset a) = emptyset := rfl theorem derive_universal {α: Type} {a: α}: (derive universal a) = universal := rfl theorem derive_iff_emptystr {α: Type} {a: α} {w: List α}: (derive emptystr a) w <-> emptyset w := Iff.intro nofun nofun theorem derive_emptystr {α: Type} {a: α}: (derive emptystr a) = emptyset := by funext rw [derive_iff_emptystr] theorem derive_iff_char {α: Type} [DecidableEq α] {a: α} {c: α} {w: List α}: (derive (char c) a) w <-> (onlyif (a = c) emptystr) w := by refine Iff.intro ?toFun ?invFun case toFun => intro D cases D with | refl => exact ⟨ rfl, rfl ⟩ case invFun => intro ⟨ H1 , H2 ⟩ cases H1 with | refl => cases H2 with | refl => exact rfl theorem derive_char {α: Type} [DecidableEq α] {a: α} {c: α}: (derive (char c) a) = (onlyif (a = c) emptystr) := by funext rw [derive_iff_char] theorem derive_iff_pred {α: Type} {p: α -> Prop} {x: α} {xs: List α}: (derive (pred p) x) xs <-> (onlyif (p x) emptystr) xs := by simp only [derive, derives, singleton_append] simp only [onlyif, emptystr] refine Iff.intro ?toFun ?invFun case toFun => intro D match D with | Exists.intro x' D => simp only [cons.injEq] at D match D with | And.intro (And.intro hxx' hxs) hpx => rw [<- hxx'] at hpx exact And.intro hpx hxs case invFun => intro ⟨ hpx , hxs ⟩ unfold pred exists x simp only [cons.injEq, true_and] exact And.intro hxs hpx theorem derive_pred {α: Type} {p: α -> Prop} [DecidablePred p] {x: α}: (derive (pred p) x) = (onlyif (p x) emptystr) := by funext rw [derive_iff_pred] theorem derive_or {α: Type} {a: α} {P Q: Lang α}: (derive (or P Q) a) = (or (derive P a) (derive Q a)) := rfl theorem derive_and {α: Type} {a: α} {P Q: Lang α}: (derive (and P Q) a) = (and (derive P a) (derive Q a)) := rfl theorem derive_onlyif {α: Type} {a: α} {s: Prop} {P: Lang α}: (derive (onlyif s P) a) = (onlyif s (derive P a)) := rfl theorem derive_iff_concat {α: Type} {x: α} {P Q: Lang α} {xs: List α}: (derive (concat P Q) x) xs <-> (or (concat (derive P x) Q) (onlyif (null P) (derive Q x))) xs := by refine Iff.intro ?toFun ?invFun case toFun => simp only [Language.or, Language.concat, derive, derives, null, onlyif] intro d guard_hyp d: ∃ x_1 y, P x_1 ∧ Q y ∧ [x] ++ xs = x_1 ++ y guard_target = (∃ x_1 y, P ([x] ++ x_1) ∧ Q y ∧ xs = x_1 ++ y) ∨ P [] ∧ Q ([x] ++ xs) match d with | Exists.intro ps (Exists.intro qs (And.intro hp (And.intro hq hs))) => guard_hyp hp : P ps guard_hyp hq : Q qs guard_hyp hs : [x] ++ xs = ps ++ qs match ps with | nil => guard_hyp hp : P [] guard_hyp hq : Q qs refine Or.inr ?r guard_target = P [] ∧ Q ([x] ++ xs) rw [nil_append] at hs rw [hs] exact And.intro hp hq | cons p ps => guard_hyp hp : P (p :: ps) guard_hyp hq : Q qs guard_hyp hs : [x] ++ xs = p :: ps ++ qs refine Or.inl ?l guard_target = ∃ x_1 y, P ([x] ++ x_1) ∧ Q y ∧ xs = x_1 ++ y simp only [cons_append, cons.injEq] at hs match hs with | And.intro hpx hs => rw [hpx] rw [nil_append] at hs rw [hs] guard_hyp hs : xs = ps ++ qs guard_target = ∃ x y, P ([p] ++ x) ∧ Q y ∧ ps ++ qs = x ++ y exact Exists.intro ps (Exists.intro qs (And.intro hp (And.intro hq rfl))) case invFun => simp only [Language.or, Language.concat, derive, derives, null, onlyif] intro e guard_hyp e : (∃ x_1 y, P ([x] ++ x_1) ∧ Q y ∧ xs = x_1 ++ y) ∨ P [] ∧ Q ([x] ++ xs) guard_target = ∃ x_1 y, P x_1 ∧ Q y ∧ [x] ++ xs = x_1 ++ y match e with | Or.inl e => guard_hyp e: ∃ x_1 y, P ([x] ++ x_1) ∧ Q y ∧ xs = x_1 ++ y guard_target = ∃ x_1 y, P x_1 ∧ Q y ∧ [x] ++ xs = x_1 ++ y match e with | Exists.intro ps (Exists.intro qs (And.intro hp (And.intro hq hs))) => guard_hyp hp: P ([x] ++ ps) guard_hyp hq: Q qs guard_hyp hs: xs = ps ++ qs rw [hs] guard_target = ∃ x_1 y, P x_1 ∧ Q y ∧ [x] ++ (ps ++ qs) = x_1 ++ y exact Exists.intro ([x] ++ ps) (Exists.intro qs (And.intro hp (And.intro hq rfl))) | Or.inr e => guard_hyp e : P [] ∧ Q ([x] ++ xs) guard_target = ∃ x_1 y, P x_1 ∧ Q y ∧ [x] ++ xs = x_1 ++ y match e with | And.intro hp hq => exact Exists.intro [] (Exists.intro (x :: xs) (And.intro hp (And.intro hq rfl))) theorem derive_concat {α: Type} {x: α} {P Q: Lang α}: (derive (concat P Q) x) = (or (concat (derive P x) Q) (onlyif (null P) (derive Q x))) := by funext rw [derive_iff_concat] theorem derive_iff_star {α: Type} {x: α} {R: Lang α} {xs: List α}: (derive (star R) x) xs <-> (concat (derive R x) (star R)) xs := by refine Iff.intro ?toFun ?invFun case toFun => intro deriveStar unfold derive at deriveStar unfold derives at deriveStar cases deriveStar with | more x' xs1 xs2 _ hxs Rxxs1 starRxs2 => unfold concat exists xs1 exists xs2 simp only [cons_append, cons.injEq] at hxs cases hxs with | intro hxs1 hxs2 => rw [hxs1] split_ands · exact Rxxs1 · exact starRxs2 · exact hxs2 case invFun => intro concatDerive unfold concat at concatDerive cases concatDerive with | intro xs1 concatDerive => cases concatDerive with | intro xs2 concatDerive => cases concatDerive with | intro deriveRxxs1 concatDerive => cases concatDerive with | intro starRxs2 hxs => unfold derive unfold derives refine star.more x xs1 xs2 ?hxs ?e ?f ?g · rw [hxs] simp only [cons_append, nil_append] · apply deriveRxxs1 · exact starRxs2 theorem derive_star {α: Type} {x: α} {R: Lang α}: (derive (star R) x) = (concat (derive R x) (star R)) := by funext rw [derive_iff_star] theorem derive_not {α: Type} {x: α} {R: Lang α}: (derive (not R) x) = Not ∘ (derive R x) := rfl theorem derive_iff_not {α: Type} {x: α} {R: Lang α} {xs: List α}: (derive (not R) x) xs <-> Not ((derive R x) xs) := by rw [derive_not] rfl -- Theorems: simplification rules theorem simp_concat_emptyset_l_is_emptyset (r: Lang α): concat emptyset r = emptyset := by unfold concat simp only [emptyset, false_and, exists_const] rfl theorem simp_concat_emptyset_r_is_emptyset (r: Lang α): concat r emptyset = emptyset := by unfold concat simp only [emptyset, false_and, and_false, exists_const] rfl theorem simp_concat_emptystr_l_is_r (r: Lang α): concat emptystr r = r := by unfold concat simp only [emptystr, exists_and_left, exists_eq_left, nil_append, exists_eq_right'] theorem simp_concat_emptystr_r_is_l (r: Lang α): concat r emptystr = r := by unfold concat simp only [emptystr, exists_and_left, exists_eq_left, append_nil, exists_eq_right'] theorem simp_concat_assoc (r s t: Lang α): concat (concat r s) t = concat r (concat s t) := by unfold concat funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h match h with | Exists.intro xs1 (Exists.intro xs2 (And.intro (Exists.intro xs3 (Exists.intro xs4 (And.intro rxs3 (And.intro sxs4 xs1split)))) (And.intro txs2 xssplit))) => clear h exists xs3 exists (xs4 ++ xs2) split_ands · exact rxs3 · exists xs4 exists xs2 · rw [xs1split] at xssplit simp only [append_assoc] at xssplit exact xssplit case mpr => intro h match h with | Exists.intro xs1 (Exists.intro xs2 (And.intro rxs1 (And.intro (Exists.intro xs3 (Exists.intro xs4 (And.intro sxs3 (And.intro txs4 xs2split) ))) xssplit))) => clear h exists (xs1 ++ xs3) exists xs4 split_ands · exists xs1 exists xs3 · exact txs4 · rw [xs2split] at xssplit simp only [append_assoc] exact xssplit -- class Associative found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsAssociative_concat {α: Type}: Std.Associative (@concat α) := { assoc := @simp_concat_assoc α } -- Test that ac_rfl uses the instance of Std.Associative example (r s t: Lang α): concat (concat r s) t = concat r (concat s t) := by ac_rfl instance IsLawfulIdentity_concat {α: Type} : Std.LawfulIdentity (@concat α) (@emptystr α) where left_id := simp_concat_emptystr_l_is_r right_id := simp_concat_emptystr_r_is_l -- Test ac_rfl uses the instance of LawfulIdentity example (r: Lang α): concat emptystr r = r := by ac_rfl -- Test ac_nf tactic example (r s: Lang α) (H: s = r): concat emptystr r = s := by ac_nf rw [H] theorem simp_or_emptyset_l_is_r (r: Lang α): or emptyset r = r := by unfold or simp only [emptyset, false_or] theorem simp_or_emptyset_r_is_l (r: Lang α): or r emptyset = r := by unfold or simp only [emptyset, or_false] theorem simp_or_universal_l_is_universal (r: Lang α): or universal r = universal := by unfold or simp only [universal, true_or] rfl theorem simp_or_universal_r_is_universal (r: Lang α): or r universal = universal := by unfold or simp only [universal, or_true] rfl theorem simp_or_null_l_emptystr_is_l (r: Lang α) (nullr: null r): or r emptystr = r := by unfold or simp only [emptystr] unfold null at nullr funext xs simp only [eq_iff_iff, or_iff_left_iff_imp] intro hxs rw [hxs] exact nullr theorem simp_or_emptystr_null_r_is_r (r: Lang α) (nullr: null r): or emptystr r = r := by unfold or simp only [emptystr] unfold null at nullr funext xs simp only [eq_iff_iff, or_iff_right_iff_imp] intro hxs rw [hxs] exact nullr theorem simp_or_idemp (r: Lang α): or r r = r := by unfold or funext xs apply or_self theorem simp_or_comm (r s: Lang α): or r s = or s r := by unfold or funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h match h with | Or.inl h => exact Or.inr h | Or.inr h => exact Or.inl h case mpr => intro h match h with | Or.inl h => exact Or.inr h | Or.inr h => exact Or.inl h theorem simp_or_assoc (r s t: Lang α): or (or r s) t = or r (or s t) := by unfold or funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro h cases h with | inl h => cases h with | inl h => left exact h | inr h => right left exact h | inr h => right right exact h · case mpr => intro h cases h with | inl h => left left exact h | inr h => cases h with | inl h => left right exact h | inr h => right exact h -- class Associative found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsAssociative_or {α: Type}: Std.Associative (@or α) := { assoc := @simp_or_assoc α } -- class Commutative found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsCommutative_or {α: Type}: Std.Commutative (@or α) := { comm := @simp_or_comm α } -- class IdempotentOp found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsIdempotentOp_or {α: Type}: Std.IdempotentOp (@or α) := { idempotent := simp_or_idemp } instance IsLawfulCommIdentity_or {α: Type} : Std.LawfulCommIdentity (@or α) (@emptyset α) where right_id r := simp_or_emptyset_r_is_l r -- Test that ac_rfl uses the instance of Std.LawfulCommIdentity example (r: Lang α): or r emptyset = r := by ac_rfl -- Test that ac_rfl uses the instance of Std.Commutative example (r s: Lang α): or r s = or s r := by ac_rfl -- Test that ac_rfl uses the instance of Std.Associative example (r s t: Lang α): or (or r s) t = or r (or s t) := by ac_rfl -- Test that ac_rfl uses the instance of Std.IdempotentOp example (r: Lang α): or (or r r) r = r := by ac_rfl -- Test that ac_rfl uses both the instances of Std.Associative and Std.Commutative example (a b c d : Lang α): (or a (or b (or c d))) = (or d (or (or b c) a)) := by ac_rfl -- Test that ac_rfl uses both the instances of Std.Associative and Std.Commutative and Std.IdempotentOp example (a b c d : Lang α): (or a (or b (or c d))) = (or a (or d (or (or b c) a))) := by ac_rfl -- Test ac_nf tactic example (r s: Lang α) (H: s = r): or emptyset (or r s) = (or r r) := by ac_nf rw [H] ac_rfl theorem simp_and_emptyset_l_is_emptyset (r: Lang α): and emptyset r = emptyset := by unfold and simp only [emptyset, false_and] rfl theorem simp_and_emptyset_r_is_emptyset (r: Lang α): and r emptyset = emptyset := by unfold and simp only [emptyset, and_false] rfl theorem simp_and_universal_l_is_r (r: Lang α): and universal r = r := by unfold and simp only [universal, true_and] theorem simp_and_universal_r_is_l (r: Lang α): and r universal = r := by unfold and simp only [universal, and_true] theorem simp_and_null_l_emptystr_is_emptystr (r: Lang α) (nullr: null r): and r emptystr = emptystr := by funext xs simp only [and, emptystr, eq_iff_iff, and_iff_right_iff_imp] intro hxs rw [hxs] exact nullr theorem simp_and_emptystr_null_r_is_emptystr (r: Lang α) (nullr: null r): and emptystr r = emptystr := by funext xs simp only [null] at nullr simp only [and, emptystr, eq_iff_iff, and_iff_left_iff_imp] intro hxs rw [hxs] exact nullr theorem simp_and_not_null_l_emptystr_is_emptyset (r: Lang α) (notnullr: Not (null r)): and r emptystr = emptyset := by funext xs simp only [and, emptystr, emptyset, eq_iff_iff, iff_false, not_and] intro hr hxs rw [hxs] at hr contradiction theorem simp_and_emptystr_not_null_r_is_emptyset (r: Lang α) (notnullr: Not (null r)): and emptystr r = emptyset := by funext xs simp only [and, emptystr, emptyset, eq_iff_iff, iff_false, not_and] intro hxs rw [hxs] exact notnullr theorem simp_and_idemp (r: Lang α): and r r = r := by unfold and funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h cases h assumption case mpr => intro h exact And.intro h h theorem simp_and_comm (r s: Lang α): and r s = and s r := by unfold and funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h cases h with | intro hr hs => exact And.intro hs hr case mpr => intro h cases h with | intro hs hr => exact And.intro hr hs theorem simp_and_assoc (r s t: Lang α): and (and r s) t = and r (and s t) := by unfold and funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h match h with | And.intro (And.intro h1 h2) h3 => exact And.intro h1 (And.intro h2 h3) case mpr => intro h match h with | And.intro h1 (And.intro h2 h3) => exact And.intro (And.intro h1 h2) h3 -- class Associative found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsAssociative_and {α: Type}: Std.Associative (@and α) := { assoc := @simp_and_assoc α } -- class Commutative found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsCommutative_and {α: Type}: Std.Commutative (@and α) := { comm := @simp_and_comm α } -- class IdempotentOp found in Init/Core.lean in namespace Std -- It is used by the ac_rfl tactic. instance IsIdempotentOp_and {α: Type}: Std.IdempotentOp (@and α) := { idempotent := simp_and_idemp } instance IsLawfulCommIdentity_and {α: Type} : Std.LawfulCommIdentity (@and α) (@universal α) where right_id r := simp_and_universal_r_is_l r -- Test that ac_rfl uses the instance of Std.LawfulCommIdentity example (r: Lang α): and r universal = r := by ac_rfl -- Test that ac_rfl uses the instance of Std.Commutative example (r s: Lang α): and r s = and s r := by ac_rfl -- Test that ac_rfl uses the instance of Std.Associative example (r s t: Lang α): and (and r s) t = and r (and s t) := by ac_rfl -- Test that ac_rfl uses the instance of Std.IdempotentOp example (r: Lang α): and r (and r r) = r := by ac_rfl -- Test that ac_rfl uses both the instances of Std.Associative and Std.Commutative example (a b c d : Lang α): (and a (and b (and c d))) = (and d (and (and b c) a)) := by ac_rfl -- Test that ac_rfl uses both the instances of Std.Associative and Std.Commutative and Std.IdempotentOp example (a b c d : Lang α): (and a (and b (and c d))) = (and d (and d (and (and b c) a))) := by ac_rfl theorem not_not_intro' {p : Prop} (h : p) : ¬ ¬ p := fun hn : (p -> False) => hn h theorem simp_not_not_is_double_negation (r: Lang α) [DecidablePred r]: not (not r) = r := by unfold not funext xs simp only [eq_iff_iff] exact Decidable.not_not theorem simp_not_and_demorgen (r s: Lang α) (xs: List α) [Decidable (r xs)] [Decidable (s xs)]: not (and r s) xs = or (not r) (not s) xs := by unfold and unfold or unfold not simp only [eq_iff_iff] exact Decidable.not_and_iff_not_or_not theorem simp_not_or_demorgen (r s: Lang α): not (or r s) = and (not r) (not s) := by unfold not unfold or unfold and simp only [not_or] theorem simp_and_not_emptystr_l_not_null_r_is_r (r: Lang α) (notnullr: Not (null r)): and (not emptystr) r = r := by funext xs simp only [and, not, emptystr, eq_iff_iff, and_iff_right_iff_imp] intro hr hxs rw [hxs] at hr contradiction theorem simp_and_not_null_l_not_emptystr_r_is_l (r: Lang α) (notnullr: Not (null r)): and r (not emptystr) = r := by funext xs simp only [null] at notnullr simp only [and, not, emptystr, eq_iff_iff, and_iff_left_iff_imp] intro hr hxs rw [hxs] at hr contradiction theorem simp_one_r_implies_star_r (r: Lang α) (xs: List α): r xs -> star r xs := by intro h cases xs · exact star.zero · case cons x xs => apply star.more x xs [] · simp only [append_nil] · exact h · exact star.zero theorem simp_star_concat_star_implies_star (r: Lang α) (xs: List α): concat (star r) (star r) xs -> star r xs := by intro h cases h with | intro xs1 h => cases h with | intro xs2 h => cases h with | intro starrxs1 h => cases h with | intro starrxs2 xssplit => rw [xssplit] clear xssplit induction starrxs1 with | zero => simp only [nil_append] exact starrxs2 | more x xs11 xs12 _ xs1split rxxs11 starrxs12 ih => rename_i xs1 rw [xs1split] apply star.more x xs11 (xs12 ++ xs2) simp only [cons_append, append_assoc] exact rxxs11 exact ih theorem simp_star_implies_star_concat_star (r: Lang α) (xs: List α): star r xs -> concat (star r) (star r) xs := by intro h cases h with | zero => unfold concat exists [] exists [] split_ands · exact star.zero · exact star.zero · simp only [append_nil] | more x xs1 xs2 _ xssplit rxxs1 starrxs2 => unfold concat exists (x::xs1) exists xs2 split_ands · refine star.more x xs1 [] _ ?_ ?_ ?_ · simp only [append_nil] · exact rxxs1 · exact star.zero · exact starrxs2 · rw [xssplit] theorem simp_star_concat_star_is_star (r: Lang α): concat (star r) (star r) = star r := by unfold concat funext xs simp only [eq_iff_iff] apply Iff.intro case mp => apply simp_star_concat_star_implies_star case mpr => apply simp_star_implies_star_concat_star theorem simp_star_star_is_star (r: Lang α): star (star r) = star r := by funext xs simp only [eq_iff_iff] apply Iff.intro case mp => intro h induction h with | zero => exact star.zero | more x xs1 xs2 _ xssplit starrxxs1 starstarrxs2 ih => rename_i xss rw [xssplit] rw [<- simp_star_concat_star_is_star] unfold concat exists (x::xs1) exists xs2 case mpr => intro h induction h with | zero => exact star.zero | more x xs1 xs2 _ xssplit rxxs1 starrxs2 ih => rename_i xss apply star.more x xs1 xs2 · exact xssplit · apply simp_one_r_implies_star_r exact rxxs1 · exact ih theorem simp_star_emptystr_is_emptystr {α: Type}: star (@emptystr α) = (@emptystr α) := by funext xs simp only [emptystr, eq_iff_iff] apply Iff.intro case mp => intro h cases h case zero => rfl case more x xs1 xs2 hemptystr hstar hsplit => nomatch hemptystr case mpr => intro h rw [h] exact star.zero theorem simp_star_emptyset_is_emptystr {α: Type}: star (@emptyset α) = (@emptystr α) := by funext xs simp only [emptystr, eq_iff_iff] apply Iff.intro case mp => intro h cases h case zero => rfl case more x xs1 xs2 hemptystr hstar hsplit => nomatch hemptystr case mpr => intro h rw [h] exact star.zero theorem simp_star_any_is_universal {α: Type}: star (@any α) = @universal α := by funext xs simp only [universal, eq_iff_iff] apply Iff.intro case mp => intro h exact True.intro case mpr => intro h induction xs with | nil => exact star.zero | cons x xs ih => apply star.more x [] xs · simp only [singleton_append] · unfold any exists x · exact ih def onlyif_true {cond: Prop} {l: List α -> Prop} (condIsTrue: cond): Language.onlyif cond l = l := by unfold Language.onlyif funext xs simp only [eq_iff_iff, and_iff_right_iff_imp] intro p assumption def onlyif_false {cond: Prop} {l: List α -> Prop} (condIsFalse: ¬cond): Language.onlyif cond l = Language.emptyset := by funext xs rw [eq_iff_iff] apply Iff.intro case mp => intro h cases h case intro condIsTrue lxs => contradiction case mpr => intro h nomatch h theorem simp_or_concat_left_distrib (a b c : Lang α) : concat a (or b c) = or (concat a b) (concat a c) := by unfold or unfold concat funext xs simp only [eq_iff_iff] simp only [exists_and_left] apply Iff.intro · case mp => intro H cases H with | intro xs1 H => cases H with | intro axs1 H => cases H with | intro x H => cases H with | intro bc H => cases bc with | inl Hb => apply Or.inl exists xs1 apply And.intro exact axs1 exists x | inr Hc => apply Or.inr exists xs1 apply And.intro exact axs1 exists x . case mpr => intro H cases H with | inl H => cases H with | intro xs1 H => cases H with | intro axs1 H => cases H with | intro x H => cases H with | intro Hb H => exists xs1 apply And.intro exact axs1 exists x apply And.intro apply Or.inl exact Hb exact H | inr H => cases H with | intro xs1 H => cases H with | intro axs1 H => cases H with | intro x H => cases H with | intro Hc H => exists xs1 apply And.intro exact axs1 exists x apply And.intro apply Or.inr exact Hc exact H theorem simp_or_concat_right_distrib (a b c : Lang α) : concat (or a b) c = or (concat a c) (concat b c) := by unfold or unfold concat funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro H cases H with | intro xs1 H => cases H with | intro xs2 H => cases H with | intro Hab H => cases H with | intro Hc H => cases Hab with | inl Ha => apply Or.inl exists xs1 exists xs2 | inr Hb => apply Or.inr exists xs1 exists xs2 · case mpr => intro H cases H with | inl H => cases H with | intro xs1 H => cases H with | intro xs2 H => cases H with | intro Ha H => cases H with | intro Hc H => exists xs1 exists xs2 apply And.intro · apply Or.inl exact Ha · apply And.intro · exact Hc · exact H | inr H => cases H with | intro xs1 H => cases H with | intro xs2 H => cases H with | intro Hb H => cases H with | intro Hc H => exists xs1 exists xs2 apply And.intro · apply Or.inr exact Hb · apply And.intro · exact Hc · exact H theorem simp_or_and_left_distrib (a b c : Lang α) : and a (or b c) = or (and a b) (and a c) := by unfold and unfold or funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro H cases H with | intro Ha Hbc => cases Hbc with | inl Hb => apply Or.inl apply And.intro Ha Hb | inr Hc => apply Or.inr apply And.intro Ha Hc · case mpr => intro H cases H with | inl Hab => cases Hab with | intro Ha Hb => apply And.intro exact Ha apply Or.inl exact Hb | inr Hac => cases Hac with | intro Ha Hc => apply And.intro exact Ha apply Or.inr exact Hc theorem simp_or_and_right_distrib (a b c : Lang α) : and (or a b) c = or (and a c) (and b c) := by unfold and unfold or funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro H cases H with | intro Hab Hc => cases Hab with | inl Ha => apply Or.inl apply And.intro Ha Hc | inr Hb => apply Or.inr apply And.intro Hb Hc · case mpr => intro H cases H with | inl Hac => cases Hac with | intro Ha Hc => apply And.intro apply Or.inl exact Ha exact Hc | inr Hbc => cases Hbc with | intro Hb Hc => apply And.intro apply Or.inr exact Hb exact Hc theorem simp_and_or_left_distrib (a b c : Lang α) : or a (and b c) = and (or a b) (or a c) := by unfold and unfold or funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro H cases H with | inl H => apply And.intro · apply Or.inl H · apply Or.inl H | inr H => cases H with | intro Hb Hc => apply And.intro · apply Or.inr Hb · apply Or.inr Hc · case mpr => intro H cases H with | intro Hab Hac => cases Hab with | inl Ha => apply Or.inl Ha | inr Hb => cases Hac with | inl Ha => apply Or.inl Ha | inr Hc => apply Or.inr apply And.intro Hb Hc theorem simp_and_or_right_distrib (a b c : Lang α) : or (and a b) c = and (or a c) (or b c) := by unfold and unfold or funext xs simp only [eq_iff_iff] apply Iff.intro · case mp => intro H cases H with | inl h => simp_all only [true_or, and_self] | inr h_1 => simp_all only [or_true, and_self] · case mpr => intro H cases H with | intro Hleft Hright => cases Hleft with | inl h => cases Hright with | inl h_1 => simp_all only [and_self, true_or] | inr h_2 => simp_all only [true_and, or_true] | inr h_1 => cases Hright with | inl h => simp_all only [and_true, or_true] | inr h_2 => simp_all only [or_true] theorem simp_or_star_any_l_is_star_any (r: Lang α): or (star any) r = (star any) := by rw [simp_star_any_is_universal] rw [simp_or_universal_l_is_universal] theorem simp_or_star_any_r_is_star_any (r: Lang α): or r (star any) = (star any) := by rw [simp_star_any_is_universal] rw [simp_or_universal_r_is_universal]