packages feed

lambdabot-4.1: scripts/FT/FreeTheorems/Lifts.hs

-- Copyright 2006, Sascha Boehme.




-- | This module defines a function to extract and unfold lifted relations
--   occurring in theorems.

module FreeTheorems.Lifts (
    extractLiftRelations
) where



import FreeTheorems.Declarations
import FreeTheorems.Delta
import FreeTheorems.Modification
import FreeTheorems.TheoremData
import FreeTheorems.Types
import FreeTheorems.Unfolding
import Control.Monad (liftM, liftM2)
import Control.Monad.State (evalState)
import Data.List (nub)
import qualified Data.Map as Map (fromAscList)
import Data.Maybe (catMaybes)





-- | Creates a list of all lifted relations occurring in the given theorem.
--   Lifted relations are @lift@ relations as well as functional relations and
--   relational abstractions.
--   The lifted relations are returned together with their unfolded description.
--   If the second argument is 'True', all instantiations in the terms of the
--   returned unfolded relations are omitted.

extractLiftRelations :: Theorem -> Bool -> TheoremState [UnfoldedRelation]
extractLiftRelations theorem omitIns = do
  rels <- extractLifts theorem
  lifts <- mapM unfoldLiftRelation $ nub rels
  if omitIns
    then return (map omitInstantiationsInUnfoldedRelation lifts)
    else return lifts



--------------------------------------------------------------------------------



-- | Extracts all lifted relations from a theorem. This is a helper function for
--   'extractLiftRelations'.

extractLifts :: Theorem -> TheoremState [Relation]
extractLifts theorem =
  case theorem of
    IsElementOf _ rel       -> collectLifts rel
    ForallPairs _ rel t     -> liftM2 (++) (collectLifts rel) (extractLifts t)
    ForallRelations _ _ t   -> extractLifts t
    ForallFunctions _ _ _ t -> extractLifts t
    ForallElements _ _ t    -> extractLifts t
    Conjunction t1 t2       -> liftM2 (++) (extractLifts t1) (extractLifts t2)
    Implication t1 t2       -> liftM2 (++) (extractLifts t1) (extractLifts t2)



-- | Returns all lift relations occurring in a relation.

collectLifts :: Relation -> TheoremState [Relation]
collectLifts rel =
  case rel of
    RelTerm _ _         -> return []
    RelVar _            -> return []

    RelLift m con rels  -> do subLifts <- subLifts m con rels
                              lifts <- liftM concat $ mapM collectLifts rels
                              return $ rel : lifts ++ subLifts

    RelLiftList _ rel'  -> do lifts <- collectLifts rel'
                              return $ rel : lifts

    RelLiftTuple _ rels -> do lifts <- liftM concat $ mapM collectLifts rels
                              return $ rel : lifts

    RelFun _ rel1 rel2  -> do lifts1 <- collectLifts rel1
                              lifts2 <- collectLifts rel2
                              return $ rel : lifts1 ++ lifts2

    RelForall _ _ rel'  -> do lifts <- collectLifts rel'
                              return $ rel : lifts



-- | Returns all sublifts occurring in the right-hand side definition of a
--   type constructor. For example, the following datatype has a sublift:
--
-- > data Foo = Bar [Int]
--
--   Here, the function will return the relation for @[Int]@ as the only sublift
--   of @Foo@.
--
--   However, only general type constructors, tuples and lists may occur as
--   sublifts. Functions and type abstractions are forbidden, because their
--   behaviour is not yet defined.

-- The function relies on the fact, that functions and type abstractions may not
-- occur on the right-hand side of data declarations. That way, it can safely
-- use 'delta' (which is also defined for functions and type abstractions) to
-- create relations of types.

subLifts :: LanguageModel
            -> TypeConstructor
            -> [Relation]
            -> TheoremState [Relation]

subLifts model con rels = do
  let Just (DataDecl _ n f) = getDataDecl con
  let vs = map (\i -> "a" ++ show i) [1..n]
  let decls = f (map (\v -> TypeVar v) vs)
  let types = concatMap (\(DataConDecl _ ts) -> ts) decls
  let env = Map.fromAscList $ zip vs rels
  relations <- mapM (applyDeltaWith model env) types
  liftM concat (mapM collectLifts relations)



--------------------------------------------------------------------------------



-- | Unfolds a lift relation. This is a helper function for
--   'extractLiftRelations'.

unfoldLiftRelation :: Relation -> TheoremState UnfoldedRelation
unfoldLiftRelation rel =
  case rel of

-- the following two cases will never occur, see 'collectLifts'
--    RelTerm _ _
--    RelVar _

    RelLift model con rels  -> liftM (pack model) (unfoldLift model con rels)
    RelLiftList model rel'  -> return $ pack model (unfoldLiftList model rel')
    RelLiftTuple model rels -> return $ pack model (unfoldLiftTuple model rels)

    RelFun model rel1 rel2  -> do (f, g) <- newVariablesFor rel
                                  let pair = (TermVar f, TermVar g)
                                  theorem <- unfoldFunction model rel1 rel2 pair
                                  return $ pack model
                                         $ UnfoldedFunction (f,g) theorem

    RelForall model rv rel' -> do (x, y) <- newVariablesFor rel
                                  let pair = (TermVar x, TermVar y)
                                  theorem <- unfoldForall model rv rel' pair
                                  return $ pack model
                                         $ UnfoldedForall (x,y) theorem
  where
    pack = UnfoldedRelation rel



-- | Unfolds a lifted relation of an algebraic datatype. It uses 'delta' on the
--   types occurring on the right-hand side of the according type constructor's
--   definition to generate relations.

unfoldLift :: LanguageModel
              -> TypeConstructor
              -> [Relation]
              -> TheoremState UnfoldedSet

unfoldLift model con rels = do
  let Just (DataDecl _ n f) = getDataDecl con
      vs = map (\i -> "a" ++ show i) [1..n]
      decls = f (map (\v -> TypeVar v) vs)
      env = Map.fromAscList $ zip vs rels

  liftM UnfoldedLift (mapM (unfoldDecl env) decls)

  where
    unfoldDecl env (DataConDecl con types) = do
      let n = length types
          xs = map (TV "x") [1..n]
          ys = map (TV "y") [1..n]
      if n == 0
        then return (con, [], [], Nothing)
        else liftM (\t -> (con, xs, ys, Just t)) (buildTheorem env xs ys types)

    buildTheorem env xs ys types = do
      rels <- mapM (applyDeltaWith model env) types
      let mkTheorem (x,y,r) = IsElementOf (TermVar x, TermVar y) r
          theorems = map mkTheorem (zip3 xs ys rels)
      return $ foldr1 Conjunction theorems



-- | Unfolds a lifted list relation.

unfoldLiftList :: LanguageModel -> Relation -> UnfoldedSet
unfoldLiftList model rel =
  let (x, xs) = (PV "x", PV "xs")
      (y, ys) = (PV "y", PV "ys")
      lift    = RelLiftList model rel
      theorem = Conjunction (IsElementOf (TermVar x, TermVar y) rel)
                            (IsElementOf (TermVar xs, TermVar ys) lift)
  in  UnfoldedLiftList ((x, xs), (y, ys)) theorem



-- | Unfolds a lifted tuple relation.

unfoldLiftTuple :: LanguageModel -> [Relation] -> UnfoldedSet
unfoldLiftTuple model rels =
  let n = length rels
      xs = map (TV "x") [1..n]
      ys = map (TV "y") [1..n]
      mkTheorem (x,y,r) = IsElementOf (TermVar x, TermVar y) r
      theorem = foldr1 Conjunction (map mkTheorem (zip3 xs ys rels))
  in  UnfoldedLiftTuple (xs, ys) theorem