diff --git a/BioInf/RNAEval.hs b/BioInf/RNAEval.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/RNAEval.hs
@@ -0,0 +1,122 @@
+
+-- | Given a sequence and a structure, evaluate the energy.
+--
+-- TODO switch to 'SSTree [Energy]' type!
+
+module BioInf.RNAEval where
+
+import Text.Printf
+import qualified Data.Vector.Unboxed as VU
+
+import Biobase.RNA
+import Biobase.Structure
+import Biobase.Structure.DotBracket
+import Biobase.Types.Ring
+import Biobase.Vienna
+import Data.PrimitiveArray
+
+import BioInf.RNAFold.EnergyInt
+import BioInf.RNAFold.Functions
+
+
+
+-- | Sum up a complete (sub-) tree.
+
+rnaEval :: ViennaTables -> String -> String -> Int
+rnaEval vna pri' sec' = treeSum $ annotateWithEnergy vna pri sst where
+  sec = dotbracketToPairlist sec'
+  sst = toSSTree sec
+  pri = mkPrimary pri'
+
+
+
+-- | Evaluate the energy of a secondary structure tree with sequence. We abuse
+-- the normal folding functions with a dummy table full of (one :: Energy).
+-- This is probably slower than another method but quickly written.
+--
+-- TODO this is basically crapfuck ;-) Should use the FoldFunctions directly
+-- instead of that strange table. Should not xxxOpt either.
+
+annotateWithEnergy :: ViennaTables -> Primary -> SSTree () -> SSTree [Int]
+annotateWithEnergy trnr pri t = f t where
+  -- extern part
+  f (SSExt l _ []) = SSExt l [one] []
+  f (SSExt l _ xs) =
+    let
+      es = map ((\(i,j) -> externalLoopOpt trnr pri dummy i j) . treeIJ) xs
+    in
+      SSExt l es (map f xs)
+  -- hairpin
+  f (SSTree i j _ []) = SSTree i j [hairpinOpt trnr pri i j] []
+  -- 1-loop
+  f (SSTree i j _ [x])
+      -- stack
+      | i+1==k&&j-1==l
+      = SSTree i j [stackOpt trnr pri dummy i j] [f x]
+      | (di,dj) `VU.elem` tabbedInteriorLoopDistances i j
+      = SSTree i j [tabbedInteriorLoopOpt trnr pri dummy i j] [f x]
+      | di==0&&dj>1
+      = SSTree i j [bulgeLOpt trnr pri dummy i j] [f x]
+      | di>1&&dj==0
+      = SSTree i j [bulgeROpt trnr pri dummy i j] [f x]
+      | di==1&&dj>1
+      = SSTree i j [interior1xnLOpt trnr pri dummy i j] [f x]
+      | di>1&&dj==1
+      = SSTree i j [interior1xnROpt trnr pri dummy i j] [f x]
+      | ds+dl>30
+      = error "not handling loops with size >30"
+      -- large interiorr loop
+      | otherwise       = SSTree i j [largeInteriorLoopOpt trnr pri dummy i j] [f x]
+    where
+      (k,l) = treeIJ x
+      di = k-i-1
+      dj = j-l-1
+      ds = min di dj
+      dl = max di dj
+  -- multiple loop
+  f (SSTree i j _ xs) =
+    let
+      cl = multibranchCloseOpt trnr pri dummy dummy i j
+      ls = map ((\(k,l) -> multibranchIJLoopOpt trnr pri dummy k l) . treeIJ) xs
+    in
+      SSTree i j (cl:ls) (map f xs)
+
+  dummy = fromAssocs (0,0) (n,n) one []
+  n = snd $ bounds pri
+
+
+
+-- | convert an annotated tree into strings that explain each score.
+--
+-- TODO this is a stupid name
+
+explainTree :: Primary -> SSTree [Int] -> [String]
+explainTree inp sst = f sst where
+  -- | exterior loop
+  f (SSExt _ _ []) = [""]
+  f (SSExt _ _ xs) = this : concatMap f xs where
+    eners = map (\(SSTree _ _ [e] _) -> e) xs
+    ener = sum eners
+    this = printf "%-20s                                     %6d   %s" "External loop" ener (show eners)
+  -- | hairpin
+  f (SSTree i j [e] []) = [this] where
+    this = printf "%-20s (%4d,%4d) %4s                    %6d" "Hairpin loop" (i+1) (j+1) (show $ pair inp i j) e
+  f (SSTree i j [e] [x@(SSTree k l _ _)]) = this : f x where
+      this = printf "%-20s (%4d,%4d) %4s   (%4d,%4d) %4s %6d" "Interior" (i+1) (j+1) (show $ pair inp i j) (k+1) (l+1) (show $ pair inp k l) e
+  f (SSTree i j es xs) = concatMap f xs ++ [this] where
+    this = printf "%-20s (%4d,%4d) %4s                    %6d %6d, %s" "Multi loop" (i+1) (j+1) (show $ pair inp i j) (sum es) (head es) (show $ tail es)
+
+
+
+-- | input sequence indices
+
+treeIJ (SSTree i j _ _) = (i,j)
+
+
+-- | Run a sum over the tree. (foldl (+), the tree annotations)
+--
+-- TODO that should go into Biobase.Structure as a generic walk over the tree
+
+treeSum t = f t where
+  f (SSExt _ es xs) = ringProductL $ es ++ map f xs
+  f (SSTree _ _ es xs) = ringProductL $ es ++ map f xs
diff --git a/BioInf/RNAFold.hs b/BioInf/RNAFold.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/RNAFold.hs
@@ -0,0 +1,115 @@
+
+-- | ViennaRNA folding based on an algebraic ring structure. This should
+-- combine the goals of few lines of codes, multiple different folding
+-- functions and extensibility.
+--
+-- NOTE Assume that you want '-d 3' for folding with dangles. Then you can just
+-- instanciate the folding functions, replacing only those functions where the
+-- folding changes based on the new dangle options.
+--
+-- NOTE compile with: -fno-method-sharing
+
+module BioInf.RNAFold where
+
+import Control.Monad
+import Control.Monad.ST
+
+import Biobase.RNA
+import Biobase.Types.Ring
+import Data.PrimitiveArray
+import Biobase.Structure
+
+import BioInf.RNAFold.Functions
+
+import Debug.Trace.Tools
+import Debug.Trace
+
+
+-- | Folding works on unboxed values of a Ring-type for which a FoldFunctions
+-- instance does exist. By default, we have this for Energy values. Again, we
+-- use a class as we could be interested in probabilistic backtracking or
+-- something like that.
+
+type ResultTables a =
+  ( Table a -- weak structures
+  , Table a -- strong structures
+  , Table a -- exactly one component
+  , Table a -- one or more components
+  , Table a -- complete external structures
+  )
+
+type Pairlist = [(Int,Int)]
+
+class (FoldFunctions a) => Fold a where
+
+  fold      :: TurnerTables a -> Primary -> (ResultTables a)
+  foldST    :: TurnerTables a -> Primary -> ST s (ResultTables a)
+  backtrack :: TurnerTables a -> Primary -> (ResultTables a) -> a -> [(Secondary,a)]
+
+  -- | We have a default instance for folding based on Rings
+
+  fold trnr inp = runST $ foldST trnr inp
+  {-# INLINE fold #-}
+
+  foldST trnr inp = do
+    let n = snd $ bounds inp
+    (weakM,weak)     <- mkTable n
+    (strongM,strong) <- mkTable n
+    (externM,extern) <- mkTableWith one n
+    (mbr1M,mbr1)     <- mkTable n
+    (mbrM,mbr)       <- mkTable n
+    forM_ [n,n-1..0] $ \i -> forM_ [i,i+1..n] $ \j -> do
+      let pIJ = pair inp i j
+      when (pIJ/=vpNP&&i+3<j) $ do
+        -- weak table
+        let hpVal = {-# SCC "hpVal" #-} hairpinOpt trnr inp i j
+        let ilVal = {-# SCC "ilVal" #-} ringSumL
+              [ largeInteriorLoopOpt trnr inp strong i j
+              , tabbedInteriorLoopOpt trnr inp strong i j
+              , bulgeLOpt trnr inp strong i j
+              , bulgeROpt trnr inp strong i j
+              , interior1xnLOpt trnr inp strong i j
+              , interior1xnROpt trnr inp strong i j
+              ]
+        let mbVal = {-# SCC "mbVal" #-} multibranchCloseOpt trnr inp mbr mbr1 i j
+        writeM weakM (i,j) $ ringSumL [hpVal,ilVal,mbVal]
+        -- strong table
+        when (i+5<j) $ do
+          let stValW = {-# SCC "stValW" #-} stackOpt trnr inp weak i j
+          let stValS = {-# SCC "stValS" #-} stackOpt trnr inp strong i j
+          writeM strongM (i,j) $ ringSumL [stValW,stValS]
+      -- multibranch loops
+      when (i>0&&j<n) $ do
+        -- M1
+        let mbr1ValS = {-# SCC "mbr1ValS" #-} multibranchIJLoopOpt trnr inp strong i j
+        let mbr1ValU = {-# SCC "mbr1ValU" #-} multibranchUnpairedJOpt trnr inp mbr1 i j
+        writeM mbr1M (i,j) $ ringSumL [mbr1ValS,mbr1ValU]
+        -- M
+        let mbrValU  = {-# SCC "mbrValU" #-} multibranchUnpairedJOpt trnr inp mbr i j
+        let mbrValS  = {-# SCC "mbrValS" #-} multibranchKJHelixOpt trnr inp strong i j
+        let mbrValMS = {-# SCC "mbrValMS" #-} multibranchAddKJHelixOpt trnr inp mbr strong i j
+        writeM mbrM (i,j) $ ringSumL [mbrValU,mbrValS,mbrValMS]
+    -- fill only part of the F array
+    let j=n
+    forM_ [n-6,n-7..0] $ \i -> do
+      let extUP   = {-# SCC "extUP"   #-} if i<n then extern ! (i+1,j) else zero
+      let extStr  = {-# SCC "extStr"  #-} externalLoopOpt trnr inp strong i j
+      let extAddL = {-# SCC "extAddL" #-} externalAddLoopOpt trnr inp strong extern i j
+      writeM externM (i,j) $ ringSumL [extUP,extStr,extAddL,one] -- always add 'one' as the open chain should always be contained
+    return (weak,strong,mbr1,mbr,extern)
+  {-# INLINE foldST #-}
+
+
+-- * Helper functions
+
+-- Create one 2dim - IxTable with default value.
+
+mkTable n = mkTableWith zero n
+
+-- Create one IxTable with user-supplied value.
+
+mkTableWith v n = do
+  tM <- fromAssocsM (0,0) (n,n) v []
+  t <- unsafeFreezeM tM
+  return (tM,t)
+
diff --git a/BioInf/RNAFold/Energy.hs b/BioInf/RNAFold/Energy.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/RNAFold/Energy.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE StandaloneDeriving #-}
+
+module BioInf.RNAFold.Energy
+  ( FoldFunctions (..)
+  , Fold (..)
+  ) where
+
+import BioInf.RNAFold
+import Biobase.Types.Energy
+import Biobase.Types.Ring
+import BioInf.RNAFold.Functions
+
+
+
+instance FoldFunctions Energy
+
+instance Fold Energy where
+  backtrack trnr inp tbls = error "write me"
+{-
+  backtrack trnr inp (weak,strong,mbr1,mbr,extern) = ext 0 n delta where
+    n = VU.length inp -1
+    delta = one :: Energy
+    overallBest = extern `unsafeIndex` (0,n)
+    ext i j d = let bestE = extern `unsafeIndex` (i,j) in
+      [ []
+      | i==j
+      , overallBest == one
+      ] ++ -- gives us the unfolded sequence
+      [ r
+      | i<j
+      , r <- ext (i+1) j d
+      ] ++
+      [ r
+      | i<j
+      , ((k,l),ce) <- externalLoopIdx trnr inp strong i j
+      , let dNew = ce `rmult` d `rmult` neg bestE
+      , dNew <= one
+      , r <- str k l d
+      ] ++
+      [ r++s
+      | i<j
+      , (k,ce) <- externalAddLoopIdx trnr inp strong extern i j
+      , let dNew = ce `rmult` d `rmult` neg bestE
+      , dNew <= one
+      , r <- str i k d
+      , s <- ext (k+1) j d ++ [[]] -- not 'd' but what 'str' leaves us with!, the [[]] only if the str-part alone works out
+      ]
+    str i j d = let bestE = strong `unsafeIndex` (i,j) in
+      [ (i,j):r
+      | i+2<j
+      , ((k,l),ce) <- stackIdx trnr inp strong i j
+      , let dNew = ce `rmult` d `rmult` neg bestE
+      , dNew <= one
+      , r <- str k l d
+      ] ++
+      [ (i,j):r
+      | i+2<j
+      , ((k,l),ce) <- stackIdx trnr inp weak   i j
+      , let dNew = ce `rmult` d `rmult` neg bestE
+      , dNew <= one
+      , r <- wea k l d
+      ]
+    wea :: Int -> Int -> a -> [Pairlist]
+    wea i j d = let bestE = weak `unsafeIndex` (i,j) in
+      [ [(i,j)]
+      | i+3<j
+      , (ce :: Energy) <- hairpinIdx trnr inp i j -- needs to be qualified as we give no other table
+      ]
+-}
+
+
+
+-- | (DEBUG) Print an array.
+
+{-
+printArr arr = do
+  --let (IT.IxTable (0,0) (_,n) _) = arr
+  let n = snd $ snd $ bounds arr
+  forM_ [0..n] $ \i -> do
+    putStrLn ""
+    forM [0..n] $ \j -> do
+      if j>=i
+        then do
+          let v = arr `unsafeIndex` (i,j)
+          if isZero v
+            then printf "%5s" "_i_"
+            else printf "%5i" (unEnergy $ arr `unsafeIndex` (i,j))
+        else do
+          putStr "     "
+  putStrLn ""
+  return ()
+-}
diff --git a/BioInf/RNAFold/EnergyInt.hs b/BioInf/RNAFold/EnergyInt.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/RNAFold/EnergyInt.hs
@@ -0,0 +1,235 @@
+{-# LANGUAGE StandaloneDeriving #-}
+
+-- | Temporary hackery until all base libraries understand newtype Energy. And
+-- yes, for testing too.
+
+module BioInf.RNAFold.EnergyInt
+  ( FoldFunctions (..)
+  , Fold (..)
+  ) where
+
+import Biobase.Types.Ring
+import Biobase.RNA
+import Biobase.Constants
+import Biobase.Structure.DotBracket
+import Biobase.Structure
+
+import Data.PrimitiveArray
+
+import BioInf.RNAFold
+import BioInf.RNAFold.Functions
+
+-- for testing only
+{-
+import Biobase.Vienna.Default
+import Debug.Trace.Tools
+import Data.List.Split
+import Text.Printf
+import Control.Monad
+import Biobase.Turner.Tables
+-}
+
+
+instance Ring Int where
+  (.+.) = min
+  (.*.) = (+)
+  neg = negate
+  one = 0
+  zero = eInf
+  isZero x = x>eMax
+  n .^. k = n * k
+  (.^^.) = error "write me"
+  {-# INLINE (.+.) #-}
+  {-# INLINE (.*.) #-}
+  {-# INLINE neg #-}
+  {-# INLINE one #-}
+  {-# INLINE zero #-}
+  {-# INLINE isZero #-}
+  {-# INLINE (.^.) #-}
+
+instance FoldFunctions Int where
+  calcTermAU tAU p = if p/=vpCG && p/=vpGC then tAU else 0
+  calcNinio maxNno nno l = min maxNno (nno * l)
+  calcLargeLoop l = floor $ 108.856 * log (fromIntegral l / 30)
+  {-# INLINE calcTermAU #-}
+  {-# INLINE calcNinio #-}
+  {-# INLINE calcLargeLoop #-}
+
+-- TODO detach backtrack so that all instances that use this kind of
+-- backtracking can immediately use it!
+
+instance Fold Int where
+  backtrack trnr inp (weak,strong,mbr1,mbr,extern) delta = filter ((<=0) . snd) $ map f $ ext 0 n delta where
+    f (xs,z) = (Secondary (n+1) xs,optE+delta-z)
+    n = snd $ bounds inp
+    optE = extern!(0,n)
+    newD d here next = d - (next - here)
+    --
+    -- All exterior loop decompositions
+    --
+    ext i j d = let ehere = extern!(i,j) in
+      [ (x,z) -- shorter ext
+      | i<j
+      , let d' = newD d ehere (extern!(i+1,j))
+      , d'>=0
+      , (x,z) <- ext (i+1) j d'
+      ] ++
+      [ (x,z) -- loop at (i,j)
+      | i<j
+      , (_,enext) <- externalLoopIdx trnr inp strong i j -- _ = (i,j)
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- str i j d'
+      ] ++
+      [ (x++y,z)
+      | i<j
+      , (k,enext) <- externalAddLoopIdx trnr inp strong extern i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z') <- str i k d'
+      , (y,z) <- ext (k+1) j z' ++ [([],z') | z'>=0 && extern!(k+1,j)==0]
+      ]
+    --
+    -- A strong stem on top of strong of weak
+    --
+    str i j d = let ehere = strong!(i,j) in
+      [ ((i,j):x,z)
+      | i<j
+      , (_,enext) <- stackIdx trnr inp strong i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- str (i+1) (j-1) d'
+      ] ++
+      [ ((i,j):x,z)
+      | i<j
+      , (_,enext) <- stackIdx trnr inp weak i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- wea (i+1) (j-1) d'
+      ]
+    wea i j d = let ehere = weak!(i,j) in
+      --
+      -- A hairpin closes at (i,j)
+      --
+      [ ([(i,j)],d')
+      | i<j
+      , enext <- hairpinIdx trnr inp i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      ] ++
+      --
+      -- interior loops
+      --
+      [ ((i,j):x,z)
+      | i<j
+      , ((k,l),enext) <- (
+          largeInteriorLoopIdx trnr inp strong i j ++
+          tabbedInteriorLoopIdx trnr inp strong i j ++
+          bulgeLIdx trnr inp strong i j ++
+          bulgeRIdx trnr inp strong i j ++
+          interior1xnLIdx trnr inp strong i j ++
+          interior1xnRIdx trnr inp strong i j
+          )
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- str k l d'
+      ] ++
+      --
+      -- multibranch loops closed at (i,j)
+      --
+      [ ((i,j):x++y,z)
+      | i<j
+      , (k,enext) <- multibranchCloseIdx trnr inp mbr mbr1 i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z') <- mul (i+1) k d'
+      , (y,z) <- mul1 (k+1) (j-1) z' -- z' is what 'mul' left us
+      ]
+    mul i j d = let ehere = mbr!(i,j) in
+      --
+      -- unpaired nucleotide on the J side
+      --
+      [ (x,z)
+      | i<j
+      , ((k,l),enext) <- multibranchUnpairedJIdx trnr inp mbr i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- mul k l d'
+      ] ++
+      --
+      -- a helix (k,j)
+      --
+      [ (x,z)
+      | i<j
+      , (k,enext) <- multibranchKJHelixIdx trnr inp strong i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- str k j d'
+      ] ++
+      --
+      -- add a helix to an existing structure
+      --
+      [ (x++y,z)
+      | i<j
+      , (k,enext) <- multibranchAddKJHelixIdx trnr inp mbr strong i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z') <- mul i k d'
+      , (y,z) <- str (k+1) j z'
+      ]
+    mul1 i j d = let ehere = mbr1!(i,j) in
+      --
+      -- Simply the strong part in a multibranch loop
+      --
+      [ (x,z)
+      | i<j
+      , (_,enext) <- multibranchIJLoopIdx trnr inp strong i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- str i j d'
+      ] ++
+      --
+      -- unpaired nucleotide on the J side
+      --
+      [ (x,z)
+      | i<j
+      , ((k,l),enext) <- multibranchUnpairedJIdx trnr inp mbr1 i j
+      , let d' = newD d ehere enext
+      , d'>=0
+      , (x,z) <- mul1 k l d'
+      ]
+
+{-
+test inp' k =
+  let
+    (_,n) = bounds inp
+    bts = backtrack trnr inp tbls k
+    inp = mkPrimary inp'
+    trnr = fst turner2004GH
+    tbls@(weak,strong,mbr1,mbr,extern) = fold trnr inp
+    optE = extern ! (0,n)
+    f x
+      | x > 999 = "   x"
+      | x < -999 = "-999"
+      | otherwise = printf "%4d" x
+    g t = do
+            let ls = splitEvery (n+1) $ map f $ toList t
+            putStr "    "
+            mapM_ (printf "%4d") [0 :: Int .. (length $ head ls) -1]
+            putStrLn ""
+            zipWithM_ (\k xs -> printf "%4d" k >> mapM_ putStr xs >> putStrLn"") [0 :: Int ..] ls
+  in do
+      print "weak"
+      g weak
+      print "strong"
+      g strong
+      print "mbr   L"
+      g mbr
+      print "mbr1  R"
+      g mbr1
+      print "extern"
+      g extern
+      print optE
+      putStrLn inp'
+      mapM_ (\(s,e) -> (putStr $ dotbracket s) >> (putStrLn $ " " ++ show e)) bts
+-}
diff --git a/BioInf/RNAFold/Functions.hs b/BioInf/RNAFold/Functions.hs
new file mode 100644
--- /dev/null
+++ b/BioInf/RNAFold/Functions.hs
@@ -0,0 +1,575 @@
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
+
+-- | These functions are implementations of RNA secondary structure folding as
+-- described in "Bompfuenewere et al., 2006, Variations on RNA folding and
+-- alignment"
+--
+-- We have all the facilities needed for folding with the RNA parameter of
+-- Turner 2004 http://rna.urmc.rochester.edu/NNDB/turner04/ but consider only
+-- "double dangles" which correspond to the ViennaRNA package option "-d2".
+-- They are a bit easier to implement and are what is used for partition
+-- function calculations. In addition, it seems unlikely to see a statiscally
+-- relevant improvement in predication with "-d1" or "-d3".
+--
+-- All functions work on an algebraic ring structure. This should make it
+-- easier to implement certain functionality without having to rewrite all the
+-- functions given here. Try deriving a new 'Ring' instance first and see if it
+-- /just works/.
+--
+-- These functions do quite well, performancewise. GHC-HEAD with "-Odph" and
+-- "-fllvm" takes 14.4s, while the highly optimized viennaRNA package (the yet
+-- unpublished 2.0 version) takes about 1-2s on a sequence of length 1000.
+--
+-- NOTE For GHC <= 6.12.3 you should copy the default instances into your
+-- instance BLA, otherwise the resulting code will be slow. Or you could just
+-- wait for the new GHC to arrive! The new one produces good code without such
+-- stuff.
+--
+-- TODO single nucleotide bulges:
+-- http://rna.urmc.rochester.edu/NNDB/turner04/bulge.html , check what Vienna
+-- 2.0 does!
+
+module BioInf.RNAFold.Functions
+  ( FoldFunctions (..)
+  , Table
+  , TurnerTables
+  , ringSumL
+  , pair
+  , riap
+  , ringProductL
+  , tabbedInteriorLoopDistances
+  ) where
+
+import qualified Data.Vector.Unboxed as VU
+import Control.Exception (assert)
+import Data.List (foldl')
+import qualified Data.Map as M
+
+import Biobase.RNA
+import Biobase.Turner.Tables
+import Biobase.Types.Ring
+import Biobase.Vienna
+import Data.PrimitiveArray
+import Data.Primitive.Types
+
+import Debug.Trace.Tools
+
+type Cell = (Int,Int)
+type Table a = PrimArray Cell a
+type TurnerTables a = Turner2004 ViennaPair Nucleotide a
+
+
+
+-- | The folding functions. It could happen that we need different folding
+-- functions with the same type, hence the class-based approach. The default
+-- instance uses the usual ring methods.
+
+class (Show a, Ring a, VU.Unbox a, Prim a) => FoldFunctions a where
+
+  stackOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  stackIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  hairpinOpt  :: TurnerTables a -> Primary -> Int -> Int -> a
+  hairpinIdx  :: TurnerTables a -> Primary -> Int -> Int -> [a]
+
+  largeInteriorLoopOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  largeInteriorLoopIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  tabbedInteriorLoopOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  tabbedInteriorLoopIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  bulgeLOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  bulgeLIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  bulgeROpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  bulgeRIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  interior1xnLOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  interior1xnLIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  interior1xnROpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  interior1xnRIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  multibranchIJLoopOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  multibranchIJLoopIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  multibranchUnpairedJOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  multibranchUnpairedJIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  multibranchKJHelixOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  multibranchKJHelixIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Int,a)]
+
+  multibranchAddKJHelixOpt  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> a
+  multibranchAddKJHelixIdx  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> [(Int,a)]
+
+  multibranchCloseOpt  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> a
+  multibranchCloseIdx  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> [(Int,a)]
+
+  externalLoopOpt  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> a
+  externalLoopIdx  :: TurnerTables a -> Primary -> Table a -> Int -> Int -> [(Cell,a)]
+
+  externalAddLoopOpt  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> a
+  externalAddLoopIdx  :: TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> [(Int,a)] -- return only 'k' index
+
+  -- | Calculate the ninio asymmetric malus. Can not be written using ring
+  -- functions alone as a 'min' or 'max' functions is required.
+
+  calcNinio :: a -> a -> Int -> a
+
+  -- | Applies a terminal AU/GU penalty, where required.
+  --
+  -- TODO shouldn't this be just: if CG||GC then one else termAU?
+
+  calcTermAU :: a -> ViennaPair -> a -- ^ Apply terminal AU penalty
+
+  -- | large hairpin loops >30 require special calculations that involve
+  -- 'floor', rounding and other stuff that can not be handled by the Ring
+  -- class alone
+
+  calcLargeLoop :: Int -> a
+
+  -- NOTE Copy these functions into your own instance. In most cases, your are
+  -- now done and get optimized loops. Each function that you do not copy uses
+  -- the version here. This can lead to less efficient code.
+  --
+  -- NOTE Fixed in GHC 6.13. The default instances should yield superb code!
+
+  stackOpt trnr inp tbl i j =
+    VU.foldl' (.+.) zero $ stackBase trnr inp tbl i j
+  hairpinOpt trnr inp i j =
+    VU.foldl' (.+.) zero $ hairpinBase trnr inp i j
+  largeInteriorLoopOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ largeInteriorLoopBase trnr inp strong i j
+  tabbedInteriorLoopOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ tabbedInteriorLoopBase trnr inp strong i j
+  bulgeLOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ bulgeLBase trnr inp strong i j
+  bulgeROpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ bulgeRBase trnr inp strong i j
+  interior1xnLOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ interior1xnLBase trnr inp strong i j
+  interior1xnROpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ interior1xnRBase trnr inp strong i j
+  multibranchIJLoopOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ multibranchIJLoopBase trnr inp strong i j
+  multibranchUnpairedJOpt trnr inp mtable i j =
+    VU.foldl' (.+.) zero $ multibranchUnpairedJBase trnr inp mtable i j
+  multibranchKJHelixOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ multibranchKJHelixBase trnr inp strong i j
+  multibranchAddKJHelixOpt trnr inp table strong i j =
+    VU.foldl' (.+.) zero $ multibranchAddKJHelixBase trnr inp table strong i j
+  multibranchCloseOpt trnr inp m m1 i j =
+    VU.foldl' (.+.) zero $ multibranchCloseBase trnr inp m m1 i j
+  externalLoopOpt trnr inp strong i j =
+    VU.foldl' (.+.) zero $ externalLoopBase trnr inp strong i j
+  externalAddLoopOpt trnr inp strong extern i j =
+    VU.foldl' (.+.) zero $ externalAddLoopBase trnr inp strong extern i j
+
+  -- NOTE copy and instanciate these functions if you have to work with many
+  -- candidate sequences. Otherwise you probably do not need the speed-up from
+  -- these functions. This stuff is for backtracking  mostly as you get lists
+  -- of indices with attached scores.
+  --
+  -- NOTE With GHC 6.13 we should get optimized code anyways!
+
+  stackIdx trnr inp tbl i j =
+    [((i+1,j-1),stackOpt trnr inp tbl i j)]
+  hairpinIdx trnr inp i j =
+    VU.toList $ hairpinBase trnr inp i j
+  largeInteriorLoopIdx trnr inp strong i j =
+    VU.toList $ VU.zip (interiorLoopIndices i j) (largeInteriorLoopBase trnr inp strong i j)
+  tabbedInteriorLoopIdx trnr inp strong i j =
+    VU.toList $ VU.zip (tabbedInteriorLoopIndices i j) $ tabbedInteriorLoopBase trnr inp strong i j
+  bulgeLIdx trnr inp strong i j =
+    VU.toList $ VU.zip (VU.map (\k -> (i+1+k,j-1)) . uncurry VU.enumFromN $ bulgeLimit i j) $ bulgeLBase trnr inp strong i j
+  bulgeRIdx trnr inp strong i j =
+    VU.toList $ VU.zip (VU.map (\k -> (i+1,j-1-k)) . uncurry VU.enumFromN $ bulgeLimit i j) $ bulgeRBase trnr inp strong i j
+  interior1xnLIdx trnr inp strong i j =
+    VU.toList $ VU.zip (VU.map (\k -> (i+1+k,j-2)) $ uncurry VU.enumFromN $ iloop1xnLimit i j) $ interior1xnLBase trnr inp strong i j
+  interior1xnRIdx trnr inp strong i j =
+    VU.toList $ VU.zip (VU.map (\k -> (i+2,j-1-k)) $ uncurry VU.enumFromN $ iloop1xnLimit i j) $ interior1xnRBase trnr inp strong i j
+  multibranchIJLoopIdx trnr inp strong i j =
+    VU.toList $ VU.zip (VU.singleton (i,j)) $ multibranchIJLoopBase trnr inp strong i j
+  multibranchUnpairedJIdx trnr inp mtable i j =
+    VU.toList $ VU.zip (VU.singleton (i,j-1)) $ multibranchUnpairedJBase trnr inp mtable i j
+  multibranchKJHelixIdx trnr inp strong i j =
+    VU.toList $ VU.zip (uncurry VU.enumFromN $ multibranchKJHelixLimit i j) $ multibranchKJHelixBase trnr inp strong i j
+  multibranchCloseIdx trnr inp m m1 i j = -- TODO this is wrong!
+    VU.toList $ VU.zip (uncurry VU.enumFromN $ multibranchCloseLimit i j) $ multibranchCloseBase trnr inp m m1 i j
+  multibranchAddKJHelixIdx trnr inp table strong i j =
+    VU.toList $ VU.zip (uncurry VU.enumFromN $ multibranchAddKJHelixLimit i j) $ multibranchAddKJHelixBase trnr inp table strong i j
+  externalLoopIdx trnr inp strong i j =
+    VU.toList $ VU.singleton ((i,j), externalLoopOpt trnr inp strong i j)
+  externalAddLoopIdx trnr inp strong extern i j =
+    VU.toList $ VU.zip (uncurry VU.enumFromN $ externalAddLoopLimit i j) $ externalAddLoopBase trnr inp strong extern i j
+
+
+
+-- * We provide a default instance working on rings.
+
+-- | Simple hairpin loops. If (i,j) pairs then, first, try to do a lookup of
+-- the exact sequence of the hairpin in a tabulated list. If this fails then,
+-- second, try length 3 hairpins and so on.
+
+hairpinBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Int -> Int -> VU.Vector a
+hairpinBase Turner2004{..} inp i j = VU.singleton go where
+  go
+    | pIJ==vpNP || l<3 = zero
+    | l<=6, Just v <- s `M.lookup` hairpinLookup = v
+    | l==3      = (hairpinL ! l) -- .*. tAU -- apparantly not anymore according to NNDB
+    | l>=31     = (hairpinL ! 30) .*. (hairpinMM ! (pIJ,bI,bJ)) .*. (calcLargeLoop l)
+    | otherwise = {-traceVal (show (i,j,pIJ,bI,bJ,hairpinL!l,tAU,hairpinMM!(pIJ,bI,bJ))) $ -} (hairpinL ! l) .*. (hairpinMM ! (pIJ,bI,bJ))
+  l = j-i-1
+  s = assert (i>=0 && checkBounds inp j) $ [inp ! k | k <- [i..j-1]]
+  bI = inp ! (i+1)
+  bJ = inp ! (j-1)
+  pIJ = pair inp i j
+  tAU = calcTermAU termAU pIJ
+{-# INLINE hairpinBase #-}
+
+-- | Extend a stem by another pair.
+
+stackBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+stackBase Turner2004{..} inp tbl i j = VU.singleton $ go (i+1,j-1) where
+  pIJ = pair inp i j
+  go (k,l)
+    | pIJ==vpNP || pKL==vpNP || isZero tE
+    = zero
+    | otherwise
+    = tE .*. ( stack ! (pIJ,pKL))
+    where
+      pKL = riap inp k l
+      tE  = tbl ! (k,l)
+{-# INLINE stackBase #-}
+
+-- | These are special cases of interior loops. Short iloops, such as 1x2 loops
+-- are completely tabulated. Look each one up here.
+--
+-- TODO needs 1-bulges as a special case
+
+tabbedInteriorLoopBase :: (Show a, FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+tabbedInteriorLoopBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\(k,l) -> (strong ! (k,l)) .*. (ftabbed (k-i-1,j-l-1) (k,l))) ili
+  ili = tabbedInteriorLoopIndices i j
+  ftabbed (di,dj) (k,l)
+    | ds==0 && dl==1 = bulgeL!1 .*. stack!(pIJ,pKL) -- no termAU, since the helical stack continues (nndb)
+    | ds==1 && dl==1 = iloop1x1 ! (pIJ,pKL,bI,bJ)
+    | di==1 && dj==2 = iloop1x2 ! (pIJ,pKL,bI,bL,bJ)
+    | di==2 && dj==1 = iloop1x2 ! (pIJ,pKL,bJ,bI,bK)
+    | ds==2 && dl==2 = iloop2x2 ! (pIJ,pKL,bI,bK,bL,bJ)
+    | ds==2 && dl==3 = iloop2x3MM!(pIJ,bI,bJ) .*. iloop2x3MM ! (pKL,bL,bK) .*. iloopL ! 5 .*. ninio
+    where
+      pKL = riap inp k l
+      bK  = inp ! (k-1)
+      bL  = inp ! (l+1)
+      ds  = min di dj
+      dl  = max di dj
+  pIJ = pair inp i j
+  bI  = inp ! (i+1)
+  bJ  = inp ! (j-1)
+{-# INLINE tabbedInteriorLoopBase #-}
+
+-- | A large number of iloops up to a total maximum loop size of 30 have to be
+-- checked. There are about 300 cases for j-i>>30. In addition, this loop does
+-- not like fusion very much and does many different lookups.
+--
+-- TODO Any performance increase here should yield substantial improvements for
+-- the overall performance of folding algorithms.
+--
+-- TODO performance improvement: Split mismatch calculation into its own table
+-- in the caller. Callee gets an additional argument.
+--
+-- TODO didjs needs to go back into a *Limit function.
+
+largeInteriorLoopBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+largeInteriorLoopBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\(di,dj) ->
+                    ijmm .*.
+                    (strong ! (i+di,j-dj)) .*.
+                    (iloopL ! (di+dj-2)) .*. -- -2 because di,dj is total IL length +2
+                    (iloopMM ! (riap inp (i+di) (j-dj), inp ! (i+di-1), inp ! (j-dj+1))) .*.
+                    calcNinio maxNinio ninio (abs $ di-dj)
+                ) didjs
+  -- NOTE NO FUSION! :-(
+  -- TODO check this!
+  didjs = interiorLoopDistances i j
+  {-
+  didjs = traceVal (show (i,j)) $ VU.unfoldr (\(di,dj) ->
+                        if di>maxc
+                          then Nothing
+                          else if di+dj>=nexc
+                                then Just ((di,dj),(di+1,3   ))
+                                else Just ((di,dj),(di  ,dj+1))
+                      ) (3,5)  -}
+  -- constant
+  {-
+  maxc = min 27 (j-i-16)
+  nexc = min 30 (j-i-13)
+  -}
+  ijmm = iloopMM ! (pIJ,bI,bJ)
+  pIJ  = pair inp i j
+  bI   = inp ! (i+1)
+  bJ   = inp ! (j-1)
+{-# INLINE largeInteriorLoopBase #-}
+
+-- | A bulge on the left side of the inner closing pair. 1-bulges are treated
+-- as tabulated interior loops.
+--
+-- (..((...)))
+-- 01234567890
+
+bulgeLBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+bulgeLBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\k ->
+                  strong ! (i+1+k,j-1) .*.
+                  bulgeL ! k .*.
+                  calcTermAU termAU (riap inp (i+1+k) (j-1)) .*.
+                  tAUij
+                ) . uncurry VU.enumFromN $ bulgeLimit i j
+  tAUij = calcTermAU termAU $ pair inp i j
+{-# INLINE bulgeLBase #-}
+
+-- | A bulge on the right side of the inner closing pair. Mirroring bulgeLBase
+--
+-- ((~)...)
+
+bulgeRBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+bulgeRBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\k ->
+                  strong ! (i+1,j-1-k) .*.
+                  bulgeL ! k .*.
+                  calcTermAU termAU (riap inp (i+1) (j-1-k)) .*.
+                  tAUij
+                ) . uncurry VU.enumFromN $ bulgeLimit i j
+  tAUij  = calcTermAU termAU $ pair inp i j
+{-# INLINE bulgeRBase #-}
+
+-- | 1xn iloops work a bit like bulges. They are more complicated because we
+-- have to consider 'ninio' values and terminal mismatches.
+--
+-- TODO how big an improvement would 'iloopL1xn' be with integrated 'ninio'
+-- values?
+--
+-- (...(~).)
+
+interior1xnLBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\k ->
+                  strong ! (i+1+k,j-2) .*.
+                  iloopL ! (k+1) .*.
+                  iloop1xnMM ! (riap inp (i+1+k) (j-2), inp ! (i+k), inp ! (j-1)) .*.
+                  calcNinio maxNinio ninio (k-1) .*.
+                  pIJmm
+                ) . uncurry VU.enumFromN $ iloop1xnLimit i j
+  pIJmm = iloop1xnMM ! (pair inp i j, inp ! (i+1), inp ! (j-1))
+{-# INLINE interior1xnLBase #-}
+
+-- | A mirror to the above.
+--
+-- (.(~)...)
+
+interior1xnRBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\k ->
+                  strong ! (i+2,j-1-k) .*.
+                  iloopL ! (k+1) .*.
+                  iloop1xnMM ! (riap inp (i+2) (j-1-k), inp ! (j-k), inp ! (i+1)) .*.
+                  calcNinio maxNinio ninio (k-1) .*.
+                  pIJmm
+                ) . uncurry VU.enumFromN $ iloop1xnLimit i j
+  pIJmm = iloop1xnMM ! (pair inp i j, inp ! (i+1), inp ! (j-1))
+{-# INLINE interior1xnRBase #-}
+
+-- | Close a multibranch loop by trying to combine one element of 'm' with one
+-- of 'm1'.
+--
+-- <[[...]][[...]]>
+-- 0123456789012345
+--           1
+
+multibranchCloseBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> VU.Vector a
+multibranchCloseBase Turner2004{..} inp m m1 i j = res where
+  res = VU.map (\k ->
+                  m ! (i+1,k) .*.
+                  m1 ! (k+1,j-1) .*.
+                  ijmm .*.
+                  mbcl
+                ) . uncurry VU.enumFromN $ multibranchCloseLimit i j
+  ijmm =  multiMM ! (pIJ,bJ,bI)
+  mbcl =  multiOffset .*. multiHelix
+  pIJ  = riap inp i j
+  bI   = inp ! (i+1)
+  bJ   = inp ! (j-1)
+{-# INLINE multibranchCloseBase #-}
+
+-- | Adds a multibranch loop at exactly (i,j).
+
+multibranchIJLoopBase Turner2004{..} inp strong i j = res where
+  res = VU.singleton $ strong ! (i,j) .*. mbrhlx .*. mbrmm
+  mbrhlx = multiHelix
+  mbrmm  =  multiMM ! (pIJ,bI,bJ) -- TODO correct orientation?
+  pIJ    = pair inp i j
+  bI     = inp ! (i-1)
+  bJ     = inp ! (j+1)
+{-# INLINE multibranchIJLoopBase #-}
+
+-- | Trivial function that adds a single unpaired nucleotide within a
+-- multibranch loop.
+
+multibranchUnpairedJBase Turner2004{..} inp mtable i j = res where
+  res = VU.singleton $ mtable ! (i,j-1) .*. mbrup
+  mbrup = multiNuc
+{-# INLINE multibranchUnpairedJBase #-}
+
+-- | Adds a multibranch loop at (k,j), with k-i unpaired nucleotides to the
+-- left of 'k'.
+
+multibranchKJHelixBase  :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Int -> Int -> VU.Vector a
+multibranchKJHelixBase Turner2004{..} inp strong i j = res where
+  res = VU.map (\k ->
+          multiNuc .^. (k-i) .*.
+          strong ! (k,j) .*.
+          multiHelix .*.
+          multiMM ! (pair inp k j, inp ! (k-1), inp ! (j+1))
+        ) . uncurry VU.enumFromN $ multibranchKJHelixLimit i j
+{-# INLINE multibranchKJHelixBase #-}
+
+-- |
+
+multibranchAddKJHelixBase Turner2004{..} inp table strong i j = res where
+  res = VU.map (\k ->
+                  table ! (i,k) .*.
+                  strong ! (k+1,j) .*.
+                  multiMM ! (pair inp (k+1) j, inp ! k, inp ! (j+1))
+                ) . uncurry VU.enumFromN $ multibranchAddKJHelixLimit i j
+{-# INLINE multibranchAddKJHelixBase #-}
+
+-- | [[...]]
+--   0123456
+
+externalLoopBase Turner2004{..} inp strong i j = res where
+  res = VU.singleton $ strong ! (i,j) .*. mm .*. tAU
+  n = snd $ bounds inp
+  pIJ = pair inp i j
+  bI = inp ! (i-1)
+  bJ = inp ! (j+1)
+  tAU = calcTermAU termAU pIJ
+  mm
+    | i>0&&j<n  = extMM ! (pIJ,bI,bJ)
+    | i>0       = dangle5 ! (pIJ,bI)
+    | j<n       = dangle3 ! (pIJ,bJ)
+    | otherwise = one
+{-# INLINE externalLoopBase #-}
+
+-- |
+
+externalAddLoopBase :: (FoldFunctions a) => TurnerTables a -> Primary -> Table a -> Table a -> Int -> Int -> VU.Vector a
+externalAddLoopBase trnr@Turner2004{..} inp strong extern i j = res where
+  res = VU.map (\k ->
+                  externalLoopOpt trnr inp strong i k .*.
+                  extern ! (k+1,j)
+                ) . uncurry VU.enumFromN $ externalAddLoopLimit i j
+{-# INLINE externalAddLoopBase #-}
+
+
+
+-- * Helper Functions.
+
+-- TODO We definitely need to check that this works!
+
+pair :: Primary -> Int -> Int -> ViennaPair
+pair inp i j
+  = assert (checkBounds inp i && checkBounds inp j)
+  $ toPair (inp `unsafeIndex` i) (inp `unsafeIndex` j)
+{-# INLINE pair #-}
+
+riap inp i j
+  = assert (i>=0 && j>=0 && checkBounds inp i && checkBounds inp j)
+  $ toPair (inp ! j) (inp ! i)
+{-# INLINE riap #-}
+
+ringSum :: (Ring a, VU.Unbox a) => VU.Vector a -> a
+ringSum v = VU.foldl' (.+.) zero v
+{- INLINE ringSum #-}
+
+ringSumL :: (Ring a, VU.Unbox a) => [a] -> a
+ringSumL v = foldl' (.+.) zero v
+{-# INLINE ringSumL #-}
+
+ringProduct :: (Ring a, VU.Unbox a) => VU.Vector a -> a
+ringProduct v = VU.foldl' (.*.) one v
+{-# INLINE ringProduct #-}
+
+ringProductL :: (Ring a, VU.Unbox a) => [a] -> a
+ringProductL v = foldl' (.*.) one v
+
+-- | Explicit index generator for interior loops. Does not create indices for:
+-- - bulges     0 k
+-- - 1xn loops  1 k
+-- - 2x3 loops  2 3, 3 2
+-- - tabulated  1 1, 1 2, 2 1, 2 2
+
+interiorLoopDistances i j =
+  VU.concatMap (
+    \d -> VU.map (\d' -> (d',d-d'))  -- written as a tuple
+          $ VU.enumFromN 3 (d-5))    -- for each distance, all possible left/right combinations
+  $ VU.enumFromN 8 (min 23 (j-i-13)) -- diagonal distance or number of unpaired nucleotides -2.
+{-# INLINE interiorLoopDistances #-}
+
+-- WTF ?! the function below is 10.000x slower than the function above!
+
+interiorLoopIndices :: Int -> Int -> VU.Vector (Int,Int)
+interiorLoopIndices !i !j = VU.map (\(k,l) -> (i+k,j-l)) $ interiorLoopDistances i j
+{-# INLINE interiorLoopIndices #-}
+
+--
+-- TODO filter 'ili' to accept only indices that are not too close. Does
+
+tabbedInteriorLoopDistances :: Int -> Int -> VU.Vector (Int,Int)
+tabbedInteriorLoopDistances i j
+  | j-i>=8    = VU.fromList [(0,1),(1,0),(1,1),(1,2),(2,1),(2,2),(2,3),(3,2)]
+  | otherwise = VU.empty
+{-# INLINE tabbedInteriorLoopDistances #-}
+
+-- | Yes, therer is the (+1,+1) and yes, this is inconsistent with the other function
+
+tabbedInteriorLoopIndices i j = VU.map (\(di,dj) -> (i+di+1,j-dj-1)) $ tabbedInteriorLoopDistances i j
+{-# INLINE tabbedInteriorLoopIndices #-}
+
+-- * All limits depending on (i,j) should be here.
+
+-- | Bulge limitations
+
+bulgeLimit :: Int -> Int -> (Int,Int)
+bulgeLimit i j = (2,min 29 $ j-i-9)
+{-# INLINE bulgeLimit #-}
+
+-- | 1xn iloop limits
+
+iloop1xnLimit :: Int -> Int -> (Int,Int)
+iloop1xnLimit i j = (3,min 26 $ j-i-10)
+{-# INLINE iloop1xnLimit #-}
+
+-- | closing of a multibranch loop
+
+multibranchCloseLimit :: Int -> Int -> (Int,Int)
+multibranchCloseLimit i j = (i+1,j-i-2) -- (i+7, j-i-14)
+{-# INLINE multibranchCloseLimit #-}
+
+-- | add mb helix
+
+multibranchAddKJHelixLimit :: Int -> Int -> (Int,Int)
+multibranchAddKJHelixLimit i j = (i+1,j-i-1)
+{-# INLINE multibranchAddKJHelixLimit #-}
+
+-- | mb helix
+
+multibranchKJHelixLimit :: Int -> Int -> (Int,Int)
+multibranchKJHelixLimit i j = (i,j-i)
+{-# INLINE multibranchKJHelixLimit #-}
+
+-- | add external loop
+
+externalAddLoopLimit :: Int -> Int -> (Int,Int)
+externalAddLoopLimit i j = (i+5,j-i-5)
+{-# INLINE externalAddLoopLimit #-}
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,675 @@
+              GNU GENERAL PUBLIC LICENSE
+                Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                     Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+ 
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+              END OF TERMS AND CONDITIONS
+
+     How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/RNAFold.cabal b/RNAFold.cabal
new file mode 100644
--- /dev/null
+++ b/RNAFold.cabal
@@ -0,0 +1,64 @@
+name:           RNAFold
+version:        0.0.2.1
+author:         Christian Hoener zu Siederdissen (Haskell), Ivo L. Hofacker et al (ViennaRNA)
+maintainer:     choener@tbi.univie.ac.at
+copyright:      Christian Hoener zu Siederdissen, 2010
+category:       Bioinformatics
+synopsis:       RNA secondary structure prediction
+license:        GPL-3
+license-file:   LICENSE
+build-type:     Simple
+stability:      experimental
+cabal-version:  >= 1.4.0
+description:
+                Provides the folding functions as used in the ViennaRNA
+                package. Here, they are in Haskell form to be used by Haskell
+                programs.
+                .
+                - This is a release aimed at testing Data.Vector
+                - Expect major performance issues with GHC < 6.13!
+
+library
+  build-depends:
+    base >=4 && <5,
+    containers,
+    vector >=0.7,
+    primitive >=0.3,
+
+    Biobase >=0.0.2,
+    BiobaseTurner >=0.0.2,
+    BiobaseVienna >=0.0.2,
+    BiobaseTypes >=0.0.2,
+    HsTools >=0.0.1.1,
+    PrimitiveArray >=0.0.2 && <0.0.3
+
+  exposed-modules:
+    BioInf.RNAFold,
+    BioInf.RNAFold.Energy,
+    BioInf.RNAFold.EnergyInt,
+    BioInf.RNAEval,
+    BioInf.RNAFold.Functions
+
+  if impl(ghc > 6.13)
+    ghc-options:
+      -Odph
+      -fllvm
+      -fforce-recomp
+      -funbox-strict-fields
+      -fllvm
+      -optlo-O3
+      -optlc-O3
+      -fdicts-cheap
+      -fspec-constr
+      -funbox-strict-fields
+      -funfolding-use-threshold=100
+      -funfolding-creation-threshold=100
+  else
+    ghc-options:-Odph
+
+--    -fno-method-sharing -- performance does not improve!
+--    -fdicts-cheap
+--    -fspec-constr
+--    -funbox-strict-fields
+--    -funfolding-use-threshold=100
+--    -funfolding-creation-threshold=100
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
