packages feed

tpdb-2.7.2: src/TPDB/DP/Transform.hs

{-# language OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE PatternSynonyms #-}

module TPDB.DP.Transform
  ( dp, mark, Marked
  , pattern Marked, pattern Original, pattern Auxiliary
  , isOriginal, isMarked, mark_top
  , defined
  ) where

import TPDB.Data
import TPDB.Pretty

import qualified Data.Set as S
import Control.Monad ( guard, forM )

import Data.Hashable
import GHC.Generics

data Mark = Orig
   | Mark
   | Aux -- ^ wat is this?
  deriving (Eq, Ord, Show, Generic)
instance Hashable Mark

data Marked a = Marked_Imp { contents :: !a
                       , mark :: !Mark
                       }
    deriving ( Show, Eq, Ord, Generic )

pattern Marked a = Marked_Imp { mark = Mark, contents = a }
pattern Original a = Marked_Imp { mark = Orig, contents = a }
pattern Auxiliary a = Marked_Imp { mark = Aux, contents = a }

isOriginal m = mark m == Orig
isMarked   m = mark m == Mark

instance Hashable a => Hashable (Marked a) 

instance Pretty a => Pretty ( Marked a) where
   pretty m = let p = pretty (contents m) in case mark m of
       Orig -> p
       Mark -> p <> "#"
       Aux -> p

mark_top :: TermC v a => Term v a -> Term v (Marked a)
mark_top  (Node f args) = 
          Node (Marked f) $ map (tmap Original) args

defined s = S.fromList $ do 
                u <- rules s
                let Node f args = lhs u
                -- will raise exception if lhs is variable
                return f

-- | compute the DP transformed system.

dp :: (Eq v, Ord s, TermC v s)
   => RS s (Term v s) 
   -> RS (Marked s) (Term v (Marked s))
dp s = 
   let os = map ( \ u -> Rule { relation = Weak
                               , lhs = tmap Original $ lhs u  
                               , rhs = tmap Original $ rhs u  
                               , top = False
                               , original_variable = original_variable u
                               } )
           $ rules s
       def = defined s
       us = do 
            u <- rules s
            let -- ssubs = S.fromList $ strict_subterms $ lhs u
                walk r = if  -- S.member r ssubs
                          isStrictSubtermOf r (lhs u)
                         then [] else case r of
                    -- will raise exception if rhs contains 
                    -- a variable that is not in lhs
                    Node f args -> 
                        ( if S.member f def then (r :) else id )
                        ( args >>= walk )
            r <- walk $ rhs u
            return $ Rule { relation = Strict
                          , lhs = mark_top $ lhs u
                          , rhs = mark_top r 
                          , top = True
                          , original_variable = original_variable u
                          }
   in RS { signature = map Marked ( S.toList def )
                     ++ map Original ( signature s )
         , rules = us ++ os
         , separate = separate s 
         }