{-# LANGUAGE CPP, RecordWildCards, TupleSections #-}
module Conjure.Engine
( module Data.Express
, module Data.Express.Fixtures
, module Test.Speculate.Engine
, module Test.Speculate.Reason
, Args(..)
, args
, conjure
, conjureWith
, conjureWithMaxSize
, conjpure
, conjpureWith
, candidateExprs
)
where
import Data.Express
import Data.Express.Fixtures hiding ((-==-))
import qualified Data.Ratio
import Test.LeanCheck.Error (errorToTrue, errorToFalse, errorToNothing)
import Test.Speculate hiding ((===), Args(..), args)
import Test.Speculate.Reason
import Test.Speculate.Engine
import Test.Speculate.Expr
import System.IO
import Conjure.Expr
import Conjure.Conjurable
data Args = Args
{ Args -> Int
maxTests :: Int
, Args -> Int
maxSize :: Int
, Args -> Int
maxRecursiveCalls :: Int
, Args -> Int
maxEquationSize :: Int
, Args -> Int
maxRecursionSize :: Int
}
args :: Args
args :: Args
args = Args :: Int -> Int -> Int -> Int -> Int -> Args
Args
{ maxTests :: Int
maxTests = Int
60
, maxSize :: Int
maxSize = Int
12
, maxRecursiveCalls :: Int
maxRecursiveCalls = Int
1
, maxEquationSize :: Int
maxEquationSize = Int
5
, maxRecursionSize :: Int
maxRecursionSize = Int
60
}
conjpure :: Conjurable f => String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpure :: String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpure = Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
forall f.
Conjurable f =>
Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpureWith Args
args
conjpureWith :: Conjurable f => Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpureWith :: Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpureWith Args{Int
maxRecursionSize :: Int
maxEquationSize :: Int
maxRecursiveCalls :: Int
maxSize :: Int
maxTests :: Int
maxRecursionSize :: Args -> Int
maxEquationSize :: Args -> Int
maxRecursiveCalls :: Args -> Int
maxSize :: Args -> Int
maxTests :: Args -> Int
..} String
nm f
f [Expr]
es = ([[Expr]]
implementationsT, [[Expr]]
candidatesT, [Expr]
tests)
where
tests :: [Expr]
tests = [Expr
ffxx Expr -> [(Expr, Expr)] -> Expr
//- [(Expr, Expr)]
bs | [(Expr, Expr)]
bs <- [[(Expr, Expr)]]
dbss]
implementationsT :: [[Expr]]
implementationsT = (Expr -> Expr) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> [[a]] -> [[b]]
mapT (Expr
vffxx Expr -> Expr -> Expr
-==-) ([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ (Expr -> Bool) -> [[Expr]] -> [[Expr]]
forall a. (a -> Bool) -> [[a]] -> [[a]]
filterT Expr -> Bool
implements [[Expr]]
candidatesT
implements :: Expr -> Bool
implements Expr
e = Expr -> Expr -> Bool
apparentlyTerminates Expr
rrff Expr
e
Bool -> Bool -> Bool
&& Expr
ffxx Expr -> Expr -> Bool
?=? Int -> Expr -> Expr -> Expr
recursexpr Int
maxRecursionSize Expr
vffxx Expr
e
candidatesT :: [[Expr]]
candidatesT = (Expr -> Bool) -> [[Expr]] -> [[Expr]]
forall a. (a -> Bool) -> [[a]] -> [[a]]
filterT (\Expr
e -> Expr -> TypeRep
typ Expr
e TypeRep -> TypeRep -> Bool
forall a. Eq a => a -> a -> Bool
== Expr -> TypeRep
typ Expr
ffxx)
([[Expr]] -> [[Expr]])
-> ([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> [[Expr]] -> [[Expr]]
forall a. Int -> [a] -> [a]
take Int
maxSize
([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ String
-> f -> Int -> Int -> (Expr -> Expr -> Bool) -> [Expr] -> [[Expr]]
forall f.
Conjurable f =>
String
-> f -> Int -> Int -> (Expr -> Expr -> Bool) -> [Expr] -> [[Expr]]
candidateExprs String
nm f
f Int
maxEquationSize Int
maxRecursiveCalls Expr -> Expr -> Bool
(===) [Expr]
es
ffxx :: Expr
ffxx = String -> f -> Expr
forall f. Conjurable f => String -> f -> Expr
canonicalApplication String
nm f
f
vffxx :: Expr
vffxx = String -> f -> Expr
forall f. Conjurable f => String -> f -> Expr
canonicalVarApplication String
nm f
f
(Expr
rrff:[Expr]
_) = Expr -> [Expr]
unfoldApp Expr
vffxx
Expr
e1 === :: Expr -> Expr -> Bool
=== Expr
e2 = Expr -> Bool
isReallyTrue (Expr
e1 Expr -> Expr -> Expr
-==- Expr
e2)
Expr
e1 ?=? :: Expr -> Expr -> Bool
?=? Expr
e2 = Expr -> Bool
isTrueWhenDefined (Expr
e1 Expr -> Expr -> Expr
-==- Expr
e2)
-==- :: Expr -> Expr -> Expr
(-==-) = f -> Expr -> Expr -> Expr
forall f. Conjurable f => f -> Expr -> Expr -> Expr
conjureMkEquation f
f
isTrueWhenDefined :: Expr -> Bool
isTrueWhenDefined Expr
e = (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
errorToFalse (Bool -> Bool) -> (Expr -> Bool) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Expr -> Bool
forall a. Typeable a => a -> Expr -> a
eval Bool
False) ([Expr] -> Bool) -> [Expr] -> Bool
forall a b. (a -> b) -> a -> b
$ ([(Expr, Expr)] -> Expr) -> [[(Expr, Expr)]] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (Expr
e Expr -> [(Expr, Expr)] -> Expr
//-) [[(Expr, Expr)]]
dbss
isReallyTrue :: Expr -> Bool
isReallyTrue = (Expr -> Bool) -> [Expr] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
errorToFalse (Bool -> Bool) -> (Expr -> Bool) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Expr -> Bool
forall a. Typeable a => a -> Expr -> a
eval Bool
False) ([Expr] -> Bool) -> (Expr -> [Expr]) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Expr -> [Expr]
gs
gs :: Expr -> [Expr]
gs :: Expr -> [Expr]
gs = Int -> [Expr] -> [Expr]
forall a. Int -> [a] -> [a]
take Int
maxTests ([Expr] -> [Expr]) -> (Expr -> [Expr]) -> Expr -> [Expr]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Expr -> [[Expr]]) -> Expr -> [Expr]
grounds (f -> Expr -> [[Expr]]
forall f. Conjurable f => f -> Expr -> [[Expr]]
conjureTiersFor f
f)
bss, dbss :: [[(Expr,Expr)]]
bss :: [[(Expr, Expr)]]
bss = Int -> [[(Expr, Expr)]] -> [[(Expr, Expr)]]
forall a. Int -> [a] -> [a]
take Int
maxTests ([[(Expr, Expr)]] -> [[(Expr, Expr)]])
-> [[(Expr, Expr)]] -> [[(Expr, Expr)]]
forall a b. (a -> b) -> a -> b
$ (Expr -> [[Expr]]) -> Expr -> [[(Expr, Expr)]]
groundBinds (f -> Expr -> [[Expr]]
forall f. Conjurable f => f -> Expr -> [[Expr]]
conjureTiersFor f
f) Expr
ffxx
dbss :: [[(Expr, Expr)]]
dbss = [[(Expr, Expr)]
bs | [(Expr, Expr)]
bs <- [[(Expr, Expr)]]
bss, Bool -> Bool
errorToFalse (Bool -> Bool) -> (Expr -> Bool) -> Expr -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> Expr -> Bool
forall a. Typeable a => a -> Expr -> a
eval Bool
False (Expr -> Bool) -> Expr -> Bool
forall a b. (a -> b) -> a -> b
$ Expr
e Expr -> [(Expr, Expr)] -> Expr
//- [(Expr, Expr)]
bs]
where
e :: Expr
e = Expr
ffxx Expr -> Expr -> Expr
-==- Expr
ffxx
conjure :: Conjurable f => String -> f -> [Expr] -> IO ()
conjure :: String -> f -> [Expr] -> IO ()
conjure = Args -> String -> f -> [Expr] -> IO ()
forall f. Conjurable f => Args -> String -> f -> [Expr] -> IO ()
conjureWith Args
args
conjureWithMaxSize :: Conjurable f => Int -> String -> f -> [Expr] -> IO ()
conjureWithMaxSize :: Int -> String -> f -> [Expr] -> IO ()
conjureWithMaxSize Int
sz = Args -> String -> f -> [Expr] -> IO ()
forall f. Conjurable f => Args -> String -> f -> [Expr] -> IO ()
conjureWith Args
args
{ maxSize :: Int
maxSize = Int
sz
, maxEquationSize :: Int
maxEquationSize = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
sz (Args -> Int
maxEquationSize Args
args)
}
conjureWith :: Conjurable f => Args -> String -> f -> [Expr] -> IO ()
conjureWith :: Args -> String -> f -> [Expr] -> IO ()
conjureWith Args
args String
nm f
f [Expr]
es = do
Expr -> IO ()
forall a. Show a => a -> IO ()
print (String -> f -> Expr
forall a. Typeable a => String -> a -> Expr
var ([String] -> String
forall a. [a] -> a
head ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String -> [String]
words String
nm) f
f)
String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"-- testing " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ([Expr] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Expr]
ts) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" combinations of argument values"
Integer -> [([Expr], [Expr])] -> IO ()
forall (t :: * -> *) t a.
(Foldable t, Show t, Num t) =>
t -> [([Expr], t a)] -> IO ()
pr Integer
1 [([Expr], [Expr])]
rs
where
pr :: t -> [([Expr], t a)] -> IO ()
pr t
n [] = String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"cannot conjure"
pr t
n (([Expr]
is,t a
es):[([Expr], t a)]
rs) = do
String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"-- looking through " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show (t a -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length t a
es) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" candidates of size " String -> String -> String
forall a. [a] -> [a] -> [a]
++ t -> String
forall a. Show a => a -> String
show t
n
case [Expr]
is of
[] -> t -> [([Expr], t a)] -> IO ()
pr (t
nt -> t -> t
forall a. Num a => a -> a -> a
+t
1) [([Expr], t a)]
rs
(Expr
i:[Expr]
_) -> do String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ Expr -> String
showEq Expr
i
String -> IO ()
putStrLn String
""
rs :: [([Expr], [Expr])]
rs = [[Expr]] -> [[Expr]] -> [([Expr], [Expr])]
forall a b. [a] -> [b] -> [(a, b)]
zip [[Expr]]
iss [[Expr]]
css
([[Expr]]
iss, [[Expr]]
css, [Expr]
ts) = Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
forall f.
Conjurable f =>
Args -> String -> f -> [Expr] -> ([[Expr]], [[Expr]], [Expr])
conjpureWith Args
args String
nm f
f [Expr]
es
showEq :: Expr -> String
showEq Expr
eq = Expr -> String
showExpr (Expr -> Expr
lhs Expr
eq) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" = " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Expr -> String
showExpr (Expr -> Expr
rhs Expr
eq)
candidateExprs :: Conjurable f
=> String -> f
-> Int
-> Int
-> (Expr -> Expr -> Bool)
-> [Expr]
-> [[Expr]]
candidateExprs :: String
-> f -> Int -> Int -> (Expr -> Expr -> Bool) -> [Expr] -> [[Expr]]
candidateExprs String
nm f
f Int
sz Int
mc Expr -> Expr -> Bool
(===) [Expr]
es =
String
-> f
-> Int
-> Int
-> (Expr -> Expr -> Bool)
-> [[Expr]]
-> [[Expr]]
forall f.
Conjurable f =>
String
-> f
-> Int
-> Int
-> (Expr -> Expr -> Bool)
-> [[Expr]]
-> [[Expr]]
candidateExprsT String
nm f
f Int
sz Int
mc Expr -> Expr -> Bool
(===)
[[Expr] -> [Expr]
forall a. Eq a => [a] -> [a]
nub ([Expr] -> [Expr]) -> [Expr] -> [Expr]
forall a b. (a -> b) -> a -> b
$ [Bool -> Expr
forall a. (Typeable a, Show a) => a -> Expr
val Bool
False, Bool -> Expr
forall a. (Typeable a, Show a) => a -> Expr
val Bool
True] [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ [Expr]
es [Expr] -> [Expr] -> [Expr]
forall a. [a] -> [a] -> [a]
++ f -> [Expr]
forall f. Conjurable f => f -> [Expr]
conjureIfs f
f]
candidateExprsT :: Conjurable f
=> String -> f
-> Int
-> Int
-> (Expr -> Expr -> Bool)
-> [[Expr]]
-> [[Expr]]
candidateExprsT :: String
-> f
-> Int
-> Int
-> (Expr -> Expr -> Bool)
-> [[Expr]]
-> [[Expr]]
candidateExprsT String
nm f
f Int
sz Int
mc Expr -> Expr -> Bool
(===) [[Expr]]
ess = [[Expr]] -> [[Expr]]
expressionsT ([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ [Expr
efExpr -> [Expr] -> [Expr]
forall a. a -> [a] -> [a]
:[Expr]
exs] [[Expr]] -> [[Expr]] -> [[Expr]]
forall a. [[a]] -> [[a]] -> [[a]]
\/ [[Expr]]
ess
where
(Expr
ef:[Expr]
exs) = Expr -> [Expr]
unfoldApp (Expr -> [Expr]) -> Expr -> [Expr]
forall a b. (a -> b) -> a -> b
$ String -> f -> Expr
forall f. Conjurable f => String -> f -> Expr
canonicalVarApplication String
nm f
f
thy :: Thy
thy = (Expr -> Expr -> Bool) -> Int -> [[Expr]] -> Thy
theoryFromAtoms Expr -> Expr -> Bool
(===) Int
sz ([[Expr]] -> Thy) -> [[Expr]] -> Thy
forall a b. (a -> b) -> a -> b
$ [f -> [Expr]
forall f. Conjurable f => f -> [Expr]
conjureHoles f
f] [[Expr]] -> [[Expr]] -> [[Expr]]
forall a. [[a]] -> [[a]] -> [[a]]
\/ [[Expr]]
ess
expressionsT :: [[Expr]] -> [[Expr]]
expressionsT [[Expr]]
ds = (Expr -> Bool) -> [[Expr]] -> [[Expr]]
forall a. (a -> Bool) -> [[a]] -> [[a]]
filterT (\Expr
e -> (Expr -> Bool) -> [Expr] -> Int
forall a. (a -> Bool) -> [a] -> Int
count (Expr -> Expr -> Bool
forall a. Eq a => a -> a -> Bool
== Expr
ef) (Expr -> [Expr]
vars Expr
e) Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
mc)
([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ (Expr -> Bool) -> [[Expr]] -> [[Expr]]
forall a. (a -> Bool) -> [[a]] -> [[a]]
filterT (Thy -> Expr -> Bool
isRootNormalE Thy
thy)
([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ [[Expr]]
ds [[Expr]] -> [[Expr]] -> [[Expr]]
forall a. [[a]] -> [[a]] -> [[a]]
\/ ([[Expr]] -> [[Expr]]
forall a. [[a]] -> [[a]]
delay ([[Expr]] -> [[Expr]]) -> [[Expr]] -> [[Expr]]
forall a b. (a -> b) -> a -> b
$ (Expr -> Expr -> Maybe Expr) -> [[Expr]] -> [[Expr]] -> [[Expr]]
forall a b c. (a -> b -> Maybe c) -> [[a]] -> [[b]] -> [[c]]
productMaybeWith Expr -> Expr -> Maybe Expr
($$) [[Expr]]
es [[Expr]]
es)
where
es :: [[Expr]]
es = [[Expr]] -> [[Expr]]
expressionsT [[Expr]]
ds
lhs, rhs :: Expr -> Expr
lhs :: Expr -> Expr
lhs (((Value String
"==" Dynamic
_) :$ Expr
e) :$ Expr
_) = Expr
e
rhs :: Expr -> Expr
rhs (((Value String
"==" Dynamic
_) :$ Expr
_) :$ Expr
e) = Expr
e
compareResult :: (Int,Expr) -> (Int,Expr) -> Ordering
compareResult :: (Int, Expr) -> (Int, Expr) -> Ordering
compareResult (Int
n1,Expr
e1) (Int
n2,Expr
e2) = Int
n2 Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` Int
n1
Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> Expr
e1 Expr -> Expr -> Ordering
`compareSimplicity` Expr
e2
(%) :: Int -> Int -> Int
Int
x % :: Int -> Int -> Int
% Int
y = Int
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
100 Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
y