/
asymptotics.lean
1725 lines (1294 loc) · 71.9 KB
/
asymptotics.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/-
Copyright (c) 2019 Jeremy Avigad. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jeremy Avigad, Yury Kudryashov
-/
import analysis.normed_space.basic
import topology.algebra.order.liminf_limsup
import topology.local_homeomorph
/-!
# Asymptotics
We introduce these relations:
* `is_O_with c l f g` : "f is big O of g along l with constant c";
* `f =O[l] g` : "f is big O of g along l";
* `f =o[l] g` : "f is little o of g along l".
Here `l` is any filter on the domain of `f` and `g`, which are assumed to be the same. The codomains
of `f` and `g` do not need to be the same; all that is needed that there is a norm associated with
these types, and it is the norm that is compared asymptotically.
The relation `is_O_with c` is introduced to factor out common algebraic arguments in the proofs of
similar properties of `is_O` and `is_o`. Usually proofs outside of this file should use `is_O`
instead.
Often the ranges of `f` and `g` will be the real numbers, in which case the norm is the absolute
value. In general, we have
`f =O[l] g ↔ (λ x, ∥f x∥) =O[l] (λ x, ∥g x∥)`,
and similarly for `is_o`. But our setup allows us to use the notions e.g. with functions
to the integers, rationals, complex numbers, or any normed vector space without mentioning the
norm explicitly.
If `f` and `g` are functions to a normed field like the reals or complex numbers and `g` is always
nonzero, we have
`f =o[l] g ↔ tendsto (λ x, f x / (g x)) l (𝓝 0)`.
In fact, the right-to-left direction holds without the hypothesis on `g`, and in the other direction
it suffices to assume that `f` is zero wherever `g` is. (This generalization is useful in defining
the Fréchet derivative.)
-/
open filter set
open_locale topological_space big_operators classical filter nnreal
namespace asymptotics
variables {α : Type*} {β : Type*} {E : Type*} {F : Type*} {G : Type*}
{E' : Type*} {F' : Type*} {G' : Type*}
{E'' : Type*} {F'' : Type*} {G'' : Type*}
{R : Type*} {R' : Type*} {𝕜 : Type*} {𝕜' : Type*}
variables [has_norm E] [has_norm F] [has_norm G]
variables [seminormed_add_comm_group E'] [seminormed_add_comm_group F']
[seminormed_add_comm_group G'] [normed_add_comm_group E''] [normed_add_comm_group F'']
[normed_add_comm_group G''] [semi_normed_ring R] [semi_normed_ring R']
variables [normed_field 𝕜] [normed_field 𝕜']
variables {c c' c₁ c₂ : ℝ} {f : α → E} {g : α → F} {k : α → G}
variables {f' : α → E'} {g' : α → F'} {k' : α → G'}
variables {f'' : α → E''} {g'' : α → F''} {k'' : α → G''}
variables {l l' : filter α}
section defs
/-! ### Definitions -/
/-- This version of the Landau notation `is_O_with C l f g` where `f` and `g` are two functions on
a type `α` and `l` is a filter on `α`, means that eventually for `l`, `∥f∥` is bounded by `C * ∥g∥`.
In other words, `∥f∥ / ∥g∥` is eventually bounded by `C`, modulo division by zero issues that are
avoided by this definition. Probably you want to use `is_O` instead of this relation. -/
@[irreducible]
def is_O_with (c : ℝ) (l : filter α) (f : α → E) (g : α → F) : Prop :=
∀ᶠ x in l, ∥ f x ∥ ≤ c * ∥ g x ∥
/-- Definition of `is_O_with`. We record it in a lemma as `is_O_with` is irreducible. -/
lemma is_O_with_iff : is_O_with c l f g ↔ ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥ := by rw is_O_with
alias is_O_with_iff ↔ is_O_with.bound is_O_with.of_bound
/-- The Landau notation `f =O[l] g` where `f` and `g` are two functions on a type `α` and `l` is
a filter on `α`, means that eventually for `l`, `∥f∥` is bounded by a constant multiple of `∥g∥`.
In other words, `∥f∥ / ∥g∥` is eventually bounded, modulo division by zero issues that are avoided
by this definition. -/
@[irreducible]
def is_O (l : filter α) (f : α → E) (g : α → F) : Prop := ∃ c : ℝ, is_O_with c l f g
notation f ` =O[`:100 l `] ` g:100 := is_O l f g
/-- Definition of `is_O` in terms of `is_O_with`. We record it in a lemma as `is_O` is
irreducible. -/
lemma is_O_iff_is_O_with : f =O[l] g ↔ ∃ c : ℝ, is_O_with c l f g := by rw is_O
/-- Definition of `is_O` in terms of filters. We record it in a lemma as we will set
`is_O` to be irreducible at the end of this file. -/
lemma is_O_iff : f =O[l] g ↔ ∃ c : ℝ, ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥ :=
by simp only [is_O, is_O_with]
lemma is_O.of_bound (c : ℝ) (h : ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥) : f =O[l] g :=
is_O_iff.2 ⟨c, h⟩
lemma is_O.of_bound' (h : ∀ᶠ x in l, ∥f x∥ ≤ ∥g x∥) : f =O[l] g :=
is_O.of_bound 1 $ by { simp_rw one_mul, exact h }
lemma is_O.bound : f =O[l] g → ∃ c : ℝ, ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥ := is_O_iff.1
/-- The Landau notation `f =o[l] g` where `f` and `g` are two functions on a type `α` and `l` is
a filter on `α`, means that eventually for `l`, `∥f∥` is bounded by an arbitrarily small constant
multiple of `∥g∥`. In other words, `∥f∥ / ∥g∥` tends to `0` along `l`, modulo division by zero
issues that are avoided by this definition. -/
@[irreducible]
def is_o (l : filter α) (f : α → E) (g : α → F) : Prop := ∀ ⦃c : ℝ⦄, 0 < c → is_O_with c l f g
notation f ` =o[`:100 l `] ` g:100 := is_o l f g
/-- Definition of `is_o` in terms of `is_O_with`. We record it in a lemma as we will set
`is_o` to be irreducible at the end of this file. -/
lemma is_o_iff_forall_is_O_with : f =o[l] g ↔ ∀ ⦃c : ℝ⦄, 0 < c → is_O_with c l f g := by rw is_o
alias is_o_iff_forall_is_O_with ↔ is_o.forall_is_O_with is_o.of_is_O_with
/-- Definition of `is_o` in terms of filters. We record it in a lemma as we will set
`is_o` to be irreducible at the end of this file. -/
lemma is_o_iff : f =o[l] g ↔ ∀ ⦃c : ℝ⦄, 0 < c → ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥ :=
by simp only [is_o, is_O_with]
alias is_o_iff ↔ is_o.bound is_o.of_bound
lemma is_o.def (h : f =o[l] g) (hc : 0 < c) : ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥ :=
is_o_iff.1 h hc
lemma is_o.def' (h : f =o[l] g) (hc : 0 < c) : is_O_with c l f g :=
is_O_with_iff.2 $ is_o_iff.1 h hc
end defs
/-! ### Conversions -/
theorem is_O_with.is_O (h : is_O_with c l f g) : f =O[l] g := by rw is_O; exact ⟨c, h⟩
theorem is_o.is_O_with (hgf : f =o[l] g) : is_O_with 1 l f g := hgf.def' zero_lt_one
theorem is_o.is_O (hgf : f =o[l] g) : f =O[l] g := hgf.is_O_with.is_O
lemma is_O.is_O_with : f =O[l] g → ∃ c : ℝ, is_O_with c l f g := is_O_iff_is_O_with.1
theorem is_O_with.weaken (h : is_O_with c l f g') (hc : c ≤ c') : is_O_with c' l f g' :=
is_O_with.of_bound $ mem_of_superset h.bound $ λ x hx,
calc ∥f x∥ ≤ c * ∥g' x∥ : hx
... ≤ _ : mul_le_mul_of_nonneg_right hc (norm_nonneg _)
theorem is_O_with.exists_pos (h : is_O_with c l f g') :
∃ c' (H : 0 < c'), is_O_with c' l f g' :=
⟨max c 1, lt_of_lt_of_le zero_lt_one (le_max_right c 1), h.weaken $ le_max_left c 1⟩
theorem is_O.exists_pos (h : f =O[l] g') : ∃ c (H : 0 < c), is_O_with c l f g' :=
let ⟨c, hc⟩ := h.is_O_with in hc.exists_pos
theorem is_O_with.exists_nonneg (h : is_O_with c l f g') :
∃ c' (H : 0 ≤ c'), is_O_with c' l f g' :=
let ⟨c, cpos, hc⟩ := h.exists_pos in ⟨c, le_of_lt cpos, hc⟩
theorem is_O.exists_nonneg (h : f =O[l] g') :
∃ c (H : 0 ≤ c), is_O_with c l f g' :=
let ⟨c, hc⟩ := h.is_O_with in hc.exists_nonneg
/-- `f = O(g)` if and only if `is_O_with c f g` for all sufficiently large `c`. -/
lemma is_O_iff_eventually_is_O_with : f =O[l] g' ↔ ∀ᶠ c in at_top, is_O_with c l f g' :=
is_O_iff_is_O_with.trans
⟨λ ⟨c, hc⟩, mem_at_top_sets.2 ⟨c, λ c' hc', hc.weaken hc'⟩, λ h, h.exists⟩
/-- `f = O(g)` if and only if `∀ᶠ x in l, ∥f x∥ ≤ c * ∥g x∥` for all sufficiently large `c`. -/
lemma is_O_iff_eventually : f =O[l] g' ↔ ∀ᶠ c in at_top, ∀ᶠ x in l, ∥f x∥ ≤ c * ∥g' x∥ :=
is_O_iff_eventually_is_O_with.trans $ by simp only [is_O_with]
lemma is_O.exists_mem_basis {ι} {p : ι → Prop} {s : ι → set α} (h : f =O[l] g')
(hb : l.has_basis p s) :
∃ (c : ℝ) (hc : 0 < c) (i : ι) (hi : p i), ∀ x ∈ s i, ∥f x∥ ≤ c * ∥g' x∥ :=
flip Exists₂.imp h.exists_pos $ λ c hc h,
by simpa only [is_O_with_iff, hb.eventually_iff, exists_prop] using h
lemma is_O_with_inv (hc : 0 < c) : is_O_with c⁻¹ l f g ↔ ∀ᶠ x in l, c * ∥f x∥ ≤ ∥g x∥ :=
by simp only [is_O_with, ← div_eq_inv_mul, le_div_iff' hc]
-- We prove this lemma with strange assumptions to get two lemmas below automatically
lemma is_o_iff_nat_mul_le_aux (h₀ : (∀ x, 0 ≤ ∥f x∥) ∨ ∀ x, 0 ≤ ∥g x∥) :
f =o[l] g ↔ ∀ n : ℕ, ∀ᶠ x in l, ↑n * ∥f x∥ ≤ ∥g x∥ :=
begin
split,
{ rintro H (_|n),
{ refine (H.def one_pos).mono (λ x h₀', _),
rw [nat.cast_zero, zero_mul],
refine h₀.elim (λ hf, (hf x).trans _) (λ hg, hg x),
rwa one_mul at h₀' },
{ have : (0 : ℝ) < n.succ, from nat.cast_pos.2 n.succ_pos,
exact (is_O_with_inv this).1 (H.def' $ inv_pos.2 this) } },
{ refine λ H, is_o_iff.2 (λ ε ε0, _),
rcases exists_nat_gt ε⁻¹ with ⟨n, hn⟩,
have hn₀ : (0 : ℝ) < n, from (inv_pos.2 ε0).trans hn,
refine ((is_O_with_inv hn₀).2 (H n)).bound.mono (λ x hfg, _),
refine hfg.trans (mul_le_mul_of_nonneg_right (inv_le_of_inv_le ε0 hn.le) _),
refine h₀.elim (λ hf, nonneg_of_mul_nonneg_right ((hf x).trans hfg) _) (λ h, h x),
exact inv_pos.2 hn₀ }
end
lemma is_o_iff_nat_mul_le : f =o[l] g' ↔ ∀ n : ℕ, ∀ᶠ x in l, ↑n * ∥f x∥ ≤ ∥g' x∥ :=
is_o_iff_nat_mul_le_aux (or.inr $ λ x, norm_nonneg _)
lemma is_o_iff_nat_mul_le' : f' =o[l] g ↔ ∀ n : ℕ, ∀ᶠ x in l, ↑n * ∥f' x∥ ≤ ∥g x∥ :=
is_o_iff_nat_mul_le_aux (or.inl $ λ x, norm_nonneg _)
/-! ### Subsingleton -/
@[nontriviality] lemma is_o_of_subsingleton [subsingleton E'] : f' =o[l] g' :=
is_o.of_bound $ λ c hc, by simp [subsingleton.elim (f' _) 0, mul_nonneg hc.le]
@[nontriviality] lemma is_O_of_subsingleton [subsingleton E'] : f' =O[l] g' :=
is_o_of_subsingleton.is_O
section congr
variables {f₁ f₂ : α → E} {g₁ g₂ : α → F}
/-! ### Congruence -/
theorem is_O_with_congr (hc : c₁ = c₂) (hf : f₁ =ᶠ[l] f₂) (hg : g₁ =ᶠ[l] g₂) :
is_O_with c₁ l f₁ g₁ ↔ is_O_with c₂ l f₂ g₂ :=
begin
unfold is_O_with,
subst c₂,
apply filter.eventually_congr,
filter_upwards [hf, hg] with _ e₁ e₂,
rw [e₁, e₂],
end
theorem is_O_with.congr' (h : is_O_with c₁ l f₁ g₁) (hc : c₁ = c₂) (hf : f₁ =ᶠ[l] f₂)
(hg : g₁ =ᶠ[l] g₂) : is_O_with c₂ l f₂ g₂ :=
(is_O_with_congr hc hf hg).mp h
theorem is_O_with.congr (h : is_O_with c₁ l f₁ g₁) (hc : c₁ = c₂) (hf : ∀ x, f₁ x = f₂ x)
(hg : ∀ x, g₁ x = g₂ x) : is_O_with c₂ l f₂ g₂ :=
h.congr' hc (univ_mem' hf) (univ_mem' hg)
theorem is_O_with.congr_left (h : is_O_with c l f₁ g) (hf : ∀ x, f₁ x = f₂ x) :
is_O_with c l f₂ g :=
h.congr rfl hf (λ _, rfl)
theorem is_O_with.congr_right (h : is_O_with c l f g₁) (hg : ∀ x, g₁ x = g₂ x) :
is_O_with c l f g₂ :=
h.congr rfl (λ _, rfl) hg
theorem is_O_with.congr_const (h : is_O_with c₁ l f g) (hc : c₁ = c₂) : is_O_with c₂ l f g :=
h.congr hc (λ _, rfl) (λ _, rfl)
theorem is_O_congr (hf : f₁ =ᶠ[l] f₂) (hg : g₁ =ᶠ[l] g₂) : f₁ =O[l] g₁ ↔ f₂ =O[l] g₂ :=
by { unfold is_O, exact exists_congr (λ c, is_O_with_congr rfl hf hg) }
theorem is_O.congr' (h : f₁ =O[l] g₁) (hf : f₁ =ᶠ[l] f₂) (hg : g₁ =ᶠ[l] g₂) : f₂ =O[l] g₂ :=
(is_O_congr hf hg).mp h
theorem is_O.congr (h : f₁ =O[l] g₁) (hf : ∀ x, f₁ x = f₂ x) (hg : ∀ x, g₁ x = g₂ x) :
f₂ =O[l] g₂ :=
h.congr' (univ_mem' hf) (univ_mem' hg)
theorem is_O.congr_left (h : f₁ =O[l] g) (hf : ∀ x, f₁ x = f₂ x) : f₂ =O[l] g :=
h.congr hf (λ _, rfl)
theorem is_O.congr_right (h : f =O[l] g₁) (hg : ∀ x, g₁ x = g₂ x) : f =O[l] g₂ :=
h.congr (λ _, rfl) hg
theorem is_o_congr (hf : f₁ =ᶠ[l] f₂) (hg : g₁ =ᶠ[l] g₂) : f₁ =o[l] g₁ ↔ f₂ =o[l] g₂ :=
by { unfold is_o, exact forall₂_congr (λ c hc, is_O_with_congr (eq.refl c) hf hg) }
theorem is_o.congr' (h : f₁ =o[l] g₁) (hf : f₁ =ᶠ[l] f₂) (hg : g₁ =ᶠ[l] g₂) : f₂ =o[l] g₂ :=
(is_o_congr hf hg).mp h
theorem is_o.congr (h : f₁ =o[l] g₁) (hf : ∀ x, f₁ x = f₂ x) (hg : ∀ x, g₁ x = g₂ x) :
f₂ =o[l] g₂ :=
h.congr' (univ_mem' hf) (univ_mem' hg)
theorem is_o.congr_left (h : f₁ =o[l] g) (hf : ∀ x, f₁ x = f₂ x) : f₂ =o[l] g :=
h.congr hf (λ _, rfl)
theorem is_o.congr_right (h : f =o[l] g₁) (hg : ∀ x, g₁ x = g₂ x) : f =o[l] g₂ :=
h.congr (λ _, rfl) hg
@[trans] theorem _root_.filter.eventually_eq.trans_is_O {f₁ f₂ : α → E} {g : α → F}
(hf : f₁ =ᶠ[l] f₂) (h : f₂ =O[l] g) : f₁ =O[l] g :=
h.congr' hf.symm eventually_eq.rfl
@[trans] theorem _root_.filter.eventually_eq.trans_is_o {f₁ f₂ : α → E} {g : α → F}
(hf : f₁ =ᶠ[l] f₂) (h : f₂ =o[l] g) : f₁ =o[l] g :=
h.congr' hf.symm eventually_eq.rfl
@[trans] theorem is_O.trans_eventually_eq {f : α → E} {g₁ g₂ : α → F}
(h : f =O[l] g₁) (hg : g₁ =ᶠ[l] g₂) : f =O[l] g₂ :=
h.congr' eventually_eq.rfl hg
@[trans] theorem is_o.trans_eventually_eq {f : α → E} {g₁ g₂ : α → F}
(h : f =o[l] g₁) (hg : g₁ =ᶠ[l] g₂) : f =o[l] g₂ :=
h.congr' eventually_eq.rfl hg
end congr
/-! ### Filter operations and transitivity -/
theorem is_O_with.comp_tendsto (hcfg : is_O_with c l f g)
{k : β → α} {l' : filter β} (hk : tendsto k l' l):
is_O_with c l' (f ∘ k) (g ∘ k) :=
is_O_with.of_bound $ hk hcfg.bound
theorem is_O.comp_tendsto (hfg : f =O[l] g) {k : β → α} {l' : filter β} (hk : tendsto k l' l) :
(f ∘ k) =O[l'] (g ∘ k) :=
is_O_iff_is_O_with.2 $ hfg.is_O_with.imp (λ c h, h.comp_tendsto hk)
theorem is_o.comp_tendsto (hfg : f =o[l] g) {k : β → α} {l' : filter β} (hk : tendsto k l' l) :
(f ∘ k) =o[l'] (g ∘ k) :=
is_o.of_is_O_with $ λ c cpos, (hfg.forall_is_O_with cpos).comp_tendsto hk
@[simp] theorem is_O_with_map {k : β → α} {l : filter β} :
is_O_with c (map k l) f g ↔ is_O_with c l (f ∘ k) (g ∘ k) :=
by { unfold is_O_with, exact eventually_map }
@[simp] theorem is_O_map {k : β → α} {l : filter β} : f =O[map k l] g ↔ (f ∘ k) =O[l] (g ∘ k) :=
by simp only [is_O, is_O_with_map]
@[simp] theorem is_o_map {k : β → α} {l : filter β} : f =o[map k l] g ↔ (f ∘ k) =o[l] (g ∘ k) :=
by simp only [is_o, is_O_with_map]
theorem is_O_with.mono (h : is_O_with c l' f g) (hl : l ≤ l') : is_O_with c l f g :=
is_O_with.of_bound $ hl h.bound
theorem is_O.mono (h : f =O[l'] g) (hl : l ≤ l') : f =O[l] g :=
is_O_iff_is_O_with.2 $ h.is_O_with.imp (λ c h, h.mono hl)
theorem is_o.mono (h : f =o[l'] g) (hl : l ≤ l') : f =o[l] g :=
is_o.of_is_O_with $ λ c cpos, (h.forall_is_O_with cpos).mono hl
theorem is_O_with.trans (hfg : is_O_with c l f g) (hgk : is_O_with c' l g k) (hc : 0 ≤ c) :
is_O_with (c * c') l f k :=
begin
unfold is_O_with at *,
filter_upwards [hfg, hgk] with x hx hx',
calc ∥f x∥ ≤ c * ∥g x∥ : hx
... ≤ c * (c' * ∥k x∥) : mul_le_mul_of_nonneg_left hx' hc
... = c * c' * ∥k x∥ : (mul_assoc _ _ _).symm
end
@[trans] theorem is_O.trans {f : α → E} {g : α → F'} {k : α → G} (hfg : f =O[l] g)
(hgk : g =O[l] k) : f =O[l] k :=
let ⟨c, cnonneg, hc⟩ := hfg.exists_nonneg, ⟨c', hc'⟩ := hgk.is_O_with in
(hc.trans hc' cnonneg).is_O
theorem is_o.trans_is_O_with (hfg : f =o[l] g) (hgk : is_O_with c l g k) (hc : 0 < c) :
f =o[l] k :=
begin
unfold is_o at *,
intros c' c'pos,
have : 0 < c' / c, from div_pos c'pos hc,
exact ((hfg this).trans hgk this.le).congr_const (div_mul_cancel _ hc.ne')
end
@[trans] theorem is_o.trans_is_O {f : α → E} {g : α → F} {k : α → G'} (hfg : f =o[l] g)
(hgk : g =O[l] k) :
f =o[l] k :=
let ⟨c, cpos, hc⟩ := hgk.exists_pos in hfg.trans_is_O_with hc cpos
theorem is_O_with.trans_is_o (hfg : is_O_with c l f g) (hgk : g =o[l] k) (hc : 0 < c) :
f =o[l] k :=
begin
unfold is_o at *,
intros c' c'pos,
have : 0 < c' / c, from div_pos c'pos hc,
exact (hfg.trans (hgk this) hc.le).congr_const (mul_div_cancel' _ hc.ne')
end
@[trans] theorem is_O.trans_is_o {f : α → E} {g : α → F'} {k : α → G} (hfg : f =O[l] g)
(hgk : g =o[l] k) :
f =o[l] k :=
let ⟨c, cpos, hc⟩ := hfg.exists_pos in hc.trans_is_o hgk cpos
@[trans] theorem is_o.trans {f : α → E} {g : α → F} {k : α → G} (hfg : f =o[l] g)
(hgk : g =o[l] k) : f =o[l] k :=
hfg.trans_is_O_with hgk.is_O_with one_pos
lemma _root_.filter.eventually.trans_is_O {f : α → E} {g : α → F'} {k : α → G}
(hfg : ∀ᶠ x in l, ∥f x∥ ≤ ∥g x∥) (hgk : g =O[l] k) : f =O[l] k :=
(is_O.of_bound' hfg).trans hgk
lemma _root_.filter.eventually.is_O {f : α → E} {g : α → ℝ} {l : filter α}
(hfg : ∀ᶠ x in l, ∥f x∥ ≤ g x) : f =O[l] g :=
is_O.of_bound' $ hfg.mono $ λ x hx, hx.trans $ real.le_norm_self _
section
variable (l)
theorem is_O_with_of_le' (hfg : ∀ x, ∥f x∥ ≤ c * ∥g x∥) : is_O_with c l f g :=
is_O_with.of_bound $ univ_mem' hfg
theorem is_O_with_of_le (hfg : ∀ x, ∥f x∥ ≤ ∥g x∥) : is_O_with 1 l f g :=
is_O_with_of_le' l $ λ x, by { rw one_mul, exact hfg x }
theorem is_O_of_le' (hfg : ∀ x, ∥f x∥ ≤ c * ∥g x∥) : f =O[l] g :=
(is_O_with_of_le' l hfg).is_O
theorem is_O_of_le (hfg : ∀ x, ∥f x∥ ≤ ∥g x∥) : f =O[l] g :=
(is_O_with_of_le l hfg).is_O
end
theorem is_O_with_refl (f : α → E) (l : filter α) : is_O_with 1 l f f :=
is_O_with_of_le l $ λ _, le_rfl
theorem is_O_refl (f : α → E) (l : filter α) : f =O[l] f := (is_O_with_refl f l).is_O
theorem is_O_with.trans_le (hfg : is_O_with c l f g) (hgk : ∀ x, ∥g x∥ ≤ ∥k x∥) (hc : 0 ≤ c) :
is_O_with c l f k :=
(hfg.trans (is_O_with_of_le l hgk) hc).congr_const $ mul_one c
theorem is_O.trans_le (hfg : f =O[l] g') (hgk : ∀ x, ∥g' x∥ ≤ ∥k x∥) : f =O[l] k :=
hfg.trans (is_O_of_le l hgk)
theorem is_o.trans_le (hfg : f =o[l] g) (hgk : ∀ x, ∥g x∥ ≤ ∥k x∥) : f =o[l] k :=
hfg.trans_is_O_with (is_O_with_of_le _ hgk) zero_lt_one
theorem is_o_irrefl' (h : ∃ᶠ x in l, ∥f' x∥ ≠ 0) : ¬f' =o[l] f' :=
begin
intro ho,
rcases ((ho.bound one_half_pos).and_frequently h).exists with ⟨x, hle, hne⟩,
rw [one_div, ← div_eq_inv_mul] at hle,
exact (half_lt_self (lt_of_le_of_ne (norm_nonneg _) hne.symm)).not_le hle
end
theorem is_o_irrefl (h : ∃ᶠ x in l, f'' x ≠ 0) : ¬f'' =o[l] f'' :=
is_o_irrefl' $ h.mono $ λ x, norm_ne_zero_iff.mpr
theorem is_O.not_is_o (h : f'' =O[l] g') (hf : ∃ᶠ x in l, f'' x ≠ 0) : ¬g' =o[l] f'' :=
λ h', is_o_irrefl hf (h.trans_is_o h')
theorem is_o.not_is_O (h : f'' =o[l] g') (hf : ∃ᶠ x in l, f'' x ≠ 0) : ¬g' =O[l] f'' :=
λ h', is_o_irrefl hf (h.trans_is_O h')
section bot
variables (c f g)
@[simp] theorem is_O_with_bot : is_O_with c ⊥ f g := is_O_with.of_bound $ trivial
@[simp] theorem is_O_bot : f =O[⊥] g := (is_O_with_bot 1 f g).is_O
@[simp] theorem is_o_bot : f =o[⊥] g := is_o.of_is_O_with $ λ c _, is_O_with_bot c f g
end bot
@[simp] theorem is_O_with_pure {x} : is_O_with c (pure x) f g ↔ ∥f x∥ ≤ c * ∥g x∥ := is_O_with_iff
theorem is_O_with.sup (h : is_O_with c l f g) (h' : is_O_with c l' f g) :
is_O_with c (l ⊔ l') f g :=
is_O_with.of_bound $ mem_sup.2 ⟨h.bound, h'.bound⟩
theorem is_O_with.sup' (h : is_O_with c l f g') (h' : is_O_with c' l' f g') :
is_O_with (max c c') (l ⊔ l') f g' :=
is_O_with.of_bound $
mem_sup.2 ⟨(h.weaken $ le_max_left c c').bound, (h'.weaken $ le_max_right c c').bound⟩
theorem is_O.sup (h : f =O[l] g') (h' : f =O[l'] g') : f =O[l ⊔ l'] g' :=
let ⟨c, hc⟩ := h.is_O_with, ⟨c', hc'⟩ := h'.is_O_with in (hc.sup' hc').is_O
theorem is_o.sup (h : f =o[l] g) (h' : f =o[l'] g) : f =o[l ⊔ l'] g :=
is_o.of_is_O_with $ λ c cpos, (h.forall_is_O_with cpos).sup (h'.forall_is_O_with cpos)
@[simp] lemma is_O_sup : f =O[l ⊔ l'] g' ↔ f =O[l] g' ∧ f =O[l'] g' :=
⟨λ h, ⟨h.mono le_sup_left, h.mono le_sup_right⟩, λ h, h.1.sup h.2⟩
@[simp] lemma is_o_sup : f =o[l ⊔ l'] g ↔ f =o[l] g ∧ f =o[l'] g :=
⟨λ h, ⟨h.mono le_sup_left, h.mono le_sup_right⟩, λ h, h.1.sup h.2⟩
lemma is_O_with_insert [topological_space α] {x : α} {s : set α} {C : ℝ} {g : α → E} {g' : α → F}
(h : ∥g x∥ ≤ C * ∥g' x∥) :
is_O_with C (𝓝[insert x s] x) g g' ↔ is_O_with C (𝓝[s] x) g g' :=
by simp_rw [is_O_with, nhds_within_insert, eventually_sup, eventually_pure, h, true_and]
lemma is_O_with.insert [topological_space α] {x : α} {s : set α} {C : ℝ} {g : α → E} {g' : α → F}
(h1 : is_O_with C (𝓝[s] x) g g') (h2 : ∥g x∥ ≤ C * ∥g' x∥) :
is_O_with C (𝓝[insert x s] x) g g' :=
(is_O_with_insert h2).mpr h1
lemma is_o_insert [topological_space α] {x : α} {s : set α} {g : α → E'} {g' : α → F'}
(h : g x = 0) : g =o[𝓝[insert x s] x] g' ↔ g =o[𝓝[s] x] g' :=
begin
simp_rw [is_o],
refine forall_congr (λ c, forall_congr (λ hc, _)),
rw [is_O_with_insert],
rw [h, norm_zero],
exact mul_nonneg hc.le (norm_nonneg _)
end
lemma is_o.insert [topological_space α] {x : α} {s : set α} {g : α → E'} {g' : α → F'}
(h1 : g =o[𝓝[s] x] g') (h2 : g x = 0) : g =o[𝓝[insert x s] x] g' :=
(is_o_insert h2).mpr h1
/-! ### Simplification : norm, abs -/
section norm_abs
variables {u v : α → ℝ}
@[simp] theorem is_O_with_norm_right : is_O_with c l f (λ x, ∥g' x∥) ↔ is_O_with c l f g' :=
by simp only [is_O_with, norm_norm]
@[simp] theorem is_O_with_abs_right : is_O_with c l f (λ x, |u x|) ↔ is_O_with c l f u :=
@is_O_with_norm_right _ _ _ _ _ _ f u l
alias is_O_with_norm_right ↔ is_O_with.of_norm_right is_O_with.norm_right
alias is_O_with_abs_right ↔ is_O_with.of_abs_right is_O_with.abs_right
@[simp] theorem is_O_norm_right : f =O[l] (λ x, ∥g' x∥) ↔ f =O[l] g' :=
by { unfold is_O, exact exists_congr (λ _, is_O_with_norm_right) }
@[simp] theorem is_O_abs_right : f =O[l] (λ x, |u x|) ↔ f =O[l] u :=
@is_O_norm_right _ _ ℝ _ _ _ _ _
alias is_O_norm_right ↔ is_O.of_norm_right is_O.norm_right
alias is_O_abs_right ↔ is_O.of_abs_right is_O.abs_right
@[simp] theorem is_o_norm_right : f =o[l] (λ x, ∥g' x∥) ↔ f =o[l] g' :=
by { unfold is_o, exact forall₂_congr (λ _ _, is_O_with_norm_right) }
@[simp] theorem is_o_abs_right : f =o[l] (λ x, |u x|) ↔ f =o[l] u :=
@is_o_norm_right _ _ ℝ _ _ _ _ _
alias is_o_norm_right ↔ is_o.of_norm_right is_o.norm_right
alias is_o_abs_right ↔ is_o.of_abs_right is_o.abs_right
@[simp] theorem is_O_with_norm_left : is_O_with c l (λ x, ∥f' x∥) g ↔ is_O_with c l f' g :=
by simp only [is_O_with, norm_norm]
@[simp] theorem is_O_with_abs_left : is_O_with c l (λ x, |u x|) g ↔ is_O_with c l u g :=
@is_O_with_norm_left _ _ _ _ _ _ g u l
alias is_O_with_norm_left ↔ is_O_with.of_norm_left is_O_with.norm_left
alias is_O_with_abs_left ↔ is_O_with.of_abs_left is_O_with.abs_left
@[simp] theorem is_O_norm_left : (λ x, ∥f' x∥) =O[l] g ↔ f' =O[l] g :=
by { unfold is_O, exact exists_congr (λ _, is_O_with_norm_left) }
@[simp] theorem is_O_abs_left : (λ x, |u x|) =O[l] g ↔ u =O[l] g :=
@is_O_norm_left _ _ _ _ _ g u l
alias is_O_norm_left ↔ is_O.of_norm_left is_O.norm_left
alias is_O_abs_left ↔ is_O.of_abs_left is_O.abs_left
@[simp] theorem is_o_norm_left : (λ x, ∥f' x∥) =o[l] g ↔ f' =o[l] g :=
by { unfold is_o, exact forall₂_congr (λ _ _, is_O_with_norm_left) }
@[simp] theorem is_o_abs_left : (λ x, |u x|) =o[l] g ↔ u =o[l] g :=
@is_o_norm_left _ _ _ _ _ g u l
alias is_o_norm_left ↔ is_o.of_norm_left is_o.norm_left
alias is_o_abs_left ↔ is_o.of_abs_left is_o.abs_left
theorem is_O_with_norm_norm : is_O_with c l (λ x, ∥f' x∥) (λ x, ∥g' x∥) ↔ is_O_with c l f' g' :=
is_O_with_norm_left.trans is_O_with_norm_right
theorem is_O_with_abs_abs : is_O_with c l (λ x, |u x|) (λ x, |v x|) ↔ is_O_with c l u v :=
is_O_with_abs_left.trans is_O_with_abs_right
alias is_O_with_norm_norm ↔ is_O_with.of_norm_norm is_O_with.norm_norm
alias is_O_with_abs_abs ↔ is_O_with.of_abs_abs is_O_with.abs_abs
theorem is_O_norm_norm : (λ x, ∥f' x∥) =O[l] (λ x, ∥g' x∥) ↔ f' =O[l] g' :=
is_O_norm_left.trans is_O_norm_right
theorem is_O_abs_abs : (λ x, |u x|) =O[l] (λ x, |v x|) ↔ u =O[l] v :=
is_O_abs_left.trans is_O_abs_right
alias is_O_norm_norm ↔ is_O.of_norm_norm is_O.norm_norm
alias is_O_abs_abs ↔ is_O.of_abs_abs is_O.abs_abs
theorem is_o_norm_norm : (λ x, ∥f' x∥) =o[l] (λ x, ∥g' x∥) ↔ f' =o[l] g' :=
is_o_norm_left.trans is_o_norm_right
theorem is_o_abs_abs : (λ x, |u x|) =o[l] (λ x, |v x|) ↔ u =o[l] v :=
is_o_abs_left.trans is_o_abs_right
alias is_o_norm_norm ↔ is_o.of_norm_norm is_o.norm_norm
alias is_o_abs_abs ↔ is_o.of_abs_abs is_o.abs_abs
end norm_abs
/-! ### Simplification: negate -/
@[simp] theorem is_O_with_neg_right : is_O_with c l f (λ x, -(g' x)) ↔ is_O_with c l f g' :=
by simp only [is_O_with, norm_neg]
alias is_O_with_neg_right ↔ is_O_with.of_neg_right is_O_with.neg_right
@[simp] theorem is_O_neg_right : f =O[l] (λ x, -(g' x)) ↔ f =O[l] g' :=
by { unfold is_O, exact exists_congr (λ _, is_O_with_neg_right) }
alias is_O_neg_right ↔ is_O.of_neg_right is_O.neg_right
@[simp] theorem is_o_neg_right : f =o[l] (λ x, -(g' x)) ↔ f =o[l] g' :=
by { unfold is_o, exact forall₂_congr (λ _ _, is_O_with_neg_right) }
alias is_o_neg_right ↔ is_o.of_neg_right is_o.neg_right
@[simp] theorem is_O_with_neg_left : is_O_with c l (λ x, -(f' x)) g ↔ is_O_with c l f' g :=
by simp only [is_O_with, norm_neg]
alias is_O_with_neg_left ↔ is_O_with.of_neg_left is_O_with.neg_left
@[simp] theorem is_O_neg_left : (λ x, -(f' x)) =O[l] g ↔ f' =O[l] g :=
by { unfold is_O, exact exists_congr (λ _, is_O_with_neg_left) }
alias is_O_neg_left ↔ is_O.of_neg_left is_O.neg_left
@[simp] theorem is_o_neg_left : (λ x, -(f' x)) =o[l] g ↔ f' =o[l] g :=
by { unfold is_o, exact forall₂_congr (λ _ _, is_O_with_neg_left) }
alias is_o_neg_left ↔ is_o.of_neg_right is_o.neg_left
/-! ### Product of functions (right) -/
lemma is_O_with_fst_prod : is_O_with 1 l f' (λ x, (f' x, g' x)) :=
is_O_with_of_le l $ λ x, le_max_left _ _
lemma is_O_with_snd_prod : is_O_with 1 l g' (λ x, (f' x, g' x)) :=
is_O_with_of_le l $ λ x, le_max_right _ _
lemma is_O_fst_prod : f' =O[l] (λ x, (f' x, g' x)) := is_O_with_fst_prod.is_O
lemma is_O_snd_prod : g' =O[l] (λ x, (f' x, g' x)) := is_O_with_snd_prod.is_O
lemma is_O_fst_prod' {f' : α → E' × F'} : (λ x, (f' x).1) =O[l] f' :=
by simpa [is_O, is_O_with] using is_O_fst_prod
lemma is_O_snd_prod' {f' : α → E' × F'} : (λ x, (f' x).2) =O[l] f' :=
by simpa [is_O, is_O_with] using is_O_snd_prod
section
variables (f' k')
lemma is_O_with.prod_rightl (h : is_O_with c l f g') (hc : 0 ≤ c) :
is_O_with c l f (λ x, (g' x, k' x)) :=
(h.trans is_O_with_fst_prod hc).congr_const (mul_one c)
lemma is_O.prod_rightl (h : f =O[l] g') : f =O[l] (λ x, (g' x, k' x)) :=
let ⟨c, cnonneg, hc⟩ := h.exists_nonneg in (hc.prod_rightl k' cnonneg).is_O
lemma is_o.prod_rightl (h : f =o[l] g') : f =o[l] (λ x, (g' x, k' x)) :=
is_o.of_is_O_with $ λ c cpos, (h.forall_is_O_with cpos).prod_rightl k' cpos.le
lemma is_O_with.prod_rightr (h : is_O_with c l f g') (hc : 0 ≤ c) :
is_O_with c l f (λ x, (f' x, g' x)) :=
(h.trans is_O_with_snd_prod hc).congr_const (mul_one c)
lemma is_O.prod_rightr (h : f =O[l] g') : f =O[l] (λ x, (f' x, g' x)) :=
let ⟨c, cnonneg, hc⟩ := h.exists_nonneg in (hc.prod_rightr f' cnonneg).is_O
lemma is_o.prod_rightr (h : f =o[l] g') : f =o[l] (λx, (f' x, g' x)) :=
is_o.of_is_O_with $ λ c cpos, (h.forall_is_O_with cpos).prod_rightr f' cpos.le
end
lemma is_O_with.prod_left_same (hf : is_O_with c l f' k') (hg : is_O_with c l g' k') :
is_O_with c l (λ x, (f' x, g' x)) k' :=
by rw is_O_with_iff at *; filter_upwards [hf, hg] with x using max_le
lemma is_O_with.prod_left (hf : is_O_with c l f' k') (hg : is_O_with c' l g' k') :
is_O_with (max c c') l (λ x, (f' x, g' x)) k' :=
(hf.weaken $ le_max_left c c').prod_left_same (hg.weaken $ le_max_right c c')
lemma is_O_with.prod_left_fst (h : is_O_with c l (λ x, (f' x, g' x)) k') :
is_O_with c l f' k' :=
(is_O_with_fst_prod.trans h zero_le_one).congr_const $ one_mul c
lemma is_O_with.prod_left_snd (h : is_O_with c l (λ x, (f' x, g' x)) k') :
is_O_with c l g' k' :=
(is_O_with_snd_prod.trans h zero_le_one).congr_const $ one_mul c
lemma is_O_with_prod_left :
is_O_with c l (λ x, (f' x, g' x)) k' ↔ is_O_with c l f' k' ∧ is_O_with c l g' k' :=
⟨λ h, ⟨h.prod_left_fst, h.prod_left_snd⟩, λ h, h.1.prod_left_same h.2⟩
lemma is_O.prod_left (hf : f' =O[l] k') (hg : g' =O[l] k') : (λ x, (f' x, g' x)) =O[l] k' :=
let ⟨c, hf⟩ := hf.is_O_with, ⟨c', hg⟩ := hg.is_O_with in (hf.prod_left hg).is_O
lemma is_O.prod_left_fst : (λ x, (f' x, g' x)) =O[l] k' → f' =O[l] k' := is_O.trans is_O_fst_prod
lemma is_O.prod_left_snd : (λ x, (f' x, g' x)) =O[l] k' → g' =O[l] k' := is_O.trans is_O_snd_prod
@[simp] lemma is_O_prod_left : (λ x, (f' x, g' x)) =O[l] k' ↔ f' =O[l] k' ∧ g' =O[l] k' :=
⟨λ h, ⟨h.prod_left_fst, h.prod_left_snd⟩, λ h, h.1.prod_left h.2⟩
lemma is_o.prod_left (hf : f' =o[l] k') (hg : g' =o[l] k') : (λ x, (f' x, g' x)) =o[l] k' :=
is_o.of_is_O_with $ λ c hc, (hf.forall_is_O_with hc).prod_left_same (hg.forall_is_O_with hc)
lemma is_o.prod_left_fst : (λ x, (f' x, g' x)) =o[l] k' → f' =o[l] k' :=
is_O.trans_is_o is_O_fst_prod
lemma is_o.prod_left_snd : (λ x, (f' x, g' x)) =o[l] k' → g' =o[l] k' :=
is_O.trans_is_o is_O_snd_prod
@[simp] lemma is_o_prod_left : (λ x, (f' x, g' x)) =o[l] k' ↔ f' =o[l] k' ∧ g' =o[l] k' :=
⟨λ h, ⟨h.prod_left_fst, h.prod_left_snd⟩, λ h, h.1.prod_left h.2⟩
lemma is_O_with.eq_zero_imp (h : is_O_with c l f'' g'') : ∀ᶠ x in l, g'' x = 0 → f'' x = 0 :=
eventually.mono h.bound $ λ x hx hg, norm_le_zero_iff.1 $ by simpa [hg] using hx
lemma is_O.eq_zero_imp (h : f'' =O[l] g'') : ∀ᶠ x in l, g'' x = 0 → f'' x = 0 :=
let ⟨C, hC⟩ := h.is_O_with in hC.eq_zero_imp
/-! ### Addition and subtraction -/
section add_sub
variables {f₁ f₂ : α → E'} {g₁ g₂ : α → F'}
theorem is_O_with.add (h₁ : is_O_with c₁ l f₁ g) (h₂ : is_O_with c₂ l f₂ g) :
is_O_with (c₁ + c₂) l (λ x, f₁ x + f₂ x) g :=
by rw is_O_with at *; filter_upwards [h₁, h₂] with x hx₁ hx₂ using
calc ∥f₁ x + f₂ x∥ ≤ c₁ * ∥g x∥ + c₂ * ∥g x∥ : norm_add_le_of_le hx₁ hx₂
... = (c₁ + c₂) * ∥g x∥ : (add_mul _ _ _).symm
theorem is_O.add (h₁ : f₁ =O[l] g) (h₂ : f₂ =O[l] g) : (λ x, f₁ x + f₂ x) =O[l] g :=
let ⟨c₁, hc₁⟩ := h₁.is_O_with, ⟨c₂, hc₂⟩ := h₂.is_O_with in (hc₁.add hc₂).is_O
theorem is_o.add (h₁ : f₁ =o[l] g) (h₂ : f₂ =o[l] g) : (λ x, f₁ x + f₂ x) =o[l] g :=
is_o.of_is_O_with $ λ c cpos, ((h₁.forall_is_O_with $ half_pos cpos).add
(h₂.forall_is_O_with $ half_pos cpos)).congr_const (add_halves c)
theorem is_o.add_add (h₁ : f₁ =o[l] g₁) (h₂ : f₂ =o[l] g₂) :
(λ x, f₁ x + f₂ x) =o[l] (λ x, ∥g₁ x∥ + ∥g₂ x∥) :=
by refine (h₁.trans_le $ λ x, _).add (h₂.trans_le _);
simp [abs_of_nonneg, add_nonneg]
theorem is_O.add_is_o (h₁ : f₁ =O[l] g) (h₂ : f₂ =o[l] g) : (λ x, f₁ x + f₂ x) =O[l] g :=
h₁.add h₂.is_O
theorem is_o.add_is_O (h₁ : f₁ =o[l] g) (h₂ : f₂ =O[l] g) : (λ x, f₁ x + f₂ x) =O[l] g :=
h₁.is_O.add h₂
theorem is_O_with.add_is_o (h₁ : is_O_with c₁ l f₁ g) (h₂ : f₂ =o[l] g) (hc : c₁ < c₂) :
is_O_with c₂ l (λx, f₁ x + f₂ x) g :=
(h₁.add (h₂.forall_is_O_with (sub_pos.2 hc))).congr_const (add_sub_cancel'_right _ _)
theorem is_o.add_is_O_with (h₁ : f₁ =o[l] g) (h₂ : is_O_with c₁ l f₂ g) (hc : c₁ < c₂) :
is_O_with c₂ l (λx, f₁ x + f₂ x) g :=
(h₂.add_is_o h₁ hc).congr_left $ λ _, add_comm _ _
theorem is_O_with.sub (h₁ : is_O_with c₁ l f₁ g) (h₂ : is_O_with c₂ l f₂ g) :
is_O_with (c₁ + c₂) l (λ x, f₁ x - f₂ x) g :=
by simpa only [sub_eq_add_neg] using h₁.add h₂.neg_left
theorem is_O_with.sub_is_o (h₁ : is_O_with c₁ l f₁ g) (h₂ : f₂ =o[l] g) (hc : c₁ < c₂) :
is_O_with c₂ l (λ x, f₁ x - f₂ x) g :=
by simpa only [sub_eq_add_neg] using h₁.add_is_o h₂.neg_left hc
theorem is_O.sub (h₁ : f₁ =O[l] g) (h₂ : f₂ =O[l] g) : (λ x, f₁ x - f₂ x) =O[l] g :=
by simpa only [sub_eq_add_neg] using h₁.add h₂.neg_left
theorem is_o.sub (h₁ : f₁ =o[l] g) (h₂ : f₂ =o[l] g) : (λ x, f₁ x - f₂ x) =o[l] g :=
by simpa only [sub_eq_add_neg] using h₁.add h₂.neg_left
end add_sub
/-! ### Lemmas about `is_O (f₁ - f₂) g l` / `is_o (f₁ - f₂) g l` treated as a binary relation -/
section is_oO_as_rel
variables {f₁ f₂ f₃ : α → E'}
theorem is_O_with.symm (h : is_O_with c l (λ x, f₁ x - f₂ x) g) :
is_O_with c l (λ x, f₂ x - f₁ x) g :=
h.neg_left.congr_left $ λ x, neg_sub _ _
theorem is_O_with_comm :
is_O_with c l (λ x, f₁ x - f₂ x) g ↔ is_O_with c l (λ x, f₂ x - f₁ x) g :=
⟨is_O_with.symm, is_O_with.symm⟩
theorem is_O.symm (h : (λ x, f₁ x - f₂ x) =O[l] g) : (λ x, f₂ x - f₁ x) =O[l] g :=
h.neg_left.congr_left $ λ x, neg_sub _ _
theorem is_O_comm : (λ x, f₁ x - f₂ x) =O[l] g ↔ (λ x, f₂ x - f₁ x) =O[l] g :=
⟨is_O.symm, is_O.symm⟩
theorem is_o.symm (h : (λ x, f₁ x - f₂ x) =o[l] g) : (λ x, f₂ x - f₁ x) =o[l] g :=
by simpa only [neg_sub] using h.neg_left
theorem is_o_comm : (λ x, f₁ x - f₂ x) =o[l] g ↔ (λ x, f₂ x - f₁ x) =o[l] g :=
⟨is_o.symm, is_o.symm⟩
theorem is_O_with.triangle (h₁ : is_O_with c l (λ x, f₁ x - f₂ x) g)
(h₂ : is_O_with c' l (λ x, f₂ x - f₃ x) g) :
is_O_with (c + c') l (λ x, f₁ x - f₃ x) g :=
(h₁.add h₂).congr_left $ λ x, sub_add_sub_cancel _ _ _
theorem is_O.triangle (h₁ : (λ x, f₁ x - f₂ x) =O[l] g) (h₂ : (λ x, f₂ x - f₃ x) =O[l] g) :
(λ x, f₁ x - f₃ x) =O[l] g :=
(h₁.add h₂).congr_left $ λ x, sub_add_sub_cancel _ _ _
theorem is_o.triangle (h₁ : (λ x, f₁ x - f₂ x) =o[l] g) (h₂ : (λ x, f₂ x - f₃ x) =o[l] g) :
(λ x, f₁ x - f₃ x) =o[l] g :=
(h₁.add h₂).congr_left $ λ x, sub_add_sub_cancel _ _ _
theorem is_O.congr_of_sub (h : (λ x, f₁ x - f₂ x) =O[l] g) : f₁ =O[l] g ↔ f₂ =O[l] g :=
⟨λ h', (h'.sub h).congr_left (λ x, sub_sub_cancel _ _),
λ h', (h.add h').congr_left (λ x, sub_add_cancel _ _)⟩
theorem is_o.congr_of_sub (h : (λ x, f₁ x - f₂ x) =o[l] g) : f₁ =o[l] g ↔ f₂ =o[l] g :=
⟨λ h', (h'.sub h).congr_left (λ x, sub_sub_cancel _ _),
λ h', (h.add h').congr_left (λ x, sub_add_cancel _ _)⟩
end is_oO_as_rel
/-! ### Zero, one, and other constants -/
section zero_const
variables (g g' l)
theorem is_o_zero : (λ x, (0 : E')) =o[l] g' :=
is_o.of_bound $ λ c hc, univ_mem' $ λ x,
by simpa using mul_nonneg hc.le (norm_nonneg $ g' x)
theorem is_O_with_zero (hc : 0 ≤ c) : is_O_with c l (λ x, (0 : E')) g' :=
is_O_with.of_bound $ univ_mem' $ λ x, by simpa using mul_nonneg hc (norm_nonneg $ g' x)
theorem is_O_with_zero' : is_O_with 0 l (λ x, (0 : E')) g :=
is_O_with.of_bound $ univ_mem' $ λ x, by simp
theorem is_O_zero : (λ x, (0 : E')) =O[l] g :=
is_O_iff_is_O_with.2 ⟨0, is_O_with_zero' _ _⟩
theorem is_O_refl_left : (λ x, f' x - f' x) =O[l] g' :=
(is_O_zero g' l).congr_left $ λ x, (sub_self _).symm
theorem is_o_refl_left : (λ x, f' x - f' x) =o[l] g' :=
(is_o_zero g' l).congr_left $ λ x, (sub_self _).symm
variables {g g' l}
@[simp] theorem is_O_with_zero_right_iff :
is_O_with c l f'' (λ x, (0 : F')) ↔ f'' =ᶠ[l] 0 :=
by simp only [is_O_with, exists_prop, true_and, norm_zero, mul_zero, norm_le_zero_iff,
eventually_eq, pi.zero_apply]
@[simp] theorem is_O_zero_right_iff : f'' =O[l] (λ x, (0 : F')) ↔ f'' =ᶠ[l] 0 :=
⟨λ h, let ⟨c, hc⟩ := h.is_O_with in is_O_with_zero_right_iff.1 hc,
λ h, (is_O_with_zero_right_iff.2 h : is_O_with 1 _ _ _).is_O⟩
@[simp] theorem is_o_zero_right_iff :
f'' =o[l] (λ x, (0 : F')) ↔ f'' =ᶠ[l] 0 :=
⟨λ h, is_O_zero_right_iff.1 h.is_O, λ h, is_o.of_is_O_with $ λ c hc, is_O_with_zero_right_iff.2 h⟩
theorem is_O_with_const_const (c : E) {c' : F''} (hc' : c' ≠ 0) (l : filter α) :
is_O_with (∥c∥ / ∥c'∥) l (λ x : α, c) (λ x, c') :=
begin
unfold is_O_with,
apply univ_mem',
intro x,
rw [mem_set_of_eq, div_mul_cancel],
rwa [ne.def, norm_eq_zero]
end
theorem is_O_const_const (c : E) {c' : F''} (hc' : c' ≠ 0) (l : filter α) :
(λ x : α, c) =O[l] (λ x, c') :=
(is_O_with_const_const c hc' l).is_O
@[simp] theorem is_O_const_const_iff {c : E''} {c' : F''} (l : filter α) [l.ne_bot] :
(λ x : α, c) =O[l] (λ x, c') ↔ (c' = 0 → c = 0) :=
begin
rcases eq_or_ne c' 0 with rfl|hc',
{ simp [eventually_eq] },
{ simp [hc', is_O_const_const _ hc'] }
end
@[simp] lemma is_O_pure {x} : f'' =O[pure x] g'' ↔ (g'' x = 0 → f'' x = 0) :=
calc f'' =O[pure x] g'' ↔ (λ y : α, f'' x) =O[pure x] (λ _, g'' x) : is_O_congr rfl rfl
... ↔ g'' x = 0 → f'' x = 0 : is_O_const_const_iff _
end zero_const
@[simp] lemma is_O_with_top : is_O_with c ⊤ f g ↔ ∀ x, ∥f x∥ ≤ c * ∥g x∥ := by rw is_O_with; refl
@[simp] lemma is_O_top : f =O[⊤] g ↔ ∃ C, ∀ x, ∥f x∥ ≤ C * ∥g x∥ := by rw is_O_iff; refl
@[simp] lemma is_o_top : f'' =o[⊤] g'' ↔ ∀ x, f'' x = 0 :=
begin
refine ⟨_, λ h, (is_o_zero g'' ⊤).congr (λ x, (h x).symm) (λ x, rfl)⟩,
simp only [is_o_iff, eventually_top],
refine λ h x, norm_le_zero_iff.1 _,
have : tendsto (λ c : ℝ, c * ∥g'' x∥) (𝓝[>] 0) (𝓝 0) :=
((continuous_id.mul continuous_const).tendsto' _ _ (zero_mul _)).mono_left inf_le_left,
exact le_of_tendsto_of_tendsto tendsto_const_nhds this
(eventually_nhds_within_iff.2 $ eventually_of_forall $ λ c hc, h hc x)
end
@[simp] lemma is_O_with_principal {s : set α} :
is_O_with c (𝓟 s) f g ↔ ∀ x ∈ s, ∥f x∥ ≤ c * ∥g x∥ :=
by rw is_O_with; refl
lemma is_O_principal {s : set α} : f =O[𝓟 s] g ↔ ∃ c, ∀ x ∈ s, ∥f x∥ ≤ c * ∥g x∥ :=
by rw is_O_iff; refl
section
variables (F) [has_one F] [norm_one_class F]
theorem is_O_with_const_one (c : E) (l : filter α) : is_O_with ∥c∥ l (λ x : α, c) (λ x, (1 : F)) :=
by simp [is_O_with_iff]
theorem is_O_const_one (c : E) (l : filter α) : (λ x : α, c) =O[l] (λ x, (1 : F)) :=
(is_O_with_const_one F c l).is_O
theorem is_o_const_iff_is_o_one {c : F''} (hc : c ≠ 0) :
f =o[l] (λ x, c) ↔ f =o[l] (λ x, (1 : F)) :=
⟨λ h, h.trans_is_O_with (is_O_with_const_one _ _ _) (norm_pos_iff.2 hc),
λ h, h.trans_is_O $ is_O_const_const _ hc _⟩
@[simp] theorem is_o_one_iff : f' =o[l] (λ x, 1 : α → F) ↔ tendsto f' l (𝓝 0) :=
by simp only [is_o_iff, norm_one, mul_one, metric.nhds_basis_closed_ball.tendsto_right_iff,
metric.mem_closed_ball, dist_zero_right]
@[simp] theorem is_O_one_iff : f =O[l] (λ x, 1 : α → F) ↔ is_bounded_under (≤) l (λ x, ∥f x∥) :=
by { simp only [is_O_iff, norm_one, mul_one], refl }
alias is_O_one_iff ↔ _ _root_.filter.is_bounded_under.is_O_one
@[simp] theorem is_o_one_left_iff : (λ x, 1 : α → F) =o[l] f ↔ tendsto (λ x, ∥f x∥) l at_top :=
calc (λ x, 1 : α → F) =o[l] f ↔ ∀ n : ℕ, ∀ᶠ x in l, ↑n * ∥(1 : F)∥ ≤ ∥f x∥ :
is_o_iff_nat_mul_le_aux $ or.inl $ λ x, by simp only [norm_one, zero_le_one]
... ↔ ∀ n : ℕ, true → ∀ᶠ x in l, ∥f x∥ ∈ Ici (n : ℝ) :
by simp only [norm_one, mul_one, true_implies_iff, mem_Ici]
... ↔ tendsto (λ x, ∥f x∥) l at_top : at_top_countable_basis_of_archimedean.1.tendsto_right_iff.symm
theorem _root_.filter.tendsto.is_O_one {c : E'} (h : tendsto f' l (𝓝 c)) :
f' =O[l] (λ x, 1 : α → F) :=
h.norm.is_bounded_under_le.is_O_one F
theorem is_O.trans_tendsto_nhds (hfg : f =O[l] g') {y : F'} (hg : tendsto g' l (𝓝 y)) :
f =O[l] (λ x, 1 : α → F) :=
hfg.trans $ hg.is_O_one F
end
theorem is_o_const_iff {c : F''} (hc : c ≠ 0) :
f'' =o[l] (λ x, c) ↔ tendsto f'' l (𝓝 0) :=
(is_o_const_iff_is_o_one ℝ hc).trans (is_o_one_iff _)
lemma is_o_id_const {c : F''} (hc : c ≠ 0) :
(λ (x : E''), x) =o[𝓝 0] (λ x, c) :=
(is_o_const_iff hc).mpr (continuous_id.tendsto 0)
theorem _root_.filter.is_bounded_under.is_O_const (h : is_bounded_under (≤) l (norm ∘ f))
{c : F''} (hc : c ≠ 0) : f =O[l] (λ x, c) :=
(h.is_O_one ℝ).trans (is_O_const_const _ hc _)
theorem is_O_const_of_tendsto {y : E''} (h : tendsto f'' l (𝓝 y)) {c : F''} (hc : c ≠ 0) :
f'' =O[l] (λ x, c) :=
h.norm.is_bounded_under_le.is_O_const hc
lemma is_O.is_bounded_under_le {c : F} (h : f =O[l] (λ x, c)) :
is_bounded_under (≤) l (norm ∘ f) :=
let ⟨c', hc'⟩ := h.bound in ⟨c' * ∥c∥, eventually_map.2 hc'⟩
theorem is_O_const_of_ne {c : F''} (hc : c ≠ 0) :
f =O[l] (λ x, c) ↔ is_bounded_under (≤) l (norm ∘ f) :=
⟨λ h, h.is_bounded_under_le, λ h, h.is_O_const hc⟩
theorem is_O_const_iff {c : F''} :
f'' =O[l] (λ x, c) ↔ (c = 0 → f'' =ᶠ[l] 0) ∧ is_bounded_under (≤) l (λ x, ∥f'' x∥) :=
begin
refine ⟨λ h, ⟨λ hc, is_O_zero_right_iff.1 (by rwa ← hc), h.is_bounded_under_le⟩, _⟩,
rintro ⟨hcf, hf⟩,
rcases eq_or_ne c 0 with hc|hc,
exacts [(hcf hc).trans_is_O (is_O_zero _ _), hf.is_O_const hc]
end
theorem is_O_iff_is_bounded_under_le_div (h : ∀ᶠ x in l, g'' x ≠ 0) :
f =O[l] g'' ↔ is_bounded_under (≤) l (λ x, ∥f x∥ / ∥g'' x∥) :=
begin
simp only [is_O_iff, is_bounded_under, is_bounded, eventually_map],
exact exists_congr (λ c, eventually_congr $ h.mono $
λ x hx, (div_le_iff $ norm_pos_iff.2 hx).symm)
end
/-- `(λ x, c) =O[l] f` if and only if `f` is bounded away from zero. -/
lemma is_O_const_left_iff_pos_le_norm {c : E''} (hc : c ≠ 0) :
(λ x, c) =O[l] f' ↔ ∃ b, 0 < b ∧ ∀ᶠ x in l, b ≤ ∥f' x∥ :=
begin
split,
{ intro h,
rcases h.exists_pos with ⟨C, hC₀, hC⟩,
refine ⟨∥c∥ / C, div_pos (norm_pos_iff.2 hc) hC₀, _⟩,
exact hC.bound.mono (λ x, (div_le_iff' hC₀).2) },