quickspec-2.2: src/QuickSpec/Internal/Pruning/UntypedTwee.hs
-- A pruner that uses twee. Does not respect types.
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE RecordWildCards, FlexibleContexts, FlexibleInstances, GADTs, PatternSynonyms, GeneralizedNewtypeDeriving, MultiParamTypeClasses, UndecidableInstances #-}
module QuickSpec.Internal.Pruning.UntypedTwee where
import QuickSpec.Internal.Testing
import QuickSpec.Internal.Pruning
import QuickSpec.Internal.Prop
import QuickSpec.Internal.Term
import QuickSpec.Internal.Type
import Data.Lens.Light
import qualified Twee
import qualified Twee.Equation as Twee
import qualified Twee.KBO as KBO
import qualified Twee.Base as Twee
import Twee hiding (Config(..))
import Twee.Rule hiding (normalForms)
import Twee.Proof hiding (Config, defaultConfig)
import Twee.Base(Ordered(..), Labelled)
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State.Strict hiding (State)
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
import QuickSpec.Internal.Terminal
import qualified Data.Set as Set
import Data.Set(Set)
import qualified Data.Map.Strict as Map
import qualified Data.IntMap as IntMap
import Control.Monad
data Config =
Config {
cfg_max_term_size :: Int,
cfg_max_cp_depth :: Int }
lens_max_term_size = lens cfg_max_term_size (\x y -> y { cfg_max_term_size = x })
lens_max_cp_depth = lens cfg_max_cp_depth (\x y -> y { cfg_max_cp_depth = x })
data Extended fun = Minimal | Skolem Twee.Var | Function fun
deriving (Eq, Ord, Typeable)
instance (Ord fun, Typeable fun) => Labelled (Extended fun)
instance Sized fun => Sized (Extended fun) where
size (Function f) = size f
size _ = 1
instance KBO.Sized (Extended fun) where
size _ = 1
instance Arity fun => Arity (Extended fun) where
arity (Function f) = arity f
arity (Skolem _) = 0
arity Minimal = 0
instance (Ord fun, Typeable fun) => Twee.Minimal (Extended fun) where
minimal = Twee.fun Minimal
instance EqualsBonus (Extended fun)
instance (Ord fun, Typeable fun, Pretty fun) => Pretty (Extended fun) where
pPrintPrec l p (Function f) = pPrintPrec l p f
pPrintPrec _ _ Minimal = text "?"
pPrintPrec _ _ (Skolem (Twee.V x)) = text ("sk" ++ show x)
instance (Ord fun, Typeable fun, PrettyTerm fun) => PrettyTerm (Extended fun) where
termStyle (Function f) = termStyle f
termStyle _ = curried
instance (Sized fun, Pretty fun, PrettyTerm fun, Ord fun, Typeable fun, Arity fun, EqualsBonus fun) => Ordered (Extended fun) where
lessEq = KBO.lessEq
lessIn = KBO.lessIn
lessEqSkolem = KBO.lessEqSkolem
newtype Pruner fun m a =
Pruner (ReaderT (Twee.Config (Extended fun)) (StateT (State (Extended fun)) m) a)
deriving (Functor, Applicative, Monad, MonadIO, MonadTester testcase term, MonadTerminal)
instance MonadTrans (Pruner fun) where
lift = Pruner . lift . lift
run :: (Typeable fun, Ord fun, Sized fun, Monad m) => Config -> Pruner fun m a -> m a
run Config{..} (Pruner x) =
evalStateT (runReaderT x config) (initialState config)
where
config =
defaultConfig {
Twee.cfg_accept_term = Just (\t -> size t <= cfg_max_term_size),
Twee.cfg_max_cp_depth = cfg_max_cp_depth }
instance (Labelled fun, Sized fun) => Sized (Twee.Term fun) where
size (Twee.Var _) = 1
size (Twee.App f ts) =
size (Twee.fun_value f) + sum (map size (Twee.unpack ts))
instance KBO.Weighted (Extended fun) where
argWeight _ = 1
type Norm fun = Twee.Term (Extended fun)
instance (Ord fun, Typed fun, Typeable fun, Arity fun, PrettyTerm fun, EqualsBonus fun, Sized fun, Monad m) =>
MonadPruner (Term fun) (Norm fun) (Pruner fun m) where
normaliser = Pruner $ do
state <- lift get
return $ \t ->
let u = normaliseTwee state t in
u
-- traceShow (text "normalise:" <+> pPrint t <+> text "->" <+> pPrint u) u
add ([] :=>: t :=: u) = Pruner $ do
state <- lift get
config <- ask
let (t' :=: u') = canonicalise (t :=: u)
if not (null (Set.intersection (normalFormsTwee state t') (normalFormsTwee state u'))) then
return False
else do
lift (put $! addTwee config t u state)
return True
add _ =
return True
--error "twee pruner doesn't support non-unit equalities"
decodeNormalForm hole t = return (decode t (error "ambiguously-typed term"))
where
decode (Twee.Var (Twee.V n)) ty =
Just (Var (V ty n))
decode (Twee.App (Twee.F _ Minimal) Twee.Empty) ty =
hole ty
decode (Twee.App (Twee.F _ (Skolem (Twee.V n))) Twee.Empty) ty =
Just (Var (V ty n))
decode (Twee.App (Twee.F _ (Function f)) ts) _ =
(Fun f :@:) <$> zipWithM decode (Twee.unpack ts) args
where
args = typeArgs (typ f)
decode _ _ = error "ill-typed term"
normTheorems = Pruner $ do
state <- lift get
let actives = IntMap.elems (Twee.st_active_set state)
let
toTheorem active =
Theorem
(toProp (equation proof))
(map toAxiom . Map.toList . groundAxiomsAndSubsts $ deriv)
where
proof = Twee.active_proof active
deriv = derivation proof
toProp (t Twee.:=: u) = [] :=>: t :=: u
toAxiom (ax, subs) = (toProp eqn, map toProp [Twee.subst sub eqn | sub <- Set.toList subs])
where
eqn = axiom_eqn ax
return (map toTheorem actives)
normaliseTwee :: (Ord fun, Typeable fun, Arity fun, PrettyTerm fun, EqualsBonus fun, Sized fun) =>
State (Extended fun) -> Term fun -> Norm fun
normaliseTwee state t =
result u (normaliseTerm state u)
where
u = simplifyTerm state (skolemise t)
normalFormsTwee :: (Ord fun, Typeable fun, Arity fun, PrettyTerm fun, EqualsBonus fun, Sized fun) =>
State (Extended fun) -> Term fun -> Set (Norm fun)
normalFormsTwee state t =
Set.fromList . Map.elems $ Map.mapWithKey result (normalForms state (skolemise t))
addTwee :: (Ord fun, Typeable fun, Arity fun, PrettyTerm fun, EqualsBonus fun, Sized fun) =>
Twee.Config (Extended fun) -> Term fun -> Term fun -> State (Extended fun) -> State (Extended fun)
addTwee config t u state =
interreduce config $
completePure config $
addAxiom config state axiom
where
axiom = Axiom 0 (prettyShow (t :=: u)) (toTwee t Twee.:=: toTwee u)
toTwee :: (Ord f, Typeable f) =>
Term f -> Twee.Term (Extended f)
toTwee = Twee.build . tt
where
tt (Var (V _ x)) =
Twee.var (Twee.V x)
tt (Fun f :@: ts) =
Twee.app (Twee.fun (Function f)) (map tt ts)
tt _ = error "partially applied term"
skolemise :: (Ord f, Typeable f) =>
Term f -> Twee.Term (Extended f)
skolemise = Twee.build . sk
where
sk (Var (V _ x)) =
Twee.con (Twee.fun (Skolem (Twee.V x)))
sk (Fun f :@: ts) =
Twee.app (Twee.fun (Function f)) (map sk ts)
sk _ = error "partially applied term"