diff --git a/Data/Array/Repa/Index/Outside.hs b/Data/Array/Repa/Index/Outside.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/Index/Outside.hs
@@ -0,0 +1,171 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeOperators #-}
+
+-- | 'Outside' covers subwords for outside calculations. These types of
+-- calculations requires quite "weird" index movements if you want to stay with
+-- usual grammars. This remains true if grammars are transformed to Chomsky
+-- normal form, only that in said form it is easier to write down the
+-- recursions.
+--
+-- TODO basically untested!
+
+module Data.Array.Repa.Index.Outside where
+
+import Control.Applicative
+import Control.DeepSeq
+import Data.Array.Repa.Index
+import Data.Array.Repa.Shape
+import GHC.Base (quotInt, remInt)
+import Test.QuickCheck
+import Test.QuickCheck.All
+import qualified Data.Vector.Unboxed as VU
+import Data.Vector.Unboxed.Deriving
+
+import Data.Array.Repa.ExtShape
+import Data.Array.Repa.Index.Subword hiding (upperTri, subwordIndex, subwordFromIndex)
+import qualified Data.Array.Repa.Index.Subword as SW
+
+
+
+stage = "Data.Array.Repa.Index.Outside"
+
+-- | 'Outside' inverts the usual subword (i,j) system.
+--
+-- TODO do I need to store N ?
+
+newtype Outside = Outside (Int:.Int)
+  deriving (Eq,Ord,Show)
+
+derivingUnbox "Outside"
+  [t| Outside -> (Int,Int) |]
+  [| \ (Outside (i:.j)) -> (i,j) |]
+  [| \ (i,j) -> Outside (i:.j) |]
+
+outside :: Int -> Int -> Outside
+outside i j = Outside (i:.j)
+{-# INLINE outside #-}
+
+-- | Size of an upper triangle starting at 'i' and ending at 'j'. "(0,N)" what
+-- be the normal thing to use. Internally, we stell upper triangular matrices.
+
+upperTri :: Outside -> Int
+upperTri (Outside (i:.j)) = triangularNumber $ j-i
+{-# INLINE upperTri #-}
+
+-- | Outside indexing. Given the longest subword and the current subword,
+-- calculate a linear index "[0,..]". "(l,n)" in this case means "l"ower bound,
+-- length "n". And "(i,j)" is the normal index.
+--
+-- TODO probably doesn't work right with non-zero base ?!
+
+subwordIndex :: Outside -> Outside -> Int
+subwordIndex (Outside (l:.n)) (Outside (i:.j)) = adr n (i,j) -- - adr n (l,n)
+  where
+    adr n (i,j) = n*i - triangularNumber i + j
+{-# INLINE subwordIndex #-}
+
+subwordFromIndex :: Outside -> Int -> Outside
+subwordFromIndex = error "not implemented"
+{-# INLINE subwordFromIndex #-}
+
+
+
+-- | Some weird things are going on here. Adding subwords (i,j) and (k,l)
+-- yields (i+k,j+l). Normally i==k==0 when calculating space requirements. If
+-- you have a subword (3,10) and want the next outer one add (-1,1) and you get
+-- what you want. We make NO(!) check that the final subword contains only
+-- non-negative indices.
+
+instance Shape sh => Shape (sh :. Outside) where
+  {-# INLINE [1] rank #-}
+  rank   (sh  :. _)
+    = rank sh + 1
+  {-# INLINE [1] zeroDim #-}
+  zeroDim = zeroDim :. Outside (0:.0)
+
+  {-# INLINE [1] unitDim #-}
+  unitDim = unitDim :. Outside (0:.1)
+
+  {-# INLINE [1] intersectDim #-}
+  intersectDim (sh1 :. Outside (i:.j)) (sh2 :. Outside (k:.l))
+    = (intersectDim sh1 sh2 :. Outside (max i k :. min j l))
+
+  {-# INLINE [1] addDim #-}
+  addDim (sh1 :. Outside (i:.j)) (sh2 :. Outside (k:.l))
+    = addDim sh1 sh2 :. Outside (i+k:.j+l)
+
+  {-# INLINE [1] size #-}
+  size  (sh1 :. sw) = size sh1 * upperTri sw
+
+  {-# INLINE [1] sizeIsValid #-}
+  sizeIsValid (sh1 :. Outside (i:.j))
+    | size sh1 > 0
+    = i>=0 && i<=j && j <= maxBound `div` size sh1
+    | otherwise
+    = False
+
+  {-# INLINE [1] toIndex #-}
+  toIndex (sh1 :. sh2) (sh1' :. sh2')
+    = toIndex sh1 sh1' * upperTri sh2 + subwordIndex sh2 sh2'
+
+  {-# INLINE [1] fromIndex #-}
+  fromIndex (ds :. d) n  = undefined -- fromIndex ds (n `quotInt` d) :. r
+    where
+      r = subwordFromIndex d n
+    -- If we assume that the index is in range, there is no point
+    -- in computing the remainder for the highest dimension since
+    -- n < d must hold. This saves one remInt per element access which
+    -- is quite a big deal.
+    {-
+    r       | rank ds == 0  = n
+            | otherwise     = n `remInt` d -}
+
+  -- | TODO fix for lower bounds check!
+  {-# INLINE [1] inShapeRange #-}
+  inShapeRange (zs :. Outside (_:._)) (sh1 :. Outside (l:.n)) (sh2 :. Outside (i:.j))
+    = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)
+
+  {-# NOINLINE listOfShape #-}
+  listOfShape (sh :. Outside (i:.j)) = i : j : listOfShape sh
+
+  {-# NOINLINE shapeOfList #-}
+  shapeOfList xx
+   = case xx of
+    []     -> error $ stage ++ ".toList: empty list when converting to  (_ :. Int)"
+    [x]    -> error $ stage ++ ".toList: only single element remaining!"
+    i:j:xs -> shapeOfList xs :. Outside (i:.j)
+
+  {-# INLINE deepSeq #-}
+  deepSeq (sh :. n) x = deepSeq sh (n `seq` x)
+
+-- |
+
+instance ExtShape sh => ExtShape (sh:.Outside) where
+  subDim (sh1:.Outside (i:.j)) (sh2:.Outside (k:.l)) = subDim sh1 sh2 :. Outside (i-k:.j-l)
+  {-# INLINE subDim #-}
+  rangeList (sh1:.Outside (i:.j)) (sh2:.Outside (k:.l)) = error "not implemented" -- [sh:.Outside (m,n) | sh <- rangeList sh1 sh2, m <- [i .. [i+k], n <- [ n <- [n1 .. (n1+n2) ] ]
+  {-# INLINE rangeList #-}
+
+-- |
+
+instance NFData Outside where
+  rnf (Outside (i:.j)) = i `seq` rnf j
+
+-- |
+
+instance Arbitrary Outside where
+  arbitrary = do
+    a <- choose (0,100)
+    b <- choose (0,100)
+    return $ Outside (min a b :. max a b)
+  shrink (Outside (i:.j))
+    | i<j       = [Outside (i:.j-1)]
+    | otherwise = []
+
+instance Arbitrary z => Arbitrary (z:.Outside) where
+  arbitrary = (:.) <$> arbitrary <*> arbitrary
+  shrink (z:.s) = (:.) <$> shrink z <*> shrink s
+
diff --git a/Data/Array/Repa/Index/Points.hs b/Data/Array/Repa/Index/Points.hs
new file mode 100644
--- /dev/null
+++ b/Data/Array/Repa/Index/Points.hs
@@ -0,0 +1,151 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeOperators #-}
+
+-- | Index structures for left- and right-linear grammars. Do not use this
+-- index for general linear- or context-free grammars.
+--
+-- Internally, both 'PointL' and 'PointR' work a lot like 'Subword's, but in
+-- non-terminals we only store the left- or right part.
+
+module Data.Array.Repa.Index.Points where
+
+import Control.Applicative
+import Control.DeepSeq
+import Data.Array.Repa.Index
+import Data.Array.Repa.Shape
+import Data.Vector.Unboxed.Deriving
+import GHC.Base (quotInt, remInt)
+import qualified Data.Vector.Unboxed as VU
+import Test.QuickCheck
+import Test.QuickCheck.All
+
+import Data.Array.Repa.ExtShape
+import Data.Array.Repa.Index.Subword
+
+
+
+-- | A point in left-linear grammars. In @(i:.j)@, @j@ is the non-terminal
+-- storage point, @i==0@ always for the non-terminal, while @i>=0@ for
+-- terminals, which are on the right of the non-terminal. (This is why
+-- left-linear grammars are called left-linear: they recurse on the left).
+--
+-- PS: all this left/right talk deals with the RHS of a production rule, the
+-- LHS is always a non-terminal ;-)
+
+newtype PointL = PointL (Int:.Int)
+  deriving (Eq,Read,Show)
+
+pointL :: Int -> Int -> PointL
+pointL i j = PointL (i:.j)
+{-# INLINE pointL #-}
+
+-- | A point in right-linear grammars.
+
+newtype PointR = PointR (Int:.Int)
+
+pointR :: Int -> Int -> PointR
+pointR i j = PointR (i:.j)
+{-# INLINE pointR #-}
+
+
+
+-- * Instances
+
+derivingUnbox "PointL"
+  [t| PointL -> (Int,Int) |]
+  [| \ (PointL (i:.j)) -> (i,j) |]
+  [| \ (i,j) -> PointL (i:.j) |]
+
+derivingUnbox "PointR"
+  [t| PointR -> (Int,Int) |]
+  [| \ (PointR (i:.j)) -> (i,j) |]
+  [| \ (i,j) -> PointR (i:.j) |]
+
+instance Shape sh => Shape (sh :. PointL) where
+  {-# INLINE [1] rank #-}
+  rank   (sh  :. _)
+    = rank sh + 1
+
+  {-# INLINE [1] zeroDim #-}
+  zeroDim = zeroDim :. PointL (0:.0)
+
+  {-# INLINE [1] unitDim #-}
+  unitDim = unitDim :. PointL (0:.1)
+
+  {-# INLINE [1] intersectDim #-}
+  intersectDim (sh1 :. PointL (i:.j)) (sh2 :. PointL (k:.l))
+    = (intersectDim sh1 sh2 :. PointL (max i k :. min j l))
+
+  {-# INLINE [1] addDim #-}
+  addDim (sh1 :. PointL (i:.j)) (sh2 :. PointL (k:.l))
+    = addDim sh1 sh2 :. PointL (i+k:.j+l)
+
+  -- NOTE size is calculated NOT as upper-triangular, but linear!
+  {-# INLINE [1] size #-}
+  size  (sh1 :. PointL (i:.j)) = size sh1 * (j-i)
+
+  {-# INLINE [1] sizeIsValid #-}
+  sizeIsValid (sh1 :. PointL (i:.j))
+    | size sh1 > 0
+    = i>=0 && i<=j && j <= maxBound `div` size sh1
+    | otherwise
+    = False
+
+  -- NOTE only the @j@ coordinate is used for indexing NTs, @i@ is just for
+  -- convenience. @l@ however restricts the NT to some value @>0@ if desired.
+  {-# INLINE [1] toIndex #-}
+  toIndex (sh1 :. PointL(l:.r)) (sh1' :. PointL(i:.j))
+    = toIndex sh1 sh1' * (r-l) + (j-l)
+
+  {-# INLINE [1] fromIndex #-}
+  fromIndex (ds :. d) n  = undefined -- fromIndex ds (n `quotInt` d) :. r
+    where
+      r = undefined
+
+  -- | TODO fix for lower bounds check!
+  {-# INLINE [1] inShapeRange #-}
+  inShapeRange (zs :. PointL (_:._)) (sh1 :. PointL (l:.n)) (sh2 :. PointL (i:.j))
+    = i<=j && l<=i && j<n && (inShapeRange zs sh1 sh2)
+
+  {-# NOINLINE listOfShape #-}
+  listOfShape (sh :. PointL (i:.j)) = i : j : listOfShape sh
+
+  {-# NOINLINE shapeOfList #-}
+  shapeOfList xx
+   = case xx of
+    []     -> error $ stage ++ ".toList: empty list when converting to  (_ :. Int)"
+    [x]    -> error $ stage ++ ".toList: only single element remaining!"
+    i:j:xs -> shapeOfList xs :. PointL (i:.j)
+
+  {-# INLINE deepSeq #-}
+  deepSeq (sh :. n) x = deepSeq sh (n `seq` x)
+
+instance ExtShape sh => ExtShape (sh:.PointL) where
+  {-# INLINE [1] subDim #-}
+  subDim (sh1:.PointL (i:.j)) (sh2:.PointL (k:.l)) = subDim sh1 sh2 :. PointL (i-k:.j-l)
+  {-# INLINE [1] rangeList #-}
+  rangeList _ _ = error "PointL:rangeList not implemented"
+
+instance NFData PointL where
+  rnf (PointL (i:.j)) = i `seq` rnf j
+  {-# INLINE rnf #-}
+
+-- TODO maybe vary the left border, too? Since this invalidates that @i==0@ in
+-- @PointL (i:.j)@, we would need to make sure that the memoizers for NTs get
+-- notified ...
+
+instance Arbitrary PointL where
+  arbitrary = do
+    b <- choose (0,100)
+    return $ pointL 0 b
+  shrink (PointL (i:.j))
+    | i<j = [pointL i $ j-1]
+    | otherwise = []
+
+instance Arbitrary z => Arbitrary (z:.PointL) where
+  arbitrary = (:.) <$> arbitrary <*> arbitrary
+  shrink (z:.s) = (:.) <$> shrink z <*> shrink s
+
diff --git a/Data/PrimitiveArray/FillTables.hs b/Data/PrimitiveArray/FillTables.hs
--- a/Data/PrimitiveArray/FillTables.hs
+++ b/Data/PrimitiveArray/FillTables.hs
@@ -21,6 +21,8 @@
 
 
 
+-- * Driver classes for table filling system.
+
 -- Upper triangular table filling. Right now, only a serial option 'upperTriS'
 -- is available.
 --
@@ -29,18 +31,28 @@
 class UpperTriS m stack where
   upperTriS :: stack -> m ()
 
--- |
---
+-- | Defines how a single index in a stack of arrays + evaluation functions is
+-- handled. The instances *should* work for any index @ix@.
+
+class Stack m sh xs where
+  writeStack :: xs -> sh -> m ()
+
+
+
+-- * Instances
+
+-- ** 1-tape grammars with 'Subword' indices.
+
 -- TODO Insert check that all extends are the same!
 
 instance
   ( Monad m
-  , MPrimArrayOps arr Subword e
-  , Stack m Subword (xs:.MutArr m (arr Subword e))
-  ) => UpperTriS m (xs:.MutArr m (arr Subword e)) where
-  upperTriS xs@(_:.x) = do
+  , MPrimArrayOps arr (Z:.Subword) e
+  , Stack m Subword (xs :. SubwordNonTerminal m arr e)
+  ) => UpperTriS m  (xs :. SubwordNonTerminal m arr e) where
+  upperTriS xs@(_:.(x,f)) = do
     -- TODO missing extends check
-    let (Subword (l:._),Subword (u:._)) = boundsM x
+    let (Z:.Subword (l:._),Z:.Subword (u:._)) = boundsM x
     S.mapM_ (go xs) $ unfolder l u
     where
       -- Write all table values at a certain subword. Note that tables are
@@ -60,13 +72,15 @@
       {-# INLINE unfolder #-}
   {-# INLINE upperTriS #-}
 
-
-
--- | Defines how a single index in a stack of arrays + evaluation functions is
--- handled.
+instance
+  ( PrimMonad m
+  , Stack m Subword xs
+  , MPrimArrayOps arr (Z:.Subword) e
+  ) => Stack m Subword (xs :. SubwordNonTerminal m arr e) where
+  writeStack (xs:.(x,f)) i = writeStack xs i >> f i >>= writeM x (Z:.i)
+  {-# INLINE writeStack #-}
 
-class Stack m sh xs where
-  writeStack :: xs -> sh -> m ()
+-- ** Multi-tape indices.
 
 instance (Monad m) => Stack m sh Z where
   writeStack _ _ = return ()
@@ -74,9 +88,16 @@
 
 instance
   ( PrimMonad m
-  , Stack m Subword xs
-  , MPrimArrayOps arr Subword e
-  ) => Stack m Subword (xs:.(MutArr m (arr Subword e),(Subword -> m e))) where
+  , Stack m ix xs
+  , MPrimArrayOps arr ix e
+  ) => Stack m ix (xs :. GeneralNonTerminal m arr ix e) where
   writeStack (xs:.(x,f)) i = writeStack xs i >> f i >>= writeM x i
   {-# INLINE writeStack #-}
+
+
+
+-- Wrap non-terminal symbol type, corresponding rule type.
+
+type SubwordNonTerminal m arr e = (MutArr m (arr (Z:.Subword) e), Subword -> m e)
+type GeneralNonTerminal m arr ix e = (MutArr m (arr ix e), ix -> m e)
 
diff --git a/Data/PrimitiveArray/QuickCheck.hs b/Data/PrimitiveArray/QuickCheck.hs
new file mode 100644
--- /dev/null
+++ b/Data/PrimitiveArray/QuickCheck.hs
@@ -0,0 +1,5 @@
+
+module Data.PrimitiveArray.QuickCheck where
+
+
+
diff --git a/Data/PrimitiveArray/Zero.hs b/Data/PrimitiveArray/Zero.hs
--- a/Data/PrimitiveArray/Zero.hs
+++ b/Data/PrimitiveArray/Zero.hs
@@ -41,7 +41,7 @@
     ma <- newM inLb inUb
     let exUb = inUb `addDim` unitDim
     let (MUnboxed _ mba) = ma
-    zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0.. toIndex exUb inUb] xs
+    zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0.. size exUb -1] xs
     return ma
   newM inLb inUb = let exUb = inUb `addDim` unitDim in
     unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>
@@ -50,7 +50,7 @@
     let exUb = inUb `addDim` unitDim
     ma <- newM inLb inUb
     let (MUnboxed _ mba) = ma
-    forM_ [0 .. toIndex exUb inUb] $ \k -> unsafeWrite mba k def
+    forM_ [0 .. size exUb -1] $ \k -> unsafeWrite mba k def
     return ma
   readM (MUnboxed exUb mba) idx = assert (inShape exUb idx) $ unsafeRead mba (toIndex exUb idx)
   writeM (MUnboxed exUb mba) idx elm = assert (inShape exUb idx) $ unsafeWrite mba (toIndex exUb idx) elm
@@ -77,7 +77,48 @@
 
 -- * Boxed, multidimensional arrays.
 
--- data Boxed sh e = Boxed !sh !(V.Vector e)
+data Boxed sh e = Boxed !sh !(V.Vector e)
+  deriving (Read,Show,Eq)
+
+data instance MutArr m (Boxed sh e) = MBoxed !sh (V.MVector (PrimState m) e)
+
+instance (Shape sh, ExtShape sh, VUM.Unbox elm) => MPrimArrayOps Boxed sh elm where
+  boundsM (MBoxed exUb _) = (zeroDim,exUb `subDim` unitDim)
+  fromListM inLb inUb xs = do
+    ma <- newM inLb inUb
+    let exUb = inUb `addDim` unitDim
+    let (MBoxed _ mba) = ma
+    zipWithM_ (\k x -> assert (length xs == size exUb) $ unsafeWrite mba k x) [0 .. size exUb - 1] xs -- [0.. toIndex exUb inUb] xs
+    return ma
+  newM inLb inUb = let exUb = inUb `addDim` unitDim in
+    unless (inLb == zeroDim) (error "MArr0 lb/=zeroDim") >>
+    MBoxed exUb `liftM` new (size exUb)
+  newWithM inLb inUb def = do
+    let exUb = inUb `addDim` unitDim
+    ma <- newM inLb inUb
+    let (MBoxed _ mba) = ma
+    forM_ [0 .. size exUb -1] $ \k -> unsafeWrite mba k def
+    return ma
+  readM (MBoxed exUb mba) idx = assert (inShape exUb idx) $ unsafeRead mba (toIndex exUb idx)
+  writeM (MBoxed exUb mba) idx elm = assert (inShape exUb idx) $ unsafeWrite mba (toIndex exUb idx) elm
+  {-# INLINE boundsM #-}
+  {-# INLINE fromListM #-}
+  {-# INLINE newM #-}
+  {-# INLINE newWithM #-}
+  {-# INLINE readM #-}
+  {-# INLINE writeM #-}
+
+instance (Shape sh, ExtShape sh, VUM.Unbox elm) => PrimArrayOps Boxed sh elm where
+  bounds (Boxed exUb _) = (zeroDim,exUb `subDim` unitDim)
+  freeze (MBoxed exUb mba) = Boxed exUb `liftM` unsafeFreeze mba
+  index (Boxed exUb ba) idx = assert (inShape exUb idx) $ unsafeIndex ba (toIndex exUb idx)
+  {-# INLINE bounds #-}
+  {-# INLINE freeze #-}
+  {-# INLINE index #-}
+
+instance (Shape sh, ExtShape sh) => PrimArrayMap Boxed sh e e' where
+  map f (Boxed sh xs) = Boxed sh (V.map f xs)
+  {-# INLINE map #-}
 
 
 {-
diff --git a/PrimitiveArray.cabal b/PrimitiveArray.cabal
--- a/PrimitiveArray.cabal
+++ b/PrimitiveArray.cabal
@@ -1,5 +1,5 @@
 Name:           PrimitiveArray
-Version:        0.5.0.0
+Version:        0.5.2.0
 License:        BSD3
 License-file:   LICENSE
 Author:         Christian Hoener zu Siederdissen
@@ -18,19 +18,17 @@
                 In general all operations are (highly) unsafe, no
                 bounds-checking or other sanity-checking is performed.
                 Operations are aimed toward efficiency as much as possible.
-                Goals of the library are to have arrays according to three
-                ideas: immutable/mutable arrays, strict/lazy arrays,
-                zero-based/lower-bound arrays. Zero-based arrays save one
-                addition on each access if the lower bound or the array is
-                always zero.
 
 Library
   Exposed-modules:
     Data.Array.Repa.ExtShape
+    Data.Array.Repa.Index.Outside
     Data.Array.Repa.Index.Point
+    Data.Array.Repa.Index.Points
     Data.Array.Repa.Index.Subword
     Data.PrimitiveArray
     Data.PrimitiveArray.FillTables
+    Data.PrimitiveArray.QuickCheck
     Data.PrimitiveArray.Zero
   Build-depends:
     base            >= 4 && <5  ,
