/
Pointwise.lean
1415 lines (1126 loc) · 53.1 KB
/
Pointwise.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 Zhouhang Zhou. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Zhouhang Zhou, Yaël Dillies
-/
import Mathlib.Data.Set.Pointwise.SMul
import Mathlib.Order.Filter.NAry
import Mathlib.Order.Filter.Ultrafilter
#align_import order.filter.pointwise from "leanprover-community/mathlib"@"e3d9ab8faa9dea8f78155c6c27d62a621f4c152d"
/-!
# Pointwise operations on filters
This file defines pointwise operations on filters. This is useful because usual algebraic operations
distribute over pointwise operations. For example,
* `(f₁ * f₂).map m = f₁.map m * f₂.map m`
* `𝓝 (x * y) = 𝓝 x * 𝓝 y`
## Main declarations
* `0` (`Filter.instZero`): Pure filter at `0 : α`, or alternatively principal filter at `0 : Set α`.
* `1` (`Filter.instOne`): Pure filter at `1 : α`, or alternatively principal filter at `1 : Set α`.
* `f + g` (`Filter.instAdd`): Addition, filter generated by all `s + t` where `s ∈ f` and `t ∈ g`.
* `f * g` (`Filter.instMul`): Multiplication, filter generated by all `s * t` where `s ∈ f` and
`t ∈ g`.
* `-f` (`Filter.instNeg`): Negation, filter of all `-s` where `s ∈ f`.
* `f⁻¹` (`Filter.instInv`): Inversion, filter of all `s⁻¹` where `s ∈ f`.
* `f - g` (`Filter.instSub`): Subtraction, filter generated by all `s - t` where `s ∈ f` and
`t ∈ g`.
* `f / g` (`Filter.instDiv`): Division, filter generated by all `s / t` where `s ∈ f` and `t ∈ g`.
* `f +ᵥ g` (`Filter.instVAdd`): Scalar addition, filter generated by all `s +ᵥ t` where `s ∈ f` and
`t ∈ g`.
* `f -ᵥ g` (`Filter.instVSub`): Scalar subtraction, filter generated by all `s -ᵥ t` where `s ∈ f`
and `t ∈ g`.
* `f • g` (`Filter.instSMul`): Scalar multiplication, filter generated by all `s • t` where
`s ∈ f` and `t ∈ g`.
* `a +ᵥ f` (`Filter.instVAddFilter`): Translation, filter of all `a +ᵥ s` where `s ∈ f`.
* `a • f` (`Filter.instSMulFilter`): Scaling, filter of all `a • s` where `s ∈ f`.
For `α` a semigroup/monoid, `Filter α` is a semigroup/monoid.
As an unfortunate side effect, this means that `n • f`, where `n : ℕ`, is ambiguous between
pointwise scaling and repeated pointwise addition. See note [pointwise nat action].
## Implementation notes
We put all instances in the locale `Pointwise`, so that these instances are not available by
default. Note that we do not mark them as reducible (as argued by note [reducible non-instances])
since we expect the locale to be open whenever the instances are actually used (and making the
instances reducible changes the behavior of `simp`).
## Tags
filter multiplication, filter addition, pointwise addition, pointwise multiplication,
-/
open Function Set Filter Pointwise
variable {F α β γ δ ε : Type*}
namespace Filter
/-! ### `0`/`1` as filters -/
section One
variable [One α] {f : Filter α} {s : Set α}
/-- `1 : Filter α` is defined as the filter of sets containing `1 : α` in locale `Pointwise`. -/
@[to_additive
"`0 : Filter α` is defined as the filter of sets containing `0 : α` in locale `Pointwise`."]
protected def instOne : One (Filter α) :=
⟨pure 1⟩
#align filter.has_one Filter.instOne
#align filter.has_zero Filter.instZero
scoped[Pointwise] attribute [instance] Filter.instOne Filter.instZero
@[to_additive (attr := simp)]
theorem mem_one : s ∈ (1 : Filter α) ↔ (1 : α) ∈ s :=
mem_pure
#align filter.mem_one Filter.mem_one
#align filter.mem_zero Filter.mem_zero
@[to_additive]
theorem one_mem_one : (1 : Set α) ∈ (1 : Filter α) :=
mem_pure.2 Set.one_mem_one
#align filter.one_mem_one Filter.one_mem_one
#align filter.zero_mem_zero Filter.zero_mem_zero
@[to_additive (attr := simp)]
theorem pure_one : pure 1 = (1 : Filter α) :=
rfl
#align filter.pure_one Filter.pure_one
#align filter.pure_zero Filter.pure_zero
@[to_additive (attr := simp)]
theorem principal_one : 𝓟 1 = (1 : Filter α) :=
principal_singleton _
#align filter.principal_one Filter.principal_one
#align filter.principal_zero Filter.principal_zero
@[to_additive]
theorem one_neBot : (1 : Filter α).NeBot :=
Filter.pure_neBot
#align filter.one_ne_bot Filter.one_neBot
#align filter.zero_ne_bot Filter.zero_neBot
scoped[Pointwise] attribute [instance] one_neBot zero_neBot
@[to_additive (attr := simp)]
protected theorem map_one' (f : α → β) : (1 : Filter α).map f = pure (f 1) :=
rfl
#align filter.map_one' Filter.map_one'
#align filter.map_zero' Filter.map_zero'
@[to_additive (attr := simp)]
theorem le_one_iff : f ≤ 1 ↔ (1 : Set α) ∈ f :=
le_pure_iff
#align filter.le_one_iff Filter.le_one_iff
#align filter.nonpos_iff Filter.nonpos_iff
@[to_additive]
protected theorem NeBot.le_one_iff (h : f.NeBot) : f ≤ 1 ↔ f = 1 :=
h.le_pure_iff
#align filter.ne_bot.le_one_iff Filter.NeBot.le_one_iff
#align filter.ne_bot.nonpos_iff Filter.NeBot.nonpos_iff
@[to_additive (attr := simp)]
theorem eventually_one {p : α → Prop} : (∀ᶠ x in 1, p x) ↔ p 1 :=
eventually_pure
#align filter.eventually_one Filter.eventually_one
#align filter.eventually_zero Filter.eventually_zero
@[to_additive (attr := simp)]
theorem tendsto_one {a : Filter β} {f : β → α} : Tendsto f a 1 ↔ ∀ᶠ x in a, f x = 1 :=
tendsto_pure
#align filter.tendsto_one Filter.tendsto_one
#align filter.tendsto_zero Filter.tendsto_zero
@[to_additive (attr := simp)]
theorem one_prod_one [One β] : (1 : Filter α) ×ˢ (1 : Filter β) = 1 :=
prod_pure_pure
#align filter.one_prod_one Filter.one_prod_one
#align filter.zero_sum_zero Filter.zero_sum_zero
/-- `pure` as a `OneHom`. -/
@[to_additive "`pure` as a `ZeroHom`."]
def pureOneHom : OneHom α (Filter α) where
toFun := pure; map_one' := pure_one
#align filter.pure_one_hom Filter.pureOneHom
#align filter.pure_zero_hom Filter.pureZeroHom
@[to_additive (attr := simp)]
theorem coe_pureOneHom : (pureOneHom : α → Filter α) = pure :=
rfl
#align filter.coe_pure_one_hom Filter.coe_pureOneHom
#align filter.coe_pure_zero_hom Filter.coe_pureZeroHom
@[to_additive (attr := simp)]
theorem pureOneHom_apply (a : α) : pureOneHom a = pure a :=
rfl
#align filter.pure_one_hom_apply Filter.pureOneHom_apply
#align filter.pure_zero_hom_apply Filter.pureZeroHom_apply
variable [One β]
@[to_additive]
-- Porting note (#11119): removed `simp` attribute because `simpNF` says it can prove it.
protected theorem map_one [FunLike F α β] [OneHomClass F α β] (φ : F) : map φ 1 = 1 := by
rw [Filter.map_one', map_one, pure_one]
#align filter.map_one Filter.map_one
#align filter.map_zero Filter.map_zero
end One
/-! ### Filter negation/inversion -/
section Inv
variable [Inv α] {f g : Filter α} {s : Set α} {a : α}
/-- The inverse of a filter is the pointwise preimage under `⁻¹` of its sets. -/
@[to_additive "The negation of a filter is the pointwise preimage under `-` of its sets."]
instance instInv : Inv (Filter α) :=
⟨map Inv.inv⟩
@[to_additive (attr := simp)]
protected theorem map_inv : f.map Inv.inv = f⁻¹ :=
rfl
#align filter.map_inv Filter.map_inv
#align filter.map_neg Filter.map_neg
@[to_additive]
theorem mem_inv : s ∈ f⁻¹ ↔ Inv.inv ⁻¹' s ∈ f :=
Iff.rfl
#align filter.mem_inv Filter.mem_inv
#align filter.mem_neg Filter.mem_neg
@[to_additive]
protected theorem inv_le_inv (hf : f ≤ g) : f⁻¹ ≤ g⁻¹ :=
map_mono hf
#align filter.inv_le_inv Filter.inv_le_inv
#align filter.neg_le_neg Filter.neg_le_neg
@[to_additive (attr := simp)]
theorem inv_pure : (pure a : Filter α)⁻¹ = pure a⁻¹ :=
rfl
#align filter.inv_pure Filter.inv_pure
#align filter.neg_pure Filter.neg_pure
@[to_additive (attr := simp)]
theorem inv_eq_bot_iff : f⁻¹ = ⊥ ↔ f = ⊥ :=
map_eq_bot_iff
#align filter.inv_eq_bot_iff Filter.inv_eq_bot_iff
#align filter.neg_eq_bot_iff Filter.neg_eq_bot_iff
@[to_additive (attr := simp)]
theorem neBot_inv_iff : f⁻¹.NeBot ↔ NeBot f :=
map_neBot_iff _
#align filter.ne_bot_inv_iff Filter.neBot_inv_iff
#align filter.ne_bot_neg_iff Filter.neBot_neg_iff
@[to_additive]
protected theorem NeBot.inv : f.NeBot → f⁻¹.NeBot := fun h => h.map _
#align filter.ne_bot.inv Filter.NeBot.inv
#align filter.ne_bot.neg Filter.NeBot.neg
@[to_additive neg.instNeBot]
lemma inv.instNeBot [NeBot f] : NeBot f⁻¹ := .inv ‹_›
scoped[Pointwise] attribute [instance] inv.instNeBot neg.instNeBot
end Inv
section InvolutiveInv
variable [InvolutiveInv α] {f g : Filter α} {s : Set α}
@[to_additive (attr := simp)]
protected lemma comap_inv : comap Inv.inv f = f⁻¹ :=
.symm <| map_eq_comap_of_inverse (inv_comp_inv _) (inv_comp_inv _)
@[to_additive]
theorem inv_mem_inv (hs : s ∈ f) : s⁻¹ ∈ f⁻¹ := by rwa [mem_inv, inv_preimage, inv_inv]
#align filter.inv_mem_inv Filter.inv_mem_inv
#align filter.neg_mem_neg Filter.neg_mem_neg
/-- Inversion is involutive on `Filter α` if it is on `α`. -/
@[to_additive "Negation is involutive on `Filter α` if it is on `α`."]
protected def instInvolutiveInv : InvolutiveInv (Filter α) :=
{ Filter.instInv with
inv_inv := fun f => map_map.trans <| by rw [inv_involutive.comp_self, map_id] }
#align filter.has_involutive_inv Filter.instInvolutiveInv
#align filter.has_involutive_neg Filter.instInvolutiveNeg
scoped[Pointwise] attribute [instance] Filter.instInvolutiveInv Filter.instInvolutiveNeg
@[to_additive (attr := simp)]
protected theorem inv_le_inv_iff : f⁻¹ ≤ g⁻¹ ↔ f ≤ g :=
⟨fun h => inv_inv f ▸ inv_inv g ▸ Filter.inv_le_inv h, Filter.inv_le_inv⟩
#align filter.inv_le_inv_iff Filter.inv_le_inv_iff
#align filter.neg_le_neg_iff Filter.neg_le_neg_iff
@[to_additive]
theorem inv_le_iff_le_inv : f⁻¹ ≤ g ↔ f ≤ g⁻¹ := by rw [← Filter.inv_le_inv_iff, inv_inv]
#align filter.inv_le_iff_le_inv Filter.inv_le_iff_le_inv
#align filter.neg_le_iff_le_neg Filter.neg_le_iff_le_neg
@[to_additive (attr := simp)]
theorem inv_le_self : f⁻¹ ≤ f ↔ f⁻¹ = f :=
⟨fun h => h.antisymm <| inv_le_iff_le_inv.1 h, Eq.le⟩
#align filter.inv_le_self Filter.inv_le_self
#align filter.neg_le_self Filter.neg_le_self
end InvolutiveInv
@[to_additive (attr := simp)]
lemma inv_atTop {G : Type*} [OrderedCommGroup G] : (atTop : Filter G)⁻¹ = atBot :=
(OrderIso.inv G).map_atTop
/-! ### Filter addition/multiplication -/
section Mul
variable [Mul α] [Mul β] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α} {a b : α}
/-- The filter `f * g` is generated by `{s * t | s ∈ f, t ∈ g}` in locale `Pointwise`. -/
@[to_additive "The filter `f + g` is generated by `{s + t | s ∈ f, t ∈ g}` in locale `Pointwise`."]
protected def instMul : Mul (Filter α) :=
⟨/- This is defeq to `map₂ (· * ·) f g`, but the hypothesis unfolds to `t₁ * t₂ ⊆ s` rather
than all the way to `Set.image2 (· * ·) t₁ t₂ ⊆ s`. -/
fun f g => { map₂ (· * ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ * t₂ ⊆ s } }⟩
#align filter.has_mul Filter.instMul
#align filter.has_add Filter.instAdd
scoped[Pointwise] attribute [instance] Filter.instMul Filter.instAdd
@[to_additive (attr := simp)]
theorem map₂_mul : map₂ (· * ·) f g = f * g :=
rfl
#align filter.map₂_mul Filter.map₂_mul
#align filter.map₂_add Filter.map₂_add
@[to_additive]
theorem mem_mul : s ∈ f * g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ * t₂ ⊆ s :=
Iff.rfl
#align filter.mem_mul Filter.mem_mul
#align filter.mem_add Filter.mem_add
@[to_additive]
theorem mul_mem_mul : s ∈ f → t ∈ g → s * t ∈ f * g :=
image2_mem_map₂
#align filter.mul_mem_mul Filter.mul_mem_mul
#align filter.add_mem_add Filter.add_mem_add
@[to_additive (attr := simp)]
theorem bot_mul : ⊥ * g = ⊥ :=
map₂_bot_left
#align filter.bot_mul Filter.bot_mul
#align filter.bot_add Filter.bot_add
@[to_additive (attr := simp)]
theorem mul_bot : f * ⊥ = ⊥ :=
map₂_bot_right
#align filter.mul_bot Filter.mul_bot
#align filter.add_bot Filter.add_bot
@[to_additive (attr := simp)]
theorem mul_eq_bot_iff : f * g = ⊥ ↔ f = ⊥ ∨ g = ⊥ :=
map₂_eq_bot_iff
#align filter.mul_eq_bot_iff Filter.mul_eq_bot_iff
#align filter.add_eq_bot_iff Filter.add_eq_bot_iff
@[to_additive (attr := simp)] -- TODO: make this a scoped instance in the `Pointwise` namespace
lemma mul_neBot_iff : (f * g).NeBot ↔ f.NeBot ∧ g.NeBot :=
map₂_neBot_iff
#align filter.mul_ne_bot_iff Filter.mul_neBot_iff
#align filter.add_ne_bot_iff Filter.add_neBot_iff
@[to_additive]
protected theorem NeBot.mul : NeBot f → NeBot g → NeBot (f * g) :=
NeBot.map₂
#align filter.ne_bot.mul Filter.NeBot.mul
#align filter.ne_bot.add Filter.NeBot.add
@[to_additive]
theorem NeBot.of_mul_left : (f * g).NeBot → f.NeBot :=
NeBot.of_map₂_left
#align filter.ne_bot.of_mul_left Filter.NeBot.of_mul_left
#align filter.ne_bot.of_add_left Filter.NeBot.of_add_left
@[to_additive]
theorem NeBot.of_mul_right : (f * g).NeBot → g.NeBot :=
NeBot.of_map₂_right
#align filter.ne_bot.of_mul_right Filter.NeBot.of_mul_right
#align filter.ne_bot.of_add_right Filter.NeBot.of_add_right
@[to_additive add.instNeBot]
protected lemma mul.instNeBot [NeBot f] [NeBot g] : NeBot (f * g) := .mul ‹_› ‹_›
scoped[Pointwise] attribute [instance] mul.instNeBot add.instNeBot
@[to_additive (attr := simp)]
theorem pure_mul : pure a * g = g.map (a * ·) :=
map₂_pure_left
#align filter.pure_mul Filter.pure_mul
#align filter.pure_add Filter.pure_add
@[to_additive (attr := simp)]
theorem mul_pure : f * pure b = f.map (· * b) :=
map₂_pure_right
#align filter.mul_pure Filter.mul_pure
#align filter.add_pure Filter.add_pure
@[to_additive]
-- Porting note (#11119): removed `simp` attribute because `simpNF` says it can prove it.
theorem pure_mul_pure : (pure a : Filter α) * pure b = pure (a * b) :=
map₂_pure
#align filter.pure_mul_pure Filter.pure_mul_pure
#align filter.pure_add_pure Filter.pure_add_pure
@[to_additive (attr := simp)]
theorem le_mul_iff : h ≤ f * g ↔ ∀ ⦃s⦄, s ∈ f → ∀ ⦃t⦄, t ∈ g → s * t ∈ h :=
le_map₂_iff
#align filter.le_mul_iff Filter.le_mul_iff
#align filter.le_add_iff Filter.le_add_iff
@[to_additive]
instance covariant_mul : CovariantClass (Filter α) (Filter α) (· * ·) (· ≤ ·) :=
⟨fun _ _ _ => map₂_mono_left⟩
#align filter.covariant_mul Filter.covariant_mul
#align filter.covariant_add Filter.covariant_add
@[to_additive]
instance covariant_swap_mul : CovariantClass (Filter α) (Filter α) (swap (· * ·)) (· ≤ ·) :=
⟨fun _ _ _ => map₂_mono_right⟩
#align filter.covariant_swap_mul Filter.covariant_swap_mul
#align filter.covariant_swap_add Filter.covariant_swap_add
@[to_additive]
protected theorem map_mul [FunLike F α β] [MulHomClass F α β] (m : F) :
(f₁ * f₂).map m = f₁.map m * f₂.map m :=
map_map₂_distrib <| map_mul m
#align filter.map_mul Filter.map_mul
#align filter.map_add Filter.map_add
/-- `pure` operation as a `MulHom`. -/
@[to_additive "The singleton operation as an `AddHom`."]
def pureMulHom : α →ₙ* Filter α where
toFun := pure; map_mul' _ _ := pure_mul_pure.symm
#align filter.pure_mul_hom Filter.pureMulHom
#align filter.pure_add_hom Filter.pureAddHom
@[to_additive (attr := simp)]
theorem coe_pureMulHom : (pureMulHom : α → Filter α) = pure :=
rfl
#align filter.coe_pure_mul_hom Filter.coe_pureMulHom
#align filter.coe_pure_add_hom Filter.coe_pureMulHom
@[to_additive (attr := simp)]
theorem pureMulHom_apply (a : α) : pureMulHom a = pure a :=
rfl
#align filter.pure_mul_hom_apply Filter.pureMulHom_apply
#align filter.pure_add_hom_apply Filter.pureMulHom_apply
end Mul
/-! ### Filter subtraction/division -/
section Div
variable [Div α] {f f₁ f₂ g g₁ g₂ h : Filter α} {s t : Set α} {a b : α}
/-- The filter `f / g` is generated by `{s / t | s ∈ f, t ∈ g}` in locale `Pointwise`. -/
@[to_additive "The filter `f - g` is generated by `{s - t | s ∈ f, t ∈ g}` in locale `Pointwise`."]
protected def instDiv : Div (Filter α) :=
⟨/- This is defeq to `map₂ (· / ·) f g`, but the hypothesis unfolds to `t₁ / t₂ ⊆ s`
rather than all the way to `Set.image2 (· / ·) t₁ t₂ ⊆ s`. -/
fun f g => { map₂ (· / ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ / t₂ ⊆ s } }⟩
#align filter.has_div Filter.instDiv
#align filter.has_sub Filter.instSub
scoped[Pointwise] attribute [instance] Filter.instDiv Filter.instSub
@[to_additive (attr := simp)]
theorem map₂_div : map₂ (· / ·) f g = f / g :=
rfl
#align filter.map₂_div Filter.map₂_div
#align filter.map₂_sub Filter.map₂_sub
@[to_additive]
theorem mem_div : s ∈ f / g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ / t₂ ⊆ s :=
Iff.rfl
#align filter.mem_div Filter.mem_div
#align filter.mem_sub Filter.mem_sub
@[to_additive]
theorem div_mem_div : s ∈ f → t ∈ g → s / t ∈ f / g :=
image2_mem_map₂
#align filter.div_mem_div Filter.div_mem_div
#align filter.sub_mem_sub Filter.sub_mem_sub
@[to_additive (attr := simp)]
theorem bot_div : ⊥ / g = ⊥ :=
map₂_bot_left
#align filter.bot_div Filter.bot_div
#align filter.bot_sub Filter.bot_sub
@[to_additive (attr := simp)]
theorem div_bot : f / ⊥ = ⊥ :=
map₂_bot_right
#align filter.div_bot Filter.div_bot
#align filter.sub_bot Filter.sub_bot
@[to_additive (attr := simp)]
theorem div_eq_bot_iff : f / g = ⊥ ↔ f = ⊥ ∨ g = ⊥ :=
map₂_eq_bot_iff
#align filter.div_eq_bot_iff Filter.div_eq_bot_iff
#align filter.sub_eq_bot_iff Filter.sub_eq_bot_iff
@[to_additive (attr := simp)]
theorem div_neBot_iff : (f / g).NeBot ↔ f.NeBot ∧ g.NeBot :=
map₂_neBot_iff
#align filter.div_ne_bot_iff Filter.div_neBot_iff
#align filter.sub_ne_bot_iff Filter.sub_neBot_iff
@[to_additive]
protected theorem NeBot.div : NeBot f → NeBot g → NeBot (f / g) :=
NeBot.map₂
#align filter.ne_bot.div Filter.NeBot.div
#align filter.ne_bot.sub Filter.NeBot.sub
@[to_additive]
theorem NeBot.of_div_left : (f / g).NeBot → f.NeBot :=
NeBot.of_map₂_left
#align filter.ne_bot.of_div_left Filter.NeBot.of_div_left
#align filter.ne_bot.of_sub_left Filter.NeBot.of_sub_left
@[to_additive]
theorem NeBot.of_div_right : (f / g).NeBot → g.NeBot :=
NeBot.of_map₂_right
#align filter.ne_bot.of_div_right Filter.NeBot.of_div_right
#align filter.ne_bot.of_sub_right Filter.NeBot.of_sub_right
@[to_additive sub.instNeBot]
lemma div.instNeBot [NeBot f] [NeBot g] : NeBot (f / g) := .div ‹_› ‹_›
scoped[Pointwise] attribute [instance] div.instNeBot sub.instNeBot
@[to_additive (attr := simp)]
theorem pure_div : pure a / g = g.map (a / ·) :=
map₂_pure_left
#align filter.pure_div Filter.pure_div
#align filter.pure_sub Filter.pure_sub
@[to_additive (attr := simp)]
theorem div_pure : f / pure b = f.map (· / b) :=
map₂_pure_right
#align filter.div_pure Filter.div_pure
#align filter.sub_pure Filter.sub_pure
@[to_additive]
-- Porting note (#11119): removed `simp` attribute because `simpNF` says it can prove it.
theorem pure_div_pure : (pure a : Filter α) / pure b = pure (a / b) :=
map₂_pure
#align filter.pure_div_pure Filter.pure_div_pure
#align filter.pure_sub_pure Filter.pure_sub_pure
@[to_additive]
protected theorem div_le_div : f₁ ≤ f₂ → g₁ ≤ g₂ → f₁ / g₁ ≤ f₂ / g₂ :=
map₂_mono
#align filter.div_le_div Filter.div_le_div
#align filter.sub_le_sub Filter.sub_le_sub
@[to_additive]
protected theorem div_le_div_left : g₁ ≤ g₂ → f / g₁ ≤ f / g₂ :=
map₂_mono_left
#align filter.div_le_div_left Filter.div_le_div_left
#align filter.sub_le_sub_left Filter.sub_le_sub_left
@[to_additive]
protected theorem div_le_div_right : f₁ ≤ f₂ → f₁ / g ≤ f₂ / g :=
map₂_mono_right
#align filter.div_le_div_right Filter.div_le_div_right
#align filter.sub_le_sub_right Filter.sub_le_sub_right
@[to_additive (attr := simp)]
protected theorem le_div_iff : h ≤ f / g ↔ ∀ ⦃s⦄, s ∈ f → ∀ ⦃t⦄, t ∈ g → s / t ∈ h :=
le_map₂_iff
#align filter.le_div_iff Filter.le_div_iff
#align filter.le_sub_iff Filter.le_sub_iff
@[to_additive]
instance covariant_div : CovariantClass (Filter α) (Filter α) (· / ·) (· ≤ ·) :=
⟨fun _ _ _ => map₂_mono_left⟩
#align filter.covariant_div Filter.covariant_div
#align filter.covariant_sub Filter.covariant_sub
@[to_additive]
instance covariant_swap_div : CovariantClass (Filter α) (Filter α) (swap (· / ·)) (· ≤ ·) :=
⟨fun _ _ _ => map₂_mono_right⟩
#align filter.covariant_swap_div Filter.covariant_swap_div
#align filter.covariant_swap_sub Filter.covariant_swap_sub
end Div
open Pointwise
/-- Repeated pointwise addition (not the same as pointwise repeated addition!) of a `Filter`. See
Note [pointwise nat action]. -/
protected def instNSMul [Zero α] [Add α] : SMul ℕ (Filter α) :=
⟨nsmulRec⟩
#align filter.has_nsmul Filter.instNSMul
/-- Repeated pointwise multiplication (not the same as pointwise repeated multiplication!) of a
`Filter`. See Note [pointwise nat action]. -/
@[to_additive existing]
protected def instNPow [One α] [Mul α] : Pow (Filter α) ℕ :=
⟨fun s n => npowRec n s⟩
#align filter.has_npow Filter.instNPow
/-- Repeated pointwise addition/subtraction (not the same as pointwise repeated
addition/subtraction!) of a `Filter`. See Note [pointwise nat action]. -/
protected def instZSMul [Zero α] [Add α] [Neg α] : SMul ℤ (Filter α) :=
⟨zsmulRec⟩
#align filter.has_zsmul Filter.instZSMul
/-- Repeated pointwise multiplication/division (not the same as pointwise repeated
multiplication/division!) of a `Filter`. See Note [pointwise nat action]. -/
@[to_additive existing]
protected def instZPow [One α] [Mul α] [Inv α] : Pow (Filter α) ℤ :=
⟨fun s n => zpowRec npowRec n s⟩
#align filter.has_zpow Filter.instZPow
scoped[Pointwise] attribute [instance] Filter.instNSMul Filter.instNPow
Filter.instZSMul Filter.instZPow
/-- `Filter α` is a `Semigroup` under pointwise operations if `α` is. -/
@[to_additive "`Filter α` is an `AddSemigroup` under pointwise operations if `α` is."]
protected def semigroup [Semigroup α] : Semigroup (Filter α) where
mul := (· * ·)
mul_assoc _ _ _ := map₂_assoc mul_assoc
#align filter.semigroup Filter.semigroup
#align filter.add_semigroup Filter.addSemigroup
/-- `Filter α` is a `CommSemigroup` under pointwise operations if `α` is. -/
@[to_additive "`Filter α` is an `AddCommSemigroup` under pointwise operations if `α` is."]
protected def commSemigroup [CommSemigroup α] : CommSemigroup (Filter α) :=
{ Filter.semigroup with mul_comm := fun _ _ => map₂_comm mul_comm }
#align filter.comm_semigroup Filter.commSemigroup
#align filter.add_comm_semigroup Filter.addCommSemigroup
section MulOneClass
variable [MulOneClass α] [MulOneClass β]
/-- `Filter α` is a `MulOneClass` under pointwise operations if `α` is. -/
@[to_additive "`Filter α` is an `AddZeroClass` under pointwise operations if `α` is."]
protected def mulOneClass : MulOneClass (Filter α) where
one := 1
mul := (· * ·)
one_mul := map₂_left_identity one_mul
mul_one := map₂_right_identity mul_one
#align filter.mul_one_class Filter.mulOneClass
#align filter.add_zero_class Filter.addZeroClass
scoped[Pointwise] attribute [instance] Filter.semigroup Filter.addSemigroup
Filter.commSemigroup Filter.addCommSemigroup Filter.mulOneClass Filter.addZeroClass
variable [FunLike F α β]
/-- If `φ : α →* β` then `mapMonoidHom φ` is the monoid homomorphism
`Filter α →* Filter β` induced by `map φ`. -/
@[to_additive "If `φ : α →+ β` then `mapAddMonoidHom φ` is the monoid homomorphism
`Filter α →+ Filter β` induced by `map φ`."]
def mapMonoidHom [MonoidHomClass F α β] (φ : F) : Filter α →* Filter β where
toFun := map φ
map_one' := Filter.map_one φ
map_mul' _ _ := Filter.map_mul φ
#align filter.map_monoid_hom Filter.mapMonoidHom
#align filter.map_add_monoid_hom Filter.mapAddMonoidHom
-- The other direction does not hold in general
@[to_additive]
theorem comap_mul_comap_le [MulHomClass F α β] (m : F) {f g : Filter β} :
f.comap m * g.comap m ≤ (f * g).comap m := fun _ ⟨_, ⟨t₁, ht₁, t₂, ht₂, t₁t₂⟩, mt⟩ =>
⟨m ⁻¹' t₁, ⟨t₁, ht₁, Subset.rfl⟩, m ⁻¹' t₂, ⟨t₂, ht₂, Subset.rfl⟩,
(preimage_mul_preimage_subset _).trans <| (preimage_mono t₁t₂).trans mt⟩
#align filter.comap_mul_comap_le Filter.comap_mul_comap_le
#align filter.comap_add_comap_le Filter.comap_add_comap_le
@[to_additive]
theorem Tendsto.mul_mul [MulHomClass F α β] (m : F) {f₁ g₁ : Filter α} {f₂ g₂ : Filter β} :
Tendsto m f₁ f₂ → Tendsto m g₁ g₂ → Tendsto m (f₁ * g₁) (f₂ * g₂) := fun hf hg =>
(Filter.map_mul m).trans_le <| mul_le_mul' hf hg
#align filter.tendsto.mul_mul Filter.Tendsto.mul_mul
#align filter.tendsto.add_add Filter.Tendsto.add_add
/-- `pure` as a `MonoidHom`. -/
@[to_additive "`pure` as an `AddMonoidHom`."]
def pureMonoidHom : α →* Filter α :=
{ pureMulHom, pureOneHom with }
#align filter.pure_monoid_hom Filter.pureMonoidHom
#align filter.pure_add_monoid_hom Filter.pureAddMonoidHom
@[to_additive (attr := simp)]
theorem coe_pureMonoidHom : (pureMonoidHom : α → Filter α) = pure :=
rfl
#align filter.coe_pure_monoid_hom Filter.coe_pureMonoidHom
#align filter.coe_pure_add_monoid_hom Filter.coe_pureAddMonoidHom
@[to_additive (attr := simp)]
theorem pureMonoidHom_apply (a : α) : pureMonoidHom a = pure a :=
rfl
#align filter.pure_monoid_hom_apply Filter.pureMonoidHom_apply
#align filter.pure_add_monoid_hom_apply Filter.pureAddMonoidHom_apply
end MulOneClass
section Monoid
variable [Monoid α] {f g : Filter α} {s : Set α} {a : α} {m n : ℕ}
/-- `Filter α` is a `Monoid` under pointwise operations if `α` is. -/
@[to_additive "`Filter α` is an `AddMonoid` under pointwise operations if `α` is."]
protected def monoid : Monoid (Filter α) :=
{ Filter.mulOneClass, Filter.semigroup, @Filter.instNPow α _ _ with }
#align filter.monoid Filter.monoid
#align filter.add_monoid Filter.addMonoid
scoped[Pointwise] attribute [instance] Filter.monoid Filter.addMonoid
@[to_additive]
theorem pow_mem_pow (hs : s ∈ f) : ∀ n : ℕ, s ^ n ∈ f ^ n
| 0 => by
rw [pow_zero]
exact one_mem_one
| n + 1 => by
rw [pow_succ]
exact mul_mem_mul (pow_mem_pow hs n) hs
#align filter.pow_mem_pow Filter.pow_mem_pow
#align filter.nsmul_mem_nsmul Filter.nsmul_mem_nsmul
@[to_additive (attr := simp) nsmul_bot]
theorem bot_pow {n : ℕ} (hn : n ≠ 0) : (⊥ : Filter α) ^ n = ⊥ := by
rw [← tsub_add_cancel_of_le (Nat.succ_le_of_lt <| Nat.pos_of_ne_zero hn), pow_succ', bot_mul]
#align filter.bot_pow Filter.bot_pow
#align filter.nsmul_bot Filter.nsmul_bot
@[to_additive]
theorem mul_top_of_one_le (hf : 1 ≤ f) : f * ⊤ = ⊤ := by
refine' top_le_iff.1 fun s => _
simp only [mem_mul, mem_top, exists_and_left, exists_eq_left]
rintro ⟨t, ht, hs⟩
rwa [mul_univ_of_one_mem (mem_one.1 <| hf ht), univ_subset_iff] at hs
#align filter.mul_top_of_one_le Filter.mul_top_of_one_le
#align filter.add_top_of_nonneg Filter.add_top_of_nonneg
@[to_additive]
theorem top_mul_of_one_le (hf : 1 ≤ f) : ⊤ * f = ⊤ := by
refine' top_le_iff.1 fun s => _
simp only [mem_mul, mem_top, exists_and_left, exists_eq_left]
rintro ⟨t, ht, hs⟩
rwa [univ_mul_of_one_mem (mem_one.1 <| hf ht), univ_subset_iff] at hs
#align filter.top_mul_of_one_le Filter.top_mul_of_one_le
#align filter.top_add_of_nonneg Filter.top_add_of_nonneg
@[to_additive (attr := simp)]
theorem top_mul_top : (⊤ : Filter α) * ⊤ = ⊤ :=
mul_top_of_one_le le_top
#align filter.top_mul_top Filter.top_mul_top
#align filter.top_add_top Filter.top_add_top
@[to_additive nsmul_top]
theorem top_pow : ∀ {n : ℕ}, n ≠ 0 → (⊤ : Filter α) ^ n = ⊤
| 0 => fun h => (h rfl).elim
| 1 => fun _ => pow_one _
| n + 2 => fun _ => by rw [pow_succ, top_pow n.succ_ne_zero, top_mul_top]
#align filter.top_pow Filter.top_pow
#align filter.nsmul_top Filter.nsmul_top
@[to_additive]
protected theorem _root_.IsUnit.filter : IsUnit a → IsUnit (pure a : Filter α) :=
IsUnit.map (pureMonoidHom : α →* Filter α)
#align is_unit.filter IsUnit.filter
#align is_add_unit.filter IsAddUnit.filter
end Monoid
/-- `Filter α` is a `CommMonoid` under pointwise operations if `α` is. -/
@[to_additive "`Filter α` is an `AddCommMonoid` under pointwise operations if `α` is."]
protected def commMonoid [CommMonoid α] : CommMonoid (Filter α) :=
{ Filter.mulOneClass, Filter.commSemigroup with }
#align filter.comm_monoid Filter.commMonoid
#align filter.add_comm_monoid Filter.addCommMonoid
open Pointwise
section DivisionMonoid
variable [DivisionMonoid α] {f g : Filter α}
@[to_additive]
protected theorem mul_eq_one_iff : f * g = 1 ↔ ∃ a b, f = pure a ∧ g = pure b ∧ a * b = 1 := by
refine' ⟨fun hfg => _, _⟩
· obtain ⟨t₁, h₁, t₂, h₂, h⟩ : (1 : Set α) ∈ f * g := hfg.symm.subst one_mem_one
have hfg : (f * g).NeBot := hfg.symm.subst one_neBot
rw [(hfg.nonempty_of_mem <| mul_mem_mul h₁ h₂).subset_one_iff, Set.mul_eq_one_iff] at h
obtain ⟨a, b, rfl, rfl, h⟩ := h
refine' ⟨a, b, _, _, h⟩
· rwa [← hfg.of_mul_left.le_pure_iff, le_pure_iff]
· rwa [← hfg.of_mul_right.le_pure_iff, le_pure_iff]
· rintro ⟨a, b, rfl, rfl, h⟩
rw [pure_mul_pure, h, pure_one]
#align filter.mul_eq_one_iff Filter.mul_eq_one_iff
#align filter.add_eq_zero_iff Filter.add_eq_zero_iff
/-- `Filter α` is a division monoid under pointwise operations if `α` is. -/
@[to_additive subtractionMonoid "`Filter α` is a subtraction monoid under pointwise operations if
`α` is."]
-- Porting note: `to_additive` guessed `divisionAddMonoid`
protected def divisionMonoid : DivisionMonoid (Filter α) :=
{ Filter.monoid, Filter.instInvolutiveInv, Filter.instDiv, Filter.instZPow (α := α) with
mul_inv_rev := fun s t => map_map₂_antidistrib mul_inv_rev
inv_eq_of_mul := fun s t h => by
obtain ⟨a, b, rfl, rfl, hab⟩ := Filter.mul_eq_one_iff.1 h
rw [inv_pure, inv_eq_of_mul_eq_one_right hab]
div_eq_mul_inv := fun f g => map_map₂_distrib_right div_eq_mul_inv }
#align filter.division_monoid Filter.divisionMonoid
#align filter.subtraction_monoid Filter.subtractionMonoid
@[to_additive]
theorem isUnit_iff : IsUnit f ↔ ∃ a, f = pure a ∧ IsUnit a := by
constructor
· rintro ⟨u, rfl⟩
obtain ⟨a, b, ha, hb, h⟩ := Filter.mul_eq_one_iff.1 u.mul_inv
refine' ⟨a, ha, ⟨a, b, h, pure_injective _⟩, rfl⟩
rw [← pure_mul_pure, ← ha, ← hb]
exact u.inv_mul
· rintro ⟨a, rfl, ha⟩
exact ha.filter
#align filter.is_unit_iff Filter.isUnit_iff
#align filter.is_add_unit_iff Filter.isAddUnit_iff
end DivisionMonoid
/-- `Filter α` is a commutative division monoid under pointwise operations if `α` is. -/
@[to_additive subtractionCommMonoid
"`Filter α` is a commutative subtraction monoid under pointwise operations if `α` is."]
protected def divisionCommMonoid [DivisionCommMonoid α] : DivisionCommMonoid (Filter α) :=
{ Filter.divisionMonoid, Filter.commSemigroup with }
#align filter.division_comm_monoid Filter.divisionCommMonoid
#align filter.subtraction_comm_monoid Filter.subtractionCommMonoid
/-- `Filter α` has distributive negation if `α` has. -/
protected def instDistribNeg [Mul α] [HasDistribNeg α] : HasDistribNeg (Filter α) :=
{ Filter.instInvolutiveNeg with
neg_mul := fun _ _ => map₂_map_left_comm neg_mul
mul_neg := fun _ _ => map_map₂_right_comm mul_neg }
#align filter.has_distrib_neg Filter.instDistribNeg
scoped[Pointwise] attribute [instance] Filter.commMonoid Filter.addCommMonoid Filter.divisionMonoid
Filter.subtractionMonoid Filter.divisionCommMonoid Filter.subtractionCommMonoid
Filter.instDistribNeg
section Distrib
variable [Distrib α] {f g h : Filter α}
/-!
Note that `Filter α` is not a `Distrib` because `f * g + f * h` has cross terms that `f * (g + h)`
lacks.
-/
theorem mul_add_subset : f * (g + h) ≤ f * g + f * h :=
map₂_distrib_le_left mul_add
#align filter.mul_add_subset Filter.mul_add_subset
theorem add_mul_subset : (f + g) * h ≤ f * h + g * h :=
map₂_distrib_le_right add_mul
#align filter.add_mul_subset Filter.add_mul_subset
end Distrib
section MulZeroClass
variable [MulZeroClass α] {f g : Filter α}
/-! Note that `Filter` is not a `MulZeroClass` because `0 * ⊥ ≠ 0`. -/
theorem NeBot.mul_zero_nonneg (hf : f.NeBot) : 0 ≤ f * 0 :=
le_mul_iff.2 fun _ h₁ _ h₂ =>
let ⟨_, ha⟩ := hf.nonempty_of_mem h₁
⟨_, ha, _, h₂, mul_zero _⟩
#align filter.ne_bot.mul_zero_nonneg Filter.NeBot.mul_zero_nonneg
theorem NeBot.zero_mul_nonneg (hg : g.NeBot) : 0 ≤ 0 * g :=
le_mul_iff.2 fun _ h₁ _ h₂ =>
let ⟨_, hb⟩ := hg.nonempty_of_mem h₂
⟨_, h₁, _, hb, zero_mul _⟩
#align filter.ne_bot.zero_mul_nonneg Filter.NeBot.zero_mul_nonneg
end MulZeroClass
section Group
variable [Group α] [DivisionMonoid β] [FunLike F α β] [MonoidHomClass F α β]
(m : F) {f g f₁ g₁ : Filter α} {f₂ g₂ : Filter β}
/-! Note that `Filter α` is not a group because `f / f ≠ 1` in general -/
-- Porting note: increase priority to appease `simpNF` so left-hand side doesn't simplify
@[to_additive (attr := simp 1100)]
protected theorem one_le_div_iff : 1 ≤ f / g ↔ ¬Disjoint f g := by
refine' ⟨fun h hfg => _, _⟩
· obtain ⟨s, hs, t, ht, hst⟩ := hfg.le_bot (mem_bot : ∅ ∈ ⊥)
exact Set.one_mem_div_iff.1 (h <| div_mem_div hs ht) (disjoint_iff.2 hst.symm)
· rintro h s ⟨t₁, h₁, t₂, h₂, hs⟩
exact hs (Set.one_mem_div_iff.2 fun ht => h <| disjoint_of_disjoint_of_mem ht h₁ h₂)
#align filter.one_le_div_iff Filter.one_le_div_iff
#align filter.nonneg_sub_iff Filter.nonneg_sub_iff
@[to_additive]
theorem not_one_le_div_iff : ¬1 ≤ f / g ↔ Disjoint f g :=
Filter.one_le_div_iff.not_left
#align filter.not_one_le_div_iff Filter.not_one_le_div_iff
#align filter.not_nonneg_sub_iff Filter.not_nonneg_sub_iff
@[to_additive]
theorem NeBot.one_le_div (h : f.NeBot) : 1 ≤ f / f := by
rintro s ⟨t₁, h₁, t₂, h₂, hs⟩
obtain ⟨a, ha₁, ha₂⟩ := Set.not_disjoint_iff.1 (h.not_disjoint h₁ h₂)
rw [mem_one, ← div_self' a]
exact hs (Set.div_mem_div ha₁ ha₂)
#align filter.ne_bot.one_le_div Filter.NeBot.one_le_div
#align filter.ne_bot.nonneg_sub Filter.NeBot.nonneg_sub
@[to_additive]
theorem isUnit_pure (a : α) : IsUnit (pure a : Filter α) :=
(Group.isUnit a).filter
#align filter.is_unit_pure Filter.isUnit_pure
#align filter.is_add_unit_pure Filter.isAddUnit_pure
@[simp]
theorem isUnit_iff_singleton : IsUnit f ↔ ∃ a, f = pure a := by
simp only [isUnit_iff, Group.isUnit, and_true_iff]
#align filter.is_unit_iff_singleton Filter.isUnit_iff_singleton
@[to_additive]
theorem map_inv' : f⁻¹.map m = (f.map m)⁻¹ :=
Semiconj.filter_map (map_inv m) f
#align filter.map_inv' Filter.map_inv'
#align filter.map_neg' Filter.map_neg'
@[to_additive]
protected theorem Tendsto.inv_inv : Tendsto m f₁ f₂ → Tendsto m f₁⁻¹ f₂⁻¹ := fun hf =>
(Filter.map_inv' m).trans_le <| Filter.inv_le_inv hf
#align filter.tendsto.inv_inv Filter.Tendsto.inv_inv
#align filter.tendsto.neg_neg Filter.Tendsto.neg_neg
@[to_additive]
protected theorem map_div : (f / g).map m = f.map m / g.map m :=
map_map₂_distrib <| map_div m
#align filter.map_div Filter.map_div
#align filter.map_sub Filter.map_sub
@[to_additive]
protected theorem Tendsto.div_div (hf : Tendsto m f₁ f₂) (hg : Tendsto m g₁ g₂) :
Tendsto m (f₁ / g₁) (f₂ / g₂) :=
(Filter.map_div m).trans_le <| Filter.div_le_div hf hg
#align filter.tendsto.div_div Filter.Tendsto.div_div
#align filter.tendsto.sub_sub Filter.Tendsto.sub_sub
end Group
open Pointwise
section GroupWithZero
variable [GroupWithZero α] {f g : Filter α}
theorem NeBot.div_zero_nonneg (hf : f.NeBot) : 0 ≤ f / 0 :=
Filter.le_div_iff.2 fun _ h₁ _ h₂ =>
let ⟨_, ha⟩ := hf.nonempty_of_mem h₁
⟨_, ha, _, h₂, div_zero _⟩
#align filter.ne_bot.div_zero_nonneg Filter.NeBot.div_zero_nonneg
theorem NeBot.zero_div_nonneg (hg : g.NeBot) : 0 ≤ 0 / g :=
Filter.le_div_iff.2 fun _ h₁ _ h₂ =>
let ⟨_, hb⟩ := hg.nonempty_of_mem h₂
⟨_, h₁, _, hb, zero_div _⟩
#align filter.ne_bot.zero_div_nonneg Filter.NeBot.zero_div_nonneg
end GroupWithZero
/-! ### Scalar addition/multiplication of filters -/
section SMul
variable [SMul α β] {f f₁ f₂ : Filter α} {g g₁ g₂ h : Filter β} {s : Set α} {t : Set β} {a : α}
{b : β}
/-- The filter `f • g` is generated by `{s • t | s ∈ f, t ∈ g}` in locale `Pointwise`. -/
@[to_additive "The filter `f +ᵥ g` is generated by `{s +ᵥ t | s ∈ f, t ∈ g}` in locale
`Pointwise`."]
protected def instSMul : SMul (Filter α) (Filter β) :=
⟨/- This is defeq to `map₂ (· • ·) f g`, but the hypothesis unfolds to `t₁ • t₂ ⊆ s`
rather than all the way to `Set.image2 (· • ·) t₁ t₂ ⊆ s`. -/
fun f g => { map₂ (· • ·) f g with sets := { s | ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ • t₂ ⊆ s } }⟩
#align filter.has_smul Filter.instSMul
#align filter.has_vadd Filter.instVAdd
scoped[Pointwise] attribute [instance] Filter.instSMul Filter.instVAdd
@[to_additive (attr := simp)]
theorem map₂_smul : map₂ (· • ·) f g = f • g :=
rfl
#align filter.map₂_smul Filter.map₂_smul
#align filter.map₂_vadd Filter.map₂_vadd
@[to_additive]
theorem mem_smul : t ∈ f • g ↔ ∃ t₁ ∈ f, ∃ t₂ ∈ g, t₁ • t₂ ⊆ t :=
Iff.rfl
#align filter.mem_smul Filter.mem_smul
#align filter.mem_vadd Filter.mem_vadd
@[to_additive]
theorem smul_mem_smul : s ∈ f → t ∈ g → s • t ∈ f • g :=
image2_mem_map₂
#align filter.smul_mem_smul Filter.smul_mem_smul
#align filter.vadd_mem_vadd Filter.vadd_mem_vadd
@[to_additive (attr := simp)]
theorem bot_smul : (⊥ : Filter α) • g = ⊥ :=
map₂_bot_left