packages feed

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

-- Copyright 2006, Sascha Boehme.




-- | This module defines a function to unfold relations generated from types to
--   theorems.

module FreeTheorems.Unfolding (
    unfold,
    unfoldFunction,
    unfoldForall,
    getTypesOf,

    -- testing interface
    -- testUnfolding
) where



import FreeTheorems.Simplification
import FreeTheorems.TheoremData
import FreeTheorems.Types
import Control.Monad (liftM)

import FreeTheorems.Delta
import FreeTheorems.Preparation
-- import FreeTheorems.Test.ArbitraryTypes
-- import Test.QuickCheck (quickCheck)





-- | Unfolds a relation to a theorem.
--   It replaces all functional relations and relation abstractions by logical
--   statements and conditions while the other relations are transformed in
--   is-element-of predicates using relations on their right-hand side.
--
--   The returned theorem is simplified using 'simplifyTheorem'.

unfold :: TermVariable
                -- ^ The name of the type from which the theorem is to be
                --   generated.
          -> Relation
                -- ^ Relation which was generated from the type.
          -> TheoremState Theorem
                -- ^ Returns the generated theorem in the corresponding theorem
                --   state.

unfold tv rel =
  liftM simplifyTheorem (unfoldRelation rel (TermVar tv, TermVar tv))





-- | Unfolds the given relation to a theorem. This is a helper function for
--   'unfold'.
--
--   Basic relations are transformed into is-element-of predicates while
--   functional relations and relation abstractions are replaced by logical
--   expressions. See also 'unfoldFunction' and 'unfoldForall'.

unfoldRelation :: Relation -> (Term, Term) -> TheoremState Theorem
unfoldRelation rel (t1, t2) =
  case rel of
    RelTerm _ _             -> return $ IsElementOf (t1,t2) rel
    RelVar _                -> return $ IsElementOf (t1,t2) rel
    RelLift _ _ _           -> return $ IsElementOf (t1,t2) rel
    RelLiftList _ _         -> return $ IsElementOf (t1,t2) rel
    RelLiftTuple _ _        -> return $ IsElementOf (t1,t2) rel
    RelFun model rel1 rel2  -> unfoldFunction model rel1 rel2 (t1,t2)
    RelForall model rv rel1 -> unfoldForall model rv rel1 (t1,t2)



-- | Unfolds a functional relation to a logical expression.

unfoldFunction :: LanguageModel
                  -> Relation
                  -> Relation
                  -> (Term, Term)
                  -> TheoremState Theorem

unfoldFunction model rel1 rel2 (t1,t2) = do
  (x,y) <- newVariablesFor rel1
  let (tx,ty) = (TermVar x, TermVar y)
  theorem <- unfoldRelation rel2 (TermApp t1 tx, TermApp t2 ty)
  case rel1 of
    RelTerm t (t1,t2) -> return $ ForallElements x t1
                                $ ForallElements y t2
                                $ Implication (IsElementOf (tx,ty) rel1) theorem

    RelVar _          -> return $ ForallPairs (x,y) rel1 theorem
    RelLift _ _ _     -> return $ ForallPairs (x,y) rel1 theorem
    RelLiftList _ _   -> return $ ForallPairs (x,y) rel1 theorem
    RelLiftTuple _ _  -> return $ ForallPairs (x,y) rel1 theorem

    RelFun _ rel3 rel4  -> do let (t1, t2) = getTypesOf rel3
                              let (t3, t4) = getTypesOf rel4
                              theorem1 <- unfoldFunction model rel3 rel4 (tx,ty)
                              return $ ForallElements x (TypeFun t1 t3)
                                     $ ForallElements y (TypeFun t2 t4)
                                     $ Implication theorem1 theorem

    RelForall _ rv rel3 -> do let (t1, t2) = getTypesOf rel1
                              theorem1 <- unfoldForall model rv rel3 (tx,ty)
                              return $ ForallElements x t1
                                     $ ForallElements y t2
                                     $ Implication theorem1 theorem



-- | Unfolds a relation abstraction to a logical expression.
--   Depending on the language model used, the expression may contain certain
--   restriction annotations.

unfoldForall :: LanguageModel
                -> RelationVariable
                -> Relation
                -> (Term, Term)
                -> TheoremState Theorem

unfoldForall model rv rel (t1,t2) = do
  let R _ _ (ttv1, ttv2) = rv
  let pair = (TermIns t1 (TypeTermVar ttv1), TermIns t2 (TypeTermVar ttv2))

  let res = case model of
              BasicModel -> []
              FixModel   -> [IsStrictAndContinuous rv]

  liftM (ForallRelations rv res) (unfoldRelation rel pair)



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



-- | Every relation is defined over a pair of closed types. This function
--   returns exactly that pair of types for an arbitrary relation. Thus, it acts
--   like an inverse delta function, although this is not fully true.

getTypesOf :: Relation -> (Type, Type)
getTypesOf rel = getTypes [] rel



-- | Computes the pair of types for a relation. This function is a helper
--   function for 'getTypesOf'.
--
--   The second argument contains a list of relation variables which should
--   be replaced by corresponding type variables (used to process abstractions).
--   Otherwise, relation variables are replaced by the according type term
--   variables.

getTypes :: [RelationVariable] -> Relation -> (Type, Type)
getTypes rvs rel =
  case rel of
    RelTerm _ typepair      -> typepair

    RelVar rv               -> let R _ v (ttv1, ttv2) = rv
                               in  if rv `elem` rvs
                                     then (TypeVar v, TypeVar v)
                                     else (TypeTermVar ttv1, TypeTermVar ttv2)

    RelLift model c rels    -> let (ts1, ts2) = unzip $ map (getTypes rvs) rels
                               in  (TypeCon c ts1, TypeCon c ts2)

    RelLiftList model rel'  -> let (t1, t2) = getTypes rvs rel'
                               in  (TypeList t1, TypeList t2)

    RelLiftTuple model rels -> let (ts1, ts2) = unzip $ map (getTypes rvs) rels
                               in  (TypeTuple ts1, TypeTuple ts2)

    RelFun model rel1 rel2  -> let (t1, t2) = getTypes rvs rel1
                                   (t3, t4) = getTypes rvs rel2
                               in  (TypeFun t1 t3, TypeFun t2 t4)

    RelForall model rv rel' -> let (t1, t2) = getTypes (rv:rvs) rel'
                                   R _ v _ = rv
                               in  (TypeForall v t1, TypeForall v t2)



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



-- A list of tests for this module.

{-
testUnfolding = do
  putStr "unfold replaces functions and abstractions ... "
  quickCheck prop_unfold
  putStr "every variable is quantified ... "
  quickCheck prop_variables_are_quantified
-}



-- Check that after expansion, there are no function type relations and
-- type abstraction relations anymore.

prop_unfold model t =
  let tv = PV "t"
      theorem = fst $ execute tv (applyDelta model (prepare t) >>= unfold tv)
  in  hasNoFunAndForall theorem


hasNoFunAndForall theorem =
  case theorem of
    IsElementOf _ rel     -> isNotFunOrForall rel
    ForallPairs _ rel t   -> isNotFunOrForall rel && hasNoFunAndForall t
    ForallRelations _ _ t -> hasNoFunAndForall t
    ForallElements _ _ t  -> hasNoFunAndForall t
    Conjunction t1 t2     -> hasNoFunAndForall t1 && hasNoFunAndForall t2
    Implication t1 t2     -> hasNoFunAndForall t1 && hasNoFunAndForall t2

isNotFunOrForall rel =
  case rel of
    RelTerm _ _      -> True
    RelVar _         -> True
    RelLift _ _ _    -> True
    RelLiftList _ _  -> True
    RelLiftTuple _ _ -> True
    RelFun _ _ _     -> False
    RelForall _ _ _  -> False



-- Check that every variable is quantified after expansion.

prop_variables_are_quantified model t =
  let tv = PV "t"
      theorem = fst $ execute tv (applyDelta model (prepare t) >>= unfold tv)
  in  cqTheorem [PV "t", PV "id"] [] [] theorem


cqTheorem tvs ttvs rvs theorem =
  case theorem of
    IsElementOf (t1,t2) rel     -> cqTerm tvs ttvs t1 && cqTerm tvs ttvs t2
                                   && cqRelation tvs ttvs rvs rel

    ForallPairs (tv1,tv2) rel t -> cqRelation tvs ttvs rvs rel
                                   && cqTheorem (tv1:tv2:tvs) ttvs rvs t

    ForallRelations rv res t    -> let R _ _ (ttv1,ttv2) = rv
                                       ttvs' = ttv1:ttv2:ttvs
                                   in cqRestriction tvs (rv:rvs) res
                                      && cqTheorem tvs ttvs' (rv:rvs) t

    ForallElements tv ty t      -> cqType [] ttvs ty
                                   && cqTheorem (tv:tvs) ttvs rvs t

    Conjunction t1 t2           -> cqTheorem tvs ttvs rvs t1
                                   && cqTheorem tvs ttvs rvs t2

    Implication t1 t2           -> cqTheorem tvs ttvs rvs t1
                                   && cqTheorem tvs ttvs rvs t2


cqRestriction tvs rvs [] = True
cqRestriction tvs rvs (res:ress) = cqRestriction tvs rvs ress &&
  case res of
    IsStrict tv              -> tv `elem` tvs
    IsStrictAndContinuous rv -> rv `elem` rvs


cqTerm tvs ttvs t =
  case t of
    TermVar tv    -> tv `elem` tvs
    TermApp t1 t2 -> cqTerm tvs ttvs t1 && cqTerm tvs ttvs t2
    TermIns t' ty -> cqTerm tvs ttvs t' && cqType [] ttvs ty

cqRelation tvs ttvs rvs rel =
  case rel of
    RelTerm t (ty1, ty2) -> cqTerm tvs ttvs t
                            && cqType [] ttvs ty1 && cqType [] ttvs ty2
    RelVar rv            -> rv `elem` rvs
    RelLift _ _ rels     -> and $ map (cqRelation tvs ttvs rvs) rels
    RelLiftList _ rel'   -> cqRelation tvs ttvs rvs rel'
    RelLiftTuple _ rels  -> and $ map (cqRelation tvs ttvs rvs) rels
    RelFun _ rel1 rel2   -> cqRelation tvs ttvs rvs rel1
                            && cqRelation tvs ttvs rvs rel2
    RelForall _ rv rel'  -> cqRelation tvs ttvs (rv:rvs) rel'

cqType vs ttvs t =
  case t of
    TypeBasic _     -> True
    TypeVar v       -> v `elem` vs
    TypeTermVar ttv -> ttv `elem` ttvs
    TypeCon _ ts    -> and $ map (cqType vs ttvs) ts
    TypeList t'     -> cqType vs ttvs t'
    TypeUnit        -> True
    TypeTuple ts    -> and $ map (cqType vs ttvs) ts
    TypeFun t1 t2   -> cqType vs ttvs t1 && cqType vs ttvs t2
    TypeForall v t' -> cqType (v:vs) ttvs t'





zz = TypeForall "a" (TypeFun (TypeBasic Char) (TypeTuple [TypeBasic Float,TypeVar "b"
  ,TypeBasic Char,TypeCon "String" [],TypeCon "String" [],TypeVar "b",TypeBasic
  Double,TypeVar "c",TypeVar "b",TypeCon "String" [],TypeBasic Int]))

zzz = fst $ execute (PV "t") (applyDelta BasicModel (prepare zz) >>= unfold (PV "t"))