@@ -0,0 +1,172 @@
1+{-# OPTIONS_GHC -funbox-strict-fields #-}
2+{-# LANGUAGE BangPatterns #-}
17+{- This is based on the following implementations:
19+ - https://hackage.haskell.org/package/union-find-0.2/docs/src/Data-UnionFind-IO.html
20+ - http://yann.regis-gianas.org/public/mini/code_UnionFind.html
22+It seems like the OCaml one came first, but I am not sure.
24+Compared to the Haskell implementation, the major changes here include:
26+ 1. No more reallocating PointInfo when changing the weight
27+ 2. Using the strict modifyIORef
32+import Control.Monad ( when )
33+import Data.IORef (IORef, modifyIORef', newIORef, readIORef, writeIORef)
34+import Data.Word (Word32)
42+ Pt (IORef (PointInfo a))
47+ = Info {-# UNPACK #-} !(IORef Word32) {-# UNPACK #-} !(IORef a)
48+ | Link {-# UNPACK #-} !(Point a)
55+fresh :: a -> IO (Point a)
57+ do weight <- newIORef 1
58+ desc <- newIORef value
59+ link <- newIORef (Info weight desc)
63+repr :: Point a -> IO (Point a)
65+ do pInfo <- readIORef ref
70+ Link point1@(Pt ref1) ->
71+ do point2 <- repr point1
72+ when (point2 /= point1) $
73+ do pInfo1 <- readIORef ref1
74+ writeIORef ref pInfo1
78+descriptor :: Point a -> IO a
79+descriptor point@(Pt ref) =
80+ do pInfo <- readIORef ref
86+ do link' <- readIORef ref1
92+ descriptor =<< repr point
95+setDescriptor :: Point a -> a -> IO ()
96+setDescriptor point@(Pt ref) newDesc =
97+ do pInfo <- readIORef ref
100+ writeIORef descRef newDesc
103+ do link' <- readIORef ref1
106+ writeIORef descRef newDesc
109+ do newPoint <- repr point
110+ setDescriptor newPoint newDesc
113+modifyDescriptor :: Point a -> (a -> a) -> IO ()
114+modifyDescriptor point@(Pt ref) func =
115+ do pInfo <- readIORef ref
118+ modifyIORef' descRef func
121+ do link' <- readIORef ref1
124+ modifyIORef' descRef func
127+ do newPoint <- repr point
128+ modifyDescriptor newPoint func
131+union :: Point a -> Point a -> a -> IO ()
132+union p1 p2 newDesc =
133+ do point1@(Pt ref1) <- repr p1
134+ point2@(Pt ref2) <- repr p2
136+ -- assert (point1 /= point2)
138+ Info w1 d1 <- readIORef ref1
139+ Info w2 d2 <- readIORef ref2
141+ weight1 <- readIORef w1
142+ weight2 <- readIORef w2
144+ let !newWeight = weight1 + weight2
146+ if weight1 >= weight2
148+ do writeIORef ref2 (Link point1)
149+ writeIORef w1 newWeight
150+ writeIORef d1 newDesc
152+ do writeIORef ref1 (Link point2)
153+ writeIORef w2 newWeight
154+ writeIORef d2 newDesc
157+equivalent :: Point a -> Point a -> IO Bool
164+redundant :: Point a -> IO Bool
166+ do pInfo <- readIORef ref