/
Ordset.lean
1800 lines (1516 loc) · 80.6 KB
/
Ordset.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) 2017 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro
-/
import Mathlib.Algebra.Order.Ring.Defs
import Mathlib.Algebra.Group.Int
import Mathlib.Data.Nat.Dist
import Mathlib.Data.Nat.Units
import Mathlib.Data.Ordmap.Ordnode
import Mathlib.Tactic.Abel
import Mathlib.Tactic.Linarith
#align_import data.ordmap.ordset from "leanprover-community/mathlib"@"47b51515e69f59bca5cf34ef456e6000fe205a69"
/-!
# Verification of the `Ordnode α` datatype
This file proves the correctness of the operations in `Data.Ordmap.Ordnode`.
The public facing version is the type `Ordset α`, which is a wrapper around
`Ordnode α` which includes the correctness invariant of the type, and it exposes
parallel operations like `insert` as functions on `Ordset` that do the same
thing but bundle the correctness proofs. The advantage is that it is possible
to, for example, prove that the result of `find` on `insert` will actually find
the element, while `Ordnode` cannot guarantee this if the input tree did not
satisfy the type invariants.
## Main definitions
* `Ordset α`: A well formed set of values of type `α`
## Implementation notes
The majority of this file is actually in the `Ordnode` namespace, because we first
have to prove the correctness of all the operations (and defining what correctness
means here is actually somewhat subtle). So all the actual `Ordset` operations are
at the very end, once we have all the theorems.
An `Ordnode α` is an inductive type which describes a tree which stores the `size` at
internal nodes. The correctness invariant of an `Ordnode α` is:
* `Ordnode.Sized t`: All internal `size` fields must match the actual measured
size of the tree. (This is not hard to satisfy.)
* `Ordnode.Balanced t`: Unless the tree has the form `()` or `((a) b)` or `(a (b))`
(that is, nil or a single singleton subtree), the two subtrees must satisfy
`size l ≤ δ * size r` and `size r ≤ δ * size l`, where `δ := 3` is a global
parameter of the data structure (and this property must hold recursively at subtrees).
This is why we say this is a "size balanced tree" data structure.
* `Ordnode.Bounded lo hi t`: The members of the tree must be in strictly increasing order,
meaning that if `a` is in the left subtree and `b` is the root, then `a ≤ b` and
`¬ (b ≤ a)`. We enforce this using `Ordnode.Bounded` which includes also a global
upper and lower bound.
Because the `Ordnode` file was ported from Haskell, the correctness invariants of some
of the functions have not been spelled out, and some theorems like
`Ordnode.Valid'.balanceL_aux` show very intricate assumptions on the sizes,
which may need to be revised if it turns out some operations violate these assumptions,
because there is a decent amount of slop in the actual data structure invariants, so the
theorem will go through with multiple choices of assumption.
**Note:** This file is incomplete, in the sense that the intent is to have verified
versions and lemmas about all the definitions in `Ordnode.lean`, but at the moment only
a few operations are verified (the hard part should be out of the way, but still).
Contributors are encouraged to pick this up and finish the job, if it appeals to you.
## Tags
ordered map, ordered set, data structure, verified programming
-/
variable {α : Type*}
namespace Ordnode
/-! ### delta and ratio -/
theorem not_le_delta {s} (H : 1 ≤ s) : ¬s ≤ delta * 0 :=
not_le_of_gt H
#align ordnode.not_le_delta Ordnode.not_le_delta
theorem delta_lt_false {a b : ℕ} (h₁ : delta * a < b) (h₂ : delta * b < a) : False :=
not_le_of_lt (lt_trans ((mul_lt_mul_left (by decide)).2 h₁) h₂) <| by
simpa [mul_assoc] using Nat.mul_le_mul_right a (by decide : 1 ≤ delta * delta)
#align ordnode.delta_lt_false Ordnode.delta_lt_false
/-! ### `singleton` -/
/-! ### `size` and `empty` -/
/-- O(n). Computes the actual number of elements in the set, ignoring the cached `size` field. -/
def realSize : Ordnode α → ℕ
| nil => 0
| node _ l _ r => realSize l + realSize r + 1
#align ordnode.real_size Ordnode.realSize
/-! ### `Sized` -/
/-- The `Sized` property asserts that all the `size` fields in nodes match the actual size of the
respective subtrees. -/
def Sized : Ordnode α → Prop
| nil => True
| node s l _ r => s = size l + size r + 1 ∧ Sized l ∧ Sized r
#align ordnode.sized Ordnode.Sized
theorem Sized.node' {l x r} (hl : @Sized α l) (hr : Sized r) : Sized (node' l x r) :=
⟨rfl, hl, hr⟩
#align ordnode.sized.node' Ordnode.Sized.node'
theorem Sized.eq_node' {s l x r} (h : @Sized α (node s l x r)) : node s l x r = .node' l x r := by
rw [h.1]
#align ordnode.sized.eq_node' Ordnode.Sized.eq_node'
theorem Sized.size_eq {s l x r} (H : Sized (@node α s l x r)) :
size (@node α s l x r) = size l + size r + 1 :=
H.1
#align ordnode.sized.size_eq Ordnode.Sized.size_eq
@[elab_as_elim]
theorem Sized.induction {t} (hl : @Sized α t) {C : Ordnode α → Prop} (H0 : C nil)
(H1 : ∀ l x r, C l → C r → C (.node' l x r)) : C t := by
induction t with
| nil => exact H0
| node _ _ _ _ t_ih_l t_ih_r =>
rw [hl.eq_node']
exact H1 _ _ _ (t_ih_l hl.2.1) (t_ih_r hl.2.2)
#align ordnode.sized.induction Ordnode.Sized.induction
theorem size_eq_realSize : ∀ {t : Ordnode α}, Sized t → size t = realSize t
| nil, _ => rfl
| node s l x r, ⟨h₁, h₂, h₃⟩ => by
rw [size, h₁, size_eq_realSize h₂, size_eq_realSize h₃]; rfl
#align ordnode.size_eq_real_size Ordnode.size_eq_realSize
@[simp]
theorem Sized.size_eq_zero {t : Ordnode α} (ht : Sized t) : size t = 0 ↔ t = nil := by
cases t <;> [simp;simp [ht.1]]
#align ordnode.sized.size_eq_zero Ordnode.Sized.size_eq_zero
theorem Sized.pos {s l x r} (h : Sized (@node α s l x r)) : 0 < s := by
rw [h.1]; apply Nat.le_add_left
#align ordnode.sized.pos Ordnode.Sized.pos
/-! `dual` -/
theorem dual_dual : ∀ t : Ordnode α, dual (dual t) = t
| nil => rfl
| node s l x r => by rw [dual, dual, dual_dual l, dual_dual r]
#align ordnode.dual_dual Ordnode.dual_dual
@[simp]
theorem size_dual (t : Ordnode α) : size (dual t) = size t := by cases t <;> rfl
#align ordnode.size_dual Ordnode.size_dual
/-! `Balanced` -/
/-- The `BalancedSz l r` asserts that a hypothetical tree with children of sizes `l` and `r` is
balanced: either `l ≤ δ * r` and `r ≤ δ * r`, or the tree is trivial with a singleton on one side
and nothing on the other. -/
def BalancedSz (l r : ℕ) : Prop :=
l + r ≤ 1 ∨ l ≤ delta * r ∧ r ≤ delta * l
#align ordnode.balanced_sz Ordnode.BalancedSz
instance BalancedSz.dec : DecidableRel BalancedSz := fun _ _ => Or.decidable
#align ordnode.balanced_sz.dec Ordnode.BalancedSz.dec
/-- The `Balanced t` asserts that the tree `t` satisfies the balance invariants
(at every level). -/
def Balanced : Ordnode α → Prop
| nil => True
| node _ l _ r => BalancedSz (size l) (size r) ∧ Balanced l ∧ Balanced r
#align ordnode.balanced Ordnode.Balanced
instance Balanced.dec : DecidablePred (@Balanced α)
| nil => by
unfold Balanced
infer_instance
| node _ l _ r => by
unfold Balanced
haveI := Balanced.dec l
haveI := Balanced.dec r
infer_instance
#align ordnode.balanced.dec Ordnode.Balanced.dec
@[symm]
theorem BalancedSz.symm {l r : ℕ} : BalancedSz l r → BalancedSz r l :=
Or.imp (by rw [add_comm]; exact id) And.symm
#align ordnode.balanced_sz.symm Ordnode.BalancedSz.symm
theorem balancedSz_zero {l : ℕ} : BalancedSz l 0 ↔ l ≤ 1 := by
simp (config := { contextual := true }) [BalancedSz]
#align ordnode.balanced_sz_zero Ordnode.balancedSz_zero
theorem balancedSz_up {l r₁ r₂ : ℕ} (h₁ : r₁ ≤ r₂) (h₂ : l + r₂ ≤ 1 ∨ r₂ ≤ delta * l)
(H : BalancedSz l r₁) : BalancedSz l r₂ := by
refine' or_iff_not_imp_left.2 fun h => _
refine' ⟨_, h₂.resolve_left h⟩
cases H with
| inl H =>
cases r₂
· cases h (le_trans (Nat.add_le_add_left (Nat.zero_le _) _) H)
· exact le_trans (le_trans (Nat.le_add_right _ _) H) (Nat.le_add_left 1 _)
| inr H =>
exact le_trans H.1 (Nat.mul_le_mul_left _ h₁)
#align ordnode.balanced_sz_up Ordnode.balancedSz_up
theorem balancedSz_down {l r₁ r₂ : ℕ} (h₁ : r₁ ≤ r₂) (h₂ : l + r₂ ≤ 1 ∨ l ≤ delta * r₁)
(H : BalancedSz l r₂) : BalancedSz l r₁ :=
have : l + r₂ ≤ 1 → BalancedSz l r₁ := fun H => Or.inl (le_trans (Nat.add_le_add_left h₁ _) H)
Or.casesOn H this fun H => Or.casesOn h₂ this fun h₂ => Or.inr ⟨h₂, le_trans h₁ H.2⟩
#align ordnode.balanced_sz_down Ordnode.balancedSz_down
theorem Balanced.dual : ∀ {t : Ordnode α}, Balanced t → Balanced (dual t)
| nil, _ => ⟨⟩
| node _ l _ r, ⟨b, bl, br⟩ => ⟨by rw [size_dual, size_dual]; exact b.symm, br.dual, bl.dual⟩
#align ordnode.balanced.dual Ordnode.Balanced.dual
/-! ### `rotate` and `balance` -/
/-- Build a tree from three nodes, left associated (ignores the invariants). -/
def node3L (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) : Ordnode α :=
node' (node' l x m) y r
#align ordnode.node3_l Ordnode.node3L
/-- Build a tree from three nodes, right associated (ignores the invariants). -/
def node3R (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) : Ordnode α :=
node' l x (node' m y r)
#align ordnode.node3_r Ordnode.node3R
/-- Build a tree from three nodes, with `a () b -> (a ()) b` and `a (b c) d -> ((a b) (c d))`. -/
def node4L : Ordnode α → α → Ordnode α → α → Ordnode α → Ordnode α
| l, x, node _ ml y mr, z, r => node' (node' l x ml) y (node' mr z r)
| l, x, nil, z, r => node3L l x nil z r
#align ordnode.node4_l Ordnode.node4L
-- should not happen
/-- Build a tree from three nodes, with `a () b -> a (() b)` and `a (b c) d -> ((a b) (c d))`. -/
def node4R : Ordnode α → α → Ordnode α → α → Ordnode α → Ordnode α
| l, x, node _ ml y mr, z, r => node' (node' l x ml) y (node' mr z r)
| l, x, nil, z, r => node3R l x nil z r
#align ordnode.node4_r Ordnode.node4R
-- should not happen
/-- Concatenate two nodes, performing a left rotation `x (y z) -> ((x y) z)`
if balance is upset. -/
def rotateL : Ordnode α → α → Ordnode α → Ordnode α
| l, x, node _ m y r => if size m < ratio * size r then node3L l x m y r else node4L l x m y r
| l, x, nil => node' l x nil
#align ordnode.rotate_l Ordnode.rotateL
-- Porting note (#11467): during the port we marked these lemmas with `@[eqns]`
-- to emulate the old Lean 3 behaviour.
theorem rotateL_node (l : Ordnode α) (x : α) (sz : ℕ) (m : Ordnode α) (y : α) (r : Ordnode α) :
rotateL l x (node sz m y r) =
if size m < ratio * size r then node3L l x m y r else node4L l x m y r :=
rfl
theorem rotateL_nil (l : Ordnode α) (x : α) : rotateL l x nil = node' l x nil :=
rfl
-- should not happen
/-- Concatenate two nodes, performing a right rotation `(x y) z -> (x (y z))`
if balance is upset. -/
def rotateR : Ordnode α → α → Ordnode α → Ordnode α
| node _ l x m, y, r => if size m < ratio * size l then node3R l x m y r else node4R l x m y r
| nil, y, r => node' nil y r
#align ordnode.rotate_r Ordnode.rotateR
-- Porting note (#11467): during the port we marked these lemmas with `@[eqns]`
-- to emulate the old Lean 3 behaviour.
theorem rotateR_node (sz : ℕ) (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) :
rotateR (node sz l x m) y r =
if size m < ratio * size l then node3R l x m y r else node4R l x m y r :=
rfl
theorem rotateR_nil (y : α) (r : Ordnode α) : rotateR nil y r = node' nil y r :=
rfl
-- should not happen
/-- A left balance operation. This will rebalance a concatenation, assuming the original nodes are
not too far from balanced. -/
def balanceL' (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α :=
if size l + size r ≤ 1 then node' l x r
else if size l > delta * size r then rotateR l x r else node' l x r
#align ordnode.balance_l' Ordnode.balanceL'
/-- A right balance operation. This will rebalance a concatenation, assuming the original nodes are
not too far from balanced. -/
def balanceR' (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α :=
if size l + size r ≤ 1 then node' l x r
else if size r > delta * size l then rotateL l x r else node' l x r
#align ordnode.balance_r' Ordnode.balanceR'
/-- The full balance operation. This is the same as `balance`, but with less manual inlining.
It is somewhat easier to work with this version in proofs. -/
def balance' (l : Ordnode α) (x : α) (r : Ordnode α) : Ordnode α :=
if size l + size r ≤ 1 then node' l x r
else
if size r > delta * size l then rotateL l x r
else if size l > delta * size r then rotateR l x r else node' l x r
#align ordnode.balance' Ordnode.balance'
theorem dual_node' (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (node' l x r) = node' (dual r) x (dual l) := by simp [node', add_comm]
#align ordnode.dual_node' Ordnode.dual_node'
theorem dual_node3L (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) :
dual (node3L l x m y r) = node3R (dual r) y (dual m) x (dual l) := by
simp [node3L, node3R, dual_node', add_comm]
#align ordnode.dual_node3_l Ordnode.dual_node3L
theorem dual_node3R (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) :
dual (node3R l x m y r) = node3L (dual r) y (dual m) x (dual l) := by
simp [node3L, node3R, dual_node', add_comm]
#align ordnode.dual_node3_r Ordnode.dual_node3R
theorem dual_node4L (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) :
dual (node4L l x m y r) = node4R (dual r) y (dual m) x (dual l) := by
cases m <;> simp [node4L, node4R, node3R, dual_node3L, dual_node', add_comm]
#align ordnode.dual_node4_l Ordnode.dual_node4L
theorem dual_node4R (l : Ordnode α) (x : α) (m : Ordnode α) (y : α) (r : Ordnode α) :
dual (node4R l x m y r) = node4L (dual r) y (dual m) x (dual l) := by
cases m <;> simp [node4L, node4R, node3L, dual_node3R, dual_node', add_comm]
#align ordnode.dual_node4_r Ordnode.dual_node4R
theorem dual_rotateL (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (rotateL l x r) = rotateR (dual r) x (dual l) := by
cases r <;> simp [rotateL, rotateR, dual_node']; split_ifs <;>
simp [dual_node3L, dual_node4L, node3R, add_comm]
#align ordnode.dual_rotate_l Ordnode.dual_rotateL
theorem dual_rotateR (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (rotateR l x r) = rotateL (dual r) x (dual l) := by
rw [← dual_dual (rotateL _ _ _), dual_rotateL, dual_dual, dual_dual]
#align ordnode.dual_rotate_r Ordnode.dual_rotateR
theorem dual_balance' (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (balance' l x r) = balance' (dual r) x (dual l) := by
simp [balance', add_comm]; split_ifs with h h_1 h_2 <;>
simp [dual_node', dual_rotateL, dual_rotateR, add_comm]
cases delta_lt_false h_1 h_2
#align ordnode.dual_balance' Ordnode.dual_balance'
theorem dual_balanceL (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (balanceL l x r) = balanceR (dual r) x (dual l) := by
unfold balanceL balanceR
cases' r with rs rl rx rr
· cases' l with ls ll lx lr; · rfl
cases' ll with lls lll llx llr <;> cases' lr with lrs lrl lrx lrr <;> dsimp only [dual, id] <;>
try rfl
split_ifs with h <;> repeat simp [h, add_comm]
· cases' l with ls ll lx lr; · rfl
dsimp only [dual, id]
split_ifs; swap; · simp [add_comm]
cases' ll with lls lll llx llr <;> cases' lr with lrs lrl lrx lrr <;> try rfl
dsimp only [dual, id]
split_ifs with h <;> simp [h, add_comm]
#align ordnode.dual_balance_l Ordnode.dual_balanceL
theorem dual_balanceR (l : Ordnode α) (x : α) (r : Ordnode α) :
dual (balanceR l x r) = balanceL (dual r) x (dual l) := by
rw [← dual_dual (balanceL _ _ _), dual_balanceL, dual_dual, dual_dual]
#align ordnode.dual_balance_r Ordnode.dual_balanceR
theorem Sized.node3L {l x m y r} (hl : @Sized α l) (hm : Sized m) (hr : Sized r) :
Sized (node3L l x m y r) :=
(hl.node' hm).node' hr
#align ordnode.sized.node3_l Ordnode.Sized.node3L
theorem Sized.node3R {l x m y r} (hl : @Sized α l) (hm : Sized m) (hr : Sized r) :
Sized (node3R l x m y r) :=
hl.node' (hm.node' hr)
#align ordnode.sized.node3_r Ordnode.Sized.node3R
theorem Sized.node4L {l x m y r} (hl : @Sized α l) (hm : Sized m) (hr : Sized r) :
Sized (node4L l x m y r) := by
cases m <;> [exact (hl.node' hm).node' hr; exact (hl.node' hm.2.1).node' (hm.2.2.node' hr)]
#align ordnode.sized.node4_l Ordnode.Sized.node4L
theorem node3L_size {l x m y r} : size (@node3L α l x m y r) = size l + size m + size r + 2 := by
dsimp [node3L, node', size]; rw [add_right_comm _ 1]
#align ordnode.node3_l_size Ordnode.node3L_size
theorem node3R_size {l x m y r} : size (@node3R α l x m y r) = size l + size m + size r + 2 := by
dsimp [node3R, node', size]; rw [← add_assoc, ← add_assoc]
#align ordnode.node3_r_size Ordnode.node3R_size
theorem node4L_size {l x m y r} (hm : Sized m) :
size (@node4L α l x m y r) = size l + size m + size r + 2 := by
cases m <;> simp [node4L, node3L, node'] <;> [abel; (simp [size, hm.1]; abel)]
#align ordnode.node4_l_size Ordnode.node4L_size
theorem Sized.dual : ∀ {t : Ordnode α}, Sized t → Sized (dual t)
| nil, _ => ⟨⟩
| node _ l _ r, ⟨rfl, sl, sr⟩ => ⟨by simp [size_dual, add_comm], Sized.dual sr, Sized.dual sl⟩
#align ordnode.sized.dual Ordnode.Sized.dual
theorem Sized.dual_iff {t : Ordnode α} : Sized (.dual t) ↔ Sized t :=
⟨fun h => by rw [← dual_dual t]; exact h.dual, Sized.dual⟩
#align ordnode.sized.dual_iff Ordnode.Sized.dual_iff
theorem Sized.rotateL {l x r} (hl : @Sized α l) (hr : Sized r) : Sized (rotateL l x r) := by
cases r; · exact hl.node' hr
rw [Ordnode.rotateL_node]; split_ifs
· exact hl.node3L hr.2.1 hr.2.2
· exact hl.node4L hr.2.1 hr.2.2
#align ordnode.sized.rotate_l Ordnode.Sized.rotateL
theorem Sized.rotateR {l x r} (hl : @Sized α l) (hr : Sized r) : Sized (rotateR l x r) :=
Sized.dual_iff.1 <| by rw [dual_rotateR]; exact hr.dual.rotateL hl.dual
#align ordnode.sized.rotate_r Ordnode.Sized.rotateR
theorem Sized.rotateL_size {l x r} (hm : Sized r) :
size (@Ordnode.rotateL α l x r) = size l + size r + 1 := by
cases r <;> simp [Ordnode.rotateL]
simp only [hm.1]
split_ifs <;> simp [node3L_size, node4L_size hm.2.1] <;> abel
#align ordnode.sized.rotate_l_size Ordnode.Sized.rotateL_size
theorem Sized.rotateR_size {l x r} (hl : Sized l) :
size (@Ordnode.rotateR α l x r) = size l + size r + 1 := by
rw [← size_dual, dual_rotateR, hl.dual.rotateL_size, size_dual, size_dual, add_comm (size l)]
#align ordnode.sized.rotate_r_size Ordnode.Sized.rotateR_size
theorem Sized.balance' {l x r} (hl : @Sized α l) (hr : Sized r) : Sized (balance' l x r) := by
unfold balance'; split_ifs
· exact hl.node' hr
· exact hl.rotateL hr
· exact hl.rotateR hr
· exact hl.node' hr
#align ordnode.sized.balance' Ordnode.Sized.balance'
theorem size_balance' {l x r} (hl : @Sized α l) (hr : Sized r) :
size (@balance' α l x r) = size l + size r + 1 := by
unfold balance'; split_ifs
· rfl
· exact hr.rotateL_size
· exact hl.rotateR_size
· rfl
#align ordnode.size_balance' Ordnode.size_balance'
/-! ## `All`, `Any`, `Emem`, `Amem` -/
theorem All.imp {P Q : α → Prop} (H : ∀ a, P a → Q a) : ∀ {t}, All P t → All Q t
| nil, _ => ⟨⟩
| node _ _ _ _, ⟨h₁, h₂, h₃⟩ => ⟨h₁.imp H, H _ h₂, h₃.imp H⟩
#align ordnode.all.imp Ordnode.All.imp
theorem Any.imp {P Q : α → Prop} (H : ∀ a, P a → Q a) : ∀ {t}, Any P t → Any Q t
| nil => id
| node _ _ _ _ => Or.imp (Any.imp H) <| Or.imp (H _) (Any.imp H)
#align ordnode.any.imp Ordnode.Any.imp
theorem all_singleton {P : α → Prop} {x : α} : All P (singleton x) ↔ P x :=
⟨fun h => h.2.1, fun h => ⟨⟨⟩, h, ⟨⟩⟩⟩
#align ordnode.all_singleton Ordnode.all_singleton
theorem any_singleton {P : α → Prop} {x : α} : Any P (singleton x) ↔ P x :=
⟨by rintro (⟨⟨⟩⟩ | h | ⟨⟨⟩⟩); exact h, fun h => Or.inr (Or.inl h)⟩
#align ordnode.any_singleton Ordnode.any_singleton
theorem all_dual {P : α → Prop} : ∀ {t : Ordnode α}, All P (dual t) ↔ All P t
| nil => Iff.rfl
| node _ _l _x _r =>
⟨fun ⟨hr, hx, hl⟩ => ⟨all_dual.1 hl, hx, all_dual.1 hr⟩, fun ⟨hl, hx, hr⟩ =>
⟨all_dual.2 hr, hx, all_dual.2 hl⟩⟩
#align ordnode.all_dual Ordnode.all_dual
theorem all_iff_forall {P : α → Prop} : ∀ {t}, All P t ↔ ∀ x, Emem x t → P x
| nil => (iff_true_intro <| by rintro _ ⟨⟩).symm
| node _ l x r => by simp [All, Emem, all_iff_forall, Any, or_imp, forall_and]
#align ordnode.all_iff_forall Ordnode.all_iff_forall
theorem any_iff_exists {P : α → Prop} : ∀ {t}, Any P t ↔ ∃ x, Emem x t ∧ P x
| nil => ⟨by rintro ⟨⟩, by rintro ⟨_, ⟨⟩, _⟩⟩
| node _ l x r => by simp only [Emem]; simp [Any, any_iff_exists, or_and_right, exists_or]
#align ordnode.any_iff_exists Ordnode.any_iff_exists
theorem emem_iff_all {x : α} {t} : Emem x t ↔ ∀ P, All P t → P x :=
⟨fun h _ al => all_iff_forall.1 al _ h, fun H => H _ <| all_iff_forall.2 fun _ => id⟩
#align ordnode.emem_iff_all Ordnode.emem_iff_all
theorem all_node' {P l x r} : @All α P (node' l x r) ↔ All P l ∧ P x ∧ All P r :=
Iff.rfl
#align ordnode.all_node' Ordnode.all_node'
theorem all_node3L {P l x m y r} :
@All α P (node3L l x m y r) ↔ All P l ∧ P x ∧ All P m ∧ P y ∧ All P r := by
simp [node3L, all_node', and_assoc]
#align ordnode.all_node3_l Ordnode.all_node3L
theorem all_node3R {P l x m y r} :
@All α P (node3R l x m y r) ↔ All P l ∧ P x ∧ All P m ∧ P y ∧ All P r :=
Iff.rfl
#align ordnode.all_node3_r Ordnode.all_node3R
theorem all_node4L {P l x m y r} :
@All α P (node4L l x m y r) ↔ All P l ∧ P x ∧ All P m ∧ P y ∧ All P r := by
cases m <;> simp [node4L, all_node', All, all_node3L, and_assoc]
#align ordnode.all_node4_l Ordnode.all_node4L
theorem all_node4R {P l x m y r} :
@All α P (node4R l x m y r) ↔ All P l ∧ P x ∧ All P m ∧ P y ∧ All P r := by
cases m <;> simp [node4R, all_node', All, all_node3R, and_assoc]
#align ordnode.all_node4_r Ordnode.all_node4R
theorem all_rotateL {P l x r} : @All α P (rotateL l x r) ↔ All P l ∧ P x ∧ All P r := by
cases r <;> simp [rotateL, all_node']; split_ifs <;>
simp [all_node3L, all_node4L, All, and_assoc]
#align ordnode.all_rotate_l Ordnode.all_rotateL
theorem all_rotateR {P l x r} : @All α P (rotateR l x r) ↔ All P l ∧ P x ∧ All P r := by
rw [← all_dual, dual_rotateR, all_rotateL]; simp [all_dual, and_comm, and_left_comm, and_assoc]
#align ordnode.all_rotate_r Ordnode.all_rotateR
theorem all_balance' {P l x r} : @All α P (balance' l x r) ↔ All P l ∧ P x ∧ All P r := by
rw [balance']; split_ifs <;> simp [all_node', all_rotateL, all_rotateR]
#align ordnode.all_balance' Ordnode.all_balance'
/-! ### `toList` -/
theorem foldr_cons_eq_toList : ∀ (t : Ordnode α) (r : List α), t.foldr List.cons r = toList t ++ r
| nil, r => rfl
| node _ l x r, r' => by
rw [foldr, foldr_cons_eq_toList l, foldr_cons_eq_toList r, ← List.cons_append,
← List.append_assoc, ← foldr_cons_eq_toList l]; rfl
#align ordnode.foldr_cons_eq_to_list Ordnode.foldr_cons_eq_toList
@[simp]
theorem toList_nil : toList (@nil α) = [] :=
rfl
#align ordnode.to_list_nil Ordnode.toList_nil
@[simp]
theorem toList_node (s l x r) : toList (@node α s l x r) = toList l ++ x :: toList r := by
rw [toList, foldr, foldr_cons_eq_toList]; rfl
#align ordnode.to_list_node Ordnode.toList_node
theorem emem_iff_mem_toList {x : α} {t} : Emem x t ↔ x ∈ toList t := by
unfold Emem; induction t <;> simp [Any, *, or_assoc]
#align ordnode.emem_iff_mem_to_list Ordnode.emem_iff_mem_toList
theorem length_toList' : ∀ t : Ordnode α, (toList t).length = t.realSize
| nil => rfl
| node _ l _ r => by
rw [toList_node, List.length_append, List.length_cons, length_toList' l,
length_toList' r]; rfl
#align ordnode.length_to_list' Ordnode.length_toList'
theorem length_toList {t : Ordnode α} (h : Sized t) : (toList t).length = t.size := by
rw [length_toList', size_eq_realSize h]
#align ordnode.length_to_list Ordnode.length_toList
theorem equiv_iff {t₁ t₂ : Ordnode α} (h₁ : Sized t₁) (h₂ : Sized t₂) :
Equiv t₁ t₂ ↔ toList t₁ = toList t₂ :=
and_iff_right_of_imp fun h => by rw [← length_toList h₁, h, length_toList h₂]
#align ordnode.equiv_iff Ordnode.equiv_iff
/-! ### `mem` -/
theorem pos_size_of_mem [LE α] [@DecidableRel α (· ≤ ·)] {x : α} {t : Ordnode α} (h : Sized t)
(h_mem : x ∈ t) : 0 < size t := by cases t; · { contradiction }; · { simp [h.1] }
#align ordnode.pos_size_of_mem Ordnode.pos_size_of_mem
/-! ### `(find/erase/split)(Min/Max)` -/
theorem findMin'_dual : ∀ (t) (x : α), findMin' (dual t) x = findMax' x t
| nil, _ => rfl
| node _ _ x r, _ => findMin'_dual r x
#align ordnode.find_min'_dual Ordnode.findMin'_dual
theorem findMax'_dual (t) (x : α) : findMax' x (dual t) = findMin' t x := by
rw [← findMin'_dual, dual_dual]
#align ordnode.find_max'_dual Ordnode.findMax'_dual
theorem findMin_dual : ∀ t : Ordnode α, findMin (dual t) = findMax t
| nil => rfl
| node _ _ _ _ => congr_arg some <| findMin'_dual _ _
#align ordnode.find_min_dual Ordnode.findMin_dual
theorem findMax_dual (t : Ordnode α) : findMax (dual t) = findMin t := by
rw [← findMin_dual, dual_dual]
#align ordnode.find_max_dual Ordnode.findMax_dual
theorem dual_eraseMin : ∀ t : Ordnode α, dual (eraseMin t) = eraseMax (dual t)
| nil => rfl
| node _ nil x r => rfl
| node _ (node sz l' y r') x r => by
rw [eraseMin, dual_balanceR, dual_eraseMin (node sz l' y r'), dual, dual, dual, eraseMax]
#align ordnode.dual_erase_min Ordnode.dual_eraseMin
theorem dual_eraseMax (t : Ordnode α) : dual (eraseMax t) = eraseMin (dual t) := by
rw [← dual_dual (eraseMin _), dual_eraseMin, dual_dual]
#align ordnode.dual_erase_max Ordnode.dual_eraseMax
theorem splitMin_eq :
∀ (s l) (x : α) (r), splitMin' l x r = (findMin' l x, eraseMin (node s l x r))
| _, nil, x, r => rfl
| _, node ls ll lx lr, x, r => by rw [splitMin', splitMin_eq ls ll lx lr, findMin', eraseMin]
#align ordnode.split_min_eq Ordnode.splitMin_eq
theorem splitMax_eq :
∀ (s l) (x : α) (r), splitMax' l x r = (eraseMax (node s l x r), findMax' x r)
| _, l, x, nil => rfl
| _, l, x, node ls ll lx lr => by rw [splitMax', splitMax_eq ls ll lx lr, findMax', eraseMax]
#align ordnode.split_max_eq Ordnode.splitMax_eq
-- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type
theorem findMin'_all {P : α → Prop} : ∀ (t) (x : α), All P t → P x → P (findMin' t x)
| nil, _x, _, hx => hx
| node _ ll lx _, _, ⟨h₁, h₂, _⟩, _ => findMin'_all ll lx h₁ h₂
#align ordnode.find_min'_all Ordnode.findMin'_all
-- @[elab_as_elim] -- Porting note: unexpected eliminator resulting type
theorem findMax'_all {P : α → Prop} : ∀ (x : α) (t), P x → All P t → P (findMax' x t)
| _x, nil, hx, _ => hx
| _, node _ _ lx lr, _, ⟨_, h₂, h₃⟩ => findMax'_all lx lr h₂ h₃
#align ordnode.find_max'_all Ordnode.findMax'_all
/-! ### `glue` -/
/-! ### `merge` -/
@[simp]
theorem merge_nil_left (t : Ordnode α) : merge t nil = t := by cases t <;> rfl
#align ordnode.merge_nil_left Ordnode.merge_nil_left
@[simp]
theorem merge_nil_right (t : Ordnode α) : merge nil t = t :=
rfl
#align ordnode.merge_nil_right Ordnode.merge_nil_right
@[simp]
theorem merge_node {ls ll lx lr rs rl rx rr} :
merge (@node α ls ll lx lr) (node rs rl rx rr) =
if delta * ls < rs then balanceL (merge (node ls ll lx lr) rl) rx rr
else if delta * rs < ls then balanceR ll lx (merge lr (node rs rl rx rr))
else glue (node ls ll lx lr) (node rs rl rx rr) :=
rfl
#align ordnode.merge_node Ordnode.merge_node
/-! ### `insert` -/
theorem dual_insert [Preorder α] [IsTotal α (· ≤ ·)] [@DecidableRel α (· ≤ ·)] (x : α) :
∀ t : Ordnode α, dual (Ordnode.insert x t) = @Ordnode.insert αᵒᵈ _ _ x (dual t)
| nil => rfl
| node _ l y r => by
have : @cmpLE αᵒᵈ _ _ x y = cmpLE y x := rfl
rw [Ordnode.insert, dual, Ordnode.insert, this, ← cmpLE_swap x y]
cases cmpLE x y <;>
simp [Ordering.swap, Ordnode.insert, dual_balanceL, dual_balanceR, dual_insert]
#align ordnode.dual_insert Ordnode.dual_insert
/-! ### `balance` properties -/
theorem balance_eq_balance' {l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l)
(sr : Sized r) : @balance α l x r = balance' l x r := by
cases' l with ls ll lx lr
· cases' r with rs rl rx rr
· rfl
· rw [sr.eq_node'] at hr ⊢
cases' rl with rls rll rlx rlr <;> cases' rr with rrs rrl rrx rrr <;>
dsimp [balance, balance']
· rfl
· have : size rrl = 0 ∧ size rrr = 0 := by
have := balancedSz_zero.1 hr.1.symm
rwa [size, sr.2.2.1, Nat.succ_le_succ_iff, Nat.le_zero, add_eq_zero_iff] at this
cases sr.2.2.2.1.size_eq_zero.1 this.1
cases sr.2.2.2.2.size_eq_zero.1 this.2
obtain rfl : rrs = 1 := sr.2.2.1
rw [if_neg, if_pos, rotateL_node, if_pos]; · rfl
all_goals dsimp only [size]; decide
· have : size rll = 0 ∧ size rlr = 0 := by
have := balancedSz_zero.1 hr.1
rwa [size, sr.2.1.1, Nat.succ_le_succ_iff, Nat.le_zero, add_eq_zero_iff] at this
cases sr.2.1.2.1.size_eq_zero.1 this.1
cases sr.2.1.2.2.size_eq_zero.1 this.2
obtain rfl : rls = 1 := sr.2.1.1
rw [if_neg, if_pos, rotateL_node, if_neg]; · rfl
all_goals dsimp only [size]; decide
· symm; rw [zero_add, if_neg, if_pos, rotateL]
· dsimp only [size_node]; split_ifs
· simp [node3L, node']; abel
· simp [node4L, node', sr.2.1.1]; abel
· apply Nat.zero_lt_succ
· exact not_le_of_gt (Nat.succ_lt_succ (add_pos sr.2.1.pos sr.2.2.pos))
· cases' r with rs rl rx rr
· rw [sl.eq_node'] at hl ⊢
cases' ll with lls lll llx llr <;> cases' lr with lrs lrl lrx lrr <;>
dsimp [balance, balance']
· rfl
· have : size lrl = 0 ∧ size lrr = 0 := by
have := balancedSz_zero.1 hl.1.symm
rwa [size, sl.2.2.1, Nat.succ_le_succ_iff, Nat.le_zero, add_eq_zero_iff] at this
cases sl.2.2.2.1.size_eq_zero.1 this.1
cases sl.2.2.2.2.size_eq_zero.1 this.2
obtain rfl : lrs = 1 := sl.2.2.1
rw [if_neg, if_neg, if_pos, rotateR_node, if_neg]; · rfl
all_goals dsimp only [size]; decide
· have : size lll = 0 ∧ size llr = 0 := by
have := balancedSz_zero.1 hl.1
rwa [size, sl.2.1.1, Nat.succ_le_succ_iff, Nat.le_zero, add_eq_zero_iff] at this
cases sl.2.1.2.1.size_eq_zero.1 this.1
cases sl.2.1.2.2.size_eq_zero.1 this.2
obtain rfl : lls = 1 := sl.2.1.1
rw [if_neg, if_neg, if_pos, rotateR_node, if_pos]; · rfl
all_goals dsimp only [size]; decide
· symm; rw [if_neg, if_neg, if_pos, rotateR]
· dsimp only [size_node]; split_ifs
· simp [node3R, node']; abel
· simp [node4R, node', sl.2.2.1]; abel
· apply Nat.zero_lt_succ
· apply Nat.not_lt_zero
· exact not_le_of_gt (Nat.succ_lt_succ (add_pos sl.2.1.pos sl.2.2.pos))
· simp [balance, balance']
symm; rw [if_neg]
· split_ifs with h h_1
· have rd : delta ≤ size rl + size rr := by
have := lt_of_le_of_lt (Nat.mul_le_mul_left _ sl.pos) h
rwa [sr.1, Nat.lt_succ_iff] at this
cases' rl with rls rll rlx rlr
· rw [size, zero_add] at rd
exact absurd (le_trans rd (balancedSz_zero.1 hr.1.symm)) (by decide)
cases' rr with rrs rrl rrx rrr
· exact absurd (le_trans rd (balancedSz_zero.1 hr.1)) (by decide)
dsimp [rotateL]; split_ifs
· simp [node3L, node', sr.1]; abel
· simp [node4L, node', sr.1, sr.2.1.1]; abel
· have ld : delta ≤ size ll + size lr := by
have := lt_of_le_of_lt (Nat.mul_le_mul_left _ sr.pos) h_1
rwa [sl.1, Nat.lt_succ_iff] at this
cases' ll with lls lll llx llr
· rw [size, zero_add] at ld
exact absurd (le_trans ld (balancedSz_zero.1 hl.1.symm)) (by decide)
cases' lr with lrs lrl lrx lrr
· exact absurd (le_trans ld (balancedSz_zero.1 hl.1)) (by decide)
dsimp [rotateR]; split_ifs
· simp [node3R, node', sl.1]; abel
· simp [node4R, node', sl.1, sl.2.2.1]; abel
· simp [node']
· exact not_le_of_gt (add_le_add (Nat.succ_le_of_lt sl.pos) (Nat.succ_le_of_lt sr.pos))
#align ordnode.balance_eq_balance' Ordnode.balance_eq_balance'
theorem balanceL_eq_balance {l x r} (sl : Sized l) (sr : Sized r) (H1 : size l = 0 → size r ≤ 1)
(H2 : 1 ≤ size l → 1 ≤ size r → size r ≤ delta * size l) :
@balanceL α l x r = balance l x r := by
cases' r with rs rl rx rr
· rfl
· cases' l with ls ll lx lr
· have : size rl = 0 ∧ size rr = 0 := by
have := H1 rfl
rwa [size, sr.1, Nat.succ_le_succ_iff, Nat.le_zero, add_eq_zero_iff] at this
cases sr.2.1.size_eq_zero.1 this.1
cases sr.2.2.size_eq_zero.1 this.2
rw [sr.eq_node']; rfl
· replace H2 : ¬rs > delta * ls := not_lt_of_le (H2 sl.pos sr.pos)
simp [balanceL, balance, H2]; split_ifs <;> simp [add_comm]
#align ordnode.balance_l_eq_balance Ordnode.balanceL_eq_balance
/-- `Raised n m` means `m` is either equal or one up from `n`. -/
def Raised (n m : ℕ) : Prop :=
m = n ∨ m = n + 1
#align ordnode.raised Ordnode.Raised
theorem raised_iff {n m} : Raised n m ↔ n ≤ m ∧ m ≤ n + 1 := by
constructor
· rintro (rfl | rfl)
· exact ⟨le_rfl, Nat.le_succ _⟩
· exact ⟨Nat.le_succ _, le_rfl⟩
· rintro ⟨h₁, h₂⟩
rcases eq_or_lt_of_le h₁ with (rfl | h₁)
· exact Or.inl rfl
· exact Or.inr (le_antisymm h₂ h₁)
#align ordnode.raised_iff Ordnode.raised_iff
theorem Raised.dist_le {n m} (H : Raised n m) : Nat.dist n m ≤ 1 := by
cases' raised_iff.1 H with H1 H2; rwa [Nat.dist_eq_sub_of_le H1, tsub_le_iff_left]
#align ordnode.raised.dist_le Ordnode.Raised.dist_le
theorem Raised.dist_le' {n m} (H : Raised n m) : Nat.dist m n ≤ 1 := by
rw [Nat.dist_comm]; exact H.dist_le
#align ordnode.raised.dist_le' Ordnode.Raised.dist_le'
theorem Raised.add_left (k) {n m} (H : Raised n m) : Raised (k + n) (k + m) := by
rcases H with (rfl | rfl)
· exact Or.inl rfl
· exact Or.inr rfl
#align ordnode.raised.add_left Ordnode.Raised.add_left
theorem Raised.add_right (k) {n m} (H : Raised n m) : Raised (n + k) (m + k) := by
rw [add_comm, add_comm m]; exact H.add_left _
#align ordnode.raised.add_right Ordnode.Raised.add_right
theorem Raised.right {l x₁ x₂ r₁ r₂} (H : Raised (size r₁) (size r₂)) :
Raised (size (@node' α l x₁ r₁)) (size (@node' α l x₂ r₂)) := by
rw [node', size_node, size_node]; generalize size r₂ = m at H ⊢
rcases H with (rfl | rfl)
· exact Or.inl rfl
· exact Or.inr rfl
#align ordnode.raised.right Ordnode.Raised.right
theorem balanceL_eq_balance' {l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l)
(sr : Sized r)
(H :
(∃ l', Raised l' (size l) ∧ BalancedSz l' (size r)) ∨
∃ r', Raised (size r) r' ∧ BalancedSz (size l) r') :
@balanceL α l x r = balance' l x r := by
rw [← balance_eq_balance' hl hr sl sr, balanceL_eq_balance sl sr]
· intro l0; rw [l0] at H
rcases H with (⟨_, ⟨⟨⟩⟩ | ⟨⟨⟩⟩, H⟩ | ⟨r', e, H⟩)
· exact balancedSz_zero.1 H.symm
exact le_trans (raised_iff.1 e).1 (balancedSz_zero.1 H.symm)
· intro l1 _
rcases H with (⟨l', e, H | ⟨_, H₂⟩⟩ | ⟨r', e, H | ⟨_, H₂⟩⟩)
· exact le_trans (le_trans (Nat.le_add_left _ _) H) (mul_pos (by decide) l1 : (0 : ℕ) < _)
· exact le_trans H₂ (Nat.mul_le_mul_left _ (raised_iff.1 e).1)
· cases raised_iff.1 e; unfold delta; omega
· exact le_trans (raised_iff.1 e).1 H₂
#align ordnode.balance_l_eq_balance' Ordnode.balanceL_eq_balance'
theorem balance_sz_dual {l r}
(H : (∃ l', Raised (@size α l) l' ∧ BalancedSz l' (@size α r)) ∨
∃ r', Raised r' (size r) ∧ BalancedSz (size l) r') :
(∃ l', Raised l' (size (dual r)) ∧ BalancedSz l' (size (dual l))) ∨
∃ r', Raised (size (dual l)) r' ∧ BalancedSz (size (dual r)) r' := by
rw [size_dual, size_dual]
exact
H.symm.imp (Exists.imp fun _ => And.imp_right BalancedSz.symm)
(Exists.imp fun _ => And.imp_right BalancedSz.symm)
#align ordnode.balance_sz_dual Ordnode.balance_sz_dual
theorem size_balanceL {l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l) (sr : Sized r)
(H : (∃ l', Raised l' (size l) ∧ BalancedSz l' (size r)) ∨
∃ r', Raised (size r) r' ∧ BalancedSz (size l) r') :
size (@balanceL α l x r) = size l + size r + 1 := by
rw [balanceL_eq_balance' hl hr sl sr H, size_balance' sl sr]
#align ordnode.size_balance_l Ordnode.size_balanceL
theorem all_balanceL {P l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l) (sr : Sized r)
(H :
(∃ l', Raised l' (size l) ∧ BalancedSz l' (size r)) ∨
∃ r', Raised (size r) r' ∧ BalancedSz (size l) r') :
All P (@balanceL α l x r) ↔ All P l ∧ P x ∧ All P r := by
rw [balanceL_eq_balance' hl hr sl sr H, all_balance']
#align ordnode.all_balance_l Ordnode.all_balanceL
theorem balanceR_eq_balance' {l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l)
(sr : Sized r)
(H : (∃ l', Raised (size l) l' ∧ BalancedSz l' (size r)) ∨
∃ r', Raised r' (size r) ∧ BalancedSz (size l) r') :
@balanceR α l x r = balance' l x r := by
rw [← dual_dual (balanceR l x r), dual_balanceR,
balanceL_eq_balance' hr.dual hl.dual sr.dual sl.dual (balance_sz_dual H), ← dual_balance',
dual_dual]
#align ordnode.balance_r_eq_balance' Ordnode.balanceR_eq_balance'
theorem size_balanceR {l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l) (sr : Sized r)
(H : (∃ l', Raised (size l) l' ∧ BalancedSz l' (size r)) ∨
∃ r', Raised r' (size r) ∧ BalancedSz (size l) r') :
size (@balanceR α l x r) = size l + size r + 1 := by
rw [balanceR_eq_balance' hl hr sl sr H, size_balance' sl sr]
#align ordnode.size_balance_r Ordnode.size_balanceR
theorem all_balanceR {P l x r} (hl : Balanced l) (hr : Balanced r) (sl : Sized l) (sr : Sized r)
(H :
(∃ l', Raised (size l) l' ∧ BalancedSz l' (size r)) ∨
∃ r', Raised r' (size r) ∧ BalancedSz (size l) r') :
All P (@balanceR α l x r) ↔ All P l ∧ P x ∧ All P r := by
rw [balanceR_eq_balance' hl hr sl sr H, all_balance']
#align ordnode.all_balance_r Ordnode.all_balanceR
/-! ### `bounded` -/
section
variable [Preorder α]
/-- `Bounded t lo hi` says that every element `x ∈ t` is in the range `lo < x < hi`, and also this
property holds recursively in subtrees, making the full tree a BST. The bounds can be set to
`lo = ⊥` and `hi = ⊤` if we care only about the internal ordering constraints. -/
def Bounded : Ordnode α → WithBot α → WithTop α → Prop
| nil, some a, some b => a < b
| nil, _, _ => True
| node _ l x r, o₁, o₂ => Bounded l o₁ x ∧ Bounded r (↑x) o₂
#align ordnode.bounded Ordnode.Bounded
theorem Bounded.dual :
∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → @Bounded αᵒᵈ _ (dual t) o₂ o₁
| nil, o₁, o₂, h => by cases o₁ <;> cases o₂ <;> trivial
| node _ l x r, _, _, ⟨ol, Or⟩ => ⟨Or.dual, ol.dual⟩
#align ordnode.bounded.dual Ordnode.Bounded.dual
theorem Bounded.dual_iff {t : Ordnode α} {o₁ o₂} :
Bounded t o₁ o₂ ↔ @Bounded αᵒᵈ _ (.dual t) o₂ o₁ :=
⟨Bounded.dual, fun h => by
have := Bounded.dual h; rwa [dual_dual, OrderDual.Preorder.dual_dual] at this⟩
#align ordnode.bounded.dual_iff Ordnode.Bounded.dual_iff
theorem Bounded.weak_left : ∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → Bounded t ⊥ o₂
| nil, o₁, o₂, h => by cases o₂ <;> trivial
| node _ l x r, _, _, ⟨ol, Or⟩ => ⟨ol.weak_left, Or⟩
#align ordnode.bounded.weak_left Ordnode.Bounded.weak_left
theorem Bounded.weak_right : ∀ {t : Ordnode α} {o₁ o₂}, Bounded t o₁ o₂ → Bounded t o₁ ⊤
| nil, o₁, o₂, h => by cases o₁ <;> trivial
| node _ l x r, _, _, ⟨ol, Or⟩ => ⟨ol, Or.weak_right⟩
#align ordnode.bounded.weak_right Ordnode.Bounded.weak_right
theorem Bounded.weak {t : Ordnode α} {o₁ o₂} (h : Bounded t o₁ o₂) : Bounded t ⊥ ⊤ :=
h.weak_left.weak_right
#align ordnode.bounded.weak Ordnode.Bounded.weak
theorem Bounded.mono_left {x y : α} (xy : x ≤ y) :
∀ {t : Ordnode α} {o}, Bounded t y o → Bounded t x o
| nil, none, _ => ⟨⟩
| nil, some _, h => lt_of_le_of_lt xy h
| node _ _ _ _, _o, ⟨ol, or⟩ => ⟨ol.mono_left xy, or⟩
#align ordnode.bounded.mono_left Ordnode.Bounded.mono_left
theorem Bounded.mono_right {x y : α} (xy : x ≤ y) :
∀ {t : Ordnode α} {o}, Bounded t o x → Bounded t o y
| nil, none, _ => ⟨⟩
| nil, some _, h => lt_of_lt_of_le h xy
| node _ _ _ _, _o, ⟨ol, or⟩ => ⟨ol, or.mono_right xy⟩
#align ordnode.bounded.mono_right Ordnode.Bounded.mono_right
theorem Bounded.to_lt : ∀ {t : Ordnode α} {x y : α}, Bounded t x y → x < y
| nil, _, _, h => h
| node _ _ _ _, _, _, ⟨h₁, h₂⟩ => lt_trans h₁.to_lt h₂.to_lt
#align ordnode.bounded.to_lt Ordnode.Bounded.to_lt
theorem Bounded.to_nil {t : Ordnode α} : ∀ {o₁ o₂}, Bounded t o₁ o₂ → Bounded nil o₁ o₂
| none, _, _ => ⟨⟩
| some _, none, _ => ⟨⟩
| some _, some _, h => h.to_lt
#align ordnode.bounded.to_nil Ordnode.Bounded.to_nil
theorem Bounded.trans_left {t₁ t₂ : Ordnode α} {x : α} :
∀ {o₁ o₂}, Bounded t₁ o₁ x → Bounded t₂ x o₂ → Bounded t₂ o₁ o₂
| none, _, _, h₂ => h₂.weak_left
| some _, _, h₁, h₂ => h₂.mono_left (le_of_lt h₁.to_lt)
#align ordnode.bounded.trans_left Ordnode.Bounded.trans_left
theorem Bounded.trans_right {t₁ t₂ : Ordnode α} {x : α} :
∀ {o₁ o₂}, Bounded t₁ o₁ x → Bounded t₂ x o₂ → Bounded t₁ o₁ o₂
| _, none, h₁, _ => h₁.weak_right
| _, some _, h₁, h₂ => h₁.mono_right (le_of_lt h₂.to_lt)
#align ordnode.bounded.trans_right Ordnode.Bounded.trans_right
theorem Bounded.mem_lt : ∀ {t o} {x : α}, Bounded t o x → All (· < x) t
| nil, _, _, _ => ⟨⟩
| node _ _ _ _, _, _, ⟨h₁, h₂⟩ =>
⟨h₁.mem_lt.imp fun _ h => lt_trans h h₂.to_lt, h₂.to_lt, h₂.mem_lt⟩
#align ordnode.bounded.mem_lt Ordnode.Bounded.mem_lt
theorem Bounded.mem_gt : ∀ {t o} {x : α}, Bounded t x o → All (· > x) t
| nil, _, _, _ => ⟨⟩
| node _ _ _ _, _, _, ⟨h₁, h₂⟩ => ⟨h₁.mem_gt, h₁.to_lt, h₂.mem_gt.imp fun _ => lt_trans h₁.to_lt⟩
#align ordnode.bounded.mem_gt Ordnode.Bounded.mem_gt
theorem Bounded.of_lt :
∀ {t o₁ o₂} {x : α}, Bounded t o₁ o₂ → Bounded nil o₁ x → All (· < x) t → Bounded t o₁ x
| nil, _, _, _, _, hn, _ => hn
| node _ _ _ _, _, _, _, ⟨h₁, h₂⟩, _, ⟨_, al₂, al₃⟩ => ⟨h₁, h₂.of_lt al₂ al₃⟩
#align ordnode.bounded.of_lt Ordnode.Bounded.of_lt
theorem Bounded.of_gt :
∀ {t o₁ o₂} {x : α}, Bounded t o₁ o₂ → Bounded nil x o₂ → All (· > x) t → Bounded t x o₂
| nil, _, _, _, _, hn, _ => hn
| node _ _ _ _, _, _, _, ⟨h₁, h₂⟩, _, ⟨al₁, al₂, _⟩ => ⟨h₁.of_gt al₂ al₁, h₂⟩
#align ordnode.bounded.of_gt Ordnode.Bounded.of_gt
theorem Bounded.to_sep {t₁ t₂ o₁ o₂} {x : α}
(h₁ : Bounded t₁ o₁ (x : WithTop α)) (h₂ : Bounded t₂ (x : WithBot α) o₂) :
t₁.All fun y => t₂.All fun z : α => y < z := by
refine h₁.mem_lt.imp fun y yx => ?_
exact h₂.mem_gt.imp fun z xz => lt_trans yx xz
#align ordnode.bounded.to_sep Ordnode.Bounded.to_sep
end