module Conjure.Defn.Redundancy
( isRedundantDefn
, isRedundantBySubsumption
, isRedundantByRepetition
, isRedundantByIntroduction
, isRedundantModuloRewriting
, hasRedundantRecursion
, subsumedWith
, simplifyDefn
, introduceVariableAt
)
where
import Conjure.Defn
isRedundantDefn :: Defn -> Bool
isRedundantDefn :: Defn -> Bool
isRedundantDefn Defn
d = Defn -> Bool
isRedundantBySubsumption Defn
d
Bool -> Bool -> Bool
|| Defn -> Bool
isRedundantByRepetition Defn
d
Bool -> Bool -> Bool
|| Defn -> Bool
isRedundantByRootRecursions Defn
d
isRedundantByRepetition :: Defn -> Bool
isRedundantByRepetition :: Defn -> Bool
isRedundantByRepetition Defn
d = ((Expr -> Expr) -> Bool) -> [Expr -> Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Expr -> Expr) -> Bool
anyAllEqual [Expr -> Expr]
shovels
where
nArgs :: Int
nArgs = [Expr] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Expr] -> Int) -> (Bndn -> [Expr]) -> Bndn -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Expr] -> [Expr]
forall a. HasCallStack => [a] -> [a]
tail ([Expr] -> [Expr]) -> (Bndn -> [Expr]) -> Bndn -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> [Expr]
unfoldApp (Expr -> [Expr]) -> (Bndn -> Expr) -> Bndn -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bndn -> Expr
forall a b. (a, b) -> a
fst (Bndn -> Int) -> Bndn -> Int
forall a b. (a -> b) -> a -> b
$ Defn -> Bndn
forall a. HasCallStack => [a] -> a
head Defn
d
shovels :: [Expr -> Expr]
shovels :: [Expr -> Expr]
shovels = [Int -> Expr -> Expr
digApp Int
n | Int
n <- [Int
1..Int
nArgs]]
anyAllEqual :: (Expr -> Expr) -> Bool
anyAllEqual :: (Expr -> Expr) -> Bool
anyAllEqual Expr -> Expr
shovel = (Defn -> Bool) -> [Defn] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Defn
bs -> Defn -> Bool
forall a. Eq a => [a] -> Bool
allEqual2 Defn
bs Bool -> Bool -> Bool
&& Defn -> Bool
isDefined Defn
bs)
([Defn] -> Bool) -> (Defn -> [Defn]) -> Defn -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Expr) -> Defn -> [Defn]
forall b a. Eq b => (a -> b) -> [a] -> [[a]]
classifyOn Bndn -> Expr
forall a b. (a, b) -> a
fst
(Defn -> [Defn]) -> (Defn -> Defn) -> Defn -> [Defn]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Bndn) -> Defn -> Defn
forall a b. (a -> b) -> [a] -> [b]
map (Bndn -> Bndn
canonicalizeBndn (Bndn -> Bndn) -> (Bndn -> Bndn) -> Bndn -> Bndn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Expr -> Expr) -> Bndn -> Bndn
forall a a' b. (a -> a') -> (a, b) -> (a', b)
first Expr -> Expr
shovel)
(Defn -> Bool) -> Defn -> Bool
forall a b. (a -> b) -> a -> b
$ Defn
d
isRedundantByIntroduction :: Defn -> Bool
isRedundantByIntroduction :: Defn -> Bool
isRedundantByIntroduction Defn
d = (Int -> Bool) -> [Int] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Int -> Bool
anyAllEqual [Int
1..Int
nArgs]
where
nArgs :: Int
nArgs = [Expr] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length ([Expr] -> Int) -> (Bndn -> [Expr]) -> Bndn -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Expr] -> [Expr]
forall a. HasCallStack => [a] -> [a]
tail ([Expr] -> [Expr]) -> (Bndn -> [Expr]) -> Bndn -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> [Expr]
unfoldApp (Expr -> [Expr]) -> (Bndn -> Expr) -> Bndn -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bndn -> Expr
forall a b. (a, b) -> a
fst (Bndn -> Int) -> Bndn -> Int
forall a b. (a -> b) -> a -> b
$ Defn -> Bndn
forall a. HasCallStack => [a] -> a
head Defn
d
anyAllEqual :: Int -> Bool
anyAllEqual :: Int -> Bool
anyAllEqual Int
i = (Defn -> Bool) -> [Defn] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\Defn
bs -> Defn -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length Defn
bs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2 Bool -> Bool -> Bool
&& Defn -> Bool
isDefined Defn
bs Bool -> Bool -> Bool
&& Int -> Defn -> Bool
noConflicts Int
i Defn
bs)
([Defn] -> Bool) -> (Defn -> [Defn]) -> Defn -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Expr) -> Defn -> [Defn]
forall b a. Eq b => (a -> b) -> [a] -> [[a]]
classifyOn (Int -> Expr -> Expr
digApp Int
i (Expr -> Expr) -> (Bndn -> Expr) -> Bndn -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bndn -> Expr
forall a b. (a, b) -> a
fst)
(Defn -> [Defn]) -> (Defn -> Defn) -> Defn -> [Defn]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Bndn) -> Defn -> Defn
forall a b. (a -> b) -> [a] -> [b]
map (Int -> Bndn -> Bndn
canonicalizeBndnLast Int
i)
(Defn -> Bool) -> Defn -> Bool
forall a b. (a -> b) -> a -> b
$ Defn
d
noConflicts :: Int -> [Bndn] -> Bool
noConflicts :: Int -> Defn -> Bool
noConflicts Int
i Defn
bs = case [Expr] -> [[Expr]]
listConflicts ((Bndn -> Expr) -> Defn -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Bndn -> Expr
forall a b. (a, b) -> b
snd Defn
bs) of
[] -> Bool
True
[[Expr]
es] -> [Expr]
es [Expr] -> [Expr] -> Bool
forall a. Eq a => a -> a -> Bool
== [Expr
efxs Expr -> Int -> Expr
$!! Int
i | (Expr
efxs,Expr
_) <- Defn
bs]
[[Expr]]
_ -> Bool
False
hasRedundantRecursion :: Defn -> Bool
hasRedundantRecursion :: Defn -> Bool
hasRedundantRecursion Defn
d = Bool -> Bool
not (Defn -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null Defn
rs) Bool -> Bool -> Bool
&& (Bndn -> Bool) -> Defn -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Bndn -> Bool
forall {b}. (Expr, b) -> Bool
matchesRHS Defn
bs
where
(Defn
bs,Defn
rs) = (Bndn -> Bool) -> Defn -> (Defn, Defn)
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Bndn -> Bool
isBaseCase Defn
d
matchesRHS :: (Expr, b) -> Bool
matchesRHS (Expr
lhs,b
_) = (Bndn -> Bool) -> Defn -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((Expr -> Expr -> Bool
`hasAppInstanceOf` Expr
lhs) (Expr -> Bool) -> (Bndn -> Expr) -> Bndn -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bndn -> Expr
forall a b. (a, b) -> b
snd) Defn
rs
isRedundantByRootRecursions :: Defn -> Bool
isRedundantByRootRecursions :: Defn -> Bool
isRedundantByRootRecursions Defn
d = case (Expr -> Bool) -> [Expr] -> ([Expr], [Expr])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition Expr -> Bool
isGround ([Expr] -> ([Expr], [Expr])) -> [Expr] -> ([Expr], [Expr])
forall a b. (a -> b) -> a -> b
$ (Bndn -> Expr) -> Defn -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Bndn -> Expr
forall a b. (a, b) -> b
snd Defn
d of
([Expr
b], rs :: [Expr]
rs@(Expr
_:[Expr]
_)) -> (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Expr -> Bool
isHole [Expr]
rs
(bs :: [Expr]
bs@(Expr
_:[Expr]
_), rs :: [Expr]
rs@(Expr
_:[Expr]
_)) -> (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Expr -> Bool
isHole [Expr]
rs Bool -> Bool -> Bool
&& (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Expr -> Bool
isGround [Expr]
bs Bool -> Bool -> Bool
&& [Expr] -> Bool
forall a. Eq a => [a] -> Bool
allEqual [Expr]
bs
([Expr], [Expr])
_ -> Bool
False
introduceVariableAt :: Int -> Bndn -> Bndn
introduceVariableAt :: Int -> Bndn -> Bndn
introduceVariableAt Int
i b :: Bndn
b@(Expr
l,Expr
r)
| Expr -> Bool
isVar Expr
p = Bndn
b
| Bool
otherwise = Expr -> Bndn
unfoldPair
(Expr -> Bndn) -> Expr -> Bndn
forall a b. (a -> b) -> a -> b
$ Bndn -> Expr
foldPair Bndn
b Expr -> Defn -> Expr
// [(Expr
p,Expr
newVar)]
where
p :: Expr
p = Expr
l Expr -> Int -> Expr
$!! Int
i
newVar :: Expr
newVar = String
newName String -> Expr -> Expr
`varAsTypeOf` Expr
p
newName :: String
newName = [String] -> String
forall a. HasCallStack => [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String -> [String]
variableNamesFromTemplate String
"x" [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
\\ Expr -> [String]
varnames Expr
l
varnames :: Expr -> [String]
varnames :: Expr -> [String]
varnames Expr
e = [String
n | Value (Char
'_':String
n) Dynamic
_ <- Expr -> [Expr]
vars Expr
e]
isRedundantBySubsumption :: Defn -> Bool
isRedundantBySubsumption :: Defn -> Bool
isRedundantBySubsumption = [Expr] -> Bool
is ([Expr] -> Bool) -> (Defn -> [Expr]) -> Defn -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Expr) -> Defn -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Bndn -> Expr
foldPair (Defn -> [Expr]) -> (Defn -> Defn) -> Defn -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bndn -> Bool) -> Defn -> Defn
forall a. (a -> Bool) -> [a] -> [a]
filter Bndn -> Bool
isCompleteBndn
where
is :: [Expr] -> Bool
is [] = Bool
False
is (Expr
b:[Expr]
bs) = (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Expr
b Expr -> Expr -> Bool
`isInstanceOf`) [Expr]
bs Bool -> Bool -> Bool
|| [Expr] -> Bool
is [Expr]
bs
isRedundantModuloRewriting :: (Expr -> Expr) -> Defn -> Bool
isRedundantModuloRewriting :: (Expr -> Expr) -> Defn -> Bool
isRedundantModuloRewriting Expr -> Expr
normalize = Defn -> Bool
is
where
is :: Defn -> Bool
is [] = Bool
False
is (Bndn
b:Defn
bs) = (Bndn -> Bool) -> Defn -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ((Expr -> Expr) -> Bndn -> Bndn -> Bool
subsumedWith Expr -> Expr
normalize Bndn
b) Defn
bs
Bool -> Bool -> Bool
|| Defn -> Bool
is Defn
bs
simplifyDefn :: Defn -> Defn
simplifyDefn :: Defn -> Defn
simplifyDefn [] = []
simplifyDefn (Bndn
b:Defn
bs) = [Bndn
b | (Expr -> Bool) -> [Expr] -> Bool
forall a. (a -> Bool) -> [a] -> Bool
none (Bndn -> Expr
foldPair Bndn
b Expr -> Expr -> Bool
`isInstanceOf`) ([Expr] -> Bool) -> [Expr] -> Bool
forall a b. (a -> b) -> a -> b
$ (Bndn -> Expr) -> Defn -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map Bndn -> Expr
foldPair Defn
bs]
Defn -> Defn -> Defn
forall a. [a] -> [a] -> [a]
++ Defn -> Defn
simplifyDefn Defn
bs
subsumedWith :: (Expr -> Expr) -> Bndn -> Bndn -> Bool
subsumedWith :: (Expr -> Expr) -> Bndn -> Bndn -> Bool
subsumedWith Expr -> Expr
normalize (Expr
lhs1,Expr
rhs1) (Expr
lhs2,Expr
rhs2)
| Expr -> Bool
hasHole Expr
rhs2 = Bool
False
| Bool
otherwise = case Expr
lhs1 Expr -> Expr -> Maybe Defn
`match` Expr
lhs2 of
Maybe Defn
Nothing -> Bool
False
Just Defn
bs -> Bndn -> Expr
forall a b. (a, b) -> b
snd (Bndn -> Bndn
canonicalizeBndn (Expr
lhs2, Expr -> Expr
normalize (Expr -> Expr) -> Expr -> Expr
forall a b. (a -> b) -> a -> b
$ Expr
rhs2 Expr -> Defn -> Expr
//- Defn
bs))
Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Bndn -> Expr
forall a b. (a, b) -> b
snd (Bndn -> Bndn
canonicalizeBndn (Expr
lhs1, Expr
rhs1))