incremental-maps-0.0.0.0: src/library/Data/Incremental/Map.hs
module Data.Incremental.Map (
-- * Changes
insert,
delete,
id,
-- * Atomic changes
AtomicChange (Insert, Delete),
-- * Transformations
member,
lookup,
filter,
map,
partition,
union,
difference,
intersection,
isSubmapOf,
keysSet,
split,
mapKeys
) where
import Prelude hiding (id,
lookup,
filter,
map)
import Data.Map (Map)
import qualified Data.Map as Map
import Data.DList (DList)
import qualified Data.DList as DList
import Data.Maybe (Maybe)
import qualified Data.Maybe as Maybe
import Data.MultiChange (MultiChange)
import qualified Data.MultiChange as MultiChange
import Data.Incremental
import qualified Data.Incremental.Tuple as Tuple
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Incremental.Set as IncSet
-- maps implementation
data AtomicChange k v = Insert k v | Delete k deriving Show
-- teeme mapi muudetavaks
instance (Ord k) => Changeable (Map k v) where
type DefaultChange (Map k v) = MultiChange (AtomicChange k v)
insert :: (Ord k) => k -> v -> DefaultChange (Map k v)
insert k v = MultiChange.singleton (Insert k v)
delete :: (Ord k) => k -> DefaultChange (Map k v)
delete k = MultiChange.singleton (Delete k)
id :: (Ord k) => DefaultChange (Map k v)
id = MultiChange.fromList []
instance (Ord k) => Change (AtomicChange k v) where
type Value (AtomicChange k v) = Map k v
Insert k v $$ m = Map.insert k v m
Delete k $$ m = Map.delete k m
append :: AtomicChange k v -> MultiChange (AtomicChange k v) -> MultiChange (AtomicChange k v)
append change changes = mappend (MultiChange.singleton change) changes
-- teeme maybe muudetavaks
instance Changeable (Maybe a)
empty :: Map k v
empty = Map.empty
singleton :: (Ord k, Changeable k, Changeable v) => (k,v) ->> Map k v
singleton = MultiChange.composeMap $ stateTrans initSingleton propSingleton
type SingletonState k v = Map k v
initSingleton :: (Ord k) => (k,v) -> (Map k v,SingletonState k v)
initSingleton (k,v) = (result,state) where
result = Map.singleton k v
state = result
propSingleton :: (Ord k, Changeable k, Changeable v) => Tuple.AtomicChange k v -> SingletonState k v -> (MultiChange (AtomicChange k v), SingletonState k v)
propSingleton multiChange m =
case multiChange of
(Tuple.First change) -> (mapChange, mapChange $$ m) where
mapChange = MultiChange.fromList [(Delete k),(Insert (change $$ k) v)]
(Tuple.Second change) -> (mapChange, mapChange $$ m) where
mapChange = (insert k (change $$ v))
where (k,v) = Map.elemAt 0 m
--member
type MemberState k = k
member :: (Ord k) => k -> (Map k v) ->> Bool
member k = MultiChange.composeMap $ stateTrans (initMember k) propMember
initMember :: (Ord k) => k -> Map k v -> (Bool, MemberState k)
initMember k m = (isMember, state) where
isMember = Map.member k m
state = k
propMember :: (Ord k) => (AtomicChange k v) -> MemberState k -> (PrimitiveChange Bool, MemberState k)
propMember (Insert k v) k'
| k == k' = (ReplaceBy True,k')
| otherwise = (Keep,k')
propMember (Delete k) k'
| k == k' =(ReplaceBy False,k')
| otherwise = (Keep,k')
--lookup
type LookupState k = k
lookup :: Ord k => k -> (Map k v) ->> Maybe v
lookup k = MultiChange.composeMap $ stateTrans (initLookup k) propLookup
initLookup :: (Ord k) => k -> Map k v -> (Maybe v, LookupState k)
initLookup k m = (result, state)
where result = Map.lookup k m
state = k
propLookup :: Ord k => AtomicChange k v -> LookupState k -> (PrimitiveChange (Maybe v), LookupState k)
propLookup (Insert k v) k'
| k == k' = (ReplaceBy (Just v),k')
| otherwise = (Keep,k')
propLookup (Delete k) k'
| k == k' =(ReplaceBy Nothing,k')
| otherwise = (Keep,k')
--filter
type FilterState v = (v -> Bool)
filter :: (Ord k) => (v -> Bool) -> Map k v ->> Map k v
filter f = MultiChange.composeMap $ stateTrans (initFilter f) propFilter
initFilter :: (Ord k) => (v -> Bool) -> Map k v -> (Map k v, FilterState v)
initFilter f m = (result, state)
where result = Map.filter f m
state = f
propFilter :: (Ord k) => AtomicChange k v -> FilterState v -> (MultiChange (AtomicChange k v), FilterState v)
propFilter (Insert k v) f
| f v = (insert k v, f)
| otherwise = (delete k, f)
propFilter (Delete k) f = (delete k, f)
--map
type MapState v a = (v -> a)
map :: (Ord k) => (v -> a) -> Map k v ->> Map k a
map f = MultiChange.composeMap $ stateTrans (initMap f) propMap
initMap :: (Ord k) => (v -> a) -> Map k v -> (Map k a, MapState v a)
initMap f m = (result,state)
where result = Map.map f m
state = f
propMap :: (Ord k) => AtomicChange k v -> MapState v a -> (MultiChange (AtomicChange k a), MapState v a)
propMap (Insert k v) f = (insert k (f v),f)
propMap (Delete k) f = (delete k,f)
--partition
type PartitionState v = ((v -> Bool))
partition :: (Ord k) => (v -> Bool) -> Map k v ->> (Map k v, Map k v)
partition f = MultiChange.composeMap $ stateTrans (initPartition f) propPartition
initPartition :: (Ord k) => (v -> Bool) -> Map k v -> ((Map k v, Map k v), PartitionState v)
initPartition f m = (result, state)
where result = Map.partition f m
state = f
propPartition :: (Ord k) => AtomicChange k v -> PartitionState v -> (MultiChange (Tuple.AtomicChange (Map k v) (Map k v)), PartitionState v)
propPartition mapChange f =
case mapChange of
(Insert k v)
| f v -> (MultiChange.fromList [Tuple.First (insert k v), Tuple.Second (delete k)],f)
| otherwise -> (MultiChange.fromList [Tuple.First (delete k), Tuple.Second (insert k v)],f)
(Delete k) -> (MultiChange.fromList [Tuple.First (delete k), Tuple.Second (delete k)],f)
--union
type UnionState k v = (Map k v, Map k v)
union :: (Ord k) => (Map k v, Map k v) ->> Map k v
union = MultiChange.composeMap $ stateTrans initUnion propUnion
initUnion :: Ord k => (Map k v, Map k v) -> (Map k v, UnionState k v)
initUnion (l,r) = (result, state)
where result = Map.union l r
state = (l,r)
propUnion :: (Ord k) => (Tuple.AtomicChange (Map k v) (Map k v)) -> UnionState k v -> (MultiChange (AtomicChange k v), UnionState k v)
propUnion multiChange state =
case multiChange of
(Tuple.First changes) -> foldl applyUnionLeft (id,state) changes
(Tuple.Second changes) -> foldl applyUnionRight (id,state) changes
--hetkel ei näe võimalust neid kokku tõsta, sest need ei ole päris samasugused meetodid, mis tuleneb unioni asümmeetrilisusest.
applyUnionLeft :: Ord k => (MultiChange (AtomicChange k v), UnionState k v) -> AtomicChange k v -> (MultiChange (AtomicChange k v), UnionState k v)
applyUnionLeft (multiChange,(l,r)) change = prop change where
prop (Delete k)
| inFirst && inSecond == False = (append change multiChange, (change $$ l, r))
| inFirst && inSecond = case secondElem of (Just v) -> (append (Insert k v) multiChange, (change $$ l, r))
| otherwise = (multiChange, (l, r))
where secondElem = Map.lookup k r
inFirst = Map.member k l
inSecond = Maybe.isJust secondElem
prop (Insert k v) = (append change multiChange, (change $$ l, r))
applyUnionRight :: Ord k => (MultiChange (AtomicChange k v), UnionState k v) -> AtomicChange k v -> (MultiChange (AtomicChange k v), UnionState k v)
applyUnionRight (multiChange,(l,r)) change = prop change where
prop (Delete k)
| inFirst = (multiChange, (l, change $$ r))
| otherwise = (append change multiChange, (l, change $$ r))
where inFirst = Map.member k l
prop (Insert k v)
| inFirst = (multiChange, (l, change $$ r))
| otherwise = (append change multiChange, (l, change $$ r))
where inFirst = Map.member k l
--difference
type DifferenceState k v = (Map k v, Map k v)
difference :: (Ord k) => (Map k v, Map k v) ->> Map k v
difference = MultiChange.composeMap $ stateTrans initDifference propDifference
initDifference :: Ord k => (Map k v, Map k v) -> (Map k v, DifferenceState k v)
initDifference (l,r) = (result, state)
where result = Map.difference l r
state = (l,r)
propDifference :: (Ord k) => (Tuple.AtomicChange (Map k v) (Map k v)) -> DifferenceState k v -> (MultiChange (AtomicChange k v), DifferenceState k v)
propDifference multiChange state =
case multiChange of
(Tuple.First changes) -> foldl applyDifferenceLeft (id,state) changes
(Tuple.Second changes) -> foldl applyDifferenceRight (id,state) changes
applyDifferenceLeft :: Ord k => (MultiChange (AtomicChange k v), (Map k v, Map k v)) -> AtomicChange k v -> (MultiChange (AtomicChange k v), (Map k v, Map k v))
applyDifferenceLeft (multiChange,(l,r)) change =
case change of
(Insert k v)
| inSecond == False -> (append change multiChange, (change $$ l, r))
| otherwise -> (multiChange, (change $$ l, r))
where inSecond = Map.member k r
(Delete k) -> (append change multiChange, (change $$ l, r))
applyDifferenceRight :: Ord k => (MultiChange (AtomicChange k v), (Map k v, Map k v)) -> AtomicChange k v -> (MultiChange (AtomicChange k v), (Map k v, Map k v))
applyDifferenceRight (multiChange,(l,r)) change =
case change of
(Insert k v)
| inFirst -> (append (Delete k) multiChange, (l, change $$ r))
| otherwise -> (multiChange, (l, change $$ r))
where inFirst = Map.member k l
(Delete k) -> case Map.lookup k l of
(Just v) -> (append (Insert k v) multiChange, (l, change $$ r))
Nothing -> (multiChange, (l, change $$ r))
--intersection
type IntersectionState k v = (Map k v, Map k v)
intersection :: (Ord k) => (Map k v, Map k v) ->> Map k v
intersection = MultiChange.composeMap $ stateTrans initIntersection propIntersection
initIntersection :: Ord k => (Map k v, Map k v) -> (Map k v, IntersectionState k v)
initIntersection (l,r) = (result, state)
where result = Map.intersection l r
state = (l,r)
propIntersection :: (Ord k) => (Tuple.AtomicChange (Map k v) (Map k v)) -> IntersectionState k v -> (MultiChange (AtomicChange k v), IntersectionState k v)
propIntersection multiChange state =
case multiChange of
(Tuple.First changes) -> foldl applyIntersectionLeft (id,state) changes
(Tuple.Second changes) -> foldl applyIntersectionRight (id,state) changes
applyIntersectionLeft :: Ord k => (MultiChange (AtomicChange k v), (Map k v, Map k v)) -> AtomicChange k v -> (MultiChange (AtomicChange k v), IntersectionState k v)
applyIntersectionLeft (multiChange,(l,r)) change =
case change of
(Insert k v)
| inSecond -> (append change multiChange, (change $$ l, r))
| otherwise -> (multiChange, (change $$ l, r))
where inSecond = Map.member k r
(Delete k)
| inSecond -> (append change multiChange, (change $$ l, r))
| otherwise -> (multiChange, (change $$ l, r))
where inSecond = Map.member k r
applyIntersectionRight :: Ord k => (MultiChange (AtomicChange k v), (Map k v, Map k v)) -> AtomicChange k v -> (MultiChange (AtomicChange k v), IntersectionState k v)
applyIntersectionRight (multiChange,(l,r)) change =
case change of
(Insert k v) ->
case Map.lookup k l of
(Just v) -> (append (Insert k v) multiChange, (l, change $$ r)) --testimine tuvastas vea mis sai parandatud
Nothing -> (multiChange, (l, change $$ r))
(Delete k)
| inFirst -> (append change multiChange, (l, change $$ r))
| otherwise -> (multiChange, (l, change $$ r))
where inFirst = Map.member k l
--submap
--state: left, right, difference
--efektiivne ainult sellisel juhul, kui hulgad on piisavalt sarnased
--originaalalgoritmi puhul piisab ühest vastunäitest, et anda vastus False, seega vähim
--keerukus on O(1)! Samas allpoololevas tehakse igal juhul kolm O(log n) keerukusega operatsiooni
type SubmapOfState k v = (Map k v, Map k v, Map k v)
isSubmapOf :: (Ord k, Eq v) => (Map k v, Map k v) ->> Bool
isSubmapOf = MultiChange.composeMap $ stateTrans initSubmapOf propSubmapOf
initSubmapOf :: (Ord k, Eq v) => (Map k v, Map k v) -> (Bool, SubmapOfState k v)
initSubmapOf (l,r) = (result, state)
where result = Map.isSubmapOf l r
state = (l, r, Map.differenceWith discardEqualValues l r)
discardEqualValues :: (Eq a) => (a -> a -> Maybe a)
discardEqualValues a b
| a == b = Nothing
| otherwise = Just a
propSubmapOf :: (Ord k, Eq v) => (Tuple.AtomicChange (Map k v) (Map k v)) -> SubmapOfState k v -> (PrimitiveChange Bool, SubmapOfState k v)
propSubmapOf multiChange state =
case multiChange of
(Tuple.First changes) -> foldl applySubmapOfLeft (Keep,state) changes
(Tuple.Second changes) -> foldl applySubmapOfRight (Keep,state) changes
applySubmapOfLeft :: (Ord k, Eq v) => (PrimitiveChange Bool, SubmapOfState k v) -> AtomicChange k v -> (PrimitiveChange Bool, SubmapOfState k v )
applySubmapOfLeft (boolChange,(l,r,lrDiff)) change = prop change where
prop (Insert k v) = right k v (Map.lookup k r) where
right k v (Just v') = if (v == v')
then (mappend (Keep) boolChange, (insert k v $$ l, r, delete k $$ lrDiff))
else (mappend (ReplaceBy False) boolChange, (insert k v $$ l, r, insert k v $$ lrDiff))
right k v (Nothing) = (mappend (ReplaceBy False) boolChange, (insert k v $$ l, r, insert k v $$ lrDiff))
prop (Delete k) = diff k (Map.lookup k lrDiff) where
diff k (Just _) = if (length lrDiff == 1)
then (mappend (ReplaceBy True) boolChange, (delete k $$ l, r, delete k $$ lrDiff))
else (mappend Keep boolChange, (delete k $$ l, r, delete k $$ lrDiff))
diff k (Nothing) = (mappend Keep boolChange, (delete k $$ l, r, delete k $$ lrDiff))
applySubmapOfRight :: (Ord k, Eq v) => (PrimitiveChange Bool, SubmapOfState k v) -> AtomicChange k v -> (PrimitiveChange Bool, SubmapOfState k v )
applySubmapOfRight (boolChange,(l,r,lrDiff)) change = prop change where
prop (Insert k v) = diff k v (Map.lookup k lrDiff) where
diff k v (Just v') = if (v == v' && length lrDiff == 1) then (mappend (ReplaceBy True) boolChange, (l,insert k v' $$ r, delete k $$ lrDiff))
else if (v == v') then (mappend (Keep) boolChange, (l,insert k v $$ r, delete k $$ lrDiff))
else (mappend Keep boolChange, (l, insert k v $$ r, lrDiff))
diff k v (Nothing) = left k v (Map.lookup k l) where
left k v (Just v') = if (v == v') then (mappend Keep boolChange, (l, insert k v $$ r, lrDiff))
else (mappend (ReplaceBy False) boolChange, (l, insert k v $$ r, insert k v' $$ lrDiff))
left k v (Nothing) = (mappend Keep boolChange, (l, insert k v $$ r, lrDiff))
prop (Delete k) = left k (Map.lookup k l) where
left k (Just v') = (mappend (ReplaceBy False) boolChange, (l, delete k $$ r, insert k v' $$ lrDiff))
left k (Nothing) = (mappend (Keep) boolChange, (l, delete k $$ r, lrDiff))
--kas siin võiks kasutada (Map k ()) ? Aga sellisel juhul ei oleks väljund võrreldav Data.Map omaga
--keysset
keysSet :: (Ord k) => Map k v ->> (Set k)
keysSet = MultiChange.bind $ simpleTrans initKeysSet propKeysSet
initKeysSet :: (Ord k) => Map k v -> (Set k)
initKeysSet m = Map.keysSet m
propKeysSet :: (Ord k) => AtomicChange k v -> MultiChange (IncSet.AtomicChange k)
propKeysSet mapChange =
case mapChange of
(Insert k v) -> MultiChange.singleton (IncSet.Insert k)
(Delete k) -> MultiChange.singleton (IncSet.Delete k)
--split
--O(logn ) -> O(log n), mõttetu
type SplitState k = k
split :: (Ord k) => k -> Map k v ->> (Map k v, Map k v)
split k = MultiChange.composeMap $ stateTrans (initSplit k) propSplit
initSplit :: (Ord k) => k -> Map k v -> ((Map k v, Map k v), SplitState k)
initSplit k m = (result,state)
where result = Map.split k m
state = k
propSplit :: (Ord k) => AtomicChange k v -> SplitState k -> (MultiChange (Tuple.AtomicChange (Map k v) (Map k v)), SplitState k)
propSplit change state =
case change of
(Insert k v)
| k < state -> (MultiChange.fromList [Tuple.First (insert k v)], state)
| k > state -> (MultiChange.fromList [Tuple.Second (insert k v)], state)
| otherwise -> (MultiChange.fromList [], state)
(Delete k)
| k < state -> (MultiChange.fromList [Tuple.First (delete k)], state)
| k > state -> (MultiChange.fromList [Tuple.Second (delete k)], state)
| otherwise -> (MultiChange.fromList [], state)
--mapkeys
--values of the new keys are collapsed
--to the value of largest key (before f is applied)
type MapKeysState a b v = ((a -> b), Map b (Map a v))
mapKeys :: (Ord a, Ord b) => (a -> b) -> Map a v ->> Map b v
mapKeys fun = MultiChange.composeMap $ stateTrans (initMapKeys fun) propMapKeys
initMapKeys :: (Ord a, Ord b) => (a -> b) -> Map a v -> (Map b v, MapKeysState a b v)
initMapKeys fun m = (result,state) where
result = Map.mapKeys fun m
state = (fun, (Map.foldrWithKey (groupKeys fun) Map.empty m))
--creates a map of keys and list of values
groupKeys :: (Ord a, Ord b) => (a -> b) -> a -> v -> Map b (Map a v) -> Map b (Map a v)
groupKeys fun key value bMap =
let fKey = fun key
entry = Map.lookup fKey bMap
addTo Nothing = Map.insert fKey (Map.singleton key value) bMap
addTo (Just aMap) = Map.insert fKey (Map.insert key value aMap) bMap
in (addTo entry)
propMapKeys :: (Ord a, Ord b) => AtomicChange a v -> MapKeysState a b v -> (MultiChange (AtomicChange b v), MapKeysState a b v)
propMapKeys change state = prop change state where
prop (Insert k v) (f,bMap) = (chg', (f,bMap')) where
bMap' = updateBmap $ Map.lookup (f k) bMap
chg' = chg $ initVal $ Map.lookup (f k) bMap'
updateBmap Nothing = Map.insert (f k) (Map.singleton k v) bMap
updateBmap (Just aMap) = Map.insert (f k) (Map.insert k v aMap) bMap
chg Nothing = insert (f k) v
chg (Just (_,v')) = insert (f k) v'
initVal (Nothing) = Nothing
initVal (Just m) = if (length m > 0)
then Just (Map.findMax m)
else Nothing
--NOTE have to make sure, that the order of evaluation is correct
--this can be achieved, by giving bMap' as an argument to chg'
--loogika:
--1. uuendan bMap
--2. otsin uue key järgi bMapist kõiki vanu vasteid
--3. kui ei ole, siis võib teha chg Delete
--4. kui on, siis tuleb teha suurimale vanale vastele Insert
prop (Delete k) (f,bMap) = (chg', (f,bMap')) where
bMap' = updateBmap $ Map.lookup (f k) bMap
chg' = chg $ initVal $ Map.lookup (f k) bMap'
updateBmap Nothing = bMap
updateBmap (Just aMap) = Map.insert (f k) (Map.delete k aMap) bMap
chg Nothing = delete (f k)
chg (Just (k',v')) = insert (f k) v'
initVal (Nothing) = Nothing
initVal (Just m) = if (length m > 0)
then Just (Map.findMax m)
else Nothing
--loogika:
--1. uuendan bMap
--2. otsin uue key järgi bMapist kõiki vanu vasteid
--3. kui ei ole, siis võib teha chg Delete
--4. kui on, siis tuleb teha suurimale vanale vastele Insert