Skip to content

Commit c43e1fc

Browse files
author
Johannes Waldmann
committed
ansatz for improved powerset
1 parent 4607c10 commit c43e1fc

File tree

1 file changed

+57
-2
lines changed

1 file changed

+57
-2
lines changed

containers/src/Data/Set/Internal.hs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ import Data.Functor.Identity (Identity)
247247
import qualified Data.Foldable as Foldable
248248
import Control.DeepSeq (NFData(rnf))
249249

250+
import qualified Data.Array as A
251+
import Data.Bits
252+
250253
import Utils.Containers.Internal.StrictPair
251254
import Utils.Containers.Internal.PtrEquality
252255

@@ -1824,6 +1827,58 @@ splitRoot orig =
18241827
--
18251828
-- @since 0.5.11
18261829

1830+
1831+
powerSet :: Set a -> Set (Set a)
1832+
powerSet xs =
1833+
let !w = length xs
1834+
!u = A.listArray (0, w-1) $ toList xs
1835+
!v = generateA (0, 2^w -1) $ \ m ->
1836+
if m == 0
1837+
then Tip
1838+
else let ST up med lo = splitBits m
1839+
in bin (u A.! (w - 1 - med))
1840+
(v A.! up) (v A.! lo)
1841+
make !begin !s =
1842+
if s == 0 then Tip
1843+
else let !sl = div (s-1) 2; !sr = s - 1 - sl
1844+
in bin (v A.! forw w (begin + sl))
1845+
(make begin sl)
1846+
(make (begin + sl+1) sr)
1847+
in make 0 (2^w)
1848+
1849+
generateA :: A.Ix i => (i,i) -> (i -> a) -> A.Array i a
1850+
generateA bnd f = A.listArray bnd $ fmap f $ A.range bnd
1851+
1852+
forw :: Int -> Int -> Int
1853+
forw !width !n = fr_go_branch (bit $ width-1) n 0
1854+
1855+
fr_go_branch :: Int -> Int -> Int -> Int
1856+
fr_go_branch !topmask !n !set =
1857+
if n == 0 then set
1858+
else if 0 == ((n-1) .&. topmask)
1859+
then fr_go_branch (shiftR topmask 1)
1860+
(n-1) (set .|. topmask)
1861+
else fr_go_branch (shiftR topmask 1)
1862+
(n .&. complement topmask) set
1863+
1864+
data StrictTriple = ST !Int !Int !Int
1865+
1866+
-- | return bitmask for upper half,
1867+
-- index of middle bit, bitmask for lower half
1868+
splitBits :: Int -> StrictTriple
1869+
splitBits m | m > 0 =
1870+
let go 0 !x = x; go k !x = go (k-1) (clearLowest x)
1871+
!up_med = go (div (popCount m) 2) m
1872+
!lo = xor m up_med
1873+
!up = clearLowest up_med
1874+
!med = xor up_med up
1875+
in ST up (countTrailingZeros med) lo
1876+
1877+
clearLowest :: Int -> Int
1878+
clearLowest m | m > 0 = m .&. (m-1)
1879+
1880+
1881+
18271882
-- Proof of complexity: step executes n times. At the ith step,
18281883
-- "insertMin x `mapMonotonic` pxs" takes O(2^i log i) time since pxs has size
18291884
-- 2^i - 1 and we insertMin into its elements which are sets of size <= i.
@@ -1834,8 +1889,8 @@ splitRoot orig =
18341889
-- = O(log n * \sum_{i=1}^{n-1} 2^i)
18351890
-- = O(2^n log n)
18361891

1837-
powerSet :: Set a -> Set (Set a)
1838-
powerSet xs0 = insertMin empty (foldr' step Tip xs0) where
1892+
powerSet_orig :: Set a -> Set (Set a)
1893+
powerSet_orig xs0 = insertMin empty (foldr' step Tip xs0) where
18391894
step x pxs = insertMin (singleton x) (insertMin x `mapMonotonic` pxs) `glue` pxs
18401895

18411896
-- | \(O(nm)\). Calculate the Cartesian product of two sets.

0 commit comments

Comments
 (0)