10. Automation: More Automation
Up to now, we've used the manual part of Lean's tactic
facilities. In this chapter, we'll learn more about some of
Lean's powerful automation features, including
tactic combinators like try and repeat, decision procedures like lia,
and automatic simplification using simp.
Using these features together with Lean's metaprogramming facilities will enable us to make
some of our proofs startlingly short! Used properly, they can
also make proofs more maintainable and robust to changes in
underlying definitions.
Our motivating example will be the following proof, repeated with just a few small changes from the IndProp chapter. We will simplify this proof in several stages.
theorem Perm3_In_old (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm with
α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]
swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []
obtain h | h | h | h := hIn swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []
. swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] right swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝ ∨ x = z✝ ∨ x ∈ []; left swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝; assumption All goals completed! 🐙
. swap12.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] left swap12.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝; assumption All goals completed! 🐙
. swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] right swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x ∈ []; right swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = z✝ ∨ x ∈ []; left swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = z✝; assumption All goals completed! 🐙
. swap12.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] contradiction All goals completed! 🐙
| swap23 => swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]
rw [List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = x✝ ∨ x ∈ [z✝, y✝] List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = x✝ ∨ x = z✝ ∨ x ∈ [y✝] List.mem_cons swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []] at * swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []
obtain h | h | h | h := hIn swap23.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []
. swap23.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] left swap23.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝; assumption All goals completed! 🐙
. swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] right swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = z✝ ∨ x = y✝ ∨ x ∈ []; right swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝ ∨ x ∈ []; left swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝; assumption All goals completed! 🐙
. swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] right swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = z✝ ∨ x = y✝ ∨ x ∈ []; left swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = z✝; assumption All goals completed! 🐙
. swap23.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] contradiction All goals completed! 🐙
| trans _ _ ih₁₂ ih₂₃ => trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝ih₁₂:x ∈ l₁✝ → x ∈ l₂✝ih₂₃:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝
apply ih₂₃ trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝ih₁₂:x ∈ l₁✝ → x ∈ l₂✝ih₂₃:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₂✝; apply ih₁₂ trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝ih₁₂:x ∈ l₁✝ → x ∈ l₂✝ih₂₃:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₁✝; apply hIn All goals completed! 🐙
In this chapter, we will introduce tactics that will shrink this proof from around eighteen lines to one.
10.1. The lia Tactic
The lia tactic implements a decision procedure for linear integer
arithmetic: propositional formulas whose atoms are linear
constraints over the natural numbers and integers. This is exactly the
fragment of first-order logic (see the Logic chapter)
obtained by restricting connectives and quantifiers to arithmetic
building blocks.
If the goal is a universally quantified formula made out of
-
numeric constants, addition (
+andsucc), subtraction (-andpred), and multiplication by constants, -
equality (
=and≠) and ordering (≤and<), and -
the logical connectives
∧,∨,¬, and→,
then invoking lia will either solve the goal, or fail because the
goal is actually false: within this fragment, lia is a complete
decision procedure. lia reasons about
the goal together with any hypotheses already in the local context: each
hypothesis is used exactly as if it had been written into the goal as an
antecedent with →.
Outside this fragment, lia can fail even when the goal is true —
for example, on n * n ≥ n, which multiplies two variables together rather
than a constant and a variable. Such a failure only means lia
couldn't decide the goal, not that the goal is false. Note that, when
failing, lia may mention another tactic, called grind.
This is another, more powerful tactic that subsumes lia, but we
will not use it here.
Anything in the goal or hypotheses that isn't built from these arithmetic
pieces — including an arbitrary proposition like x ∈ l — lia
simply treats as an opaque atom. So lia can also solve goals that
are purely propositional, with no arithmetic in them at all, as long as the
only way such atoms are combined is with ∧, ∨, ¬, and →.
example (m n o p : Nat) :
m + n ≤ n + o ∧ o + 3 = p + 3 →
m ≤ p := by m:Natn:Nato:Natp:Nat⊢ m + n ≤ n + o ∧ o + 3 = p + 3 → m ≤ p
lia All goals completed! 🐙
example (m n : Nat) :
m + n = n + m := by m:Natn:Nat⊢ m + n = n + m
lia All goals completed! 🐙
example (m n p : Nat) :
m + (n + p) = m + n + p := by m:Natn:Natp:Nat⊢ m + (n + p) = m + n + p
lia All goals completed! 🐙
example (a b c d : Prop) :
(a → b) → (b → c) → (c → d) → (a → d) := by a:Propb:Propc:Propd:Prop⊢ (a → b) → (b → c) → (c → d) → a → d
lia All goals completed! 🐙
example (α : Type) (x : α) (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ → x ∈ l₂) (h₂ : x ∈ l₂ → x ∈ l₃) : x ∈ l₁ → x ∈ l₃ := by α:Typex:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ → x ∈ l₂h₂:x ∈ l₂ → x ∈ l₃⊢ x ∈ l₁ → x ∈ l₃
lia All goals completed! 🐙
The lia tactic can solve many of the cases of our old Perm3.In example.
theorem Perm3_In_better_with_lia (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm with
| swap12 => swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]
rw [List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = y✝ ∨ x ∈ [x✝, z✝] List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = y✝ ∨ x = x✝ ∨ x ∈ [z✝] List.mem_cons swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []] at * swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []
obtain h | h | h | h := hIn swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []swap12.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []
/- In addition to basic arithmetic, `lia` can also discharge goals
that are simple facts about logic. -/
. swap12.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was right; left; assumption
. swap12.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was left; assumption
. swap12.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was right; right; left; assumption
. swap12.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was contradiction
| swap23 => swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]
rw [List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = x✝ ∨ x ∈ [z✝, y✝] List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = x✝ ∨ x = z✝ ∨ x ∈ [y✝] List.mem_cons swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []] at * swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []
obtain h | h | h | h := hIn swap23.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []swap23.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []
. swap23.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = x✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was left; assumption
. swap23.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = y✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was right; right; left; assumption
. swap23.inr.inr.inl α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was right; right; assumption
. swap23.inr.inr.inr α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αh:x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙 -- was contradiction
| trans _ _ ih₁₂ ih₂₃ => trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝ih₁₂:x ∈ l₁✝ → x ∈ l₂✝ih₂₃:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝
lia All goals completed! 🐙 -- was apply ih₂₃; apply ih₁₂; apply hIn
10.2. Tactic Combinators
In Induction, we saw how to use the <;> combinator in order to apply
the same tactic to every subgoal in a proof. As a reminder, consider this example,
where cases on b and c each leaves two subgoals that are discharged identically:
example (b c : Bool) : (b && c) = (c && b) := by b:Boolc:Bool⊢ (b && c) = (c && b)
cases b false c:Bool⊢ (false && c) = (c && false)true c:Bool⊢ (true && c) = (c && true) <;> false c:Bool⊢ (false && c) = (c && false)true c:Bool⊢ (true && c) = (c && true) cases c true.false ⊢ (true && false) = (false && true)true.true ⊢ (true && true) = (true && true) <;> false.false ⊢ (false && false) = (false && false)false.true ⊢ (false && true) = (true && false)true.false ⊢ (true && false) = (false && true)true.true ⊢ (true && true) = (true && true) rfl All goals completed! 🐙
We can use this combinator to further simplify our Perm3 proof:
theorem Perm3_In_better_with_lia_semi (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm with
| swap12 => swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]
rw [List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = y✝ ∨ x ∈ [x✝, z✝] List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = y✝ ∨ x = x✝ ∨ x ∈ [z✝] List.mem_cons swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []] at * swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] <;> swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] lia All goals completed! 🐙
| swap23 => swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]
rw [List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = x✝ ∨ x ∈ [z✝, y✝] List.mem_cons, swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = x✝ ∨ x = z✝ ∨ x ∈ [y✝] List.mem_cons swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ []] at * swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] <;> swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙
| trans _ _ ih₁₂ ih₂₃ => trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝ih₁₂:x ∈ l₁✝ → x ∈ l₂✝ih₂₃:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ lia All goals completed! 🐙
The <;> is not the only combinator that Lean has to offer.
In general, combinators allow us to build tactics out of smaller ones.
Getting used to them takes a little energy, but it lets us scale up to
more complex definitions and more interesting properties without
drowning in boring, repetitive detail.
INCOMING BOCHUM MATERIAL summarized by Claude (old/bochum-lf-updates/AltAuto.v): the
Bochum LF updates extend AltAuto's discussion of the sequencing
tactical with new material on Rocq's "local form with `..`":
T; [T1 .. | Tn]
which applies T1 to the first goal, Tn to the last, and T1 to all
goals in between (variants: T; [T1 | .. | Tn] applies nothing in
between; the `..` may also appear first, last, or alone). The new
material illustrates this by revisiting star_app from IndProp:
Lemma star_app'': forall T (s1 s2 : list T) (re : reg_exp T),
s1 =~ Star re ->
s2 =~ Star re ->
s1 ++ s2 =~ Star re.
Proof.
intros T s1 s2 re H1.
remember (Star re) as re' eqn:Eq.
induction H1
as [|x'|s1 re1 s2' re2 Hmatch1 IH1 Hmatch2 IH2
|s1 re1 re2 Hmatch IH|re1 s2' re2 Hmatch IH
|re''|s1 s2' re'' Hmatch1 IH1 Hmatch2 IH2];
[discriminate .. | intros H; apply H | idtac]. (* <=== *)
(* MStarApp *)
intros H1. rewrite <- app_assoc.
apply MStarApp.
+ apply Hmatch1.
+ apply IH2.
* apply Eq.
* apply H1.
Qed.
(first shown in its long form with all seven cases spelled out, then
shortened as above). Bochum also adds a QUIETSOLUTION alternate
solution to AltAuto's re_opt exercise that uses nested `..` lists
instead of `try`, and rewords the introduction of `T; T'` to say
simply that it is "equivalent to locally performing T' on all the
subgoals".
To incorporate: Lean has no direct analogue of the positional
`[T1 .. | Tn]` goal-selector list; the closest idioms are
case-labelled alternatives (`case ... =>`/`next`), `all_goals`,
and `first`. A future pass should decide whether to add a
parallel discussion here (e.g. using `star_app` below, proving the
six non-MStarApp cases uniformly) or to record the Rocq material
as intentionally unported.
10.2.1. The try Combinator
The first such combinator we'll discuss is try. If t is a tactic,
then try t is a tactic that is just like t
except that, if t fails, try t successfully does nothing at all
(rather than failing).
example {a : Prop} (h : a) : a := by a:Proph:a⊢ a
try rfl a:Proph:a⊢ a -- `rfl` would fail here, but `try` swallows it...
exact h All goals completed! 🐙 -- ...so we can still finish some other way.
example : 1 = 1 := by ⊢ 1 = 1
try rfl All goals completed! 🐙 -- here `try rfl` just does `rfl`
There is not much reason to use try in completely manual proofs like
these, but it is very useful together with the <;> combinator.
inductive Silly : Nat → Prop where
| mk1 {n : Nat} (h : n > 1) : Silly n
| mk2 {n : Nat} (h : 1 ∈ []) : Silly n
| mk3 {n : Nat} (h : ∃ m, n = m + 2) : Silly n
example {n : Nat} (h : Silly n) : n ≠ 1 := by n:Nath:Silly n⊢ n ≠ 1
inversion h with
| mk1 => lia All goals completed! 🐙
| mk2 => contradiction All goals completed! 🐙
| mk3 => lia All goals completed! 🐙
Here, we can use the lia tactic to close some of these goals, but not all of them. So,
a more compact way to write this proof would be:
example {n} (h : Silly n) : n ≠ 1 := by n:Nath:Silly n⊢ n ≠ 1
cases h mk1 n:Nath✝:n > 1⊢ n ≠ 1mk2 n:Nath✝:1 ∈ []⊢ n ≠ 1mk3 n:Nath✝:∃ m, n = m + 2⊢ n ≠ 1 <;> mk1 n:Nath✝:n > 1⊢ n ≠ 1mk2 n:Nath✝:1 ∈ []⊢ n ≠ 1mk3 n:Nath✝:∃ m, n = m + 2⊢ n ≠ 1 try lia All goals completed! 🐙
-- `lia` doesn't know that `1 ∈ []` is impossible,
-- but we can use `contradiction`
contradiction All goals completed! 🐙
We can further simplify our Perm3.In example with try.
theorem Perm3_In_better_with_try (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm with
(try rw [List.mem_cons, trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = y✝ ∨ x = x✝ ∨ x ∈ [z✝] List.mem_cons swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []] swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ [] at * swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] <;> swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙)
| trans => trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ lia All goals completed! 🐙
Note that try lia <;> try rw [...] <;> lia doesn't work because <;> short circuits.
A failure in the first lia prevents the rest of the sequence from
executing, meaning the try rw [...] never fires. (try lia <;> ... is parsed
try (lia <;> (...)), and it's the outermost try that catches the failure in this case.)
We'll see a solution to this problem further below.
example (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ <;> swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ try lia All goals completed! 🐙 <;>
try rw [List.mem_cons, List.mem_cons, List.mem_cons] at * <;> lia
10.2.2. The repeat Combinator
The repeat combinator takes another tactic or parenthesized sequence of tactics
and keeps applying it until it fails.
Here is an example proving that 10 is in a long list using repeat:
example : 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] := by ⊢ 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
repeat
rw [List.mem_cons ⊢ 10 = 1 ∨ 10 ∈ [2, 3, 4, 5, 6, 7, 8, 9, 10]] ⊢ 10 = 9 ∨ 10 ∈ [10] ⊢ 10 = 10 ∨ 10 ∈ []
try left ⊢ 10 = 10; rfl All goals completed! 🐙
-- `try` makes this optional, which is necessary for the
-- last repetition where `left; rfl` succeeds
try right ⊢ 10 ∈ [10]
The tactic repeat t never fails: if the tactic t doesn't apply
to the original goal, then repeat t succeeds without changing the
goal at all (i.e., it repeats zero times).
example : 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] := by ⊢ 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
-- this is a no-op
repeat lia All goals completed! 🐙
repeat
rw [List.mem_cons ⊢ 10 = 1 ∨ 10 ∈ [2, 3, 4, 5, 6, 7, 8, 9, 10]] ⊢ 10 = 9 ∨ 10 ∈ [10] ⊢ 10 = 10 ∨ 10 ∈ []
try left ⊢ 10 = 10; rfl All goals completed! 🐙
try right ⊢ 10 ∈ [10]
The tactic repeat t does not have any upper bound on the
number of times it applies t. If t is a tactic that always
succeeds (and makes progress), then repeat t will loop
forever.
example (m n : Nat) : m + n = n + m := by
/- Uncomment the next line to see the infinite loop occur. You will
then need to recomment it to make Lean listen to you again. -/
-- repeat rewrite [Nat.add_comm]
Wait — did we just write an infinite loop in Lean?!?!
Sort of.
While evaluation in Lean's term language is guaranteed to
terminate, tactic evaluation is not. This does not affect Lean's
logical consistency, however, since the job of repeat and other
tactics is to guide Lean in constructing proofs; if the
construction process diverges (i.e., it does not terminate), this
simply means that we have failed to construct a proof at all, not
that we have constructed a bad proof.
10.2.3. The first Combinator
The first combinator takes a sequence of tactics and tries them in order,
stopping after the first success. As a silly example:
example (n m : Nat) : n * (m + 1) = n * m + n := by n:Natm:Nat⊢ n * (m + 1) = n * m + n
first | rfl All goals completed! 🐙 | left | lia | induction n
Neither rfl nor left succeeds on this goal,
but lia does, so first stops after lia
and never tries induction. As with try,
first is most useful in combination with other combinators.
For example, we can rewrite our previous examples that used
repeat and try like so:
example : 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] := by ⊢ 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
repeat first
| exact List.mem_cons_self All goals completed! 🐙
| apply List.mem_cons_of_mem ⊢ 10 ∈ [10]
It occurs to me having gotten this far that we could really use some quizzes to test understanding of these various combinators to this point.
The first tactic here will attempt to close the goal with an application of
List.mem_cons_self, if it can, and otherwise apply List.mem_cons_of_mem to proceed to
checking the next element in the list. Note that the order here is important!
If we had instead written:
example : 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] := by ⊢ 10 ∈ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
repeat first
| apply List.mem_cons_of_mem ⊢ 10 ∈ []
| exact List.mem_cons_self ⊢ 10 ∈ []
-- unprovable state!
Here, when we reach the goal 10 ∈ [10], instead of closing the goal with
List.mem_cons_self like before, we would instead first try apply List.mem_cons_of_mem,
which would also succeed. This leaves us with the goal 10 ∈ [], which is of course false.
With first, we can solve the earlier issue with try where it would stop
executing the sequence on the first failure.
theorem Perm3_In_better_with_first (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ <;> swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝
first
| rw [List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x ∈ [y✝, z✝]⊢ x = y✝ ∨ x ∈ [x✝, z✝] List.mem_cons, swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x ∈ [z✝]⊢ x = y✝ ∨ x = x✝ ∨ x ∈ [z✝] List.mem_cons swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = y✝ ∨ x = x✝ ∨ x = z✝ ∨ x ∈ []] swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] at * trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ <;> swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝ ∨ x ∈ []⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ ∨ x ∈ [] lia All goals completed! 🐙
| lia All goals completed! 🐙
Our Perm3.In example is now quite short! Can we still do better?
10.3. The simp Tactic
The simp tactic is Lean's simplifier. It is one of the most powerful
tools in the language, and it is used heavily in real Lean developments.
The tactic simplifies the target (the goal and/or one or more hypotheses)
by repeatedly rewriting it using a set of lemmas.
At each step it tries every lemma in its available set the way
first would, applies whichever one matches
via rw, and repeats until no lemma applies anywhere.
Like repeat, it fails outright if it never manages to apply a rewrite
("simp made no progress"), rather than succeeding as a
no-op the way try simp would.
The simp tactic's available set of lemmas begins with a default set and can be extended
to include theorems labeled @[simp].
Indeed, the characterizing lemmas we've been writing for
our definitions all throughout this book are examples
of these simplification lemmas, or
simp lemmas as they're called by Lean programmers, only
we have refrained from annotating them as such (until now!).
namespace simp_lemmas_example
/- `add_zero` and `add_succ` are the `simp` lemmas for `+`. -/
@[simp]
theorem add_zero (n : Nat) : n + 0 = n := by n:Nat⊢ n + 0 = n rfl All goals completed! 🐙
@[simp]
theorem add_succ (n m : Nat) : n + (m + 1) = (n + m) + 1 := by n:Natm:Nat⊢ n + (m + 1) = n + m + 1 rfl All goals completed! 🐙
Instead of manually rewriting by the characterizing lemmas in the example below,
simp does it automatically.
theorem add_succ_nested (n m : Nat) :
n + (m + 1 + 1) = (n + m + 1) + 1 := by n:Natm:Nat⊢ n + (m + 1 + 1) = n + m + 1 + 1
simp All goals completed! 🐙
The other way to extend simp's set of available lemmas is to list them
explicitly, by writing simp [<theorems>]. If you want simp to only use those,
you can use simp only [<theorems>]. As with rw, you can also supply a
definition to simp to simplify using that definition.
theorem add_succ_nested_2 (n m : Nat) :
n + (m + 1 + 1) = (n + m + 1) + 1 := by n:Natm:Nat⊢ n + (m + 1 + 1) = n + m + 1 + 1
simp only [add_succ, add_zero] All goals completed! 🐙
If you want to know what simp is doing, you can run simp?.
theorem add_succ_nested_3 (n m : Nat) :
n + (m + 1 + 1) = (n + m + 1) + 1 := by n:Natm:Nat⊢ n + (m + 1 + 1) = n + m + 1 + 1
simp? All goals completed! 🐙
end simp_lemmas_example
In the InfoView, you will see
Click the [apply] button to replace simp? with
the suggested replacement. You should always do this for your final proof scripts, just
as was recommended for rw? and exact? in the
UsingLean chapter.
Interestingly, we can see for this example that simp used the Nat version
of add_zero, not our own, added above, and also pulled in Nat.add_left_cancel_iff,
which is not strictly needed. But the combination works, even if it is not minimal.
As with apply and rw, simp can also simplify
hypotheses — invoking simp as simp [<lemmas>] at h
runs the simplifier at hypothesis h.
example α x (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ ++ l₂)
(h₂ : x ∈ l₂ ++ l₃) :
x ∈ l₁ ++ l₃ ∨ x ∈ l₂ := by α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ++ l₂h₂:x ∈ l₂ ++ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂
simp at h₁ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ++ l₃h₁:x ∈ l₁ ∨ x ∈ l₂⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp at h₂ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂; lia All goals completed! 🐙
We could equally well have written
example α x (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ ++ l₂)
(h₂ : x ∈ l₂ ++ l₃) :
x ∈ l₁ ++ l₃ ∨ x ∈ l₂ := by α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ++ l₂h₂:x ∈ l₂ ++ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂
simp at * α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂; lia All goals completed! 🐙
If we want to mutually simplify everywhere, we can use simp_all, which
simplifies in all hypotheses and in the goal at the same time. The tactic simp_all
is not the same as simp at *. The latter
simplifies each target independently, whereas simp_all
additionally lets the (simplified) hypotheses simplify each other and the goal,
iterating to a joint fixpoint.
Here's an example that illustrates the difference:
example (a b : Nat) (h1 : a = 0) (h2 : a + b = 5) : b = 5 := by a:Natb:Nath1:a = 0h2:a + b = 5⊢ b = 5
simp at * a:Natb:Nath1:a = 0h2:a + b = 5⊢ b = 5
This fails with:
But simp_all closes the goal:
example (a b : Nat) (h1 : a = 0) (h2 : a + b = 5) : b = 5 := by a:Natb:Nath1:a = 0h2:a + b = 5⊢ b = 5
simp_all All goals completed! 🐙
We can dramatically simplify our Perm3_In_shortest theorem using simp_all:
theorem Perm3_In_shortest (α : Type) (x : α) (l₁ l₂ : List α)
(hPerm : Perm3 l₁ l₂) (hIn : x ∈ l₁) : x ∈ l₂ := by α:Typex:αl₁:List αl₂:List αhPerm:Perm3 l₁ l₂hIn:x ∈ l₁⊢ x ∈ l₂
induction hPerm swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ <;> swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [y✝, x✝, z✝]swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x ∈ [x✝, y✝, z✝]⊢ x ∈ [x✝, z✝, y✝]trans α:Typex:αl₁:List αl₂:List αl₁✝:List αl₂✝:List αl₃✝:List αh₁₂✝:Perm3 l₁✝ l₂✝h₂₃✝:Perm3 l₂✝ l₃✝h₁₂_ih✝:x ∈ l₁✝ → x ∈ l₂✝h₂₃_ih✝:x ∈ l₂✝ → x ∈ l₃✝hIn:x ∈ l₁✝⊢ x ∈ l₃✝ simp_all All goals completed! 🐙 <;> swap12 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝⊢ x = y✝ ∨ x = x✝ ∨ x = z✝swap23 α:Typex:αl₁:List αl₂:List αx✝:αy✝:αz✝:αhIn:x = x✝ ∨ x = y✝ ∨ x = z✝⊢ x = x✝ ∨ x = z✝ ∨ x = y✝ lia All goals completed! 🐙
Should we add something like the following, to explain conditional rewrites?
Recall from Tactics that rewriting with a theorem h₁ -> h₂ -> a = b uses
a = b and leaves h₁ and h₂ as new subgoals. We can include such theorems
in simp's available set, too, but it handles the premises differently:
it tries to discharge h₁, h₂ too, recursively, using simp again (by default),
and only fires the rewrite if it succeeds.
If it can't discharge a premise, it just doesn't use that lemma.
Claude tested three variants of this against the real toolchain (lake env lean).
The double_injective lemma from Tactics doesn't actually work here: its conclusion is the
bare variable n = m, which isn't a usable rewrite pattern (simp lemmas need a real
compound term on the left), so simp [double_injective] fails outright with "simp made
no progress" before it ever gets anywhere near the n.double = m.double premise.
A conditional lemma that does have a proper compound left-hand side, like
Nat.sub_add_cancel : n ≤ m -> m - n + n = m, tells a cleaner three-part story. With
hle : n ≤ m in context:
example (n m : Nat) (hle : n ≤ m) : m - n + n = m := by simp [Nat.sub_add_cancel] -- fails: "simp made no progress" example (n m : Nat) (hle : n ≤ m) : m - n + n = m := by simp [Nat.sub_add_cancel, hle] -- succeeds example (n m : Nat) (hle : n ≤ m) : m - n + n = m := by simp_all [Nat.sub_add_cancel] -- succeeds, without naming hle
The first case shows the discharge step only consults the active simp set (default set
plus whatever's explicitly listed) -- not arbitrary context hypotheses -- so hle
sitting right there doesn't help; simp just skips the lemma, exactly the "no error, no
leftover subgoal" behavior claimed above. The second shows discharge working once hle
is added to the set. The third previews simp_all (introduced a bit further down this
chapter): it folds every hypothesis into the active set automatically, so it discharges
the premise without hle being named at all. That third point makes this example worth
placing right here rather than after simp_all -- it's a preview, and it ties the two
sections together.
10.3.1. Idiomatic simp Usage
Worth tying this convention explicitly back to the fixpoint framing suggested near the
top of this section: a terminal simp is safe precisely because nothing downstream
depends on its exact resulting term -- only on whether it helped close the goal. A
nonterminal simp is risky because whatever manual tactic comes next (cases h1 with |
inl h => ... in the example below) depends on the specific shape simp leaves behind,
and that shape isn't a stable contract -- it can change as the simp set grows, since
simp just runs to whatever fixpoint the current lemma set produces. Saying that
explicitly might make the "why" land harder than jumping straight to the
terminal/nonterminal rule.
Because simp is such a powerful tactic, the Lean community has developed a number of
conventions surrounding appropriate usage. One such convention is around
terminal simp usage.
A call to simp is considered terminal either when it is the last tactic used to close a
goal or when it is followed only by other automatic (also called "flexible") tactics like
simp or lia. In idiomatic Lean, all nonterminal uses of simp should
use the only qualifier and specify exactly which lemmas are being used to simplify.
Use of simp without only should only occur in terminal positions.
In our example from before, the use of simp is terminal (and therefore okay)
because it is followed only by other simps and lia:
example α x (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ ++ l₂)
(h₂ : x ∈ l₂ ++ l₃) :
x ∈ l₁ ++ l₃ ∨ x ∈ l₂ := by α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ++ l₂h₂:x ∈ l₂ ++ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂
simp at h₁ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ++ l₃h₁:x ∈ l₁ ∨ x ∈ l₂⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp at h₂ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂; lia All goals completed! 🐙
On the other hand, if we instead decline to use lia and solve the goal manually,
this example uses simp in a nonterminal position and is considered poor style:
example α x (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ ++ l₂)
(h₂ : x ∈ l₂ ++ l₃) :
x ∈ l₁ ++ l₃ ∨ x ∈ l₂ := by α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ++ l₂h₂:x ∈ l₂ ++ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂
simp at h₁ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ++ l₃h₁:x ∈ l₁ ∨ x ∈ l₂⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp at h₂ α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂; simp α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂
cases h₁ with
| inl h => inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂ left inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ x ∈ l₁ ∨ x ∈ l₃; left inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ x ∈ l₁; exact h All goals completed! 🐙
| inr h => inr α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₂⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂ right inr α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₂⊢ x ∈ l₂; exact h All goals completed! 🐙
Using simp this way is brittle because if we add new simp lemmas to our library,
this can change the way that our hypotheses and goals are simplified. Because our proof
after the simps relies on the precise structure of the goals and hypotheses, these
changes could cause the proof to break as the structure of the development evolves.
We can fix the style of this proof by changing the simps to specify which theorems
they are using to simplify:
example α x (l₁ l₂ l₃ : List α)
(h₁ : x ∈ l₁ ++ l₂)
(h₂ : x ∈ l₂ ++ l₃) :
x ∈ l₁ ++ l₃ ∨ x ∈ l₂ := by α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ++ l₂h₂:x ∈ l₂ ++ l₃⊢ x ∈ l₁ ++ l₃ ∨ x ∈ l₂
-- the * here targets all hypotheses and the goal
simp only [List.mem_append] at * α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₁:x ∈ l₁ ∨ x ∈ l₂h₂:x ∈ l₂ ∨ x ∈ l₃⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂
cases h₁ with
| inl h => inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂ left inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ x ∈ l₁ ∨ x ∈ l₃; left inl α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₁⊢ x ∈ l₁; exact h All goals completed! 🐙
| inr h => inr α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₂⊢ (x ∈ l₁ ∨ x ∈ l₃) ∨ x ∈ l₂ right inr α:Type u_1x:αl₁:List αl₂:List αl₃:List αh₂:x ∈ l₂ ∨ x ∈ l₃h:x ∈ l₂⊢ x ∈ l₂; exact h All goals completed! 🐙
This usage of simp only is better because the addition of new simp lemmas won't
cause this proof to change.
Another rule around proper simp usage applies to the appropriate definition
of simp lemmas.
All of the theorems marked with the @[simp] attribute in a Lean library compose the simp set
for that library, and the result of simplifying an expression iteratively using all of the
theorems in the simp set is the simp normal form of that expression.
It's important for the stability of proofs using simp that all the theorems in the simp
set progress towards this normal form. Accordingly, library designers often first consider
what they want that normal form to look like, and then structure their theorem definitions
accordingly. As a simple example, the simp normal form for lists prefers to use the ++
notation instead of List.append, so there is a simp theorem List.append_eq
whose type is List.append_eq {α : Type u} {as bs : List α} : as.append bs = as ++ bs.
In this case, the simp normal form appears on the right, while the expression in need of
simplification appears on the left. We can thus think of this theorem as simplifying from left
to right. Not every simp lemma in the standard library has a simp normal form
on its right-hand side, but all make progress towards simp normal form when applied.
For our purposes, in this textbook and in later ones, we will take care to define our simp
lemmas such that they respect this left-to-right simplification behavior.
10.4. The trivial Tactic
A final automated tactic to have in your toolkit is trivial,
which tries a number of different simple tactics
(such as rfl or contradiction)
to close the current goal. Some examples:
example : 1 = 1 := by ⊢ 1 = 1 trivial All goals completed! 🐙
example : (1, 2).fst = 1 := by ⊢ (1, 2).fst = 1 trivial All goals completed! 🐙
example (a b : Prop) : ¬ a → a → b := by a:Propb:Prop⊢ ¬a → a → b intro h₁ h₂ a:Propb:Proph₁:¬ah₂:a⊢ b; trivial All goals completed! 🐙
10.5. Case Study: Regular Expressions
As a culminating exercise for this chapter and as practice using the automation techniques we discussed above on a real proof, we examine the theory of regular expressions, eventually working up to a proof of the pumping lemma.
10.5.1. Definitions
Regular expressions are a formal language for describing sets of strings. Their syntax is defined as follows:
inductive RegExp (α : Type) : Type where
| EmptySet
| EmptyStr
| Char (c : α)
| App (r1 r2 : RegExp α)
| Union (r1 r2 : RegExp α)
| Star (r : RegExp α)
deriving BEq, DecidableEq, Repr
-- prevents printing dot-chained, method-call-style like r1.App r2
attribute [pp_nodot] RegExp.Char RegExp.App RegExp.Union RegExp.Star
namespace RegExp
Note that this definition is polymorphic: regular
expressions in RegExp α describe strings with characters drawn
from α — which in this exercise we represent as lists with
elements from α.
(Technical aside: we depart slightly from standard practice in
that we do not require the type α to be finite. This results in
a somewhat different theory of regular expressions, but the
difference is not significant for present purposes.)
CH: Do you mean here that this is different because the inductive type doesn't specify α is finite? In Lean the convention is for inductives not to carry Prop-valued typeclass assumptions, enforcing this only at the theorems that use them. So this could give off a slightly wrong impression. DHS: @bcpierce00 What was the purpose of this aside in the original Rocq text? Does it make sense to keep here?
We connect regular expressions and strings by defining when a regular expression matches some string.
It would be convenient to declare the variables below so that inline prose
throughout the rest of this section can use α, x, s, s₁, s₂, s₃,
ss, re, re₁, and re₂ without repeating their type annotations, but the
same problem described in Logic applies: an unused variable
is silently added to the local context in basically every proof from here on,
even when the theorem never mentions it, which makes theorem hover-overs in
the HTML book unusable. Until we have a way to declare variables visible only
for inline prose (rather than for every lean block), we leave this
commented out:
-- variable -- (α : Type) -- (x : α) -- (s s₁ s₂ s₃ : List α) -- (ss : List (List α)) -- (re re₁ re₂ : RegExp α)
Informally, this looks as follows:
-
The regular expression
EmptySetdoes not match any string. -
EmptyStrmatches the empty string[]. -
Char xmatches the one-character string[x]. -
If
re₁matchess₁, andre₂matchess₂, thenApp re₁ re₂matchess₁ ++ s₂. -
If at least one of
re₁andre₂matchess, thenUnion re₁ re₂matchess. -
Finally, if we can write some string
sas the concatenation of a sequence of stringss = s₁ ++ ... ++ sₖ, and the expressionrematches each one of the stringssᵢ, thenStar rematchess.In particular, the sequence of strings may be empty, so
Star realways matches the empty string[]no matter whatreis.
We can easily translate this intuition into a set of rules,
where we write s =~ re to say that re matches s:
─────────────── (mEmpty)
[] =~ EmptyStr
─────────────── (mChar)
[x] =~ (Char x)
s₁ =~ re₁ s₂ =~ re₂
─────────────────────────── (mApp)
(s₁ ++ s₂) =~ (App re₁ re₂)
s₁ =~ re₁
───────────────────── (mUnionL)
s₁ =~ (Union re₁ re₂)
s₂ =~ re₂
───────────────────── (mUnionR)
s₂ =~ (Union re₁ re₂)
──────────────── (mStar0)
[] =~ (Star re)
s₁ =~ re s₂ =~ (Star re)
──────────────────────────── (mStarApp)
(s₁ ++ s₂) =~ (Star re)
This directly corresponds to the following inductive definition:
inductive ExpMatch {α : Type} : List α → RegExp α → Prop where
| mEmpty : ExpMatch [] EmptyStr
| mChar (c : α) : ExpMatch [c] (Char c)
| mApp (s₁ s₂ : List α) {re₁ re₂ : RegExp α}
(h₁ : ExpMatch s₁ re₁) (h₂ : ExpMatch s₂ re₂)
: ExpMatch (s₁ ++ s₂) (App re₁ re₂)
| mUnionL (s₁ : List α) {re₁ re₂ : RegExp α}
(h₁ : ExpMatch s₁ re₁) : ExpMatch s₁ (Union re₁ re₂)
| mUnionR (s₂ : List α) {re₁ re₂ : RegExp α}
(h₂ : ExpMatch s₂ re₂) : ExpMatch s₂ (Union re₁ re₂)
| mStar0 (re : RegExp α) : ExpMatch [] (Star re)
| mStarApp (s₁ s₂ : List α) {re : RegExp α}
(h₁ : ExpMatch s₁ re) (h₂ : ExpMatch s₂ (Star re))
: ExpMatch (s₁ ++ s₂) (Star re)
open ExpMatch
infix:40 " =~ " => ExpMatch
Notice that this clause in our informal definition...
"The expression
EmptySetdoes not match any string."
... is not explicitly reflected in the above definition. Do we need to add something?
(A) Yes, we should add a rule for this.
(B) No, one of the other rules already covers this case.
(C) No, the lack of a rule actually gives us the behavior we want.
Notice that these rules are not quite the same as the
intuition that we gave at the beginning of the section. First, we
don't need to include a rule explicitly stating that no string is
matched by EmptySet; indeed, the syntax of inductive definitions
doesn't even allow us to give such a "negative rule." We just
don't happen to include any rule that would have the effect of
EmptySet matching some string.
Second, the intuition we gave for Union and Star corresponds
to two constructors each: mUnionL / mUnionR, and mStar0 /
mStarApp. The result is logically equivalent to the original
intuition but more convenient to use in Lean, since the recursive
occurrences of ExpMatch are given as direct arguments to the
constructors, making it easier to perform induction on evidence.
(The exercises below ask you
to prove that the constructors given in the inductive declaration
and the ones that would arise from a more literal transcription of
the intuition are indeed equivalent.)
Let's illustrate these rules with a few examples.
10.5.2. Examples
example : [1] =~ Char 1 := by ⊢ [1] =~ Char 1
apply mChar All goals completed! 🐙
example : [1, 2] =~ App (Char 1) (Char 2) := by ⊢ [1, 2] =~ App (Char 1) (Char 2)
apply mApp [1] h₁ ⊢ [1] =~ Char 1h₂ ⊢ [2] =~ Char 2 <;> h₁ ⊢ [1] =~ Char 1h₂ ⊢ [2] =~ Char 2 constructor All goals completed! 🐙
Notice how the last example applies mApp to the string
[1] directly. Since the goal mentions [1, 2] instead of
[1] ++ [2], Lean wouldn't be able to figure out how to split
the string on its own.
Using inversion, we can also show that certain strings do not
match a regular expression:
example : ¬([1, 2] =~ Char 1) := by ⊢ ¬[1, 2] =~ Char 1
intro contra contra:[1, 2] =~ Char 1⊢ False; inversion contra All goals completed! 🐙
We can define helper functions for writing down regular
expressions. The reg_exp_of_list function constructs a regular
expression that matches exactly the string that it receives as an
argument:
def reg_exp_of_list {α} (l : List α) :=
match l with
| [] => EmptyStr
| x :: l' => App (Char x) (reg_exp_of_list l')
example : [1, 2, 3] =~ reg_exp_of_list [1, 2, 3] := by ⊢ [1, 2, 3] =~ reg_exp_of_list [1, 2, 3]
apply mApp [1] h₁ ⊢ [1] =~ Char 1h₂ ⊢ [2, 3] =~ reg_exp_of_list [2, 3]; constructor h₂ ⊢ [2, 3] =~ reg_exp_of_list [2, 3]
apply mApp [2] h₂.h₁ ⊢ [2] =~ Char 2h₂.h₂ ⊢ [3] =~ reg_exp_of_list [3]; constructor h₂.h₂ ⊢ [3] =~ reg_exp_of_list [3]
apply mApp [3] h₂.h₂.h₁ ⊢ [3] =~ Char 3h₂.h₂.h₂ ⊢ [] =~ reg_exp_of_list []; constructor h₂.h₂.h₂ ⊢ [] =~ reg_exp_of_list []
constructor All goals completed! 🐙
As a quick exercise, prove that every list matches reg_exp_of_list of itself:
theorem regexp_match_of_list α (l : List α) : l =~ reg_exp_of_list l := by α:Typel:List α⊢ l =~ reg_exp_of_list l
solution!
induction l with
| nil => nil α:Type⊢ [] =~ reg_exp_of_list [] constructor All goals completed! 🐙
| cons hd tl ih => cons α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tl⊢ hd :: tl =~ reg_exp_of_list (hd :: tl)
simp only [reg_exp_of_list] cons α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tl⊢ hd :: tl =~ App (Char hd) (reg_exp_of_list tl)
have h : hd :: tl = [hd] ++ tl := by α:Typel:List α⊢ l =~ reg_exp_of_list l simp cons α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ hd :: tl =~ App (Char hd) (reg_exp_of_list tl)
rw [h cons α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ [hd] ++ tl =~ App (Char hd) (reg_exp_of_list tl)] cons α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ [hd] ++ tl =~ App (Char hd) (reg_exp_of_list tl)
constructor cons.h₁ α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ [hd] =~ Char hdcons.h₂ α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ tl =~ reg_exp_of_list tl; constructor cons.h₂ α:Typehd:αtl:List αih:tl =~ reg_exp_of_list tlh:hd :: tl = [hd] ++ tl⊢ tl =~ reg_exp_of_list tl; assumption All goals completed! 🐙
We can also prove general facts about ExpMatch. For instance,
the following lemma shows that every string s matched by re
is also matched by Star re.
theorem MStar1 α s (re : RegExp α) (h : s =~ re) : s =~ Star re := by α:Types:List αre:RegExp αh:s =~ re⊢ s =~ Star re
workinclass!
rw [← List.append_nil s α:Types:List αre:RegExp αh:s =~ re⊢ s ++ [] =~ Star re] α:Types:List αre:RegExp αh:s =~ re⊢ s ++ [] =~ Star re
constructor h₁ α:Types:List αre:RegExp αh:s =~ re⊢ s =~ reh₂ α:Types:List αre:RegExp αh:s =~ re⊢ [] =~ Star re
. h₁ α:Types:List αre:RegExp αh:s =~ re⊢ s =~ re assumption All goals completed! 🐙
. h₂ α:Types:List αre:RegExp αh:s =~ re⊢ [] =~ Star re constructor All goals completed! 🐙
(Note the use of List.append_nil to change the goal of the theorem to
exactly the shape expected by mStarApp.)
The following lemmas show that the intuition about matching given at the beginning of the section can be obtained from the formal inductive definition.
theorem EmptySet_is_empty α (s : List α) : ¬(s =~ EmptySet) := by α:Types:List α⊢ ¬s =~ EmptySet
solution!
intro h α:Types:List αh:s =~ EmptySet⊢ False
inversion h All goals completed! 🐙
theorem MUnion' α (s : List α) (re₁ re₂ : RegExp α) :
s =~ re₁ ∨ s =~ re₂ →
s =~ Union re₁ re₂ := by α:Types:List αre₁:RegExp αre₂:RegExp α⊢ s =~ re₁ ∨ s =~ re₂ → s =~ Union re₁ re₂
solution!
intro h α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₁ ∨ s =~ re₂⊢ s =~ Union re₁ re₂
obtain h | h := h inl α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₁⊢ s =~ Union re₁ re₂inr α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₂⊢ s =~ Union re₁ re₂
case inl => α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₁⊢ s =~ Union re₁ re₂ apply mUnionL α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₁⊢ s =~ re₁; assumption All goals completed! 🐙
case inr => α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₂⊢ s =~ Union re₁ re₂ apply mUnionR α:Types:List αre₁:RegExp αre₂:RegExp αh:s =~ re₂⊢ s =~ re₂; assumption All goals completed! 🐙
The next lemma is stated in terms of the List.foldr function on lists:
if ss : List (List α) represents a sequence of
strings s₁, ..., sₙ, then List.foldr (· ++ ·) [] ss is the result of
concatenating them all together.
theorem MStar' α (ss : List (List α)) (re : RegExp α)
(h : ∀ s, s ∈ ss → s =~ re) :
ss.foldr (· ++ ·) [] =~ Star re := by α:Typess:List (List α)re:RegExp αh:∀ (s : List α), s ∈ ss → s =~ re⊢ List.foldr (fun x1 x2 => x1 ++ x2) [] ss =~ Star re
solution!
induction ss with
| nil => nil α:Typere:RegExp αh:∀ (s : List α), s ∈ [] → s =~ re⊢ List.foldr (fun x1 x2 => x1 ++ x2) [] [] =~ Star re constructor All goals completed! 🐙
| cons s ss' ih => cons α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ List.foldr (fun x1 x2 => x1 ++ x2) [] (s :: ss') =~ Star re
simp only [List.foldr_cons] cons α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ s ++ List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star re
constructor cons.h₁ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ s =~ recons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star re
· cons.h₁ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ s =~ re apply h cons.h₁ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ s ∈ s :: ss'; simp All goals completed! 🐙
· cons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star re apply ih cons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ re⊢ ∀ (s : List α), s ∈ ss' → s =~ re; intro s' hs' cons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ res':List αhs':s' ∈ ss'⊢ s' =~ re
apply h cons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ res':List αhs':s' ∈ ss'⊢ s' ∈ s :: ss'; right cons.h₂ α:Typere:RegExp αs:List αss':List (List α)ih:(∀ (s : List α), s ∈ ss' → s =~ re) → List.foldr (fun x1 x2 => x1 ++ x2) [] ss' =~ Star reh:∀ (s_1 : List α), s_1 ∈ s :: ss' → s_1 =~ res':List αhs':s' ∈ ss'⊢ List.Mem s' ss'; assumption All goals completed! 🐙
It turns out that the EmptyStr constructor is actually not
needed, since the regular expression matching the empty string can
also be defined from Star and EmptySet:
def EmptyStr' {α : Type} := @Star α (EmptySet)
State and prove that this EmptyStr' definition matches exactly
the same strings as the EmptyStr constructor.
theorem empty_equiv {α : Type} (s : List α) :
s =~ EmptyStr ↔ s =~ EmptyStr' := by α:Types:List α⊢ s =~ EmptyStr ↔ s =~ EmptyStr'
constructor mp α:Types:List α⊢ s =~ EmptyStr → s =~ EmptyStr'mpr α:Types:List α⊢ s =~ EmptyStr' → s =~ EmptyStr <;> mp α:Types:List α⊢ s =~ EmptyStr → s =~ EmptyStr'mpr α:Types:List α⊢ s =~ EmptyStr' → s =~ EmptyStr intro h mpr α:Types:List αh:s =~ EmptyStr'⊢ s =~ EmptyStr
. mp α:Types:List αh:s =~ EmptyStr⊢ s =~ EmptyStr' inversion h mEmpty α:Type⊢ [] =~ EmptyStr'; constructor All goals completed! 🐙
. mpr α:Types:List αh:s =~ EmptyStr'⊢ s =~ EmptyStr inversion h with
| mStar0 => constructor All goals completed! 🐙
| mStarApp _ _ h₁ _ => inversion h₁ All goals completed! 🐙
Since the definition of ExpMatch has a recursive
structure, we might expect that proofs involving regular
expressions will often require induction on evidence.
For example, suppose we want to prove the following intuitive
fact: if a string s is matched by a regular expression re,
then all elements of s must occur as character literals
somewhere in re.
To state this as a theorem, we first define a function reChars
that lists all characters that occur in a regular expression:
def reChars {α : Type} (re : RegExp α) : List α :=
match re with
| EmptySet => []
| EmptyStr => []
| Char x => [x]
| App re₁ re₂ => reChars re₁ ++ reChars re₂
| Union re₁ re₂ => reChars re₁ ++ reChars re₂
| Star re => reChars re
Now, the main theorem:
theorem in_re_match {α : Type} {s : List α} {re : RegExp α} {x : α}
(hmatch : s =~ re) (hin : x ∈ s) : x ∈ reChars re := by α:Types:List αre:RegExp αx:αhmatch:s =~ rehin:x ∈ s⊢ x ∈ re.reChars
induction hmatch with
| mEmpty => mEmpty α:Types:List αre:RegExp αx:αhin:x ∈ []⊢ x ∈ EmptyStr.reChars contradiction All goals completed! 🐙
| mChar c => mChar α:Types:List αre:RegExp αx:αc:αhin:x ∈ [c]⊢ x ∈ (Char c).reChars simp only [reChars] mChar α:Types:List αre:RegExp αx:αc:αhin:x ∈ [c]⊢ x ∈ [c]; assumption All goals completed! 🐙
| mApp _ _ _ _ ih₁ ih₂ => mApp α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin:x ∈ s₁✝ ++ s₂✝⊢ x ∈ (App re₁✝ re₂✝).reChars
/- Something interesting happens in the `mApp` case. We obtain
_two_ induction hypotheses: one that applies when `x` occurs in
`s₁` (which is matched by `re₁`), and a second one that applies
when `x` occurs in `s₂` (matched by `re₂`). -/
workinclass!
simp only [reChars, List.mem_append] at * mApp α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin:x ∈ s₁✝ ∨ x ∈ s₂✝⊢ x ∈ re₁✝.reChars ∨ x ∈ re₂✝.reChars
cases hin with
| inl hin₁ => mApp.inl α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin₁:x ∈ s₁✝⊢ x ∈ re₁✝.reChars ∨ x ∈ re₂✝.reChars left mApp.inl α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin₁:x ∈ s₁✝⊢ x ∈ re₁✝.reChars; exact ih₁ hin₁ All goals completed! 🐙
| inr hin₂ => mApp.inr α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin₂:x ∈ s₂✝⊢ x ∈ re₁✝.reChars ∨ x ∈ re₂✝.reChars right mApp.inr α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝ih₁:x ∈ s₁✝ → x ∈ re₁✝.reCharsih₂:x ∈ s₂✝ → x ∈ re₂✝.reCharshin₂:x ∈ s₂✝⊢ x ∈ re₂✝.reChars; exact ih₂ hin₂ All goals completed! 🐙
| mUnionL _ _ ih => mUnionL α:Types:List αre:RegExp αx:αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝ih:x ∈ s₁✝ → x ∈ re₁✝.reCharshin:x ∈ s₁✝⊢ x ∈ (Union re₁✝ re₂✝).reChars
simp only [reChars, List.mem_append] mUnionL α:Types:List αre:RegExp αx:αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝ih:x ∈ s₁✝ → x ∈ re₁✝.reCharshin:x ∈ s₁✝⊢ x ∈ re₁✝.reChars ∨ x ∈ re₂✝.reChars; left mUnionL α:Types:List αre:RegExp αx:αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝ih:x ∈ s₁✝ → x ∈ re₁✝.reCharshin:x ∈ s₁✝⊢ x ∈ re₁✝.reChars; exact ih hin All goals completed! 🐙
| mUnionR _ _ ih => mUnionR α:Types:List αre:RegExp αx:αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝ih:x ∈ s₂✝ → x ∈ re₂✝.reCharshin:x ∈ s₂✝⊢ x ∈ (Union re₁✝ re₂✝).reChars
simp only [reChars, List.mem_append] mUnionR α:Types:List αre:RegExp αx:αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝ih:x ∈ s₂✝ → x ∈ re₂✝.reCharshin:x ∈ s₂✝⊢ x ∈ re₁✝.reChars ∨ x ∈ re₂✝.reChars; right mUnionR α:Types:List αre:RegExp αx:αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝ih:x ∈ s₂✝ → x ∈ re₂✝.reCharshin:x ∈ s₂✝⊢ x ∈ re₂✝.reChars; exact ih hin All goals completed! 🐙
| mStar0 => mStar0 α:Types:List αre:RegExp αx:αre✝:RegExp αhin:x ∈ []⊢ x ∈ (Star re✝).reChars simp at hin All goals completed! 🐙
| mStarApp _ _ _ _ ih₁ ih₂ => mStarApp α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝ih₁:x ∈ s₁✝ → x ∈ re✝.reCharsih₂:x ∈ s₂✝ → x ∈ (Star re✝).reCharshin:x ∈ s₁✝ ++ s₂✝⊢ x ∈ (Star re✝).reChars
/- Here again we get two induction hypotheses, and they illustrate
why we need induction on evidence for `ExpMatch`, rather than
induction on the regular expression `re`: the latter would only
provide an induction hypothesis for strings that match `re`, which
would not allow us to reason about the case `x ∈ s₂`. -/
workinclass!
simp only [List.mem_append] at hin mStarApp α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝ih₁:x ∈ s₁✝ → x ∈ re✝.reCharsih₂:x ∈ s₂✝ → x ∈ (Star re✝).reCharshin:x ∈ s₁✝ ∨ x ∈ s₂✝⊢ x ∈ (Star re✝).reChars
cases hin with
| inl hin₁ => mStarApp.inl α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝ih₁:x ∈ s₁✝ → x ∈ re✝.reCharsih₂:x ∈ s₂✝ → x ∈ (Star re✝).reCharshin₁:x ∈ s₁✝⊢ x ∈ (Star re✝).reChars exact ih₁ hin₁ All goals completed! 🐙
| inr hin₂ => mStarApp.inr α:Types:List αre:RegExp αx:αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝ih₁:x ∈ s₁✝ → x ∈ re✝.reCharsih₂:x ∈ s₂✝ → x ∈ (Star re✝).reCharshin₂:x ∈ s₂✝⊢ x ∈ (Star re✝).reChars exact ih₂ hin₂ All goals completed! 🐙
Write a recursive function reNotEmpty that tests whether a
regular expression matches some string. Prove that your function
is correct.
def reNotEmpty {α : Type} (re : RegExp α) : Bool :=
match re with
| EmptySet => false
| EmptyStr => true
| Char _ => true
| App re₁ re₂ => reNotEmpty re₁ && reNotEmpty re₂
| Union re₁ re₂ => reNotEmpty re₁ || reNotEmpty re₂
| Star _ => true
theorem reNotEmpty_correct {α : Type} (re : RegExp α) :
(∃ s, s =~ re) ↔ reNotEmpty re = true := by α:Typere:RegExp α⊢ (∃ s, s =~ re) ↔ re.reNotEmpty = true
induction re with (simp only [reNotEmpty] Star α:Typere:RegExp αr_ih✝:(∃ s, s =~ re) ↔ re.reNotEmpty = true⊢ (∃ s, s =~ Star re) ↔ True)
| EmptySet => EmptySet α:Type⊢ (∃ s, s =~ EmptySet) ↔ false = true
simp only [Bool.false_eq_true, iff_false, not_exists] EmptySet α:Type⊢ ∀ (x : List α), ¬x =~ EmptySet
intro s h EmptySet α:Types:List αh:s =~ EmptySet⊢ False; inversion h All goals completed! 🐙
| EmptyStr => EmptyStr α:Type⊢ (∃ s, s =~ EmptyStr) ↔ True
simp only [iff_true] EmptyStr α:Type⊢ ∃ s, s =~ EmptyStr; exists [] EmptyStr α:Type⊢ [] =~ EmptyStr; constructor All goals completed! 🐙
| Char x => Char α:Typex:α⊢ (∃ s, s =~ Char x) ↔ True
simp only [iff_true] Char α:Typex:α⊢ ∃ s, s =~ Char x; exists [x] Char α:Typex:α⊢ [x] =~ Char x; constructor All goals completed! 🐙
| App re₁ re₂ ih₁ ih₂ => App α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ App re₁ re₂) ↔ (re₁.reNotEmpty && re₂.reNotEmpty) = true
simp only [Bool.and_eq_true] App α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ App re₁ re₂) ↔ re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true
constructor App.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ App re₁ re₂) → re₁.reNotEmpty = true ∧ re₂.reNotEmpty = trueApp.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true → ∃ s, s =~ App re₁ re₂
· App.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ App re₁ re₂) → re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true intro h App.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh:∃ s, s =~ App re₁ re₂⊢ re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true
obtain ⟨s, h⟩ := h App.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh:s =~ App re₁ re₂⊢ re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true
inversion h with
| mApp s₁ s₂ h₁ h₂ =>
constructor mApp.left α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ re₁.reNotEmpty = truemApp.right α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ re₂.reNotEmpty = true
case left => α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ re₁.reNotEmpty = true apply ih₁.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ ∃ s, s =~ re₁; exists s₁ All goals completed! 🐙
case right => α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ re₂.reNotEmpty = true apply ih₂.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues₁:List αs₂:List αh₁:s₁ =~ re₁h₂:s₂ =~ re₂⊢ ∃ s, s =~ re₂; exists s₂ All goals completed! 🐙
· App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true → ∃ s, s =~ App re₁ re₂ intro h App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh:re₁.reNotEmpty = true ∧ re₂.reNotEmpty = true⊢ ∃ s, s =~ App re₁ re₂
obtain ⟨h₁, h₂⟩ := h App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = true⊢ ∃ s, s =~ App re₁ re₂
obtain ⟨s₁, hs₁⟩ := ih₁.mpr h₁ App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁⊢ ∃ s, s =~ App re₁ re₂
obtain ⟨s₂, hs₂⟩ := ih₂.mpr h₂ App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ ∃ s, s =~ App re₁ re₂
exists (s₁ ++ s₂) App.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ s₁ ++ s₂ =~ App re₁ re₂; constructor App.mpr.h₁ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ s₁ =~ re₁App.mpr.h₂ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ s₂ =~ re₂ <;> App.mpr.h₁ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ s₁ =~ re₁App.mpr.h₂ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trueh₂:re₂.reNotEmpty = trues₁:List αhs₁:s₁ =~ re₁s₂:List αhs₂:s₂ =~ re₂⊢ s₂ =~ re₂ assumption All goals completed! 🐙
| Union re₁ re₂ ih₁ ih₂ => Union α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ Union re₁ re₂) ↔ (re₁.reNotEmpty || re₂.reNotEmpty) = true
simp only [Bool.or_eq_true] Union α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ Union re₁ re₂) ↔ re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true
constructor Union.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ Union re₁ re₂) → re₁.reNotEmpty = true ∨ re₂.reNotEmpty = trueUnion.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true → ∃ s, s =~ Union re₁ re₂
· Union.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ (∃ s, s =~ Union re₁ re₂) → re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true intro h Union.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh:∃ s, s =~ Union re₁ re₂⊢ re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true
obtain ⟨s, h⟩ := h Union.mp α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh:s =~ Union re₁ re₂⊢ re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true
inversion h with
| mUnionL h₁ => left mUnionL α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh₁:s =~ re₁⊢ re₁.reNotEmpty = true; apply ih₁.mp mUnionL α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh₁:s =~ re₁⊢ ∃ s, s =~ re₁; exists s All goals completed! 🐙
| mUnionR h₂ => right mUnionR α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh₂:s =~ re₂⊢ re₂.reNotEmpty = true; apply ih₂.mp mUnionR α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trues:List αh₂:s =~ re₂⊢ ∃ s, s =~ re₂; exists s All goals completed! 🐙
· Union.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = true⊢ re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true → ∃ s, s =~ Union re₁ re₂ intro h Union.mpr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh:re₁.reNotEmpty = true ∨ re₂.reNotEmpty = true⊢ ∃ s, s =~ Union re₁ re₂
obtain h₁ | h₂ := h Union.mpr.inl α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = true⊢ ∃ s, s =~ Union re₁ re₂Union.mpr.inr α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₂:re₂.reNotEmpty = true⊢ ∃ s, s =~ Union re₁ re₂
case inl => α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = true⊢ ∃ s, s =~ Union re₁ re₂ obtain ⟨s, hs⟩ := ih₁.mpr h₁ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trues:List αhs:s =~ re₁⊢ ∃ s, s =~ Union re₁ re₂; exists s α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trues:List αhs:s =~ re₁⊢ s =~ Union re₁ re₂; constructor α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₁:re₁.reNotEmpty = trues:List αhs:s =~ re₁⊢ s =~ re₁; assumption All goals completed! 🐙
case inr => α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₂:re₂.reNotEmpty = true⊢ ∃ s, s =~ Union re₁ re₂ obtain ⟨s, hs⟩ := ih₂.mpr h₂ α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₂:re₂.reNotEmpty = trues:List αhs:s =~ re₂⊢ ∃ s, s =~ Union re₁ re₂; exists s α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₂:re₂.reNotEmpty = trues:List αhs:s =~ re₂⊢ s =~ Union re₁ re₂; apply mUnionR α:Typere₁:RegExp αre₂:RegExp αih₁:(∃ s, s =~ re₁) ↔ re₁.reNotEmpty = trueih₂:(∃ s, s =~ re₂) ↔ re₂.reNotEmpty = trueh₂:re₂.reNotEmpty = trues:List αhs:s =~ re₂⊢ s =~ re₂; assumption All goals completed! 🐙
| Star re _ => Star α:Typere:RegExp αr_ih✝:(∃ s, s =~ re) ↔ re.reNotEmpty = true⊢ (∃ s, s =~ Star re) ↔ True
simp only [iff_true] Star α:Typere:RegExp αr_ih✝:(∃ s, s =~ re) ↔ re.reNotEmpty = true⊢ ∃ s, s =~ Star re; exists [] Star α:Typere:RegExp αr_ih✝:(∃ s, s =~ re) ↔ re.reNotEmpty = true⊢ [] =~ Star re; constructor All goals completed! 🐙
10.5.3. The generalize Tactic
One potentially confusing feature of the induction tactic is
that it won't let you perform an induction over a term that
isn't sufficiently general. Here's an example:
example (α : Type) (s₁ s₂ : List α) (re : RegExp α) :
s₁ =~ Star re →
s₂ =~ Star re →
s₁ ++ s₂ =~ Star re := by α:Types₁:List αs₂:List αre:RegExp α⊢ s₁ =~ Star re → s₂ =~ Star re → s₁ ++ s₂ =~ Star re
intro h₁ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ Star re⊢ s₂ =~ Star re → s₁ ++ s₂ =~ Star re
/- Now, just doing an `inversion` on `h₁` won't get us very far in
the recursive cases. (Try it!) So we need induction (on
evidence). We might try this, but Lean won't let us: -/
induction h₁ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ Star re⊢ s₂ =~ Star re → s₁ ++ s₂ =~ Star re
The problem here is that induction over a Prop hypothesis only
works properly with hypotheses that are "fully general," i.e.,
ones in which all the arguments are just variables, as opposed to more
specific expressions like Star re.
A possible, but awkward, way to solve this problem is "manually generalizing" over the problematic expressions by adding explicit equality hypotheses to the lemma:
example α (s₁ s₂ : List α) (re re' : RegExp α) :
re' = Star re →
s₁ =~ re' →
s₂ =~ Star re →
s₁ ++ s₂ =~ Star re := by α:Types₁:List αs₂:List αre:RegExp αre':RegExp α⊢ re' = Star re → s₁ =~ re' → s₂ =~ Star re → s₁ ++ s₂ =~ Star re
intro h₁ h₂ h₃ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₁:re' = Star reh₂:s₁ =~ re'h₃:s₂ =~ Star re⊢ s₁ ++ s₂ =~ Star re
/- We can now proceed by performing induction over evidence
directly, because the argument to the first hypothesis is
sufficiently general, which means that we can discharge most cases
by inverting the `re' = Star re` equality in the context. -/
induction h₂ mEmpty α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star reh₁:EmptyStr = Star re⊢ [] ++ s₂ =~ Star remChar α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star rec✝:αh₁:Char c✝ = Star re⊢ [c✝] ++ s₂ =~ Star remApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star res₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝ = Star re → s₁✝ ++ s₂ =~ Star reh₂_ih✝:re₂✝ = Star re → s₂✝ ++ s₂ =~ Star reh₁:App re₁✝ re₂✝ = Star re⊢ s₁✝ ++ s₂✝ ++ s₂ =~ Star remUnionL α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star res₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝ = Star re → s₁✝ ++ s₂ =~ Star reh₁:Union re₁✝ re₂✝ = Star re⊢ s₁✝ ++ s₂ =~ Star remUnionR α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star res₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝ = Star re → s₂✝ ++ s₂ =~ Star reh₁:Union re₁✝ re₂✝ = Star re⊢ s₂✝ ++ s₂ =~ Star remStar0 α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star rere✝:RegExp αh₁:Star re✝ = Star re⊢ [] ++ s₂ =~ Star remStarApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αh₃:s₂ =~ Star res₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝ = Star re → s₁✝ ++ s₂ =~ Star reh₂_ih✝:Star re✝ = Star re → s₂✝ ++ s₂ =~ Star reh₁:Star re✝ = Star re⊢ s₁✝ ++ s₂✝ ++ s₂ =~ Star re
/- This works, but it makes the statement of the lemma a bit ugly.
Fortunately, there is a better way... -/
The tactic generalize h : e = x causes Lean to (1) replace all
occurrences of the expression e by the variable x, and (2) add
an equation h : e = x to the context. Here's how we can use it
to show the above result:
theorem star_app α (s₁ s₂ : List α) (re : RegExp α) :
s₁ =~ Star re →
s₂ =~ Star re →
s₁ ++ s₂ =~ Star re := by α:Types₁:List αs₂:List αre:RegExp α⊢ s₁ =~ Star re → s₂ =~ Star re → s₁ ++ s₂ =~ Star re
intro h₁ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ Star re⊢ s₂ =~ Star re → s₁ ++ s₂ =~ Star re
generalize heq : Star re = re' at h₁ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αheq:Star re = re'h₁:s₁ =~ re'⊢ s₂ =~ re' → s₁ ++ s₂ =~ re'
/- We now have `heq : Star re = re'`;
`heq` is contradictory in most cases, allowing us to conclude
immediately via `contradiction`. -/
induction h₁ mEmpty α:Types₁:List αs₂:List αre:RegExp αre':RegExp αheq:Star re = EmptyStr⊢ s₂ =~ EmptyStr → [] ++ s₂ =~ EmptyStrmChar α:Types₁:List αs₂:List αre:RegExp αre':RegExp αc✝:αheq:Star re = Char c✝⊢ s₂ =~ Char c✝ → [c✝] ++ s₂ =~ Char c✝mApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:Star re = re₁✝ → s₂ =~ re₁✝ → s₁✝ ++ s₂ =~ re₁✝h₂_ih✝:Star re = re₂✝ → s₂ =~ re₂✝ → s₂✝ ++ s₂ =~ re₂✝heq:Star re = App re₁✝ re₂✝⊢ s₂ =~ App re₁✝ re₂✝ → s₁✝ ++ s₂✝ ++ s₂ =~ App re₁✝ re₂✝mUnionL α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:Star re = re₁✝ → s₂ =~ re₁✝ → s₁✝ ++ s₂ =~ re₁✝heq:Star re = Union re₁✝ re₂✝⊢ s₂ =~ Union re₁✝ re₂✝ → s₁✝ ++ s₂ =~ Union re₁✝ re₂✝mUnionR α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:Star re = re₂✝ → s₂ =~ re₂✝ → s₂✝ ++ s₂ =~ re₂✝heq:Star re = Union re₁✝ re₂✝⊢ s₂ =~ Union re₁✝ re₂✝ → s₂✝ ++ s₂ =~ Union re₁✝ re₂✝mStar0 α:Types₁:List αs₂:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝⊢ s₂ =~ Star re✝ → [] ++ s₂ =~ Star re✝mStarApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → s₂ =~ re✝ → s₁✝ ++ s₂ =~ re✝h₂_ih✝:Star re = Star re✝ → s₂ =~ Star re✝ → s₂✝ ++ s₂ =~ Star re✝heq:Star re = Star re✝⊢ s₂ =~ Star re✝ → s₁✝ ++ s₂✝ ++ s₂ =~ Star re✝ <;> mEmpty α:Types₁:List αs₂:List αre:RegExp αre':RegExp αheq:Star re = EmptyStr⊢ s₂ =~ EmptyStr → [] ++ s₂ =~ EmptyStrmChar α:Types₁:List αs₂:List αre:RegExp αre':RegExp αc✝:αheq:Star re = Char c✝⊢ s₂ =~ Char c✝ → [c✝] ++ s₂ =~ Char c✝mApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:Star re = re₁✝ → s₂ =~ re₁✝ → s₁✝ ++ s₂ =~ re₁✝h₂_ih✝:Star re = re₂✝ → s₂ =~ re₂✝ → s₂✝ ++ s₂ =~ re₂✝heq:Star re = App re₁✝ re₂✝⊢ s₂ =~ App re₁✝ re₂✝ → s₁✝ ++ s₂✝ ++ s₂ =~ App re₁✝ re₂✝mUnionL α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:Star re = re₁✝ → s₂ =~ re₁✝ → s₁✝ ++ s₂ =~ re₁✝heq:Star re = Union re₁✝ re₂✝⊢ s₂ =~ Union re₁✝ re₂✝ → s₁✝ ++ s₂ =~ Union re₁✝ re₂✝mUnionR α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:Star re = re₂✝ → s₂ =~ re₂✝ → s₂✝ ++ s₂ =~ re₂✝heq:Star re = Union re₁✝ re₂✝⊢ s₂ =~ Union re₁✝ re₂✝ → s₂✝ ++ s₂ =~ Union re₁✝ re₂✝mStar0 α:Types₁:List αs₂:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝⊢ s₂ =~ Star re✝ → [] ++ s₂ =~ Star re✝mStarApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → s₂ =~ re✝ → s₁✝ ++ s₂ =~ re✝h₂_ih✝:Star re = Star re✝ → s₂ =~ Star re✝ → s₂✝ ++ s₂ =~ Star re✝heq:Star re = Star re✝⊢ s₂ =~ Star re✝ → s₁✝ ++ s₂✝ ++ s₂ =~ Star re✝ try contradiction mStarApp α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → s₂ =~ re✝ → s₁✝ ++ s₂ =~ re✝h₂_ih✝:Star re = Star re✝ → s₂ =~ Star re✝ → s₂✝ ++ s₂ =~ Star re✝heq:Star re = Star re✝⊢ s₂ =~ Star re✝ → s₁✝ ++ s₂✝ ++ s₂ =~ Star re✝
-- The interesting cases are those that correspond to `Star`.
case mStar0 _ => α:Types₁:List αs₂:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝⊢ s₂ =~ Star re✝ → [] ++ s₂ =~ Star re✝ intro h₂ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝h₂:s₂ =~ Star re✝⊢ [] ++ s₂ =~ Star re✝; simp only [List.nil_append] α:Types₁:List αs₂:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝h₂:s₂ =~ Star re✝⊢ s₂ =~ Star re✝; exact h₂ All goals completed! 🐙
case mStarApp _ _ _ _ _ _ ih₂ => α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → s₂ =~ re✝ → s₁✝ ++ s₂ =~ re✝ih₂:Star re = Star re✝ → s₂ =~ Star re✝ → s₂✝ ++ s₂ =~ Star re✝heq:Star re = Star re✝⊢ s₂ =~ Star re✝ → s₁✝ ++ s₂✝ ++ s₂ =~ Star re✝
injections heq α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → s₂ =~ re✝ → s₁✝ ++ s₂ =~ re✝ih₂:Star re = Star re✝ → s₂ =~ Star re✝ → s₂✝ ++ s₂ =~ Star re✝heq:re = re✝⊢ s₂ =~ Star re✝ → s₁✝ ++ s₂✝ ++ s₂ =~ Star re✝; subst heq α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star re⊢ s₂ =~ Star re → s₁✝ ++ s₂✝ ++ s₂ =~ Star re
intro h₂ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₁✝ ++ s₂✝ ++ s₂ =~ Star re; simp only [List.append_assoc] α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₁✝ ++ (s₂✝ ++ s₂) =~ Star re
apply mStarApp h₁ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₁✝ =~ reh₂ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₂✝ ++ s₂ =~ Star re
. h₁ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₁✝ =~ re assumption All goals completed! 🐙
. h₂ α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₂✝ ++ s₂ =~ Star re apply ih₂ h₂.heq α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ Star re = Star reh₂.a α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₂ =~ Star re <;> h₂.heq α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ Star re = Star reh₂.a α:Types₁:List αs₂:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αh₁✝:s₁✝ =~ reh₂✝:s₂✝ =~ Star reh₁_ih✝:Star re = re → s₂ =~ re → s₁✝ ++ s₂ =~ reih₂:Star re = Star re → s₂ =~ Star re → s₂✝ ++ s₂ =~ Star reh₂:s₂ =~ Star re⊢ s₂ =~ Star re trivial All goals completed! 🐙
/- Note that the induction hypothesis `ih₂` on the `mStarApp` case
mentions an additional premise `Star re'' = Star re`, which
results from the equality generated by `generalize`. -/
Do not confuse generalize with the generalizing clause on
induction introduced in the Tactics chapter.
The generalizing clause would not help us here — induction on
s₁ =~ Star re would still fail because Star re is a compound expression,
not a bare variable.
The MStar'' lemma below (combined with its converse, the
MStar' exercise above) shows that our definition of ExpMatch
for Star is equivalent to the informal one given previously.
theorem MStar'' α (s : List α) (re : RegExp α) (h : s =~ Star re) :
exists ss : List (List α),
s = List.foldr (· ++ ·) [] ss
∧ ∀ s', s' ∈ ss → s' =~ re := by α:Types:List αre:RegExp αh:s =~ Star re⊢ ∃ ss, s = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
solution!
generalize heq : Star re = re' at h α:Types:List αre:RegExp αre':RegExp αheq:Star re = re'h:s =~ re'⊢ ∃ ss, s = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
induction h mEmpty α:Types:List αre:RegExp αre':RegExp αheq:Star re = EmptyStr⊢ ∃ ss, [] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remChar α:Types:List αre:RegExp αre':RegExp αc✝:αheq:Star re = Char c✝⊢ ∃ ss, [c✝] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remApp α:Types:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:Star re = re₁✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reh₂_ih✝:Star re = re₂✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = App re₁✝ re₂✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remUnionL α:Types:List αre:RegExp αre':RegExp αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:Star re = re₁✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Union re₁✝ re₂✝⊢ ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remUnionR α:Types:List αre:RegExp αre':RegExp αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:Star re = re₂✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Union re₁✝ re₂✝⊢ ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remStar0 α:Types:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝⊢ ∃ ss, [] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remStarApp α:Types:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reh₂_ih✝:Star re = Star re✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Star re✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re <;> mEmpty α:Types:List αre:RegExp αre':RegExp αheq:Star re = EmptyStr⊢ ∃ ss, [] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remChar α:Types:List αre:RegExp αre':RegExp αc✝:αheq:Star re = Char c✝⊢ ∃ ss, [c✝] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remApp α:Types:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:Star re = re₁✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reh₂_ih✝:Star re = re₂✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = App re₁✝ re₂✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remUnionL α:Types:List αre:RegExp αre':RegExp αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:Star re = re₁✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Union re₁✝ re₂✝⊢ ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remUnionR α:Types:List αre:RegExp αre':RegExp αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:Star re = re₂✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Union re₁✝ re₂✝⊢ ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remStar0 α:Types:List αre:RegExp αre':RegExp αre✝:RegExp αheq:Star re = Star re✝⊢ ∃ ss, [] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ remStarApp α:Types:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reh₂_ih✝:Star re = Star re✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Star re✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re try trivial mStarApp α:Types:List αre:RegExp αre':RegExp αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:Star re = re✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reh₂_ih✝:Star re = Star re✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Star re✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
case mStar0 ih => α:Types:List αre:RegExp αre':RegExp αih:RegExp αheq:Star re = Star re✝⊢ ∃ ss, [] = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re exists [] α:Types:List αre:RegExp αre':RegExp αih:RegExp αheq:Star re = Star re✝⊢ [] = List.foldr (fun x1 x2 => x1 ++ x2) [] [] ∧ ∀ (s' : List α), s' ∈ [] → s' =~ re; simp All goals completed! 🐙
case mStarApp s₁ s₂ re h₁ h₂ ih₁ ih₂ => α:Types:List αre✝:RegExp αre':RegExp αs₁:List αs₂:List αre:RegExp αh₁:s₁✝ =~ re✝h₂:s₂✝ =~ Star re✝ih₁:Star re = re✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:Star re = Star re✝⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
injections heq α:Types:List αre✝:RegExp αre':RegExp αs₁:List αs₂:List αre:RegExp αh₁:s₁✝ =~ re✝h₂:s₂✝ =~ Star re✝ih₁:Star re = re✝ → ∃ ss, s₁✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re✝ → ∃ ss, s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reheq:re✝ = re⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re; subst heq α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
obtain ⟨ss, hfold, hall⟩ := ih₂ rfl α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ ∃ ss, s₁✝ ++ s₂✝ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ re
exists (s₁ :: ss) α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ s₁ ++ s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] (s₁ :: ss) ∧ ∀ (s' : List α), s' ∈ s₁ :: ss → s' =~ re
simp only [List.foldr_cons, List.mem_cons, forall_eq_or_imp] α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ s₁ ++ s₂ = s₁ ++ List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ s₁ =~ re ∧ ∀ (a : List α), a ∈ ss → a =~ re; rw [← hfold α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ s₁ ++ s₂ = s₁ ++ s₂ ∧ s₁ =~ re ∧ ∀ (a : List α), a ∈ ss → a =~ re] α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ s₁ ++ s₂ = s₁ ++ s₂ ∧ s₁ =~ re ∧ ∀ (a : List α), a ∈ ss → a =~ re
repeat
constructor right.right α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ ∀ (s' : List α), s' ∈ ss → s' =~ re
trivial right.right α:Types:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ re⊢ ∀ (s' : List α), s' ∈ ss → s' =~ re
intro s h right.right α:Types✝:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ res:List αh:s ∈ ss⊢ s =~ re; apply hall right.right α:Types✝:List αre:RegExp αre':RegExp αs₁:List αs₂:List αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:Star re = re → ∃ ss, s₁ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ reih₂:Star re = Star re → ∃ ss, s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] ss ∧ ∀ (s' : List α), s' ∈ ss → s' =~ ress:List (List α)hfold:s₂ = List.foldr (fun x1 x2 => x1 ++ x2) [] sshall:∀ (s' : List α), s' ∈ ss → s' =~ res:List αh:s ∈ ss⊢ s ∈ ss; trivial All goals completed! 🐙
10.5.4. The "Weak" Pumping Lemma
One of the first really interesting theorems in the theory of
regular expressions is the so-called pumping lemma, which
states, informally, that any sufficiently long string s matching
a regular expression re can be "pumped" by repeating some middle
section of s an arbitrary number of times to produce a new
string also matching re. For the sake of simplicity, this
exercise considers a slightly weaker theorem than is usually
stated in courses on automata theory — hence the name
weak_pumping. The stronger one can be found below.
To get started, we need to define "sufficiently long." Since we
are working in a constructive logic, we actually need to be able
to calculate, for each regular expression re, a minimum length
for strings s to guarantee "pumpability."
def pumpingConstant {α : Type} (re : RegExp α) : Nat :=
match re with
| EmptySet => 1
| EmptyStr => 1
| Char _ => 2
| App re₁ re₂ => re₁.pumpingConstant + re₂.pumpingConstant
| Union re₁ re₂ => re₁.pumpingConstant + re₂.pumpingConstant
| Star r => r.pumpingConstant
You may find these lemmas about the pumping constant useful when proving the pumping lemma below.
theorem pumping_constant_ge_1 {α : Type} (re : RegExp α) :
re.pumpingConstant ≥ 1 := by α:Typere:RegExp α⊢ re.pumpingConstant ≥ 1
induction re with (simp_all [pumpingConstant] All goals completed! 🐙; try lia All goals completed! 🐙)
theorem pumping_constant_0_false {α : Type} (re : RegExp α)
(h : re.pumpingConstant = 0) : False := by α:Typere:RegExp αh:re.pumpingConstant = 0⊢ False
have := pumping_constant_ge_1 re α:Typere:RegExp αh:re.pumpingConstant = 0this:re.pumpingConstant ≥ 1⊢ False; lia All goals completed! 🐙
Next, it is useful to define an auxiliary function that repeats a
string (appends it to itself) some number of times. Note
how we define simp lemmas for napp to go with its definition.
def napp {α : Type} (n : Nat) (l : List α) : List α :=
match n with
| 0 => []
| n' + 1 => l ++ napp n' l
@[simp]
theorem napp_zero {α : Type} (l : List α) : napp 0 l = [] := by α:Typel:List α⊢ napp 0 l = [] rfl All goals completed! 🐙
@[simp]
theorem napp_succ {α : Type} (n : Nat) (l : List α) :
napp (n + 1) l = l ++ napp n l := by α:Typen:Natl:List α⊢ napp (n + 1) l = l ++ napp n l rfl All goals completed! 🐙
These auxiliary lemmas might also be useful in your proof of the pumping lemma.
@[simp]
theorem napp_plus {α : Type} (n m : Nat) (l : List α) :
napp (n + m) l = napp n l ++ napp m l := by α:Typen:Natm:Natl:List α⊢ napp (n + m) l = napp n l ++ napp m l
induction n with simp_all [Nat.succ_add] All goals completed! 🐙
theorem napp_star {α : Type} (m : Nat) (s₁ s₂ : List α) (re : RegExp α)
(hs₁ : s₁ =~ re) (hs₂ : s₂ =~ Star re) :
napp m s₁ ++ s₂ =~ Star re := by α:Typem:Nats₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star re⊢ napp m s₁ ++ s₂ =~ Star re
induction m with
| zero => zero α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star re⊢ napp 0 s₁ ++ s₂ =~ Star re simp only [napp_zero, List.nil_append] zero α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star re⊢ s₂ =~ Star re; trivial All goals completed! 🐙
| succ m ih => succ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ napp (m + 1) s₁ ++ s₂ =~ Star re
simp only [napp_succ] succ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ s₁ ++ napp m s₁ ++ s₂ =~ Star re
rw [List.append_assoc succ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ s₁ ++ (napp m s₁ ++ s₂) =~ Star re] succ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ s₁ ++ (napp m s₁ ++ s₂) =~ Star re
apply mStarApp succ.h₁ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ s₁ =~ resucc.h₂ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ napp m s₁ ++ s₂ =~ Star re <;> succ.h₁ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ s₁ =~ resucc.h₂ α:Types₁:List αs₂:List αre:RegExp αhs₁:s₁ =~ rehs₂:s₂ =~ Star rem:Natih:napp m s₁ ++ s₂ =~ Star re⊢ napp m s₁ ++ s₂ =~ Star re trivial All goals completed! 🐙
The (weak) pumping lemma itself says that, if s =~ re and if the
length of s is at least the pumping constant of re, then s
can be split into three substrings s₁ ++ s₂ ++ s₃ in such a way
that s₂ can be repeated any number of times and the result, when
combined with s₁ and s₃, will still match re.
Since s₂ is also guaranteed not to be the empty string, this gives us
a (constructive!) way to generate strings matching re that are
as long as we like.
This proof is quite long, so to make it more tractable we've broken it up into a number of subproofs, which we then assemble to prove the main lemma.
Your job is to complete the proofs of the helper lemmas; the main lemma relies on these.
theorem weak_pumping_char {α : Type} (x : α)
(h : (Char x).pumpingConstant ≤ [x].length) :
∃ s₁ s₂ s₃ : List α,
[x] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₂ ++ s₃ =~ Char x) := by α:Typex:αh:(Char x).pumpingConstant ≤ [x].length⊢ ∃ s₁ s₂ s₃, [x] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Char x
solution!
simp [pumpingConstant] at h All goals completed! 🐙
theorem weak_pumping_app {α : Type} (s₁ s₂ : List α) (re₁ re₂ : RegExp α)
(h₁ : s₁ =~ re₁)
(h₂ : s₂ =~ re₂)
(ih₁ : re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄ : List α,
s₁ = s₂ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₂ ++ napp m s₃ ++ s₄ =~ re₁))
(ih₂ : re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄ : List α,
s₂ = s₁ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₃ ++ s₄ =~ re₂))
(hLen : (App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).length) :
∃ s₀ s₃ s₄ : List α,
s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂) := by α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
obtain h | h :
re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length := by α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).length⊢ re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length
solution!
rw [List.length_append α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ s₁.length + s₂.length⊢ re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length] at hLen α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ s₁.length + s₂.length⊢ re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length
simp [pumpingConstant] at hLen α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁.length + s₂.length⊢ re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length
lia inl α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂inr α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
case inl => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
solution!
specialize ih₁ h α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
let ⟨s₁₂, s₁₃, s₁₄, h₁, h₂, h₃⟩ := ih₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
rw [h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ ∃ s₀ s₃ s₄, s₁₂ ++ s₁₃ ++ s₁₄ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂] α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ ∃ s₀ s₃ s₄, s₁₂ ++ s₁₃ ++ s₁₄ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
exists s₁₂, s₁₃, s₁₄ ++ s₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ s₁₃ ++ s₁₄ ++ s₂ = s₁₂ ++ s₁₃ ++ (s₁₄ ++ s₂) ∧
s₁₃ ≠ [] ∧ ∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
constructor left α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ s₁₃ ++ s₁₄ ++ s₂ = s₁₂ ++ s₁₃ ++ (s₁₄ ++ s₂)right α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₃ ≠ [] ∧ ∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
case left => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ s₁₃ ++ s₁₄ ++ s₂ = s₁₂ ++ s₁₃ ++ (s₁₄ ++ s₂) simp All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₃ ≠ [] ∧ ∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
constructor left α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₃ ≠ []right α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ ∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
case left => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₃ ≠ [] assumption All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ ∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
intro m α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []h₃:∀ (m : Nat), s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁m:Nat⊢ s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂; specialize h₃ m α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ napp m s₁₃ ++ (s₁₄ ++ s₂) =~ App re₁ re₂
rw [← List.append_assoc α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ napp m s₁₃ ++ s₁₄ ++ s₂ =~ App re₁ re₂] α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ napp m s₁₃ ++ s₁₄ ++ s₂ =~ App re₁ re₂
constructor h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁h₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₂ =~ re₂ <;> h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁h₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₂:List αs₁₃:List αs₁₄:List αh₁:s₁ = s₁₂ ++ s₁₃ ++ s₁₄h₂:s₁₃ ≠ []m:Nath₃:s₁₂ ++ napp m s₁₃ ++ s₁₄ =~ re₁⊢ s₂ =~ re₂ trivial All goals completed! 🐙
case inr => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
solution!
specialize ih₂ h α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
let ⟨s₂₁, s₂₂, s₂₃, h₁, h₂, h₃⟩ := ih₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
rw [h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₀ s₃ s₄, s₁ ++ (s₂₁ ++ s₂₂ ++ s₂₃) = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂] α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₀ s₃ s₄, s₁ ++ (s₂₁ ++ s₂₂ ++ s₂₃) = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ App re₁ re₂
exists (s₁ ++ s₂₁), s₂₂, s₂₃ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₁ ++ (s₂₁ ++ s₂₂ ++ s₂₃) = s₁ ++ s₂₁ ++ s₂₂ ++ s₂₃ ∧
s₂₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
constructor left α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₁ ++ (s₂₁ ++ s₂₂ ++ s₂₃) = s₁ ++ s₂₁ ++ s₂₂ ++ s₂₃right α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
case left => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₁ ++ (s₂₁ ++ s₂₂ ++ s₂₃) = s₁ ++ s₂₁ ++ s₂₂ ++ s₂₃ simp All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
constructor left α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ []right α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∀ (m : Nat), s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
case left => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] assumption All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∀ (m : Nat), s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
intro m α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂m:Nat⊢ s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂; specialize h₃ m α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []m:Nath₃:s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₁ ++ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ App re₁ re₂
simp only [List.append_assoc] at * α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₂:s₂₂ ≠ []m:Natih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄, s₁ = s₂ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ (napp m s₃ ++ s₄) =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ (napp m s₃ ++ s₄) =~ re₂h₁:s₂ = s₂₁ ++ (s₂₂ ++ s₂₃)h₃:s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂⊢ s₁ ++ (s₂₁ ++ (napp m s₂₂ ++ s₂₃)) =~ App re₁ re₂
constructor h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₂:s₂₂ ≠ []m:Natih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄, s₁ = s₂ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ (napp m s₃ ++ s₄) =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ (napp m s₃ ++ s₄) =~ re₂h₁:s₂ = s₂₁ ++ (s₂₂ ++ s₂₃)h₃:s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂⊢ s₁ =~ re₁h₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₂:s₂₂ ≠ []m:Natih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄, s₁ = s₂ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ (napp m s₃ ++ s₄) =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ (napp m s₃ ++ s₄) =~ re₂h₁:s₂ = s₂₁ ++ (s₂₂ ++ s₂₃)h₃:s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂⊢ s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂ <;> h₁ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₂:s₂₂ ≠ []m:Natih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄, s₁ = s₂ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ (napp m s₃ ++ s₄) =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ (napp m s₃ ++ s₄) =~ re₂h₁:s₂ = s₂₁ ++ (s₂₂ ++ s₂₃)h₃:s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂⊢ s₁ =~ re₁h₂ α:Types₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁h₂✝:s₂ =~ re₂hLen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₂:s₂₂ ≠ []m:Natih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄, s₁ = s₂ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ (napp m s₃ ++ s₄) =~ re₁ih₂:∃ s₁ s₃ s₄, s₂ = s₁ ++ (s₃ ++ s₄) ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ (napp m s₃ ++ s₄) =~ re₂h₁:s₂ = s₂₁ ++ (s₂₂ ++ s₂₃)h₃:s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂⊢ s₂₁ ++ (napp m s₂₂ ++ s₂₃) =~ re₂ assumption All goals completed! 🐙
theorem weak_pumping_union_l {α : Type} (s₁ : List α) (re₁ re₂ : RegExp α)
(h₁ : s₁ =~ re₁)
(ih : re₁.pumpingConstant ≤ s₁.length →
∃ s₂ s₃ s₄ : List α,
s₁ = s₂ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₂ ++ napp m s₃ ++ s₄ =~ re₁))
(hLen : (Union re₁ re₂).pumpingConstant ≤ s₁.length) :
∃ s₀ s₂ s₃ : List α,
s₁ = s₀ ++ s₂ ++ s₃ ∧
s₂ ≠ [ ] ∧
(∀ m : Nat, s₀ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂) := by α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₂ s₃, s₁ = s₀ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
have h : re₁.pumpingConstant ≤ s₁.length := by
solution!
simp only [pumpingConstant] at hLen α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁hLen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁.length⊢ re₁.pumpingConstant ≤ s₁.length; lia α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₂ s₃, s₁ = s₀ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
solution!
specialize ih h α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₂ s₃, s₁ = s₀ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
obtain ⟨s₁₁, s₁₂, s₁₃, h₁, h₂, h₃⟩ := ih α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ ∃ s₀ s₂ s₃, s₁ = s₀ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
exists s₁₁ α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ ∃ s₂ s₃, s₁ = s₁₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₂ ++ s₃ =~ Union re₁ re₂; exists s₁₂ α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ ∃ s₃, s₁ = s₁₁ ++ s₁₂ ++ s₃ ∧ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₃ =~ Union re₁ re₂; exists s₁₃ α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁ = s₁₁ ++ s₁₂ ++ s₁₃ ∧ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
constructor left α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁ = s₁₁ ++ s₁₂ ++ s₁₃right α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
case left => α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁ = s₁₁ ++ s₁₂ ++ s₁₃ assumption All goals completed! 🐙
case right => α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
constructor left α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₂ ≠ []right α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
case left => α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₂ ≠ [] assumption All goals completed! 🐙
case right => α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
intro m α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁m:Nat⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂; specialize h₃ m α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ Union re₁ re₂
apply mUnionL α:Types₁:List αre₁:RegExp αre₂:RegExp αh₁✝:s₁ =~ re₁hLen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re₁
assumption All goals completed! 🐙
theorem weak_pumping_union_r {α : Type} (s₂ : List α) (re₁ re₂ : RegExp α)
(h₂ : s₂ =~ re₂)
(ih : re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄ : List α,
s₂ = s₁ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₃ ++ s₄ =~ re₂))
(hLen : (Union re₁ re₂).pumpingConstant ≤ s₂.length) :
∃ s₁ s₀ s₃ : List α,
s₂ = s₁ ++ s₀ ++ s₃ ∧
s₀ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂) := by α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.length⊢ ∃ s₁ s₀ s₃, s₂ = s₁ ++ s₀ ++ s₃ ∧ s₀ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂
-- symmetric to the previous
have h : re₂.pumpingConstant ≤ s₂.length := by
solution!
simp only [pumpingConstant] at hLen α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₂.length⊢ re₂.pumpingConstant ≤ s₂.length; lia α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length → ∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁ s₀ s₃, s₂ = s₁ ++ s₀ ++ s₃ ∧ s₀ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂
solution!
specialize ih h α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁ s₀ s₃, s₂ = s₁ ++ s₀ ++ s₃ ∧ s₀ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂
let ⟨s₂₁, s₂₂, s₂₃, h₁, h₂, h₃⟩ := ih α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₁ s₀ s₃, s₂ = s₁ ++ s₀ ++ s₃ ∧ s₀ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂
exists s₂₁ α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₀ s₃, s₂ = s₂₁ ++ s₀ ++ s₃ ∧ s₀ ≠ [] ∧ ∀ (m : Nat), s₂₁ ++ napp m s₀ ++ s₃ =~ Union re₁ re₂; exists s₂₂ α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∃ s₃, s₂ = s₂₁ ++ s₂₂ ++ s₃ ∧ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₃ =~ Union re₁ re₂; exists s₂₃ α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂ = s₂₁ ++ s₂₂ ++ s₂₃ ∧ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
constructor left α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂ = s₂₁ ++ s₂₂ ++ s₂₃right α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
case left => α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂ = s₂₁ ++ s₂₂ ++ s₂₃ assumption All goals completed! 🐙
case right => α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] ∧ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
constructor left α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ []right α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
case left => α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₂ ≠ [] assumption All goals completed! 🐙
case right => α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ ∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
intro m α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []h₃:∀ (m : Nat), s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂m:Nat⊢ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂; specialize h₃ m α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []m:Nath₃:s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ Union re₁ re₂
apply mUnionR α:Types₂:List αre₁:RegExp αre₂:RegExp αh₂✝:s₂ =~ re₂ih:∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ re₂hLen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₂₁:List αs₂₂:List αs₂₃:List αh₁:s₂ = s₂₁ ++ s₂₂ ++ s₂₃h₂:s₂₂ ≠ []m:Nath₃:s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂⊢ s₂₁ ++ napp m s₂₂ ++ s₂₃ =~ re₂
assumption All goals completed! 🐙
theorem weak_pumping_star_zero {α : Type} (re : RegExp α)
(h : (Star re).pumpingConstant ≤ @List.length α []) :
∃ s₁ s₂ s₃ : List α,
[ ] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₂ ++ s₃ =~ Star re) := by α:Typere:RegExp αh:(Star re).pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re
solution!
simp only [List.length_nil] at h α:Typere:RegExp αh:(Star re).pumpingConstant ≤ 0⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re
inversion h with
| refl h h₁ =>
have h₂ := pumping_constant_ge_1 re refl α:Typere:RegExp αh✝:(Star re).pumpingConstant ≤ 0h:h✝ ≍ ⋯h₁:0 = re.pumpingConstanth₂:re.pumpingConstant ≥ 1⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re
rw [← h₁ refl α:Typere:RegExp αh✝:(Star re).pumpingConstant ≤ 0h:h✝ ≍ ⋯h₁:0 = re.pumpingConstanth₂:0 ≥ 1⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re] at h₂ refl α:Typere:RegExp αh✝:(Star re).pumpingConstant ≤ 0h:h✝ ≍ ⋯h₁:0 = re.pumpingConstanth₂:0 ≥ 1⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re; inversion h₂ All goals completed! 🐙
theorem weak_pumping_star_app {α : Type} (s₁ s₂ : List α) (re : RegExp α)
(h₁ : s₁ =~ re)
(h₂ : s₂ =~ Star re)
(ih₁ : re.pumpingConstant ≤ List.length s₁ →
∃ s₂ s₃ s₄ : List α,
s₁ = s₂ ++ s₃ ++ s₄
∧ s₃ ≠ [ ] ∧
(∀ m : Nat, s₂ ++ napp m s₃ ++ s₄ =~ re))
(ih₂ : (Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄ : List α,
s₂ = s₁ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₁ ++ napp m s₃ ++ s₄ =~ Star re))
(hLen : (Star re).pumpingConstant ≤ (s₁ ++ s₂).length) :
∃ s₀ s₃ s₄ : List α,
s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧
s₃ ≠ [ ] ∧
(∀ m : Nat, s₀ ++ napp m s₃ ++ s₄ =~ .Star re) := by α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ (s₁ ++ s₂).length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
rw [List.length_append α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re] at * α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
obtain hs₁len0 | ⟨s₁len, hs₁re₁⟩ | hs₁re₁ :
(s₁.length = 0
∨ (s₁.length ≠ 0 ∧ s₁.length < re.pumpingConstant)
∨ re.pumpingConstant ≤ s₁.length) := by α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.length⊢ s₁.length = 0 ∨ s₁.length ≠ 0 ∧ s₁.length < re.pumpingConstant ∨ re.pumpingConstant ≤ s₁.length
cases s₁ with
| nil => nil α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ [].length + s₂.length⊢ [].length = 0 ∨ [].length ≠ 0 ∧ [].length < re.pumpingConstant ∨ re.pumpingConstant ≤ [].length solution!(left nil α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ [].length + s₂.length⊢ [].length = 0; rfl All goals completed! 🐙)
| cons h s₁' => cons α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.length⊢ (h :: s₁').length = 0 ∨
(h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length
solution!
right cons α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.length⊢ (h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length
have hcases : (List.length (h :: s₁') < re.pumpingConstant
∨ re.pumpingConstant ≤ List.length (h :: s₁')) := by α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.length⊢ s₁.length = 0 ∨ s₁.length ≠ 0 ∧ s₁.length < re.pumpingConstant ∨ re.pumpingConstant ≤ s₁.length
lia cons α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthhcases:(h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length⊢ (h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length
cases hcases with
| inl => cons.inl α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length
left cons.inl α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant; constructor cons.inl.left α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length ≠ 0cons.inl.right α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length < re.pumpingConstant
case left => α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length ≠ 0 intro contra α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstantcontra:(h :: s₁').length = 0⊢ False; contradiction All goals completed! 🐙
case right => α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:(h :: s₁').length < re.pumpingConstant⊢ (h :: s₁').length < re.pumpingConstant assumption All goals completed! 🐙
| inr => cons.inr α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:re.pumpingConstant ≤ (h :: s₁').length⊢ (h :: s₁').length ≠ 0 ∧ (h :: s₁').length < re.pumpingConstant ∨ re.pumpingConstant ≤ (h :: s₁').length right cons.inr α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh:αs₁':List αh₁:h :: s₁' =~ reih₁:re.pumpingConstant ≤ (h :: s₁').length →
∃ s₂ s₃ s₄, h :: s₁' = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (h :: s₁').length + s₂.lengthh✝:re.pumpingConstant ≤ (h :: s₁').length⊢ re.pumpingConstant ≤ (h :: s₁').length; assumption inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁len0:s₁.length = 0⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star reinr.inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star reinr.inr α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
. inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁len0:s₁.length = 0⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re solution!
have hs₁nil : s₁ = [] := by
cases s₁ nil α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ [].length + s₂.lengthhs₁len0:[].length = 0⊢ [] = []cons α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehead✝:αtail✝:List αh₁:head✝ :: tail✝ =~ reih₁:re.pumpingConstant ≤ (head✝ :: tail✝).length →
∃ s₂ s₃ s₄, head✝ :: tail✝ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (head✝ :: tail✝).length + s₂.lengthhs₁len0:(head✝ :: tail✝).length = 0⊢ head✝ :: tail✝ = []; rfl cons α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehead✝:αtail✝:List αh₁:head✝ :: tail✝ =~ reih₁:re.pumpingConstant ≤ (head✝ :: tail✝).length →
∃ s₂ s₃ s₄, head✝ :: tail✝ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ (head✝ :: tail✝).length + s₂.lengthhs₁len0:(head✝ :: tail✝).length = 0⊢ head✝ :: tail✝ = []; contradiction inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁len0:s₁.length = 0hs₁nil:s₁ = []⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
subst hs₁nil inl α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ [].length + s₂.lengthhs₁len0:[].length = 0⊢ ∃ s₀ s₃ s₄, [] ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
simp only [List.length_nil, Nat.zero_add] at hLen inl α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehs₁len0:[].length = 0hLen:(Star re).pumpingConstant ≤ s₂.length⊢ ∃ s₀ s₃ s₄, [] ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
apply ih₂ inl α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehs₁len0:[].length = 0hLen:(Star re).pumpingConstant ≤ s₂.length⊢ (Star re).pumpingConstant ≤ s₂.length; apply hLen All goals completed! 🐙
. inr.inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re solution!
exists [] inr.inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∃ s₃ s₄, s₁ ++ s₂ = [] ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), [] ++ napp m s₃ ++ s₄ =~ Star re; exists s₁ inr.inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∃ s₄, s₁ ++ s₂ = [] ++ s₁ ++ s₄ ∧ s₁ ≠ [] ∧ ∀ (m : Nat), [] ++ napp m s₁ ++ s₄ =~ Star re; exists s₂ inr.inl α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ++ s₂ = [] ++ s₁ ++ s₂ ∧ s₁ ≠ [] ∧ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re
constructor inr.inl.left α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ++ s₂ = [] ++ s₁ ++ s₂inr.inl.right α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ≠ [] ∧ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re; rfl inr.inl.right α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ≠ [] ∧ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re
constructor inr.inl.right.left α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ≠ []inr.inl.right.right α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re
case left => α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ s₁ ≠ [] intro contra α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstantcontra:s₁ = []⊢ False; subst contra α:Types₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length → ∃ s₂ s₃ s₄, [] = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ rehLen:(Star re).pumpingConstant ≤ [].length + s₂.lengths₁len:[].length ≠ 0hs₁re₁:[].length < re.pumpingConstant⊢ False; contradiction All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstant⊢ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re
intro m α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstantm:Nat⊢ [] ++ napp m s₁ ++ s₂ =~ Star re; apply napp_star hs₁ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstantm:Nat⊢ s₁ =~ rehs₂ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstantm:Nat⊢ s₂ =~ Star re
assumption hs₂ α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengths₁len:s₁.length ≠ 0hs₁re₁:s₁.length < re.pumpingConstantm:Nat⊢ s₂ =~ Star re
assumption All goals completed! 🐙
. inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length → ∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re solution!
specialize ih₁ hs₁re₁ inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.length⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
let ⟨s₁₁, s₁₂, s₁₃, h₁, h₂, h₃⟩ := ih₁ inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ ∃ s₀ s₃ s₄, s₁ ++ s₂ = s₀ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₀ ++ napp m s₃ ++ s₄ =~ Star re
exists s₁₁ inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ ∃ s₃ s₄, s₁ ++ s₂ = s₁₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₃ ++ s₄ =~ Star re; exists s₁₂ inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ ∃ s₄, s₁ ++ s₂ = s₁₁ ++ s₁₂ ++ s₄ ∧ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₄ =~ Star re; exists (s₁₃ ++ s₂) inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁ ++ s₂ = s₁₁ ++ s₁₂ ++ (s₁₃ ++ s₂) ∧ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
rw [h₁ inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ s₁₂ ++ s₁₃ ++ s₂ = s₁₁ ++ s₁₂ ++ (s₁₃ ++ s₂) ∧
s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re] inr.inr α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ s₁₂ ++ s₁₃ ++ s₂ = s₁₁ ++ s₁₂ ++ (s₁₃ ++ s₂) ∧
s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
constructor inr.inr.left α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ s₁₂ ++ s₁₃ ++ s₂ = s₁₁ ++ s₁₂ ++ (s₁₃ ++ s₂)inr.inr.right α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
case left => α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ s₁₂ ++ s₁₃ ++ s₂ = s₁₁ ++ s₁₂ ++ (s₁₃ ++ s₂) simp All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₂ ≠ [] ∧ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
constructor left α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₂ ≠ []right α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
case left => α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₂ ≠ [] assumption All goals completed! 🐙
case right => α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ ∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
intro m α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []h₃:∀ (m : Nat), s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ rem:Nat⊢ s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re; specialize h₃ m α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ napp m s₁₂ ++ (s₁₃ ++ s₂) =~ Star re
rw [← List.append_assoc α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ ++ s₂ =~ Star re] α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ ++ s₂ =~ Star re
apply mStarApp h₁ α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ reh₂ α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₂ =~ Star re <;> h₁ α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ reh₂ α:Types₁:List αs₂:List αre:RegExp αh₁✝:s₁ =~ reh₂✝:s₂ =~ Star reih₁:∃ s₂ s₃ s₄, s₁ = s₂ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₂ ++ napp m s₃ ++ s₄ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₃ s₄, s₂ = s₁ ++ s₃ ++ s₄ ∧ s₃ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₃ ++ s₄ =~ Star rehLen:(Star re).pumpingConstant ≤ s₁.length + s₂.lengthhs₁re₁:re.pumpingConstant ≤ s₁.lengths₁₁:List αs₁₂:List αs₁₃:List αh₁:s₁ = s₁₁ ++ s₁₂ ++ s₁₃h₂:s₁₂ ≠ []m:Nath₃:s₁₁ ++ napp m s₁₂ ++ s₁₃ =~ re⊢ s₂ =~ Star re assumption All goals completed! 🐙
theorem weak_pumping {α : Type} {re : RegExp α} {s : List α}
(hmatch : s =~ re) (hlen : re.pumpingConstant ≤ s.length) :
∃ s₁ s₂ s₃ : List α,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧
∀ m, s₁ ++ napp m s₂ ++ s₃ =~ re := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃, s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
solution!
induction hmatch mEmpty α:Typere:RegExp αs:List αhlen:EmptyStr.pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ EmptyStrmChar α:Typere:RegExp αs:List αc✝:αhlen:(Char c✝).pumpingConstant ≤ [c✝].length⊢ ∃ s₁ s₂ s₃, [c✝] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Char c✝mApp α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ ∃ s₁ s₂ s₃, s₁✝ ++ s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ App re₁✝ re₂✝mUnionL α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ ∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Union re₁✝ re₂✝mUnionR α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ ∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Union re₁✝ re₂✝mStar0 α:Typere:RegExp αs:List αre✝:RegExp αhlen:(Star re✝).pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝mStarApp α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ ∃ s₁ s₂ s₃, s₁✝ ++ s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝
case mEmpty => α:Typere:RegExp αs:List αhlen:EmptyStr.pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ EmptyStr simp [pumpingConstant] at hlen All goals completed! 🐙
case mChar => α:Typere:RegExp αs:List αc✝:αhlen:(Char c✝).pumpingConstant ≤ [c✝].length⊢ ∃ s₁ s₂ s₃, [c✝] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Char c✝ apply weak_pumping_char α:Typere:RegExp αs:List αc✝:αhlen:(Char c✝).pumpingConstant ≤ [c✝].length⊢ (Char c✝).pumpingConstant ≤ [c✝].length; assumption All goals completed! 🐙
case mApp => α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ ∃ s₁ s₂ s₃, s₁✝ ++ s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ App re₁✝ re₂✝ apply weak_pumping_app h₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₁✝ =~ re₁✝h₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₂✝ =~ re₂✝ih₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝ih₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hLen α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length <;> h₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₁✝ =~ re₁✝h₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₂✝ =~ re₂✝ih₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝ih₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hLen α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₂✝:s₂✝ =~ re₂✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (App re₁✝ re₂✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length assumption All goals completed! 🐙
case mUnionL => α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ ∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Union re₁✝ re₂✝ apply weak_pumping_union_l h₁ α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ s₁✝ =~ re₁✝ih α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hLen α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ (Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length <;> h₁ α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ s₁✝ =~ re₁✝ih α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hLen α:Typere:RegExp αs:List αs₁✝:List αre₁✝:RegExp αre₂✝:RegExp αh₁✝:s₁✝ =~ re₁✝h₁_ih✝:re₁✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₁✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length⊢ (Union re₁✝ re₂✝).pumpingConstant ≤ s₁✝.length assumption All goals completed! 🐙
case mUnionR => α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ ∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Union re₁✝ re₂✝ apply weak_pumping_union_r h₂ α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ s₂✝ =~ re₂✝ih α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hLen α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ (Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length <;> h₂ α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ s₂✝ =~ re₂✝ih α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hLen α:Typere:RegExp αs:List αs₂✝:List αre₁✝:RegExp αre₂✝:RegExp αh₂✝:s₂✝ =~ re₂✝h₂_ih✝:re₂✝.pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re₂✝hlen:(Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length⊢ (Union re₁✝ re₂✝).pumpingConstant ≤ s₂✝.length assumption All goals completed! 🐙
case mStar0 => α:Typere:RegExp αs:List αre✝:RegExp αhlen:(Star re✝).pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃, [] = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝ apply weak_pumping_star_zero α:Typere:RegExp αs:List αre✝:RegExp αhlen:(Star re✝).pumpingConstant ≤ [].length⊢ (Star re✝).pumpingConstant ≤ [].length <;> α:Typere:RegExp αs:List αre✝:RegExp αhlen:(Star re✝).pumpingConstant ≤ [].length⊢ (Star re✝).pumpingConstant ≤ [].length assumption All goals completed! 🐙
case mStarApp => α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ ∃ s₁ s₂ s₃, s₁✝ ++ s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝ apply weak_pumping_star_app h₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₁✝ =~ re✝h₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₂✝ =~ Star re✝ih₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝ih₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hLen α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length <;> h₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₁✝ =~ re✝h₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ s₂✝ =~ Star re✝ih₁ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝ih₂ α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hLen α:Typere:RegExp αs:List αs₁✝:List αs₂✝:List αre✝:RegExp αh₁✝:s₁✝ =~ re✝h₂✝:s₂✝ =~ Star re✝h₁_ih✝:re✝.pumpingConstant ≤ s₁✝.length →
∃ s₁ s₂ s₃, s₁✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re✝h₂_ih✝:(Star re✝).pumpingConstant ≤ s₂✝.length →
∃ s₁ s₂ s₃, s₂✝ = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re✝hlen:(Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length⊢ (Star re✝).pumpingConstant ≤ (s₁✝ ++ s₂✝).length assumption All goals completed! 🐙
10.5.5. The "Strong" Pumping Lemma
Now here is the usual version of the pumping lemma. In addition to
requiring that s₂ ≠ [], it also strengthens the result to
include the claim that s₁.length + s₂.length ≤ re.pumpingConstant.
theorem pumping {α : Type} {re : RegExp α} {s : List α}
(hmatch : s =~ re) (hlen : re.pumpingConstant ≤ s.length) :
∃ s₁ s₂ s₃ : List α,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧
s₁.length + s₂.length ≤ re.pumpingConstant ∧
∀ m, s₁ ++ napp m s₂ ++ s₃ =~ re := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
solution!
induction hmatch with
| mEmpty mEmpty α:Typere:RegExp αs:List αhlen:EmptyStr.pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ EmptyStr.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ EmptyStr
| mChar _ mChar α:Typere:RegExp αs:List αc✝:αhlen:(Char c✝).pumpingConstant ≤ [c✝].length⊢ ∃ s₁ s₂ s₃,
[c✝] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ (Char c✝).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Char c✝ => mChar α:Typere:RegExp αs:List αc✝:αhlen:(Char c✝).pumpingConstant ≤ [c✝].length⊢ ∃ s₁ s₂ s₃,
[c✝] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ (Char c✝).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Char c✝mEmpty α:Typere:RegExp αs:List αhlen:EmptyStr.pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ EmptyStr.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ EmptyStr
simp [pumpingConstant] at hlen All goals completed! 🐙
| @mApp s₁ s₂ re₁ re₂ h₁ h₂ ih₁ ih₂ => mApp α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
have h : re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
simp only [append_length, pumpingConstant] at hlen α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁.length + s₂.length⊢ re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length
lia mApp α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length ∨ re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
obtain h | h := h mApp.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂mApp.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
· mApp.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂ obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih₁ h mApp.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂; clear ih₁ ih₂ mApp.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
subst_vars mApp.inl α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∃ s₁ s₂_1 s₃,
s₁' ++ s₂' ++ s₃' ++ s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
exists s₁', s₂', (s₃' ++ s₂) mApp.inl α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂) ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
simp only [List.append_assoc] mApp.inl α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ True ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂
constructor mApp.inl.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ TruemApp.inl.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂; exact True.intro mApp.inl.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂
constructor mApp.inl.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mApp.inl.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂; assumption mApp.inl.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂
constructor mApp.inl.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstantmApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂
· mApp.inl.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant simp_all [pumpingConstant] mApp.inl.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:¬s₂' = []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ (napp m s₂' ++ s₃') =~ re₁h₁:s₁' ++ (s₂' ++ s₃') =~ re₁hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + (s₃'.length + s₂.length))h:re₁.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)⊢ s₁'.length + s₂'.length ≤ re₁.pumpingConstant + re₂.pumpingConstant; lia All goals completed! 🐙
· mApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂ intro m mApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ (napp m s₂' ++ (s₃' ++ s₂)) =~ App re₁ re₂
rw [←List.append_assoc, mApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂ ←List.append_assoc mApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ App re₁ re₂] mApp.inl.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ App re₁ re₂
apply mApp mApp.inl.right.right.right.h₁ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁mApp.inl.right.right.right.h₂ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ re₂ <;> mApp.inl.right.right.right.h₁ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁mApp.inl.right.right.right.h₂ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂s₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ re₂ simp_all All goals completed! 🐙
· mApp.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂ have h' : s₁.length < re₁.pumpingConstant ∨ re₁.pumpingConstant <= s₁.length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re lia mApp.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':s₁.length < re₁.pumpingConstant ∨ re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
obtain h' | h' := h' mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':s₁.length < re₁.pumpingConstant⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂mApp.inr.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
· mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':s₁.length < re₁.pumpingConstant⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂ obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih₂ h mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αheq:s₂ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂; clear ih₁ ih₂ mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αheq:s₂ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
subst_vars mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∃ s₁_1 s₂ s₃,
s₁ ++ (s₁' ++ s₂' ++ s₃') = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧
s₁_1.length + s₂.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ App re₁ re₂
exists (s₁ ++ s₁'), s₂', s₃' mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁ ++ (s₁' ++ s₂' ++ s₃') = s₁ ++ s₁' ++ s₂' ++ s₃' ∧
s₂' ≠ [] ∧
(s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ s₁' ++ napp m s₂' ++ s₃' =~ App re₁ re₂
simp only [List.append_assoc] mApp.inr.inl α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ True ∧
s₂' ≠ [] ∧
(s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂
constructor mApp.inr.inl.left α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ TruemApp.inr.inl.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
(s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂; exact True.intro mApp.inr.inl.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
(s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂
constructor mApp.inr.inl.right.left α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mApp.inr.inl.right.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ (s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂; assumption mApp.inr.inl.right.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ (s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂
constructor mApp.inr.inl.right.right.left α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ (s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstantmApp.inr.inl.right.right.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂
· mApp.inr.inl.right.right.left α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ (s₁ ++ s₁').length + s₂'.length ≤ (App re₁ re₂).pumpingConstant simp_all [pumpingConstant] mApp.inr.inl.right.right.left α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:¬s₂' = []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ (napp m s₂' ++ s₃') =~ re₂h₂:s₁' ++ (s₂' ++ s₃') =~ re₂hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁.length + (s₁'.length + (s₂'.length + s₃'.length))h:re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)⊢ s₁.length + s₁'.length + s₂'.length ≤ re₁.pumpingConstant + re₂.pumpingConstant; lia All goals completed! 🐙
· mApp.inr.inl.right.right.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂ intro m mApp.inr.inl.right.right.right α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁ ++ (s₁' ++ (napp m s₂' ++ s₃')) =~ App re₁ re₂
apply mApp mApp.inr.inl.right.right.right.h₁ α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁ =~ re₁mApp.inr.inl.right.right.right.h₂ α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ (napp m s₂' ++ s₃') =~ re₂ <;> mApp.inr.inl.right.right.right.h₁ α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁ =~ re₁mApp.inr.inl.right.right.right.h₂ α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h':s₁.length < re₁.pumpingConstants₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ (s₁' ++ s₂' ++ s₃')).lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ (napp m s₂' ++ s₃') =~ re₂ simp_all All goals completed! 🐙
· mApp.inr.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂ obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih₁ h' mApp.inr.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂ih₁:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁ih₂:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂; clear ih₁ ih₂ mApp.inr.inr α:Typere:RegExp αs:List αs₁:List αs₂:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁h₂:s₂ =~ re₂hlen:(App re₁ re₂).pumpingConstant ≤ (s₁ ++ s₂).lengthh:re₂.pumpingConstant ≤ s₂.lengthh':re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
subst_vars mApp.inr.inr α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∃ s₁ s₂_1 s₃,
s₁' ++ s₂' ++ s₃' ++ s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ App re₁ re₂
exists s₁', s₂', (s₃' ++ s₂) mApp.inr.inr α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂) ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧
∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
constructor mApp.inr.inr.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂)mApp.inr.inr.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂; simp only [List.append_assoc] mApp.inr.inr.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
constructor mApp.inr.inr.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mApp.inr.inr.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂; assumption mApp.inr.inr.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
constructor mApp.inr.inr.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstantmApp.inr.inr.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
· mApp.inr.inr.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (App re₁ re₂).pumpingConstant simp_all [pumpingConstant] mApp.inr.inr.right.right.left α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:¬s₂' = []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ (napp m s₂' ++ s₃') =~ re₁h₁:s₁' ++ (s₂' ++ s₃') =~ re₁hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + (s₃'.length + s₂.length))h':re₁.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)⊢ s₁'.length + s₂'.length ≤ re₁.pumpingConstant + re₂.pumpingConstant; lia All goals completed! 🐙
· mApp.inr.inr.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂ intro m mApp.inr.inr.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ App re₁ re₂
rw [←List.append_assoc mApp.inr.inr.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ App re₁ re₂] mApp.inr.inr.right.right.right α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ App re₁ re₂
apply mApp mApp.inr.inr.right.right.right.h₁ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁mApp.inr.inr.right.right.right.h₂ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ re₂ <;> mApp.inr.inr.right.right.right.h₁ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁mApp.inr.inr.right.right.right.h₂ α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂h:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(App re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃' ++ s₂).lengthh':re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ re₂ simp_all All goals completed! 🐙
| @mUnionL s₁ re₁ re₂ h₁ ih => mUnionL α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧
s₁_1.length + s₂.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
have h : re₁.pumpingConstant ≤ s₁.length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
simp only [pumpingConstant] at hlen α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁.length⊢ re₁.pumpingConstant ≤ s₁.length
lia mUnionL α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧
s₁_1.length + s₂.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih h mUnionL α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁ih:re₁.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re₁.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧
s₁_1.length + s₂.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ Union re₁ re₂; clear ih mUnionL α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ ∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧
s₁_1.length + s₂.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ Union re₁ re₂
exists s₁', s₂', s₃' mUnionL α:Typere:RegExp αs:List αs₁:List αre₁:RegExp αre₂:RegExp αh₁:s₁ =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ s₁.lengthh:re₁.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁⊢ s₁ = s₁' ++ s₂' ++ s₃' ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; subst_vars mUnionL α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' = s₁' ++ s₂' ++ s₃' ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionL.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' = s₁' ++ s₂' ++ s₃'mUnionL.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; simp only [List.append_assoc] mUnionL.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionL.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mUnionL.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; assumption mUnionL.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionL.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstantmUnionL.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
· mUnionL.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant simp_all [pumpingConstant] mUnionL.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:¬s₂' = []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ (napp m s₂' ++ s₃') =~ re₁h₁:s₁' ++ (s₂' ++ s₃') =~ re₁hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)h:re₁.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)⊢ s₁'.length + s₂'.length ≤ re₁.pumpingConstant + re₂.pumpingConstant; lia All goals completed! 🐙
· mUnionL.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂ intro m mUnionL.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
apply mUnionL mUnionL.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁ <;> mUnionL.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₁.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₁h₁:s₁' ++ s₂' ++ s₃' =~ re₁hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₁.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₁ simp_all All goals completed! 🐙
| @mUnionR s₂ re₁ re₂ h₂ ih => mUnionR α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ s₂.length⊢ ∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Union re₁ re₂
have h : re₂.pumpingConstant ≤ s₂.length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
simp only [pumpingConstant] at hlen α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₂.length⊢ re₂.pumpingConstant ≤ s₂.length
lia mUnionR α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.length⊢ ∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Union re₁ re₂
obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih h mUnionR α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂ih:re₂.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re₂.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αheq:s₂ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂⊢ ∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Union re₁ re₂; clear ih mUnionR α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αheq:s₂ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂⊢ ∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁.length + s₂_1.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Union re₁ re₂
exists s₁', s₂', s₃' mUnionR α:Typere:RegExp αs:List αs₂:List αre₁:RegExp αre₂:RegExp αh₂:s₂ =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ s₂.lengthh:re₂.pumpingConstant ≤ s₂.lengths₁':List αs₂':List αs₃':List αheq:s₂ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂⊢ s₂ = s₁' ++ s₂' ++ s₃' ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; subst_vars mUnionR α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' = s₁' ++ s₂' ++ s₃' ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionR.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' = s₁' ++ s₂' ++ s₃'mUnionR.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; simp only [List.append_assoc] mUnionR.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionR.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mUnionR.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂; assumption mUnionR.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
constructor mUnionR.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstantmUnionR.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
· mUnionR.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Union re₁ re₂).pumpingConstant simp_all [pumpingConstant] mUnionR.right.right.left α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:¬s₂' = []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ (napp m s₂' ++ s₃') =~ re₂h₂:s₁' ++ (s₂' ++ s₃') =~ re₂hlen:re₁.pumpingConstant + re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)h:re₂.pumpingConstant ≤ s₁'.length + (s₂'.length + s₃'.length)⊢ s₁'.length + s₂'.length ≤ re₁.pumpingConstant + re₂.pumpingConstant; lia All goals completed! 🐙
· mUnionR.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂ intro m mUnionR.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ Union re₁ re₂
apply mUnionR mUnionR.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₂ <;> mUnionR.right.right.right α:Typere:RegExp αs:List αre₁:RegExp αre₂:RegExp αs₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re₂.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re₂h₂:s₁' ++ s₂' ++ s₃' =~ re₂hlen:(Union re₁ re₂).pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthh:re₂.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ re₂ simp_all All goals completed! 🐙
| mStar0 re => mStar0 α:Typere✝:RegExp αs:List αre:RegExp αhlen:(Star re).pumpingConstant ≤ [].length⊢ ∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re
simp only [pumpingConstant, List.length_nil, Nat.le_zero_eq] at hlen mStar0 α:Typere✝:RegExp αs:List αre:RegExp αhlen:re.pumpingConstant = 0⊢ ∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re
apply pumping_constant_0_false at hlen mStar0 α:Typere✝:RegExp αs:List αre:RegExp αhlen:False⊢ ∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ Star re; contradiction All goals completed! 🐙
| @mStarApp s₁ s₂ re h₁ h₂ ih₁ ih₂ => mStarApp α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:(Star re).pumpingConstant ≤ (s₁ ++ s₂).length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
simp only [List.length_append, pumpingConstant] at hlen mStarApp α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
have h' : s₁.length = 0
∨ (s₁.length ≠ 0 ∧ s₁.length < re.pumpingConstant)
∨ re.pumpingConstant ≤ s₁.length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
induction s₁ with
| nil => nil α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length →
∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ [].length + s₂.length⊢ [].length = 0 ∨ [].length ≠ 0 ∧ [].length < re.pumpingConstant ∨ re.pumpingConstant ≤ [].length simp All goals completed! 🐙
| cons hd tl ih => cons α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehd:αtl:List αih:tl =~ re →
(re.pumpingConstant ≤ tl.length →
∃ s₁ s₂ s₃,
tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re) →
re.pumpingConstant ≤ tl.length + s₂.length →
tl.length = 0 ∨ tl.length ≠ 0 ∧ tl.length < re.pumpingConstant ∨ re.pumpingConstant ≤ tl.lengthh₁:hd :: tl =~ reih₁:re.pumpingConstant ≤ (hd :: tl).length →
∃ s₁ s₂ s₃,
hd :: tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ (hd :: tl).length + s₂.length⊢ (hd :: tl).length = 0 ∨
(hd :: tl).length ≠ 0 ∧ (hd :: tl).length < re.pumpingConstant ∨ re.pumpingConstant ≤ (hd :: tl).length
right cons α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehd:αtl:List αih:tl =~ re →
(re.pumpingConstant ≤ tl.length →
∃ s₁ s₂ s₃,
tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re) →
re.pumpingConstant ≤ tl.length + s₂.length →
tl.length = 0 ∨ tl.length ≠ 0 ∧ tl.length < re.pumpingConstant ∨ re.pumpingConstant ≤ tl.lengthh₁:hd :: tl =~ reih₁:re.pumpingConstant ≤ (hd :: tl).length →
∃ s₁ s₂ s₃,
hd :: tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ (hd :: tl).length + s₂.length⊢ (hd :: tl).length ≠ 0 ∧ (hd :: tl).length < re.pumpingConstant ∨ re.pumpingConstant ≤ (hd :: tl).length
have hcases : (hd :: tl).length < re.pumpingConstant
∨ re.pumpingConstant ≤ (hd :: tl).length := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re lia cons α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehd:αtl:List αih:tl =~ re →
(re.pumpingConstant ≤ tl.length →
∃ s₁ s₂ s₃,
tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re) →
re.pumpingConstant ≤ tl.length + s₂.length →
tl.length = 0 ∨ tl.length ≠ 0 ∧ tl.length < re.pumpingConstant ∨ re.pumpingConstant ≤ tl.lengthh₁:hd :: tl =~ reih₁:re.pumpingConstant ≤ (hd :: tl).length →
∃ s₁ s₂ s₃,
hd :: tl = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ (hd :: tl).length + s₂.lengthhcases:(hd :: tl).length < re.pumpingConstant ∨ re.pumpingConstant ≤ (hd :: tl).length⊢ (hd :: tl).length ≠ 0 ∧ (hd :: tl).length < re.pumpingConstant ∨ re.pumpingConstant ≤ (hd :: tl).length
simp_all mStarApp α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':s₁.length = 0 ∨ s₁.length ≠ 0 ∧ s₁.length < re.pumpingConstant ∨ re.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
obtain h' | ⟨hneq', hlen'⟩ | h' := h' mStarApp.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':s₁.length = 0⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star remStarApp.inr.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star remStarApp.inr.inr α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':re.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
· mStarApp.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':s₁.length = 0⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re have heq : s₁ = [] := by α:Typere:RegExp αs:List αhmatch:s =~ rehlen:re.pumpingConstant ≤ s.length⊢ ∃ s₁ s₂ s₃,
s = s₁ ++ s₂ ++ s₃ ∧ s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ re
cases s₁ nil α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length →
∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ [].length + s₂.lengthh':[].length = 0⊢ [] = []cons α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehead✝:αtail✝:List αh₁:head✝ :: tail✝ =~ reih₁:re.pumpingConstant ≤ (head✝ :: tail✝).length →
∃ s₁ s₂ s₃,
head✝ :: tail✝ = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ (head✝ :: tail✝).length + s₂.lengthh':(head✝ :: tail✝).length = 0⊢ head✝ :: tail✝ = [] <;> nil α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star reh₁:[] =~ reih₁:re.pumpingConstant ≤ [].length →
∃ s₁ s₂ s₃,
[] = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ [].length + s₂.lengthh':[].length = 0⊢ [] = []cons α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehead✝:αtail✝:List αh₁:head✝ :: tail✝ =~ reih₁:re.pumpingConstant ≤ (head✝ :: tail✝).length →
∃ s₁ s₂ s₃,
head✝ :: tail✝ = s₁ ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂ ++ s₃ =~ rehlen:re.pumpingConstant ≤ (head✝ :: tail✝).length + s₂.lengthh':(head✝ :: tail✝).length = 0⊢ head✝ :: tail✝ = [] trivial mStarApp.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':s₁.length = 0heq:s₁ = []⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
simp_all [pumpingConstant] All goals completed! 🐙
· mStarApp.inr.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re exists [], s₁, s₂ mStarApp.inr.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ s₁ ++ s₂ = [] ++ s₁ ++ s₂ ∧
s₁ ≠ [] ∧ [].length + s₁.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), [] ++ napp m s₁ ++ s₂ =~ Star re
simp only [pumpingConstant, List.nil_append] at * mStarApp.inr.inl α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ True ∧ s₁ ≠ [] ∧ [].length + s₁.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re
constructor mStarApp.inr.inl.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ TruemStarApp.inr.inl.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ s₁ ≠ [] ∧ [].length + s₁.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re; exact True.intro mStarApp.inr.inl.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ s₁ ≠ [] ∧ [].length + s₁.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re
constructor mStarApp.inr.inl.right.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ s₁ ≠ []mStarApp.inr.inl.right.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ [].length + s₁.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re
· mStarApp.inr.inl.right.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ s₁ ≠ [] simp_all All goals completed! 🐙
· mStarApp.inr.inl.right.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ [].length + s₁.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re constructor mStarApp.inr.inl.right.right.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ [].length + s₁.length ≤ re.pumpingConstantmStarApp.inr.inl.right.right.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re
· mStarApp.inr.inl.right.right.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ [].length + s₁.length ≤ re.pumpingConstant simp_all mStarApp.inr.inl.right.right.left α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ (s₂ ++ s₃) ∧
¬s₂ = [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ (napp m s₂ ++ s₃) =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ (s₂_1 ++ s₃) ∧
¬s₂_1 = [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ (napp m s₂_1 ++ s₃) =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':¬s₁ = []hlen':s₁.length < re.pumpingConstant⊢ s₁.length ≤ re.pumpingConstant; lia All goals completed! 🐙
· mStarApp.inr.inl.right.right.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstant⊢ ∀ (m : Nat), napp m s₁ ++ s₂ =~ Star re intro m mStarApp.inr.inl.right.right.right α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstantm:Nat⊢ napp m s₁ ++ s₂ =~ Star re
apply napp_star mStarApp.inr.inl.right.right.right.hs₁ α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstantm:Nat⊢ s₁ =~ remStarApp.inr.inl.right.right.right.hs₂ α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstantm:Nat⊢ s₂ =~ Star re <;> mStarApp.inr.inl.right.right.right.hs₁ α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstantm:Nat⊢ s₁ =~ remStarApp.inr.inl.right.right.right.hs₂ α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:re.pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthhneq':s₁.length ≠ 0hlen':s₁.length < re.pumpingConstantm:Nat⊢ s₂ =~ Star re trivial All goals completed! 🐙
· mStarApp.inr.inr α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':re.pumpingConstant ≤ s₁.length⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re obtain ⟨s₁', s₂', s₃', heq, hneq, hlen', hmatch'⟩ := ih₁ h' mStarApp.inr.inr α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₁:re.pumpingConstant ≤ s₁.length →
∃ s₁_1 s₂ s₃,
s₁ = s₁_1 ++ s₂ ++ s₃ ∧
s₂ ≠ [] ∧ s₁_1.length + s₂.length ≤ re.pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂ ++ s₃ =~ reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':re.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re; clear ih₁ mStarApp.inr.inr α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':re.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re⊢ ∃ s₁_1 s₂_1 s₃,
s₁ ++ s₂ = s₁_1 ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧
s₁_1.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁_1 ++ napp m s₂_1 ++ s₃ =~ Star re
exists s₁', s₂', s₃' ++ s₂ mStarApp.inr.inr α:Typere✝:RegExp αs:List αs₁:List αs₂:List αre:RegExp αh₁:s₁ =~ reh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star rehlen:re.pumpingConstant ≤ s₁.length + s₂.lengthh':re.pumpingConstant ≤ s₁.lengths₁':List αs₂':List αs₃':List αheq:s₁ = s₁' ++ s₂' ++ s₃'hneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ re⊢ s₁ ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂) ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
subst_vars mStarApp.inr.inr α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂) ∧
s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
constructor mStarApp.inr.inr.left α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁' ++ s₂' ++ s₃' ++ s₂ = s₁' ++ s₂' ++ (s₃' ++ s₂)mStarApp.inr.inr.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re; simp only [List.append_assoc] mStarApp.inr.inr.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ [] ∧
s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
constructor mStarApp.inr.inr.right.left α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₂' ≠ []mStarApp.inr.inr.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re; assumption mStarApp.inr.inr.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
constructor mStarApp.inr.inr.right.right.left α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Star re).pumpingConstantmStarApp.inr.inr.right.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
· mStarApp.inr.inr.right.right.left α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ s₁'.length + s₂'.length ≤ (Star re).pumpingConstant simp_all [pumpingConstant] All goals completed! 🐙
· mStarApp.inr.inr.right.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length⊢ ∀ (m : Nat), s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re intro m mStarApp.inr.inr.right.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ (s₃' ++ s₂) =~ Star re
rw [←List.append_assoc mStarApp.inr.inr.right.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ Star re] mStarApp.inr.inr.right.right.right α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' ++ s₂ =~ Star re
apply mStarApp mStarApp.inr.inr.right.right.right.h₁ α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ remStarApp.inr.inr.right.right.right.h₂ α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ Star re <;> mStarApp.inr.inr.right.right.right.h₁ α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₁' ++ napp m s₂' ++ s₃' =~ remStarApp.inr.inr.right.right.right.h₂ α:Typere✝:RegExp αs:List αs₂:List αre:RegExp αh₂:s₂ =~ Star reih₂:(Star re).pumpingConstant ≤ s₂.length →
∃ s₁ s₂_1 s₃,
s₂ = s₁ ++ s₂_1 ++ s₃ ∧
s₂_1 ≠ [] ∧ s₁.length + s₂_1.length ≤ (Star re).pumpingConstant ∧ ∀ (m : Nat), s₁ ++ napp m s₂_1 ++ s₃ =~ Star res₁':List αs₂':List αs₃':List αhneq:s₂' ≠ []hlen':s₁'.length + s₂'.length ≤ re.pumpingConstanthmatch':∀ (m : Nat), s₁' ++ napp m s₂' ++ s₃' =~ reh₁:s₁' ++ s₂' ++ s₃' =~ rehlen:re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').length + s₂.lengthh':re.pumpingConstant ≤ (s₁' ++ s₂' ++ s₃').lengthm:Nat⊢ s₂ =~ Star re simp_all All goals completed! 🐙
end RegExp
10.5.6. Palindromes Revisited
Here is one possible definition of the palindrome inductive predicate, Pal,
which we saw in the last chapter.
namespace PalConv
inductive Pal {α : Type} : List α → Prop where
| nil : Pal []
| singleton {x : α} : Pal [x]
| cons_snoc {x : α} {l : List α} (h : Pal l) : Pal (x :: (l ++ [x]))
We previously proved that ∀ l, Pal l → l = l.reverse.
The converse is also true, but significantly more difficult to prove, due
to the lack of evidence. Using the definition of Pal above, prove that
∀ l, l = l.reverse → Pal l
A similar proof using strong induction!
(Nat.strongRec is available in Batteries.)
theorem reverse_pal {α : Type} {l : List α}
(h : l = l.reverse) : Pal l := by
induction hlen : l.length using Nat.strongRec generalizing l with
| ind n ih =>
cases l with
| nil => constructor
| cons x xs =>
cases hxs : xs.reverse with
| nil =>
rw [← List.reverse_nil] at hxs
simp only [List.reverse_nil, List.reverse_eq_nil_iff] at hxs
subst xs
constructor
| cons y ys =>
rw [List.reverse_cons, hxs] at h
injection h with hxy htail
subst y
simp only [htail, List.append_eq, List.reverse_append, List.reverse_cons, List.reverse_nil,
List.nil_append, List.cons_append, List.cons.injEq, true_and] at hxs
rw [htail]
apply Pal.cons_snoc
apply ih ys.length _ hxs.symm rfl
rw [← hlen]
simp only [htail, List.append_eq, List.length_cons, List.length_append, List.length_nil,
Nat.zero_add]
lia
/- Proving the converse theorem is much harder, because a standard
induction over the list `l` doesn't work. The trick to the
following proof, due to Nathan Collins, is to induct over _half
the length_ of `l`. -/
theorem reverse_pal {α : Type} {n : Nat} {l : List α}
(hlen : l.length / 2 = n) (hrev : l = l.reverse) : Pal l := by α:Typen:Natl:List αhlen:l.length / 2 = nhrev:l = l.reverse⊢ Pal l
induction n generalizing l with
/- (length l) / 2 = 0 || l has length 0 or 1 -/
| zero => zero α:Typel:List αhlen:l.length / 2 = 0hrev:l = l.reverse⊢ Pal l
cases l with
| nil => zero.nil α:Typehlen:[].length / 2 = 0hrev:[] = [].reverse⊢ Pal [] constructor All goals completed! 🐙
| cons x xs => zero.cons α:Typex:αxs:List αhlen:(x :: xs).length / 2 = 0hrev:x :: xs = (x :: xs).reverse⊢ Pal (x :: xs)
cases xs with
| nil => zero.cons.nil α:Typex:αhlen:[x].length / 2 = 0hrev:[x] = [x].reverse⊢ Pal [x] constructor All goals completed! 🐙
| cons y ys => zero.cons.cons α:Typex:αy:αys:List αhlen:(x :: y :: ys).length / 2 = 0hrev:x :: y :: ys = (x :: y :: ys).reverse⊢ Pal (x :: y :: ys)
/- impossible : (x :: y :: ys) has length > 1 -/
simp only [List.length_cons, simp_lemmas_example.add_succ, Nat.add_zero,
Nat.div_eq_zero_iff, reduceCtorEq, false_or] at hlen zero.cons.cons α:Typex:αy:αys:List αhrev:x :: y :: ys = (x :: y :: ys).reversehlen:ys.length + 0 + 1 + 0 + 1 < 2⊢ Pal (x :: y :: ys)
lia All goals completed! 🐙
/- (length l) / 2 >= 1 || l has length at least 2 -/
| succ n ih => succ α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal ll:List αhlen:l.length / 2 = n + 1hrev:l = l.reverse⊢ Pal l
cases l with
| nil => succ.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lhlen:[].length / 2 = n + 1hrev:[] = [].reverse⊢ Pal [] rw [List.length_nil, succ.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lhlen:0 / 2 = n + 1hrev:[] = [].reverse⊢ Pal [] Nat.zero_div succ.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lhlen:0 = n + 1hrev:[] = [].reverse⊢ Pal []] at hlen succ.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lhlen:0 = n + 1hrev:[] = [].reverse⊢ Pal []; contradiction All goals completed! 🐙
| cons x xs => succ.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(x :: xs).length / 2 = n + 1hrev:x :: xs = (x :: xs).reverse⊢ Pal (x :: xs)
rw [List.length_cons succ.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = (x :: xs).reverse⊢ Pal (x :: xs)] at hlen succ.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = (x :: xs).reverse⊢ Pal (x :: xs)
rw [List.reverse_cons succ.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = xs.reverse ++ [x]⊢ Pal (x :: xs)] at hrev succ.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = xs.reverse ++ [x]⊢ Pal (x :: xs)
cases heq : xs.reverse with
| nil => succ.cons.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = xs.reverse ++ [x]heq:xs.reverse = []⊢ Pal (x :: xs)
simp only [List.reverse_eq_nil_iff] at heq succ.cons.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = xs.reverse ++ [x]heq:xs = []⊢ Pal (x :: xs)
subst xs succ.cons.nil α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αhlen:([].length + 1) / 2 = n + 1hrev:[x] = [].reverse ++ [x]⊢ Pal [x]
constructor All goals completed! 🐙
| cons y ys => succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1hrev:x :: xs = xs.reverse ++ [x]y:αys:List αheq:xs.reverse = y :: ys⊢ Pal (x :: xs)
rw [heq succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhrev:x :: xs = y :: ys ++ [x]heq:xs.reverse = y :: ys⊢ Pal (x :: xs)] at hrev succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhrev:x :: xs = y :: ys ++ [x]heq:xs.reverse = y :: ys⊢ Pal (x :: xs)
injection hrev with hxy heq' succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αheq:xs.reverse = y :: yshxy:x = yheq':xs = ys.append [x]⊢ Pal (x :: xs)
simp only [heq', List.append_eq, List.reverse_append, List.reverse_cons, List.reverse_nil,
List.nil_append, List.cons_append, List.cons.injEq] at heq succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ Pal (x :: xs)
rw [heq' succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ Pal (x :: ys.append [x])] succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ Pal (x :: ys.append [x])
constructor succ.cons.cons α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ Pal ys
apply ih succ.cons.cons.hlen α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ ys.length / 2 = nsucc.cons.cons.hrev α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ ys = ys.reverse
· succ.cons.cons.hlen α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ ys.length / 2 = n simp only [heq', List.append_eq, List.length_append, List.length_cons, List.length_nil,
simp_lemmas_example.add_succ, Nat.add_zero] at hlen succ.cons.cons.hlen α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αy:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = yshlen:(ys.length + 0 + 1 + 0 + 1) / 2 = n + 0 + 1⊢ ys.length / 2 = n
lia All goals completed! 🐙
· succ.cons.cons.hrev α:Typen:Natih:∀ {l : List α}, l.length / 2 = n → l = l.reverse → Pal lx:αxs:List αhlen:(xs.length + 1) / 2 = n + 1y:αys:List αhxy:x = yheq':xs = ys.append [x]heq:x = y ∧ ys.reverse = ys⊢ ys = ys.reverse exact heq.2.symm All goals completed! 🐙
theorem palindrome_converse {α : Type} {l : List α} (h : l = l.reverse) : Pal l := by α:Typel:List αh:l = l.reverse⊢ Pal l
exact reverse_pal rfl h All goals completed! 🐙
end PalConv