@@ -740,7 +740,8 @@ unsafeFindMax (Bin _ _ r) = unsafeFindMax r
740
740
{- -------------------------------------------------------------------
741
741
Disjoint
742
742
--------------------------------------------------------------------}
743
- -- | \(O(n+m)\). Check whether the key sets of two maps are disjoint
743
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
744
+ -- Check whether the key sets of two maps are disjoint
744
745
-- (i.e. their 'intersection' is empty).
745
746
--
746
747
-- > disjoint (fromList [(2,'a')]) (fromList [(1,()), (3,())]) == True
@@ -1091,7 +1092,8 @@ unionsWith :: Foldable f => (a->a->a) -> f (IntMap a) -> IntMap a
1091
1092
unionsWith f ts
1092
1093
= Foldable. foldl' (unionWith f) empty ts
1093
1094
1094
- -- | \(O(n+m)\). The (left-biased) union of two maps.
1095
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1096
+ -- The (left-biased) union of two maps.
1095
1097
-- It prefers the first map when duplicate keys are encountered,
1096
1098
-- i.e. (@'union' == 'unionWith' 'const'@).
1097
1099
--
@@ -1101,7 +1103,8 @@ union :: IntMap a -> IntMap a -> IntMap a
1101
1103
union m1 m2
1102
1104
= mergeWithKey' Bin const id id m1 m2
1103
1105
1104
- -- | \(O(n+m)\). The union with a combining function.
1106
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1107
+ -- The union with a combining function.
1105
1108
--
1106
1109
-- > unionWith (++) (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "aA"), (7, "C")]
1107
1110
--
@@ -1111,7 +1114,8 @@ unionWith :: (a -> a -> a) -> IntMap a -> IntMap a -> IntMap a
1111
1114
unionWith f m1 m2
1112
1115
= unionWithKey (\ _ x y -> f x y) m1 m2
1113
1116
1114
- -- | \(O(n+m)\). The union with a combining function.
1117
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1118
+ -- The union with a combining function.
1115
1119
--
1116
1120
-- > let f key left_value right_value = (show key) ++ ":" ++ left_value ++ "|" ++ right_value
1117
1121
-- > unionWithKey f (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == fromList [(3, "b"), (5, "5:a|A"), (7, "C")]
@@ -1125,15 +1129,17 @@ unionWithKey f m1 m2
1125
1129
{- -------------------------------------------------------------------
1126
1130
Difference
1127
1131
--------------------------------------------------------------------}
1128
- -- | \(O(n+m)\). Difference between two maps (based on keys).
1132
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1133
+ -- Difference between two maps (based on keys).
1129
1134
--
1130
1135
-- > difference (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == singleton 3 "b"
1131
1136
1132
1137
difference :: IntMap a -> IntMap b -> IntMap a
1133
1138
difference m1 m2
1134
1139
= mergeWithKey (\ _ _ _ -> Nothing ) id (const Nil ) m1 m2
1135
1140
1136
- -- | \(O(n+m)\). Difference with a combining function.
1141
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1142
+ -- Difference with a combining function.
1137
1143
--
1138
1144
-- > let f al ar = if al == "b" then Just (al ++ ":" ++ ar) else Nothing
1139
1145
-- > differenceWith f (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (3, "B"), (7, "C")])
@@ -1143,7 +1149,8 @@ differenceWith :: (a -> b -> Maybe a) -> IntMap a -> IntMap b -> IntMap a
1143
1149
differenceWith f m1 m2
1144
1150
= differenceWithKey (\ _ x y -> f x y) m1 m2
1145
1151
1146
- -- | \(O(n+m)\). Difference with a combining function. When two equal keys are
1152
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1153
+ -- Difference with a combining function. When two equal keys are
1147
1154
-- encountered, the combining function is applied to the key and both values.
1148
1155
-- If it returns 'Nothing', the element is discarded (proper set difference).
1149
1156
-- If it returns (@'Just' y@), the element is updated with a new value @y@.
@@ -1157,8 +1164,8 @@ differenceWithKey f m1 m2
1157
1164
= mergeWithKey f id (const Nil ) m1 m2
1158
1165
1159
1166
1160
- -- TODO(wrengr): re-verify that asymptotic bound
1161
- -- | \(O(n+m)\). Remove all the keys in a given set from a map.
1167
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1168
+ -- Remove all the keys in a given set from a map.
1162
1169
--
1163
1170
-- @
1164
1171
-- m \`withoutKeys\` s = 'filterWithKey' (\\k _ -> k ``IntSet.notMember`` s) m
@@ -1221,7 +1228,8 @@ withoutBM _ Nil = Nil
1221
1228
{- -------------------------------------------------------------------
1222
1229
Intersection
1223
1230
--------------------------------------------------------------------}
1224
- -- | \(O(n+m)\). The (left-biased) intersection of two maps (based on keys).
1231
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1232
+ -- The (left-biased) intersection of two maps (based on keys).
1225
1233
--
1226
1234
-- > intersection (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == singleton 5 "a"
1227
1235
@@ -1230,8 +1238,8 @@ intersection m1 m2
1230
1238
= mergeWithKey' bin const (const Nil ) (const Nil ) m1 m2
1231
1239
1232
1240
1233
- -- TODO(wrengr): re-verify that asymptotic bound
1234
- -- | \(O(n+m)\). The restriction of a map to the keys in a set.
1241
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1242
+ -- The restriction of a map to the keys in a set.
1235
1243
--
1236
1244
-- @
1237
1245
-- m \`restrictKeys\` s = 'filterWithKey' (\\k _ -> k ``IntSet.member`` s) m
@@ -1291,15 +1299,17 @@ restrictBM bm t@(Tip k _)
1291
1299
restrictBM _ Nil = Nil
1292
1300
1293
1301
1294
- -- | \(O(n+m)\). The intersection with a combining function.
1302
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1303
+ -- The intersection with a combining function.
1295
1304
--
1296
1305
-- > intersectionWith (++) (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == singleton 5 "aA"
1297
1306
1298
1307
intersectionWith :: (a -> b -> c ) -> IntMap a -> IntMap b -> IntMap c
1299
1308
intersectionWith f m1 m2
1300
1309
= intersectionWithKey (\ _ x y -> f x y) m1 m2
1301
1310
1302
- -- | \(O(n+m)\). The intersection with a combining function.
1311
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1312
+ -- The intersection with a combining function.
1303
1313
--
1304
1314
-- > let f k al ar = (show k) ++ ":" ++ al ++ "|" ++ ar
1305
1315
-- > intersectionWithKey f (fromList [(5, "a"), (3, "b")]) (fromList [(5, "A"), (7, "C")]) == singleton 5 "5:a|A"
@@ -1312,7 +1322,8 @@ intersectionWithKey f m1 m2
1312
1322
Symmetric difference
1313
1323
--------------------------------------------------------------------}
1314
1324
1315
- -- | \(O(n+m)\). The symmetric difference of two maps.
1325
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1326
+ -- The symmetric difference of two maps.
1316
1327
--
1317
1328
-- The result contains entries whose keys appear in exactly one of the two maps.
1318
1329
--
@@ -1355,7 +1366,8 @@ symDiffTip !t1 !k1 = go
1355
1366
MergeWithKey
1356
1367
--------------------------------------------------------------------}
1357
1368
1358
- -- | \(O(n+m)\). A high-performance universal combining function. Using
1369
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
1370
+ -- A high-performance universal combining function. Using
1359
1371
-- 'mergeWithKey', all combining functions can be defined without any loss of
1360
1372
-- efficiency (with exception of 'union', 'difference' and 'intersection',
1361
1373
-- where sharing of some nodes is lost with 'mergeWithKey').
@@ -1391,6 +1403,7 @@ symDiffTip !t1 !k1 = go
1391
1403
-- @only2@ are 'id' and @'const' 'empty'@, but for example @'map' f@ or
1392
1404
-- @'filterWithKey' f@ could be used for any @f@.
1393
1405
1406
+ -- See Note [IntMap merge complexity]
1394
1407
mergeWithKey :: (Key -> a -> b -> Maybe c ) -> (IntMap a -> IntMap c ) -> (IntMap b -> IntMap c )
1395
1408
-> IntMap a -> IntMap b -> IntMap c
1396
1409
mergeWithKey f g1 g2 = mergeWithKey' bin combine g1 g2
@@ -2375,13 +2388,15 @@ deleteMax = maybe Nil snd . maxView
2375
2388
{- -------------------------------------------------------------------
2376
2389
Submap
2377
2390
--------------------------------------------------------------------}
2378
- -- | \(O(n+m)\). Is this a proper submap? (ie. a submap but not equal).
2391
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
2392
+ -- Is this a proper submap? (ie. a submap but not equal).
2379
2393
-- Defined as (@'isProperSubmapOf' = 'isProperSubmapOfBy' (==)@).
2380
2394
isProperSubmapOf :: Eq a => IntMap a -> IntMap a -> Bool
2381
2395
isProperSubmapOf m1 m2
2382
2396
= isProperSubmapOfBy (==) m1 m2
2383
2397
2384
- {- | \(O(n+m)\). Is this a proper submap? (ie. a submap but not equal).
2398
+ {- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
2399
+ Is this a proper submap? (ie. a submap but not equal).
2385
2400
The expression (@'isProperSubmapOfBy' f m1 m2@) returns 'True' when
2386
2401
@keys m1@ and @keys m2@ are not equal,
2387
2402
all keys in @m1@ are in @m2@, and when @f@ returns 'True' when
@@ -2432,13 +2447,14 @@ submapCmp predicate (Tip k x) t
2432
2447
submapCmp _ Nil Nil = EQ
2433
2448
submapCmp _ Nil _ = LT
2434
2449
2435
- -- | \(O(n+m)\). Is this a submap?
2450
+ -- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n\).
2451
+ -- Is this a submap?
2436
2452
-- Defined as (@'isSubmapOf' = 'isSubmapOfBy' (==)@).
2437
2453
isSubmapOf :: Eq a => IntMap a -> IntMap a -> Bool
2438
2454
isSubmapOf m1 m2
2439
2455
= isSubmapOfBy (==) m1 m2
2440
2456
2441
- {- | \(O(n+m) \).
2457
+ {- | \(O(\min(n, m \log \frac{2^W}{m})), m \leq n \).
2442
2458
The expression (@'isSubmapOfBy' f m1 m2@) returns 'True' if
2443
2459
all keys in @m1@ are in @m2@, and when @f@ returns 'True' when
2444
2460
applied to their respective values. For example, the following
@@ -3812,3 +3828,39 @@ withEmpty bars = " ":bars
3812
3828
-- right child. We have the same three cases for a Bin. However, the bitwise
3813
3829
-- operations we use to determine the case is naturally different due to the
3814
3830
-- difference in representation.
3831
+
3832
+ -- Note [IntMap merge complexity]
3833
+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3834
+ -- The merge algorithm (used for union, intersection, etc.) is adopted from
3835
+ -- Okasaki-Gill who give the complexity as O(m+n), where m and n are the sizes
3836
+ -- of the two input maps. This is correct, since we visit all constructors in
3837
+ -- both maps in the worst case, but we can try to find a tighter bound.
3838
+ --
3839
+ -- Consider that m<=n, i.e. m is the size of the smaller map and n is the size
3840
+ -- of the larger. It does not matter which map is the first argument.
3841
+ --
3842
+ -- Now we have O(n) as one upper bound for our complexity, since O(n) is the
3843
+ -- same as O(m+n) for m<=n.
3844
+ --
3845
+ -- Next, consider the smaller map. For this map, we will visit some
3846
+ -- constructors, plus all the Bins of the larger map that lie in our way.
3847
+ -- For the former, the worst case is that we visit all constructors, which is
3848
+ -- O(m).
3849
+ -- For the latter, the worst case is that we encounter Bins at every point
3850
+ -- possible. This happens when for every key in the smaller map, the path to
3851
+ -- that key's Tip in the larger map has a full length of W, with a Bin at every
3852
+ -- bit position. To maximize the total number of Bins, the paths should be as
3853
+ -- disjoint as possible. But even if the paths are spread out, at least O(m)
3854
+ -- Bins are unavoidably shared, which extend up to a depth of lg(m) from the
3855
+ -- root. Beyond this, the paths may be disjoint. This gives us a total of
3856
+ -- O(m + m (W - lg m)) = O(m log (2^W / m)).
3857
+ -- The number of Bins we encounter is also bounded by the total number of Bins,
3858
+ -- which is n-1, but we already have O(n) as an upper bound.
3859
+ --
3860
+ -- Combining our bounds, we have the final complexity as
3861
+ -- O(min(n, m log (2^W / m))).
3862
+ --
3863
+ -- Note that
3864
+ -- * This is similar to the Map merge complexity, which is O(m log (n/m)).
3865
+ -- * When m is a small constant the term simplifies to O(min(n, W)), which is
3866
+ -- just the complexity we expect for single operations like insert and delete.
0 commit comments