ADPfusion-0.5.0.0: src/Pseudoknot.hs
module Main where
import Control.Applicative
import Control.Monad
import Control.Monad.ST
import Data.Char (toUpper,toLower)
import Data.List as L
import Data.Vector.Fusion.Util
import Debug.Trace
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import qualified Data.Vector.Fusion.Stream.Monadic as SM
import qualified Data.Vector.Unboxed as VU
import System.Environment (getArgs)
import Text.Printf
import Data.PrimitiveArray as PA
import ADP.Fusion
data Nussinov m x r c = Nussinov
{ unp :: x -> c -> x
, jux :: x -> c -> x -> c -> x
, pse :: () -> () -> x -> x -> x
, nil :: () -> x
, pk1 :: (Z:.x:.()) -> (Z:.c:.()) -> x -> (Z:.():.x) -> (Z:.():.c) -> x
, pk2 :: (Z:.x:.()) -> (Z:.c:.()) -> x -> (Z:.():.x) -> (Z:.():.c) -> x
, nll :: (Z:.():.()) -> x
, h :: SM.Stream m x -> m r
}
makeAlgebraProduct ''Nussinov
bpmax :: Monad m => Nussinov m Int Int Char
bpmax = Nussinov
{ unp = \ x c -> x
, jux = \ x c y d -> if c `pairs` d then x + y + 1 else -999999
, pse = \ () () x y -> x + y
, nil = \ () -> 0
, pk1 = \ (Z:.x:.()) (Z:.a:.()) y (Z:.():.z) (Z:.():.b) -> if a `pairs` b then x + y + z + 1 else -888888
, pk2 = \ (Z:.x:.()) (Z:.a:.()) y (Z:.():.z) (Z:.():.b) -> if a `pairs` b then x + y + z + 1 else -888888
, nll = \ (Z:.():.()) -> 0
, h = SM.foldl' max (-999999)
}
{-# INLINE bpmax #-}
-- |
pairs !c !d
= c=='A' && d=='U'
|| c=='C' && d=='G'
|| c=='G' && d=='C'
|| c=='G' && d=='U'
|| c=='U' && d=='A'
|| c=='U' && d=='G'
{-# INLINE pairs #-}
-- |
--
-- TODO It could be beneficial to introduce
-- @type Splitted = Either String (String,String)@
-- or something isomorphic. While [String] works, it allows for too many
-- possibilities here! ([] ist lightweight, on the other hand ...)
pretty :: Monad m => Nussinov m [String] [[String]] Char
pretty = Nussinov
{ unp = \ [x] c -> [x ++ "."]
, jux = \ [x] c [y] d -> [x ++ "(" ++ y ++ ")"]
, pse = \ () () [x1,x2] [y1,y2] -> [x1 ++ y1 ++ x2 ++ y2]
, nil = \ () -> [""]
, pk1 = \ (Z:.[x]:.()) (Z:.a:.()) [y1,y2] (Z:.():.[z]) (Z:.():.b) -> [x ++ "[" ++ y1 , y2 ++ z ++ "]"]
, pk2 = \ (Z:.[x]:.()) (Z:.a:.()) [y1,y2] (Z:.():.[z]) (Z:.():.b) -> [x ++ "{" ++ y1 , y2 ++ z ++ "}"]
, nll = \ (Z:.():.()) -> ["",""]
, h = SM.toList
}
{-# INLINE pretty #-}
-- |
grammar Nussinov{..} t' u' v' c =
let t = t' ( unp <<< t % c |||
jux <<< t % c % t % c |||
nil <<< Epsilon |||
pse <<< (split (Proxy :: Proxy "U") (Proxy :: Proxy Fragment) u)
% (split (Proxy :: Proxy "V") (Proxy :: Proxy Fragment) v)
% (split (Proxy :: Proxy "U") (Proxy :: Proxy Final) u)
% (split (Proxy :: Proxy "V") (Proxy :: Proxy Final) v) ... h
)
u = u' ( pk1 <<< (M:|t:|Deletion) % (M:|c:|Deletion) % u % (M:|Deletion:|t) % (M:|Deletion:|c) |||
nll <<< (M:|Epsilon:|Epsilon) ... h
)
v = v' ( pk2 <<< (M:|t:|Deletion) % (M:|c:|Deletion) % v % (M:|Deletion:|t) % (M:|Deletion:|c) |||
nll <<< (M:|Epsilon:|Epsilon) ... h
)
in Z:.t:.u:.v
{-# INLINE grammar #-}
runPseudoknot :: Int -> String -> (Int,[[String]])
runPseudoknot k inp = (d, take k bs) where
i = VU.fromList . Prelude.map toUpper $ inp
n = VU.length i
!(Z:.t:.u:.v) = runInsideForward i
d = unId $ axiom t
bs = {- let ITbl _ _ _ x _ = v in traceShow (filter (flip elem gives . fst) $ assocs x) $ -} runInsideBacktrack i (Z:.t:.u:.v)
gives = [ Z:.subword 2 2 :. subword 3 3
, Z:.subword 1 2 :. subword 3 5
]
{-
- u g a a c
- 0 1 2 3 4 5
-}
{-# NOINLINE runPseudoknot #-}
type X = ITbl Id Unboxed (Subword I) Int
type T = ITbl Id Unboxed (Z:.Subword I:.Subword I) Int
runInsideForward :: VU.Vector Char -> Z:.X:.T:.T
runInsideForward i = mutateTablesWithHints (Proxy :: Proxy MonotoneMCFG)
$ grammar bpmax
(ITbl 0 0 EmptyOk (PA.fromAssocs (subword 0 0) (subword 0 n) (-666999) []))
(ITbl 0 0 (Z:.EmptyOk:.EmptyOk) (PA.fromAssocs (Z:.subword 0 0:.subword 0 0) (Z:.subword 0 n:.subword 0 n) (-777999) []))
(ITbl 0 0 (Z:.EmptyOk:.EmptyOk) (PA.fromAssocs (Z:.subword 0 0:.subword 0 0) (Z:.subword 0 n:.subword 0 n) (-888999) []))
(chr i)
where n = VU.length i
{-# NoInline runInsideForward #-}
runInsideBacktrack :: VU.Vector Char -> Z:.X:.T:.T -> [[String]]
runInsideBacktrack i (Z:.t:.u:.v) = unId $ axiom b
where !(Z:.b:._:._) = grammar (bpmax <|| pretty)
(toBacktrack t (undefined :: Id a -> Id a))
(toBacktrack u (undefined :: Id a -> Id a))
(toBacktrack v (undefined :: Id a -> Id a))
(chr i)
{-# NoInline runInsideBacktrack #-}
main = do
as <- getArgs
let k = if null as then 1 else read $ head as
ls <- lines <$> getContents
forM_ ls $ \l -> do
putStrLn l
let (s,xs) = runPseudoknot k l
print s
mapM_ (\[x] -> printf "%s %5d\n" x s) xs