@@ -4,21 +4,21 @@ import Mathlib.Tactic.Tendsto.Meta.LeadingTerm
44
55set_option linter.style.longLine false
66
7- open Filter Asymptotics TendstoTactic Stream' Seq ElimDestruct
7+ open Filter Asymptotics TendstoTactic Stream'. Seq ElimDestruct
88
99open Lean Elab Meta Tactic Qq
1010
1111namespace TendstoTactic
1212
13- def basis_wo : MS. WellOrderedBasis [fun (x : ℝ) ↦ x] := by
14- simp [MS. WellOrderedBasis]
13+ def basis_wo : WellOrderedBasis [fun (x : ℝ) ↦ x] := by
14+ simp [WellOrderedBasis]
1515 exact fun ⦃U⦄ a ↦ a
1616
1717partial def createMS (body : Expr) : TacticM MS := do
1818 let basis : Q(List (ℝ → ℝ)) := q([fun (x : ℝ) ↦ x])
19- let basis_wo : Q(MS. WellOrderedBasis $basis) := q(basis_wo)
19+ let basis_wo : Q(WellOrderedBasis $basis) := q(basis_wo)
2020 let zero_aux : Q(0 < List.length $basis) := q(by decide)
21- match body.nat? with
21+ match body.nat? with -- TODO: other numerals
2222 | .some n =>
2323 return MS.const basis body basis_wo
2424 | none =>
@@ -54,89 +54,63 @@ partial def createMS (body : Expr) : TacticM MS := do
5454 return MS.div ms1 ms2 h_trimmed ⟨⟩
5555 | _ => throwError f!"Unsupported body in createMS: {body}"
5656
57+
5758def computeTendsto (f : Q(ℝ → ℝ)) : TacticM ((limit : Q(Filter ℝ)) × Q(Tendsto $f atTop $limit)) := do
5859 match f with
5960 | .lam _ _ b _ =>
6061 let ms ← createMS b
61- let ⟨ms_trimmed, h_trimmed⟩ ← trimMS ms
62+ let ⟨ms_trimmed, h_trimmed⟩ ← trimPartialMS ms
6263
6364 let hf_eq ← mkFreshExprMVarQ q($ms.F = $f)
6465 hf_eq.mvarId!.applyRfl
6566
66- let limit ← mkFreshExprMVarQ q(Filter ℝ)
67- let goal ← mkFreshExprMVarQ q(Tendsto $ms.F atTop $limit)
68- let targetType := Q(Tendsto $f atTop $limit)
69- let res : targetType := q(Eq.subst (motive := fun x ↦ Tendsto x atTop $limit) $hf_eq $goal)
70-
71- match ms_trimmed.basis with
72- | ~q(List.cons $basis_hd $basis_tl) =>
73- match ms_trimmed.val with
74- | ~q(PreMS.nil) =>
75- limit.mvarId!.assign q(nhds (0 : ℝ))
76- let h_tendsto := q(PreMS.nil_tendsto_zero $ms_trimmed.h_approx)
77- goal.mvarId!.assign h_tendsto
78- | ~q(PreMS.cons $hd $tl) =>
79- let ⟨leading, h_leading_eq⟩ ← getLeadingTermWithProof ms_trimmed.val
80- let h_tendsto ← match leading with
81- | ~q(⟨$coef, $exps⟩) =>
82- let coef_comp ← compareReal coef
83- match coef_comp with
84- | .zero h_coef =>
85- limit.mvarId!.assign q(nhds (0 : ℝ))
86- return q(PreMS.tendsto_zero_of_zero_coef $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_coef)
87- | .neg h_coef =>
88- match ← getFirstIs exps with
89- | .pos h_exps =>
90- return q(PreMS.tendsto_bot_of_FirstIsPos $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps $h_coef)
91- | .neg h_exps =>
92- return q(PreMS.tendsto_zero_of_FirstIsNeg $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps)
93- | .zero h_exps =>
94- return q(PreMS.tendsto_const_of_AllZero $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps)
95- | .pos h_coef =>
96- match ← getFirstIs exps with
97- | .pos h_exps =>
98- return q(PreMS.tendsto_top_of_FirstIsPos $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps $h_coef)
99- | .neg h_exps =>
100- return q(PreMS.tendsto_zero_of_FirstIsNeg $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps)
101- | .zero h_exps =>
102- return q(PreMS.tendsto_const_of_AllZero $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed $ms_trimmed.h_basis $h_leading_eq $h_exps)
103- | _ => throwError "Unexpected result of getLeadingTermWithProof"
104- goal.mvarId!.assign h_tendsto
105- | _ => throwError "Unexpected result of trimMS"
106- | _ => throwError "Unexpected basis in computeTendsto"
67+ let ~q(List.cons $basis_hd $basis_tl) := ms_trimmed.basis | throwError "Unexpected basis in computeTendsto"
68+ -- I don't how to avoid Expr here.
69+ let h_tendsto : Expr ← match ms_trimmed.val with
70+ | ~q(PreMS.nil) =>
71+ pure (q(PreMS.nil_tendsto_zero $ms_trimmed.h_approx) : Expr)
72+ | ~q(PreMS.cons $hd $tl) =>
73+ let ⟨leading, h_leading_eq⟩ ← getLeadingTermWithProof ms_trimmed.val
74+ let ~q(⟨$coef, $exps⟩) := leading | throwError "Unexpected leading in computeTendsto"
75+ let h_tendsto ← match ← getFirstIs exps with
76+ | .pos h_exps =>
77+ match ← compareReal coef with
78+ | .neg h_coef =>
79+ pure (q(PreMS.tendsto_bot_of_FirstIsPos $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed.get! $ms_trimmed.h_basis $h_leading_eq $h_exps $h_coef) : Expr)
80+ | .pos h_coef =>
81+ pure (q(PreMS.tendsto_top_of_FirstIsPos $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed.get! $ms_trimmed.h_basis $h_leading_eq $h_exps $h_coef) : Expr)
82+ | .zero _ => throwError "Unexpected zero coef with FirstIsPos"
83+ | .neg h_exps =>
84+ pure (q(PreMS.tendsto_zero_of_FirstIsNeg $ms_trimmed.h_wo $ms_trimmed.h_approx $h_leading_eq $h_exps) : Expr)
85+ | .zero h_exps =>
86+ pure (q(PreMS.tendsto_const_of_AllZero $ms_trimmed.h_wo $ms_trimmed.h_approx $h_trimmed.get! $ms_trimmed.h_basis $h_leading_eq $h_exps) : Expr)
87+ | _ => throwError "Unexpected result of trimMS"
10788
108- -- TODO: is this necessary?
109- let goal' ← instantiateMVarsQ goal
110- let ⟨0 , t, _⟩ ← inferTypeQ goal' | throwError "Unexpected goal's universe level"
111- match t with
112- | ~q(Tendsto (α := ℝ) (β := ℝ) $f atTop $limit_res) =>
113- limit.mvarId!.assign limit_res
114- | _ => pure ()
89+ let ⟨0 , t, h_tendsto⟩ ← inferTypeQ h_tendsto | throwError "Unexpected h_tendsto's universe level"
90+ let ~q(@Tendsto ℝ ℝ $g atTop $limit) := t | throwError "Unexpected h_tendsto's type"
91+ haveI ' : $g =Q $ms.F := ⟨⟩
11592
116- return ⟨← instantiateMVarsQ limit, ← instantiateMVars res⟩
93+ let res := q(Eq.subst (motive := fun x ↦ Tendsto x atTop $limit) $hf_eq $h_tendsto)
94+ return ⟨limit, res⟩
11795 | _ => throwError "Function should be lambda"
11896
11997elab "compute_asymptotics" : tactic =>
12098 Lean.Elab.Tactic.withMainContext do
12199 let target : Q(Prop ) ← getMainTarget
122- match target with
123- | ~q(@Filter.Tendsto ℝ ℝ $f atTop $targetLimit) =>
124- let ⟨1 , fType, f⟩ ← inferTypeQ f | throwError "Unexpected universe level of function in compute_asymptotics"
125- match fType with
126- | ~q(ℝ → ℝ) =>
127- let ⟨limit, h_tendsto⟩ ← computeTendsto f
128- let result : Q(Prop ) ← inferType h_tendsto
129- if !(← isDefEq target result) then
130- match targetLimit, limit with
131- | ~q(nhds $a), ~q(nhds $b) =>
132- let h_eq : Q($b = $a) ← mkFreshExprMVarQ q($b = $a)
133- (← getMainGoal).assign q(Eq.subst (motive := fun x ↦ Filter.Tendsto $f atTop (nhds (X := ℝ) x)) $h_eq $h_tendsto)
134- setGoals (← evalTacticAt (← `(tactic| try norm_num1)) h_eq.mvarId!)
135- | _ =>
136- throwError m! "I've proved that { ← ppExpr (← inferType h_tendsto)} . Is this what you expect?"
137- else
138- (← getMainGoal).assign h_tendsto
139- | _ => throwError "Only real functions are supported"
140- | _ => throwError "The goal must me in the form Tendsto (fun x ↦ ...) atTop ..."
100+ let ~q(@Filter.Tendsto ℝ ℝ $f atTop $targetLimit) := target | throwError "The goal must me in the form Tendsto (fun x ↦ ...) atTop ..."
101+ let ⟨1 , fType, f⟩ ← inferTypeQ f | throwError "Unexpected universe level of function in compute_asymptotics"
102+ let ~q(ℝ → ℝ) := fType | throwError "Only real functions are supported"
103+ let ⟨limit, h_tendsto⟩ ← computeTendsto f
104+ let result : Q(Prop ) ← inferType h_tendsto
105+ if !(← isDefEq target result) then
106+ match targetLimit, limit with
107+ | ~q(nhds $a), ~q(nhds $b) =>
108+ let h_eq : Q($b = $a) ← mkFreshExprMVarQ q($b = $a)
109+ (← getMainGoal).assign q(Eq.subst (motive := fun x ↦ Filter.Tendsto $f atTop (nhds (X := ℝ) x)) $h_eq $h_tendsto)
110+ setGoals (← evalTacticAt (← `(tactic| try norm_num1)) h_eq.mvarId!)
111+ | _ =>
112+ throwError m! "I've proved that { ← ppExpr (← inferType h_tendsto)} . Is this what you expect?"
113+ else
114+ (← getMainGoal).assign h_tendsto
141115
142116end TendstoTactic
0 commit comments