/-
Copyright (c) 2019 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl, Yury Kudryashov

! This file was ported from Lean 3 source module order.filter.archimedean
! leanprover-community/mathlib commit 4d392a6c9c4539cbeca399b3ee0afea398fbd2eb
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.Order.Archimedean
import Mathbin.Order.Filter.AtTopBot

/-!
# `at_top` filter and archimedean (semi)rings/fields

> THIS FILE IS SYNCHRONIZED WITH MATHLIB4.
> Any changes to this file require a corresponding PR to mathlib4.

In this file we prove that for a linear ordered archimedean semiring `R` and a function `f : α → ℕ`,
the function `coe ∘ f : α → R` tends to `at_top` along a filter `l` if and only if so does `f`.
We also prove that `coe : ℕ → R` tends to `at_top` along `at_top`, as well as version of these
two results for `ℤ` (and a ring `R`) and `ℚ` (and a field `R`).
-/

variable {α R : Type _}

open Filter Set

#print Nat.comap_cast_atTop /-
@[simp]
theorem Nat.comap_cast_atTop [StrictOrderedSemiring R] [Archimedean R] :
    comap (coe : ℕ → R) atTop = atTop :=
  comap_embedding_atTop (fun _ _ => Nat.cast_le) exists_nat_ge
#align nat.comap_coe_at_top Nat.comap_cast_atTop
-/

#print tendsto_nat_cast_atTop_iff /-
theorem tendsto_nat_cast_atTop_iff [StrictOrderedSemiring R] [Archimedean R] {f : α → ℕ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop :=
  tendsto_atTop_embedding (fun a₁ a₂ => Nat.cast_le) exists_nat_ge
#align tendsto_coe_nat_at_top_iff tendsto_nat_cast_atTop_iff
-/

#print tendsto_nat_cast_atTop_atTop /-
theorem tendsto_nat_cast_atTop_atTop [StrictOrderedSemiring R] [Archimedean R] :
    Tendsto (coe : ℕ → R) atTop atTop :=
  Nat.mono_cast.tendsto_atTop_atTop exists_nat_ge
#align tendsto_coe_nat_at_top_at_top tendsto_nat_cast_atTop_atTop
-/

/- warning: int.comap_coe_at_top -> Int.comap_cast_atTop is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Eq.{1} (Filter.{0} Int) (Filter.comap.{0, u1} Int R ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1)))))))) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R _inst_1))))) (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Eq.{1} (Filter.{0} Int) (Filter.comap.{0, u1} Int R (Int.cast.{u1} R (Ring.toIntCast.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1))) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R _inst_1)))) (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))
Case conversion may be inaccurate. Consider using '#align int.comap_coe_at_top Int.comap_cast_atTopₓ'. -/
@[simp]
theorem Int.comap_cast_atTop [StrictOrderedRing R] [Archimedean R] :
    comap (coe : ℤ → R) atTop = atTop :=
  comap_embedding_atTop (fun _ _ => Int.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge r
    ⟨n, by exact_mod_cast hn⟩
#align int.comap_coe_at_top Int.comap_cast_atTop

/- warning: int.comap_coe_at_bot -> Int.comap_cast_atBot is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Eq.{1} (Filter.{0} Int) (Filter.comap.{0, u1} Int R ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1)))))))) (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R _inst_1))))) (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Eq.{1} (Filter.{0} Int) (Filter.comap.{0, u1} Int R (Int.cast.{u1} R (Ring.toIntCast.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1))) (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R _inst_1)))) (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))
Case conversion may be inaccurate. Consider using '#align int.comap_coe_at_bot Int.comap_cast_atBotₓ'. -/
@[simp]
theorem Int.comap_cast_atBot [StrictOrderedRing R] [Archimedean R] :
    comap (coe : ℤ → R) atBot = atBot :=
  comap_embedding_atBot (fun _ _ => Int.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge (-r)
    ⟨-n, by simpa [neg_le] using hn⟩
#align int.comap_coe_at_bot Int.comap_cast_atBot

/- warning: tendsto_coe_int_at_top_iff -> tendsto_int_cast_atTop_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : StrictOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R _inst_1)))] {f : α -> Int} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => (fun (a : Type) (b : Type.{u2}) [self : HasLiftT.{1, succ u2} a b] => self.0) Int R (HasLiftT.mk.{1, succ u2} Int R (CoeTCₓ.coe.{1, succ u2} Int R (Int.castCoe.{u2} R (AddGroupWithOne.toHasIntCast.{u2} R (AddCommGroupWithOne.toAddGroupWithOne.{u2} R (Ring.toAddCommGroupWithOne.{u2} R (StrictOrderedRing.toRing.{u2} R _inst_1))))))) (f n)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R _inst_1))))) (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : StrictOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R _inst_1)))] {f : α -> Int} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => Int.cast.{u2} R (Ring.toIntCast.{u2} R (StrictOrderedRing.toRing.{u2} R _inst_1)) (f n)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R _inst_1)))) (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))
Case conversion may be inaccurate. Consider using '#align tendsto_coe_int_at_top_iff tendsto_int_cast_atTop_iffₓ'. -/
theorem tendsto_int_cast_atTop_iff [StrictOrderedRing R] [Archimedean R] {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
  rw [← tendsto_comap_iff, Int.comap_cast_atTop]
#align tendsto_coe_int_at_top_iff tendsto_int_cast_atTop_iff

/- warning: tendsto_coe_int_at_bot_iff -> tendsto_int_cast_atBot_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : StrictOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R _inst_1)))] {f : α -> Int} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => (fun (a : Type) (b : Type.{u2}) [self : HasLiftT.{1, succ u2} a b] => self.0) Int R (HasLiftT.mk.{1, succ u2} Int R (CoeTCₓ.coe.{1, succ u2} Int R (Int.castCoe.{u2} R (AddGroupWithOne.toHasIntCast.{u2} R (AddCommGroupWithOne.toAddGroupWithOne.{u2} R (Ring.toAddCommGroupWithOne.{u2} R (StrictOrderedRing.toRing.{u2} R _inst_1))))))) (f n)) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R _inst_1))))) (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : StrictOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R _inst_1)))] {f : α -> Int} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => Int.cast.{u2} R (Ring.toIntCast.{u2} R (StrictOrderedRing.toRing.{u2} R _inst_1)) (f n)) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R _inst_1)))) (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))
Case conversion may be inaccurate. Consider using '#align tendsto_coe_int_at_bot_iff tendsto_int_cast_atBot_iffₓ'. -/
theorem tendsto_int_cast_atBot_iff [StrictOrderedRing R] [Archimedean R] {f : α → ℤ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
  rw [← tendsto_comap_iff, Int.comap_cast_atBot]
#align tendsto_coe_int_at_bot_iff tendsto_int_cast_atBot_iff

/- warning: tendsto_coe_int_at_top_at_top -> tendsto_int_cast_atTop_atTop is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Filter.Tendsto.{0, u1} Int R ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1)))))))) (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R _inst_1))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R _inst_1)))], Filter.Tendsto.{0, u1} Int R (Int.cast.{u1} R (Ring.toIntCast.{u1} R (StrictOrderedRing.toRing.{u1} R _inst_1))) (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R _inst_1)))
Case conversion may be inaccurate. Consider using '#align tendsto_coe_int_at_top_at_top tendsto_int_cast_atTop_atTopₓ'. -/
theorem tendsto_int_cast_atTop_atTop [StrictOrderedRing R] [Archimedean R] :
    Tendsto (coe : ℤ → R) atTop atTop :=
  Int.cast_mono.tendsto_atTop_atTop fun b =>
    let ⟨n, hn⟩ := exists_nat_ge b
    ⟨n, by exact_mod_cast hn⟩
#align tendsto_coe_int_at_top_at_top tendsto_int_cast_atTop_atTop

/- warning: rat.comap_coe_at_top -> Rat.comap_cast_atTop is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1))))))], Eq.{1} (Filter.{0} Rat) (Filter.comap.{0, u1} Rat R ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Rat R (HasLiftT.mk.{1, succ u1} Rat R (CoeTCₓ.coe.{1, succ u1} Rat R (Rat.castCoe.{u1} R (DivisionRing.toHasRatCast.{u1} R (Field.toDivisionRing.{u1} R (LinearOrderedField.toField.{u1} R _inst_1))))))) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1)))))))) (Filter.atTop.{0} Rat Rat.preorder)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (OrderedCommSemiring.toOrderedSemiring.{u1} R (StrictOrderedCommSemiring.toOrderedCommSemiring.{u1} R (LinearOrderedCommSemiring.toStrictOrderedCommSemiring.{u1} R (LinearOrderedSemifield.toLinearOrderedCommSemiring.{u1} R (LinearOrderedField.toLinearOrderedSemifield.{u1} R _inst_1))))))], Eq.{1} (Filter.{0} Rat) (Filter.comap.{0, u1} Rat R (Rat.cast.{u1} R (LinearOrderedField.toRatCast.{u1} R _inst_1)) (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1))))))) (Filter.atTop.{0} Rat Rat.instPreorderRat)
Case conversion may be inaccurate. Consider using '#align rat.comap_coe_at_top Rat.comap_cast_atTopₓ'. -/
@[simp]
theorem Rat.comap_cast_atTop [LinearOrderedField R] [Archimedean R] :
    comap (coe : ℚ → R) atTop = atTop :=
  comap_embedding_atTop (fun _ _ => Rat.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge r
    ⟨n, by simpa⟩
#align rat.comap_coe_at_top Rat.comap_cast_atTop

/- warning: rat.comap_coe_at_bot -> Rat.comap_cast_atBot is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1))))))], Eq.{1} (Filter.{0} Rat) (Filter.comap.{0, u1} Rat R ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Rat R (HasLiftT.mk.{1, succ u1} Rat R (CoeTCₓ.coe.{1, succ u1} Rat R (Rat.castCoe.{u1} R (DivisionRing.toHasRatCast.{u1} R (Field.toDivisionRing.{u1} R (LinearOrderedField.toField.{u1} R _inst_1))))))) (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1)))))))) (Filter.atBot.{0} Rat Rat.preorder)
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedField.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (OrderedCommSemiring.toOrderedSemiring.{u1} R (StrictOrderedCommSemiring.toOrderedCommSemiring.{u1} R (LinearOrderedCommSemiring.toStrictOrderedCommSemiring.{u1} R (LinearOrderedSemifield.toLinearOrderedCommSemiring.{u1} R (LinearOrderedField.toLinearOrderedSemifield.{u1} R _inst_1))))))], Eq.{1} (Filter.{0} Rat) (Filter.comap.{0, u1} Rat R (Rat.cast.{u1} R (LinearOrderedField.toRatCast.{u1} R _inst_1)) (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R (LinearOrderedCommRing.toLinearOrderedRing.{u1} R (LinearOrderedField.toLinearOrderedCommRing.{u1} R _inst_1))))))) (Filter.atBot.{0} Rat Rat.instPreorderRat)
Case conversion may be inaccurate. Consider using '#align rat.comap_coe_at_bot Rat.comap_cast_atBotₓ'. -/
@[simp]
theorem Rat.comap_cast_atBot [LinearOrderedField R] [Archimedean R] :
    comap (coe : ℚ → R) atBot = atBot :=
  comap_embedding_atBot (fun _ _ => Rat.cast_le) fun r =>
    let ⟨n, hn⟩ := exists_nat_ge (-r)
    ⟨-n, by simpa [neg_le] ⟩
#align rat.comap_coe_at_bot Rat.comap_cast_atBot

/- warning: tendsto_coe_rat_at_top_iff -> tendsto_rat_cast_atTop_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : LinearOrderedField.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1))))))] {f : α -> Rat} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => (fun (a : Type) (b : Type.{u2}) [self : HasLiftT.{1, succ u2} a b] => self.0) Rat R (HasLiftT.mk.{1, succ u2} Rat R (CoeTCₓ.coe.{1, succ u2} Rat R (Rat.castCoe.{u2} R (DivisionRing.toHasRatCast.{u2} R (Field.toDivisionRing.{u2} R (LinearOrderedField.toField.{u2} R _inst_1)))))) (f n)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1)))))))) (Filter.Tendsto.{u1, 0} α Rat f l (Filter.atTop.{0} Rat Rat.preorder))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : LinearOrderedField.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (OrderedCommSemiring.toOrderedSemiring.{u2} R (StrictOrderedCommSemiring.toOrderedCommSemiring.{u2} R (LinearOrderedCommSemiring.toStrictOrderedCommSemiring.{u2} R (LinearOrderedSemifield.toLinearOrderedCommSemiring.{u2} R (LinearOrderedField.toLinearOrderedSemifield.{u2} R _inst_1))))))] {f : α -> Rat} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => Rat.cast.{u2} R (LinearOrderedField.toRatCast.{u2} R _inst_1) (f n)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1))))))) (Filter.Tendsto.{u1, 0} α Rat f l (Filter.atTop.{0} Rat Rat.instPreorderRat))
Case conversion may be inaccurate. Consider using '#align tendsto_coe_rat_at_top_iff tendsto_rat_cast_atTop_iffₓ'. -/
theorem tendsto_rat_cast_atTop_iff [LinearOrderedField R] [Archimedean R] {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atTop ↔ Tendsto f l atTop := by
  rw [← tendsto_comap_iff, Rat.comap_cast_atTop]
#align tendsto_coe_rat_at_top_iff tendsto_rat_cast_atTop_iff

/- warning: tendsto_coe_rat_at_bot_iff -> tendsto_rat_cast_atBot_iff is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : LinearOrderedField.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1))))))] {f : α -> Rat} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => (fun (a : Type) (b : Type.{u2}) [self : HasLiftT.{1, succ u2} a b] => self.0) Rat R (HasLiftT.mk.{1, succ u2} Rat R (CoeTCₓ.coe.{1, succ u2} Rat R (Rat.castCoe.{u2} R (DivisionRing.toHasRatCast.{u2} R (Field.toDivisionRing.{u2} R (LinearOrderedField.toField.{u2} R _inst_1)))))) (f n)) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1)))))))) (Filter.Tendsto.{u1, 0} α Rat f l (Filter.atBot.{0} Rat Rat.preorder))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} [_inst_1 : LinearOrderedField.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (OrderedCommSemiring.toOrderedSemiring.{u2} R (StrictOrderedCommSemiring.toOrderedCommSemiring.{u2} R (LinearOrderedCommSemiring.toStrictOrderedCommSemiring.{u2} R (LinearOrderedSemifield.toLinearOrderedCommSemiring.{u2} R (LinearOrderedField.toLinearOrderedSemifield.{u2} R _inst_1))))))] {f : α -> Rat} {l : Filter.{u1} α}, Iff (Filter.Tendsto.{u1, u2} α R (fun (n : α) => Rat.cast.{u2} R (LinearOrderedField.toRatCast.{u2} R _inst_1) (f n)) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R (LinearOrderedCommRing.toLinearOrderedRing.{u2} R (LinearOrderedField.toLinearOrderedCommRing.{u2} R _inst_1))))))) (Filter.Tendsto.{u1, 0} α Rat f l (Filter.atBot.{0} Rat Rat.instPreorderRat))
Case conversion may be inaccurate. Consider using '#align tendsto_coe_rat_at_bot_iff tendsto_rat_cast_atBot_iffₓ'. -/
theorem tendsto_rat_cast_atBot_iff [LinearOrderedField R] [Archimedean R] {f : α → ℚ}
    {l : Filter α} : Tendsto (fun n => (f n : R)) l atBot ↔ Tendsto f l atBot := by
  rw [← tendsto_comap_iff, Rat.comap_cast_atBot]
#align tendsto_coe_rat_at_bot_iff tendsto_rat_cast_atBot_iff

/- warning: at_top_countable_basis_of_archimedean -> atTop_hasCountableBasis_of_archimedean is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedSemiring.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1)))], Filter.HasCountableBasis.{u1, 0} R Nat (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedCancelAddCommMonoid.toPartialOrder.{u1} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1))))) (fun (n : Nat) => True) (fun (n : Nat) => Set.Ici.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedCancelAddCommMonoid.toPartialOrder.{u1} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1)))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Nat R (HasLiftT.mk.{1, succ u1} Nat R (CoeTCₓ.coe.{1, succ u1} Nat R (Nat.castCoe.{u1} R (AddMonoidWithOne.toNatCast.{u1} R (AddCommMonoidWithOne.toAddMonoidWithOne.{u1} R (NonAssocSemiring.toAddCommMonoidWithOne.{u1} R (Semiring.toNonAssocSemiring.{u1} R (StrictOrderedSemiring.toSemiring.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1))))))))) n))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedSemiring.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R _inst_1))], Filter.HasCountableBasis.{u1, 0} R Nat (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedSemiring.toPartialOrder.{u1} R _inst_1))) (fun (n : Nat) => True) (fun (n : Nat) => Set.Ici.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedSemiring.toPartialOrder.{u1} R _inst_1)) (Nat.cast.{u1} R (Semiring.toNatCast.{u1} R (StrictOrderedSemiring.toSemiring.{u1} R _inst_1)) n))
Case conversion may be inaccurate. Consider using '#align at_top_countable_basis_of_archimedean atTop_hasCountableBasis_of_archimedeanₓ'. -/
theorem atTop_hasCountableBasis_of_archimedean [LinearOrderedSemiring R] [Archimedean R] :
    (atTop : Filter R).HasCountableBasis (fun n : ℕ => True) fun n => Ici n :=
  { Countable := to_countable _
    to_hasBasis :=
      atTop_basis.to_hasBasis
        (fun x hx =>
          let ⟨n, hn⟩ := exists_nat_ge x
          ⟨n, trivial, Ici_subset_Ici.2 hn⟩)
        fun n hn => ⟨n, trivial, Subset.rfl⟩ }
#align at_top_countable_basis_of_archimedean atTop_hasCountableBasis_of_archimedean

/- warning: at_bot_countable_basis_of_archimedean -> atBot_hasCountableBasis_of_archimedean is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (StrictOrderedRing.toStrictOrderedSemiring.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1))))], Filter.HasCountableBasis.{u1, 0} R Int (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1))))) (fun (m : Int) => True) (fun (m : Int) => Set.Iic.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedAddCommGroup.toPartialOrder.{u1} R (StrictOrderedRing.toOrderedAddCommGroup.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1)))) ((fun (a : Type) (b : Type.{u1}) [self : HasLiftT.{1, succ u1} a b] => self.0) Int R (HasLiftT.mk.{1, succ u1} Int R (CoeTCₓ.coe.{1, succ u1} Int R (Int.castCoe.{u1} R (AddGroupWithOne.toHasIntCast.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (StrictOrderedRing.toRing.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1)))))))) m))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedRing.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R (LinearOrderedRing.toLinearOrderedSemiring.{u1} R _inst_1))))], Filter.HasCountableBasis.{u1, 0} R Int (Filter.atBot.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1)))) (fun (m : Int) => True) (fun (m : Int) => Set.Iic.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedRing.toPartialOrder.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1))) (Int.cast.{u1} R (Ring.toIntCast.{u1} R (StrictOrderedRing.toRing.{u1} R (LinearOrderedRing.toStrictOrderedRing.{u1} R _inst_1))) m))
Case conversion may be inaccurate. Consider using '#align at_bot_countable_basis_of_archimedean atBot_hasCountableBasis_of_archimedeanₓ'. -/
theorem atBot_hasCountableBasis_of_archimedean [LinearOrderedRing R] [Archimedean R] :
    (atBot : Filter R).HasCountableBasis (fun m : ℤ => True) fun m => Iic m :=
  { Countable := to_countable _
    to_hasBasis :=
      atBot_basis.to_hasBasis
        (fun x hx =>
          let ⟨m, hm⟩ := exists_int_lt x
          ⟨m, trivial, Iic_subset_Iic.2 hm.le⟩)
        fun m hm => ⟨m, trivial, Subset.rfl⟩ }
#align at_bot_countable_basis_of_archimedean atBot_hasCountableBasis_of_archimedean

/- warning: at_top_countably_generated_of_archimedean -> atTop_isCountablyGenerated_of_archimedean is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} [_inst_1 : LinearOrderedSemiring.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1)))], Filter.IsCountablyGenerated.{u1} R (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (OrderedCancelAddCommMonoid.toPartialOrder.{u1} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u1} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u1} R _inst_1)))))
but is expected to have type
  forall {R : Type.{u1}} [_inst_1 : StrictOrderedSemiring.{u1} R] [_inst_2 : Archimedean.{u1} R (OrderedSemiring.toOrderedAddCommMonoid.{u1} R (StrictOrderedSemiring.toOrderedSemiring.{u1} R _inst_1))], Filter.IsCountablyGenerated.{u1} R (Filter.atTop.{u1} R (PartialOrder.toPreorder.{u1} R (StrictOrderedSemiring.toPartialOrder.{u1} R _inst_1)))
Case conversion may be inaccurate. Consider using '#align at_top_countably_generated_of_archimedean atTop_isCountablyGenerated_of_archimedeanₓ'. -/
instance (priority := 100) atTop_isCountablyGenerated_of_archimedean [LinearOrderedSemiring R]
    [Archimedean R] : (atTop : Filter R).IsCountablyGenerated :=
  atTop_hasCountableBasis_of_archimedean.IsCountablyGenerated
#align at_top_countably_generated_of_archimedean atTop_isCountablyGenerated_of_archimedean

#print atBot_isCountablyGenerated_of_archimedean /-
instance (priority := 100) atBot_isCountablyGenerated_of_archimedean [LinearOrderedRing R]
    [Archimedean R] : (atBot : Filter R).IsCountablyGenerated :=
  atBot_hasCountableBasis_of_archimedean.IsCountablyGenerated
#align at_bot_countably_generated_of_archimedean atBot_isCountablyGenerated_of_archimedean
-/

namespace Filter

variable {l : Filter α} {f : α → R} {r : R}

section LinearOrderedSemiring

variable [LinearOrderedSemiring R] [Archimedean R]

/- warning: filter.tendsto.const_mul_at_top' -> Filter.Tendsto.const_mul_atTop' is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedSemiring.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (MulZeroClass.toHasZero.{u2} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (Distrib.toHasMul.{u2} R (NonUnitalNonAssocSemiring.toDistrib.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))) r (f x)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedSemiring.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (MonoidWithZero.toZero.{u2} R (Semiring.toMonoidWithZero.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) r (f x)) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.const_mul_at_top' Filter.Tendsto.const_mul_atTop'ₓ'. -/
/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the left) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `filter.tendsto.const_mul_at_top`). -/
theorem Tendsto.const_mul_atTop' (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => r * f x) l atTop :=
  by
  apply tendsto_at_top.2 fun b => _
  obtain ⟨n : ℕ, hn : 1 ≤ n • r⟩ := Archimedean.arch 1 hr
  rw [nsmul_eq_mul'] at hn
  filter_upwards [tendsto_at_top.1 hf (n * max b 0)]with x hx
  calc
    b ≤ 1 * max b 0 := by
      rw [one_mul]
      exact le_max_left _ _
    _ ≤ r * n * max b 0 := (mul_le_mul_of_nonneg_right hn (le_max_right _ _))
    _ = r * (n * max b 0) := by rw [mul_assoc]
    _ ≤ r * f x := mul_le_mul_of_nonneg_left hx (le_of_lt hr)

#align filter.tendsto.const_mul_at_top' Filter.Tendsto.const_mul_atTop'

/- warning: filter.tendsto.at_top_mul_const' -> Filter.Tendsto.atTop_mul_const' is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedSemiring.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (MulZeroClass.toHasZero.{u2} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (Distrib.toHasMul.{u2} R (NonUnitalNonAssocSemiring.toDistrib.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedSemiring.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (MonoidWithZero.toZero.{u2} R (Semiring.toMonoidWithZero.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (NonUnitalNonAssocSemiring.toMul.{u2} R (NonAssocSemiring.toNonUnitalNonAssocSemiring.{u2} R (Semiring.toNonAssocSemiring.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedSemiring.toPartialOrder.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_mul_const' Filter.Tendsto.atTop_mul_const'ₓ'. -/
/-- If a function tends to infinity along a filter, then this function multiplied by a positive
constant (on the right) also tends to infinity. The archimedean assumption is convenient to get a
statement that works on `ℕ`, `ℤ` and `ℝ`, although not necessary (a version in ordered fields is
given in `filter.tendsto.at_top_mul_const`). -/
theorem Tendsto.atTop_mul_const' (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x * r) l atTop :=
  by
  apply tendsto_at_top.2 fun b => _
  obtain ⟨n : ℕ, hn : 1 ≤ n • r⟩ := Archimedean.arch 1 hr
  have hn' : 1 ≤ (n : R) * r := by rwa [nsmul_eq_mul] at hn
  filter_upwards [tendsto_at_top.1 hf (max b 0 * n)]with x hx
  calc
    b ≤ max b 0 * 1 := by
      rw [mul_one]
      exact le_max_left _ _
    _ ≤ max b 0 * (n * r) := (mul_le_mul_of_nonneg_left hn' (le_max_right _ _))
    _ = max b 0 * n * r := by rw [mul_assoc]
    _ ≤ f x * r := mul_le_mul_of_nonneg_right hx (le_of_lt hr)

#align filter.tendsto.at_top_mul_const' Filter.Tendsto.atTop_mul_const'

end LinearOrderedSemiring

section LinearOrderedRing

variable [LinearOrderedRing R] [Archimedean R]

/- warning: filter.tendsto.at_top_mul_neg_const' -> Filter.Tendsto.atTop_mul_neg_const' is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) r (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (MulZeroClass.toHasZero.{u2} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u2} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))))))))) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (Distrib.toHasMul.{u2} R (Ring.toDistrib.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (MonoidWithZero.toZero.{u2} R (Semiring.toMonoidWithZero.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1)))))))) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (NonUnitalNonAssocRing.toMul.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_mul_neg_const' Filter.Tendsto.atTop_mul_neg_const'ₓ'. -/
/-- See also `filter.tendsto.at_top_mul_neg_const` for a version of this lemma for
`linear_ordered_field`s which does not require the `archimedean` assumption. -/
theorem Tendsto.atTop_mul_neg_const' (hr : r < 0) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x * r) l atBot := by
  simpa only [tendsto_neg_at_top_iff, mul_neg] using hf.at_top_mul_const' (neg_pos.mpr hr)
#align filter.tendsto.at_top_mul_neg_const' Filter.Tendsto.atTop_mul_neg_const'

/- warning: filter.tendsto.at_bot_mul_const' -> Filter.Tendsto.atBot_mul_const' is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (MulZeroClass.toHasZero.{u2} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u2} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (Distrib.toHasMul.{u2} R (Ring.toDistrib.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (MonoidWithZero.toZero.{u2} R (Semiring.toMonoidWithZero.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1))))))) r) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (NonUnitalNonAssocRing.toMul.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_bot_mul_const' Filter.Tendsto.atBot_mul_const'ₓ'. -/
/-- See also `filter.tendsto.at_bot_mul_const` for a version of this lemma for
`linear_ordered_field`s which does not require the `archimedean` assumption. -/
theorem Tendsto.atBot_mul_const' (hr : 0 < r) (hf : Tendsto f l atBot) :
    Tendsto (fun x => f x * r) l atBot :=
  by
  simp only [← tendsto_neg_at_top_iff, ← neg_mul] at hf⊢
  exact hf.at_top_mul_const' hr
#align filter.tendsto.at_bot_mul_const' Filter.Tendsto.atBot_mul_const'

/- warning: filter.tendsto.at_bot_mul_neg_const' -> Filter.Tendsto.atBot_mul_neg_const' is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (StrictOrderedRing.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) r (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (MulZeroClass.toHasZero.{u2} R (NonUnitalNonAssocSemiring.toMulZeroClass.{u2} R (NonUnitalNonAssocRing.toNonUnitalNonAssocSemiring.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))))))))) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (Distrib.toHasMul.{u2} R (Ring.toDistrib.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (StrictOrderedRing.toOrderedAddCommGroup.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {f : α -> R} {r : R} [_inst_1 : LinearOrderedRing.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedSemiring.toOrderedAddCommMonoid.{u2} R (StrictOrderedSemiring.toOrderedSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1))))], (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (MonoidWithZero.toZero.{u2} R (Semiring.toMonoidWithZero.{u2} R (StrictOrderedSemiring.toSemiring.{u2} R (LinearOrderedSemiring.toStrictOrderedSemiring.{u2} R (LinearOrderedRing.toLinearOrderedSemiring.{u2} R _inst_1)))))))) -> (Filter.Tendsto.{u1, u2} α R f l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HMul.hMul.{u2, u2, u2} R R R (instHMul.{u2} R (NonUnitalNonAssocRing.toMul.{u2} R (NonAssocRing.toNonUnitalNonAssocRing.{u2} R (Ring.toNonAssocRing.{u2} R (StrictOrderedRing.toRing.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (StrictOrderedRing.toPartialOrder.{u2} R (LinearOrderedRing.toStrictOrderedRing.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_bot_mul_neg_const' Filter.Tendsto.atBot_mul_neg_const'ₓ'. -/
/-- See also `filter.tendsto.at_bot_mul_neg_const` for a version of this lemma for
`linear_ordered_field`s which does not require the `archimedean` assumption. -/
theorem Tendsto.atBot_mul_neg_const' (hr : r < 0) (hf : Tendsto f l atBot) :
    Tendsto (fun x => f x * r) l atTop := by
  simpa only [mul_neg, tendsto_neg_at_bot_iff] using hf.at_bot_mul_const' (neg_pos.2 hr)
#align filter.tendsto.at_bot_mul_neg_const' Filter.Tendsto.atBot_mul_neg_const'

end LinearOrderedRing

section LinearOrderedCancelAddCommMonoid

variable [LinearOrderedCancelAddCommMonoid R] [Archimedean R]

/- warning: filter.tendsto.at_top_nsmul_const -> Filter.Tendsto.atTop_nsmul_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedCancelAddCommMonoid.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1))] {f : α -> Nat}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (AddRightCancelMonoid.toAddMonoid.{u2} R (AddCancelMonoid.toAddRightCancelMonoid.{u2} R (AddCancelCommMonoid.toAddCancelMonoid.{u2} R (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))))))))) r) -> (Filter.Tendsto.{u1, 0} α Nat f l (Filter.atTop.{0} Nat (PartialOrder.toPreorder.{0} Nat (OrderedCancelAddCommMonoid.toPartialOrder.{0} Nat (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{0} Nat Nat.strictOrderedSemiring))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Nat R (AddMonoid.SMul.{u2} R (AddRightCancelMonoid.toAddMonoid.{u2} R (AddCancelMonoid.toAddRightCancelMonoid.{u2} R (AddCancelCommMonoid.toAddCancelMonoid.{u2} R (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedCancelAddCommMonoid.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R _inst_1))] {f : α -> Nat}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (AddRightCancelMonoid.toZero.{u2} R (AddCancelMonoid.toAddRightCancelMonoid.{u2} R (AddCancelCommMonoid.toAddCancelMonoid.{u2} R (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1))))))) r) -> (Filter.Tendsto.{u1, 0} α Nat f l (Filter.atTop.{0} Nat (PartialOrder.toPreorder.{0} Nat (StrictOrderedSemiring.toPartialOrder.{0} Nat Nat.strictOrderedSemiring)))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Nat R R (instHSMul.{0, u2} Nat R (AddMonoid.SMul.{u2} R (AddRightCancelMonoid.toAddMonoid.{u2} R (AddCancelMonoid.toAddRightCancelMonoid.{u2} R (AddCancelCommMonoid.toAddCancelMonoid.{u2} R (OrderedCancelAddCommMonoid.toCancelAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1))))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedCancelAddCommMonoid.toPartialOrder.{u2} R (LinearOrderedCancelAddCommMonoid.toOrderedCancelAddCommMonoid.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_nsmul_const Filter.Tendsto.atTop_nsmul_constₓ'. -/
theorem Tendsto.atTop_nsmul_const {f : α → ℕ} (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x • r) l atTop :=
  by
  refine' tendsto_at_top.mpr fun s => _
  obtain ⟨n : ℕ, hn : s ≤ n • r⟩ := Archimedean.arch s hr
  exact (tendsto_at_top.mp hf n).mono fun a ha => hn.trans (nsmul_le_nsmul hr.le ha)
#align filter.tendsto.at_top_nsmul_const Filter.Tendsto.atTop_nsmul_const

end LinearOrderedCancelAddCommMonoid

section LinearOrderedAddCommGroup

variable [LinearOrderedAddCommGroup R] [Archimedean R]

/- warning: filter.tendsto.at_top_nsmul_neg_const -> Filter.Tendsto.atTop_nsmul_neg_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (OrderedAddCommGroup.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))] {f : α -> Nat}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))))))) -> (Filter.Tendsto.{u1, 0} α Nat f l (Filter.atTop.{0} Nat (PartialOrder.toPreorder.{0} Nat (OrderedCancelAddCommMonoid.toPartialOrder.{0} Nat (StrictOrderedSemiring.toOrderedCancelAddCommMonoid.{0} Nat Nat.strictOrderedSemiring))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Nat R (AddMonoid.SMul.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toLinearOrderedAddCancelCommMonoid.{u2} R _inst_1)))] {f : α -> Nat}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (NegZeroClass.toZero.{u2} R (SubNegZeroMonoid.toNegZeroClass.{u2} R (SubtractionMonoid.toSubNegZeroMonoid.{u2} R (SubtractionCommMonoid.toSubtractionMonoid.{u2} R (AddCommGroup.toDivisionAddCommMonoid.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))))))) -> (Filter.Tendsto.{u1, 0} α Nat f l (Filter.atTop.{0} Nat (PartialOrder.toPreorder.{0} Nat (StrictOrderedSemiring.toPartialOrder.{0} Nat Nat.strictOrderedSemiring)))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Nat R R (instHSMul.{0, u2} Nat R (AddMonoid.SMul.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_nsmul_neg_const Filter.Tendsto.atTop_nsmul_neg_constₓ'. -/
theorem Tendsto.atTop_nsmul_neg_const {f : α → ℕ} (hr : r < 0) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x • r) l atBot := by simpa using hf.at_top_nsmul_const (neg_pos.2 hr)
#align filter.tendsto.at_top_nsmul_neg_const Filter.Tendsto.atTop_nsmul_neg_const

/- warning: filter.tendsto.at_top_zsmul_const -> Filter.Tendsto.atTop_zsmul_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (OrderedAddCommGroup.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))))))) r) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toLinearOrderedAddCancelCommMonoid.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (NegZeroClass.toZero.{u2} R (SubNegZeroMonoid.toNegZeroClass.{u2} R (SubtractionMonoid.toSubNegZeroMonoid.{u2} R (SubtractionCommMonoid.toSubtractionMonoid.{u2} R (AddCommGroup.toDivisionAddCommMonoid.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))))) r) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Int R R (instHSMul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_zsmul_const Filter.Tendsto.atTop_zsmul_constₓ'. -/
theorem Tendsto.atTop_zsmul_const {f : α → ℤ} (hr : 0 < r) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x • r) l atTop :=
  by
  refine' tendsto_at_top.mpr fun s => _
  obtain ⟨n : ℕ, hn : s ≤ n • r⟩ := Archimedean.arch s hr
  replace hn : s ≤ (n : ℤ) • r; · simpa
  exact (tendsto_at_top.mp hf n).mono fun a ha => hn.trans (zsmul_le_zsmul hr.le ha)
#align filter.tendsto.at_top_zsmul_const Filter.Tendsto.atTop_zsmul_const

/- warning: filter.tendsto.at_top_zsmul_neg_const -> Filter.Tendsto.atTop_zsmul_neg_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (OrderedAddCommGroup.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))))))) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toLinearOrderedAddCancelCommMonoid.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (NegZeroClass.toZero.{u2} R (SubNegZeroMonoid.toNegZeroClass.{u2} R (SubtractionMonoid.toSubNegZeroMonoid.{u2} R (SubtractionCommMonoid.toSubtractionMonoid.{u2} R (AddCommGroup.toDivisionAddCommMonoid.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))))))) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atTop.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Int R R (instHSMul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_top_zsmul_neg_const Filter.Tendsto.atTop_zsmul_neg_constₓ'. -/
theorem Tendsto.atTop_zsmul_neg_const {f : α → ℤ} (hr : r < 0) (hf : Tendsto f l atTop) :
    Tendsto (fun x => f x • r) l atBot := by simpa using hf.at_top_zsmul_const (neg_pos.2 hr)
#align filter.tendsto.at_top_zsmul_neg_const Filter.Tendsto.atTop_zsmul_neg_const

/- warning: filter.tendsto.at_bot_zsmul_const -> Filter.Tendsto.atBot_zsmul_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (OrderedAddCommGroup.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))))))) r) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toLinearOrderedAddCancelCommMonoid.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (NegZeroClass.toZero.{u2} R (SubNegZeroMonoid.toNegZeroClass.{u2} R (SubtractionMonoid.toSubNegZeroMonoid.{u2} R (SubtractionCommMonoid.toSubtractionMonoid.{u2} R (AddCommGroup.toDivisionAddCommMonoid.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))))) r) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Int R R (instHSMul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))) (f x) r) l (Filter.atBot.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_bot_zsmul_const Filter.Tendsto.atBot_zsmul_constₓ'. -/
theorem Tendsto.atBot_zsmul_const {f : α → ℤ} (hr : 0 < r) (hf : Tendsto f l atBot) :
    Tendsto (fun x => f x • r) l atBot :=
  by
  simp only [← tendsto_neg_at_top_iff, ← neg_zsmul] at hf⊢
  exact hf.at_top_zsmul_const hr
#align filter.tendsto.at_bot_zsmul_const Filter.Tendsto.atBot_zsmul_const

/- warning: filter.tendsto.at_bot_zsmul_neg_const -> Filter.Tendsto.atBot_zsmul_neg_const is a dubious translation:
lean 3 declaration is
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (OrderedCancelAddCommMonoid.toOrderedAddCommMonoid.{u2} R (OrderedAddCommGroup.toOrderedCancelAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (OfNat.mk.{u2} R 0 (Zero.zero.{u2} R (AddZeroClass.toHasZero.{u2} R (AddMonoid.toAddZeroClass.{u2} R (SubNegMonoid.toAddMonoid.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))))))))) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (OrderedAddCommGroup.toPartialOrder.{0} Int (StrictOrderedRing.toOrderedAddCommGroup.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing))))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => SMul.smul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
but is expected to have type
  forall {α : Type.{u1}} {R : Type.{u2}} {l : Filter.{u1} α} {r : R} [_inst_1 : LinearOrderedAddCommGroup.{u2} R] [_inst_2 : Archimedean.{u2} R (LinearOrderedAddCommMonoid.toOrderedAddCommMonoid.{u2} R (LinearOrderedCancelAddCommMonoid.toLinearOrderedAddCommMonoid.{u2} R (LinearOrderedAddCommGroup.toLinearOrderedAddCancelCommMonoid.{u2} R _inst_1)))] {f : α -> Int}, (LT.lt.{u2} R (Preorder.toLT.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))) r (OfNat.ofNat.{u2} R 0 (Zero.toOfNat0.{u2} R (NegZeroClass.toZero.{u2} R (SubNegZeroMonoid.toNegZeroClass.{u2} R (SubtractionMonoid.toSubNegZeroMonoid.{u2} R (SubtractionCommMonoid.toSubtractionMonoid.{u2} R (AddCommGroup.toDivisionAddCommMonoid.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))))))) -> (Filter.Tendsto.{u1, 0} α Int f l (Filter.atBot.{0} Int (PartialOrder.toPreorder.{0} Int (StrictOrderedRing.toPartialOrder.{0} Int (LinearOrderedRing.toStrictOrderedRing.{0} Int (LinearOrderedCommRing.toLinearOrderedRing.{0} Int Int.linearOrderedCommRing)))))) -> (Filter.Tendsto.{u1, u2} α R (fun (x : α) => HSMul.hSMul.{0, u2, u2} Int R R (instHSMul.{0, u2} Int R (SubNegMonoid.SMulInt.{u2} R (AddGroup.toSubNegMonoid.{u2} R (AddCommGroup.toAddGroup.{u2} R (OrderedAddCommGroup.toAddCommGroup.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))) (f x) r) l (Filter.atTop.{u2} R (PartialOrder.toPreorder.{u2} R (OrderedAddCommGroup.toPartialOrder.{u2} R (LinearOrderedAddCommGroup.toOrderedAddCommGroup.{u2} R _inst_1)))))
Case conversion may be inaccurate. Consider using '#align filter.tendsto.at_bot_zsmul_neg_const Filter.Tendsto.atBot_zsmul_neg_constₓ'. -/
theorem Tendsto.atBot_zsmul_neg_const {f : α → ℤ} (hr : r < 0) (hf : Tendsto f l atBot) :
    Tendsto (fun x => f x • r) l atTop := by simpa using hf.at_bot_zsmul_const (neg_pos.2 hr)
#align filter.tendsto.at_bot_zsmul_neg_const Filter.Tendsto.atBot_zsmul_neg_const

end LinearOrderedAddCommGroup

end Filter


/-
Copyright (c) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import data.multiset.erase_dup
import data.list.min_max

/-!
# The fold operation for a commutative associative operation over a multiset.
-/

namespace multiset
variables {α β : Type*}

/-! ### fold -/
section fold
variables (op : α → α → α) [hc : is_commutative α op] [ha : is_associative α op]
local notation a * b := op a b
include hc ha

/-- `fold op b s` folds a commutative associative operation `op` over
  the multiset `s`. -/
def fold : α → multiset α → α := foldr op (left_comm _ hc.comm ha.assoc)

theorem fold_eq_foldr (b : α) (s : multiset α) :
  fold op b s = foldr op (left_comm _ hc.comm ha.assoc) b s := rfl

@[simp] theorem coe_fold_r (b : α) (l : list α) : fold op b l = l.foldr op b := rfl

theorem coe_fold_l (b : α) (l : list α) : fold op b l = l.foldl op b :=
(coe_foldr_swap op _ b l).trans $ by simp [hc.comm]

theorem fold_eq_foldl (b : α) (s : multiset α) :
  fold op b s = foldl op (right_comm _ hc.comm ha.assoc) b s :=
quot.induction_on s $ λ l, coe_fold_l _ _ _

@[simp] theorem fold_zero (b : α) : (0 : multiset α).fold op b = b := rfl

@[simp] theorem fold_cons_left : ∀ (b a : α) (s : multiset α),
  (a ::ₘ s).fold op b = a * s.fold op b := foldr_cons _ _

theorem fold_cons_right (b a : α) (s : multiset α) : (a ::ₘ s).fold op b = s.fold op b * a :=
by simp [hc.comm]

theorem fold_cons'_right (b a : α) (s : multiset α) : (a ::ₘ s).fold op b = s.fold op (b * a) :=
by rw [fold_eq_foldl, foldl_cons, ← fold_eq_foldl]

theorem fold_cons'_left (b a : α) (s : multiset α) : (a ::ₘ s).fold op b = s.fold op (a * b) :=
by rw [fold_cons'_right, hc.comm]

theorem fold_add (b₁ b₂ : α) (s₁ s₂ : multiset α) :
  (s₁ + s₂).fold op (b₁ * b₂) = s₁.fold op b₁ * s₂.fold op b₂ :=
multiset.induction_on s₂
  (by rw [add_zero, fold_zero, ← fold_cons'_right, ← fold_cons_right op])
  (by simp {contextual := tt}; cc)

theorem fold_singleton (b a : α) : ({a} : multiset α).fold op b = a * b := foldr_singleton _ _ _ _

theorem fold_distrib {f g : β → α} (u₁ u₂ : α) (s : multiset β) :
  (s.map (λx, f x * g x)).fold op (u₁ * u₂) = (s.map f).fold op u₁ * (s.map g).fold op u₂ :=
multiset.induction_on s (by simp) (by simp {contextual := tt}; cc)

theorem fold_hom {op' : β → β → β} [is_commutative β op'] [is_associative β op']
  {m : α → β} (hm : ∀x y, m (op x y) = op' (m x) (m y)) (b : α) (s : multiset α) :
  (s.map m).fold op' (m b) = m (s.fold op b) :=
multiset.induction_on s (by simp) (by simp [hm] {contextual := tt})

theorem fold_union_inter [decidable_eq α] (s₁ s₂ : multiset α) (b₁ b₂ : α) :
  (s₁ ∪ s₂).fold op b₁ * (s₁ ∩ s₂).fold op b₂ = s₁.fold op b₁ * s₂.fold op b₂ :=
by rw [← fold_add op, union_add_inter, fold_add op]

@[simp] theorem fold_erase_dup_idem [decidable_eq α] [hi : is_idempotent α op] (s : multiset α)
  (b : α) :
  (erase_dup s).fold op b = s.fold op b :=
multiset.induction_on s (by simp) $ λ a s IH, begin
  by_cases a ∈ s; simp [IH, h],
  show fold op b s = op a (fold op b s),
  rw [← cons_erase h, fold_cons_left, ← ha.assoc, hi.idempotent],
end

end fold

section order

lemma max_le_of_forall_le {α : Type*} [canonically_linear_ordered_add_monoid α]
  (l : multiset α) (n : α) (h : ∀ (x ∈ l), x ≤ n) :
  l.fold max ⊥ ≤ n :=
begin
  induction l using quotient.induction_on,
  simpa using list.max_le_of_forall_le _ _ h
end

lemma max_nat_le_of_forall_le (l : multiset ℕ) (n : ℕ) (h : ∀ (x ∈ l), x ≤ n) :
  l.fold max 0 ≤ n :=
max_le_of_forall_le l n h

end order

open nat

theorem le_smul_erase_dup [decidable_eq α] (s : multiset α) :
  ∃ n : ℕ, s ≤ n • erase_dup s :=
⟨(s.map (λ a, count a s)).fold max 0, le_iff_count.2 $ λ a, begin
  rw count_nsmul, by_cases a ∈ s,
  { refine le_trans _ (nat.mul_le_mul_left _ $ count_pos.2 $ mem_erase_dup.2 h),
    have : count a s ≤ fold max 0 (map (λ a, count a s) (a ::ₘ erase s a));
    [simp [le_max_left], simpa [cons_erase h]] },
  { simp [count_eq_zero.2 h, nat.zero_le] }
end⟩

end multiset


/-
Copyright (c) 2019 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Jeremy Avigad

The Fréchet derivative.

Let `E` and `F` be normed spaces, and `f : E → F`. Then

  `has_fderiv_at_within f f' x s`

says that the function `f' : E → F` is a bounded linear map and `f` has derivative `f'` at
`x`, where the domain of interest is restricted to `s`. We also have

  `has_fderiv_at f f' x := has_fderiv_at_within f f' x univ`

The derivative is defined in terms of the `is_o` relation, but also characterized in terms of
the `tendsto` relation.
-/
import topology.basic analysis.normed_space.bounded_linear_maps analysis.asymptotics tactic.abel
open filter asymptotics

section

variables (K : Type*) [normed_field K]
variables {E : Type*} [normed_space K E]
variables {F : Type*} [normed_space K F]
variables {G : Type*} [normed_space K G]
include K

def has_fderiv_at_filter (f : E → F) (f' : E → F) (x : E) (L : filter E) :=
is_bounded_linear_map K f' ∧
  is_o (λ x', f x' - f x - f' (x' - x)) (λ x', x' - x) L

def has_fderiv_at_within (f : E → F) (f' : E → F) (x : E) (s : set E) :=
has_fderiv_at_filter K f f' x (nhds_within x s)

def has_fderiv_at (f : E → F) (f' : E → F) (x : E) :=
has_fderiv_at_filter K f f' x (nhds x)

variables {K}

theorem has_fderiv_at_filter.is_o {f : E → F} {f' : E → F} {x L}
  (h : has_fderiv_at_filter K f f' x L) :
  is_o (λ x', f x' - f x - f' (x' - x)) (λ x', x' - x) L :=
h.right

theorem has_fderiv_at.is_o {f : E → F} {f' : E → F} {x : E} (h : has_fderiv_at K f f' x) :
  is_o (λ x', f x' - f x - f' (x' - x)) (λ x', x' - x) (nhds x) :=
h.is_o

theorem has_fderiv_at_filter_iff_tendsto {f : E → F} {f' : E → F} {x : E} {L : filter E} :
  has_fderiv_at_filter K f f' x L ↔
    is_bounded_linear_map K f' ∧
      tendsto (λ x', ∥x' - x∥⁻¹ * ∥f x' - f x - f' (x' - x)∥) L (nhds 0) :=
and.congr_right_iff.mpr $
  assume bf' : is_bounded_linear_map K f',
  have f'0 : f' 0 = 0 := (bf'.to_linear_map _).map_zero,
  have h : ∀ x', ∥x' - x∥ = 0 → ∥f x' - f x - f' (x' - x)∥ = 0, from
    assume x' hx',
    have x' = x, from eq_of_sub_eq_zero ((norm_eq_zero _).mp hx'),
    by rw this; simp [f'0],
  begin
    rw [←is_o_norm_left, ←is_o_norm_right, is_o_iff_tendsto h],
    exact tendsto.congr'r (λ x', mul_comm _ _)
  end

theorem has_fderiv_at_within_iff_tendsto {f : E → F} {f' : E → F} {x : E} {s : set E} :
  has_fderiv_at_within K f f' x s ↔
    is_bounded_linear_map K f' ∧
      tendsto (λ x', ∥x' - x∥⁻¹ * ∥f x' - f x - f' (x' - x)∥) (nhds_within x s) (nhds 0) :=
has_fderiv_at_filter_iff_tendsto

theorem has_fderiv_at_iff_tendsto {f : E → F} {f' : E → F} {x : E} :
  has_fderiv_at K f f' x ↔
    is_bounded_linear_map K f' ∧
      tendsto (λ x', ∥x' - x∥⁻¹ * ∥f x' - f x - f' (x' - x)∥) (nhds x) (nhds 0) :=
has_fderiv_at_filter_iff_tendsto

theorem has_fderiv_at_filter.mono {f : E → F} {f' : E → F} {x : E} {L₁ L₂ : filter E}
  (hst : L₁ ≤ L₂) : has_fderiv_at_filter K f f' x L₂ → has_fderiv_at_filter K f f' x L₁ :=
and.imp_right (is_o.mono hst)

theorem has_fderiv_at_within.mono {f : E → F} {f' : E → F} {x : E} {s t : set E}
  (hst : s ⊆ t) : has_fderiv_at_within K f f' x t → has_fderiv_at_within K f f' x s :=
has_fderiv_at_filter.mono (nhds_within_mono _ hst)

theorem has_fderiv_at_filter_of_has_fderiv_at {f : E → F} {f' : E → F} {x : E}
  {L : filter E} (hL : L ≤ nhds x) (h : has_fderiv_at K f f' x) : has_fderiv_at_filter K f f' x L :=
h.mono hL

theorem has_fderiv_at_within_of_has_fderiv_at {f : E → F} {f' : E → F} {x : E} {s : set E} :
  has_fderiv_at K f f' x → has_fderiv_at_within K f f' x s :=
has_fderiv_at_filter_of_has_fderiv_at lattice.inf_le_left

theorem has_fderiv_at_filter_congr' {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E} {L : filter E}
  (hx : f₀ x = f₁ x) (h₀ : {x | f₀ x = f₁ x} ∈ L) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at_filter K f₀ f₀' x L ↔ has_fderiv_at_filter K f₁ f₁' x L :=
by rw (funext h₁ : f₀' = f₁'); exact
and_congr_right (λ _, is_o_congr
  (by filter_upwards [h₀] λ x' (h:_=_), by simp [h, hx])
  (univ_mem_sets' $ λ _, rfl))

theorem has_fderiv_at_filter_congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E} {L : filter E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at_filter K f₀ f₀' x L ↔ has_fderiv_at_filter K f₁ f₁' x L :=
has_fderiv_at_filter_congr' (h₀ _) (univ_mem_sets' h₀) h₁

theorem has_fderiv_at_filter.congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E} {L : filter E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at_filter K f₀ f₀' x L → has_fderiv_at_filter K f₁ f₁' x L :=
(has_fderiv_at_filter_congr h₀ h₁).1

theorem has_fderiv_at_within_congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E} {s : set E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at_within K f₀ f₀' x s ↔ has_fderiv_at_within K f₁ f₁' x s :=
has_fderiv_at_filter_congr h₀ h₁

theorem has_fderiv_at_within.congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E} {s : set E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at_within K f₀ f₀' x s → has_fderiv_at_within K f₁ f₁' x s :=
(has_fderiv_at_within_congr h₀ h₁).1

theorem has_fderiv_at_congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at K f₀ f₀' x ↔ has_fderiv_at K f₁ f₁' x :=
has_fderiv_at_filter_congr h₀ h₁

theorem has_fderiv_at.congr {f₀ f₁ : E → F} {f₀' f₁' : E → F} {x : E}
  (h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
  has_fderiv_at K f₀ f₀' x → has_fderiv_at K f₁ f₁' x :=
(has_fderiv_at_congr h₀ h₁).1

theorem has_fderiv_at_filter_id (x : E) (L : filter E) : has_fderiv_at_filter K id id x L :=
⟨is_bounded_linear_map.id, (is_o_zero _ _).congr_left (by simp)⟩

theorem has_fderiv_at_within_id (x : E) (s : set E) : has_fderiv_at_within K id id x s :=
has_fderiv_at_filter_id _ _

theorem has_fderiv_at_id (x : E) : has_fderiv_at K id id x :=
has_fderiv_at_filter_id _ _

theorem has_fderiv_at_filter_const (c : F) (x : E) (L : filter E) :
  has_fderiv_at_filter K (λ x, c) (λ y, 0) x L :=
⟨is_bounded_linear_map.zero, (is_o_zero _ _).congr_left (by simp)⟩

theorem has_fderiv_at_within_const (c : F) (x : E) (s : set E) :
  has_fderiv_at_within K (λ x, c) (λ y, 0) x s :=
has_fderiv_at_filter_const _ _ _

theorem has_fderiv_at_const (c : F) (x : E) :
  has_fderiv_at K (λ x, c) (λ y, 0) x :=
has_fderiv_at_filter_const _ _ _

set_option class.instance_max_depth 43

theorem has_fderiv_at_filter_smul {f : E → F} {f' : E → F} {x : E} {L : filter E}
    (c : K) (h : has_fderiv_at_filter K f f' x L) :
  has_fderiv_at_filter K (λ x, c • f x) (λ x, c • f' x) x L :=
⟨is_bounded_linear_map.smul c h.left,
  (is_o_const_smul_left h.right c).congr_left $
  λ x, by simp [smul_neg, smul_add]⟩

theorem has_fderiv_at_within_smul {f : E → F} {f' : E → F} {x : E} {s : set E}
    (c : K) : has_fderiv_at_within K f f' x s →
  has_fderiv_at_within K (λ x, c • f x) (λ x, c • f' x) x s :=
has_fderiv_at_filter_smul _

theorem has_fderiv_at_smul {f : E → F} {f' : E → F} {x : E}
    (c : K) : has_fderiv_at K f f' x →
  has_fderiv_at K (λ x, c • f x) (λ x, c • f' x) x :=
has_fderiv_at_filter_smul _

theorem has_fderiv_at_filter_add {f g : E → F} {f' g' : E → F} {x : E} {L : filter E}
  (hf : has_fderiv_at_filter K f f' x L) (hg : has_fderiv_at_filter K g g' x L) :
  has_fderiv_at_filter K (λ x, f x + g x) (λ x, f' x + g' x) x L :=
⟨is_bounded_linear_map.add hf.left hg.left,
  (hf.right.add hg.right).congr_left (by simp)⟩

theorem has_fderiv_at_within_add {f g : E → F} {f' g' : E → F} {x : E} {s : set E} :
  has_fderiv_at_within K f f' x s → has_fderiv_at_within K g g' x s →
  has_fderiv_at_within K (λ x, f x + g x) (λ x, f' x + g' x) x s :=
has_fderiv_at_filter_add

theorem has_fderiv_at_add {f g : E → F} {f' g' : E → F} {x : E} :
  has_fderiv_at K f f' x → has_fderiv_at K g g' x →
  has_fderiv_at K (λ x, f x + g x) (λ x, f' x + g' x) x :=
has_fderiv_at_filter_add

theorem has_fderiv_at_filter_neg {f : E → F} {f' : E → F} {x : E} {L : filter E}
  (h : has_fderiv_at_filter K f f' x L) :
  has_fderiv_at_filter K (λ x, -f x) (λ x, -f' x) x L :=
(has_fderiv_at_filter_smul (-1 : K) h).congr (by simp) (by simp)

theorem has_fderiv_at_within_neg {f : E → F} {f' : E → F} {x : E} {s : set E} :
  has_fderiv_at_within K f f' x s → has_fderiv_at_within K (λ x, -f x) (λ x, -f' x) x s :=
has_fderiv_at_filter_neg

theorem has_fderiv_at_neg {f : E → F} {f' : E → F} {x : E} :
  has_fderiv_at K f f' x → has_fderiv_at K (λ x, -f x) (λ x, -f' x) x :=
has_fderiv_at_filter_neg

theorem has_fderiv_at_filter_sub {f g : E → F} {f' g' : E → F} {x : E} {L : filter E}
  (hf : has_fderiv_at_filter K f f' x L) (hg : has_fderiv_at_filter K g g' x L) :
  has_fderiv_at_filter K (λ x, f x - g x) (λ x, f' x - g' x) x L :=
has_fderiv_at_filter_add hf (has_fderiv_at_filter_neg hg)

theorem has_fderiv_at_within_sub {f g : E → F} {f' g' : E → F} {x : E} {s : set E} :
  has_fderiv_at_within K f f' x s → has_fderiv_at_within K g g' x s →
  has_fderiv_at_within K (λ x, f x - g x) (λ x, f' x - g' x) x s :=
has_fderiv_at_filter_sub

theorem has_fderiv_at_sub {f g : E → F} {f' g' : E → F} {x : E} :
  has_fderiv_at K f f' x → has_fderiv_at K g g' x →
  has_fderiv_at K (λ x, f x - g x) (λ x, f' x - g' x) x :=
has_fderiv_at_filter_sub

theorem has_fderiv_at_filter.is_O_sub {f : E → F} {f' : E → F} {x : E} {L : filter E}
  (h : has_fderiv_at_filter K f f' x L) : is_O (λ x', f x' - f x) (λ x', x' - x) L :=
h.2.to_is_O.congr_of_sub.2 (h.1.is_O_sub _ _)

theorem has_fderiv_at_filter.tendsto_nhds {f : E → F} {f' : E → F} {x : E} {L : filter E}
  (hL : L ≤ nhds x) (h : has_fderiv_at_filter K f f' x L) : tendsto f L (nhds (f x)) :=
begin
  have : tendsto (λ x', f x' - f x) L (nhds 0),
  { refine h.is_O_sub.trans_tendsto (tendsto_le_left hL _),
    rw ← sub_self x, exact tendsto_sub tendsto_id tendsto_const_nhds },
  have := tendsto_add this tendsto_const_nhds,
  rw zero_add (f x) at this,
  exact this.congr (by simp)
end

theorem has_fderiv_at_within.continuous_at_within {f : E → F} {f' : E → F} {x : E} {s : set E} :
  has_fderiv_at_within K f f' x s → continuous_at_within f x s :=
has_fderiv_at_filter.tendsto_nhds lattice.inf_le_left

theorem has_fderiv_at.continuous_at {f : E → F} {f' : E → F} {x : E} :
  has_fderiv_at K f f' x → continuous_at f x :=
has_fderiv_at_filter.tendsto_nhds (le_refl _)

theorem has_fderiv_at_filter.comp {g g' : F → G} {f f' : E → F} {L : filter E} {x : E}
  (hf : has_fderiv_at_filter K f f' x L)
  (hg : has_fderiv_at_filter K g g' (f x) (L.map f)) :
  has_fderiv_at_filter K (g ∘ f) (g' ∘ f') x L :=
⟨hg.1.comp hf.1, begin
  have eq₁ := (hg.1.is_O_comp _).trans_is_o hf.2,
  have eq₂ := ((hg.2.comp f).mono le_comap_map).trans_is_O hf.is_O_sub,
  refine eq₂.tri (eq₁.congr_left (λ x', _)),
  rw [show g' (_-_) = g' _ - g' _, from (hg.1.to_linear_map _).map_sub _ _]
end⟩

/- A readable version of the previous theorem, a general form of the chain rule. -/

example {g g' : F → G} {f f' : E → F} {L : filter E} {x : E}
  (hf : has_fderiv_at_filter K f f' x L)
  (hg : has_fderiv_at_filter K g g' (f x) (L.map f)) :
  has_fderiv_at_filter K (g ∘ f) (g' ∘ f') x L :=
⟨hg.1.comp hf.1,
begin
  have : is_o (λ x', g (f x') - g (f x) - g' (f x' - f x)) (λ x', f x' - f x) L,
    from (hg.2.comp f).mono le_comap_map,
  have eq₁ : is_o (λ x', g (f x') - g (f x) - g' (f x' - f x)) (λ x', x' - x) L,
    from this.trans_is_O hf.is_O_sub,
  have eq₂ : is_o (λ x', f x' - f x - f' (x' - x)) (λ x', x' - x) L,
    from hf.2,
  have : is_O (λ x', g' (f x' - f x - f' (x' - x))) (λ x', f x' - f x - f' (x' - x)) L,
    from hg.1.is_O_comp _,
  have : is_o (λ x', g' (f x' - f x - f' (x' - x))) (λ x', x' - x) L,
    from this.trans_is_o eq₂,
  have eq₃ : is_o (λ x', g' (f x' - f x) - (g' (f' (x' - x)))) (λ x', x' - x) L,
    by { refine this.congr_left (λ x', _),
         rw [show g' (_-_) = g' _ - g' _, from (hg.1.to_linear_map _).map_sub _ _] },
  exact eq₁.tri eq₃
end⟩

theorem has_fderiv_at_within.comp {g g' : F → G} {f f' : E → F} {s : set E} {x : E}
  (hf : has_fderiv_at_within K f f' x s)
  (hg : has_fderiv_at_within K g g' (f x) (f '' s)) :
  has_fderiv_at_within K (g ∘ f) (g' ∘ f') x s :=
hf.comp (has_fderiv_at_filter.mono
  hf.continuous_at_within.tendsto_nhds_within_image hg)

/-- The chain rule. -/
theorem has_fderiv_at.comp {g g' : F → G} {f f' : E → F} {x : E}
  (hf : has_fderiv_at K f f' x) (hg : has_fderiv_at K g g' (f x)) :
  has_fderiv_at K (g ∘ f) (g' ∘ f') x :=
hf.comp (hg.mono hf.continuous_at)

end

/-
In the special case of a normed space over the reals, we can use scalar multiplication in the
`tendsto` characterization of the Fréchet derivative.
-/

section

variables {E : Type*} [normed_space ℝ E]
variables {F : Type*} [normed_space ℝ F]
variables {G : Type*} [normed_space ℝ G]

set_option class.instance_max_depth 34

theorem has_fderiv_at_filter_real_equiv {f : E → F} {f' : E → F} {x : E} {L : filter E}
    (bf' : is_bounded_linear_map ℝ f') :
  tendsto (λ x' : E, ∥x' - x∥⁻¹ * ∥f x' - f x - f' (x' - x)∥) L (nhds 0) ↔
  tendsto (λ x' : E, ∥x' - x∥⁻¹ • (f x' - f x - f' (x' - x))) L (nhds 0) :=
begin
  have f'0 : f' 0 = 0 := (bf'.to_linear_map _).map_zero,
  symmetry, rw [tendsto_iff_norm_tendsto_zero], refine tendsto.congr'r (λ x', _),
  have : ∥x' + -x∥⁻¹ ≥ 0, from inv_nonneg.mpr (norm_nonneg _),
  simp [norm_smul, real.norm_eq_abs, abs_of_nonneg this]
end

end