packages feed

order-maintenance 0.0.0.0 → 0.0.1.0

raw patch · 20 files changed

+1023/−575 lines, 20 filesdep +Cabaldep +QuickCheckdep +cabal-test-quickcheckPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: Cabal, QuickCheck, cabal-test-quickcheck, order-maintenance

API changes (from Hackage documentation)

- Control.Monad.Trans.Order.Lazy: instance Typeable Element
+ Control.Monad.Trans.Order.Algorithm: dietzSleatorAmortizedLog :: Algorithm
+ Control.Monad.Trans.Order.Algorithm: dietzSleatorAmortizedLogWithSize :: Int -> Algorithm
+ Control.Monad.Trans.Order.Algorithm: withRawAlgorithm :: Algorithm -> (forall a. RawAlgorithm a s -> ST s r) -> ST s r
+ Control.Monad.Trans.Order.Raw: RawAlgorithm :: ST s (RawOrder a s) -> (RawOrder a s -> RawElement a s -> RawElement a s -> ST s Ordering) -> (RawOrder a s -> ST s (RawElement a s)) -> (RawOrder a s -> ST s (RawElement a s)) -> (RawOrder a s -> RawElement a s -> ST s (RawElement a s)) -> (RawOrder a s -> RawElement a s -> ST s (RawElement a s)) -> (RawOrder a s -> RawElement a s -> ST s ()) -> RawAlgorithm a s
+ Control.Monad.Trans.Order.Raw: compareElements :: RawAlgorithm a s -> RawOrder a s -> RawElement a s -> RawElement a s -> ST s Ordering
+ Control.Monad.Trans.Order.Raw: data RawAlgorithm a s
+ Control.Monad.Trans.Order.Raw: delete :: RawAlgorithm a s -> RawOrder a s -> RawElement a s -> ST s ()
+ Control.Monad.Trans.Order.Raw: newAfter :: RawAlgorithm a s -> RawOrder a s -> RawElement a s -> ST s (RawElement a s)
+ Control.Monad.Trans.Order.Raw: newBefore :: RawAlgorithm a s -> RawOrder a s -> RawElement a s -> ST s (RawElement a s)
+ Control.Monad.Trans.Order.Raw: newMaximum :: RawAlgorithm a s -> RawOrder a s -> ST s (RawElement a s)
+ Control.Monad.Trans.Order.Raw: newMinimum :: RawAlgorithm a s -> RawOrder a s -> ST s (RawElement a s)
+ Control.Monad.Trans.Order.Raw: newOrder :: RawAlgorithm a s -> ST s (RawOrder a s)
+ Control.Monad.Trans.Order.Raw: type RawElement a s = STRef s (ElementCell a s)
+ Control.Monad.Trans.Order.Raw: type RawOrder a s = STRef s (OrderCell a s)

Files

+ dist/build/testsStub/testsStub-tmp/testsStub.hs view
@@ -0,0 +1,5 @@+module Main ( main ) where+import Distribution.Simple.Test.LibV09 ( stubMain )+import TestSuite ( tests )+main :: IO ()+main = stubMain tests
order-maintenance.cabal view
@@ -1,5 +1,5 @@ Name:          order-maintenance-Version:       0.0.0.0+Version:       0.0.1.0 Cabal-Version: >= 1.16 Build-Type:    Simple License:       BSD3@@ -9,12 +9,12 @@ Maintainer:    wolfgang@cs.ioc.ee Stability:     provisional Homepage:      http://darcs.wolfgang.jeltsch.info/haskell/order-maintenance-Package-URL:   http://hackage.haskell.org/packages/archive/order-maintenance/0.0.0.0/order-maintenance-0.0.0.0.tar.gz+Package-URL:   http://hackage.haskell.org/packages/archive/order-maintenance/0.0.1.0/order-maintenance-0.0.1.0.tar.gz Synopsis:      Algorithms for the order maintenance problem with a safe                interface Description:   This package is about order maintenance. Category:      Data-Tested-With:   GHC == 7.8.3+Tested-With:   GHC == 7.10.1  Source-Repository head @@ -25,7 +25,7 @@      Type:     darcs     Location: http://darcs.wolfgang.jeltsch.info/haskell/order-maintenance/main-    Tag:      order-maintenance-0.0.0.0+    Tag:      order-maintenance-0.0.1.0  Library @@ -42,18 +42,33 @@                         RankNTypes                         TypeFamilies -    if impl(ghc >= 7.8) {-        Default-Extensions: AutoDeriveTypeable-    }-     Exposed-Modules: Control.Monad.Trans.Order                      Control.Monad.Trans.Order.Algorithm                      Control.Monad.Trans.Order.Lazy+                     Control.Monad.Trans.Order.Raw                      Control.Monad.Trans.Order.Strict -    Other-Modules: Control.Monad.Trans.Order.Algorithm.Dumb+    Other-Modules: Control.Monad.Trans.Order.Algorithm.DietzSleatorAmortizedLog+                   Control.Monad.Trans.Order.Algorithm.Dumb                    Control.Monad.Trans.Order.Algorithm.Type                    Control.Monad.Trans.Order.Lazy.Internals-                   Control.Monad.Trans.Order.Raw -    HS-Source-Dirs: src+    HS-Source-Dirs: src/library++Test-Suite tests++    Type: detailed-0.9++    Build-Depends: base                  >= 3.0  && < 5,+                   Cabal                 >= 1.16 && < 2,+                   cabal-test-quickcheck >= 0.1  && < 0.2,+                   containers            >= 0.5  && < 0.6,+                   QuickCheck            >= 2.6  && < 3,+                   transformers          >= 0.3  && < 0.5,+                   order-maintenance     == 0.0.1.0++    Default-Language: Haskell2010++    Test-Module: TestSuite++    HS-Source-Dirs: src/test-suites
− src/Control/Monad/Trans/Order.hs
@@ -1,7 +0,0 @@-module Control.Monad.Trans.Order (--    module Control.Monad.Trans.Order.Lazy--) where--import Control.Monad.Trans.Order.Lazy
− src/Control/Monad/Trans/Order/Algorithm.hs
@@ -1,83 +0,0 @@-module Control.Monad.Trans.Order.Algorithm (--    -- * General things--    Algorithm,-    defaultAlgorithm,--    -- * Specific algorithms--    dumb--) where--import Control.Monad.Trans.Order.Algorithm.Type-import Control.Monad.Trans.Order.Algorithm.Dumb as Dumb--{-FIXME:-    Implement the following:--      • an algorithm that uses arbitarily deep log-trees--      • the file maintenance algorithm by Bender et al. combined with log-trees-        of fixed height--      • a function that converts any algorithm into one that shifts elements-        between two orders upon deletion (for avoiding sparsly populated order-        structures)--    Maybe it makes sense to additionally offer the file maintenance algorithm by-    Bender et al. as an order maintenance algorithm in its own right.--}--{-FIXME:-    For implementing Bender et al., it might be good to store the calibrator-    tree in an array, level by level from top to bottom. The array must then be-    created without initializing its elements. Initially the tree would be-    small; so few array elements would be used. When extending the tree, we-    would face the problem that initializing all the additionally used elements-    would take more than O(1) time. We can maybe use the trick by Barak A.-    Pearlmutter¹ (or a variant of it, specialized for our particular-    initialization pattern) to get O(1) time.--      ¹ See his e-mail to me from 5 December 2014.--}--{-FIXME:-    More notes regarding implementing Bender et al.:--      • We can store the set of all children of a single node of a log-tree in-        an array of 48 64-bit words. Each word represents one child. Children-        are stored in the temporal order of their allocation. 48 bits of a word-        are the label, 3 are the left sibling index, 3 are the right sibling-        index. The parent pointer (pointer to the array plus index in the array)-        has to be stored only once per such an array, not for every child.--      • A block in the file maintenance data structure could encompass 48 or-        maybe also 64 elements. A 64-bit word could be used to store which of-        the array cells are taken by an element and which are free.--      • I think that on the upper two levels of a log tree, we need up to three-        times as many nodes for storing log-many subtrees, because of overflow-        nodes. This would mean that with the above approach, we could store up-        to 48 × 12 × 12 ≈ 7000 elements in a log tree and ca. 7000 × 48 ≈ 350000-        actual elements per file maintenance block. The total memory use would-        be a bit more than 8 × 350000 = 2.8 MB.--      • The number of actual elements per file maintenance block (350,000) would-        be a bit more than 2^18. Since our k would be 48, we could have up to-        2^48 × 2^18 = 2^66 elements theoretically. So we could reach the maximum-        of 2^64 elements.--}---- * General things---- NOTE: Algorithm is imported from Data.OrderMaintenance.Algorithm.Type.--defaultAlgorithm :: Algorithm-defaultAlgorithm = dumb---- * Specific algorithms--dumb :: Algorithm-dumb = Dumb.algorithm
− src/Control/Monad/Trans/Order/Algorithm/Dumb.hs
@@ -1,100 +0,0 @@-module Control.Monad.Trans.Order.Algorithm.Dumb (--    algorithm--) where---- Control--import Control.Applicative-import Control.Monad.ST---- Data--import           Data.Function-import           Data.Ratio-import           Data.STRef-import qualified Data.Set as Set-import           Data.Set (Set)-import           Control.Monad.Trans.Order.Algorithm.Type-import           Control.Monad.Trans.Order.Raw--algorithm :: Algorithm-algorithm = Algorithm rawAlgorithm--data Dumb--type instance OrderCell Dumb s = PureOrder--type instance ElementCell Dumb s = PureElement--type PureOrder = Set PureElement--type PureElement = Rational--rawAlgorithm :: RawAlgorithm Dumb s-rawAlgorithm = RawAlgorithm {-    newOrder        = newSTRef Set.empty,-    compareElements = liftA2 compare `on` readSTRef,-    insertMinimum   = fromPureInsert pureInsertMinimum,-    insertMaximum   = fromPureInsert pureInsertMaximum,-    insertAfter     = relative fromPureInsert pureInsertAfter,-    insertBefore    = relative fromPureInsert pureInsertBefore,-    delete          = relative fromPure pureDelete-}--fromPure :: (PureOrder -> (a, PureOrder)) -> RawOrder Dumb s -> ST s a-fromPure trans rawOrder = do-                              pureOrder <- readSTRef rawOrder-                              let (output, pureOrder') = trans pureOrder-                              writeSTRef rawOrder pureOrder'-                              return output--fromPureInsert :: (PureOrder -> PureElement)-               -> RawOrder Dumb s-               -> ST s (RawElement Dumb s)-fromPureInsert trans rawOrder = fromPure trans' rawOrder >>= newSTRef where--    trans' pureOrder = let--                           pureElement = trans pureOrder--                       in (pureElement, Set.insert pureElement pureOrder)--relative :: ((PureOrder -> a) -> RawOrder Dumb s -> ST s b)-         -> (PureElement -> PureOrder -> a)-         -> RawElement Dumb s-         -> RawOrder Dumb s-         -> ST s b-relative conv trans rawElem rawOrder = do-    pureElem <- readSTRef rawElem-    conv (trans pureElem) rawOrder--pureInsertMinimum :: PureOrder -> PureElement-pureInsertMinimum pureOrder-    | Set.null pureOrder = 1 % 2-    | otherwise          = Set.findMin pureOrder / 2--pureInsertMaximum :: PureOrder -> PureElement-pureInsertMaximum pureOrder-    | Set.null pureOrder = 1 % 2-    | otherwise          = (Set.findMax pureOrder + 1) / 2--pureInsertAfter :: PureElement -> PureOrder -> PureElement-pureInsertAfter pureElement pureOrder = pureElement' where--    greater = snd (Set.split pureElement pureOrder)--    pureElement' | Set.null greater = (pureElement + 1) / 2-                 | otherwise        = (pureElement + Set.findMin greater) / 2--pureInsertBefore :: PureElement -> PureOrder -> PureElement-pureInsertBefore pureElement pureOrder = pureElement' where--    lesser = fst (Set.split pureElement pureOrder)--    pureElement' | Set.null lesser = pureElement / 2-                 | otherwise       = (pureElement + Set.findMax lesser) / 2--pureDelete :: PureElement -> PureOrder -> ((), PureOrder)-pureDelete pureElement pureOrder = ((), Set.delete pureElement pureOrder)
− src/Control/Monad/Trans/Order/Algorithm/Type.hs
@@ -1,9 +0,0 @@-module Control.Monad.Trans.Order.Algorithm.Type (--    Algorithm (Algorithm)--) where--import Control.Monad.Trans.Order.Raw--data Algorithm = forall o . Algorithm (forall s . RawAlgorithm o s)
− src/Control/Monad/Trans/Order/Lazy.hs
@@ -1,148 +0,0 @@-module Control.Monad.Trans.Order.Lazy (--    -- * The Order monad--    Order,-    evalOrder,-    evalOrderWith,--    -- * The OrderT monad transformer--    OrderT,-    evalOrderT,-    force,--    -- * Elements--    Element,-    newMinimum,-    newMaximum,-    newAfter,-    newBefore--) where---- Control--import Control.Monad.ST-import Control.Monad.Trans.State.Lazy-import Control.Monad.Trans.Order.Raw-import Control.Monad.Trans.Order.Lazy.Internals-import Control.Monad.Trans.Order.Algorithm-import Control.Monad.Trans.Order.Algorithm.Type---- Data--import Data.Functor.Identity-import Data.IORef---- System--import System.IO.Unsafe---- GHC--import GHC.IORef -- for converting from STRef RealWorld to IORef--{-FIXME:-    Introduce conversions between the lazy and the strict variant, similar to-    the conversions for ST.--}-{-FIXME:-    Consider introducing a restricted variant of mapStateT (for the lazy and the-    strict OrderT monad):--            mapOrderT :: (forall a . m a -> n a) -> OrderT o m a -> OrderT o n a--    Maybe this should not be called mapOrderT, since it is only a restricted-    variant and a corresponding mapOrder would be trivial.--}-{-FIXME:-    Probably we should also have variants of liftCallCC, etc., which are present-    for StateT (for the lazy and the strict OrderT monad).--}---- * The Order monad--type Order o = OrderT o Identity--evalOrder :: (forall o . Order o a) -> a-evalOrder order = runIdentity (evalOrderT order)--evalOrderWith :: Algorithm -> (forall o . Order o a) -> a-evalOrderWith alg order = runIdentity (evalOrderTWith alg order)---- * The OrderT monad transformer--evalOrderT :: Monad m => (forall o . OrderT o m a) -> m a-evalOrderT = evalOrderTWith defaultAlgorithm--evalOrderTWith :: Monad m => Algorithm -> (forall o . OrderT o m a) -> m a-evalOrderTWith (Algorithm rawAlg) (OrderT stateT) = monad where--    monad = evalStateT stateT (emptyOrderRep rawAlg)--force :: Monad m => OrderT o m ()-force = OrderT $ get >>= \ order -> order `seq` return ()---- * Elements--data Element o = Element (RawElement o RealWorld)-                         (RawAlgorithm o RealWorld)-                         Lock--- NOTE: Evaluation of the Element constructor triggers the I/O for insertions.--instance Eq (Element o) where--    (==) (Element rawElem1 (RawAlgorithm _ _ _ _ _ _ _) _)-         (Element rawElem2 _                            _) = equal where--        equal = rawElem1 == rawElem2--instance Ord (Element o) where--    compare (Element rawElem1 rawAlg lock)-            (Element rawElem2 _      _)    = ordering where--        ordering = unsafePerformIO $-                   criticalSection lock $-                   stToIO $ compareElements rawAlg rawElem1 rawElem2-{-FIXME:-    Introduce the safety measures for unsafePerformIO. It should not matter how-    many times the I/O is performed.--}--fromInsert :: Monad m-           => (RawAlgorithm o RealWorld-                   -> RawOrder o RealWorld-                   -> ST RealWorld (RawElement o RealWorld))-           -> OrderT o m (Element o)-fromInsert insert = OrderT $ StateT (return . explicitStateInsert) where--    explicitStateInsert order@(OrderRep rawOrder rawAlg lock) = output where--        output = unsafePerformIO $-                 criticalSection lock $-                 do-                     rawElem <- stToIO $ insert rawAlg rawOrder-                     mkWeakIORef (IORef rawElem)-                                 (criticalSection lock $-                                  stToIO $-                                  delete rawAlg rawElem rawOrder)-                     return (Element rawElem rawAlg lock, order)-    {-FIXME:-        Introduce the safety measures for unsafePerformIO. The I/O must occur only-        once.-    -}--newMinimum :: Monad m => OrderT o m (Element o)-newMinimum = fromInsert insertMinimum--newMaximum :: Monad m => OrderT o m (Element o)-newMaximum = fromInsert insertMaximum--newAfter :: Monad m => Element o -> OrderT o m (Element o)-newAfter (~(Element rawElem _ _)) = fromInsert (flip insertAfter rawElem)--newBefore :: Monad m => Element o -> OrderT o m (Element o)-newBefore (~(Element rawElem _ _)) = fromInsert (flip insertBefore rawElem)
− src/Control/Monad/Trans/Order/Lazy/Internals.hs
@@ -1,71 +0,0 @@-module Control.Monad.Trans.Order.Lazy.Internals (--    -- * The lazy OrderT monad transformer--    OrderT (OrderT),-    OrderRep (OrderRep),-    emptyOrderRep,--    -- * Locks--    Lock,-    criticalSection--) where---- Control--import Control.Monad-import Control.Applicative-import Control.Monad.Trans.Class-import Control.Monad.IO.Class-import Control.Monad.Trans.State.Lazy-import Control.Monad.ST-import Control.Concurrent.MVar-import Control.Monad.Trans.Order.Raw---- System--import System.IO.Unsafe---- * The lazy OrderT monad transformer--newtype OrderT o m a = OrderT (StateT (OrderRep o) m a) deriving (-    Functor,-    Applicative,-    Alternative,-    Monad,-    MonadPlus,-    MonadTrans,-    MonadIO)-    -- FIXME: Should we also have a MonadFix instance?--data OrderRep o = OrderRep (RawOrder o RealWorld)-                           (RawAlgorithm o RealWorld)-                           Lock--- FIXME: Maybe use OrderedSet instead of OrderRep.--- NOTE: Evaluation of the OrderRep constructor triggers the I/O for insertions.--emptyOrderRep :: (forall s . RawAlgorithm o s) -> OrderRep o-emptyOrderRep rawAlg = unsafePerformIO $ do-    rawOrder <- stToIO (newOrder rawAlg)-    lock <- newLock-    return (OrderRep rawOrder rawAlg lock)-{-FIXME:-    Introduce the safety measures for unsafePerformIO. It should not matter-    how many times the I/O is performed.--}---- * Locks--type Lock = MVar ()--newLock :: IO Lock-newLock = newEmptyMVar--criticalSection :: Lock -> IO a -> IO a-criticalSection lock act = do-    putMVar lock ()-    val <- act-    takeMVar lock-    return val
− src/Control/Monad/Trans/Order/Raw.hs
@@ -1,39 +0,0 @@-module Control.Monad.Trans.Order.Raw (--    RawOrder,-    OrderCell,-    RawElement,-    ElementCell,-    RawAlgorithm (-        RawAlgorithm,-        newOrder,-        compareElements,-        insertMinimum,-        insertMaximum,-        insertAfter,-        insertBefore,-        delete-    )--) where--import Control.Monad.ST-import Data.STRef--type RawOrder o s = STRef s (OrderCell o s)--type family OrderCell o s--type RawElement o s = STRef s (ElementCell o s)--type family ElementCell o s--data RawAlgorithm o s = RawAlgorithm {-    newOrder        :: ST s (RawOrder o s),-    compareElements :: RawElement o s -> RawElement o s -> ST s Ordering,-    insertMinimum   :: RawOrder o s -> ST s (RawElement o s),-    insertMaximum   :: RawOrder o s -> ST s (RawElement o s),-    insertAfter     :: RawElement o s -> RawOrder o s -> ST s (RawElement o s),-    insertBefore    :: RawElement o s -> RawOrder o s -> ST s (RawElement o s),-    delete          :: RawElement o s -> RawOrder o s -> ST s ()-}
− src/Control/Monad/Trans/Order/Strict.hs
@@ -1,107 +0,0 @@-module Control.Monad.Trans.Order.Strict (--    -- * The Order monad--    Order,-    evalOrder,-    evalOrderWith,--    -- * The OrderT monad transformer--    OrderT,-    evalOrderT,-    force,--    -- * Elements--    Element,-    newMinimum,-    newMaximum,-    newAfter,-    newBefore,--    -- * Converting between lazy and strict OrderT--    lazyToStrictOrderT,-    strictToLazyOrderT--) where---- Control--import           Control.Monad-import           Control.Applicative-import           Control.Monad.Trans.Class-import           Control.Monad.IO.Class-import qualified Control.Monad.Trans.State.Lazy-                     as Lazy-import           Control.Monad.Trans.State.Strict-import           Control.Monad.Trans.Order.Lazy-                     (Element)-import qualified Control.Monad.Trans.Order.Lazy-                     as Lazy-import           Control.Monad.Trans.Order.Lazy.Internals-                     (OrderRep, emptyOrderRep)-import qualified Control.Monad.Trans.Order.Lazy.Internals-                     as Lazy-import           Control.Monad.Trans.Order.Algorithm-import           Control.Monad.Trans.Order.Algorithm.Type---- Data--import Data.Functor.Identity---- * The Order monad--type Order o = OrderT o Identity--evalOrder :: (forall o . Order o a) -> a-evalOrder order = runIdentity (evalOrderT order)--evalOrderWith :: Algorithm -> (forall o . Order o a) -> a-evalOrderWith alg order = runIdentity (evalOrderTWith alg order)---- * The OrderT monad transformer--newtype OrderT o m a = OrderT (StateT (OrderRep o) m a) deriving (-    Functor,-    Applicative,-    Alternative,-    Monad,-    MonadPlus,-    MonadTrans,-    MonadIO)-    -- FIXME: Should we also have a MonadFix instance?--evalOrderT :: Monad m => (forall o . OrderT o m a) -> m a-evalOrderT = evalOrderTWith defaultAlgorithm--evalOrderTWith :: Monad m => Algorithm -> (forall o . OrderT o m a) -> m a-evalOrderTWith (Algorithm rawAlg) (OrderT stateT) = monad where--    monad = evalStateT stateT (emptyOrderRep rawAlg)--force :: Monad m => OrderT o m ()-force = lazyToStrictOrderT Lazy.force---- * Elements--newMinimum :: Monad m => OrderT o m (Element o)-newMinimum = lazyToStrictOrderT Lazy.newMinimum--newMaximum :: Monad m => OrderT o m (Element o)-newMaximum = lazyToStrictOrderT Lazy.newMaximum--newAfter :: Monad m => Element o -> OrderT o m (Element o)-newAfter = lazyToStrictOrderT . Lazy.newAfter--newBefore :: Monad m => Element o -> OrderT o m (Element o)-newBefore = lazyToStrictOrderT . Lazy.newBefore---- * Converting between lazy and strict OrderT--lazyToStrictOrderT :: Lazy.OrderT o m a -> OrderT o m a-lazyToStrictOrderT (Lazy.OrderT (Lazy.StateT fun)) = OrderT (StateT fun)--strictToLazyOrderT :: OrderT o m a -> Lazy.OrderT o m a-strictToLazyOrderT (OrderT (StateT fun)) = Lazy.OrderT (Lazy.StateT fun)
+ src/library/Control/Monad/Trans/Order.hs view
@@ -0,0 +1,7 @@+module Control.Monad.Trans.Order (++    module Control.Monad.Trans.Order.Lazy++) where++import Control.Monad.Trans.Order.Lazy
+ src/library/Control/Monad/Trans/Order/Algorithm.hs view
@@ -0,0 +1,102 @@+module Control.Monad.Trans.Order.Algorithm (++    -- * General things++    Algorithm,+    defaultAlgorithm,+    withRawAlgorithm,++    -- * Specific algorithms++    dumb,+    dietzSleatorAmortizedLog,+    dietzSleatorAmortizedLogWithSize++) where++import Control.Monad.ST+import Control.Monad.Trans.Order.Raw+import Control.Monad.Trans.Order.Algorithm.Type+import Control.Monad.Trans.Order.Algorithm.Dumb+           as Dumb+import Control.Monad.Trans.Order.Algorithm.DietzSleatorAmortizedLog+           as DietzSleatorAmortizedLog++{-FIXME:+    Implement the following:++      • an algorithm that uses arbitarily deep log-trees++      • the file maintenance algorithm by Bender et al. combined with log-trees+        of fixed height++      • a function that converts any algorithm into one that shifts elements+        between two orders upon deletion (for avoiding sparsly populated order+        structures)++    Maybe it makes sense to additionally offer the file maintenance algorithm by+    Bender et al. as an order maintenance algorithm in its own right.+-}++{-FIXME:+    For implementing Bender et al., it might be good to store the calibrator+    tree in an array, level by level from top to bottom. The array must then be+    created without initializing its elements. Initially the tree would be+    small; so few array elements would be used. When extending the tree, we+    would face the problem that initializing all the additionally used elements+    would take more than O(1) time. We can maybe use the trick by Barak A.+    Pearlmutter¹ (or a variant of it, specialized for our particular+    initialization pattern) to get O(1) time.++      ¹ See his e-mail to me from 5 December 2014.+-}++{-FIXME:+    More notes regarding implementing Bender et al.:++      • We can store the set of all children of a single node of a log-tree in+        an array of 48 64-bit words. Each word represents one child. Children+        are stored in the temporal order of their allocation. 48 bits of a word+        are the label, 3 are the left sibling index, 3 are the right sibling+        index. The parent pointer (pointer to the array plus index in the array)+        has to be stored only once per such an array, not for every child.++      • A block in the file maintenance data structure could encompass 48 or+        maybe also 64 elements. A 64-bit word could be used to store which of+        the array cells are taken by an element and which are free.++      • I think that on the upper two levels of a log tree, we need up to three+        times as many nodes for storing log-many subtrees, because of overflow+        nodes. This would mean that with the above approach, we could store up+        to 48 × 12 × 12 ≈ 7000 elements in a log tree and ca. 7000 × 48 ≈ 350000+        actual elements per file maintenance block. The total memory use would+        be a bit more than 8 × 350000 = 2.8 MB.++      • The number of actual elements per file maintenance block (350,000) would+        be a bit more than 2^18. Since our k would be 48, we could have up to+        2^48 × 2^18 = 2^66 elements theoretically. So we could reach the maximum+        of 2^64 elements.+-}++-- * General things++-- NOTE: Algorithm is imported from Data.OrderMaintenance.Algorithm.Type.++defaultAlgorithm :: Algorithm+defaultAlgorithm = dietzSleatorAmortizedLog++withRawAlgorithm :: Algorithm+                 -> (forall a . RawAlgorithm a s -> ST s r)+                 -> ST s r+withRawAlgorithm (Algorithm rawAlg) cont = cont rawAlg++-- * Specific algorithms++dumb :: Algorithm+dumb = Dumb.algorithm++dietzSleatorAmortizedLog :: Algorithm+dietzSleatorAmortizedLog = DietzSleatorAmortizedLog.algorithm++dietzSleatorAmortizedLogWithSize :: Int -> Algorithm+dietzSleatorAmortizedLogWithSize = DietzSleatorAmortizedLog.algorithmWithSize
+ src/library/Control/Monad/Trans/Order/Algorithm/DietzSleatorAmortizedLog.hs view
@@ -0,0 +1,185 @@+module Control.Monad.Trans.Order.Algorithm.DietzSleatorAmortizedLog (++    algorithm,+    algorithmWithSize++) where++-- Control++import Control.Applicative+import Control.Monad+import Control.Monad.ST+import Control.Monad.Trans.Order.Algorithm.Type+import Control.Monad.Trans.Order.Raw++-- Data++import Data.STRef+import Data.Word+import Data.Bits++algorithm :: Algorithm+algorithm = algorithmWithSize defaultSize++defaultSize :: Int+defaultSize = 63++algorithmWithSize :: Int -> Algorithm+algorithmWithSize size = Algorithm (rawAlgorithmWithSize size)++data DietzSleatorAmortizedLog++type instance OrderCell DietzSleatorAmortizedLog s = Cell s++type instance ElementCell DietzSleatorAmortizedLog s = Cell s++data Cell s = Cell {+                  label :: Label,+                  next  :: CellRef s,+                  prev  :: CellRef s+              }++type CellRef s = STRef s (Cell s)++newtype Label = Label LabelWord deriving (Eq, Ord)++type LabelWord = Word64++labelWordSize :: Int+labelWordSize = 64++initialBaseLabel :: Label+initialBaseLabel = Label 0++rawAlgorithmWithSize :: Int -> RawAlgorithm DietzSleatorAmortizedLog s+rawAlgorithmWithSize size+    | size < 0 || size >= labelWordSize+        = error "Control.Monad.Trans.Order.Algorithm.DietzSleatorAmortizedLog: \+                \Size out of bounds"+    | otherwise+        = RawAlgorithm {+              newOrder        = fixST $+                                \ ref -> newSTRef $ Cell {+                                   label = initialBaseLabel,+                                   next  = ref,+                                   prev  = ref+                                },+              compareElements = \ baseRef ref1 ref2 -> do+                                    baseCell <- readSTRef baseRef+                                    cell1 <- readSTRef ref1+                                    cell2 <- readSTRef ref2+                                    let offset1 = labelDiff (label cell1)+                                                            (label baseCell)+                                    let offset2 = labelDiff (label cell2)+                                                            (label baseCell)+                                    return $ compare offset1 offset2,+              newMinimum      = newAfterCell,+              newMaximum      = newBeforeCell,+              newAfter        = const newAfterCell,+              newBefore       = const newBeforeCell,+              delete          = \ _ ref -> do+                                    cell <- readSTRef ref+                                    modifySTRef+                                        (prev cell)+                                        (\ prevCell -> prevCell {+                                                           next = next cell+                                                       })+                                    modifySTRef+                                        (next cell)+                                        (\ nextCell -> nextCell {+                                                           prev = prev cell+                                                       })+          } where++    noOfLabels :: LabelWord+    noOfLabels = shiftL 1 size++    labelMask :: LabelWord+    labelMask = pred noOfLabels++    toLabel :: LabelWord -> Label+    toLabel = Label . (.&. labelMask)++    labelSum :: Label -> Label -> Label+    labelSum (Label word1) (Label word2) = toLabel (word1 + word2)++    labelDiff :: Label -> Label -> Label+    labelDiff (Label word1) (Label word2) = toLabel (word1 - word2)++    labelDistance :: Label -> Label -> LabelWord+    labelDistance lbl1 lbl2 = case labelDiff lbl1 lbl2 of+                                  Label word | word == 0 -> noOfLabels+                                             | otherwise -> word++    newAfterCell :: CellRef s -> ST s (CellRef s)+    newAfterCell ref = do+        relabel ref+        lbl <- label <$> readSTRef ref+        nextRef <- next <$> readSTRef ref+        nextLbl <- label <$> readSTRef nextRef+        newRef <- newSTRef $ Cell {+            label = labelSum lbl (Label (labelDistance nextLbl lbl `div` 2)),+            next  = nextRef,+            prev  = ref+        }+        modifySTRef ref     (\ cell     -> cell     { next = newRef })+        modifySTRef nextRef (\ nextCell -> nextCell { prev = newRef })+        return newRef++    relabel :: CellRef s -> ST s ()+    relabel startRef = do+        startCell <- readSTRef startRef+        let delimSearch ref gapCount = do+                cell <- readSTRef ref+                let gapSum = labelDistance (label cell) (label startCell)+                if gapSum <= gapCount ^ 2+                    then if ref == startRef+                             then error "Control.Monad.Trans.Order.Algorithm.\+                                        \DietzSleatorAmortizedLog: \+                                        \Order full"+                             else delimSearch (next cell) (succ gapCount)+                    else return (ref, gapSum, gapCount)+        (delimRef, gapSum, gapCount) <- delimSearch (next startCell) 1+        let smallGap = gapSum `div` gapCount+        let largeGapCount = gapSum `mod` gapCount+        let changeLabels ref idx = when (ref /= delimRef) $ do+                cell <- readSTRef ref+                let lbl = labelSum+                              (label startCell)+                              (Label (idx * smallGap + min largeGapCount idx))+                writeSTRef ref (cell { label = lbl })+                changeLabels (next cell) (succ idx)+        changeLabels (next startCell) 1+    {-FIXME:+        We allow the number of cells to be larger than the square root of the+        number of possible labels as long as we find a sparse part in our circle+        of cells (since our order full condition is only true if the complete+        circle is congested). This should not influence correctness and probably+        also not time complexity, but we should check this more thoroughly.+    -}+    {-FIXME:+        We arrange the large and small gaps differently from Dietz and Sleator+        by putting all the large gaps at the beginning instead of distributing+        them over the relabeled area. However, this should not influence time+        complexity, as the complexity proof seems to only rely on the fact that+        gap sizes differ by at most 1. We should check this more thoroughly+        though.+    -}++    newBeforeCell :: CellRef s -> ST s (CellRef s)+    newBeforeCell ref = do+        cell <- readSTRef ref+        newAfterCell (prev cell)++labels :: CellRef s -> ST s [LabelWord]+labels startRef = do+    let aux ref = do+            cell <- readSTRef ref+            let ref' = next cell+            lbls <- if ref' == startRef+                        then return []+                        else aux ref'+            return (label cell : lbls)+    lbls <- aux startRef+    return $ map (\ (Label word) -> word) lbls where
+ src/library/Control/Monad/Trans/Order/Algorithm/Dumb.hs view
@@ -0,0 +1,102 @@+module Control.Monad.Trans.Order.Algorithm.Dumb (++    algorithm++) where++-- Control++import Control.Applicative+import Control.Monad.ST+import Control.Monad.Trans.Order.Algorithm.Type+import Control.Monad.Trans.Order.Raw++-- Data++import           Data.Ratio+import           Data.STRef+import qualified Data.Set as Set+import           Data.Set (Set)++algorithm :: Algorithm+algorithm = Algorithm rawAlgorithm++data Dumb++type instance OrderCell Dumb s = PureOrder++type instance ElementCell Dumb s = PureElement++type PureOrder = Set PureElement++type PureElement = Rational++rawAlgorithm :: RawAlgorithm Dumb s+rawAlgorithm = RawAlgorithm {+    newOrder        = newSTRef Set.empty,+    compareElements = \ _ rawElem1 rawElem2 -> do+                          pureElem1 <- readSTRef rawElem1+                          pureElem2 <- readSTRef rawElem2+                          return (compare pureElem1 pureElem2),+    newMinimum      = fromPureInsert pureInsertMinimum,+    newMaximum      = fromPureInsert pureInsertMaximum,+    newAfter        = relative fromPureInsert pureInsertAfter,+    newBefore       = relative fromPureInsert pureInsertBefore,+    delete          = relative fromPure pureDelete+}++fromPure :: (PureOrder -> (a, PureOrder)) -> RawOrder Dumb s -> ST s a+fromPure trans rawOrder = do+                              pureOrder <- readSTRef rawOrder+                              let (output, pureOrder') = trans pureOrder+                              writeSTRef rawOrder pureOrder'+                              return output++fromPureInsert :: (PureOrder -> PureElement)+               -> RawOrder Dumb s+               -> ST s (RawElement Dumb s)+fromPureInsert trans rawOrder = fromPure trans' rawOrder >>= newSTRef where++    trans' pureOrder = let++                           pureElement = trans pureOrder++                       in (pureElement, Set.insert pureElement pureOrder)++relative :: ((PureOrder -> a) -> RawOrder Dumb s -> ST s b)+         -> (PureOrder -> PureElement -> a)+         -> RawOrder Dumb s+         -> RawElement Dumb s+         -> ST s b+relative conv trans rawOrder rawElem = do+    pureElem <- readSTRef rawElem+    conv (flip trans pureElem) rawOrder++pureInsertMinimum :: PureOrder -> PureElement+pureInsertMinimum pureOrder+    | Set.null pureOrder = 1 % 2+    | otherwise          = Set.findMin pureOrder / 2++pureInsertMaximum :: PureOrder -> PureElement+pureInsertMaximum pureOrder+    | Set.null pureOrder = 1 % 2+    | otherwise          = (Set.findMax pureOrder + 1) / 2++pureInsertAfter :: PureOrder -> PureElement -> PureElement+pureInsertAfter pureOrder pureElement = pureElement' where++    greater = snd (Set.split pureElement pureOrder)++    pureElement' | Set.null greater = (pureElement + 1) / 2+                 | otherwise        = (pureElement + Set.findMin greater) / 2++pureInsertBefore :: PureOrder -> PureElement -> PureElement+pureInsertBefore pureOrder pureElement = pureElement' where++    lesser = fst (Set.split pureElement pureOrder)++    pureElement' | Set.null lesser = pureElement / 2+                 | otherwise       = (pureElement + Set.findMax lesser) / 2++pureDelete :: PureOrder -> PureElement -> ((), PureOrder)+pureDelete pureOrder pureElement = ((), Set.delete pureElement pureOrder)
+ src/library/Control/Monad/Trans/Order/Algorithm/Type.hs view
@@ -0,0 +1,9 @@+module Control.Monad.Trans.Order.Algorithm.Type (++    Algorithm (Algorithm)++) where++import Control.Monad.Trans.Order.Raw++data Algorithm = forall a . Algorithm (forall s . RawAlgorithm a s)
+ src/library/Control/Monad/Trans/Order/Lazy.hs view
@@ -0,0 +1,164 @@+module Control.Monad.Trans.Order.Lazy (++    -- * The Order monad++    Order,+    evalOrder,+    evalOrderWith,++    -- * The OrderT monad transformer++    OrderT,+    evalOrderT,+    force,++    -- * Elements++    Element,+    newMinimum,+    newMaximum,+    newAfter,+    newBefore++) where++-- Control++import           Control.Monad.ST+import           Control.Monad.Trans.State.Lazy+import           Control.Monad.Trans.Order.Raw+                     hiding (newMinimum, newMaximum, newAfter, newBefore)+import qualified Control.Monad.Trans.Order.Raw+                     as Raw+import           Control.Monad.Trans.Order.Lazy.Internals+import           Control.Monad.Trans.Order.Algorithm+import           Control.Monad.Trans.Order.Algorithm.Type++-- Data++import Data.Functor.Identity+import Data.IORef++-- System++import System.IO.Unsafe++-- GHC++import GHC.IORef -- for converting from STRef RealWorld to IORef++{-FIXME:+    Introduce conversions between the lazy and the strict variant, similar to+    the conversions for ST.+-}+{-FIXME:+    Consider introducing a restricted variant of mapStateT (for the lazy and the+    strict OrderT monad):++            mapOrderT :: (forall a . m a -> n a) -> OrderT o m a -> OrderT o n a++    Maybe this should not be called mapOrderT, since it is only a restricted+    variant and a corresponding mapOrder would be trivial.+-}+{-FIXME:+    Probably we should also have variants of liftCallCC, etc., which are present+    for StateT (for the lazy and the strict OrderT monad).+-}++-- * The Order monad++type Order o = OrderT o Identity++evalOrder :: (forall o . Order o a) -> a+evalOrder order = runIdentity (evalOrderT order)++evalOrderWith :: Algorithm -> (forall o . Order o a) -> a+evalOrderWith alg order = runIdentity (evalOrderTWith alg order)++-- * The OrderT monad transformer++-- NOTE: OrderT is imported from Control.Monad.Trans.Order.Lazy.Internals.++evalOrderT :: Monad m => (forall o . OrderT o m a) -> m a+evalOrderT = evalOrderTWith defaultAlgorithm++evalOrderTWith :: Monad m => Algorithm -> (forall o . OrderT o m a) -> m a+evalOrderTWith (Algorithm rawAlg) (OrderT stateT) = monad where++    monad = evalStateT stateT (emptyOrderRep rawAlg)++force :: Monad m => OrderT o m ()+force = OrderT $ get >>= \ order -> order `seq` return ()++-- * Elements++data Element o = Element (RawAlgorithm o RealWorld)+                         (Gate o)+                         (RawElement o RealWorld)+-- NOTE: Evaluation of the Element constructor triggers the I/O for insertions.++instance Eq (Element o) where++    (==) (Element (RawAlgorithm _ _ _ _ _ _ _) _ rawElem1)+         (Element _                            _ rawElem2) = equal where++        equal = rawElem1 == rawElem2++instance Ord (Element o) where++    compare (Element rawAlg gate rawElem1)+            (Element _      _    rawElem2) = ordering where++        ordering = unsafePerformIO $+                   withRawOrder gate $ \ rawOrder ->+                   stToIO $ compareElements rawAlg rawOrder rawElem1 rawElem2+{-FIXME:+    Introduce the safety measures for unsafePerformIO. It should not matter how+    many times the I/O is performed.+-}++fromRawNew :: Monad m+           => (RawAlgorithm o RealWorld+                   -> RawOrder o RealWorld+                   -> ST RealWorld (RawElement o RealWorld))+           -> OrderT o m (Element o)+fromRawNew rawNew = OrderT $ StateT (return . explicitStateNew) where++    explicitStateNew order@(OrderRep rawAlg gate) = output where++        output = unsafePerformIO $+                 withRawOrder gate $ \ rawOrder ->+                 do+                     rawElem <- stToIO $ rawNew rawAlg rawOrder+                     mkWeakIORef (IORef rawElem)+                                 (withRawOrder gate $ \ rawOrder ->+                                  stToIO $+                                  delete rawAlg rawOrder rawElem)+                     return (Element rawAlg gate rawElem, order)+    {-FIXME:+        Introduce the safety measures for unsafePerformIO. The I/O must occur only+        once.+    -}++newMinimum :: Monad m => OrderT o m (Element o)+newMinimum = fromRawNew Raw.newMinimum++newMaximum :: Monad m => OrderT o m (Element o)+newMaximum = fromRawNew Raw.newMaximum++newAfter :: Monad m => Element o -> OrderT o m (Element o)+newAfter (~(Element _ _ rawElem)) = fromRawNeighbor Raw.newAfter rawElem++newBefore :: Monad m => Element o -> OrderT o m (Element o)+newBefore (~(Element _ _ rawElem)) = fromRawNeighbor Raw.newBefore rawElem++fromRawNeighbor :: Monad m+                => (RawAlgorithm o RealWorld+                        -> RawOrder o RealWorld+                        -> RawElement o RealWorld+                        -> ST RealWorld (RawElement o RealWorld))+                -> RawElement o RealWorld+                -> OrderT o m (Element o)+fromRawNeighbor rawNewNeighbor rawElem = fromRawNew rawNew where++    rawNew rawAlg rawOrder = rawNewNeighbor rawAlg rawOrder rawElem
+ src/library/Control/Monad/Trans/Order/Lazy/Internals.hs view
@@ -0,0 +1,66 @@+module Control.Monad.Trans.Order.Lazy.Internals (++    -- * The lazy OrderT monad transformer++    OrderT (OrderT),+    OrderRep (OrderRep),+    emptyOrderRep,++    -- * Gates++    Gate,+    withRawOrder++) where++-- Control++import Control.Monad+import Control.Applicative+import Control.Monad.Trans.Class+import Control.Monad.IO.Class+import Control.Monad.Trans.State.Lazy+import Control.Monad.ST+import Control.Concurrent.MVar+import Control.Exception+import Control.Monad.Trans.Order.Raw++-- System++import System.IO.Unsafe++-- * The lazy OrderT monad transformer++newtype OrderT o m a = OrderT (StateT (OrderRep o) m a) deriving (+    Functor,+    Applicative,+    Alternative,+    Monad,+    MonadPlus,+    MonadTrans,+    MonadIO)+    -- FIXME: Should we also have a MonadFix instance?++data OrderRep o = OrderRep (RawAlgorithm o RealWorld) (Gate o)+-- FIXME: Maybe use OrderedSet instead of OrderRep.+-- NOTE: Evaluation of the OrderRep constructor triggers the I/O for insertions.++emptyOrderRep :: (forall s . RawAlgorithm o s) -> OrderRep o+emptyOrderRep rawAlg = unsafePerformIO $ do+    rawOrder <- stToIO (newOrder rawAlg)+    gate <- newGate rawOrder+    return (OrderRep rawAlg gate)+{-FIXME:+    Introduce the safety measures for unsafePerformIO. It should not matter+    how many times the I/O is performed.+-}++-- * Gates++newtype Gate a = Gate (MVar (RawOrder a RealWorld))++newGate :: RawOrder a RealWorld -> IO (Gate a)+newGate = fmap Gate . newMVar++withRawOrder :: Gate a -> (RawOrder a RealWorld -> IO r) -> IO r+withRawOrder (Gate mVar) cont = bracket (takeMVar mVar) (putMVar mVar) cont
+ src/library/Control/Monad/Trans/Order/Raw.hs view
@@ -0,0 +1,51 @@+module Control.Monad.Trans.Order.Raw (++    RawOrder,+    OrderCell,+    RawElement,+    ElementCell,+    RawAlgorithm (+        RawAlgorithm,+        newOrder,+        compareElements,+        newMinimum,+        newMaximum,+        newAfter,+        newBefore,+        delete+    )++) where++import Control.Monad.ST+import Data.STRef++type RawOrder a s = STRef s (OrderCell a s)++type family OrderCell a s++type RawElement a s = STRef s (ElementCell a s)++type family ElementCell a s++data RawAlgorithm a s = RawAlgorithm {+    newOrder        :: ST s (RawOrder a s),+    compareElements :: RawOrder a s+                    -> RawElement a s+                    -> RawElement a s+                    -> ST s Ordering,+    newMinimum      :: RawOrder a s -> ST s (RawElement a s),+    newMaximum      :: RawOrder a s -> ST s (RawElement a s),+    newAfter        :: RawOrder a s -> RawElement a s -> ST s (RawElement a s),+    newBefore       :: RawOrder a s -> RawElement a s -> ST s (RawElement a s),+    delete          :: RawOrder a s -> RawElement a s -> ST s ()+}+{-FIXME:+    If we ever allow users to plug in their own algorithms, we have to flag the+    respective function as unsafe and point out that referential transparency is+    in danger if the algorithm does not fulfill the specification. This is+    because element comparison is presented to the user as a pure function. The+    important condition is that for any two elements, compareElements must+    always return the same result as long as delete is not called on either+    element.+-}
+ src/library/Control/Monad/Trans/Order/Strict.hs view
@@ -0,0 +1,107 @@+module Control.Monad.Trans.Order.Strict (++    -- * The Order monad++    Order,+    evalOrder,+    evalOrderWith,++    -- * The OrderT monad transformer++    OrderT,+    evalOrderT,+    force,++    -- * Elements++    Element,+    newMinimum,+    newMaximum,+    newAfter,+    newBefore,++    -- * Converting between lazy and strict OrderT++    lazyToStrictOrderT,+    strictToLazyOrderT++) where++-- Control++import           Control.Monad+import           Control.Applicative+import           Control.Monad.Trans.Class+import           Control.Monad.IO.Class+import qualified Control.Monad.Trans.State.Lazy+                     as Lazy+import           Control.Monad.Trans.State.Strict+import           Control.Monad.Trans.Order.Lazy+                     (Element)+import qualified Control.Monad.Trans.Order.Lazy+                     as Lazy+import           Control.Monad.Trans.Order.Lazy.Internals+                     (OrderRep, emptyOrderRep)+import qualified Control.Monad.Trans.Order.Lazy.Internals+                     as Lazy+import           Control.Monad.Trans.Order.Algorithm+import           Control.Monad.Trans.Order.Algorithm.Type++-- Data++import Data.Functor.Identity++-- * The Order monad++type Order o = OrderT o Identity++evalOrder :: (forall o . Order o a) -> a+evalOrder order = runIdentity (evalOrderT order)++evalOrderWith :: Algorithm -> (forall o . Order o a) -> a+evalOrderWith alg order = runIdentity (evalOrderTWith alg order)++-- * The OrderT monad transformer++newtype OrderT o m a = OrderT (StateT (OrderRep o) m a) deriving (+    Functor,+    Applicative,+    Alternative,+    Monad,+    MonadPlus,+    MonadTrans,+    MonadIO)+    -- FIXME: Should we also have a MonadFix instance?++evalOrderT :: Monad m => (forall o . OrderT o m a) -> m a+evalOrderT = evalOrderTWith defaultAlgorithm++evalOrderTWith :: Monad m => Algorithm -> (forall o . OrderT o m a) -> m a+evalOrderTWith (Algorithm rawAlg) (OrderT stateT) = monad where++    monad = evalStateT stateT (emptyOrderRep rawAlg)++force :: Monad m => OrderT o m ()+force = lazyToStrictOrderT Lazy.force++-- * Elements++newMinimum :: Monad m => OrderT o m (Element o)+newMinimum = lazyToStrictOrderT Lazy.newMinimum++newMaximum :: Monad m => OrderT o m (Element o)+newMaximum = lazyToStrictOrderT Lazy.newMaximum++newAfter :: Monad m => Element o -> OrderT o m (Element o)+newAfter = lazyToStrictOrderT . Lazy.newAfter++newBefore :: Monad m => Element o -> OrderT o m (Element o)+newBefore = lazyToStrictOrderT . Lazy.newBefore++-- * Converting between lazy and strict OrderT++lazyToStrictOrderT :: Lazy.OrderT o m a -> OrderT o m a+lazyToStrictOrderT (Lazy.OrderT (Lazy.StateT fun)) = OrderT (StateT fun)++strictToLazyOrderT :: OrderT o m a -> Lazy.OrderT o m a+strictToLazyOrderT (OrderT (StateT fun)) = Lazy.OrderT (Lazy.StateT fun)
+ src/test-suites/TestSuite.hs view
@@ -0,0 +1,199 @@+module TestSuite (++    tests++) where++-- Control++import           Control.Monad+import           Control.Monad.ST+import           Control.Monad.Trans.Class+import           Control.Monad.Trans.State+import           Control.Monad.Trans.Order.Algorithm+                     (Algorithm, withRawAlgorithm)+import qualified Control.Monad.Trans.Order.Algorithm+                     as Algorithm+import           Control.Monad.Trans.Order.Raw++-- Data++import           Data.Set (Set)+import qualified Data.Set as Set+import           Data.Map (Map)+import qualified Data.Map as Map++-- Test++import Test.QuickCheck++-- Distribution++import Distribution.TestSuite+import Distribution.TestSuite.QuickCheck++-- * Tests++tests :: IO [Test]+tests = return $ map (uncurry comparisonTest) [+            (dumb, dietzSleatorAmortizedLogWithSize14)+        ]++-- * Order computations++newtype OrderComp = OrderComp [OrderStmt]++initialID :: Int+initialID = 1++instance Show OrderComp where++    show (OrderComp stmts)+        | null stmts = "no statements"+        | otherwise  = str ++ concatMap (", " ++) strs where++            str : strs = zipWith showStmt stmts nextIds++            newElemCounts = map newElemCount stmts++            nextIds = scanl (+) initialID newElemCounts++data CompGenState = CompGenState (Set Int) Int++instance Arbitrary OrderComp where++    arbitrary = sized $ \ size -> do+                    len <- choose (0, size)+                    stmts <- evalStateT (replicateM len genStmt)+                                        (CompGenState Set.empty initialID)+                    return (OrderComp stmts)++    shrink (OrderComp stmts) = if null stmts+                                   then []+                                   else [OrderComp (init stmts)]++type ComparisonMatrix = Map (Int, Int) Ordering++runComp :: Algorithm -> OrderComp -> ComparisonMatrix+runComp alg comp = compMatrix where++    compMatrix = runST (withRawAlgorithm alg (\ rawAlg -> execComp rawAlg comp))++data CompExecState a s = CompExecState (ElementMap a s) Int++type ElementMap a s = Map Int (RawElement a s)++execComp :: RawAlgorithm a s -> OrderComp -> ST s ComparisonMatrix+execComp rawAlg (OrderComp stmts) = do+    rawOrder <- newOrder rawAlg+    let execStmts = mapM_ (execStmt rawAlg rawOrder) stmts+    let initState = CompExecState Map.empty initialID+    ((), CompExecState elemMap _) <- runStateT execStmts initState+    let idElemPairs = Map.toList elemMap+    let comparisonPair (id1, elem1) (id2, elem2) = do+            ordering <- compareElements rawAlg rawOrder elem1 elem2+            return ((id1, id2), ordering)+    comparisonPairs <- sequence $ liftM2 comparisonPair idElemPairs idElemPairs+    return $ Map.fromList comparisonPairs++data OrderStmt = NewMinimum+               | NewMaximum+               | NewAfter Int+               | NewBefore Int+               | Delete Int++newElemCount :: OrderStmt -> Int+newElemCount NewMinimum     = 1+newElemCount NewMaximum     = 1+newElemCount (NewAfter id)  = 1+newElemCount (NewBefore id) = 1+newElemCount (Delete id)    = 0++showStmt :: OrderStmt -> Int -> String+showStmt NewMinimum     = showNewStmt "newMinimum"+showStmt NewMaximum     = showNewStmt "newMaximum"+showStmt (NewAfter id)  = showNewStmt ("newAfter " ++ showElem id)+showStmt (NewBefore id) = showNewStmt ("newBefore " ++ showElem id)+showStmt (Delete id)    = const ("delete " ++ showElem id)++showNewStmt :: String -> Int -> String+showNewStmt base nextId = base ++ " -> " ++ showElem nextId++showElem :: Int -> String+showElem id = "x_" ++ show id++genStmt :: StateT CompGenState Gen OrderStmt+genStmt = do+    CompGenState liveIds nextId <- get+    let liveIdGen = elements (Set.toList liveIds)+    stmt <- lift $+            if Set.null liveIds+                then elements [NewMinimum, NewMaximum]+                else frequency [+                         (1, return NewMinimum),+                         (1, return NewMaximum),+                         (3, fmap NewAfter liveIdGen),+                         (3, fmap NewBefore liveIdGen),+                         (2, fmap Delete liveIdGen)+                     ]+    let newStmtIds = (Set.singleton nextId, Set.empty)+    let (newIds, deadIds) = case stmt of+                                NewMinimum  -> newStmtIds+                                NewMaximum  -> newStmtIds+                                NewAfter _  -> newStmtIds+                                NewBefore _ -> newStmtIds+                                Delete id   -> (Set.empty, Set.singleton id)+    put $ CompGenState ((liveIds `Set.union` newIds) `Set.difference` deadIds)+                       (nextId + Set.size newIds)+    return stmt++execStmt :: RawAlgorithm a s+         -> RawOrder a s+         -> OrderStmt+         -> StateT (CompExecState a s) (ST s) ()+execStmt rawAlg rawOrder = exec where++    exec NewMinimum     = execNew newMinimum+    exec NewMaximum     = execNew newMaximum+    exec (NewAfter id)  = execNewNeighbor newAfter id+    exec (NewBefore id) = execNewNeighbor newBefore id+    exec (Delete id)    = execDelete id++    execNew new = do+        CompExecState elemMap nextId <- get+        rawElem <- lift $ new rawAlg rawOrder+        put $ CompExecState (Map.insert nextId rawElem elemMap) (succ nextId)++    execNewNeighbor newNeighbor id = do+        CompExecState elemMap _ <- get+        let new rawAlg rawOrder = newNeighbor rawAlg rawOrder (elemMap Map.! id)+        execNew new++    execDelete id = do+        CompExecState elemMap nextId <- get+        lift $ delete rawAlg rawOrder (elemMap Map.! id)+        put $ CompExecState (Map.delete id elemMap) nextId++-- * Named algorithms++data NamedAlgorithm = NamedAlgorithm String Algorithm++dumb :: NamedAlgorithm+dumb = NamedAlgorithm "Dumb" Algorithm.dumb++dietzSleatorAmortizedLogWithSize14 :: NamedAlgorithm+dietzSleatorAmortizedLogWithSize14 = NamedAlgorithm name alg where++    name = "Dietz and Sleator O(log n) amortized time"++    alg = Algorithm.dietzSleatorAmortizedLogWithSize 14++-- * Test pattern++comparisonTest :: NamedAlgorithm -> NamedAlgorithm -> Test+comparisonTest (NamedAlgorithm name1 alg1)+               (NamedAlgorithm name2 alg2) = testProperty name prop where++    name = name1 ++ " vs. " ++ name2++    prop comp = runComp alg1 comp == runComp alg2 comp