{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
module What4.Expr.Simplify
( simplify
, count_subterms
) where
import Control.Lens ((^.))
import Control.Monad (void, when)
import Control.Monad.ST
import Control.Monad.State (MonadState(..), State, execState)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import Data.Maybe
import qualified Data.Parameterized.HashTable as PH
import Data.Parameterized.Nonce
import Data.Parameterized.TraversableFC
import Data.Word
import What4.Interface
import qualified What4.SemiRing as SR
import What4.Expr.Builder
import qualified What4.Expr.WeightedSum as WSum
data NormCache t st fs
= NormCache { forall t (st :: Type -> Type) fs.
NormCache t st fs -> ExprBuilder t st fs
ncBuilder :: !(ExprBuilder t st fs)
, forall t (st :: Type -> Type) fs.
NormCache t st fs -> HashTable RealWorld (Expr t) (Expr t)
ncTable :: !(PH.HashTable RealWorld (Expr t) (Expr t))
}
norm :: NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm :: forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm NormCache t st fs
c Expr t tp
e = do
mr <- ST RealWorld (Maybe (Expr t tp)) -> IO (Maybe (Expr t tp))
forall a. ST RealWorld a -> IO a
stToIO (ST RealWorld (Maybe (Expr t tp)) -> IO (Maybe (Expr t tp)))
-> ST RealWorld (Maybe (Expr t tp)) -> IO (Maybe (Expr t tp))
forall a b. (a -> b) -> a -> b
$ HashTable RealWorld (Expr t) (Expr t)
-> Expr t tp -> ST RealWorld (Maybe (Expr t tp))
forall {k} (key :: k -> Type) s (val :: k -> Type) (tp :: k).
(HashableF key, TestEquality key) =>
HashTable s key val -> key tp -> ST s (Maybe (val tp))
PH.lookup (NormCache t st fs -> HashTable RealWorld (Expr t) (Expr t)
forall t (st :: Type -> Type) fs.
NormCache t st fs -> HashTable RealWorld (Expr t) (Expr t)
ncTable NormCache t st fs
c) Expr t tp
e
case mr of
Just Expr t tp
r -> Expr t tp -> IO (Expr t tp)
forall a. a -> IO a
forall (m :: Type -> Type) a. Monad m => a -> m a
return Expr t tp
r
Maybe (Expr t tp)
Nothing -> do
r <- NormCache t st fs -> Expr t tp -> IO (Expr t tp)
forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm' NormCache t st fs
c Expr t tp
e
stToIO $ PH.insert (ncTable c) e r
return r
bvIteDist :: (BoolExpr t -> r -> r -> IO r)
-> Expr t i
-> (Expr t i -> IO r)
-> IO r
bvIteDist :: forall t r (i :: BaseType).
(BoolExpr t -> r -> r -> IO r)
-> Expr t i -> (Expr t i -> IO r) -> IO r
bvIteDist BoolExpr t -> r -> r -> IO r
muxFn (Expr t i -> Maybe (App (Expr t) i)
forall t (tp :: BaseType). Expr t tp -> Maybe (App (Expr t) tp)
asApp -> Just (BaseIte BaseTypeRepr i
_ Integer
_ BoolExpr t
c Expr t i
t Expr t i
f)) Expr t i -> IO r
atomFn = do
t' <- (BoolExpr t -> r -> r -> IO r)
-> Expr t i -> (Expr t i -> IO r) -> IO r
forall t r (i :: BaseType).
(BoolExpr t -> r -> r -> IO r)
-> Expr t i -> (Expr t i -> IO r) -> IO r
bvIteDist BoolExpr t -> r -> r -> IO r
muxFn Expr t i
t Expr t i -> IO r
atomFn
f' <- bvIteDist muxFn f atomFn
muxFn c t' f'
bvIteDist BoolExpr t -> r -> r -> IO r
_ Expr t i
u Expr t i -> IO r
atomFn = Expr t i -> IO r
atomFn Expr t i
u
newtype Or x = Or {forall {k} (x :: k). Or x -> Bool
unOr :: Bool}
instance Functor Or where
fmap :: forall a b. (a -> b) -> Or a -> Or b
fmap a -> b
_f (Or Bool
b) = (Bool -> Or b
forall {k} (x :: k). Bool -> Or x
Or Bool
b)
instance Applicative Or where
pure :: forall a. a -> Or a
pure a
_ = Bool -> Or a
forall {k} (x :: k). Bool -> Or x
Or Bool
False
(Or Bool
a) <*> :: forall a b. Or (a -> b) -> Or a -> Or b
<*> (Or Bool
b) = Bool -> Or b
forall {k} (x :: k). Bool -> Or x
Or (Bool
a Bool -> Bool -> Bool
|| Bool
b)
norm' :: forall t st fs tp . NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm' :: forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm' NormCache t st fs
nc (AppExpr AppExpr t tp
a0) = do
let sb :: ExprBuilder t st fs
sb = NormCache t st fs -> ExprBuilder t st fs
forall t (st :: Type -> Type) fs.
NormCache t st fs -> ExprBuilder t st fs
ncBuilder NormCache t st fs
nc
case AppExpr t tp -> App (Expr t) tp
forall t (tp :: BaseType). AppExpr t tp -> App (Expr t) tp
appExprApp AppExpr t tp
a0 of
SemiRingSum WeightedSum (Expr t) sr
s
| let sr :: SemiRingRepr sr
sr = WeightedSum (Expr t) sr -> SemiRingRepr sr
forall (f :: BaseType -> Type) (sr :: SemiRing).
WeightedSum f sr -> SemiRingRepr sr
WSum.sumRepr WeightedSum (Expr t) sr
s
, SR.SemiRingBVRepr BVFlavorRepr fv
SR.BVArithRepr NatRepr w
w <- SemiRingRepr sr
sr
, Or (WeightedSum (Expr t) sr) -> Bool
forall {k} (x :: k). Or x -> Bool
unOr (forall (k :: BaseType -> Type) (j :: BaseType -> Type)
(m :: Type -> Type) (sr :: SemiRing).
(Applicative m, Tm k) =>
(j (SemiRingBase sr) -> m (k (SemiRingBase sr)))
-> WeightedSum j sr -> m (WeightedSum k sr)
WSum.traverseVars @(Expr t) (\Expr t (SemiRingBase sr)
x -> Bool -> Or (Expr t (BaseBVType w))
forall {k} (x :: k). Bool -> Or x
Or (Expr t (BaseBVType w) -> Integer
forall t (tp :: BaseType). Expr t tp -> Integer
iteSize Expr t (BaseBVType w)
Expr t (SemiRingBase sr)
x Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
1)) WeightedSum (Expr t) sr
s)
-> do let tms :: [(BV w, Expr t (BaseBVType w))]
tms = ([(BV w, Expr t (BaseBVType w))]
-> [(BV w, Expr t (BaseBVType w))]
-> [(BV w, Expr t (BaseBVType w))])
-> (Coefficient sr
-> Expr t (SemiRingBase sr) -> [(BV w, Expr t (BaseBVType w))])
-> (Coefficient sr -> [(BV w, Expr t (BaseBVType w))])
-> WeightedSum (Expr t) sr
-> [(BV w, Expr t (BaseBVType w))]
forall r (sr :: SemiRing) (f :: BaseType -> Type).
(r -> r -> r)
-> (Coefficient sr -> f (SemiRingBase sr) -> r)
-> (Coefficient sr -> r)
-> WeightedSum f sr
-> r
WSum.eval [(BV w, Expr t (BaseBVType w))]
-> [(BV w, Expr t (BaseBVType w))]
-> [(BV w, Expr t (BaseBVType w))]
forall a. [a] -> [a] -> [a]
(++) (\Coefficient sr
c Expr t (SemiRingBase sr)
x -> [(BV w
Coefficient sr
c,Expr t (BaseBVType w)
Expr t (SemiRingBase sr)
x)]) ([(BV w, Expr t (BaseBVType w))]
-> BV w -> [(BV w, Expr t (BaseBVType w))]
forall a b. a -> b -> a
const []) WeightedSum (Expr t) sr
s
let f :: [(BV w, Expr t (BaseBVType w))]
-> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
f [] Expr t tp -> IO (Expr t tp)
k = ExprBuilder t st fs
-> NatRepr w -> BV w -> IO (SymBV (ExprBuilder t st fs) w)
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> NatRepr w -> BV w -> IO (SymBV (ExprBuilder t st fs) w)
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> NatRepr w -> BV w -> IO (SymBV sym w)
bvLit ExprBuilder t st fs
sb NatRepr w
w (WeightedSum (Expr t) sr
sWeightedSum (Expr t) sr
-> Getting (BV w) (WeightedSum (Expr t) sr) (BV w) -> BV w
forall s a. s -> Getting a s a -> a
^.Getting (BV w) (WeightedSum (Expr t) sr) (BV w)
(Coefficient sr -> Const (BV w) (Coefficient sr))
-> WeightedSum (Expr t) sr
-> Const (BV w) (WeightedSum (Expr t) sr)
forall (f1 :: BaseType -> Type) (sr :: SemiRing)
(f2 :: Type -> Type).
Functor f2 =>
(Coefficient sr -> f2 (Coefficient sr))
-> WeightedSum f1 sr -> f2 (WeightedSum f1 sr)
WSum.sumOffset) IO (Expr t tp) -> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= Expr t tp -> IO (Expr t tp)
k
f ((BV w
c,Expr t (BaseBVType w)
x):[(BV w, Expr t (BaseBVType w))]
xs) Expr t tp -> IO (Expr t tp)
k =
(Expr t BaseBoolType -> Expr t tp -> Expr t tp -> IO (Expr t tp))
-> Expr t (BaseBVType w)
-> (Expr t (BaseBVType w) -> IO (Expr t tp))
-> IO (Expr t tp)
forall t r (i :: BaseType).
(BoolExpr t -> r -> r -> IO r)
-> Expr t i -> (Expr t i -> IO r) -> IO r
bvIteDist (ExprBuilder t st fs
-> Pred (ExprBuilder t st fs)
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (SymBV (ExprBuilder t st fs) w)
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> Pred (ExprBuilder t st fs)
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (SymBV (ExprBuilder t st fs) w)
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
bvIte ExprBuilder t st fs
sb) Expr t (BaseBVType w)
x ((Expr t (BaseBVType w) -> IO (Expr t tp)) -> IO (Expr t tp))
-> (Expr t (BaseBVType w) -> IO (Expr t tp)) -> IO (Expr t tp)
forall a b. (a -> b) -> a -> b
$ \Expr t (BaseBVType w)
x' ->
ExprBuilder t st fs
-> SemiRingRepr sr
-> Coefficient sr
-> Expr t (SemiRingBase sr)
-> IO (Expr t (SemiRingBase sr))
forall t (st :: Type -> Type) fs (sr :: SemiRing).
ExprBuilder t st fs
-> SemiRingRepr sr
-> Coefficient sr
-> Expr t (SemiRingBase sr)
-> IO (Expr t (SemiRingBase sr))
scalarMul ExprBuilder t st fs
sb SemiRingRepr sr
sr BV w
Coefficient sr
c Expr t (BaseBVType w)
Expr t (SemiRingBase sr)
x' IO (Expr t (BaseBVType w))
-> (Expr t (BaseBVType w) -> IO (Expr t tp)) -> IO (Expr t tp)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Expr t (BaseBVType w)
cx' ->
[(BV w, Expr t (BaseBVType w))]
-> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
f [(BV w, Expr t (BaseBVType w))]
xs ((Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp))
-> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
forall a b. (a -> b) -> a -> b
$ \Expr t tp
xs' ->
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (SymBV (ExprBuilder t st fs) w)
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (SymBV (ExprBuilder t st fs) w)
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
bvAdd ExprBuilder t st fs
sb SymBV (ExprBuilder t st fs) w
Expr t (BaseBVType w)
cx' SymBV (ExprBuilder t st fs) w
Expr t tp
xs' IO (Expr t tp) -> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
>>= Expr t tp -> IO (Expr t tp)
k
[(BV w, Expr t (BaseBVType w))]
-> (Expr t tp -> IO (Expr t tp)) -> IO (Expr t tp)
f [(BV w, Expr t (BaseBVType w))]
tms (NormCache t st fs -> Expr t tp -> IO (Expr t tp)
forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm NormCache t st fs
nc)
BaseEq (BaseBVRepr NatRepr w
_w) (Expr t tp1 -> Maybe (App (Expr t) tp1)
forall t (tp :: BaseType). Expr t tp -> Maybe (App (Expr t) tp)
asApp -> Just (BaseIte BaseTypeRepr tp1
_ Integer
_ Expr t BaseBoolType
x_c Expr t tp1
x_t Expr t tp1
x_f)) Expr t tp1
y -> do
z_t <- ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
bvEq ExprBuilder t st fs
sb SymBV (ExprBuilder t st fs) w
Expr t tp1
x_t SymBV (ExprBuilder t st fs) w
Expr t tp1
y
z_f <- bvEq sb x_f y
norm nc =<< itePred sb x_c z_t z_f
BaseEq (BaseBVRepr NatRepr w
_w) Expr t tp1
x (Expr t tp1 -> Maybe (App (Expr t) tp1)
forall t (tp :: BaseType). Expr t tp -> Maybe (App (Expr t) tp)
asApp -> Just (BaseIte BaseTypeRepr tp1
_ Integer
_ Expr t BaseBoolType
y_c Expr t tp1
y_t Expr t tp1
y_f)) -> do
z_t <- ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
bvEq ExprBuilder t st fs
sb SymBV (ExprBuilder t st fs) w
Expr t tp1
x SymBV (ExprBuilder t st fs) w
Expr t tp1
y_t
z_f <- bvEq sb x y_f
norm nc =<< itePred sb y_c z_t z_f
BVSlt (Expr t (BaseBVType w) -> Maybe (App (Expr t) (BaseBVType w))
forall t (tp :: BaseType). Expr t tp -> Maybe (App (Expr t) tp)
asApp -> Just (BaseIte BaseTypeRepr (BaseBVType w)
_ Integer
_ Expr t BaseBoolType
x_c Expr t (BaseBVType w)
x_t Expr t (BaseBVType w)
x_f)) Expr t (BaseBVType w)
y -> do
z_t <- ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
bvSlt ExprBuilder t st fs
sb SymBV (ExprBuilder t st fs) w
Expr t (BaseBVType w)
x_t SymBV (ExprBuilder t st fs) w
Expr t (BaseBVType w)
y
z_f <- bvSlt sb x_f y
norm nc =<< itePred sb x_c z_t z_f
BVSlt Expr t (BaseBVType w)
x (Expr t (BaseBVType w) -> Maybe (App (Expr t) (BaseBVType w))
forall t (tp :: BaseType). Expr t tp -> Maybe (App (Expr t) tp)
asApp -> Just (BaseIte BaseTypeRepr (BaseBVType w)
_ Integer
_ Expr t BaseBoolType
y_c Expr t (BaseBVType w)
y_t Expr t (BaseBVType w)
y_f)) -> do
z_t <- ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall (w :: Natural).
(1 <= w) =>
ExprBuilder t st fs
-> SymBV (ExprBuilder t st fs) w
-> SymBV (ExprBuilder t st fs) w
-> IO (Pred (ExprBuilder t st fs))
forall sym (w :: Natural).
(IsExprBuilder sym, 1 <= w) =>
sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
bvSlt ExprBuilder t st fs
sb SymBV (ExprBuilder t st fs) w
Expr t (BaseBVType w)
x SymBV (ExprBuilder t st fs) w
Expr t (BaseBVType w)
y_t
z_f <- bvSlt sb x y_f
norm nc =<< itePred sb y_c z_t z_f
App (Expr t) tp
app -> do
app' <- (forall (tp :: BaseType). Expr t tp -> IO (Expr t tp))
-> App (Expr t) tp -> IO (App (Expr t) tp)
forall (m :: Type -> Type) (f :: BaseType -> Type)
(e :: BaseType -> Type) (utp :: BaseType).
(Applicative m, OrdF f, Eq (f BaseBoolType), HashableF f,
HasAbsValue f) =>
(forall (tp :: BaseType). e tp -> m (f tp))
-> App e utp -> m (App f utp)
traverseApp (NormCache t st fs -> Expr t tp -> IO (Expr t tp)
forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm NormCache t st fs
nc) App (Expr t) tp
app
if app' == app then
return (AppExpr a0)
else
norm nc =<< sbMakeExpr sb app'
norm' NormCache t st fs
nc (NonceAppExpr NonceAppExpr t tp
p0) = do
let predApp :: NonceApp t (Expr t) tp
predApp = NonceAppExpr t tp -> NonceApp t (Expr t) tp
forall t (tp :: BaseType).
NonceAppExpr t tp -> NonceApp t (Expr t) tp
nonceExprApp NonceAppExpr t tp
p0
p <- (forall (tp :: BaseType). Expr t tp -> IO (Expr t tp))
-> forall (x :: BaseType).
NonceApp t (Expr t) x -> IO (NonceApp t (Expr t) x)
forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
(g :: k -> Type) (m :: Type -> Type).
(TraversableFC t, Applicative m) =>
(forall (x :: k). f x -> m (g x))
-> forall (x :: l). t f x -> m (t g x)
forall (f :: BaseType -> Type) (g :: BaseType -> Type)
(m :: Type -> Type).
Applicative m =>
(forall (x :: BaseType). f x -> m (g x))
-> forall (x :: BaseType). NonceApp t f x -> m (NonceApp t g x)
traverseFC (NormCache t st fs -> Expr t x -> IO (Expr t x)
forall t (st :: Type -> Type) fs (tp :: BaseType).
NormCache t st fs -> Expr t tp -> IO (Expr t tp)
norm NormCache t st fs
nc) NonceApp t (Expr t) tp
predApp
if p == predApp then
return $! NonceAppExpr p0
else
norm nc =<< sbNonceExpr (ncBuilder nc) p
norm' NormCache t st fs
_ Expr t tp
e = Expr t tp -> IO (Expr t tp)
forall a. a -> IO a
forall (m :: Type -> Type) a. Monad m => a -> m a
return Expr t tp
e
simplify :: ExprBuilder t st fs -> BoolExpr t -> IO (BoolExpr t)
simplify :: forall t (st :: Type -> Type) fs.
ExprBuilder t st fs -> BoolExpr t -> IO (BoolExpr t)
simplify ExprBuilder t st fs
sb BoolExpr t
p = do
tbl <- ST RealWorld (HashTable RealWorld (Expr t) (Expr t))
-> IO (HashTable RealWorld (Expr t) (Expr t))
forall a. ST RealWorld a -> IO a
stToIO (ST RealWorld (HashTable RealWorld (Expr t) (Expr t))
-> IO (HashTable RealWorld (Expr t) (Expr t)))
-> ST RealWorld (HashTable RealWorld (Expr t) (Expr t))
-> IO (HashTable RealWorld (Expr t) (Expr t))
forall a b. (a -> b) -> a -> b
$ ST RealWorld (HashTable RealWorld (Expr t) (Expr t))
forall {k} s (key :: k -> Type) (val :: k -> Type).
ST s (HashTable s key val)
PH.new
let nc = NormCache { ncBuilder :: ExprBuilder t st fs
ncBuilder = ExprBuilder t st fs
sb
, ncTable :: HashTable RealWorld (Expr t) (Expr t)
ncTable = HashTable RealWorld (Expr t) (Expr t)
tbl
}
norm nc p
type Counter = State (Map Word64 Int)
recordExpr :: Nonce t (tp::k) -> Counter Bool
recordExpr :: forall t k (tp :: k). Nonce t tp -> Counter Bool
recordExpr Nonce t tp
n = do
m <- StateT (Map Word64 Int) Identity (Map Word64 Int)
forall s (m :: Type -> Type). MonadState s m => m s
get
let (mr, m') = Map.insertLookupWithKey (\Word64
_ -> Int -> Int -> Int
forall a. Num a => a -> a -> a
(+)) (indexValue n) 1 m
put $ m'
return $! isNothing mr
count_subterms' :: Expr t tp -> Counter ()
count_subterms' :: forall t (tp :: BaseType).
Expr t tp -> StateT (Map Word64 Int) Identity ()
count_subterms' Expr t tp
e0 =
case Expr t tp
e0 of
BoolExpr{} -> () -> StateT (Map Word64 Int) Identity ()
forall a. a -> StateT (Map Word64 Int) Identity a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
SemiRingLiteral{} -> () -> StateT (Map Word64 Int) Identity ()
forall a. a -> StateT (Map Word64 Int) Identity a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
StringExpr{} -> () -> StateT (Map Word64 Int) Identity ()
forall a. a -> StateT (Map Word64 Int) Identity a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
FloatExpr{} -> () -> StateT (Map Word64 Int) Identity ()
forall a. a -> StateT (Map Word64 Int) Identity a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
AppExpr AppExpr t tp
ae -> do
is_new <- Nonce t tp -> Counter Bool
forall t k (tp :: k). Nonce t tp -> Counter Bool
recordExpr (AppExpr t tp -> Nonce t tp
forall t (tp :: BaseType). AppExpr t tp -> Nonce t tp
appExprId AppExpr t tp
ae)
when is_new $ do
traverseFC_ count_subterms' (appExprApp ae)
NonceAppExpr NonceAppExpr t tp
nae -> do
is_new <- Nonce t tp -> Counter Bool
forall t k (tp :: k). Nonce t tp -> Counter Bool
recordExpr (NonceAppExpr t tp -> Nonce t tp
forall t (tp :: BaseType). NonceAppExpr t tp -> Nonce t tp
nonceExprId NonceAppExpr t tp
nae)
when is_new $ do
traverseFC_ count_subterms' (nonceExprApp nae)
BoundVarExpr ExprBoundVar t tp
v -> do
Counter Bool -> StateT (Map Word64 Int) Identity ()
forall (f :: Type -> Type) a. Functor f => f a -> f ()
void (Counter Bool -> StateT (Map Word64 Int) Identity ())
-> Counter Bool -> StateT (Map Word64 Int) Identity ()
forall a b. (a -> b) -> a -> b
$ Nonce t tp -> Counter Bool
forall t k (tp :: k). Nonce t tp -> Counter Bool
recordExpr (ExprBoundVar t tp -> Nonce t tp
forall t (tp :: BaseType). ExprBoundVar t tp -> Nonce t tp
bvarId ExprBoundVar t tp
v)
count_subterms :: Expr t tp -> Map Word64 Int
count_subterms :: forall t (tp :: BaseType). Expr t tp -> Map Word64 Int
count_subterms Expr t tp
e = StateT (Map Word64 Int) Identity ()
-> Map Word64 Int -> Map Word64 Int
forall s a. State s a -> s -> s
execState (Expr t tp -> StateT (Map Word64 Int) Identity ()
forall t (tp :: BaseType).
Expr t tp -> StateT (Map Word64 Int) Identity ()
count_subterms' Expr t tp
e) Map Word64 Int
forall k a. Map k a
Map.empty