circus-0.1.0.0: src/Circus/Simplify.hs
module Circus.Simplify (simplify) where
import Circus.Types
import Control.Arrow
import Data.List
import qualified Data.Map as M
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as S
------------------------------------------------------------------------------
-- | Gather sets of input and output ports for the given cell.
cellPorts :: Cell -> (Set PortName, Set PortName)
cellPorts c =
let ports = M.assocs $ cellPortDirections c
(ip, op) = fmap fst *** fmap fst $ partition ((== Input) . snd) ports
in (S.fromList ip, S.fromList op)
------------------------------------------------------------------------------
-- | Gather input and output bits for the given cell.
ioBits :: Module -> (Set Bit, Set Bit)
ioBits m = flip foldMap (moduleCells m) $ \c ->
let (ip, op) = cellPorts c
ib = foldMap (fromMaybe [] . flip M.lookup (cellConnections c)) $ ip
ob = foldMap (fromMaybe [] . flip M.lookup (cellConnections c)) $ op
mod_ports = fmap (portDirection &&& portBits) $ M.elems $ modulePorts m
(iports, oports) = (snd =<<) *** (snd =<<) $ partition ((== Input) . fst) mod_ports
in (S.fromList $ ib <> oports, S.fromList $ ob <> iports)
------------------------------------------------------------------------------
-- | Delete any cells which output only bits in the @to_kill@ set.
pruneCellsOutput :: Set Bit -> Module -> Module
pruneCellsOutput to_kill m = m
{ moduleCells = M.filter (not . should_kill) $ moduleCells m
}
where
should_kill :: Cell -> Bool
should_kill c =
let (_, op) = cellPorts c
in case S.toList op of
[pn] ->
let bits = fromMaybe [] $ M.lookup pn $ cellConnections c
in all (flip S.member to_kill) bits
_ -> False
------------------------------------------------------------------------------
-- | Recursively delete cells that output only bits which are unused in the
-- circuit.
simplify :: Module -> Module
simplify m =
let (ib, ob) = ioBits m
to_kill = ob S.\\ ib
m' = pruneCellsOutput to_kill m
in case m == m' of
True -> m
False -> simplify m'