@@ -5,6 +5,7 @@ Authors: Chris Hughes, Abhimanyu Pallavi Sudhir, Jean Lo, Calle Sönne, Sébasti
55 Rémy Degenne, David Loeffler
66-/
77import Mathlib.Analysis.SpecialFunctions.Pow.Complex
8+ import Mathlib.Data.Nat.NthRoot.Defs
89import Qq
910
1011/-! # Power function on `ℝ`
@@ -1042,94 +1043,155 @@ namespace Mathlib.Meta.NormNum
10421043
10431044open Lean.Meta Qq
10441045
1046+ theorem IsNat.rpow_eq_pow {b : ℝ} {n : ℕ} (h : IsNat b n) (a : ℝ) : a ^ b = a ^ n := by
1047+ rw [h.1 , Real.rpow_natCast]
1048+
1049+ theorem IsInt.rpow_eq_inv_pow {b : ℝ} {n : ℕ} (h : IsInt b (.negOfNat n)) (a : ℝ) :
1050+ a ^ b = (a ^ n)⁻¹ := by
1051+ rw [h.1 , Real.rpow_intCast, Int.negOfNat_eq, zpow_neg, Int.ofNat_eq_coe, zpow_natCast]
1052+
1053+ @[deprecated IsNat.rpow_eq_pow (since := "2025-10-21")]
10451054theorem isNat_rpow_pos {a b : ℝ} {nb ne : ℕ}
10461055 (pb : IsNat b nb) (pe' : IsNat (a ^ nb) ne) :
10471056 IsNat (a ^ b) ne := by
10481057 rwa [pb.out, rpow_natCast]
10491058
1059+ @[deprecated IsInt.rpow_eq_inv_pow (since := "2025-10-21")]
10501060theorem isNat_rpow_neg {a b : ℝ} {nb ne : ℕ}
10511061 (pb : IsInt b (Int.negOfNat nb)) (pe' : IsNat (a ^ (Int.negOfNat nb)) ne) :
10521062 IsNat (a ^ b) ne := by
10531063 rwa [pb.out, Real.rpow_intCast]
10541064
1065+ @[deprecated IsNat.rpow_eq_pow (since := "2025-10-21")]
10551066theorem isInt_rpow_pos {a b : ℝ} {nb ne : ℕ}
10561067 (pb : IsNat b nb) (pe' : IsInt (a ^ nb) (Int.negOfNat ne)) :
10571068 IsInt (a ^ b) (Int.negOfNat ne) := by
10581069 rwa [pb.out, rpow_natCast]
10591070
1071+ @[deprecated IsInt.rpow_eq_inv_pow (since := "2025-10-21")]
10601072theorem isInt_rpow_neg {a b : ℝ} {nb ne : ℕ}
10611073 (pb : IsInt b (Int.negOfNat nb)) (pe' : IsInt (a ^ (Int.negOfNat nb)) (Int.negOfNat ne)) :
10621074 IsInt (a ^ b) (Int.negOfNat ne) := by
10631075 rwa [pb.out, Real.rpow_intCast]
10641076
1077+ @[deprecated IsNat.rpow_eq_pow (since := "2025-10-21")]
10651078theorem isNNRat_rpow_pos {a b : ℝ} {nb : ℕ}
10661079 {num den : ℕ}
10671080 (pb : IsNat b nb) (pe' : IsNNRat (a ^ nb) num den) :
10681081 IsNNRat (a ^ b) num den := by
10691082 rwa [pb.out, rpow_natCast]
10701083
1084+ @[deprecated IsNat.rpow_eq_pow (since := "2025-10-21")]
10711085theorem isRat_rpow_pos {a b : ℝ} {nb : ℕ}
10721086 {num : ℤ} {den : ℕ}
10731087 (pb : IsNat b nb) (pe' : IsRat (a ^ nb) num den) :
10741088 IsRat (a ^ b) num den := by
10751089 rwa [pb.out, rpow_natCast]
10761090
1091+ @[deprecated IsInt.rpow_eq_inv_pow (since := "2025-10-21")]
10771092theorem isNNRat_rpow_neg {a b : ℝ} {nb : ℕ}
10781093 {num den : ℕ}
10791094 (pb : IsInt b (Int.negOfNat nb)) (pe' : IsNNRat (a ^ (Int.negOfNat nb)) num den) :
10801095 IsNNRat (a ^ b) num den := by
10811096 rwa [pb.out, Real.rpow_intCast]
10821097
1098+ @[deprecated IsInt.rpow_eq_inv_pow (since := "2025-10-21")]
10831099theorem isRat_rpow_neg {a b : ℝ} {nb : ℕ}
10841100 {num : ℤ} {den : ℕ}
10851101 (pb : IsInt b (Int.negOfNat nb)) (pe' : IsRat (a ^ (Int.negOfNat nb)) num den) :
10861102 IsRat (a ^ b) num den := by
10871103 rwa [pb.out, Real.rpow_intCast]
10881104
1089- /-- Evaluates expressions of the form `a ^ b` when `a` and `b` are both reals. -/
1105+ /-- Given proofs
1106+ - that `a` is a natural number `m`
1107+ - that `b` is a nonnegative rational number `n / d`
1108+ - that `r ^ d = m ^ n` (written as `r ^ d = k`, `m ^ n = l`, `k = l`)
1109+ prove that `a ^ b = r`.
1110+ -/
1111+ theorem IsNat.rpow_isNNRat {a b : ℝ} {m n d r : ℕ} (ha : IsNat a m) (hb : IsNNRat b n d)
1112+ (k : ℕ) (hr : r ^ d = k) (l : ℕ) (hm : m ^ n = l) (hkl : k = l) : IsNat (a ^ b) r := by
1113+ rcases ha with ⟨rfl⟩
1114+ constructor
1115+ have : d ≠ 0 := mod_cast hb.den_nz
1116+ rw [hb.to_eq rfl rfl, div_eq_mul_inv, Real.rpow_natCast_mul, ← Nat.cast_pow, hm, ← hkl, ← hr,
1117+ Nat.cast_pow, Real.pow_rpow_inv_natCast] <;> positivity
1118+
1119+ theorem IsNNRat.rpow_isNNRat (a b : ℝ) (na da : ℕ) (ha : IsNNRat a na da)
1120+ (nr dr : ℕ) (hnum : IsNat ((na : ℝ) ^ b) nr) (hden : IsNat ((da : ℝ) ^ b) dr) :
1121+ IsNNRat (a ^ b) nr dr := by
1122+ suffices IsNNRat (nr / dr : ℝ) nr dr by
1123+ simpa [ha.to_eq, Real.div_rpow, hnum.1 , hden.1 ]
1124+ apply IsNNRat.of_raw
1125+ rw [← hden.1 ]
1126+ apply (Real.rpow_pos_of_pos _ _).ne'
1127+ exact lt_of_le_of_ne' da.cast_nonneg ha.den_nz
1128+
1129+ theorem rpow_isRat_eq_inv_rpow (a b : ℝ) (n d : ℕ) (hb : IsRat b (Int.negOfNat n) d) :
1130+ a ^ b = (a⁻¹) ^ (n / d : ℝ) := by
1131+ rw [← Real.rpow_neg_eq_inv_rpow, hb.neg_to_eq rfl rfl]
1132+
1133+ open Lean in
1134+ /-- Given proofs
1135+ - that `a` is a natural number `na`;
1136+ - that `b` is a nonnegative rational number `nb / db`;
1137+ returns a tuple of
1138+ - a natural number `r` (result);
1139+ - the same number, as an expression;
1140+ - a proof that `a ^ b = r`.
1141+
1142+ Fails if `na` is not a `db`th power of a natural number.
1143+ -/
1144+ def proveIsNatRPowIsNNRat
1145+ (a : Q(ℝ)) (na : Q(ℕ)) (pa : Q(IsNat $a $na))
1146+ (b : Q(ℝ)) (nb db : Q(ℕ)) (pb : Q(IsNNRat $b $nb $db)) :
1147+ MetaM (ℕ × Σ r : Q(ℕ), Q(IsNat ($a ^ $b) $r)) := do
1148+ let r := (Nat.nthRoot db.natLit! na.natLit!) ^ nb.natLit!
1149+ have er : Q(ℕ) := mkRawNatLit r
1150+ -- avoid evaluating powers in kernel
1151+ let .some ⟨c, pc⟩ ← liftM <| OptionT.run <| evalNatPow er db | failure
1152+ let .some ⟨d, pd⟩ ← liftM <| OptionT.run <| evalNatPow na nb | failure
1153+ guard (c.natLit! = d.natLit!)
1154+ have hcd : Q($c = $d) := (q(Eq.refl $c) : Expr)
1155+ return (r, ⟨er, q(IsNat.rpow_isNNRat $pa $pb $c $pc $d $pd $hcd)⟩)
1156+
1157+ /-- Evaluates expressions of the form `a ^ b` when `a` and `b` are both reals.
1158+ Works if `a`, `b`, and `a ^ b` are in fact rational numbers,
1159+ except for the case `a < 0`, `b` isn't integer.
1160+
1161+ TODO: simplify terms like `(-a : ℝ) ^ (b / 3 : ℝ)` and `(-a : ℝ) ^ (b / 2 : ℝ)` too,
1162+ possibly after first considering changing the junk value. -/
10901163@[norm_num (_ : ℝ) ^ (_ : ℝ)]
1091- def evalRPow : NormNumExt where eval {u α} e := do
1092- let .app (.app f (a : Q(ℝ))) (b : Q(ℝ)) ← Lean.Meta.whnfR e | failure
1093- guard <|← withNewMCtxDepth <| isDefEq f q(HPow.hPow (α := ℝ) (β := ℝ))
1094- haveI' : u =QL 0 := ⟨⟩
1095- haveI' : $α =Q ℝ := ⟨⟩
1096- haveI' h : $e =Q $a ^ $b := ⟨⟩
1097- h.check
1098- let (rb : Result b) ← derive (α := q(ℝ)) b
1099- match rb with
1100- | .isBool .. | .isNNRat .. | .isNegNNRat .. => failure
1101- | .isNat sβ nb pb =>
1102- match ← derive q($a ^ $nb) with
1103- | .isBool .. => failure
1104- | .isNat sα' ne' pe' =>
1105- assumeInstancesCommute
1106- haveI' : $sα' =Q AddGroupWithOne.toAddMonoidWithOne := ⟨⟩
1107- return .isNat sα' ne' q(isNat_rpow_pos $pb $pe')
1108- | .isNegNat sα' ne' pe' =>
1109- assumeInstancesCommute
1110- return .isNegNat sα' ne' q(isInt_rpow_pos $pb $pe')
1111- | .isNNRat sα' qe' nume' dene' pe' =>
1112- assumeInstancesCommute
1113- return .isNNRat sα' qe' nume' dene' q(isNNRat_rpow_pos $pb $pe')
1114- | .isNegNNRat sα' qe' nume' dene' pe' =>
1115- assumeInstancesCommute
1116- return .isNegNNRat sα' qe' nume' dene' q(isRat_rpow_pos $pb $pe')
1117- | .isNegNat sβ nb pb =>
1118- match ← derive q($a ^ (-($nb : ℤ))) with
1119- | .isBool .. => failure
1120- | .isNat sα' ne' pe' =>
1164+ def evalRPow : NormNumExt where eval {u αR} e := do
1165+ match u, αR, e with
1166+ | 0 , ~q(ℝ), ~q(($a : ℝ)^($b : ℝ)) =>
1167+ match ← derive b with
1168+ | .isNat sβ nb pb =>
11211169 assumeInstancesCommute
1122- return .isNat sα' ne' q(isNat_rpow_neg $pb $pe')
1123- | .isNegNat sα' ne' pe' =>
1124- let _ := q(Real.instRing)
1170+ return .eqTrans q(IsNat.rpow_eq_pow $pb _) (← derive q($a ^ $nb))
1171+ | .isNegNat sβ nb pb =>
11251172 assumeInstancesCommute
1126- return .isNegNat sα' ne' q(isInt_rpow_neg $pb $pe' )
1127- | .isNNRat sα' qe' nume' dene' pe' =>
1173+ return .eqTrans q(IsInt.rpow_eq_inv_pow $pb _) (← derive q(($a ^ $nb)⁻¹) )
1174+ | .isNNRat _ qb nb db pb => do
11281175 assumeInstancesCommute
1129- return .isNNRat sα' qe' nume' dene' q(isNNRat_rpow_neg $pb $pe')
1130- | .isNegNNRat sα' qe' nume' dene' pe' =>
1176+ match ← derive a with
1177+ | .isNat sa na pa => do
1178+ let ⟨_, r, pr⟩ ← proveIsNatRPowIsNNRat a na pa b nb db pb
1179+ return .isNat sa r pr
1180+ | .isNNRat _ qα na da pa => do
1181+ assumeInstancesCommute
1182+ let ⟨rnum, ernum, pnum⟩ ←
1183+ proveIsNatRPowIsNNRat q(Nat.rawCast $na) na q(IsNat.of_raw _ _) b nb db pb
1184+ let ⟨rden, erden, pden⟩ ←
1185+ proveIsNatRPowIsNNRat q(Nat.rawCast $da) da q(IsNat.of_raw _ _) b nb db pb
1186+ return .isNNRat q(inferInstance) (rnum / rden) ernum erden
1187+ q(IsNNRat.rpow_isNNRat $a $b $na $da $pa $ernum $erden $pnum $pden)
1188+ | _ => failure
1189+ | .isNegNNRat _ qb nb db pb => do
1190+ let r ← derive q(($a⁻¹) ^ ($nb / $db : ℝ))
11311191 assumeInstancesCommute
1132- return .isNegNNRat sα' qe' nume' dene' q(isRat_rpow_neg $pb $pe')
1192+ return .eqTrans q(rpow_isRat_eq_inv_rpow $a $b $nb $db $pb) r
1193+ | _ => failure
1194+ | _ => failure
11331195
11341196end Mathlib.Meta.NormNum
11351197
0 commit comments