Skip to content

Conversation

meooow25
Copy link
Contributor

@meooow25 meooow25 commented May 4, 2025

linkL restores balance when the left tree is too heavy for the right tree, but unlike link it skips checking the other way around. linkR handles the opposite. linkL and linkR are used where we know the direction in which we need to rebalance.

linkL and linkR delegate to linkL_ and linkR_, which do the actual work. link also delegates to linkL_ and linkR_, since the direction does not change when linking two trees. This single-direction linking algorithm can be seen in Figure 4 of "Parallel Ordered Sets Using Join". Similarly, link2/merge delegates to link2L_,link2_R/mergeL_,mergeR_.

Benchmarks show a decrease in time and allocations, especially in set-set operations like union. Inspection of the Core of the previous link implementation revealed that it reboxes trees in some cases, which explains the decrease in allocations.

Closes #307.

linkL restores balance when the left tree is too heavy for the right
tree, but unlike link it skips checking the other way around. linkR
handles the opposite. linkL and linkR are used where we know the
direction in which we need to rebalance.

linkL and linkR delegate to linkL_ and linkR_, which do the actual work.
link also delegates to linkL_ and linkR_, since the direction does not
change when linking two trees. This single-direction linking algorithm
can be seen in Figure 4 of "Parallel Ordered Sets Using Join". Similarly,
link2/merge delegates to link2L_,link2_R/mergeL_,mergeR_.

Benchmarks show a decrease in time and allocations, especially in set-set
operations like union. Inspection of the Core of the previous link
implementation revealed that it reboxes trees in some cases, which
explains the decrease in allocations.
@meooow25
Copy link
Contributor Author

meooow25 commented Jul 7, 2025

Benchmarks on GHC 9.12.2:

Set-set
Name                                  Time - - - - - - - -    Allocated - - - - -
                                           A       B     %         A       B     %
difference-block_nn                   460 μs  376 μs  -18%    1.1 MB  1.0 MB   -5%
difference-block_nn_swap              461 μs  369 μs  -19%    1.1 MB  1.0 MB   -5%
difference-block_ns                    51 μs   40 μs  -21%    153 KB  145 KB   -5%
difference-block_sn_swap               51 μs   37 μs  -26%    142 KB  135 KB   -5%
difference-common_nn                  5.5 ms  5.3 ms   -3%     10 MB  8.1 MB  -21%
difference-common_nn_swap             3.4 ms  3.3 ms   -2%    5.0 MB  4.8 MB   -5%
difference-common_ns                  2.7 ms  2.5 ms   -7%    5.0 MB  4.4 MB  -13%
difference-common_nt                  126 μs  118 μs   -5%    360 KB  317 KB  -12%
difference-common_sn_swap             1.2 ms  1.1 ms   -1%    1.9 MB  1.8 MB   -3%
difference-common_tn_swap              85 μs   87 μs   +2%    130 KB  128 KB   -1%
difference-disj_nn                    2.8 μs  2.1 μs  -24%     10 KB   10 KB   +0%
difference-disj_nn_swap               2.6 μs  1.9 μs  -27%     10 KB   10 KB   +0%
difference-disj_ns                    2.3 μs  1.7 μs  -26%    8.1 KB  8.1 KB   +0%
difference-disj_nt                    1.5 μs  1.1 μs  -26%    5.0 KB  5.0 KB   +0%
difference-disj_sn_swap               2.4 μs  1.6 μs  -33%    8.4 KB  8.1 KB   -3%
difference-disj_tn_swap               1.5 μs  1.1 μs  -24%    5.0 KB  5.0 KB   +0%
difference-mix_nn                     6.6 ms  5.9 ms  -10%     15 MB   15 MB   -2%
difference-mix_nn_swap                6.7 ms  5.9 ms  -11%     15 MB   15 MB   -2%
difference-mix_ns                     1.9 ms  1.6 ms  -11%    4.1 MB  3.7 MB   -9%
difference-mix_nt                     116 μs  100 μs  -13%    261 KB  227 KB  -13%
difference-mix_sn_swap                1.7 ms  1.5 ms   -9%    2.8 MB  2.7 MB   -2%
difference-mix_tn_swap                 95 μs   91 μs   -3%    154 KB  152 KB   -1%
intersection-block_nn                 475 μs  375 μs  -21%    1.1 MB  1.0 MB   -5%
intersection-block_nn_swap            473 μs  374 μs  -20%    1.1 MB  1.0 MB   -5%
intersection-block_ns                  53 μs   38 μs  -28%    142 KB  135 KB   -5%
intersection-block_sn_swap             52 μs   39 μs  -24%    153 KB  145 KB   -5%
intersection-common_nn                5.0 ms  5.0 ms   +0%    7.9 MB  7.6 MB   -3%
intersection-common_nn_swap           2.8 ms  2.6 ms   -6%    4.8 MB  4.4 MB   -6%
intersection-common_ns                1.6 ms  1.5 ms   -5%    2.7 MB  2.6 MB   -2%
intersection-common_nt                107 μs  102 μs   -4%    161 KB  159 KB   -1%
intersection-common_sn_swap           1.4 ms  1.2 ms  -10%    3.0 MB  2.7 MB  -10%
intersection-common_tn_swap            95 μs   81 μs  -14%    231 KB  200 KB  -13%
intersection-disj_nn                  2.7 μs  1.9 μs  -28%     10 KB   10 KB   +0%
intersection-disj_nn_swap             3.0 μs  2.3 μs  -23%     10 KB   10 KB   +0%
intersection-disj_ns                  2.4 μs  1.6 μs  -32%    8.4 KB  8.1 KB   -3%
intersection-disj_nt                  1.5 μs  1.1 μs  -25%    5.0 KB  5.0 KB   +0%
intersection-disj_sn_swap             2.5 μs  1.9 μs  -23%    8.1 KB  8.1 KB   +0%
intersection-disj_tn_swap             1.5 μs  1.2 μs  -21%    5.0 KB  5.0 KB   +0%
intersection-mix_nn                   6.1 ms  5.3 ms  -13%     15 MB   15 MB   -2%
intersection-mix_nn_swap              6.1 ms  5.2 ms  -14%     15 MB   15 MB   -2%
intersection-mix_ns                   1.6 ms  1.5 ms   -5%    2.8 MB  2.7 MB   -2%
intersection-mix_nt                    99 μs   95 μs   -4%    154 KB  152 KB   -1%
intersection-mix_sn_swap              1.8 ms  1.6 ms  -12%    4.1 MB  3.7 MB   -9%
intersection-mix_tn_swap              107 μs   90 μs  -16%    261 KB  227 KB  -13%
symmetricDifference-block_nn          653 μs  525 μs  -19%    1.7 MB  1.6 MB   -8%
symmetricDifference-block_nn_swap     655 μs  531 μs  -18%    1.7 MB  1.6 MB   -7%
symmetricDifference-block_ns           65 μs   49 μs  -25%    211 KB  195 KB   -7%
symmetricDifference-block_sn_swap      69 μs   55 μs  -20%    249 KB  233 KB   -6%
symmetricDifference-common_nn         5.1 ms  5.1 ms   -1%    7.9 MB  7.6 MB   -3%
symmetricDifference-common_nn_swap    5.2 ms  4.9 ms   -5%    8.5 MB  8.1 MB   -3%
symmetricDifference-common_ns         2.0 ms  1.9 ms   -4%    3.4 MB  3.3 MB   -2%
symmetricDifference-common_nt         119 μs  115 μs   -3%    243 KB  240 KB   -1%
symmetricDifference-common_sn_swap    2.6 ms  2.4 ms   -7%    4.7 MB  4.4 MB   -6%
symmetricDifference-common_tn_swap    133 μs  120 μs   -9%    349 KB  317 KB   -9%
symmetricDifference-disj_nn           3.5 μs  2.8 μs  -20%     16 KB   16 KB   -3%
symmetricDifference-disj_nn_swap      3.8 μs  3.0 μs  -21%     17 KB   16 KB   -3%
symmetricDifference-disj_ns           3.0 μs  2.1 μs  -28%     13 KB   12 KB   -5%
symmetricDifference-disj_nt           1.7 μs  1.3 μs  -24%    7.1 KB  6.8 KB   -3%
symmetricDifference-disj_sn_swap      3.3 μs  2.6 μs  -20%     15 KB   14 KB   -2%
symmetricDifference-disj_tn_swap      2.0 μs  1.6 μs  -18%    9.6 KB  9.3 KB   -2%
symmetricDifference-mix_nn             13 ms   12 ms   -4%     19 MB   18 MB   -2%
symmetricDifference-mix_nn_swap        13 ms   12 ms   -5%     19 MB   18 MB   -2%
symmetricDifference-mix_ns            3.0 ms  2.9 ms   -3%    5.1 MB  5.0 MB   -2%
symmetricDifference-mix_nt            129 μs  125 μs   -3%    297 KB  293 KB   -1%
symmetricDifference-mix_sn_swap       2.9 ms  2.7 ms   -7%    4.5 MB  4.1 MB   -9%
symmetricDifference-mix_tn_swap       116 μs   99 μs  -13%    273 KB  239 KB  -12%
union-block_nn                        621 μs  523 μs  -15%    1.6 MB  1.5 MB   -8%
union-block_nn_swap                   633 μs  513 μs  -18%    1.6 MB  1.5 MB   -8%
union-block_ns                         64 μs   49 μs  -22%    204 KB  188 KB   -7%
union-block_sn_swap                    66 μs   54 μs  -18%    238 KB  222 KB   -6%
union-common_nn                       3.0 ms  2.8 ms   -4%    4.7 MB  4.5 MB   -5%
union-common_nn_swap                  5.0 ms  4.9 ms   -2%    7.3 MB  6.9 MB   -4%
union-common_ns                       885 μs  856 μs   -3%    1.3 MB  1.2 MB   -4%
union-common_nt                        43 μs   40 μs   -6%     49 KB   47 KB   -4%
union-common_sn_swap                  1.6 ms  1.5 ms   -4%    2.8 MB  2.6 MB   -8%
union-common_tn_swap                   76 μs   73 μs   -4%    200 KB  181 KB   -9%
union-disj_nn                         3.3 μs  2.6 μs  -22%     16 KB   15 KB   -3%
union-disj_nn_swap                    3.5 μs  2.8 μs  -19%     16 KB   15 KB   -3%
union-disj_ns                         2.9 μs  2.1 μs  -26%     12 KB   11 KB   -5%
union-disj_nt                         1.7 μs  1.3 μs  -23%    6.8 KB  6.5 KB   -4%
union-disj_sn_swap                    3.0 μs  2.4 μs  -20%     14 KB   14 KB   -3%
union-disj_tn_swap                    1.8 μs  1.5 μs  -17%    9.0 KB  8.7 KB   -3%
union-mix_nn                           15 ms   14 ms   -3%     23 MB   23 MB   -1%
union-mix_nn_swap                      15 ms   14 ms   -3%     23 MB   23 MB   -1%
union-mix_ns                          2.0 ms  2.1 ms   +1%    3.8 MB  3.7 MB   -1%
union-mix_nt                           74 μs   71 μs   -3%    188 KB  185 KB   -1%
union-mix_sn_swap                     3.2 ms  2.3 ms  -27%    4.0 MB  3.7 MB   -7%
union-mix_tn_swap                      87 μs   79 μs   -8%    228 KB  207 KB   -9%
Map-map
Name                                  Time - - - - - - - -    Allocated - - - - -
                                           A       B     %         A       B     %
difference-block_nn                   437 μs  339 μs  -22%    1.3 MB  1.2 MB   -5%
difference-block_nn_swap              439 μs  337 μs  -23%    1.3 MB  1.2 MB   -5%
difference-block_ns                    47 μs   35 μs  -24%    184 KB  174 KB   -5%
difference-block_sn_swap               47 μs   32 μs  -31%    171 KB  162 KB   -5%
difference-common_nn                  6.4 ms  6.2 ms   -3%     12 MB  9.8 MB  -21%
difference-common_nn_swap             3.7 ms  3.4 ms   -6%    6.0 MB  5.7 MB   -5%
difference-common_ns                  3.3 ms  2.8 ms  -12%    6.1 MB  5.2 MB  -13%
difference-common_nt                  132 μs  119 μs   -9%    433 KB  380 KB  -12%
difference-common_sn_swap             1.2 ms  1.1 ms   -3%    2.3 MB  2.2 MB   -3%
difference-common_tn_swap              77 μs   75 μs   -2%    156 KB  154 KB   -1%
difference-disj_nn                    2.4 μs  1.8 μs  -25%     12 KB   12 KB   +0%
difference-disj_nn_swap               2.3 μs  1.6 μs  -29%     12 KB   12 KB   +0%
difference-disj_ns                    2.0 μs  1.5 μs  -25%    9.8 KB  9.8 KB   +0%
difference-disj_nt                    1.3 μs  924 ns  -26%    6.0 KB  6.0 KB   +0%
difference-disj_sn_swap               2.1 μs  1.4 μs  -35%     10 KB  9.8 KB   -3%
difference-disj_tn_swap               1.3 μs  958 ns  -27%    6.0 KB  6.0 KB   +0%
difference-mix_nn                     7.0 ms  6.2 ms  -11%     18 MB   17 MB   -2%
difference-mix_nn_swap                6.8 ms  6.3 ms   -7%     18 MB   17 MB   -2%
difference-mix_ns                     1.9 ms  1.7 ms  -13%    4.9 MB  4.4 MB   -9%
difference-mix_nt                     109 μs   89 μs  -18%    313 KB  272 KB  -13%
difference-mix_sn_swap                1.6 ms  1.5 ms   -7%    3.4 MB  3.3 MB   -2%
difference-mix_tn_swap                 89 μs   83 μs   -6%    185 KB  182 KB   -1%
intersection-block_nn                 456 μs  345 μs  -24%    1.3 MB  1.2 MB   -5%
intersection-block_nn_swap            451 μs  346 μs  -23%    1.3 MB  1.2 MB   -5%
intersection-block_ns                  50 μs   34 μs  -32%    171 KB  162 KB   -5%
intersection-block_sn_swap             49 μs   37 μs  -23%    184 KB  174 KB   -5%
intersection-common_nn                5.9 ms  5.6 ms   -5%    9.4 MB  9.1 MB   -3%
intersection-common_nn_swap           2.9 ms  2.6 ms  -10%    5.7 MB  5.3 MB   -6%
intersection-common_ns                1.6 ms  1.6 ms   -5%    3.2 MB  3.2 MB   -2%
intersection-common_nt                102 μs   94 μs   -7%    193 KB  191 KB   -1%
intersection-common_sn_swap           1.4 ms  1.2 ms  -10%    3.6 MB  3.2 MB  -10%
intersection-common_tn_swap            91 μs   75 μs  -16%    278 KB  240 KB  -13%
intersection-disj_nn                  2.3 μs  1.6 μs  -29%     12 KB   12 KB   +0%
intersection-disj_nn_swap             2.4 μs  1.8 μs  -27%     12 KB   12 KB   +0%
intersection-disj_ns                  2.1 μs  1.4 μs  -33%     10 KB  9.8 KB   -3%
intersection-disj_nt                  1.3 μs  1.0 μs  -23%    6.0 KB  6.0 KB   +0%
intersection-disj_sn_swap             2.0 μs  1.5 μs  -26%    9.8 KB  9.8 KB   +0%
intersection-disj_tn_swap             1.2 μs  906 ns  -26%    6.0 KB  6.0 KB   +0%
intersection-mix_nn                   6.3 ms  5.5 ms  -13%     18 MB   17 MB   -2%
intersection-mix_nn_swap              6.3 ms  5.4 ms  -13%     18 MB   17 MB   -2%
intersection-mix_ns                   1.7 ms  1.5 ms   -9%    3.4 MB  3.3 MB   -2%
intersection-mix_nt                    95 μs   91 μs   -4%    185 KB  182 KB   -1%
intersection-mix_sn_swap              1.9 ms  1.6 ms  -16%    4.9 MB  4.4 MB   -9%
intersection-mix_tn_swap              107 μs   89 μs  -16%    313 KB  272 KB  -13%
symmetricDifference-block_nn          687 μs  522 μs  -23%    2.1 MB  1.9 MB   -8%
symmetricDifference-block_nn_swap     685 μs  530 μs  -22%    2.1 MB  1.9 MB   -7%
symmetricDifference-block_ns           66 μs   47 μs  -28%    253 KB  234 KB   -7%
symmetricDifference-block_sn_swap      70 μs   54 μs  -22%    299 KB  279 KB   -6%
symmetricDifference-common_nn         6.1 ms  5.7 ms   -7%    9.5 MB  9.2 MB   -3%
symmetricDifference-common_nn_swap    5.8 ms  5.5 ms   -5%     10 MB  9.8 MB   -3%
symmetricDifference-common_ns         2.3 ms  2.1 ms   -7%    4.0 MB  3.9 MB   -2%
symmetricDifference-common_nt         115 μs  111 μs   -3%    292 KB  288 KB   -1%
symmetricDifference-common_sn_swap    3.1 ms  2.7 ms  -14%    5.6 MB  5.3 MB   -6%
symmetricDifference-common_tn_swap    135 μs  119 μs  -12%    418 KB  380 KB   -9%
symmetricDifference-disj_nn           3.2 μs  2.4 μs  -26%     20 KB   19 KB   -3%
symmetricDifference-disj_nn_swap      3.3 μs  2.5 μs  -23%     20 KB   19 KB   -3%
symmetricDifference-disj_ns           2.8 μs  1.9 μs  -31%     15 KB   14 KB   -5%
symmetricDifference-disj_nt           1.6 μs  1.2 μs  -23%    8.5 KB  8.2 KB   -3%
symmetricDifference-disj_sn_swap      3.0 μs  2.2 μs  -25%     18 KB   17 KB   -2%
symmetricDifference-disj_tn_swap      2.0 μs  1.4 μs  -27%     11 KB   11 KB   -2%
symmetricDifference-mix_nn             14 ms   14 ms   -2%     23 MB   22 MB   -2%
symmetricDifference-mix_nn_swap        14 ms   14 ms   -3%     23 MB   22 MB   -2%
symmetricDifference-mix_ns            3.3 ms  3.2 ms   -3%    6.2 MB  6.0 MB   -2%
symmetricDifference-mix_nt            127 μs  120 μs   -5%    356 KB  351 KB   -1%
symmetricDifference-mix_sn_swap       3.4 ms  2.9 ms  -13%    5.4 MB  4.9 MB   -9%
symmetricDifference-mix_tn_swap       117 μs   96 μs  -18%    328 KB  287 KB  -12%
union-block_nn                        623 μs  502 μs  -19%    2.0 MB  1.8 MB   -8%
union-block_nn_swap                   625 μs  501 μs  -19%    2.0 MB  1.8 MB   -8%
union-block_ns                         60 μs   44 μs  -26%    245 KB  226 KB   -7%
union-block_sn_swap                    64 μs   51 μs  -21%    285 KB  266 KB   -6%
union-common_nn                       3.1 ms  2.8 ms   -9%    5.7 MB  5.4 MB   -5%
union-common_nn_swap                  6.4 ms  4.6 ms  -27%    8.3 MB  7.9 MB   -4%
union-common_ns                       911 μs  802 μs  -11%    1.5 MB  1.5 MB   -4%
union-common_nt                        43 μs   38 μs  -12%     59 KB   57 KB   -4%
union-common_sn_swap                  1.8 ms  1.6 ms  -12%    3.4 MB  3.1 MB   -8%
union-common_tn_swap                   77 μs   70 μs   -9%    240 KB  216 KB   -9%
union-disj_nn                         3.1 μs  2.4 μs  -21%     19 KB   18 KB   -3%
union-disj_nn_swap                    3.2 μs  2.6 μs  -19%     19 KB   18 KB   -3%
union-disj_ns                         2.6 μs  1.8 μs  -31%     14 KB   14 KB   -5%
union-disj_nt                         1.5 μs  1.2 μs  -23%    8.1 KB  7.8 KB   -4%
union-disj_sn_swap                    2.9 μs  2.3 μs  -20%     17 KB   17 KB   -3%
union-disj_tn_swap                    1.8 μs  1.4 μs  -24%     11 KB   10 KB   -3%
union-mix_nn                           16 ms   16 ms   +0%     28 MB   27 MB   -1%
union-mix_nn_swap                      16 ms   16 ms   +0%     28 MB   27 MB   -1%
union-mix_ns                          2.4 ms  2.4 ms   +1%    4.6 MB  4.5 MB   -1%
union-mix_nt                           74 μs   72 μs   -3%    225 KB  223 KB   -1%
union-mix_sn_swap                     2.9 ms  2.8 ms   -4%    4.8 MB  4.4 MB   -7%
union-mix_tn_swap                      90 μs   79 μs  -12%    273 KB  248 KB   -9%

@meooow25 meooow25 merged commit 9498edf into haskell:master Jul 8, 2025
14 checks passed
@meooow25 meooow25 deleted the link-left-right branch July 8, 2025 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add left and right link variants
1 participant