packages feed

ADPfusion 0.1.0.0 → 0.2.0.0

raw patch · 25 files changed

+2822/−1767 lines, 25 filesdep +deepseqdep +repadep +strictdep −criteriondep ~PrimitiveArraydep ~QuickCheckdep ~primitivenew-component:exe:NeedlemanWunsch

Dependencies added: deepseq, repa, strict, template-haskell, transformers

Dependencies removed: criterion

Dependency ranges changed: PrimitiveArray, QuickCheck, primitive, vector

Files

ADP/Fusion.hs view
@@ -1,12 +1,122 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} --- | Pure combinators along the lines of original ADP. We simply re-export the--- monadic interface without the monadic function application combinator.+-- | Generalized fusion system for grammars.+--+-- NOTE Symbols typically do not check bound data for consistency. If you, say,+-- bind a terminal symbol to an input of length 0 and then run your grammar,+-- you probably get errors, garbled data or random crashes. Such checks are+-- done via asserts in non-production code.+--+-- TODO each combinator should come with a special outer check. Given some+-- index (say (i,j), this can then check if i-const >= 0, or j+const<=n, or+-- i+const<=j. That should speed up everything that uses GChr combinators.+-- Separating out this check means that certain inner loops can run without any+-- conditions and just jump.  module ADP.Fusion-  ( module ADP.Fusion.Monadic-  , module ADP.Fusion.Monadic.Internal+  -- basic combinators+  ( (<<<)+  , (<<#)+  , (|||)+  , (...)+  , (~~)+  , (%)+  -- filters+  , check+  -- parsers+  , chr+  , chrLeft+  , chrRight+  , peekL+  , peekR+  , empty+  , region+  , sregion+--  , Tbl (..)+--  , BtTbl (..)+  , MTbl (..)+  , ENE (..)+  , ENZ (..)+  , None (..)   ) where -import ADP.Fusion.Monadic hiding ((#<<))-import ADP.Fusion.Monadic.Internal (Scalar(..))+import Data.Strict.Tuple+import GHC.Exts (inline)+import qualified Data.Vector.Fusion.Stream.Monadic as S++import ADP.Fusion.Apply+import ADP.Fusion.Chr+import ADP.Fusion.Classes+import ADP.Fusion.Empty+import ADP.Fusion.Region+import ADP.Fusion.Table+import ADP.Fusion.None++++-- | Apply a function to symbols on the RHS of a production rule. Builds the+-- stack of symbols from 'xs' using 'build', then hands this stack to+-- 'mkStream' together with the initial 'iniT' telling 'mkStream' that we are+-- in the "outer" position. Once the stream has been created, we 'S.map'+-- 'getArg' to get just the arguments in the stack, and finally 'apply' the+-- function 'f'.++infixl 8 <<<+(<<<) f xs = \ij -> outerCheck (checkValidIndex (build xs) ij) . S.map (apply (inline f) . getArg) . mkStream (build xs) (outer ij) $ ij+{-# INLINE (<<<) #-}++infixl 8 <<#+(<<#) f xs = \ij -> outerCheck (checkValidIndex (build xs) ij) . S.mapM (apply (inline f) . getArg) . mkStream (build xs) (outer ij) $ ij+{-# INLINE (<<#) #-}++-- | Combine two RHSs to give a choice between parses.++infixl 7 |||+(|||) xs ys = \ij -> xs ij S.++ ys ij+{-# INLINE (|||) #-}++-- | Applies the objective function 'h' to a stream 's'. The objective function+-- reduces the stream to a single optimal value (or some vector of co-optimal+-- things).++infixl 5 ...+(...) s h = h . s+{-# INLINE (...) #-}++-- | Additional outer check with user-given check function++infixl 6 `check`+check xs f = \ij -> let chk = f ij in chk `seq` outerCheck chk (xs ij)+{-# INLINE check #-}++-- | Separator between RHS symbols.++infixl 9 ~~+(~~) = (:!:)+{-# INLINE (~~) #-}++-- | This separator looks much paper "on paper" and is not widely used otherwise.++infixl 9 %+(%) = (:!:)+{-# INLINE (%) #-}++++++++
+ ADP/Fusion/Apply.hs view
@@ -0,0 +1,91 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module ADP.Fusion.Apply where++import Data.Array.Repa.Index++++-- * Apply function 'f' in '(<<<)'++class Apply x where+  type Fun x :: *+  apply :: Fun x -> x++instance Apply (Z:.a -> res) where+  type Fun (Z:.a -> res) = a -> res+  apply fun (Z:.a) = fun a+  {-# INLINE apply #-}++instance Apply (Z:.a:.b -> res) where+  type Fun (Z:.a:.b -> res) = a->b -> res+  apply fun (Z:.a:.b) = fun a b+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c -> res) where+  type Fun (Z:.a:.b:.c -> res) = a->b->c -> res+  apply fun (Z:.a:.b:.c) = fun a b c+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d -> res) where+  type Fun (Z:.a:.b:.c:.d -> res) = a->b->c->d -> res+  apply fun (Z:.a:.b:.c:.d) = fun a b c d+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e -> res) where+  type Fun (Z:.a:.b:.c:.d:.e -> res) = a->b->c->d->e -> res+  apply fun (Z:.a:.b:.c:.d:.e) = fun a b c d e+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f -> res) = a->b->c->d->e->f -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f) = fun a b c d e f+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g -> res) = a->b->c->d->e->f->g -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g) = fun a b c d e f g+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h -> res) = a->b->c->d->e->f->g->h -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h) = fun a b c d e f g h+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) = a->b->c->d->e->f->g->h->i -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i) = fun a b c d e f g h i+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) = a->b->c->d->e->f->g->h->i->j -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j) = fun a b c d e f g h i j+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) = a->b->c->d->e->f->g->h->i->j->k -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k) = fun a b c d e f g h i j k+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) = a->b->c->d->e->f->g->h->i->j->k->l -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l) = fun a b c d e f g h i j k l+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m) = fun a b c d e f g h i j k l m+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n) = fun a b c d e f g h i j k l m n+  {-# INLINE apply #-}++instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) where+  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n->o -> res+  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o) = fun a b c d e f g h i j k l m n o+  {-# INLINE apply #-}+
+ ADP/Fusion/Chr.hs view
@@ -0,0 +1,306 @@+{-# LANGUAGE GADTs #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.Chr where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Unboxed as VU+import qualified Data.Vector.Generic as VG+import Data.Strict.Maybe+import Prelude hiding (Maybe(..))++import Data.Array.Repa.Index.Subword++import ADP.Fusion.Classes++import Debug.Trace++++-- | Parses a single character.++chr xs = GChr (VG.unsafeIndex) xs+{-# INLINE chr #-}++-- | Parses a single character and returns the character to the left in a+-- strict Maybe.++chrLeft xs = GChr f xs where+  f xs k = ( xs VG.!? (k-1)+           , VG.unsafeIndex xs k+           )+  {-# INLINE f #-}+{-# INLINE chrLeft #-}++-- With default character++chrLeftD d xs = GChr f xs where+  f xs k = ( Prelude.maybe d id $ xs VG.!? (k-1)+           , VG.unsafeIndex xs k+           )+  {-# INLINE f #-}+{-# INLINE chrLeftD #-}++-- | Parses a single character and returns the character to the right in a+-- strict Maybe.++chrRight xs = GChr f xs where+  f xs k = ( VG.unsafeIndex xs k+           , xs VG.!? (k+1)+           )+  {-# INLINE f #-}+{-# INLINE chrRight #-}++-- | A generic Character parser that reads a single character but allows+-- passing additional information.++data GChr r x where -- = forall v . VG.Vector v x =>+  GChr :: VG.Vector v x => !(v x -> Int -> r) -> !(v x) -> GChr r x++instance Build (GChr r x)++instance+  ( ValidIndex ls Subword+  ) => ValidIndex (ls :!: GChr r x) Subword where+    validIndex (ls :!: GChr _ xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+      i>=a && j<=VG.length xs -c && i+b<=j && validIndex ls abc ij+    {-# INLINE validIndex #-}+    getParserRange (ls :!: GChr _ _) ix = let (a:!:b:!:c) = getParserRange ls ix in (a:!:b+1:!:max 0 (c-1))+    {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: GChr r x) Subword where+    data Elm (ls :!: GChr r x) Subword = ElmGChr !(Elm ls Subword) !r !Subword+    type Arg (ls :!: GChr r x) = Arg ls :. r+    getArg !(ElmGChr ls x _) = getArg ls :. x+    getIdx !(ElmGChr _ _ idx) = idx+    {-# INLINE getArg #-}+    {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: GChr r x) Subword where+  mkStream !(ls :!: GChr f xs) Outer !ij@(Subword (i:.j)) =+    let dta = f xs (j-1)+    in  dta `seq` S.map (\s -> ElmGChr s dta (subword (j-1) j)) $ mkStream ls Outer (subword i $ j-1)+  mkStream !(ls :!: GChr f xs) (Inner cnc szd) !ij@(Subword (i:.j))+    = S.map (\s -> let Subword (k:.l) = getIdx s+                   in  ElmGChr s (f xs l) (subword l $ l+1)+            )+    $ mkStream ls (Inner cnc szd) (subword i $ j-1)+  {-# INLINE mkStream #-}++-- | Wrapping a GChr to allow zero/one behaviour. Parses a character (or not)+-- in a strict maybe.++newtype ZeroOne r x = ZeroOne { unZeroOne :: GChr r x }++zoLeft xs = ZeroOne $ chrLeft xs+{-# INLINE zoLeft #-}++++-- | Generalized peek.++data GPeek r x = GPeek !(VU.Vector x -> Int -> r) !(VU.Vector x) !(Int:!:Int)++instance Build (GPeek r x)++instance+  ( ValidIndex ls Subword+  , VU.Unbox x+  ) => ValidIndex (ls :!: GPeek r x) Subword where+    validIndex (ls :!: GPeek _ xs _) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+      i>=a && j<VU.length xs -c && i+b<=j && validIndex ls abc ij+    {-# INLINE validIndex #-}+    getParserRange (ls :!: GPeek _ _ (a':!:c')) ix =+      let (a:!:b:!:c) = getParserRange ls ix in (a+a' :!: b :!: (c+c'))+    {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: GPeek r x) Subword where+    data Elm (ls :!: GPeek r x) Subword = ElmGPeek !(Elm ls Subword) !r !Subword+    type Arg (ls :!: GPeek r x) = Arg ls :. r+    getArg !(ElmGPeek ls x _) = getArg ls :. x+    getIdx !(ElmGPeek _ _ idx) = idx+    {-# INLINE getArg #-}+    {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: GPeek r x) Subword where+  mkStream !(ls :!: GPeek f xs _) Outer !ij@(Subword (i:.j)) =+    let dta = f xs (j-1)+    in  dta `seq` S.map (\s -> ElmGPeek s dta (subword j j)) $ mkStream ls Outer ij+  mkStream !(ls :!: GPeek f xs _) (Inner cnc szd) !ij@(Subword (i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s+                   in  ElmGPeek s (f xs (l-1)) (subword l l)+            )+    $ mkStream ls (Inner cnc szd) ij+  {-# INLINE mkStream #-}+++{-+-- * Parse a single character.++data Chr x = Chr !(VU.Vector x)++--chr = Chr+--{-# INLINE chr #-}++instance+  ( ValidIndex ls Subword+  , VU.Unbox xs+  ) => ValidIndex (ls :!: Chr xs) Subword where+    validIndex (ls :!: Chr xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+      let+      in  i>=a && j<VU.length xs -c && i+b<=j && validIndex ls abc ij+    {-# INLINE validIndex #-}+    getParserRange (ls :!: Chr xs) ix = let (a:!:b:!:c) = getParserRange ls ix in (a:!:b+1:!:max 0 (c-1))+    {-# INLINE getParserRange #-}++instance Build (Chr x)++instance+  ( Elms ls Subword+  ) => Elms (ls :!: Chr x) Subword where+  data Elm (ls :!: Chr x) Subword = ElmChr !(Elm ls Subword) !x !Subword+  type Arg (ls :!: Chr x) = Arg ls :. x+  getArg !(ElmChr ls x _) = getArg ls :. x+  getIdx !(ElmChr _ _ idx) = idx+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++-- |+--+-- For 'Outer' cases, we extract the data, 'seq' it and then stream. This moves+-- extraction out of the loop.++instance+  ( Monad m+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: Chr x) Subword where+  mkStream !(ls :!: Chr xs) Outer !ij@(Subword(i:.j)) =+    let dta = VG.unsafeIndex xs (j-1)+    in  dta `seq` S.map (\s -> ElmChr s dta (subword (j-1) j)) $ mkStream ls Outer (subword i $ j-1)+  mkStream !(ls :!: Chr xs) (Inner cnc szd) !ij@(Subword(i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s+                   in  ElmChr s (VG.unsafeIndex xs l) (subword l $ l+1)+            )+    $ mkStream ls (Inner cnc szd) (subword i $ j-1)+  {-# INLINE mkStream #-}+-}++++-- * Peeking to the left++data PeekL x = PeekL !(VU.Vector x)++peekL = PeekL+{-# INLINE peekL #-}++instance Build (PeekL x)++instance+  ( ValidIndex ls Subword+  , VU.Unbox x+  ) => ValidIndex (ls :!: PeekL x) Subword where+  validIndex (ls :!: PeekL xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    i>=a && j<=VU.length xs -c && i+b<=j && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: PeekL xs) ix = let (a:!:b:!:c) = getParserRange ls ix in if b==0 then (a+1:!:b:!:c) else (a:!:b:!:c)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: PeekL x) Subword where+  data Elm (ls :!: PeekL x) Subword = ElmPeekL !(Elm ls Subword) !x !Subword+  type Arg (ls :!: PeekL x) = Arg ls :. x+  getArg !(ElmPeekL ls x _) = getArg ls :. x+  getIdx !(ElmPeekL _ _ idx) = idx+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: PeekL x) Subword where+  mkStream !(ls :!: PeekL xs) Outer !ij@(Subword(i:.j)) =+    let dta = VU.unsafeIndex xs (j-1)+    in  dta `seq` S.map (\s -> ElmPeekL s dta (subword j j)) $ mkStream ls Outer ij+  mkStream !(ls :!: PeekL xs) (Inner cnc szd) !ij@(Subword(i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s+                   in  ElmPeekL s (VU.unsafeIndex xs $ l-1) (subword l l)+            )+    $ mkStream ls (Inner cnc szd) ij+  {-# INLINE mkStream #-}++++-- * Peeking to the right++data PeekR x = PeekR !(VU.Vector x)++peekR = PeekR+{-# INLINE peekR #-}++instance Build (PeekR x)++instance+  ( ValidIndex ls Subword+  , VU.Unbox x+  ) => ValidIndex (ls :!: PeekR x) Subword where+  validIndex (ls :!: PeekR xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    i>=a && j<=VU.length xs -c && i+b<=j && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: PeekR xs) ix = let (a:!:b:!:c) = getParserRange ls ix in (a:!:b:!:c+1)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: PeekR x) Subword where+  data Elm (ls :!: PeekR x) Subword = ElmPeekR !(Elm ls Subword) !x !Subword+  type Arg (ls :!: PeekR x) = Arg ls :. x+  getArg !(ElmPeekR ls x _) = getArg ls :. x+  getIdx !(ElmPeekR _ _ idx) = idx+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: PeekR x) Subword where+  mkStream !(ls :!: PeekR xs) Outer !ij@(Subword(i:.j)) =+    let dta = VU.unsafeIndex xs j+    in  dta `seq` S.map (\s -> ElmPeekR s dta (subword j j)) $ mkStream ls Outer ij+  mkStream !(ls :!: PeekR xs) (Inner cnc szd) !ij@(Subword(i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s+                   in  ElmPeekR s (VU.unsafeIndex xs l) (subword l l)+            )+    $ mkStream ls (Inner cnc szd) ij+  {-# INLINE mkStream #-}+
+ ADP/Fusion/Classes.hs view
@@ -0,0 +1,396 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.Classes where++import Data.Array.Repa.Index+import Data.Strict.Maybe+import Data.Strict.Tuple+import Data.Vector.Fusion.Stream.Size+import Prelude hiding (Maybe(..))+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Prelude as P++import Data.Array.Repa.Index.Subword+import Data.Array.Repa.Index.Outside+import Data.Array.Repa.Index.Points++++-- * Data and type constructors++-- | The Inner/Outer handler. We encode three states. We are in 'Outer' or+-- right-most position, or 'Inner' position. The 'Inner' position encodes if+-- loop conditional 'CheckNoCheck' need to be performed.+--+-- In f <<< Z % table % table, the two tables already perform a conditional+-- branch, so that Z/table does not have to check boundary conditions.+--+-- In f <<< Z % table % char, no check is performed in table/char, so Z/table+-- needs to perform a boundary check.++data CheckNoCheck+  = Check+  | NoCheck+  deriving (Eq,Show)++data InnerOuter+  = Inner !CheckNoCheck !(Maybe Int)+  | Outer+  deriving (Eq,Show)++data ENE+  = EmptyT+  | NonEmptyT+  | ZeroT+  deriving (Eq,Show)++++-- * Classes++-- |++class Elms x i where+  data Elm x i :: *+  type Arg x :: *+  getArg :: Elm x i -> Arg x+  getIdx :: Elm x i -> i++-- |++class Index i where+  type InOut  i :: *+  type ENZ    i :: *+  type PartialIndex i :: *+  type ParserRange i :: *+  outer :: i -> InOut i+  leftPartialIndex  :: i -> PartialIndex i+  rightPartialIndex :: i -> PartialIndex i+  fromPartialIndices :: PartialIndex i -> PartialIndex i -> i++class EmptyENZ enz where+  toEmptyENZ    :: enz -> enz+  toNonEmptyENZ :: enz -> enz++-- |++class (Monad m) => MkStream m x i where+  mkStream :: x -> InOut i -> i -> S.Stream m (Elm x i)++-- | Build the stack using (%)++class Build x where+  type Stack x :: *+  type Stack x = Z :!: x+  build :: x -> Stack x+  default build :: (Stack x ~ (Z :!: x)) => x -> Stack x+  build x = Z :!: x+  {-# INLINE build #-}++-- | 'ValidIndex', via 'validIndex' statically checks if an index 'i' is valid+-- for a stack of terminals and non-terminals 'x'. 'validIndex' is used to+-- short-circuit streams via 'outerCheck'.++class (Index i) => ValidIndex x i where+  validIndex :: x -> ParserRange i -> i -> Bool+  getParserRange :: x -> i -> ParserRange i++++-- * Helper functions++-- | Correct wrapping of 'validIndex' and 'getParserRange'.++checkValidIndex x i = validIndex x (getParserRange x i) i+{-# INLINE checkValidIndex #-}++-- | 'outerCheck' acts as a static filter. If 'b' is true, we keep all stream+-- elements. If 'b' is false, we discard all stream elements.++outerCheck :: Monad m => Bool -> S.Stream m a -> S.Stream m a+outerCheck b (S.Stream step sS n) = b `seq` S.Stream snew (Left (b,sS)) Unknown where+  {-# INLINE [1] snew #-}+  snew (Left  (False,s)) = return $ S.Done+  snew (Left  (True ,s)) = return $ S.Skip (Right s)+  snew (Right s        ) = do r <- step s+                              case r of+                                S.Yield x s' -> return $ S.Yield x (Right s')+                                S.Skip    s' -> return $ S.Skip    (Right s')+                                S.Done       -> return $ S.Done+{-# INLINE outerCheck #-}++++-- * Instances++++-- ** Unsorted++instance EmptyENZ ENE where+  toEmptyENZ ene  | ene==NonEmptyT = EmptyT+                  | otherwise      = ene+  toNonEmptyENZ ene | ene==EmptyT  = NonEmptyT+                    | otherwise    = ene+  {-# INLINE toEmptyENZ #-}+  {-# INLINE toNonEmptyENZ #-}++++-- ** PointL++instance Index PointL where+  type InOut PointL = InnerOuter+  type ENZ   PointL = ENE+  type PartialIndex PointL = Int+  type ParserRange  PointL = (Int:!:Int:!:Int)+  outer _ = Outer+  leftPartialIndex (PointL (i:.j)) = i+  rightPartialIndex (PointL (i:.j)) = j+  fromPartialIndices i j = pointL i j+  {-# INLINE outer #-}+  {-# INLINE leftPartialIndex #-}+  {-# INLINE rightPartialIndex #-}+  {-# INLINE fromPartialIndices #-}++instance ValidIndex Z PointL where+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}+  validIndex _ _ _ = True+  getParserRange _ _ = (0 :!: 0 :!: 0)++++-- ** 'Subword'++instance Index Subword where+  type InOut Subword = InnerOuter+  type ENZ   Subword = ENE+  type PartialIndex Subword = Int+  type ParserRange Subword = (Int :!: Int :!: Int)+  outer _ = Outer+  leftPartialIndex (Subword (i:.j)) = i+  rightPartialIndex (Subword (i:.j)) = j+  fromPartialIndices i j = subword i j+  {-# INLINE outer #-}+  {-# INLINE leftPartialIndex #-}+  {-# INLINE rightPartialIndex #-}+  {-# INLINE fromPartialIndices #-}++-- | The bottom of every stack of RHS arguments in a grammar.++instance+  ( Monad m+  ) => MkStream m Z Subword where+  mkStream Z Outer !(Subword (i:.j)) = S.unfoldr step i where+    step !k+      | k==j      = P.Just $ (ElmZ (subword i i), j+1)+      | otherwise = P.Nothing+  mkStream Z (Inner NoCheck Nothing)  !(Subword (i:.j)) = S.singleton $ ElmZ $ subword i i+  mkStream Z (Inner NoCheck (Just z)) !(Subword (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j && k+z>=j = P.Just $ (ElmZ (subword i i), j+1)+      | otherwise      = P.Nothing+  mkStream Z (Inner Check Nothing)   !(Subword (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j      = P.Just $ (ElmZ (subword i i), j+1)+      | otherwise = P.Nothing+  mkStream Z (Inner Check (Just z)) !(Subword (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j && k+z>=j = P.Just $ (ElmZ (subword i i), j+1)+      | otherwise      = P.Nothing+  {-# INLINE mkStream #-}++instance ValidIndex Z Subword where+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}+  validIndex _ _ _ = True+  getParserRange _ _ = (0 :!: 0 :!: 0)++++-- ** Outside++instance Index Outside where+  type InOut Outside = InnerOuter+  type ENZ   Outside = ENE+  type PartialIndex Outside = Int+  type ParserRange Outside = (Int :!: Int :!: Int)+  outer _ = Outer+  leftPartialIndex (Outside (i:.j)) = error "outside: not sure yet" -- i+  rightPartialIndex (Outside (i:.j)) = error "outside: not sure yet" -- j+  fromPartialIndices i j = error "outside: not sure yet" -- outside i j+  {-# INLINE outer #-}+  {-# INLINE leftPartialIndex #-}+  {-# INLINE rightPartialIndex #-}+  {-# INLINE fromPartialIndices #-}++-- | The bottom of every stack of RHS arguments in a grammar.++instance+  ( Monad m+  ) => MkStream m Z Outside where+  {-+  mkStream Z Outer !(Outside (i:.j)) = S.unfoldr step i where+    step !k+      | k==j      = P.Just $ (ElmZ (outside i i), j+1)+      | otherwise = P.Nothing+  mkStream Z (Inner NoCheck Nothing)  !(Outside (i:.j)) = S.singleton $ ElmZ $ outside i i+  mkStream Z (Inner NoCheck (Just z)) !(Outside (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j && k+z>=j = P.Just $ (ElmZ (outside i i), j+1)+      | otherwise      = P.Nothing+  mkStream Z (Inner Check Nothing)   !(Outside (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j      = P.Just $ (ElmZ (outside i i), j+1)+      | otherwise = P.Nothing+  mkStream Z (Inner Check (Just z)) !(Outside (i:.j)) = S.unfoldr step i where+    step !k+      | k<=j && k+z>=j = P.Just $ (ElmZ (outside i i), j+1)+      | otherwise      = P.Nothing+  {-# INLINE mkStream #-}+  -}++instance ValidIndex Z Outside where+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}+  validIndex _ _ _ = True+  getParserRange _ _ = (0 :!: 0 :!: 0)++++-- ** 'Z'++instance Index Z where+  type InOut Z = Z+  type ENZ   Z = Z+  type PartialIndex Z = Z+  type ParserRange Z = Z+  outer Z = Z+  leftPartialIndex Z = Z+  rightPartialIndex Z = Z+  fromPartialIndices Z Z = Z+  {-# INLINE outer #-}+  {-# INLINE leftPartialIndex #-}+  {-# INLINE rightPartialIndex #-}+  {-# INLINE fromPartialIndices #-}++instance EmptyENZ Z where+  toEmptyENZ _ = Z+  toNonEmptyENZ _ = Z+  {-# INLINE toEmptyENZ #-}+  {-# INLINE toNonEmptyENZ #-}++instance+  (+  ) => Elms Z ix where+  data Elm Z ix = ElmZ !ix+  type Arg Z = Z+  getArg !(ElmZ _) = Z+  getIdx !(ElmZ ix) = ix+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance Monad m => MkStream m Z Z where+  mkStream _ _ _ = S.singleton (ElmZ Z)+  {-# INLINE mkStream #-}++instance ValidIndex Z Z where+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}+  validIndex _ _ _ = True+  getParserRange _ _ = Z++++-- * Multi-dim instances++-- ** '(is:.i)'++instance (Index is, Index i) => Index (is:.i) where+  type InOut (is:.i) = InOut is :. InOut i+  type ENZ   (is:.i) = ENZ   is :. ENZ i+  type PartialIndex (is:.i) = PartialIndex is :. PartialIndex i+  type ParserRange (is:.i) = ParserRange is :. ParserRange i+  outer (is:.i) = outer is :. outer i+  leftPartialIndex (is:.i) = leftPartialIndex is :. leftPartialIndex i+  rightPartialIndex (is:.i) = rightPartialIndex is :. rightPartialIndex i+  fromPartialIndices (is:.i) (js:.j) = fromPartialIndices is js :. fromPartialIndices i j+  {-# INLINE outer #-}+  {-# INLINE leftPartialIndex #-}+  {-# INLINE rightPartialIndex #-}+  {-# INLINE fromPartialIndices #-}++instance (EmptyENZ es, EmptyENZ e) => EmptyENZ (es:.e) where+  toEmptyENZ (es:.e) = toEmptyENZ es :. toEmptyENZ e+  toNonEmptyENZ (es:.e) = toNonEmptyENZ es :. toNonEmptyENZ e+  {-# INLINE toEmptyENZ #-}+  {-# INLINE toNonEmptyENZ #-}++instance (ValidIndex Z is, ValidIndex Z i) => ValidIndex Z (is:.i) where+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}+  validIndex _ _ _ = True+  getParserRange Z (is:.i) = getParserRange Z is :. getParserRange Z i++++-- ** multi-dim with Subword++instance+  ( Monad m+  , MkStream m Z is+  ) => MkStream m Z (is:.Subword) where+  mkStream Z (io:.Outer) (is:.Subword (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.subword i i)) . S.filter (const $ i==j) $ mkStream Z io is+  mkStream Z (io:.Inner NoCheck Nothing) (is:.Subword (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.subword i i)) $ mkStream Z io is+  mkStream Z (io:.Inner NoCheck (Just z)) (is:.Subword (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.subword i i)) . S.filter (const $ i<=j && i+z>=j) $ mkStream Z io is+  mkStream Z (io:.Inner Check Nothing) (is:.Subword (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.subword i i)) . S.filter (const $ i<=j) $ mkStream Z io is+  mkStream Z (io:.Inner Check (Just z)) (is:.Subword (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.subword i i)) . S.filter (const $ i<=j && i+z>=j) $ mkStream Z io is+  {-# INLINE mkStream #-}++++-- ** multi-dim with PointL++-- TODO automatically created, check correctness++instance+  ( Monad m+  , MkStream m Z is+  ) => MkStream m Z (is:.PointL) where+  mkStream Z (io:.Outer) (is:.PointL (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.pointL i i)) . S.filter (const $ i==j) $ mkStream Z io is+  mkStream Z (io:.Inner NoCheck Nothing) (is:.PointL (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.pointL i i)) $ mkStream Z io is+  mkStream Z (io:.Inner NoCheck (Just z)) (is:.PointL (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.pointL i i)) . S.filter (const $ i<=j && i+z>=j) $ mkStream Z io is+  mkStream Z (io:.Inner Check Nothing) (is:.PointL (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.pointL i i)) . S.filter (const $ i<=j) $ mkStream Z io is+  mkStream Z (io:.Inner Check (Just z)) (is:.PointL (i:.j))+    = S.map (\(ElmZ jt) -> ElmZ (jt:.pointL i i)) . S.filter (const $ i<=j && i+z>=j) $ mkStream Z io is+  {-# INLINE mkStream #-}++++++-- * Special instances++instance Build x => Build (x:!:y) where+  type Stack (x:!:y) = Stack x :!: y+  build (x:!:y) = build x :!: y+  {-# INLINE build #-}+
+ ADP/Fusion/Empty.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.Empty where++import Data.Array.Repa.Index+import Data.Strict.Maybe+import Data.Strict.Tuple+import Prelude hiding (Maybe(..))+import qualified Data.Vector.Fusion.Stream.Monadic as S++import Data.Array.Repa.Index.Subword++import ADP.Fusion.Classes++++data Empty = Empty++empty = Empty+{-# INLINE empty #-}++instance+  ( ValidIndex ls Subword+  ) => ValidIndex (ls :!: Empty) Subword where+    validIndex (ls:!:Empty) abc ij@(Subword (i:.j)) = i==j && validIndex ls abc ij+    {-# INLINE validIndex #-}++instance Build Empty++instance+  ( Elms ls Subword+  ) => Elms (ls :!: Empty) Subword where+  data Elm (ls :!: Empty) Subword = ElmEmpty !(Elm ls Subword) !() !Subword+  type Arg (ls :!: Empty) = Arg ls :. ()+  getArg !(ElmEmpty ls () _) = getArg ls :. ()+  getIdx !(ElmEmpty _ _ i)   = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:Empty) Subword where+  mkStream !(ls:!:Empty) Outer !ij@(Subword (i:.j))+    = S.map (\s -> ElmEmpty s () (subword i j))+    $ S.filter (\_ -> i==j)+    $ mkStream ls Outer ij+  {-# INLINE mkStream #-}+
+ ADP/Fusion/Examples/Palindrome.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE RecordWildCards #-}++module ADP.Fusion.Examples.Palindrome where++import Data.Vector.Fusion.Stream.Monadic (Stream (..))+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Unboxed as VU+import qualified Data.Vector as V+import Data.Array.Repa.Index+import Control.Monad+import Control.Monad.Trans.Class+import qualified Control.Monad.Trans.Writer.Lazy as W+import qualified Control.Arrow as A++import Data.PrimitiveArray as PA+import Data.PrimitiveArray.Zero as PA++import ADP.Fusion hiding (empty)+import ADP.Fusion.Empty hiding (empty)+import ADP.Fusion.Chr+import ADP.Fusion.Table+import Data.Array.Repa.Index.Subword+import ADP.Fusion.TH++++data SignatureT m x r = Signature+  { pair  :: Char -> x -> Char -> x+  , empty :: () -> x+  , h     :: Stream m x -> m r+  }++-- makeAlgebraProduct ''SignatureT++{-++-- gPalindrome :: Signature m x -> Empty -> Char -> tbl -> (tbl, Subword -> m x)++gPalindrome Signature{..} e c s =+  ( s, (  empty <<< e         |||+          pair  <<< c % s % c ... h+       )+  )+{-# INLINE gPalindrome #-}++++aPair :: Monad m => Signature m Int Int+aPair = Signature+  { pair = \l x r -> if l==r then (x+4983) else -999999+  , empty = \() -> 4711+  , h = S.foldl' max (-888888)+  }+{-# INLINE aPair #-}++aPretty :: Monad m => Signature m String (Stream m String)+aPretty = Signature+  { pair = \l x r -> "(" ++ x ++ ")"+  , empty = \() -> ""+  , h = return . id+  }++(<**) :: (Monad m, CombElem x' x) => Signature m x x' -> Signature m y y' -> Signature m (x,Stream m y) y'+(<**) x y = Signature+  { pair = \l (zx,zy) r -> (pair x l zx r, S.map (\z -> pair y l z r) zy)+  , empty = \() -> (empty x (), S.singleton $ empty y ())+  , h = \zs -> do hfst <- h x $ S.map fst zs+                  h y $ S.concatMap snd . S.filter (combElem hfst . fst) $ zs+  }+{-# INLINE (<**) #-}++(***) :: (Monad m) => Signature m x x' -> Signature m y y' -> Signature m (x,y) (x',y')+(***) x y = Signature+  { pair = \l (zx,zy) r -> (pair x l zx r, pair y l zy r)+  , empty = \() -> (empty x (), empty y ())+--  , h = \zs -> do hfst <- h x $ S.map fst zs+--                  let phfs = S.concatMap snd . S.filter (combElem hfst . fst) $ zs+--                  hsnd <- h y phfs+  }+{-# INLINE (***) #-}++class CombElem x y where+  combElem :: x -> y -> Bool++instance (Eq x) => CombElem x x where+  combElem = (==)++instance (VU.Unbox x, Eq x) => CombElem (VU.Vector x) x where+  combElem xs y = VU.elem y xs++instance (Eq x) => CombElem (V.Vector x) x where+  combElem xs y = V.elem y xs++palindromeFill :: VU.Vector Char -> IO (PA.Unboxed (Z:.Subword) Int)+palindromeFill inp = do+  let n = VU.length inp+  !t' <- newWithM (Z:.subword 0 0) (Z:.subword 0 n) 0+  let t= mTblSw EmptyT t'+  let b = chr inp+  let e = Empty+  fillTable $ gPalindrome aPair e b t+  freeze t'+{-# NOINLINE palindromeFill #-}++fillTable (MTbl _ tbl, f) = do+  let (_,Z:.Subword (0:.n)) = boundsM tbl+  forM_ [n,n-1..0] $ \i -> forM_ [i..n] $ \j -> do+    (f $ subword i j) >>= writeM tbl (Z:.subword i j)+{-# INLINE fillTable #-}++-}+
+ ADP/Fusion/Examples/TwoDim.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeOperators #-}++-- | This is not really a working example, but rather to check the GHC-Core for+-- fusion.++--module ADP.Fusion.Examples.TwoDim where+module Main where++import Data.Vector.Fusion.Stream.Monadic (Stream (..))+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Unboxed as VU+import qualified Data.Vector as V+import Data.Array.Repa.Index+import Control.Monad+import Control.Monad.Trans.Class+import qualified Control.Monad.Trans.Writer.Lazy as W+import qualified Control.Arrow as A+import System.IO.Unsafe (unsafePerformIO)+import Control.Applicative++import Data.Array.Repa.Index.Points+import Data.PrimitiveArray as PA+import Data.PrimitiveArray.Zero as PA++import ADP.Fusion hiding (empty)+import ADP.Fusion.Empty hiding (empty)+import ADP.Fusion.Chr+import ADP.Fusion.Table+import ADP.Fusion.Multi+import Data.Array.Repa.Index.Subword+import ADP.Fusion.TH++++main = do+  ls <- lines <$> getContents+  align ls++align [] = return ()+align [c] = error "single last line"+align (a:b:xs) = do+  putStrLn a+  putStrLn b+  print $ needlemanWunsch (VU.fromList a) (VU.fromList b)+  align xs++data Signature m x r c = Signature+  { step_step :: x -> (Z:.c :.c ) -> x+  , step_loop :: x -> (Z:.c :.()) -> x+  , loop_step :: x -> (Z:.():.c ) -> x+  , nil_nil   ::      (Z:.():.()) -> x+  , h         :: Stream m x -> m r+  }++-- grammar :: Signature m x r c -> ???+grammar Signature{..} a i1 i2 =+  ( a, step_step <<< a % (T:!chr i1:!chr i2) |||+       step_loop <<< a % (T:!chr i1:!None  ) |||+       loop_step <<< a % (T:!None  :!chr i2) |||+       nil_nil   <<< (T:!Empty:!Empty)       ... h+  )+{-# INLINE grammar #-}++sScore :: Monad m => Signature m Int Int Char+sScore = Signature+  { step_step = \x (Z:.a:.b) -> if a==b then x+1 else x-1+  , step_loop = \x _         -> x-1+  , loop_step = \x _         -> x-1+  , nil_nil   = const 0+  , h = S.foldl' max 0+  }+{-# INLINE sScore #-}++needlemanWunsch i1 i2 = (ws ! (Z:.pointL 0 n1:.pointL 0 n2), bt) where+  ws = unsafePerformIO (forwardPhase i1 i2)+  n1 = VU.length i1+  n2 = VU.length i2+  bt = [] :: String+{-# NOINLINE needlemanWunsch #-}++forwardPhase :: VU.Vector Char -> VU.Vector Char -> IO (PA.Unboxed (Z:.PointL:.PointL) Int)+forwardPhase i1 i2 = do+  let n1 = VU.length i1+  let n2 = VU.length i2+  !t' <- newWithM (Z:.pointL 0 0:.pointL 0 0) (Z:.pointL 0 n1:.pointL 0 n2) 0+  let t= mTbl (Z:.EmptyT:.EmptyT) t'+  fillTable $ grammar sScore t i1 i2+  freeze t'+{-# INLINE forwardPhase #-}++fillTable (MTbl _ tbl, f) = do+  let (_,Z:.PointL(0:.n1):.PointL(0:.n2)) = boundsM tbl+  forM_ [0 .. n1] $ \k1 -> forM_ [0 .. n2] $ \k2 -> do+    (f $ Z:.pointL 0 k1:.pointL 0 k2) >>= writeM tbl (Z:.pointL 0 k1:.pointL 0 k2)+{-# INLINE fillTable #-}+
− ADP/Fusion/GAPlike.hs
@@ -1,571 +0,0 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}---- | ------ HINTS for writing your own (Non-) terminals:------ - ALWAYS provide types for local functions of 'mkStream' and--- 'mkStreamInner'. Otherwise stream-fusion gets confused and doesn't optimize.--- (Observable in core by looking for 'Left', 'RIght' constructors and 'SPEC'--- constructors.--module ADP.Fusion.GAPlike where--import Control.Monad.Primitive-import Data.Primitive.Types (Prim(..))-import Data.Vector.Fusion.Stream.Size-import GHC.Prim (Constraint)-import qualified Data.Vector.Fusion.Stream.Monadic as S-import qualified Data.Vector.Unboxed as VU--import Data.PrimitiveArray (PrimArrayOps(..), MPrimArrayOps(..))-import "PrimitiveArray" Data.Array.Repa.Index-import qualified Data.PrimitiveArray as PA-import qualified Data.PrimitiveArray.Zero.Unboxed as ZU------ * The required type classes. Each class does its own thing.---- | The 'Build' class. Combines the arguments into a stack before they are--- turned into a stream.------------ To use, simply write "instance Build MyDataCtor" as we have sensible default--- instances.--class Build x where-  -- | The stack of arguments we are building.-  type BuildStack x :: *-  -- | The default is for the left-most element.-  type BuildStack x = None :. x-  -- | Given an element, create the stack.-  build :: x -> BuildStack x-  -- | Default for the left-most element.-  default build :: (BuildStack x ~ (None :. x)) => x -> BuildStack x-  build x = None :. x-  {-# INLINE build #-}---- | The stream element. Creates a type-level recursive data type containing--- the extracted arguments.--class StreamElement x where-  -- | one element of the stream, recursively defined-  data StreamElm x :: *-  -- | top-most index of the stream -- typically int-  type StreamTopIdx  x :: *-  -- | complete, recursively defined argument of the stream-  type StreamArg  x :: *-  -- | Given a stream element, we extract the top-most idx-  getTopIdx :: StreamElm x -> StreamTopIdx x-  -- | extract the recursively defined argument in a well-defined way for 'apply'-  getArg :: StreamElm x -> StreamArg x---- | Given the arguments, creates a stream of 'StreamElement's.--class (StreamConstraint x) => MkStream m x where-  type StreamConstraint x :: Constraint-  type StreamConstraint x = ()-  mkStream      :: (StreamConstraint x) => x -> (Int,Int) -> S.Stream m (StreamElm x)-  mkStreamInner :: (StreamConstraint x) => x -> (Int,Int) -> S.Stream m (StreamElm x)------ * Terminates the stack of arguments---- | Very simple data ctor--data None = None---- | For CORE-language, we have our own Arg-terminator--data ArgZ = ArgZ--instance StreamElement None where-  data StreamElm None    = SeNone !Int-  type StreamTopIdx None = Int-  type StreamArg    None = ArgZ-  getTopIdx (SeNone k) = k-  getArg _ = ArgZ-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance (Monad m) => MkStream m None where-  mkStream None (i,j) = S.unfoldr step i where-    step k-      | k<=j = Just (SeNone i, j+1)-      | otherwise = Nothing-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  mkStreamInner = mkStream-  {-# INLINE mkStreamInner #-}------ * A single character terminal. Using unboxed vector to hold the input. Note--- that "character" means parsing a scalar, not that the 'Chr' parser only--- accepts "Char"s.--data Chr e = Chr !(VU.Vector e)--instance Build (Chr e)--instance (StreamElement x) => StreamElement (x:.Chr e) where-  data StreamElm (x:.Chr e) = SeChr !(StreamElm x) !Int !e-  type StreamTopIdx (x:.Chr e) = Int-  type StreamArg (x:.Chr e) = StreamArg x :. e-  getTopIdx (SeChr _ k _) = k-  getArg (SeChr x _ e) = getArg x :. e-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}---- TODO I think, we can rewrite both versions to use S.map instead of S.flatten.--instance (Monad m, MkStream m x, StreamElement x, StreamTopIdx x ~ Int, VU.Unbox e) => MkStream m (x:.Chr e) where-  mkStream (x:.Chr es) (i,j) = S.flatten mk step Unknown $ mkStream x (i,j-1) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x)-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.Chr e)))-    step (x,k)-      | k+1 == j = return $ S.Yield (SeChr x (k+1) (VU.unsafeIndex es k)) (x,j+1)-      | otherwise = return S.Done-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  mkStreamInner (x:.Chr es) (i,j) = S.flatten mk step Unknown $ mkStreamInner x (i,j-1) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x)-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.Chr e)))-    step (x,k)-      | k < j     = return $ S.Yield (SeChr x (k+1) (VU.unsafeIndex es k)) (x,j+1)-      | otherwise = return $ S.Done-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStreamInner #-}------ * Empty and non-empty tables.------ TODO This will probably become more funny with triangular tables ...---- | empty subwords allowed--data E---- | only non-empty subwords--data N--class TransToN t where-  type TransTo t :: *-  transToN :: t -> TransTo t---- | Used by the instances below for index calculations.--class TblType tt where-  initDeltaIdx :: tt -> Int--instance TblType E where-  initDeltaIdx _ = 0-  {-# INLINE initDeltaIdx #-}--instance TblType N where-  initDeltaIdx _ = 1-  {-# INLINE initDeltaIdx #-}---- ** Immutable tables--data Tbl c es = Tbl !es--instance TransToN (Tbl c es) where-  type TransTo (Tbl c es) = Tbl N es-  transToN (Tbl es) = Tbl es-  {-# INLINE transToN #-}--instance Build (Tbl c es)--instance (StreamElement x, PrimArrayOps arr DIM2 e, TblType c) => StreamElement (x:.Tbl c (arr DIM2 e)) where-  data StreamElm    (x:.Tbl c (arr DIM2 e)) = SeTbl !(StreamElm x) !Int !e-  type StreamTopIdx (x:.Tbl c (arr DIM2 e)) = Int-  type StreamArg    (x:.Tbl c (arr DIM2 e)) = StreamArg x :. e-  getTopIdx (SeTbl _ k _) = k-  getArg    (SeTbl x _ e) = getArg x :. e-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance (Monad m, MkStream m x, StreamElement x, StreamTopIdx x ~ Int, PrimArrayOps arr DIM2 e, TblType c) => MkStream m (x:.Tbl c (arr DIM2 e)) where-  -- | The outer stream function assumes that mkStreamInner generates a valid-  -- stream that does not need to be checked. (This should always be true!).-  -- The table entry to read is [k,j], as we supposedly are generating the-  -- outermost stream. Even more "outermost" streams will have changed 'j'-  -- beforehand. 'mkStream' should only ever be used if 'j' can be fixed.-  mkStream (x:.Tbl t) (i,j) = S.map step $ mkStreamInner x (i,j - initDeltaIdx (undefined :: c)) where-    step :: StreamElm x -> StreamElm (x:.Tbl c (arr DIM2 e))-    step x = let k = getTopIdx x in SeTbl x j (t PA.! (Z:.k:.j))-    {-# INLINE step #-}-  -- | The inner stream will, in each step, check if the current subword [k,l]-  -- (forall l>=k) is valid and terminate the stream once l>j.-  mkStreamInner (x:.Tbl t) (i,j) = S.flatten mk step Unknown $ mkStreamInner x (i,j) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x + initDeltaIdx (undefined :: c))-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.Tbl c (arr DIM2 e))))-    step (x,l)-      | l<=j      = return $ S.Yield (SeTbl x l (t PA.! (Z:.k:.l))) (x,l+1)-      | otherwise = return $ S.Done-      where k = getTopIdx x-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  {-# INLINE mkStreamInner #-}---- ** Mutable tables in some monad.--data MTbl c es = MTbl !es--instance TransToN (MTbl c es) where-  type TransTo (MTbl c es) = MTbl N es-  transToN (MTbl es) = MTbl es-  {-# INLINE transToN #-}--mtblN :: es -> MTbl N es-mtblN es = MTbl es-{-# INLINE mtblN #-}--mtblE :: es -> MTbl E es-mtblE es = MTbl es-{-# INLINE mtblE #-}--instance Build (MTbl c es)--instance (StreamElement x, MPrimArrayOps marr DIM2 e, TblType c) => StreamElement (x:.MTbl c (marr s DIM2 e)) where-  data StreamElm    (x:.MTbl c (marr s DIM2 e)) = SeMTbl !(StreamElm x) !Int !e-  type StreamTopIdx (x:.MTbl c (marr s DIM2 e)) = Int-  type StreamArg    (x:.MTbl c (marr s DIM2 e)) = StreamArg x :. e-  getTopIdx (SeMTbl _ k _) = k-  getArg    (SeMTbl x _ e) = getArg x :. e-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance-  ( Monad m-  , PrimMonad m-  , MkStream m x-  , StreamElement x-  , StreamTopIdx x ~ Int-  , MPrimArrayOps marr DIM2 e-  , TblType c-  , s ~ PrimState m-  ) => MkStream m (x:.MTbl c (marr s DIM2 e)) where-  -- | The outer stream function assumes that mkStreamInner generates a valid-  -- stream that does not need to be checked. (This should always be true!).-  -- The table entry to read is [k,j], as we supposedly are generating the-  -- outermost stream. Even more "outermost" streams will have changed 'j'-  -- beforehand. 'mkStream' should only ever be used if 'j' can be fixed.-  mkStream (x:.MTbl t) (i,j) = S.mapM step $ mkStreamInner x (i,j - initDeltaIdx (undefined :: c)) where-    step :: StreamElm x -> m (StreamElm (x:.MTbl c (marr s DIM2 e)))-    step x = let k = getTopIdx x in PA.readM t (Z:.k:.j) >>= \e -> return $ SeMTbl x j e-    {-# INLINE step #-}-  -- | The inner stream will, in each step, check if the current subword [k,l]-  -- (forall l>=k) is valid and terminate the stream once l>j.-  mkStreamInner (x:.MTbl t) (i,j) = S.flatten mk step Unknown $ mkStreamInner x (i,j) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x + initDeltaIdx (undefined :: c))-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.MTbl c (marr s DIM2 e))))-    step (x,l)-      | l<=j      = readM t (Z:.k:.l) >>= \e -> return $ S.Yield (SeMTbl x l e) (x,l+1)-      | otherwise = return $ S.Done-      where k = getTopIdx x-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  {-# INLINE mkStreamInner #-}---- ** Some convenience functions.--tNtoE :: Tbl N x -> Tbl E x-tNtoE (Tbl x) = Tbl x-{-# INLINE tNtoE #-}--tEtoN :: Tbl E x -> Tbl N x-tEtoN (Tbl x) = Tbl x-{-# INLINE tEtoN #-}------ * Parses an empty subword.---- | The empty subword. Can not be part of a more complex RHS for obvious--- reasons: "S -> E S" doesn't make sense. Used in some grammars as the base--- case.--data Empty = Empty--instance Build Empty where-  type BuildStack Empty = Empty-  build c = c-  {-# INLINE build #-}--instance StreamElement (Empty) where-  data StreamElm    Empty = SeEmpty !Int-  type StreamTopIdx Empty = Int-  type StreamArg    Empty = ArgZ :. ()-  getTopIdx (SeEmpty k) = k-  getArg    (SeEmpty _) = ArgZ :. ()-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance (Monad m) => MkStream m (Empty) where-  mkStream Empty (i,j) = S.unfoldr step i where-    step k-      | k==j      = Just (SeEmpty k, j+1)-      | otherwise = Nothing-    {-# INLINE step #-}-  mkStreamInner = error "undefined for Empty"-  {-# INLINE mkStream #-}-  {-# INLINE mkStreamInner #-}------ * Parsing subwords with restriced size. Both min- and max-size are given--- when binding input.--data RestrictedRegion e = RRegion !Int !Int !(VU.Vector e)--instance Build (RestrictedRegion e)--instance (StreamElement x) => StreamElement (x:.RestrictedRegion e) where-  data StreamElm (x:.RestrictedRegion e) = SeResRegion !(StreamElm x) !Int (VU.Vector e)-  type StreamTopIdx (x:.RestrictedRegion e) = Int-  type StreamArg (x:.RestrictedRegion e) = StreamArg x :. (VU.Vector e)-  getTopIdx (SeResRegion _ k _) = k-  getArg (SeResRegion x _ e) = getArg x :. e-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance (Monad m, MkStream m x, StreamElement x, StreamTopIdx x ~ Int, VU.Unbox e) => MkStream m (x:.RestrictedRegion e) where-  mkStream (x:.RRegion minR maxR xs) (i,j) = S.flatten mk step Unknown $ mkStream x (i,j-1) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x)-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.RestrictedRegion e)))-    step (x,k)-      | k+minR <= j && k+maxR >= j = return $ S.Yield (SeResRegion x k (VU.unsafeSlice k (max maxR (j-k)) xs)) (x,j+1)-      | otherwise = return S.Done-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  mkStreamInner (x:.RRegion minR maxR xs) (i,j) = S.flatten mk step Unknown $ mkStream x (i,j) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x + minR)-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.RestrictedRegion e)))-    step (x,l)-      | l<=j && (l-k)<=maxR = return $ S.Yield (SeResRegion x l (VU.unsafeSlice k (l-k) xs)) (x,j+1)-      | otherwise           = return S.Done-      where k = getTopIdx x-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStreamInner #-}------ * Backtracking tables.------ Since we want the slow forward phase to be fast, in the backtracking phase,--- we need to keep track of additional things. The backtracking table 'BTtbl'--- requires the table and an additional backtracking function. You should use--- the same composed function as for the forward pahse creating the bound table--- in the first place.---- | The backtracking table 'BTtbl" captures a DP table and the function used--- to fill it.--data BTtbl c t g = BTtbl t g--instance TransToN (BTtbl c t g) where-  type TransTo (BTtbl c t g) = BTtbl N t g-  transToN (BTtbl t g) = BTtbl t g-  {-# INLINE transToN #-}--bttblN :: t -> g -> BTtbl N t g-bttblN t g = BTtbl t g-{-# INLINE bttblN #-}--bttblE :: t -> g -> BTtbl E t g-bttblE t g = BTtbl t g-{-# INLINE bttblE #-}--instance Build (BTtbl c t g)---- | The backtracking function, given our index pair, return a stream of--- backtracked results. (Return as in we are in a monad).------ TODO Should this be "(Int,Int) -> m (SM.Stream Id b)" or are there cases--- where we'd like to have monadic effects on the "b"s?--type BTfun m b = (Int,Int) -> m (S.Stream m b)--instance (Monad m, StreamElement x, TblType c) => StreamElement (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b)) where-  data StreamElm    (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b)) = SeBTtbl !(StreamElm x) !Int !e (m (S.Stream m b))-  type StreamTopIdx (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b)) = Int-  type StreamArg    (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b)) = StreamArg x :. (e, m (S.Stream m b))-  getTopIdx (SeBTtbl _ k _ _) = k-  getArg    (SeBTtbl x _ e g) = getArg x :. (e,g)-  {-# INLINE getTopIdx #-}-  {-# INLINE getArg #-}--instance-  ( Monad m-  , MkStream m x-  , StreamElement x-  , VU.Unbox e-  , StreamTopIdx x ~ Int-  , TblType c-  ) => MkStream m (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b)) where-  mkStream (x:.BTtbl t g) (i,j) = S.map step $ mkStreamInner x (i,j - initDeltaIdx (undefined :: c)) where-    step :: StreamElm x -> StreamElm (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b))-    step x = let k = getTopIdx x in SeBTtbl x j (t PA.! (Z:.k:.j)) (g (k,j))-    {-# INLINE step #-}-  mkStreamInner (x:.BTtbl t g) (i,j) = S.flatten mk step Unknown $ mkStreamInner x (i,j) where-    mk :: StreamElm x -> m (StreamElm x, Int)-    mk x = return (x, getTopIdx x + initDeltaIdx (undefined :: c))-    step :: (StreamElm x, Int) -> m (S.Step (StreamElm x, Int) (StreamElm (x:.BTtbl c (ZU.Arr0 DIM2 e) (BTfun m b))))-    step (x,l)-      | l<=j      = return $ S.Yield (SeBTtbl x l (t PA.! (Z:.k:.l)) (g (k,l))) (x,l+1)-      | otherwise = return $ S.Done-      where k = getTopIdx x-    {-# INLINE mk #-}-    {-# INLINE step #-}-  {-# INLINE mkStream #-}-  {-# INLINE mkStreamInner #-}------ * Build complex stacks--instance Build x => Build (x,y) where-  type BuildStack (x,y) = BuildStack x :. y-  build (x,y) = build x :. y-  {-# INLINE build #-}------ * combinators--infixl 8 <<<-(<<<) f t ij = S.map (\s -> apply f $ getArg s) $ mkStream (build t) ij-{-# INLINE (<<<) #-}--infixl 7 |||-(|||) xs ys ij = xs ij S.++ ys ij-{-# INLINE (|||) #-}--infixl 6 ...-(...) s h ij = h $ s ij-{-# INLINE (...) #-}--infixl 6 ..@-(..@) s h ij = h ij $ s ij-{-# INLINE (..@) #-}--infixl 9 ~~-(~~) = (,)-{-# INLINE (~~) #-}--infixl 9 %-(%) = (,)-{-# INLINE (%) #-}------ * Apply function 'f' in '(<<<)'--class Apply x where-  type Fun x :: *-  apply :: Fun x -> x--instance Apply (ArgZ:.a -> res) where-  type Fun (ArgZ:.a -> res) = a -> res-  apply fun (ArgZ:.a) = fun a-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b -> res) where-  type Fun (ArgZ:.a:.b -> res) = a->b -> res-  apply fun (ArgZ:.a:.b) = fun a b-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c -> res) where-  type Fun (ArgZ:.a:.b:.c -> res) = a->b->c -> res-  apply fun (ArgZ:.a:.b:.c) = fun a b c-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d -> res) where-  type Fun (ArgZ:.a:.b:.c:.d -> res) = a->b->c->d -> res-  apply fun (ArgZ:.a:.b:.c:.d) = fun a b c d-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e -> res) = a->b->c->d->e -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e) = fun a b c d e-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f -> res) = a->b->c->d->e->f -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f) = fun a b c d e f-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g -> res) = a->b->c->d->e->f->g -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g) = fun a b c d e f g-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h -> res) = a->b->c->d->e->f->g->h -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h) = fun a b c d e f g h-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) = a->b->c->d->e->f->g->h->i -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i) = fun a b c d e f g h i-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) = a->b->c->d->e->f->g->h->i->j -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j) = fun a b c d e f g h i j-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) = a->b->c->d->e->f->g->h->i->j->k -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k) = fun a b c d e f g h i j k-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) = a->b->c->d->e->f->g->h->i->j->k->l -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l) = fun a b c d e f g h i j k l-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m) = fun a b c d e f g h i j k l m-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n) = fun a b c d e f g h i j k l m n-  {-# INLINE apply #-}--instance Apply (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) where-  type Fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n->o -> res-  apply fun (ArgZ:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o) = fun a b c d e f g h i j k l m n o-  {-# INLINE apply #-}-
− ADP/Fusion/GAPlike/Criterion.hs
@@ -1,179 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE PackageImports #-}--module ADP.Fusion.GAPlike.Criterion where--import Control.Monad.ST-import Criterion.Main-import Data.Char-import qualified Data.Vector.Fusion.Stream.Monadic as S-import qualified Data.Vector.Fusion.Stream as SP--import Data.PrimitiveArray-import Data.PrimitiveArray.Unboxed.VectorZero as UVZ-import Data.PrimitiveArray.Unboxed.Zero as UZ-import "PrimitiveArray" Data.Array.Repa.Index-import "PrimitiveArray" Data.Array.Repa.Shape--import ADP.Fusion.GAPlike-import ADP.Fusion.GAPlike.DevelCommon----criterionMain = defaultMain-  [ bgroup "testTTT3"-    [ bench "  10" (whnf (testTTT 0)   10)-    , bench " 100" (whnf (testTTT 0)  100)-    , bench "1000" (whnf (testTTT 0) 1000)-    ]-  , bgroup "testTTTT4"-    [ bench "  10" (whnf (testTTTT 0)   10)-    , bench " 100" (whnf (testTTTT 0)  100)-    , bench "1000" (whnf (testTTTT 0) 1000)-    ]-  , bgroup "testTTTT4ga"-    [ bench "  10" (whnf (testTTTTga 0)   10)-    , bench " 100" (whnf (testTTTTga 0)  100)-    , bench "1000" (whnf (testTTTTga 0) 1000)-    ]-  , bgroup "testTTTT4gaPA"-    [ bench "  10" (whnf (testTTTTgaPA 0)   10)-    , bench " 100" (whnf (testTTTTgaPA 0)  100)-    , bench "1000" (whnf (testTTTTgaPA 0) 1000)-    ]-  , bgroup "testTTTT4gaImmu"-    [ bench "  10" (whnf (testTTTTgaImmu 0)   10)-    , bench " 100" (whnf (testTTTTgaImmu 0)  100)-    , bench "1000" (whnf (testTTTTgaImmu 0) 1000)-    ]-  , bgroup "testTTTT4gaImmuPA"-    [ bench "  10" (whnf (testTTTTgaImmuPA 0)   10)-    , bench " 100" (whnf (testTTTTgaImmuPA 0)  100)-    , bench "1000" (whnf (testTTTTgaImmuPA 0) 1000)-    ]-  ]------ * Criterion tests--testC :: Int -> Int -> Int-testC i j = runST doST where-  doST :: ST s Int-  doST = do-    let c = Chr dvu-    (gord1 <<< c ... ghsum) (i,j)-{-# NOINLINE testC #-}--gTestC (ord1,hsum) c =-  (ord1 <<< c ... hsum)--aTestC = (ord1,hsum) where-  ord1 = gord1-  hsum = ghsum--testCC :: Int -> Int -> Int-testCC i j = runST doST where-  doST :: ST s Int-  doST = do-    let c = Chr dvu-    let d = Chr dvu-    (gord2 <<< c % d ... ghsum) (i,j)-{-# NOINLINE testCC #-}--type TBL s = Tbl N (UVZ.MArr0 s DIM2 Int)--testT :: Int -> Int -> Int-testT i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: TBL s <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) 1 []-    (id <<< tbl ... ghsum) (i,j)-{-# NOINLINE testT #-}--testTT :: Int -> Int -> Int-testTT i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: TBL s <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) 1 []-    (gplus2 <<< tbl % tbl ... ghsum) (i,j)-  {-# INLINE doST #-}-{-# NOINLINE testTT #-}--testTTT :: Int -> Int -> Int-testTTT i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: TBL s <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) 1 []-    (gplus3 <<< tbl % tbl % tbl ... ghsum) (i,j)-{-# NOINLINE testTTT #-}--testTTTT :: Int -> Int -> Int-testTTTT i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: TBL s <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) (1::Int) []-    (gplus4 <<< tbl % tbl % tbl % tbl ... ghsum) (i,j)-  {-# INLINE doST #-}-{-# NOINLINE testTTTT #-}--testTTTTga :: Int -> Int -> Int-testTTTTga i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: TBL s <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) (1::Int) []-    gTTTga aTTTga tbl (i,j)-  {-# INLINE doST #-}-{-# NOINLINE testTTTTga #-}--testTTTTgaPA :: Int -> Int -> Int-testTTTTgaPA i j = runST doST where-  doST :: ST s Int-  doST = do-    tbl :: Tbl N (UZ.MArr0 s DIM2 Int) <- Tbl `fmap` fromAssocsM (Z:.0:.0) (Z:.j:.j) (1::Int) []-    gTTTga aTTTga tbl (i,j)-  {-# INLINE doST #-}-{-# NOINLINE testTTTTgaPA #-}--testTTTTgaImmu :: Int -> Int -> Int-testTTTTgaImmu i j =-    let tbl = (Tbl $ fromAssocs (Z:.0:.0) (Z:.j:.j) 1 []) :: Tbl N (UVZ.Arr0 DIM2 Int) -    in tbl `seq` gTTTga aTTTgaImmu tbl (i,j)-{-# NOINLINE testTTTTgaImmu #-}--testTTTTgaImmuPA :: Int -> Int -> Int-testTTTTgaImmuPA i j =-    let tbl = (Tbl $ fromAssocs (Z:.0:.0) (Z:.j:.j) 1 []) :: Tbl N (UZ.Arr0 DIM2 Int) -    in tbl `seq` gTTTga aTTTgaImmu tbl (i,j)-{-# NOINLINE testTTTTgaImmuPA #-}--gTTTga (plus4, hsum) tbl =-  (plus4 <<< tbl % tbl % tbl % tbl ... hsum)-{-# INLINE gTTTga #-}--aTTTga = (plus4, hsum) where-  plus4 = gplus4-  hsum = ghsum--aTTTgaImmu = (plus4, hsum) where-  plus4 = gplus4-  hsum = gihsum-{-# INLINE aTTTgaImmu #-}--gord1 a = ord a--gord2 a b = ord a + ord b--gord3 a b c = ord a + ord b + ord c--gplus2 a b = a+b--gplus3 a b c = a+b+c--gplus4 a b c d = a+b+c+d--ghsum :: S.Stream (ST s) Int -> ST s Int-ghsum = S.foldl' (+) 0--gihsum :: SP.Stream Int -> Int-gihsum = SP.foldl' (+) 0
− ADP/Fusion/GAPlike/DevelCommon.hs
@@ -1,22 +0,0 @@-{-# LANGUAGE PackageImports #-}--module ADP.Fusion.GAPlike.DevelCommon where--import qualified Data.PrimitiveArray as PA-import qualified Data.Vector.Unboxed as VU--import Data.PrimitiveArray.Unboxed.VectorZero as UVZ-import Data.PrimitiveArray.Unboxed.Zero as UZ-import "PrimitiveArray" Data.Array.Repa.Index-import "PrimitiveArray" Data.Array.Repa.Shape----dvu = VU.fromList $ concat $ replicate 10 ['a'..'z']-{-# NOINLINE dvu #-}--type PAT = UVZ.Arr0 DIM2 Int-pat :: PAT-pat = PA.fromAssocs (Z:.0:.0) (Z:.1000:.1000) 0 [(Z:.i:.j,j-i) | i <-[0..1000], j<-[i..1000] ]-{-# NOINLINE pat #-}-
− ADP/Fusion/GAPlike/QuickCheck.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE TemplateHaskell #-}--module ADP.Fusion.GAPlike.QuickCheck where--import Test.QuickCheck-import Test.QuickCheck.All-import qualified Data.Vector.Fusion.Stream as SP-import qualified Data.Vector.Unboxed as VU--import "PrimitiveArray" Data.Array.Repa.Index-import "PrimitiveArray" Data.Array.Repa.Shape-import Data.PrimitiveArray--import ADP.Fusion.QuickCheck.Arbitrary-import ADP.Fusion.GAPlike.DevelCommon-import ADP.Fusion.GAPlike------ * QuickCheck--checkC_fusion (i,j) = id <<< Chr dvu ... SP.toList $ (i,j)-checkC_list   (i,j) = [dvu VU.! i | i+1==j]-prop_checkC = checkC_fusion === checkC_list--checkCC_fusion (i,j) = (,) <<< Chr dvu % Chr dvu ... SP.toList $ (i,j)-checkCC_list   (i,j) = [ (dvu VU.! i, dvu VU.! (i+1)) | i+2==j ]-prop_checkCC = checkCC_fusion === checkCC_list--checkP_fusion (i,j) = id <<< (Tbl pat :: Tbl E PAT)  ... SP.toList $ (i,j)-checkP_list   (i,j) = [ (pat!(Z:.i:.j)) | i<=j ]-prop_checkP = checkP_fusion === checkP_list--checkPP_fusion (i,j) = let tbl = Tbl pat :: Tbl E PAT-                       in  (,) <<< tbl % tbl ... SP.toList $ (i,j)-checkPP_list   (i,j) = [ (pat!(Z:.i:.k), pat!(Z:.k:.j)) | k<-[i..j] ]-prop_checkPP = checkPP_fusion === checkPP_list--checkCPC_fusion (i,j) = let tbl = Tbl pat :: Tbl E PAT-                        in  (,,) <<< Chr dvu % tbl % Chr dvu ... SP.toList $ (i,j)-checkCPC_list (i,j) = [ (dvu VU.! i, pat!(Z:.i+1:.j-1), dvu VU.! (j-1)) | i+2<=j ]-prop_checkCPC = checkCPC_fusion === checkCPC_list--checkNN_fusion (i,j) = let tbl = Tbl pat :: Tbl N PAT-                       in  (,) <<< tbl % tbl ... SP.toList $ (i,j)-checkNN_list   (i,j) = [ (pat!(Z:.i:.k), pat!(Z:.k:.j)) | k<-[i+1..j-1] ]-prop_checkNN = checkNN_fusion === checkNN_list----options = stdArgs {maxSuccess = 1000}--customCheck = quickCheckWithResult options--allProps = $forAllProperties customCheck-
− ADP/Fusion/Monadic.hs
@@ -1,197 +0,0 @@-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE PackageImports #-}---- | Monadic combinators. Code like------ @f <<< xs ~~~ ys ... Stream.sum@------ will generate efficient GHC core for a dynamic program comparable to------ @sum [ f (xs!(i,k)) (ys!(k,j)) | k<-[i..j]]@.--module ADP.Fusion.Monadic where--import "PrimitiveArray" Data.Array.Repa.Index-import qualified Data.Vector.Fusion.Stream.Monadic as S--import ADP.Fusion.Monadic.Internal------ * Apply functions to arguments.---- | A monadic version of the function application combinator. Applies 'f'--- which has a monadic effect.--infixl 8 #<<-(#<<) f t ij = S.mapM (\(_,_,c) -> apply f c) $ streamGen t ij-{-# INLINE (#<<) #-}---- | Pure function application combinator. Applies 'f' which is pure. The--- arguments to 'f', meaning 't' can be monadic, however!--infixl 8 <<<-(<<<) f t ij = S.map (\(_,_,c) -> apply f c) $ streamGen t ij-{-# INLINE (<<<) #-}------ * Combine multiple right-hand sides of a non-terminal in a context-free--- grammar.---- | If both, 'xs' and 'ys' are streams of candidate answers, they can be--- combined here. The answer (or sort) type of 'xs' and 'ys' has to be the--- same. Works like @(++)@ for lists.--infixl 7 |||-(|||) xs ys ij = xs ij S.++ ys ij-{-# INLINE (|||) #-}------ * Reduce streams to single answers.------ NOTE "Single answers" can be of a vector-type! One is not constrained to--- scalar results. This allows for many exiting algorithms.---- | Reduces a streams of answers to the type of stored answers. The resulting--- type could be scalar, which it will be for highest-performance algorithms,--- or it could be a subset of answers stored in some kind of data structure.--infixl 6 ...-(...) stream h ij = h $ stream ij-{-# INLINE (...) #-}---- | Specialized version of choice function application, with a choice function--- that needs to know the subword index it is working on.--infixl 6 ..@-(..@) stream h ij = h ij $ stream ij-{-# INLINE (..@) #-}------ * Combinators to chain function arguments.------ ** General combinator creation.---- | General function to create combinators. The left-hand side @xs@ in @xs--- `comb` ys@ will have a size between @minL@ and @maxL@, while @ys@ and--- /everything to its right will be guaranteed @minR@ size.--makeLeft_MinRight (minL,maxL) minR = comb where-  {-# INLINE comb #-}-  comb xs ys = Box mk step xs ys-  {-# INLINE mk #-}-  mk (z:.k:.j,a,b) = return (z:.k:.k+minL:.j,a,b)-  {-# INLINE step #-}-  step (z:.k:.l:.j,a,b)-    | l<=j-minR && l<=k+maxL = return $ S.Yield (z:.k:.l:.j,a,b) (z:.k:.l+1:.j,a,b)-    | otherwise              = return $ S.Done-{-# INLINE makeLeft_MinRight #-}---- | Create combinators which are to be used in the right-most position of a--- chain. 1st, they make sure that the second to last region has a size of at--- least 'minL'. 2nd, they constrain the last argument to a size between 'minR'--- and 'maxR'.--makeMinLeft_Right minL (minR,maxR) = comb where-  {-# INLINE comb #-}-  comb xs ys = Box mk step xs ys-  {-# INLINE mk #-}-  mk (z:.k:.j,a,b) = let l = max (k+minL) (j-maxR) in return (z:.k:.l:.j,a,b)-  {-# INLINE step #-}-  step (z:.k:.l:.j,a,b)-    | l<=j-minR = return $ S.Yield (z:.k:.l:.j,a,b) (z:.k:.l+1:.j,a,b)-    | otherwise = return $ S.Done-{-# INLINE makeMinLeft_Right #-}------ ** A number of often-used combinators.--infixl 9 -~+, +~-, -~~, ~~---(-~+) = makeLeft_MinRight (1,1) 1-{-# INLINE (-~+) #-}--(+~-) = makeMinLeft_Right 1 (1,1)-{-# INLINE (+~-) #-}--(-~~) = makeLeft_MinRight (1,1) 0-{-# INLINE (-~~) #-}--(~~-) = makeMinLeft_Right 0 (1,1)-{-# INLINE (~~-) #-}--(+~--) = makeMinLeft_Right 1 (2,2)-{-# INLINE (+~--) #-}--infixl 9 ~~~-(~~~) xs ys = Box mk step xs ys where-  {-# INLINE mk #-}-  mk (z:.k:.j,vidx,vstack) = return $ (z:.k:.k:.j,vidx,vstack)-  {-# INLINE step #-}-  step (z:.k:.l:.j,vidx,vstack)-    | l<=j      = return $ S.Yield (z:.k:.l:.j,vidx,vstack) (z:.k:.l+1:.j,vidx,vstack)-    | otherwise = return $ S.Done-{-# INLINE (~~~) #-}---- | @xs +~+ ys@ with @xs@ and @ys@ non-empty. The non-emptyness constraint on--- @ys@ works only for two arguments. With three or more arguments, a--- left-leaning combinator to the right of @ys@ is required to establish--- non-emptyness.--infixl 9 +~+-(+~+) xs ys = Box mk step xs ys where-  {-# INLINE mk #-}-  mk (z:.k:.j,vidx,vstack) = return $ (z:.k:.k+1:.j,vidx,vstack)-  {-# INLINE step #-}-  step (z:.k:.l:.j,vidx,vstack)-    | l+1<=j    = return $ S.Yield (z:.k:.l:.j,vidx,vstack) (z:.k:.l+1:.j,vidx,vstack)-    | otherwise = return $ S.Done-{-# INLINE (+~+) #-}---- | @ls ~~~ xs !-~+ ys@ with xs having a size of one and @ls@ further to the--- left having a size of one or more.--infixl 9 !-~+-(!-~+) xs ys = Box mk step xs ys where-  {-# INLINE mk #-}-  mk (z:.k:.j,vidx,vstack)-    | k>0       = return $ (z:.k:.k+1:.j,vidx,vstack)-    | otherwise = return $ (z:.k:.j+1:.j,vidx,vstack)-  {-# INLINE step #-}-  step (z:.k:.l:.j,vidx,vstack)-    | l+1<=j    = return $ S.Yield (z:.k:.l:.j,vidx,vstack) (z:.k:.j+1:.j,vidx,vstack)-    | otherwise = return $ S.Done-{-# INLINE (!-~+) #-}---- | @xs +~-! ys ~~~ rs@ with @ys@ having a size of one and @rs@ further to the--- right having a size of one.--infixl 9 +~-!-(+~-!) xs ys = Box mk step xs ys where-  {-# INLINE mk #-}-  mk (z:.k:.j,vidx,vstack) = return $ (z:.k:.j-2:.j,vidx,vstack)-  {-# INLINE step #-}-  step (z:.k:.l:.j,vidx,vstack)-    | l+2==j    = return $ S.Yield (z:.k:.l:.j,vidx,vstack) (z:.k:.j+1:.j,vidx,vstack)-    | otherwise = return $ S.Done-{-# INLINE (+~-!) #-}---- | @xs -~- ys@ produces an answer only if both @xs@ and @ys@ have size one.--- The total size here then is two.--infixl 9 -~--(-~-) xs ys = Box mk step xs ys where-  {-# INLINE mk #-}-  mk (z:.k:.j,vidx,vstack) = return $ (z:.k:.k+1:.j,vidx,vstack)-  {-# INLINE step #-}-  step (z:.k:.l:.j,vidx,vstack)-    | k+1==l && l+1==j = return $ S.Yield (z:.k:.l:.j,vidx,vstack) (z:.k:.l+1:.j,vidx,vstack)-    | otherwise        = return $ S.Done-{-# INLINE (-~-) #-}-
− ADP/Fusion/Monadic/Internal.hs
@@ -1,492 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DoAndIfThenElse #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE OverlappingInstances #-}-{-# LANGUAGE PackageImports #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}--{-# OPTIONS_HADDOCK hide #-}---- | The internal working of ADPfusion. All combinator applications are turned--- into efficient code during compile time.------ If you have a data structure to be used as an argument in a combinator--- chain, derive an instance 'ExtractValue', 'StreamGen', and 'PreStreamGen'.------ NOTE: If this doesn't happen, it is a possible bug, or GHC changed its--- optimizer (like with GHC 7.2 -> 7.4).------ TODO If possible, instance generation will be using the Generics system in--- the future.--module ADP.Fusion.Monadic.Internal where--import Control.Monad.Primitive-import Control.Monad.ST-import Data.List (intersperse)-import Data.Primitive.Types-import Data.Vector.Fusion.Stream.Size-import "PrimitiveArray" Data.Array.Repa.Index-import "PrimitiveArray" Data.Array.Repa.Shape-import qualified Data.Vector.Fusion.Stream.Monadic as S-import qualified Data.Vector.Unboxed as VU-import Text.Printf--import qualified Data.PrimitiveArray as PA-import qualified Data.PrimitiveArray.Zero.Unboxed as ZU-import qualified Data.PrimitiveArray.Zero as Z------ * StreamGen---- | Generate stream from either one (DIM2 -> m cnt) or some combination of--- terminals derived from uses of nextTo.--class Monad m => StreamGen m t r | t -> r where-  streamGen :: t -> DIM2 -> S.Stream m r--#define mkStreamGen(cnt) \-instance (Monad m, ExtractValue m (cnt), Asor (cnt) ~ k, Elem (cnt) ~ elm) \-=> StreamGen m (cnt) (DIM2,Z:.k,Z:.elm) where { \-  {-# INLINE streamGen #-} \-;  streamGen x ij = extractStreamLast x $ preStreamGen x ij }--mkStreamGen(DIM2 -> Scalar elm)-mkStreamGen(DIM2 -> ScalarM elm)-mkStreamGen(DIM2 -> Vect elm)-mkStreamGen(DIM2 -> VectM elm)-mkStreamGen(ZU.MArr0 s sh elm)-mkStreamGen(ZU.Arr0 sh elm)--mkStreamGen(Z.MArr0 s sh (VU.Vector elm))-mkStreamGen(Z.Arr0 sh (VU.Vector elm))---- | two or more elements combined by NextTo (~~~), "xs" as anything, "ys" is--- monadic.--instance-  ( Monad m-  , ExtractValue m ys, Asor ys ~ cY, Elem ys ~ eY-  , PreStreamGen m (Box mk step xs ys) (idx:.Int,adx:.cX,arg:.eX)-  , Idx2 _idx ~ idx-  ) => StreamGen m (Box mk step xs ys) (idx:.Int,adx:.cX:.cY,arg:.eX:.eY) where-  streamGen (Box mk step xs ys) ij-    = extractStreamLast ys-    $ preStreamGen (Box mk step xs ys) ij-  {-# INLINE streamGen #-}------ * PreStreamGen---- | Required by most 'StreamGen' instances just before 'extractStreamLast' is--- called.--class Monad m => PreStreamGen m s q | s -> q where-  preStreamGen-    :: s      -- ^ the composite type of the arguments-    -> DIM2   -- ^ the original index @(Z:.i:.j)@-    -> S.Stream m q -- ^ the stream we get out of it---- | Creates the single step on the left which does nothing more then set the--- outermost indices to (i,j). This does not use the alpha/omega's--singlePreStreamGen ij = S.unfoldr step ij where-  {-# INLINE step #-}-  step (Z:.i:.j)-    | i<=j      = Just ((Z:.i:.j ,Z,Z), Z:.j+1:.j)-    | otherwise = Nothing-{-# INLINE singlePreStreamGen #-}--#define mkPreStreamGen(s) \-instance (Monad m) => PreStreamGen m (s) (DIM2,Z,Z) where { \-  {-# INLINE preStreamGen #-} \-;  preStreamGen _ = singlePreStreamGen }--mkPreStreamGen(DIM2 -> Scalar elm)-mkPreStreamGen(DIM2 -> ScalarM elm)-mkPreStreamGen(DIM2 -> Vect elm)-mkPreStreamGen(DIM2 -> VectM elm)-mkPreStreamGen(ZU.MArr0 s sh elm)-mkPreStreamGen(ZU.Arr0 sh elm)--mkPreStreamGen(Z.MArr0 s sh (VU.Vector elm))-mkPreStreamGen(Z.Arr0 sh (VU.Vector elm))---- | the first two arguments from nextTo, monadic xs.--instance ( Monad m-         , ExtractValue m xs, Asor xs ~ cX, Elem xs ~ eX-         , PreStreamGen m xs xsStack-         , (idxX,adxX,argX) ~ xsStack-         , (z0:.Int:.Int) ~ idxX-         , ((idxX,adxX,argX) -> m (idxX:.Int,adxX,argX)) ~ mk-         , ((idxX:.Int,adxX,argX) -> m (S.Step (idxX:.Int,adxX,argX) (idxX:.Int,adxX,argX))) ~ step-         ) => PreStreamGen m (Box mk step xs ys) (idxX:.Int,adxX:.cX,argX:.eX) where-  preStreamGen (Box mk step xs ys) ij-    = extractStream xs-    $ S.flatten mk step Unknown-    $ preStreamGen xs ij-  {-# INLINE preStreamGen #-}---- | Pre-stream generation for deeply nested boxes.--instance-  ( Monad m-  , ExtractValue m xs, Asor xs ~ cX, Elem xs ~ eX-  , PreStreamGen m (Box box2 box3 box1 xs) xsStack-  , (idxX,adxX,argX) ~ xsStack-  , (z0:.Int:.Int) ~ idxX-  , ((idxX,adxX,argX) -> m (idxX:.Int,adxX,argX)) ~ mk-  , ((idxX:.Int,adxX,argX) -> m (S.Step (idxX:.Int,adxX,argX) (idxX:.Int,adxX,argX))) ~ step-  ) => PreStreamGen m (Box mk step (Box box2 box3 box1 xs) ys) (idxX:.Int,adxX:.cX,argX:.eX) where-  preStreamGen (Box mk step box@(Box _ _ _ xs) ys) ij-    = extractStream xs-    $ S.flatten mk step Unknown-    $ preStreamGen box ij-  {-# INLINE preStreamGen #-}------ * ExtractValue: extract values from data structures.--class (Monad m) => ExtractValue m cnt where-  type Asor cnt :: *-  type Elem cnt :: *-  extractValue  :: ()-                => cnt-                -> DIM2-                -> Asor cnt-                -> m (Elem cnt)-  extractStream :: ()-                => cnt-                -> S.Stream m (Idx3 z,astack,vstack)-                -> S.Stream m (Idx3 z,astack:.Asor cnt,vstack:.Elem cnt)-  extractStreamLast :: ()-                    => cnt-                    -> S.Stream m (Idx2 z,astack,vstack)-                    -> S.Stream m (Idx2 z,astack:.Asor cnt,vstack:.Elem cnt)---- | Mutable arrays.--instance-  ( PrimMonad m-  , VU.Unbox elm-  , PrimState m ~ s-  , DIM2 ~ sh-  ) => ExtractValue m (ZU.MArr0 s sh elm) where-  type Asor (ZU.MArr0 s sh elm) = Z-  type Elem (ZU.MArr0 s sh elm) = elm-  extractValue cnt ij z = do-    x <- PA.readM cnt ij-    x `seq` return x-  extractStream cnt stream = S.mapM addElm stream where-    addElm (z:.k:.x:.l, astack, vstack) = do-      vadd <- PA.readM cnt (Z:.k:.x)-      vadd `seq` return (z:.k:.x:.l, astack:.Z, vstack :. vadd)-  extractStreamLast sngl stream = S.mapM addElm stream where-    addElm (z:.k:.x, astack, vstack) = do-      vadd <- PA.readM sngl (Z:.k:.x)-      vadd `seq` return (z:.k:.x, astack:.Z, vstack:.vadd)-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | Immutable arrays.--instance-  ( Monad m-  , VU.Unbox elm-  , DIM2 ~ sh-  ) => ExtractValue m (ZU.Arr0 sh elm) where-  type Asor (ZU.Arr0 sh elm) = Z-  type Elem (ZU.Arr0 sh elm) = elm-  extractValue cnt ij z = do-    let x = PA.index cnt ij-    x `seq` return x-  extractStream cnt stream = S.map addElm stream where-    addElm (z:.k:.x:.l, astack, vstack) = let vadd = PA.index cnt (Z:.k:.x) in-      vadd `seq` (z:.k:.x:.l, astack:.Z, vstack :. vadd)-  extractStreamLast cnt stream = S.map addElm stream where-    addElm (z:.k:.x, astack, vstack) = let vadd = PA.index cnt (Z:.k:.x) in-      vadd `seq` (z:.k:.x, astack:.Z, vstack:.vadd)-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | Function with 'Scalar' return value.--instance-  ( Monad m-  ) => ExtractValue m (DIM2 -> Scalar elm) where-  type Asor (DIM2 -> Scalar elm) = Z-  type Elem (DIM2 -> Scalar elm) = elm-  extractValue cnt ij z = do-    let Scalar x = cnt ij-    x `seq` return x-  extractStream cnt stream = S.map addElm stream where-    addElm (z:.k:.x:.l, astack, vstack) = let Scalar vadd = cnt (Z:.k:.x) in-      vadd `seq` (z:.k:.x:.l, astack:.Z, vstack :. vadd)-  extractStreamLast cnt stream = S.map addElm stream where-    addElm (z:.k:.x, astack, vstack) = let Scalar vadd = cnt (Z:.k:.x) in-      vadd `seq` (z:.k:.x, astack:.Z, vstack:.vadd)-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | Function with monadic 'Scalar' return value.--instance-  ( Monad m-  ) => ExtractValue m (DIM2 -> ScalarM (m elm)) where-  type Asor (DIM2 -> ScalarM (m elm)) = Z-  type Elem (DIM2 -> ScalarM (m elm)) = elm-  extractValue cnt ij z = do-    let ScalarM x' = cnt ij-    x <- x'-    x `seq` return x-  extractStream cnt stream = S.mapM addElm stream where-    addElm (z:.k:.x:.l, astack, vstack) = do-      let ScalarM vadd' = cnt (Z:.k:.x)-      vadd <- vadd'-      vadd `seq` return (z:.k:.x:.l, astack:.Z, vstack :. vadd)-  extractStreamLast cnt stream = S.mapM addElm stream where-    addElm (z:.k:.x, astack, vstack) = do-      let ScalarM vadd' = cnt (Z:.k:.x)-      vadd <- vadd'-      vadd `seq` return (z:.k:.x, astack:.Z, vstack:.vadd)-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | This instance is a bit crazy, since the accessor is the current stream--- itself. No idea how efficient this is (need to squint at CORE), but I plan--- to use it for backtracking only.------ TODO Using this instance tends to break to optimizer ;-) -- don't use it--- yet!--instance-  ( Monad m-  ) => ExtractValue m (DIM2 -> S.Stream m elm) where-  type Asor (DIM2 -> S.Stream m elm) = S.Stream m elm-  type Elem (DIM2 -> S.Stream m elm) = elm-  extractValue cnt ij z = error "this function is not well-defined for these streams"-  extractStream cnt stream = S.flatten mk step Unknown $ stream where-    mk (z:.k:.l:.j,as,vs) = do-      let strm = cnt (Z:.k:.l)-      return (z:.k:.l:.j,as:.strm,vs)-    step (idx,as:.strm,vs) = do-      isNull <- S.null strm-      if isNull-      then return $ S.Done-      else do hd <- S.head strm-              hd `seq` return $ S.Yield (idx,as:.strm,vs:.hd) (idx,as:.S.tail strm,vs)-  extractStreamLast cnt stream = S.flatten mk step Unknown $ stream where-    mk (z:.l:.j,as,vs) = do-      let strm = cnt (Z:.l:.j)-      return (z:.l:.j,as:.strm,vs)-    step (idx,as:.strm,vs) = do-      isNull <- S.null strm-      if isNull-      then return $ S.Done-      else do hd <- S.head strm-              hd `seq` return $ S.Yield (idx,as:.strm,vs:.hd) (idx,as:.S.tail strm,vs)-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | Instance of boxed array with vector-valued cells. We assume that we want--- to store multiple results for each cell. If the intent is to store one--- scalar result, use the 'Scalar' wrapper.--instance-  ( PrimMonad m-  , Prim elm-  , VU.Unbox elm-  , PrimState m ~ s-  , DIM2 ~ sh-  ) => ExtractValue m (Z.MArr0 s sh (VU.Vector elm)) where-  type Asor (Z.MArr0 s sh (VU.Vector elm)) = Int-  type Elem (Z.MArr0 s sh (VU.Vector elm)) = elm-  extractValue cnt ij z = do-    x <- PA.readM cnt ij-    let y = x `VU.unsafeIndex` z-    y `seq` return y-  extractStream cnt stream = S.flatten mk step Unknown $ stream where-    mk (idx,as,vs) = return (idx,as:.0,vs)-    step (z:.k:.l:.j,as:.a,vs) = do-      x <- PA.readM cnt (Z:.k:.l)-      case (x VU.!? a) of-        Just v  -> v `seq` return $ S.Yield (z:.k:.l:.j,as:.a,vs:.v) (z:.k:.l:.j,as:.(a+1),vs)-        Nothing -> return $ S.Done-  extractStreamLast cnt stream = S.flatten mk step Unknown $ stream where-    mk (idx,as,vs) = return (idx,as:.0,vs)-    step (z:.l:.j,as:.a,vs) = do-      x <- PA.readM cnt (Z:.l:.j)-      case (x VU.!? a) of-        Just v  -> v `seq` return $ S.Yield (z:.l:.j,as:.a,vs:.v) (z:.l:.j,as:.(a+1),vs)-        Nothing -> return $ S.Done-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}---- | vector-based cells--instance-  ( Monad m-  , Prim elm-  , VU.Unbox elm-  , DIM2 ~ sh-  ) => ExtractValue m (Z.Arr0 sh (VU.Vector elm)) where-  type Asor (Z.Arr0 sh (VU.Vector elm)) = Int-  type Elem (Z.Arr0 sh (VU.Vector elm)) = elm-  extractValue cnt ij z = do-    let x = PA.index cnt ij-    let y = x `VU.unsafeIndex` z-    y `seq` return y-  extractStream cnt stream = S.flatten mk step Unknown $ stream where-    mk (idx,as,vs) = return (idx,as:.0,vs)-    step (z:.k:.l:.j,as:.a,vs) = do-      let x = PA.index cnt (Z:.k:.l)-      case (x VU.!? a) of-        Just v  -> v `seq` return $ S.Yield (z:.k:.l:.j,as:.a,vs:.v) (z:.k:.l:.j,as:.(a+1),vs)-        Nothing -> return $ S.Done-  extractStreamLast cnt stream = S.flatten mk step Unknown $ stream where-    mk (idx,as,vs) = return (idx,as:.0,vs)-    step (z:.l:.j,as:.a,vs) = do-      let x = PA.index cnt (Z:.l:.j)-      case (x VU.!? a) of-        Just v  -> v `seq` return $ S.Yield (z:.l:.j,as:.a,vs:.v) (z:.l:.j,as:.(a+1),vs)-        Nothing -> return $ S.Done-  {-# INLINE extractValue #-}-  {-# INLINE extractStream #-}-  {-# INLINE extractStreamLast #-}----- * Apply function 'f' with arguments on a stack 'x'.------ NOTE look at the end of this part for mkApply before writing instances by--- hand... ;-)--class Apply x where-  type Fun x :: *-  apply :: Fun x -> x--instance Apply (Z:.a -> res) where-  type Fun (Z:.a -> res) = a -> res-  apply fun (Z:.a) = fun a-  {-# INLINE apply #-}--instance Apply (Z:.a:.b -> res) where-  type Fun (Z:.a:.b -> res) = a->b -> res-  apply fun (Z:.a:.b) = fun a b-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c -> res) where-  type Fun (Z:.a:.b:.c -> res) = a->b->c -> res-  apply fun (Z:.a:.b:.c) = fun a b c-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d -> res) where-  type Fun (Z:.a:.b:.c:.d -> res) = a->b->c->d -> res-  apply fun (Z:.a:.b:.c:.d) = fun a b c d-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e -> res) where-  type Fun (Z:.a:.b:.c:.d:.e -> res) = a->b->c->d->e -> res-  apply fun (Z:.a:.b:.c:.d:.e) = fun a b c d e-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f -> res) = a->b->c->d->e->f -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f) = fun a b c d e f-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g -> res) = a->b->c->d->e->f->g -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g) = fun a b c d e f g-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h -> res) = a->b->c->d->e->f->g->h -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h) = fun a b c d e f g h-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i -> res) = a->b->c->d->e->f->g->h->i -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i) = fun a b c d e f g h i-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j -> res) = a->b->c->d->e->f->g->h->i->j -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j) = fun a b c d e f g h i j-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k -> res) = a->b->c->d->e->f->g->h->i->j->k -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k) = fun a b c d e f g h i j k-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l -> res) = a->b->c->d->e->f->g->h->i->j->k->l -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l) = fun a b c d e f g h i j k l-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m) = fun a b c d e f g h i j k l m-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n) = fun a b c d e f g h i j k l m n-  {-# INLINE apply #-}--instance Apply (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) where-  type Fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o -> res) = a->b->c->d->e->f->g->h->i->j->k->l->m->n->o -> res-  apply fun (Z:.a:.b:.c:.d:.e:.f:.g:.h:.i:.j:.k:.l:.m:.n:.o) = fun a b c d e f g h i j k l m n o-  {-# INLINE apply #-}--{--mkApply to = do-  let xs    = ['a' .. to]-  let args  = concat . (":.":) . intersperse ":." . map (:[]) $ xs-  let arga  = concat . intersperse "->" . map (:[]) $ xs-  let args' = intersperse ' ' xs-  printf "instance Apply (Z%s -> res) where\n" args-  printf "  type Fun (Z%s -> res) = %s -> res\n" args arga-  printf "  apply fun (Z%s) = fun %s\n" args args'-  printf "  {-# INLINE apply #-}\n"--}------ * helper stuff--data Box mk step xs ys = Box mk step xs ys--type Idx3 z = z:.Int:.Int:.Int--type Idx2 z = z:.Int:.Int------ * wrappers for functions instead of arrays as arguments. It can be much--- cheaper in terms of writing code to just provide a function @DIM2 -> Scalar--- a@ instead of writing instances for your data structure.--newtype Scalar a = Scalar {unScalar :: a}--newtype ScalarM a = ScalarM {unScalarM :: a}--newtype Vect a = Vect {unVect :: a}--newtype VectM a = VectM {unVectM :: a}
+ ADP/Fusion/Multi.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE UnicodeSyntax #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE TypeOperators #-}++-- | The multi-tape extension of ADPfusion. Just re-exports everything.++module ADP.Fusion.Multi+  ( module ADP.Fusion.Multi.Classes+  , module ADP.Fusion.Multi.Empty+  , module ADP.Fusion.Multi.GChr+  , module ADP.Fusion.Multi.None+  ) where++import ADP.Fusion.Multi.Classes+import ADP.Fusion.Multi.None+import ADP.Fusion.Multi.GChr+import ADP.Fusion.Multi.Empty++++{-+type instance TermOf (Term ts (ZeroOne r xs)) = TermOf ts :. Maybe r++instance+  ( TermValidIndex ts is+  ) => TermValidIndex (Term ts (ZeroOne r xs)) (is:.PointL) where+  termDimensionsValid (ts:!ZeroOne (gchr)) = termDimensionsValid (ts:!gchr)+  {-+  getTermParserRange (ts:!+  -}+++++-- The experimental zero/one wrapper++instance+  ( Monad m+  , TermElm m ts is+  ) => TermElm m (Term ts (ZeroOne r xs)) (is:.PointL) where+  termStream (ts:!(ZeroOne (GChr f xs))) (io:.o) (is:.ij@(PointL(i:.j)))+    = doubleStream+    . termStream (ts:!GChr f xs) (io:.o) (is:.ij)+    where+      {-# INLINE doubleStream #-}+      doubleStream (S.Stream step sS n) = S.Stream sNew (Left sS) (2*n) where+        {-# INLINE [1] sNew #-}+        sNew (Left s) = do r <- step s+                           case r of+                             S.Yield (abc:!:(es:.e)) s' -> return $ S.Yield (abc:!:(es:.Just e)) (Right s')+                             S.Skip                  s' -> return $ S.Skip                       (Left  s')+                             S.Done                     -> return $ S.Done+        sNew (Right s) = do r <- step s+                            case r of+                              S.Yield (abc:!:(es:.e)) s' -> return $ S.Yield (abc:!:(es:.Nothing)) (Left s')+--                              S.Skip                  s' -> return $ S.Skip                        (Left s')+--                              S.Done                     -> return $ S.Done+  {-# INLINE termStream #-}+-}+++-- Empty+
+ ADP/Fusion/Multi/Classes.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeFamilies #-}++module ADP.Fusion.Multi.Classes where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import qualified Data.Vector.Fusion.Stream.Monadic as S++import ADP.Fusion.Classes++++-- | The zero-th dimension of every terminal parser.++data TermBase = T++-- | Combine a terminal parser of dimension k in @a@ with a new 1-dim parser+-- @b@ generating a parser of dimension k+1.++data Term a b = a :! b++-- | A 'termStream' extracts all terminal elements from a multi-dimensional+-- terminal symbol.++class+  ( Monad m+  ) => TermElm m t ix where+  termStream :: t -> InOut ix -> ix -> S.Stream m (ze :!: zix :!: ix) -> S.Stream m (ze :!: zix :!: ix :!: TermOf t)++-- |++type family TermOf t :: *++-- | To calculate parser ranges and index validity we need an additional type+-- class that recurses over the individual 'Term' elements.++class TermValidIndex t i where+  termDimensionsValid :: t -> ParserRange i -> i -> Bool+  getTermParserRange  :: t -> i -> ParserRange i -> ParserRange i+  termInnerOuter :: t -> i -> InOut i -> InOut i+  termLeftIndex :: t -> i -> i++++-- * The instance declarations for generic @Term a b@ data ctors.++instance Build (Term a b)++instance+  ( ValidIndex ls ix+  , TermValidIndex (Term a b) ix+  , Show ix+  , Show (ParserRange ix)+  ) => ValidIndex (ls :!: Term a b) ix where+  validIndex (ls :!: t) abc ix =+    termDimensionsValid t abc ix && validIndex ls abc ix+  {-# INLINE validIndex #-}+  getParserRange (ls :!: t) ix = getTermParserRange t ix (getParserRange ls ix)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls ix+  ) => Elms (ls :!: Term a b) ix where+    data Elm (ls :!: Term a b) ix = ElmTerm !(Elm ls ix) !(TermOf (Term a b)) !ix+    type Arg (ls :!: Term a b) = Arg ls :. (TermOf (Term a b))+    getArg !(ElmTerm ls x _) = getArg ls :. x+    getIdx !(ElmTerm _ _ idx) = idx+    {-# INLINE getArg #-}+    {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls ix+  , MkStream m ls ix+  , TermElm m (Term a b) ix+  , TermValidIndex (Term a b) ix+  ) => MkStream m (ls :!: Term a b) ix where+  mkStream !(ls :!: t) !io !ij+    = S.map (\(s:!:Z:!:zij:!:e) -> ElmTerm s e zij)+    $ termStream t io ij+    $ S.map (\s -> (s :!: Z :!: getIdx s))+    $ mkStream ls (termInnerOuter t ij io) (termLeftIndex t ij)+  {-# INLINE mkStream #-}++++-- * Terminal stream of 'TermBase' with index 'Z'++type instance TermOf TermBase = Z++instance+  ( Monad m+  ) => TermElm m (TermBase) Z where+  termStream T _ Z = S.map (\(zs:!:zix:!:Z) -> (zs:!:zix:!:Z:!:Z))+  {-# INLINE termStream #-}++instance TermValidIndex TermBase Z where+  termDimensionsValid T Z Z = True+  getTermParserRange  T Z Z = Z+  termInnerOuter T Z Z = Z+  termLeftIndex T Z = Z+  {-# INLINE termDimensionsValid #-}+  {-# INLINE getTermParserRange #-}+  {-# INLINE termInnerOuter #-}+  {-# INLINE termLeftIndex #-}+
+ ADP/Fusion/Multi/Empty.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}++module ADP.Fusion.Multi.Empty where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import qualified Data.Vector.Fusion.Stream.Monadic as S++import Data.Array.Repa.Index.Points++import ADP.Fusion.Classes+import ADP.Fusion.Empty+import ADP.Fusion.Multi.Classes++++type instance TermOf (Term ts Empty) = TermOf ts :. ()++instance+  ( Monad m+  , TermElm m ts is+  ) => TermElm m (Term ts Empty) (is:.PointL) where+  termStream (ts:!Empty) (io:.Outer) (is:.ij@(PointL(i:.j))) =+    S.map (\(zs:!:(zix:.kl):!:zis:!:e) -> (zs:!:zix:!:(zis:.kl):!:(e:.())))+    . termStream ts io is+    . S.map (\(zs:!:zix:!:(zis:.kl)) -> (zs:!:(zix:.kl):!:zis))+  {-# INLINE termStream #-}++instance+  ( TermValidIndex ts is+  ) => TermValidIndex (Term ts Empty) (is:.PointL) where+  termDimensionsValid (ts:!Empty) (prs:.(a:!:b:!:c)) (is:.PointL(i:.j))+    = termDimensionsValid ts prs is+  getTermParserRange (ts:!Empty) (is:._) (prs:.(a:!:b:!:c))+    = getTermParserRange ts is prs :. (a:!:b:!:c)+  termInnerOuter (ts:!_) (is:._) (ios:.io) = termInnerOuter ts is ios :. io+  termLeftIndex  (ts:!_) (is:.ij) = termLeftIndex ts is :. ij+  {-# INLINE termDimensionsValid #-}+  {-# INLINE getTermParserRange #-}+  {-# INLINE termInnerOuter #-}+  {-# INLINE termLeftIndex #-}+
+ ADP/Fusion/Multi/GChr.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}++module ADP.Fusion.Multi.GChr where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Generic as VG++import Data.Array.Repa.Index.Points+import Data.Array.Repa.Index.Subword++import ADP.Fusion.Chr+import ADP.Fusion.Classes+import ADP.Fusion.Multi.Classes+++type instance TermOf (Term ts (GChr r xs)) = TermOf ts :. r++++-- * Multi-dim 'Subword's.++-- TODO we want to evaluate @f xs $ j-1@ just once before the stream is+-- generated. Unfortunately, this will evaluate cases like index (-1) as well,+-- which leads to crashes. The code below is safe but slower. We should+-- incorporate a version that performs and @outerCheck@ in the code.++instance+  ( Monad m+  , TermElm m ts is+  ) => TermElm m (Term ts (GChr r xs)) (is:.Subword) where+  termStream (ts :! GChr f xs) (io:.Outer) (is:.ij@(Subword(i:.j)))+    = S.map (\(zs :!: (zix:.kl) :!: zis :!: e) -> (zs :!: zix :!: (zis:.subword (j-1) j) :!: (e:.(f xs $ j-1))))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  termStream (ts :! GChr f xs) (io:.Inner _ _) (is:.ij)+    = S.map (\(zs :!: (zix:.kl@(Subword(k:.l))) :!: zis :!: e) -> let dta = f xs l in dta `seq` (zs :!: zix :!: (zis:.subword l (l+1)) :!: (e:.dta)))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  {-# INLINE termStream #-}++instance+  ( TermValidIndex ts is+  ) => TermValidIndex (Term ts (GChr r xs)) (is:.Subword) where+  termDimensionsValid (ts:!GChr _ xs) (prs:.(a:!:b:!:c)) (is:.Subword(i:.j))+    = i>=a && j<=VG.length xs -c && i+b<=j && termDimensionsValid ts prs is+  getTermParserRange (ts:!GChr _ _) (is:._) (prs:.(a:!:b:!:c))+    = getTermParserRange ts is prs :. (a:!:b+1:!:max 0 (c-1))+  termInnerOuter (ts:!_) (is:._) (ios:.io) = termInnerOuter ts is ios :. io+  termLeftIndex  (ts:!_) (is:.Subword (i:.j)) = termLeftIndex ts is :. subword i (j-1)+  {-# INLINE termDimensionsValid #-}+  {-# INLINE getTermParserRange #-}+  {-# INLINE termInnerOuter #-}+  {-# INLINE termLeftIndex #-}++++-- * Multi-dim 'PointL's++-- | NOTE This instance is currently the only one using an "inline outer+-- check". If This behaves well, it could be possible to put checks for valid+-- indices inside the outerCheck function. (Currently disabled, as the compiler+-- chokes on four-way alignments).++instance+  ( Monad m+  , TermElm m ts is+  ) => TermElm m (Term ts (GChr r xs)) (is:.PointL) where+  termStream (ts :! GChr f xs) (io:.Outer) (is:.ij@(PointL(i:.j)))+    -- = outerCheck (j>0)+    -- . let dta = (f xs $ j-1) in dta `seq` S.map (\(zs :!: (zix:.kl) :!: zis :!: e) -> (zs :!: zix :!: (zis:.pointL (j-1) j) :!: (e:.dta)))+    = S.map (\(zs :!: (zix:.kl) :!: zis :!: e) -> (zs :!: zix :!: (zis:.pointL (j-1) j) :!: (e:.(f xs $ j-1))))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  termStream (ts :! GChr f xs) (io:.Inner _ _) (is:.ij)+    = S.map (\(zs :!: (zix:.kl@(PointL(k:.l))) :!: zis :!: e) -> let dta = f xs l in dta `seq` (zs :!: zix :!: (zis:.pointL l (l+1)) :!: (e:.dta)))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  {-# INLINE termStream #-}++-- TODO auto-generated, check correctness++instance+  ( TermValidIndex ts is+  ) => TermValidIndex (Term ts (GChr r xs)) (is:.PointL) where+  termDimensionsValid (ts:!GChr _ xs) (prs:.(a:!:b:!:c)) (is:.PointL(i:.j))+    = {- i>=a && j<=VG.length xs -c && i+b<=j && -} termDimensionsValid ts prs is+  getTermParserRange (ts:!GChr _ _) (is:._) (prs:.(a:!:b:!:c))+    = getTermParserRange ts is prs :. (a:!:b+1:!:max 0 (c-1))+  termInnerOuter (ts:!_) (is:._) (ios:.io) = termInnerOuter ts is ios :. io+  termLeftIndex  (ts:!_) (is:.PointL (i:.j)) = termLeftIndex ts is :. pointL i (j-1)+  {-# INLINE termDimensionsValid #-}+  {-# INLINE getTermParserRange #-}+  {-# INLINE termInnerOuter #-}+  {-# INLINE termLeftIndex #-}+
+ ADP/Fusion/Multi/None.hs view
@@ -0,0 +1,52 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}++module ADP.Fusion.Multi.None where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import qualified Data.Vector.Fusion.Stream.Monadic as S++import Data.Array.Repa.Index.Points++import ADP.Fusion.Classes+import ADP.Fusion.Multi.Classes+import ADP.Fusion.None++++type instance TermOf (Term ts None) = TermOf ts :. ()++instance+  ( Monad m+  , TermElm m ts is+  ) => TermElm m (Term ts None) (is:.PointL) where+  termStream (ts :! None) (io:.Outer) (is:.ij@(PointL(i:.j))) =+    S.map (\(zs :!: (zix:.kl) :!: zis :!: e) -> (zs :!: zix :!: (zis:.kl) :!: (e:.())))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  termStream (ts :! None) (io:.Inner _ _) (is:.ij)+    = S.map (\(zs :!: (zix:.kl) :!: zis :!: e) -> (zs :!: zix :!: (zis:.kl) :!: (e:.())))+    . termStream ts io is+    . S.map (\(zs :!: zix :!: (zis:.kl)) -> (zs :!: (zix:.kl) :!: zis))+  {-# INLINE termStream #-}++-- TODO auto-gen'ed++instance+  ( TermValidIndex ts is+  ) => TermValidIndex (Term ts None) (is:.PointL) where+  termDimensionsValid (ts:!None) (prs:.(a:!:b:!:c)) (is:.PointL(i:.j))+    = termDimensionsValid ts prs is+  getTermParserRange (ts:!None) (is:._) (prs:.(a:!:b:!:c))+    = getTermParserRange ts is prs :. (a:!:b:!:c)+  termInnerOuter (ts:!_) (is:._) (ios:.io) = termInnerOuter ts is ios :. io+  termLeftIndex  (ts:!_) (is:.ij) = termLeftIndex ts is :. ij+  {-# INLINE termDimensionsValid #-}+  {-# INLINE getTermParserRange #-}+  {-# INLINE termInnerOuter #-}+  {-# INLINE termLeftIndex #-}+
+ ADP/Fusion/None.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.None where++import Data.Array.Repa.Index+import Data.Strict.Maybe+import Data.Strict.Tuple+import Prelude hiding (Maybe(..))+import qualified Data.Vector.Fusion.Stream.Monadic as S++import Data.Array.Repa.Index.Subword++import ADP.Fusion.Classes++++data None = None++none = None+{-# INLINE none #-}++-- None is always valid++instance+  ( ValidIndex ls Subword+  ) => ValidIndex (ls :!: None) Subword where+    validIndex (ls:!:None) abc ij@(Subword (i:.j)) = validIndex ls abc ij+    {-# INLINE validIndex #-}++instance Build None++instance+  ( Elms ls Subword+  ) => Elms (ls :!: None) Subword where+  data Elm (ls :!: None) Subword = ElmNone !(Elm ls Subword) !() !Subword+  type Arg (ls :!: None) = Arg ls :. ()+  getArg !(ElmNone ls () _) = getArg ls :. ()+  getIdx !(ElmNone _ _ i)   = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:None) Subword where+  mkStream !(ls:!:None) Outer !ij@(Subword (i:.j))+    = S.map (\s -> ElmNone s () (subword i j))+    $ S.filter (\_ -> i==j)+    $ mkStream ls Outer ij+  {-# INLINE mkStream #-}+
ADP/Fusion/QuickCheck.hs view
@@ -1,185 +1,531 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} --- | QuickCheck properties for a number of ADPfusion combinators. Each test is--- once written using ADPfusion and once using list comprehensions. Typing--- @allProps@ in ghci will run all tests, prefixed @prop_@ with a thousand--- tests each.- module ADP.Fusion.QuickCheck where -import Data.List-import Data.Vector.Fusion.Stream.Size-import Data.Vector.Fusion.Util+import Control.Monad+import Control.Applicative+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import Data.Array.Repa.Arbitrary+import Debug.Trace import qualified Data.Vector.Fusion.Stream as S+import qualified Data.Vector.Fusion.Stream.Monadic as SM import qualified Data.Vector.Unboxed as VU import Test.QuickCheck import Test.QuickCheck.All+import Test.QuickCheck.Monadic+import Data.List ((\\))+import System.IO.Unsafe -import "PrimitiveArray" Data.Array.Repa.Index+import Data.Array.Repa.Index.Subword+import Data.Array.Repa.Index.Point+import Data.Array.Repa.Index.Points+import qualified Data.PrimitiveArray as PA+import qualified Data.PrimitiveArray.Zero as PA -import ADP.Fusion.QuickCheck.Arbitrary-import qualified ADP.Fusion as F-import qualified ADP.Fusion.Monadic as M-import qualified ADP.Fusion.Monadic.Internal as F+import ADP.Fusion+import ADP.Fusion.Table+import ADP.Fusion.Multi  +-- | Check if a single region returns the correct result (namely a slice from+-- the input). -options = stdArgs {maxSuccess = 1000}+prop_R sw@(Subword (i:.j)) = zs == ls where+  zs = id <<< region xs ... S.toList $ sw+  ls = [VU.slice i (j-i) xs | i>=0, j<=100] -customCheck = quickCheckWithResult options+-- | Two regions next to each other. -allProps = $forAllProperties customCheck+prop_RR sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< region xs % region xs ... S.toList $ sw+  ls = [(VU.slice i (k-i) xs, VU.slice k (j-k) xs) | k <- [i..j]] +-- | And finally, three regions (with smaller subword sizes only) +prop_RRR sw@(Subword (i:.j)) = (j-i<=30) ==> zs == ls where+  zs = (,,) <<< region xs % region xs % region xs ... S.toList $ sw+  ls = [  ( VU.slice i (k-i) xs+          , VU.slice k (l-k) xs+          , VU.slice l (j-l) xs+          ) | k <- [i..j], l <- [k..j]] --- * Some definitions:------ @O@ means one--- @M@ means many--- @P@ means one or more--- @ML_x_y@ is for a makeLeftCombinator with boundaries x and y+-- | Three sized regions (with smaller subword sizes only) --- ** @xs -~+ ys@, size @xs@ = 1, size @ys@ >= 1.+prop_SSS sw@(Subword (i:.j)) = zs == ls where+  zs = (,,) <<< sregion 3 10 xs % sregion 3 10 xs % sregion 3 10 xs ... S.toList $ sw+  ls = [  ( VU.slice i (k-i) xs+          , VU.slice k (l-k) xs+          , VU.slice l (j-l) xs+          ) | k <- [i..j], l <- [k..j], minimum [k-i,l-k,j-l] >=3, maximum [k-i,l-k,j-l] <= 10] -fOP (i,j) = S.toList $ (,) F.<<< fRegion F.-~+ fRegion F.... id $ Z:.i:.j+-- | Single-character parser. -lOP (i,j) = [ ((i,i+1), (i+1,j)) | i+1<=j-1 ]+prop_C sw@(Subword (i:.j)) = zs == ls where+  zs = id <<< chr xs ... S.toList $ sw+  ls = [xs VU.! i | i+1==j, i>=0, j<=100] -prop_OP = fOP === lOP+-- | 2x Single-character parser. --- ** @xs -~~ ys -~~ zs@, size @xs@ = 1, size @ys@ = 1, size @zs@ >= 0.+prop_CC sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< chr xs % chr xs ... S.toList $ sw+  ls = [(xs VU.! i, xs VU.! (i+1)) | i+2==j] -fOOP (i,j) = S.toList $ (,,) F.<<< fRegion F.-~~ fRegion F.-~~ fRegion F.... id $ Z:.i:.j+-- ** Single character plus peeking -lOOP (i,j) = [ ( (i,i+1), (i+1,i+2), (i+2,j) ) | i+2<=j ]+prop_PlC sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< peekL xs % chr xs ... S.toList $ sw+  ls = [(xs VU.! (j-2), xs VU.! (j-1)) | j>1, i+1==j] -prop_OOP = fOOP === lOOP+prop_PrC sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< peekR xs % chr xs ... S.toList $ sw+  ls = [(xs VU.! (j-1), xs VU.! (j-1)) | i+1==j] --- ** @xs +~- ys@, size @xs@ >= 1, size @ys@ = 1.+prop_CPr sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< chr xs % peekR xs ... S.toList $ sw+  ls = [(xs VU.! (j-1), xs VU.! j) | i>=0, j<=99,i+1==j] -fPO (i,j) = S.toList $ (,) F.<<< fRegion F.+~- fRegion F.... id $ Z:.i:.j+prop_CPl sw@(Subword (i:.j)) = zs == ls where+  zs = (,) <<< chr xs % peekL xs ... S.toList $ sw+  ls = [(xs VU.! (j-1), xs VU.! (j-1)) | i+1==j] -lPO (i,j) = [ ( (i,j-1), (j-1,j) ) | i+1<=j-1 ]+-- | 2x Single-character parser bracketing a single region. -prop_PO (Small i, Small j) = fPO (i,j) == lPO (i,j)+prop_CRC sw@(Subword (i:.j)) = zs == ls+  where+    zs = (,,) <<< chr xs % region xs % chr xs ... S.toList $ sw+    ls = [(xs VU.! i, VU.slice (i+1) (j-i-2) xs , xs VU.! (j-1)) |i+2<=j] --- ** @xs -~+ ys +~- zs@, size @xs@ = 1, size @ys@ >= 1, size @zs@ = 1. This is--- a "hairpin" in RNA bioinformatics.+-- | 2x Single-character parser bracketing regions. -fOPO (i,j) = S.toList $ (,,) F.<<< fRegion F.-~+ fRegion F.+~- fRegion F.... id $ Z:.i:.j+prop_CRRC sw@(Subword (i:.j)) = zs == ls+  where+    zs = (,,,) <<< chr xs % region xs % region xs % chr xs ... S.toList $ sw+    ls = [ ( xs VU.! i+           , VU.slice (i+1) (k-i-1) xs+           , VU.slice k (j-k-1) xs+           , xs VU.! (j-1)+           ) | k <- [i+1 .. j-1]] -lOPO (i,j) = [ ( (i,i+1), (i+1,j-1), (j-1,j) ) | i+2<=j, i+1<j-1 ]+-- | complex behaviour with characters and regions -prop_OPO = fOPO === lOPO+prop_CRCRC sw@(Subword (i:.j)) = zs == ls where+  zs = (,,,,) <<< chr xs % region xs % chr xs % region xs % chr xs ... S.toList $ sw+  ls = [ ( xs VU.! i+         , VU.slice (i+1) (k-i-1) xs+         , xs VU.! k+         , VU.slice (k+1) (j-k-2) xs+         , xs VU.! (j-1)+         ) | k <- [i+1 .. j-2] ] --- ** The central region is non-empty, with two size-1 regions on each side.--- Will create @O(n)@ candidates, which will all fail, except for the last one--- (if @j-i@ is large enough).+-- | Interior-loop like structures. -fOOPOOslow (i,j) = S.toList $ (,,,,) F.<<< fRegion F.-~+ fRegion F.-~+ fRegion F.+~+ fRegion F.-~- fRegion F.... id $ Z:.i:.j+prop_Interior1 sw@(Subword (i:.j)) = zs == ls where+  zs = (,,) <<< chr xs % peekR xs % sregion 1 5 xs ... S.toList $ sw+  ls = [ ( xs VU.! i+         , xs VU.! (i+1)+         , VU.slice (i+1) (j-i-1) xs+         ) | j-i>=2, j-i<=6+       ] -lOOPOO (i,j) = [ ( (i,i+1), (i+1,i+2), (i+2,j-2), (j-2,j-1), (j-1,j) ) | i+4<=j, i+2<j-2 ]+prop_Interior2 sw@(Subword (i:.j)) = zs == ls where+  zs = (,,,,) <<< chr xs % peekR xs % sregion 1 5 xs % peekR xs % sregion 2 5 xs ... S.toList $ sw+  ls = [ ( xs VU.! i+         , xs VU.! (i+1)+         , VU.slice (i+1) (k-i-1) xs+         , xs VU.! k+         , VU.slice k (j-k) xs+         ) | j-i>=4, j-i<=11, k <- [i+2 .. (min j $ i+6)], j-k>=2, j-k<=5+       ] -prop_OOPOOslow = fOOPOOslow === lOOPOO+prop_Interior3 sw@(Subword (i:.j)) = zs == ls where+  zs = (,,,,,,) <<< chr xs % peekR xs % sregion 1 5 xs % peekR xs % sregion 2 5 xs % peekL xs % sregion 1 5 xs ... S.toList $ sw+  ls = [ ( xs VU.! i+         , xs VU.! (i+1)+         , VU.slice (i+1) (k-i-1) xs+         , xs VU.! k+         , VU.slice k (l-k) xs+         , xs VU.! (l-1)+         , VU.slice l (j-l) xs+         ) | i>= 0+           , j<= 100+           , k <- [i..j]+           , l <- [k..j]+           , j-i>=5, j-i<=16+           , k-i-1>=1, k-i-1<=5+           , l-k>=2, l-k<=5+           , j-l>=1, j-l<=5+       ] --- ** The above test can be sped up by the use of the @+~--@ combinator. It--- fixes the left and right side, by allowing only exactly size two on its--- right. Each combinator here will 'Yield' exactly once, then be 'Done'.+prop_Interior4 sw@(Subword (i:.j)) = zs == ls where+  zs = (,,,,,,,,) <<< chr xs % peekR xs % sregion 1 5 xs % peekR xs % sregion 2 5 xs % peekL xs % sregion 1 5 xs % peekL xs % chr xs ... S.toList $ sw+  ls = [ ( xs VU.! i+         , xs VU.! (i+1)+         , VU.slice (i+1) (k-i-1) xs+         , xs VU.! k+         , VU.slice k (l-k) xs+         , xs VU.! (l-1)+         , VU.slice l (j-l-1) xs+         , xs VU.! (j-2)+         , xs VU.! (j-1)+         ) | k <- [i..j]+           , l <- [k..j]+           , j-i>=6, j-i<=17+           , k-i-1>=1, k-i-1<=5+           , l-k>=2, l-k<=5+           , j-l-1>=1, j-l-1<=5+       ] -fOOPOOfast (i,j) = S.toList $ (,,,,) F.<<< fRegion F.-~+ fRegion F.-~+ fRegion F.+~-- fRegion F.-~- fRegion F.... id $ Z:.i:.j+prop_Interior5 sw@(Subword (i:.j)) = zs == ls where+  zs = (,,,,,,,,,,) <<< peekL xs % chr xs % peekR xs % sregion 1 5 xs % peekR xs % sregion 2 5 xs % peekL xs % sregion 1 5 xs % peekL xs % chr xs % peekR xs ... S.toList $ sw+  ls = [ ( xs VU.! (i-1)+         , xs VU.! i+         , xs VU.! (i+1)+         , VU.slice (i+1) (k-i-1) xs+         , xs VU.! k+         , VU.slice k (l-k) xs+         , xs VU.! (l-1)+         , VU.slice l (j-l-1) xs+         , xs VU.! (j-2)+         , xs VU.! (j-1)+         , xs VU.! j+         ) | i>= 1+           , j<= 99+           , k <- [i..j]+           , l <- [k..j]+           , i>0, j-1 < VU.length xs+           , j-i>=6, j-i<=17+           , k-i-1>=1, k-i-1<=5+           , l-k>=2, l-k<=5+           , j-l-1>=1, j-l-1<=5+       ] -prop_OOPOOfast = fOOPOOfast === lOOPOO+-- | A single mutable table should return one result. --- ** A complex right-hand side which was problematic in 0.0.0.3 of ADPfusion.--- In original ADP @base -~~ weak ~~- base +~+ string@ we want the @base@ parts--- to have size 1, @weak@ of any size, and @string@ to be non-empty. In--- ADPfusion @as -~+ bs@ means that @as@ has size one, @bs@ size 1 or more.+prop_Mt sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: PA.MutArr IO (PA.Unboxed (Z:.Subword) Int) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw EmptyT mxs+    zs <- run $ id <<< mt ... SM.toList $ sw+    ls <- run $ sequence $ [(PA.readM mxs (Z:.sw)) | i<=j]+    assert $ zs == ls -fOPOP (i,j) = S.toList $ (,,,) F.<<< fRegion F.-~+ fRegion F.+~+ fRegion F.-~+ fRegion F.... id $ Z:.i:.j+-- | table, then character. -lOPOP (i,j) = [ ( (i,i+1), (i+1,k), (k,k+1), (k+1,j) ) | k <- [i+1 .. j-2], i+1<k, k+1<j ]+prop_MtC sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int)) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw EmptyT mxs+    zs <- run $ (,) <<< mt % chr xs ... SM.toList $ sw+    ls <- run $ sequence $ [(PA.readM mxs (Z:.subword i (j-1))) >>= \a -> return (a,xs VU.! (j-1)) | i<j]+    assert $ zs == ls -prop_OPOP = fOPOP === lOPOP+-- | Character, then table. --- ** One more of those complex right-hand sides. This one is already rather--- complicated. We have @one -~+ one -~+ many +~+ one -~~ one -~+ plus@ where--- @one@ has size 1, many has size 0 to many, plus has size 1 to many. The last--- combinator @-~+@ again short-curcuits by being 'Done' once the left-hand--- side is larger than one.+prop_CMt sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int)) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw EmptyT mxs+    zs <- run $ (,) <<< chr xs % mt ... SM.toList $ sw+    ls <- run $ sequence $ [(PA.readM mxs (Z:.subword (i+1) j)) >>= \a -> return (xs VU.! i,a) | i<j]+    assert $ zs == ls -fOOPOOP (i,j) = S.toList $ (,,,,,) F.<<< fRegion F.-~+ fRegion F.-~+ fRegion F.+~+ fRegion F.-~~ fRegion F.-~+ fRegion F.... id $ Z:.i:.j+-- | Two mutable tables. Basically like Region's. -lOOPOOP (i,j) = [ ( (i,i+1), (i+1,i+2), (i+2,k), (k,k+1), (k+1,k+2), (k+2,j) ) | k <- [i+2 .. j-3], i+2<k, k+2<j ]+prop_MtMt sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int)) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw EmptyT mxs+    zs <- run $ (,) <<< mt % mt ... SM.toList $ sw+    ls <- run $ sequence $ [(PA.readM mxs (Z:.subword i k)) >>= \a -> PA.readM mxs (Z:.subword k j) >>= \b -> return (a,b) | k <- [i..j]]+    assert $ zs == ls -prop_OOPOOP = fOOPOOP === lOOPOOP+-- | Just to make it more interesting, sprinkle in some 'Chr' symbols. --- ** We now introduce two independently moving indices and size zero regions.+prop_CMtCMtC sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int)) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw EmptyT mxs+    zs <- run $ (,,,,) <<< chr xs % mt % chr xs % mt % chr xs ... SM.toList $ sw+    ls <- run $ sequence $ [ (PA.readM mxs (Z:.subword (i+1) k)) >>=+                            \a -> PA.readM mxs (Z:.subword (k+1) (j-1)) >>=+                            \b -> return ( xs VU.! i+                                         , a+                                         , xs VU.! k+                                         , b+                                         , xs VU.! (j-1)+                                         )+                           | k <- [i+1..j-2]]+    assert $ zs == ls -fMMM (i,j) = S.toList $ (,,) F.<<< fRegion F.~~~ fRegion F.~~~ fRegion F.... id $ Z:.i:.j+-- | And now with non-empty tables. -lMMM (i,j) = [ ( (i,k), (k,l), (l,j) ) | k <- [i..j], l<-[k..j] ]+prop_CMnCMnC sw@(Subword (i:.j)) = monadicIO $ do+    mxs :: (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int)) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ] -- (1 :: Int)+    let mt = mTblSw NonEmptyT mxs+    zs <- run $ (,,,,) <<< chr xs % mt % chr xs % mt % chr xs ... SM.toList $ sw+    ls <- run $ sequence $ [ (PA.readM mxs (Z:.subword (i+1) k)) >>=+                            \a -> PA.readM mxs (Z:.subword (k+1) (j-1)) >>=+                            \b -> return ( xs VU.! i+                                         , a+                                         , xs VU.! k+                                         , b+                                         , xs VU.! (j-1)+                                         )+                           | k <- [i+2..j-3]]+    assert $ zs == ls -prop_MMM = fMMM === lMMM+{-+ - Currently not allowing 0-dim multi-tapes. --- ** Three independent regions, each one enclosed by two size-1 regions.--- Compile-time hog.+prop_Tt ix@Z = zs == ls where+  zs = id <<< T ... S.toList $ ix+  ls = [ Z ]+-} -fOPOOPOOPO (i,j) = S.toList $ (,,,,,,,,) F.<<< fRegion F.-~+ fRegion F.+~+ fRegion F.-~+-                                          {--} fRegion F.-~+ fRegion F.+~+ fRegion F.-~+-                                          {--} fRegion F.-~+ fRegion F.+~- fRegion F.... id $ Z:.i:.j+-- ** -lOPOOPOOPO (i,j) = [ ( (i,i+1), (i+1,k), (k,k+1), {--} (k+1,k+2), (k+2,l), (l,l+1), {--} (l+1,l+2), (l+2,j-1), (j-1,j) )-                   | k<-[i+1 .. j-5], l<-[k+2 .. j-3], i+1<k, k+2<l, l+2<j-1 ]+prop_Tc ix@(Z:.Subword(i:.j)) = zs == ls where+  zs = id <<< (T:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i) | i>=0, j<= 100, i+1==j ] -prop_OPOOPOOPO = fOPOOPOOPO === lOPOOPOOPO+prop_Tcc ix@(Z:.Subword(i:.j):.Subword(k:.l)) = zs == ls where+  zs = id <<< (T:!chr xs:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i:.xs VU.! k) | i>=0, j<=100, k>=0, j<=100, i+1==j, k+1==l ] --- ** Two non-empty regions, the right one with single-size regions around it.--- (sorry about the name)+-- ** -fPOPO (i,j) = S.toList $ (,,,) F.<<< fRegion F.+~+ fRegion F.-~+ fRegion F.+~- fRegion F.... id $ Z:.i:.j+prop_TcTc ix@(Z:.Subword(i:.j)) = zs == ls where+  zs = (,) <<< (T:!chr xs) % (T:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i,Z:.xs VU.! (i+1)) | i>=0, j<= 100, i+2==j ] -lPOPO (i,j) = [ ( (i,k), (k,k+1), (k+1,j-1), (j-1,j) ) | k <- [i+1 .. j-3] ]+prop_TccTcc ix@(Z:.Subword(i:.j):.Subword(k:.l)) = zs == ls where+  zs = (,) <<< (T:!chr xs:!chr xs) % (T:!chr xs:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i:.xs VU.! k, Z:.xs VU.! (i+1):.xs VU.! (k+1)) | i>=0, j<=100, k>=0, j<=100, i+2==j, k+2==l ] -prop_POPO (Small i, Small j) = fPOPO (i,j) == lPOPO (i,j)+-- ** --- ** Sanity-checking special constraints.+prop_Mt2 ix@(Z:.Subword(i:.j)) = monadicIO $ do+  mxs :: PA.MutArr IO (PA.Unboxed (Z:.Subword) Int) <- run $ PA.fromListM (Z:.subword 0 0) (Z:.subword 0 100) [0 ..]+  let mt = mTbl (Z:.EmptyT) mxs -- :: MTbl (Z:.Subword) (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int))+  zs <- run $ id <<< mt ... SM.toList $ ix+  ls <- run $ sequence $ [ (PA.readM mxs (Z:.subword i j)) | i>=0, j<=100, i<=j ]+  assert $ zs == ls -fOO (i,j) = S.toList $ (,) F.<<< fRegion F.-~- fRegion F.... id $ Z:.i:.j+prop_MtMt2 ix@(Z:.Subword(i:.j)) = monadicIO $ do+  mxs :: PA.MutArr IO (PA.Unboxed (Z:.Subword) Int) <- run $ PA.fromListM (Z:.subword 0 0) (Z:.subword 0 100) [0 ..]+  let mt = mTbl (Z:.EmptyT) mxs -- :: MTbl (Z:.Subword) (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int))+  zs <- run $ (,) <<< mt % mt ... SM.toList $ ix+  ls <- run $ sequence $ [ liftM2 (,) (PA.readM mxs (Z:.subword i k)) (PA.readM mxs (Z:.subword k j)) | i>=0, j<=100, k<-[i..j] ]+  assert $ zs == ls -lOO (i,j) = [ ( (i,i+1), (j-1,j) ) | i+2==j ]+prop_MtMtMt2 ix@(Z:.Subword(i:.j)) = monadicIO $ do+  mxs :: PA.MutArr IO (PA.Unboxed (Z:.Subword) Int) <- run $ PA.fromListM (Z:.subword 0 0) (Z:.subword 0 100) [0 ..]+  let mt = mTbl (Z:.EmptyT) mxs -- :: MTbl (Z:.Subword) (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int))+  zs <- run $ (,,) <<< mt % mt % mt ... SM.toList $ ix+  ls <- run $ sequence $ [ liftM3 (,,) (PA.readM mxs (Z:.subword i k)) (PA.readM mxs (Z:.subword k l)) (PA.readM mxs (Z:.subword l j)) | i>=0, j<=100, k<-[i..j], l<-[k..j] ]+  assert $ zs == ls -prop_OO (Small i, Small j) = fOO (i,j) == lOO (i,j)+prop_TcMtTc ix@(Z:.Subword(i:.j)) = monadicIO $ do+  mxs :: PA.MutArr IO (PA.Unboxed (Z:.Subword) Int) <- run $ PA.fromListM (Z:.subword 0 0) (Z:.subword 0 100) [0 ..]+  let mt = mTbl (Z:.EmptyT) mxs :: MTbl (Z:.Subword) (PA.MutArr IO (PA.Unboxed (Z:.Subword) Int))+  zs <- run $ (,,) <<< (T:!chr xs) % mt % (T:!chr xs) ... SM.toList $ ix+  ls <- run $ sequence $ [ (PA.readM mxs (Z:.subword (i+1) (j-1)) >>= \z -> return (Z:.xs VU.! i,z,Z:.xs VU.! (j-1))) | i>=0, j<=100, i+2<=j ]+  assert $ zs == ls --- ** Two non-empty regions+prop_2dim ix@(Z:.TinySubword(i:.j):.TinySubword(k:.l)) = monadicIO $ do+  mxs <- run $ pure $ mxsSwSw+  let mt = mTbl (Z:.EmptyT:.EmptyT) mxs+  zs <- run $ (,) <<< mt % mt ... SM.toList $ Z:.subword i j:.subword k l+  ls <- run $ sequence $ [ liftM2 (,) (PA.readM mxs (Z:.subword i a:.subword k b)) (PA.readM mxs (Z:.subword a j:.subword b l)) | i>=0, j<=100, k>=0, l<=100, a<-[i..j], b<-[k..l] ]+  assert $ zs==ls -fPP (i,j) = S.toList $ (,) F.<<< fRegion F.+~+ fRegion F.... id $ Z:.i:.j+prop_2dimCMCMC ix@(Z:.TinySubword(i:.j):.TinySubword(k:.l)) = monadicIO $ do+  mxs <- run $ pure $ mxsSwSw -- :: PA.MutArr IO (PA.Unboxed (Z:.Subword:.Subword) Int) <- run $ PA.fromListM (Z:.subword 0 0:.subword 0 0) (Z:.subword 0 100:.subword 0 100) [0 ..]+  let mt = mTbl (Z:.EmptyT:.EmptyT) mxs+  zs <- run $ (,,,,) <<< (T:!chr xs:!chr xs) % mt % (T:!chr xs:!chr xs) % mt % (T:!chr xs:!chr xs) ... SM.toList $ Z:.subword i j:.subword k l+  ls <- run $ sequence $ [ liftM5 (,,,,) (pure $ Z:.xs VU.! i:.xs VU.! k)+                                         (PA.readM mxs (Z:.subword (i+1) a:.subword (k+1) b))+                                         (pure $ Z:.xs VU.! a:.xs VU.! b)+                                         (PA.readM mxs (Z:.subword (a+1) (j-1):.subword (b+1) (l-1)))+                                         (pure $ Z:.xs VU.! (j-1):.xs VU.! (l-1))+                         | j-i>=3, l-k>=3, i>=0, j<=100, k>=0, l<=100, a<-[i+1..j-2], b<-[k+1..l-2] ]+  assert $ zs==ls -lPP (i,j) = [ ( (i,k), (k,j) ) | k<-[i+1 .. j-1] ]+-- * working on 'PointL's -prop_PP (Small i, Small j) = fPP (i,j) == lPP (i,j)+prop_P_Tt ix@(Z:.PointL (i:.j)) = zs == ls where+  zs = id <<< (T:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i) | i+1==j ] --- ** using 'makeLeft_MinRight'+prop_P_CC ix@(Z:.PointL (i:.j)) = zs == ls where+  zs = (,) <<< (T:!chr xs) % (T:!chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! i, Z:.xs VU.! (i+1)) | i+2==j ] -fML_1_4M (i,j) = S.toList $ (,) F.<<< fRegion `ml_1_4` fRegion F.... id $ Z:.i:.j where-  infixl 9 `ml_1_4`-  ml_1_4 = F.makeLeft_MinRight (1,4) 0+prop_P_2dimCMCMC ix@(Z:.PointL(i:.j):.PointL(k:.l)) = monadicIO $ do+  mxs <- run $ pure $ mxsPP+  let mt = mTbl (Z:.EmptyT:.EmptyT) mxs+  zs <- run $ (,,,,) <<< (T:!chr xs:!chr xs) % mt % (T:!chr xs:!chr xs) % mt % (T:!chr xs:!chr xs) ... SM.toList $ ix+  ls <- run $ sequence $ [ liftM5 (,,,,) (pure $ Z:.xs VU.! i:.xs VU.! k)+                                         (PA.readM mxs (Z:.pointL (i+1) a:.pointL (k+1) b))+                                         (pure $ Z:.xs VU.! a:.xs VU.! b)+                                         (PA.readM mxs (Z:.pointL (a+1) (j-1):.pointL (b+1) (l-1)))+                                         (pure $ Z:.xs VU.! (j-1):.xs VU.! (l-1))+                         | j-i>=3, l-k>=3, i>=0, j<=100, k>=0, l<=100, a<-[i+1..j-2], b<-[k+1..l-2] ]+  assert $ zs==ls -lML_1_4M (i,j) = [ ( (i,k), (k,j) ) | k <- [i+1 .. min (i+4) j] ]+{-+prop_TcTc ix@(Z:.Point i) = {- traceShow (zs,ls) $ -} zs == ls where+  zs = (,) <<< Term (T:.Chr xs) % Term (T:.Chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! (i-2), Z:.xs VU.! (i-1)) | i>1 ] -prop_ML_1_4M = fML_1_4M === lML_1_4M+-- deriving instance Show (Elm (None :. Term (T :. Chr Int)) (Z :. Point)) --- ** using 'makeLeft_MinRight' and 'makeMinLeft_Right'. Inner regions fixed to--- be non-empty.+prop_TpTc ix@(Z:.Point i) = {- traceShow (zs,ls) $ -} zs == ls where+  zs = (,) <<< Term (T:.Peek (-1) xs) % Term (T:.Chr xs) ... S.toList $ ix+  ls = [ (Z:.f i, Z:.xs VU.! (i-1)) | i>0 ]+  f i = if i>1 then xs VU.! (i-2) else (-1) -fML_1_4MMR_1_4 (i,j) = S.toList $ (,,) F.<<< fRegion `ml_1_4` fRegion `mr_1_4` fRegion F.... id $ Z:.i:.j where-  infixl 9 `ml_1_4`-  ml_1_4 = F.makeLeft_MinRight (1,4) 1-  infixl 9 `mr_1_4`-  mr_1_4 = F.makeMinLeft_Right 1 (1,4)+prop_TcTpTc ix@(Z:.Point i) = {- traceShow (zs,ls) $ -} zs == ls where+  zs = (,,) <<< Term (T:.Chr xs) % Term (T:.Peek (-1) xs) % Term (T:.Chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! (i-2), Z:.f i, Z:.xs VU.! (i-1)) | i>1 ]+  f i = if i>1 then xs VU.! (i-2) else (-1) -lML_1_4MMR_1_4 (i,j) = [ ( (i,k), (k,l), (l,j) ) | k<-[i+1 .. min (i+4) j], l <- [max k (j-4) .. j-1], k<l ]+{-+prop_Mt_Tc ix@(Z:.Subword(i:.j)) = monadicIO $ do+    mxs :: (PA.MU IO (Z:.Subword) Int) <- run $ PA.fromListM (Z:. Subword (0:.0)) (Z:. Subword (0:.100)) [0 .. ]+    let mt = mtable mxs+    zs <- run $ (,) <<< mt % Term (T:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [(PA.readM mxs (Z:.subword i (j-1))) >>= \a -> return (a,Z:.xs VU.! (j-1)) | i<j ]+    assert $ zs == ls+-} -prop_ML_1_4MMR_1_4 = fML_1_4MMR_1_4 === lML_1_4MMR_1_4+prop_P_Mt_Tt ix@(Z:.Point i) = monadicIO $ do+    mxs :: (PA.MU IO (Z:.Point) Int) <- run $ PA.fromListM (Z:.Point 0) (Z:.Point 100) [0 .. ]+    let mt = mtable mxs+    zs <- run $ (,) <<< mt % Term (T:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [(PA.readM mxs (Z:.Point (i-1))) >>= \a -> return (a,Z:.xs VU.! (i-1)) | i>0 ]+    assert $ zs == ls++prop_P_Mt_TpTc ix@(Z:.Point i) = monadicIO $ do+    mxs :: (PA.MU IO (Z:.Point) Int) <- run $ PA.fromListM (Z:.Point 0) (Z:.Point 100) [0 .. ]+    let mt = mtable mxs+    let f i = if i>1 then xs VU.! (i-2) else (-1)+    zs <- run $ (,,) <<< mt % Term (T:.Peek (-1) xs) % Term (T:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [(PA.readM mxs (Z:.Point (i-1))) >>= \a -> return (a,Z:.f i,Z:.xs VU.! (i-1)) | i>0 ]+    assert $ zs == ls++-- | and with 2-tape grammars++prop_Tcc ix@(Z:.Subword(i:.j):.Subword(k:.l)) = zs == ls where+  zs = id <<< Term (T:.Chr xs:.Chr xs) ... S.toList $ ix+  ls = [ (  Z+         :. xs VU.! i+         :. xs VU.! k+         ) | i+1==j, k+1==l ]++prop_Mt_Tcc (Z:.TinySubword (i:.j):.TinySubword (k:.l)) = monadicIO $ do+    let ix = Z :. subword i j :. subword k l+    mxs :: (PA.MU IO (Z:.Subword:.Subword) Int) <- run $ PA.fromListM (Z:. Subword (0:.0):.Subword(0:.0)) (Z:. Subword (0:.j+1):.Subword (0:.k+1)) [0 .. ]+    let mt = mtable mxs+    zs <- run $ (,) <<< mt % Term (T:.Chr xs:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [ (PA.readM mxs (Z:.subword i (j-1):.subword k (l-1))) >>= \a -> return (a,Z:.xs VU.! (j-1):.xs VU.! (l-1)) | i<j,k<l ]+    assert $ zs == ls++prop_P_Ttt ix@(Z:.Point i:.Point j) = zs == ls where+  zs = id <<< Term (T:.Chr xs:.Chr xs) ... S.toList $ ix+  ls = [ (Z:.xs VU.! (i-1):.xs VU.! (j-1)) | i>0, j>0 ]++prop_P_Mt_Ttt ix@(Z:.Point i:.Point j) = monadicIO $ do+    mxs :: (PA.MU IO (Z:.Point:.Point) Int) <- run $ PA.fromListM (Z:.Point 0:.Point 0) (Z:.Point 100:.Point 100) [0 .. ]+    let mt = mtable mxs+    zs <- run $ (,) <<< mt % Term (T:.Chr xs:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [(PA.readM mxs (Z:.Point (i-1):.Point (j-1))) >>= \a -> return (a,Z:.xs VU.! (i-1):.xs VU.! (j-1)) | i>0,j>0 ]+    assert $ zs == ls++prop_P_Mt_Tpp_Ttt ix@(Z:.Point i:.Point j) = monadicIO $ do+    mxs :: (PA.MU IO (Z:.Point:.Point) Int) <- run $ PA.fromListM (Z:.Point 0:.Point 0) (Z:.Point 100:.Point 100) [0 .. ]+    let mt = mtable mxs+    let f i j = Z:. (if i>1 then xs VU.! (i-2) else (-1)) :. (if j>1 then xs VU.! (j-2) else (-1))+    zs <- run $ (,,) <<< mt % Term (T:.Peek (-1) xs:.Peek (-1) xs) % Term (T:.Chr xs:.Chr xs) ... SM.toList $ ix+    ls <- run $ sequence $ [(PA.readM mxs (Z:.Point (i-1):.Point (j-1))) >>= \a -> return (a,f i j,Z:.xs VU.! (i-1):.xs VU.! (j-1)) | i>0,j>0 ]+    -- traceShow (zs,ls) $+    assert $ zs == ls++-- | and with 3-tape grammars++prop_Tccc ix@(Z:.Subword(i:.j):.Subword(k:.l):.Subword(a:.b)) = zs == ls where+  zs = id <<< Term (T:.Chr xs:.Chr xs:.Chr xs) ... S.toList $ ix+  ls = [ (  Z+         :. xs VU.! i+         :. xs VU.! k+         :. xs VU.! a+         ) | i+1==j, k+1==l, a+1==b ]++-- * helper functions and stuff++-- | Helper function to create non-specialized regions++region = Region Nothing Nothing++-- |++mtable xs = MTable Eall xs++{-+-- | A subword (i,j) should always produce an index in the allowed range++prop_subwordIndex (Small n, Subword (i:.j)) = (n>j) ==> p where+  p = n * (n+1) `div` 2 >= k+  k = subwordIndex (subword 0 n) (subword i j)+-}++-}++-- | data set. Can be made fixed as the maximal subword size is statically known!++xs = VU.fromList [0 .. 99 :: Int]++--+--+--TODO will break if PrimitiveArray assertions are active (need to fixe exact length of list)++mxsSwSw = unsafePerformIO $ zzz where+  zzz :: IO (PA.MutArr IO (PA.Unboxed (Z:.Subword:.Subword) Int))+  zzz = PA.fromListM (Z:.subword 0 0:.subword 0 0) (Z:.subword 0 100:.subword 0 100) [0 ..]++mxsPP = unsafePerformIO $ zzz where+  zzz :: IO (PA.MutArr IO (PA.Unboxed (Z:.PointL:.PointL) Int))+  zzz = PA.fromListM (Z:.pointL 0 0:.pointL 0 0) (Z:.pointL 0 100:.pointL 0 100) [0 ..]++-- * general quickcheck stuff++options = stdArgs {maxSuccess = 1000}++customCheck = quickCheckWithResult options++allProps = $forAllProperties customCheck++++newtype Small = Small Int+  deriving (Show)++instance Arbitrary Small where+  arbitrary = Small <$> choose (0,100)+  shrink (Small i) = Small <$> shrink i++newtype TinySubword = TinySubword (Int:.Int)+  deriving (Show)++instance Arbitrary TinySubword where+  arbitrary = do a <- choose (0,20)+                 b <- choose (0,20)+                 return $ TinySubword $ min a b :. max a b+  shrink (TinySubword (a:.b)) = [TinySubword (a:.b-1) | a<b]++instance Arbitrary z => Arbitrary (z:.TinySubword) where+  arbitrary = (:.) <$> arbitrary <*> arbitrary+  shrink (z:.s) = (:.) <$> shrink z <*> shrink s+ 
− ADP/Fusion/QuickCheck/Arbitrary.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE PackageImports #-}--module ADP.Fusion.QuickCheck.Arbitrary where--import Test.QuickCheck-import Test.QuickCheck.All--import "PrimitiveArray" Data.Array.Repa.Index--import qualified ADP.Fusion.Monadic.Internal as F--lAchar (i,j) = [j | i+1 == j]---- |------ NOTE we have to add 1 to the i-index. Legacy ADP reads chars from an input--- array starting at "1", while ADPfusion starts arrays at "0".--fAchar :: DIM2 -> (F.Scalar Int)-fAchar (Z:.i:.j) = F.Scalar $ (i+1)--fRegion :: DIM2 -> (F.Scalar (Int,Int))-fRegion (Z:.i:.j) = F.Scalar $ (i,j)---- * quickcheck stuff--newtype Small = Small Int-  deriving (Show)--instance Arbitrary Small where-  arbitrary = Small `fmap` choose (0,50)-  shrink (Small x)-    | x>0       = [Small $ x-1]-    | otherwise = []--small x = x>=0 && x <=50--(===) f g (Small i, Small j) = f (i,j) == g (i,j)-
+ ADP/Fusion/Region.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.Region where++import Data.Array.Repa.Index+import Data.Strict.Tuple+import Data.Vector.Fusion.Stream.Size+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Unboxed as VU+import Data.Strict.Maybe+import Prelude hiding (Maybe(..))++import Data.Array.Repa.Index.Subword++import ADP.Fusion.Classes++import Control.Exception (assert)+import Debug.Trace++++-- * Regions of unlimited size++data Region x = Region !(VU.Vector x)++instance Build (Region x)++instance+  ( ValidIndex ls Subword+  , VU.Unbox xs+  ) => ValidIndex (ls :!: Region xs) Subword where+  validIndex (ls :!: Region xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    i>=a && j<=VU.length xs -c && i+b<=j && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: Region xs) ix = let (a:!:b:!:c) = getParserRange ls ix in (a:!:b:!:c)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: Region x) Subword where+  data Elm (ls :!: Region x) Subword = ElmRegion !(Elm ls Subword) !(VU.Vector x) !Subword+  type Arg (ls :!: Region x)         = Arg ls :. VU.Vector x+  getArg !(ElmRegion ls xs _) = getArg ls :. xs+  getIdx !(ElmRegion _ _   i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:Region x) Subword where+  mkStream !(ls:!:Region xs) Outer !ij@(Subword (i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s in ElmRegion s (VU.unsafeSlice l (j-l) xs) (subword l j))+    $ mkStream ls (Inner Check Nothing) ij+  mkStream !(ls:!:Region xs) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+      mk !s = let (Subword (k:.l)) = getIdx s+                  l' = case szd of Nothing -> l+                                   Just z  -> max l (j-z)+              in  return (s :!: l :!: l')+      step !(s :!: k :!: l)+        | l > j     =  return S.Done+        | otherwise = return $ S.Yield (ElmRegion s (VU.unsafeSlice k (l-k) xs) (subword k l)) (s :!: k :!: l+1)+  {-# INLINE mkStream #-}++region :: VU.Vector x -> Region x+region = Region+{-# INLINE region #-}++++-- * Regions of unlimited size++data SRegion x = SRegion !Int !Int !(VU.Vector x)++instance Build (SRegion x)++instance+  ( ValidIndex ls Subword+  , VU.Unbox xs+  ) => ValidIndex (ls :!: SRegion xs) Subword where+  validIndex (ls :!: SRegion lb ub xs) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    i>=a && j<=VU.length xs -c && i+b<=j && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: SRegion lb ub xs) ix = let (a:!:b:!:c) = getParserRange ls ix in (a:!:b+lb:!:max 0 (c-lb))+  {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: SRegion x) Subword where+  data Elm (ls :!: SRegion x) Subword = ElmSRegion !(Elm ls Subword) !(VU.Vector x) !Subword+  type Arg (ls :!: SRegion x)         = Arg ls :. VU.Vector x+  getArg !(ElmSRegion ls xs _) = getArg ls :. xs+  getIdx !(ElmSRegion _ _   i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++-- |+--+-- TODO Check that all inner / outer sized calculations are correct+--+-- NOTE mkStream/Inner gives a size hint of Nothing, as in purely inner cases,+-- min/max boundaries are determined solely from the running rightmost index+-- from the next inner component.+--+-- NOTE the filter in mkStream/Outer is still necessary to check for+-- lowerbound>0 conditions. We /could/ send the lower bound down with another+-- size hint, but this only makes sense if you have use cases, where the lower+-- bound is a lot higher than "0". Otherwise the current code is simpler.+--+-- TODO use drop instead of filter: still condition, but large lower bounds are captured+--+-- TODO remove mkStream/Outer : filter and test if one condition less gives+-- much better runtimes.++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:SRegion x) Subword where+  mkStream !(ls:!:SRegion lb ub xs) Outer !ij@(Subword (i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s in assert (l>=0 && j-i>=0) $ ElmSRegion s (VU.slice l (j-l) xs) (subword l j))+    $ S.filter (\s -> let (Subword (k:.l)) = getIdx s in (j-l >= lb && j-l <= ub))+    $ mkStream ls (Inner Check (Just ub)) ij+  mkStream !(ls:!:SRegion lb ub xs) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+      mk !s = let (Subword (k:.l)) = getIdx s+                  l' = case szd of Nothing -> l+lb+                                   Just z  -> max (l+lb) (j-z)+              in  return (s :!: l :!: l')+      step !(s :!: k :!: l)+        | l>j || l-k>ub =  return S.Done+        | otherwise     = return $ assert (k>=0 && l-k>=0) $ S.Yield (ElmSRegion s (VU.slice k (l-k) xs) (subword k l)) (s :!: k :!: l+1)+  {-# INLINE mkStream #-}++-- |+sregion :: Int -> Int -> VU.Vector x -> SRegion x+sregion = SRegion+{-# INLINE sregion #-}+
+ ADP/Fusion/Table.hs view
@@ -0,0 +1,563 @@+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE TypeSynonymInstances #-}++module ADP.Fusion.Table where++import Control.Monad.Primitive+import Data.Array.Repa.Index+import Data.Array.Repa.Shape+import Data.Strict.Tuple+import Data.Vector.Fusion.Stream.Size+import qualified Data.Vector.Fusion.Stream.Monadic as S+import qualified Data.Vector.Unboxed as VU+import Data.Strict.Maybe+import Prelude hiding (Maybe(..))++import Data.Array.Repa.Index.Subword+import Data.Array.Repa.Index.Points+import Data.Array.Repa.ExtShape+import qualified Data.PrimitiveArray as PA+import qualified Data.PrimitiveArray.Zero as PA++import ADP.Fusion.Classes++import Debug.Trace++++-- * Mutable table with adaptive storage.++data MTbl i xs = MTbl !(ENZ i) !xs -- (PA.MutArr m (arr i x))++mTblSw :: ENE -> PA.MutArr m (arr (Z:.Subword) x) -> MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))+mTblSw = MTbl+{-# INLINE mTblSw #-}++mTbl :: ENZ i -> PA.MutArr m (arr i x) -> MTbl i (PA.MutArr m (arr i x))+mTbl = MTbl+{-# INLINE mTbl #-}++-- | Generate the list of indices for use in table lookup.+--+-- Don't touch stuff in greek! ζ is the interior stack of arguments, α the+-- stack of saved indices++class TableIndices i where+  tableIndices :: Monad m => InOut i -> ENZ i -> i -> S.Stream m (ζ:!:α:!:i) -> S.Stream m (ζ:!:α:!:i)++++-- * Instances++instance TableIndices Z where+  tableIndices Z Z Z = id+  {-# INLINE tableIndices #-}++instance TableIndices Subword where+  -- | These actually don't make sense in 1-dim settings, we keep the code as a+  -- reminder how things should look like: @tableIndices Outer ZeroT+  -- (Subword(i:.j)) = S.map (:!:subword j j)@+  tableIndices _ ZeroT _ = error "TableIndices Subword/ZeroT does not make sense"+  tableIndices Outer _ (Subword(i:.j)) = S.map (\(ζ:!:α:!:Subword(k:.l)) -> (ζ:!:α:!:subword l j))+  tableIndices (Inner _ szd) ene (Subword(i:.j)) = S.flatten mk step Unknown where+    mk (ζ:!:α:!:kl@(Subword(k:.l))) =+      let le = l + case ene of { EmptyT -> 0 ; NonEmptyT -> 1 }+          l' = case szd of { Nothing -> le ; Just z -> max le (j-z) }+      in  return (ζ:!:α:!:l:!:l')+    step (ζ:!:α:!:k:!:l)+      | i>j = return S.Done+      | otherwise = return $ S.Yield (ζ:!:α:!:subword k l) (ζ:!:α:!:k:!:l+1)+  {-# INLINE tableIndices #-}++instance TableIndices is => TableIndices (is:.Subword) where+  tableIndices (os:.Outer) (es:._) (is:.Subword(i:.j))+    = S.map (\(ζ:!:(α:!:Subword(_:.l)):!:is) -> (ζ:!:α:!:(is:.subword l j))) -- extend index to the end+    . tableIndices os es is -- extend the @is@ part+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:!:i):!:is)) -- move topmost index to α for safekeeping+  -- tables annotated with zero-width have zero width @l--l@+  -- This also reduces the number of "running indices"+  --+  -- TODO consider returning "def"ault elements here, instead of data from+  -- zero-length subword? Or does 'ZeroT' actually mean to extract (a/the)+  -- zero-length subword?+  --+  tableIndices (os:.Inner _ szd) (es:.ZeroT) (is:.Subword(i:.j))+    = S.map (\(ζ:!:(α:.Subword(k:.l)):!:is) -> (ζ:!:α:!:(is:.subword l l)))+    . tableIndices os es is+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:.i):!:is))+  -- the default case, where we need to create indices+  tableIndices (os:.Inner _ szd) (es:.e) (is:.Subword(i:.j))+    = S.flatten mk step Unknown+    . tableIndices os es is+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:.i):!:is))+    where mk (ζ:!:(α:.Subword (k:.l)):!:is) =+            let le = l + case e of { EmptyT -> 0 ; NonEmptyT -> 1 }+                l' = case szd of { Nothing -> le ; Just z -> max le (j-z) }+            in  return (ζ:!:α:!:is:!:l:!:l')+          step (ζ:!:α:!:is:!:k:!:l)+            | l > j = return $ S.Done+            | otherwise = return $ S.Yield (ζ:!:α:!:(is:.subword k l)) (ζ:!:α:!:is:!:k:!:l+1)+  {-#  INLINE tableIndices #-}++instance TableIndices is => TableIndices (is:.PointL) where+  tableIndices (os:.Outer) (es:._) (is:.PointL(i:.j))+    = S.map (\(ζ:!:(α:!:PointL(_:.l)):!:is) -> (ζ:!:α:!:(is:.pointL l j))) -- extend index to the end+    . tableIndices os es is -- extend the @is@ part+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:!:i):!:is)) -- move topmost index to α for safekeeping+  tableIndices (os:.Inner _ szd) (es:.ZeroT) (is:.PointL(i:.j))+    = S.map (\(ζ:!:(α:.PointL(k:.l)):!:is) -> (ζ:!:α:!:(is:.pointL l l)))  -- does @l==lower bound@ have to be true here?+    . tableIndices os es is+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:.i):!:is))+  -- the default case, where we need to create indices+  tableIndices (os:.Inner _ szd) (es:.e) (is:.PointL(i:.j))+    = S.flatten mk step Unknown+    . tableIndices os es is+    . S.map (\(ζ:!:α:!:(is:.i)) -> (ζ:!:(α:.i):!:is))+    where mk (ζ:!:(α:.PointL (k:.l)):!:is) =+            let le = l + case e of { EmptyT -> 0 ; NonEmptyT -> 1 }+                l' = case szd of { Nothing -> le ; Just z -> max le (j-z) }+            in  return (ζ:!:α:!:is:!:l:!:l')+          step (ζ:!:α:!:is:!:k:!:l)+            | l > j = return $ S.Done+            | otherwise = return $ S.Yield (ζ:!:α:!:(is:.pointL k l)) (ζ:!:α:!:is:!:k:!:l+1)+  {-#  INLINE tableIndices #-}++instance Build (MTbl i x)++-- ** Subword++instance+  ( ValidIndex ls Subword+  , Monad m+  , PA.MPrimArrayOps arr (Z:.Subword) x+  ) => ValidIndex (ls:!:MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  validIndex (_  :!: MTbl ZeroT _) _ _ = error "table with ZeroT found, there is no reason (actually: no implementation) for 1-dim ZeroT tables"+  validIndex (ls :!: MTbl ene tbl) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    let (_,Z:.Subword (0:.n)) = PA.boundsM tbl+        minsize = max b (if ene==EmptyT then 0 else 1)+    in  i>=a && i+minsize<=j && j<=n-c && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: MTbl ene _) ix = let (a:!:b:!:c) = getParserRange ls ix in if ene==EmptyT then (a:!:b:!:c) else (a:!:b+1:!:c)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls Subword+  ) => Elms (ls :!: MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  data Elm (ls :!: MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))) Subword = ElmMTblSw !(Elm ls Subword) !x !Subword -- ElmBtTbl !(Elm ls Subword) !x !(m (S.Stream m b)) !Subword+  type Arg (ls :!: MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))) = Arg ls :. x+  getArg !(ElmMTblSw ls x _) = getArg ls :. x+  getIdx !(ElmMTblSw _  _ i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , PrimMonad m+  , Elms ls Subword+  , MkStream m ls Subword+  , PA.MPrimArrayOps arr (Z:.Subword) x+  ) => MkStream m (ls :!: MTbl Subword (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  mkStream !(ls:!:MTbl ene tbl) Outer !ij@(Subword (i:.j))+    = S.mapM (\s -> let (Subword (_:.l)) = getIdx s in PA.readM tbl (Z:.subword l j) >>= \z -> return $ ElmMTblSw s z (subword l j))+    $ mkStream ls (Inner Check Nothing) (subword i $ case ene of { EmptyT -> j ; NonEmptyT -> j-1 })+  mkStream !(ls:!:MTbl ene tbl) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+    mk !s = let (Subword (_:.l)) = getIdx s+                le = l + case ene of { EmptyT -> 0 ; NonEmptyT -> 1}+                l' = case szd of Nothing -> le+                                 Just z  -> max le (j-z)+            in return (s :!: l :!: l')+    {-# INLINE [0] mk #-}+    step !(s :!: k :!: l)+      | l > j = return S.Done+      | otherwise = PA.readM tbl (Z:.subword k l) >>= \z -> return $ S.Yield (ElmMTblSw s z (subword k l)) (s :!: k :!: l+1)+    {-# INLINE [0] step #-}+  {-# INLINE mkStream #-}++-- ** multi-dim indices++instance+  ( Elms ls (is:.i)+  ) => Elms (ls :!: MTbl (is:.i) (PA.MutArr m (arr (is:.i) x))) (is:.i) where+  data Elm (ls :!: MTbl (is:.i) (PA.MutArr m (arr (is:.i) x))) (is:.i) = ElmMTbl !(Elm ls (is:.i)) !x !(is:.i)+  type Arg (ls :!: MTbl (is:.i) (PA.MutArr m (arr (is:.i) x))) = Arg ls :. x+  getArg !(ElmMTbl ls x _) = getArg ls :. x+  getIdx !(ElmMTbl _ _  i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , PrimMonad m+  , PA.MPrimArrayOps arr (is:.i) x+  , Elms ls (is:.i)+  , NonTermValidIndex (is:.i)+  , TableIndices (is:.i)+  , MkStream m ls (is:.i)+  ) => MkStream m (ls:!:MTbl (is:.i) (PA.MutArr m (arr (is:.i) x))) (is:.i) where+  mkStream (ls :!: MTbl enz tbl) os is+    = S.mapM (\(s:!:Z:!:β) -> PA.readM tbl β >>= \z -> return $ ElmMTbl s z β) -- extract data using β index+    . tableIndices os enz is -- generate indices for multiple dimensions+    . S.map (\s -> (s:!:Z:!:getIdx s)) -- extract the right-most current index+    $ mkStream ls (nonTermInnerOuter is os) (nonTermLeftIndex is os enz) -- TODO fix os is!+  {-# INLINE mkStream #-}++instance+  ( ValidIndex ls (is:.i)+  , PA.MPrimArrayOps arr (is:.i) x+  , NonTermValidIndex (is:.i)+  ) => ValidIndex (ls :!: MTbl (is:.i) (PA.MutArr m (arr (is:.i) x))) (is:.i) where+  validIndex (ls :!: MTbl es tbl) abc isi =+    let (_,rght) = PA.boundsM tbl+    in  nonTermValidIndex es rght abc isi && validIndex ls abc isi+  getParserRange (ls :!: MTbl es _) ix = getNonTermParserRange es ix $ getParserRange ls ix+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}++class NonTermValidIndex i where+  nonTermValidIndex :: ENZ i -> i -> ParserRange i -> i -> Bool+  getNonTermParserRange :: ENZ i -> i -> ParserRange i -> ParserRange i+  nonTermInnerOuter :: i -> InOut i -> InOut i+  nonTermLeftIndex :: i -> InOut i -> ENZ i -> i++instance NonTermValidIndex Z where+  nonTermValidIndex Z Z Z Z = True+  getNonTermParserRange Z Z Z = Z+  nonTermInnerOuter Z Z = Z+  nonTermLeftIndex Z Z Z = Z+  {-# INLINE nonTermValidIndex #-}+  {-# INLINE getNonTermParserRange #-}+  {-# INLINE nonTermInnerOuter #-}+  {-# INLINE nonTermLeftIndex #-}++instance NonTermValidIndex is => NonTermValidIndex (is:.Subword) where+  nonTermValidIndex (es:.e) (ns:.Subword(_:.n)) (abc:.(a:!:b:!:c)) (is:.Subword(i:.j)) =+    let minsize = max b (if e==EmptyT then 0 else 1)+    in  i>=a && i+minsize<=j && j<=n-c && nonTermValidIndex es ns abc is+  getNonTermParserRange (es:.e) (is:._) (abc:.(a:!:b:!:c)) =+    let b' = b + if e==EmptyT then 0 else 1+    in  getNonTermParserRange es is abc :. (a:!:b':!:c)+  nonTermInnerOuter (is:._) (os:.Outer) = nonTermInnerOuter is os :. Inner Check Nothing+  nonTermInnerOuter (is:._) (os:.Inner _ _) = nonTermInnerOuter is os :. Inner NoCheck Nothing+  nonTermLeftIndex (is:.Subword(i:.j)) (os:.o) (es:.e)+    | o==Outer && e==NonEmptyT = nonTermLeftIndex is os es :. subword i (j-1)+    | otherwise                = nonTermLeftIndex is os es :. subword i j+  {-# INLINE nonTermValidIndex #-}+  {-# INLINE getNonTermParserRange #-}+  {-# INLINE nonTermInnerOuter #-}+  {-# INLINE nonTermLeftIndex #-}++-- TODO autogenerated, check correctness++instance NonTermValidIndex is => NonTermValidIndex (is:.PointL) where+  nonTermValidIndex (es:.e) (ns:.PointL(_:.n)) (abc:.(a:!:b:!:c)) (is:.PointL(i:.j)) =+    let minsize = max b (if e==EmptyT then 0 else 1)+    in  i>=a && i+minsize<=j && j<=n-c && nonTermValidIndex es ns abc is+  getNonTermParserRange (es:.e) (is:._) (abc:.(a:!:b:!:c)) =+    let b' = b + if e==EmptyT then 0 else 1+    in  getNonTermParserRange es is abc :. (a:!:b':!:c)+  nonTermInnerOuter (is:._) (os:.Outer) = nonTermInnerOuter is os :. Inner Check Nothing+  nonTermInnerOuter (is:._) (os:.Inner _ _) = nonTermInnerOuter is os :. Inner NoCheck Nothing+  nonTermLeftIndex (is:.PointL(i:.j)) (os:.o) (es:.e)+    | o==Outer && e==NonEmptyT = nonTermLeftIndex is os es :. pointL i (j-1)+    | otherwise                = nonTermLeftIndex is os es :. pointL i j+  {-# INLINE nonTermValidIndex #-}+  {-# INLINE getNonTermParserRange #-}+  {-# INLINE nonTermInnerOuter #-}+  {-# INLINE nonTermLeftIndex #-}++++data BtTbl i xs f = BtTbl !(ENZ i) !xs !f -- (i -> m (S.Stream m b))++btTbl :: ENZ i -> xs -> f -> BtTbl i xs f --(i -> m (S.Stream m b)) -> BtTbl m i xs b+btTbl = BtTbl+{-# INLINE btTbl #-}++type DefBtTbl m isi x b = BtTbl isi (PA.Unboxed isi x) (isi -> m (S.Stream m b))+type SwBtTbl m x b = BtTbl Subword (PA.Unboxed (Z:.Subword) x) (Subword -> m (S.Stream m b))++instance Build (BtTbl i xs f)++instance+  ( Elms ls Subword+  ) => Elms (ls :!: SwBtTbl m x b) Subword where+  data Elm (ls :!: SwBtTbl m x b) Subword = ElmSwBtTbl !(Elm ls Subword) !(x,m (S.Stream m b)) !Subword+  type Arg (ls :!: SwBtTbl m x b) = Arg ls :. (x,m (S.Stream m b))+  getArg !(ElmSwBtTbl ls x _) = getArg ls :. x+  getIdx !(ElmSwBtTbl _ _  i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls Subword+  , VU.Unbox x+  , MkStream m ls Subword+  ) => MkStream m (ls :!: SwBtTbl m x b) Subword where+  mkStream !(ls:!:BtTbl ene tbl f) Outer !ij@(Subword (i:.j))+    = S.mapM (\s -> let (Subword (_:.l)) = getIdx s in return $ ElmSwBtTbl s (tbl PA.! (Z:.subword l j), f $ subword l j) (subword l j))+    $ mkStream ls (Inner Check Nothing) (subword i $ case ene of { EmptyT -> j ; NonEmptyT -> j-1 })+  mkStream !(ls:!:BtTbl ene tbl f) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+    mk !s = let (Subword (_:.l)) = getIdx s+                le = l + case ene of { EmptyT -> 0 ; NonEmptyT -> 1}+                l' = case szd of Nothing -> le+                                 Just z  -> max le (j-z)+            in return (s :!: l :!: l')+    step !(s :!: k :!: l)+      | l > j = return S.Done+      | otherwise = return $ S.Yield (ElmSwBtTbl s (tbl PA.! (Z:.subword k l), f $ subword k l) (subword k l)) (s :!: k :!: l+1)+  {-# INLINE mkStream #-}++instance+  ( ValidIndex ls Subword+  , VU.Unbox x+  ) => ValidIndex (ls :!: SwBtTbl m x b) Subword where+  validIndex (_  :!: BtTbl ZeroT _ _) _ _ = error "table with ZeroT found, there is no reason (actually: no implementation) for 1-dim ZeroT tables"+  validIndex (ls :!: BtTbl ene tbl _) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    let (_,Z:.Subword (0:.n)) = PA.bounds tbl+        minsize = max b (if ene==EmptyT then 0 else 1)+    in  i>=a && i+minsize<=j && j<=n-c && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: BtTbl ene _ f) ix = let (a:!:b:!:c) = getParserRange ls ix in if ene==EmptyT then (a:!:b:!:c) else (a:!:b+1:!:c)+  {-# INLINE getParserRange #-}++instance+  ( Elms ls (is:.i)+  ) => Elms (ls :!: DefBtTbl m (is:.i) x b) (is:.i) where+  data Elm (ls :!: DefBtTbl m (is:.i) x b) (is:.i) = ElmBtTbl !(Elm ls (is:.i)) !(x,m (S.Stream m b)) !(is:.i)+  type Arg (ls :!: DefBtTbl m (is:.i) x b) = Arg ls :. (x,m (S.Stream m b))+  getArg !(ElmBtTbl ls x _) = getArg ls :. x+  getIdx !(ElmBtTbl _ _  i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , Elms ls (is:.i)+  , ExtShape (is:.i)+  , Shape (is:.i)+  , VU.Unbox x+  , NonTermValidIndex (is:.i)+  , TableIndices (is:.i)+  , MkStream m ls (is:.i)+  ) => MkStream m (ls:!:DefBtTbl m (is:.i) x b) (is:.i) where+  mkStream (ls :!: BtTbl enz tbl f) os is+    = S.map (\(s:!:Z:!:β) -> ElmBtTbl s (tbl PA.! β,f β) β) -- extract data using β index+    . tableIndices os enz is -- generate indices for multiple dimensions+    . S.map (\s -> (s:!:Z:!:getIdx s)) -- extract the right-most current index+    $ mkStream ls (nonTermInnerOuter is os) (nonTermLeftIndex is os enz) -- TODO fix os is!+  {-# INLINE mkStream #-}++instance+  ( ValidIndex ls (is:.i)+  , Shape (is:.i)+  , ExtShape (is:.i)+  , VU.Unbox x+  , NonTermValidIndex (is:.i)+  ) => ValidIndex (ls :!: DefBtTbl m (is:.i) x b) (is:.i) where+  validIndex (ls :!: BtTbl es tbl f) abc isi =+    let (_,rght) = PA.bounds tbl+    in  nonTermValidIndex es rght abc isi && validIndex ls abc isi+  getParserRange (ls :!: BtTbl es _ _) ix = getNonTermParserRange es ix $ getParserRange ls ix+  {-# INLINE validIndex #-}+  {-# INLINE getParserRange #-}++++class EmptyTable x where+  toEmptyT :: x -> x+  toNonEmptyT :: x -> x++instance (EmptyENZ (ENZ i)) => EmptyTable (MTbl i xs) where+  toEmptyT    (MTbl enz xs) = MTbl (toEmptyENZ    enz) xs+  toNonEmptyT (MTbl enz xs) = MTbl (toNonEmptyENZ enz) xs+  {-# INLINE toEmptyT #-}+  {-# INLINE toNonEmptyT #-}++instance (EmptyENZ (ENZ i)) => EmptyTable (BtTbl i xs f) where+  toEmptyT    (BtTbl enz xs f) = BtTbl (toEmptyENZ    enz) xs f+  toNonEmptyT (BtTbl enz xs f) = BtTbl (toNonEmptyENZ enz) xs f+  {-# INLINE toEmptyT #-}+  {-# INLINE toNonEmptyT #-}+++++{-++-- * Backtracking tables.++data BtTbl m x b = BtTbl ENE !(PA.Unboxed (Z:.Subword) x) !(Subword -> m (S.Stream m b))++instance Build (BtTbl m x b)++instance+  ( Monad m+  , Elms ls Subword+  ) => Elms (ls :!: BtTbl m x b) Subword where+  data Elm (ls :!: BtTbl m x b) Subword = ElmBtTbl !(Elm ls Subword) !x !(m (S.Stream m b)) !Subword+  type Arg (ls :!: BtTbl m x b) = Arg ls :. (x,m (S.Stream m b))+  getArg !(ElmBtTbl ls x b _) = getArg ls :. (x,b)+  getIdx !(ElmBtTbl _  _ _ i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls :!: BtTbl m x b) Subword where+  mkStream !(ls:!:BtTbl ene xs f) Outer !ij@(Subword (i:.j))+    = S.map (\s -> let (Subword (k:.l)) = getIdx s in ElmBtTbl s (xs PA.! (Z:.subword l j)) (f $ subword l j) (subword l j))+    $ mkStream ls (Inner Check Nothing) (subword i $ case ene of { EmptyT -> j ; NoEmptyT -> j-1 })+  mkStream !(ls:!:BtTbl ene xs f) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+    mk !s = let (Subword (k:.l)) = getIdx s+                le = l + case ene of { EmptyT -> 0 ; NoEmptyT -> 1}+                l' = case szd of Nothing -> le+                                 Just z  -> max le (j-z)+            in  return (s:!:l:!: l')+    step !(s:!:k:!:l)+      | l > j     = return $ S.Done+      | otherwise = return $ S.Yield (ElmBtTbl s (xs PA.! (Z:.subword k l)) (f $ subword k l) (subword k l)) (s:!:k:!:l+1)+  {-# INLINE mkStream #-}++++-- * Unboxed mutable table for the forward phase in one dimension.++data MTbl xs = MTbl !ENE !xs++instance+  ( ValidIndex ls Subword+  , Monad m+  , PA.MPrimArrayOps arr (Z:.Subword) x+  ) => ValidIndex (ls:!:MTbl (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  validIndex (_  :!: MTbl ZeroT _) _ _ = error "table with ZeroT found, there is no reason (actually: no implementation) for 1-dim ZeroT tables"+  validIndex (ls :!: MTbl ene tbl) abc@(a:!:b:!:c) ij@(Subword (i:.j)) =+    let (_,Z:.Subword (0:.n)) = PA.boundsM tbl+        minsize = max b (if ene==EmptyT then 0 else 1)+    in  i>=a && i+minsize<=j && j<=n-c && validIndex ls abc ij+  {-# INLINE validIndex #-}+  getParserRange (ls :!: MTbl ene _) ix = let (a:!:b:!:c) = getParserRange ls ix in if ene==EmptyT then (a:!:b:!:c) else (a:!:b+1:!:c)+  {-# INLINE getParserRange #-}++instance Build (MTbl xs)++instance+  ( Monad m+  , Elms ls Subword+  ) => Elms (ls :!: MTbl (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  data Elm (ls :!: MTbl (PA.MutArr m (arr (Z:.Subword) x))) Subword = ElmMTbl !(Elm ls Subword) !x !Subword+  type Arg (ls :!: MTbl (PA.MutArr m (arr (Z:.Subword) x))) = Arg ls :. x+  getArg !(ElmMTbl ls x _) = getArg ls :. x+  getIdx !(ElmMTbl _ _ i) = i+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( PrimMonad m+  , PA.MPrimArrayOps arr (Z:.Subword) x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:MTbl (PA.MutArr m (arr (Z:.Subword) x))) Subword where+  mkStream !(ls:!:MTbl ene tbl) Outer !ij@(Subword (i:.j))+    = S.mapM (\s -> let (Subword (_:.l)) = getIdx s in PA.readM tbl (Z:.subword l j) >>= \z -> return $ ElmMTbl s z (subword l j))+    $ mkStream ls (Inner Check Nothing) (subword i $ case ene of { EmptyT -> j ; NoEmptyT -> j-1 })+  mkStream !(ls:!:MTbl ene tbl) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+    mk !s = let (Subword (_:.l)) = getIdx s+                le = l + case ene of { EmptyT -> 0 ; NoEmptyT -> 1}+                l' = case szd of Nothing -> le+                                 Just z  -> max le (j-z)+            in return (s :!: l :!: l')+    step !(s :!: k :!: l)+      | l > j = return S.Done+      | otherwise = PA.readM tbl (Z:.subword k l) >>= \z -> return $ S.Yield (ElmMTbl s z (subword k l)) (s :!: k :!: l+1)+  {-# INLINE mkStream #-}++++{-++-- ** multi-tape generalization: empty / nonempty++instance+  ( ValidIndex ls (is:.i)+  , Monad m+  , PA.MPrimArrayOps arr (is:.i) x+  ) => ValidIndex (ls :!: MTbl (PA.MutArr m (arr (is:.i) x))) (is:.i) where+    validIndex (ls :!: MTbl ene tbl) (is:.i) =+      let+      in  undefined++instance+  ( Monad m+  ) => Elms (ls :!: MTbl (PA.MutArr m (arr (is:.i) x))) (is:.i) where++instance+  ( Monad m+  ) => MkStream m (ls:!: MTbl (PA.MutArr m (arr (is:.i) x))) (is:.i) where+  mkStream !(ls:!:MTbl ene tbl) io is+    = undefined++++{-+data GMtbl i x = forall m . GMtbl (ENEdim i) (PA.MutArr m (Storage i x))++-}++-}++-}+++{-++-- * Immutable tables.++data Tbl x = Tbl !(PA.Unboxed (Z:.Subword) x)++instance Build (Tbl x)++instance+  ( Elms ls Subword+  ) => Elms (ls :!: Tbl x) Subword where+  data Elm (ls :!: Tbl x) Subword = ElmTbl !(Elm ls Subword) !x !Subword+  type Arg (ls :!: Tbl x) = Arg ls :. x+  getArg !(ElmTbl ls x _) = getArg ls :. x+  getIdx !(ElmTbl _ _ idx) = idx+  {-# INLINE getArg #-}+  {-# INLINE getIdx #-}++instance+  ( Monad m+  , VU.Unbox x+  , Elms ls Subword+  , MkStream m ls Subword+  ) => MkStream m (ls:!:Tbl x) Subword where+  mkStream !(ls:!:Tbl xs) Outer !ij@(Subword (i:.j)) = S.map (\s -> let (Subword (k:.l)) = getIdx s in ElmTbl s (xs PA.! (Z:.subword l j)) (subword l j)) $ mkStream ls (Inner Check Nothing) ij+  mkStream !(ls:!:Tbl xs) (Inner _ szd) !ij@(Subword (i:.j)) = S.flatten mk step Unknown $ mkStream ls (Inner NoCheck Nothing) ij where+    mk !s = let (Subword (k:.l)) = getIdx s+                le = l -- TODO need to add ENE here ! -- + case ene of { EmptyT -> 0 ; NoEmptyT -> 1}+                l' = case szd of Nothing -> le+                                 Just z  -> max le (j-z)+            in  return (s :!: l :!: l')+    step !(s :!: k :!: l)+      | l > j = return S.Done+      | otherwise = return $ S.Yield (ElmTbl s (xs PA.! (Z:.subword k l)) (subword k l)) (s :!: k :!: l+1)+  {-# INLINE mkStream #-}+++-}++
ADPfusion.cabal view
@@ -1,7 +1,7 @@ name:           ADPfusion-version:        0.1.0.0-author:         Christian Hoener zu Siederdissen, 2011-2012-copyright:      Christian Hoener zu Siederdissen, 2011-2012+version:        0.2.0.0+author:         Christian Hoener zu Siederdissen, 2011-2013+copyright:      Christian Hoener zu Siederdissen, 2011-2013 homepage:       http://www.tbi.univie.ac.at/~choener/adpfusion maintainer:     choener@tbi.univie.ac.at category:       Algorithms, Data Structures, Bioinformatics@@ -35,12 +35,13 @@                 translates to three nested for loops (for C). In the figure,                 four different approaches are compared using inputs with size                 100 characters to 1000 characters in increments of 100-                characters. "C" is an implementation ("./C/" directory) in "C"+                characters. "C" is an implementation (@./C/@ directory) in "C"                 using "gcc -O3". "ADP" is the original ADP approach (see link                 above), while "GAPC" uses the "GAP" language                 (<http://gapc.eu/>).-                <<https://github.com/choener/ADPfusion/gaplike-performance.png>>                 .+                <<http://www.tbi.univie.ac.at/~choener/adpfusion/gaplike-nussinov-runtime.jpg>>+                .                 Please note that actual performance will depend much on table                 layout and data structures accessed during calculations, but in                 general performance is very good: close to C and better than@@ -57,116 +58,65 @@                 that performs backtracking, or samples structures                 stochastically, among others things.                 .-                This version is still highly experimental and makes use of-                multiple recent improvements in GHC. This is particularly true-                for the monadic interface.                 .                 .-                .-                Newley added are the ADP.Fusion.GAPlike modules. These allow-                for writing grammars with only one (non)-terminal combinator.-                The logic for index manipulation is now moved into data types-                for terminals and non-terminals.-                .-                While this change leads to slightly more complicated instances-                for each new terminal or non-terminal, the overall code-                complexity is significantly lower. In addition, Constraint-                Kinds make complex interactions between (non)-terminals-                possible, while still managing to produce high-performance-                code.-                .-                The final goal would, of course, be to have no inter-terminal-                combinators anymore.-                .-                * GHC 7.6, LLVM, and -fnew-codegen recommended: gives a speedup-                  of x2 for GAPcriterion-                .-                .-                .-                .-                Long term goals: Outer indices with more than two dimensions,-                specialized table design, a combinator library, a library for-                computational biology.-                .                 Two algorithms from the realm of computational biology are                 provided as examples on how to write dynamic programming                 algorithms using this library:                 <http://hackage.haskell.org/package/Nussinov78> and                 <http://hackage.haskell.org/package/RNAFold>.-                .-                Changes since 0.0.1.2:-                .-                * require GHC 7.6-                .-                * ADP.Fusion.GAPlike module for (almost) combinator-less grammars-                .-                * ConstraintKinds for constrained parsers in GAPlike.-                .-                .-                .-                Changes since 0.0.1.0:-                .-                * compatibility with GHC 7.4-                .-                * note: still using fundeps & and TFs together. The TF-only version does not optimize as well (I know why but not yet how to fix it)-                .-                .-                .-                Using the new code generator?-                .-                The new code generator is not official yet, but I recommend trying it out:-                <<https://github.com/choener/ADPfusion/gaplike-newcodegen.png>>    Extra-Source-Files:   README.md-  ADP/Fusion/QuickCheck.hs-  ADP/Fusion/QuickCheck/Arbitrary.hs  -Flag devel-  description: build criterion benchmarks and pull in QuickCheck-  default: False - library   build-depends:     base >= 4 && < 5,-    ghc-prim,-    primitive      == 0.5.*   ,-    vector         == 0.10.*  ,-    PrimitiveArray == 0.4.*+    deepseq        >= 1.3     ,+    ghc-prim                  ,+    primitive      >= 0.5     ,+    PrimitiveArray == 0.5.2.* ,+    QuickCheck     >= 2.5     ,+    repa           >= 3.2     ,+    strict         >= 0.3.2   ,+    template-haskell          ,+    transformers              ,+    vector         >= 0.10   exposed-modules:     ADP.Fusion-    ADP.Fusion.Monadic-    ADP.Fusion.Monadic.Internal-    ADP.Fusion.GAPlike+    ADP.Fusion.Apply+    ADP.Fusion.Chr+    ADP.Fusion.Classes+    ADP.Fusion.Empty+    ADP.Fusion.Examples.Palindrome+    ADP.Fusion.Multi+    ADP.Fusion.Multi.Classes+    ADP.Fusion.Multi.Empty+    ADP.Fusion.Multi.GChr+    ADP.Fusion.Multi.None+    ADP.Fusion.None+    ADP.Fusion.QuickCheck+    ADP.Fusion.Region+    ADP.Fusion.Table    ghc-options:     -O2 -funbox-strict-fields -executable GAPcriterion-  buildable:-    False-  if flag(devel)-    buildable:-      True-    build-depends:-      criterion  == 0.6.* ,-      QuickCheck == 2.5-  other-modules:-    ADP.Fusion.GAPlike.DevelCommon-    ADP.Fusion.GAPlike.Criterion-    ADP.Fusion.GAPlike.QuickCheck+executable NeedlemanWunsch   main-is:-    Tests/GAPcriterion.hs+    ADP/Fusion/Examples/TwoDim.hs   ghc-options:-    -fllvm -O2 -funbox-strict-fields -optlo-O3 -optlo-std-compile-opts-  if impl(GHC > 7.4)-    ghc-options:-      -fnew-codegen-+    -Odph+    -funbox-strict-fields+    -funfolding-use-threshold1000+    -funfolding-keeness-factor1000+    -fllvm+    -optlo-O3 -optlo-std-compile-opts+    -fllvm-tbaa  source-repository head   type: git
− Tests/GAPcriterion.hs
@@ -1,9 +0,0 @@--module Main where--import ADP.Fusion.GAPlike2.Criterion----main = criterionMain-