CPL-0.2.0: src/Simp.hs
{- # OPTIONS -ddump-simpl -ddump-stg # -}
-----------------------------------------------------------------------------
-- |
-- Module : Simp
-- Copyright : (c) Masahiro Sakai 2004-2009
-- License : BSD-style
--
-- Maintainer : masahiro.sakai@gmail.com
-- Stability : provisional
-- Portability : portable
--
-- Simplifier
--
-----------------------------------------------------------------------------
module Simp
( CompiledExp
, compile
, decompile
, simp
, simpWithTrace
) where
import qualified Exp as E
import qualified CDT
import qualified FE
import Exp (Id)
import Type
import Control.Monad
import Control.Monad.RWS
import Data.Array
import qualified Data.Map as Map
----------------------------------------------------------------------------
data CompiledExp
= Identity
| Comp CompiledExp CompiledExp
| LNat !CDT.Nat
| RNat !CDT.Nat
| LFact !CDT.CDT [CompiledExp] !(Array Int CompiledExp)
| RFact !CDT.CDT [CompiledExp]
| Var E.Exp CompiledExp
compile :: (Map.Map E.Id ([E.Id], E.Exp)) -> E.Exp -> CompiledExp
compile env = f
where
f E.Identity = Identity
f (E.Comp a b) = f a `comp` f b
f (E.Funct sym args) = expandFunct sym (map f args)
f (E.Fact sym args) = mkFact sym (map f args)
f (E.Nat sym) = mkNat sym
f src@(E.Var v args) = Var src (compile env' body)
where
(ps, body) = env Map.! v
-- Note that Map.union is left biased
env' = Map.union (Map.fromList [(p, ([], arg)) | (p,arg) <- zip ps args]) env
{-# INLINE mkFact #-}
mkFact :: CDT.CDT -> [CompiledExp] -> CompiledExp
mkFact obj args =
case CDT.objectType obj of
CDT.LeftObject -> lfact
where
lfact = LFact obj args (listArray (0, CDT.nNats obj - 1) l)
l = zipWith f args (CDT.nats obj)
f arg nat =
case CDT.natIsUnconditioned nat of --- optimize
True -> arg
False -> arg `comp` (subst1 lfact (CDT.natDeclDom nat))
CDT.RightObject -> RFact obj args
{-# INLINE mkNat #-}
mkNat :: CDT.Nat -> CompiledExp
mkNat sym =
case CDT.objectType (CDT.natCDT sym) of
CDT.LeftObject -> LNat sym
CDT.RightObject -> RNat sym
decompile :: CompiledExp -> E.Exp
decompile Identity = E.Identity
decompile (Comp e1 e2) = E.Comp (decompile e1) (decompile e2)
decompile (LNat nat) = E.Nat nat
decompile (RNat nat) = E.Nat nat
decompile (LFact sym args _) = E.Fact sym (map decompile args)
decompile (RFact sym args) = E.Fact sym (map decompile args)
decompile (Var src _) = src
----------------------------------------------------------------------------
simp :: Bool -> CompiledExp -> CompiledExp
simp full startExp =
if full
then simpFull startExp
else simpLazy startExp
{-# NOINLINE simpFull #-}
{-# NOINLINE simpLazy #-}
simpFull, simpLazy :: CompiledExp -> CompiledExp
simpFull = simpImpl True
simpLazy = simpImpl False
{-# INLINE simpImpl #-}
simpImpl :: Bool -> CompiledExp -> CompiledExp
simpImpl full startExp = seq full $ simp1 startExp Identity
where
simp1 :: CompiledExp -> CompiledExp -> CompiledExp
simp1 Identity c = c --- IDENT
simp1 (Comp a b) c = simp1 a (simp1 b c) --- COMP
simp1 e@(LNat _) c = e `comp` c -- L-NAT
simp1 (RNat sym) c
| full = simp1_FULL_R_NAT sym c --- FULL-R-NAT
| otherwise = simp1_R_NAT sym c --- R-NAT
simp1 (LFact _ _ table) c = --- L-FACT
case split c of
(LNat sym, c') -> simp1 (table ! (CDT.natIndex sym)) c'
_ -> impossible
simp1 e@(RFact obj args) c
| full && CDT.isUnconditioned obj = simp1_FULL_C_FACT obj args c
| otherwise = e `comp` c -- R-FACT
simp1 (Var _ e) c = simp1 e c
----------------------------------
simp1_R_NAT :: CDT.Nat -> CompiledExp -> CompiledExp
simp1_R_NAT sym c =
case simp2 c sym of
(factR@(RFact _ args), c'') ->
if CDT.natIsUnconditioned sym --- optimize
then simp1 (args !! CDT.natIndex sym) c''
else simp1 (subst1 factR (CDT.natDeclCod sym))
(simp1 (args !! CDT.natIndex sym) c'')
_ -> impossible
simp1_FULL_R_NAT :: CDT.Nat -> CompiledExp -> CompiledExp
simp1_FULL_R_NAT sym factP =
case pickupFactR sym factP of
(factR@(RFact _ args), factP') ->
if CDT.natIsUnconditioned sym
then simp1 (args !! CDT.natIndex sym) factP'
else simp1 (subst1 factR (CDT.natDeclCod sym))
(simp1 (args !! CDT.natIndex sym) factP')
_ -> impossible
simp1_FULL_C_FACT :: CDT.CDT -> [CompiledExp] -> CompiledExp -> CompiledExp
simp1_FULL_C_FACT obj args p = RFact obj (zipWith f args (CDT.nats obj))
{- 並列処理出来るのって、ここのzipWithくらいだろうか -}
where
f e nat =
case CDT.natDeclDom nat of
FE.Var 0 -> simp1 e p
fe -> e `comp` subst1 p fe -- ack(3,3)で16000回くらい
----------------------------------
simp2 :: CompiledExp -> CDT.Nat -> (CompiledExp, CompiledExp)
simp2 c sym = f (CDT.natProjectionSequence sym) c
where
f :: [Int] -> CompiledExp -> (CompiledExp, CompiledExp)
f [] c = split c --- R-NAT-V
f (j:js) c_ = --- R-NAT-F
case split c_ of
(RFact p args, c) ->
case g 0 args (CDT.nats p) of
(factR, args') -> (factR, (RFact p args'))
where
g i (arg:args) (nat:nats)
| i==j =
case f js (simp1 arg c) of
(factR', arg') -> (factR',arg':args')
| otherwise =
let arg' = arg `comp` subst1 c (CDT.natDeclDom nat)
in (factR, arg':args')
where (factR, args') = g (i+1) args nats
g _ [] [] = (undefined, [])
g _ _ _ = impossible
_ -> impossible
{-# INLINE pickupFactR #-}
pickupFactR :: CDT.Nat -> CompiledExp -> (CompiledExp,CompiledExp)
pickupFactR sym = f (CDT.natProjectionSequence sym)
where
f :: [Int] -> CompiledExp -> (CompiledExp, CompiledExp)
f [] e = split e
f (j:js) (RFact p args) =
case processArgs 0 args of
(factR, args') -> (factR, RFact p args')
where
processArgs :: Int -> [CompiledExp] -> (CompiledExp, [CompiledExp])
processArgs i (arg:args)
| i==j =
case f js arg of
(factR, arg') -> (factR, arg':args)
| otherwise =
case processArgs (i+1) args of
(factR, args') -> (factR, arg:args')
processArgs _ _ = impossible
f _ _ = impossible
----------------------------------------------------------------------------
type Trace = [(Int,CompiledExp,CompiledExp)]
type M = RWS Int Trace ()
runM :: M x -> Trace
runM x =
case runRWS x 0 () of
(_,_,c) -> c
trace :: CompiledExp -> CompiledExp -> M ()
trace e c = do
depth <- ask
seq depth $ seq e $ seq c $ tell [(depth,e,c)]
deepen :: M a -> M a
deepen = local (+1)
simpWithTrace :: Bool -> CompiledExp -> Trace
simpWithTrace full startExp = seq full $ runM $ do
c <- simp1 startExp Identity
trace Identity c
return ()
where
simp1 :: CompiledExp -> CompiledExp -> M CompiledExp
simp1 a c = trace a c >> simp1' a c
simp1' Identity c = return c
simp1' (Comp a b) c = do
c' <- deepen (simp1 b c)
simp1 a c'
simp1' e@(LNat _) c = return (e `comp` c) --- L-NAT
simp1' (RNat sym) c
| full = simp1_FULL_R_NAT sym c --- FULL-R-NAT
| otherwise = simp1_R_NAT sym c --- R-NAT
simp1' (LFact _ _ table) c = --- L-FACT
case split c of
(LNat sym, c') -> simp1 (table ! (CDT.natIndex sym)) c'
_ -> impossible
simp1' e@(RFact obj args) c
| full && CDT.isUnconditioned obj = simp1_FULL_C_FACT obj args c --- FULL-C-FACT
| otherwise = return (e `comp` c) -- R-FACT
simp1' (Var _ e) c = simp1 e c
----------------------------------
simp1_R_NAT :: CDT.Nat -> CompiledExp -> M CompiledExp
simp1_R_NAT sym c = do
tmp <- simp2 c sym
case tmp of
(factR@(RFact _ args), c'') ->
if CDT.natIsUnconditioned sym
then simp1 (args !! CDT.natIndex sym) c''
else simp1 (subst1 factR (CDT.natDeclCod sym) `comp` (args !! CDT.natIndex sym)) c''
_ -> impossible
simp1_FULL_R_NAT :: CDT.Nat -> CompiledExp -> M CompiledExp
simp1_FULL_R_NAT sym factP =
case pickupFactR sym factP of
(factR@(RFact _ args), factP') ->
if CDT.natIsUnconditioned sym
then simp1 (args !! CDT.natIndex sym) factP'
else simp1 (subst1 factR (CDT.natDeclCod sym) `comp` (args !! CDT.natIndex sym)) factP'
_ -> impossible
simp1_FULL_C_FACT :: CDT.CDT -> [CompiledExp] -> CompiledExp -> M CompiledExp
simp1_FULL_C_FACT obj args p = do
args' <- zipWithM f args (CDT.nats obj)
return (RFact obj args')
where
f e nat =
case CDT.natDeclDom nat of
FE.Var 0 -> simp1 e p
fe -> return (e `comp` subst1 p fe) -- ack(3,3)で16000回くらい
----------------------------------
simp2 :: CompiledExp -> CDT.Nat -> M (CompiledExp, CompiledExp)
simp2 c sym = f (CDT.natProjectionSequence sym) c
where
f :: [Int] -> CompiledExp -> M (CompiledExp, CompiledExp)
f [] c = return (split c) --- R-NAT-V
f (j:js) c_ = --- R-NAT-F
case split c_ of
(RFact p args, c) -> do
(factR, args') <- g 0 args (CDT.nats p)
return (factR, (RFact p args'))
where
g _ [] [] = return (undefined, [])
g i (arg:args) (nat:nats)
| i==j = do
(_, args') <- g (i+1) args nats
tmp <- simp1 arg c
(factR', arg') <- f js tmp
return (factR',arg':args')
| otherwise = do
(factR, args') <- g (i+1) args nats
let arg' = arg `comp` subst1 c (CDT.natDeclDom nat)
return (factR, arg':args')
g _ _ _ = impossible
_ -> impossible
----------------------------------------------------------------------------
{-# INLINE comp #-}
comp :: CompiledExp -> CompiledExp -> CompiledExp
comp a Identity = a
comp Identity b = b
comp a b = Comp a b
split :: CompiledExp -> (CompiledExp, CompiledExp)
split (Comp a b) =
case split a of
(c, d) -> (c, d `comp` b)
split a = (a,Identity)
{-
split :: CompiledExp -> (CompiledExp, CompiledExp)
split (Comp a b) = go a b
where
go (Comp a b) r = go a (Comp b r)
go e r = (e, r)
split e = (e, Identity)
-}
subst1 :: CompiledExp -> FE.FE -> CompiledExp
subst1 x e = FE.fold f expandFunct e
where
f 0 = x
f _ = Identity
expandFunct :: CDT.CDT -> [CompiledExp] -> CompiledExp
expandFunct _ [] = Identity
expandFunct obj args = mkFact obj (map g (CDT.nats obj))
where
g nat = FE.fold h expandFunct cod `comp` (mkNat nat `comp` FE.fold h expandFunct dom)
where
h 0 = Identity
h i = args !! (i-1)
dom:->cod = CDT.natDeclType nat
impossible :: a
impossible = error "impossible happens"