mirror of
https://git.cs.ou.nl/joshua.moerman/mealy-decompose.git
synced 2025-04-30 02:07:44 +02:00
60 lines
No EOL
2 KiB
Haskell
60 lines
No EOL
2 KiB
Haskell
module Merger where
|
|
|
|
import Partition
|
|
|
|
import Control.Monad (replicateM)
|
|
import Control.Monad.IO.Class (liftIO)
|
|
import Control.Monad.Trans.State.Strict
|
|
import Data.Bifunctor (first)
|
|
import Data.List (minimumBy)
|
|
import Data.Map.Strict qualified as Map
|
|
import Data.Ord (comparing)
|
|
import Data.Set qualified as Set
|
|
|
|
data MergerStats = MergerStats
|
|
{ numberOfComponents :: Int
|
|
, maximalComponent :: Int
|
|
, totalSize :: Int
|
|
}
|
|
deriving (Eq, Ord, Read, Show)
|
|
|
|
data MergerAction = Stop | Continue
|
|
deriving (Eq, Ord, Read, Show)
|
|
|
|
type MergerStrategy = MergerStats -> MergerAction
|
|
|
|
heuristicMerger :: Ord o => [(o, Partition)] -> MergerStrategy -> IO [([o], Partition)]
|
|
heuristicMerger components strategy = do
|
|
projmap <- evalStateT (loop 2) (Map.fromList (fmap (first pure) components))
|
|
return $ Map.assocs projmap
|
|
where
|
|
score ps p3 = numBlocks p3 - sum (fmap numBlocks ps)
|
|
combine ops = let os = fmap fst ops
|
|
ps = fmap snd ops
|
|
p3 = foldr1 commonRefinement ps
|
|
in ((os, p3), score ps p3)
|
|
isSortedOn f ls = and $ zipWith (\a b -> f a < f b) ls (drop 1 ls)
|
|
allCombs n projs = fmap combine . filter (isSortedOn fst) $ replicateM n projs
|
|
minComb n projs = minimumBy (comparing snd) (allCombs n projs)
|
|
safeStrategy ms@MergerStats{..}
|
|
| numberOfComponents <= 1 = Stop
|
|
| otherwise = strategy ms
|
|
|
|
loop n = do
|
|
projmap <- get
|
|
let numberOfComponents = Map.size projmap
|
|
componentSizes = fmap numBlocks . Map.elems $ projmap
|
|
maximalComponent = maximum componentSizes
|
|
totalSize = sum componentSizes
|
|
ms = MergerStats{..}
|
|
liftIO . print $ ms
|
|
case safeStrategy ms of
|
|
Stop -> return projmap
|
|
Continue -> do
|
|
let ((os, p3), _) = minComb n (Map.assocs projmap)
|
|
o3 = mconcat os
|
|
newProjmap = Map.insert o3 p3 . Map.withoutKeys projmap $ Set.fromList os
|
|
put newProjmap
|
|
if Map.size newProjmap < n
|
|
then loop (Map.size newProjmap)
|
|
else loop n |