diff --git a/Biobase.cabal b/Biobase.cabal
--- a/Biobase.cabal
+++ b/Biobase.cabal
@@ -1,5 +1,5 @@
 name:           Biobase
-version:        0.3.1.0
+version:        0.3.1.1
 author:         Christian Hoener zu Siederdissen
 maintainer:     choener@tbi.univie.ac.at
 homepage:       http://www.tbi.univie.ac.at/~choener/
@@ -129,8 +129,9 @@
     Biobase.RNA.NucBounds
     Biobase.RNA.Pairs
     Biobase.RNA.ViennaPair
+    Biobase.ScoreTypes
     Biobase.Structure
-    Biobase.Structure.DotBracket
+    Biobase.Structure.Constraint
     Biobase.Structure.Shapes
     Biobase.Types.Convert
     Biobase.Types.Energy
diff --git a/Biobase/RNA/Hashes.hs b/Biobase/RNA/Hashes.hs
--- a/Biobase/RNA/Hashes.hs
+++ b/Biobase/RNA/Hashes.hs
@@ -1,18 +1,31 @@
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 
--- | Fast hash functions for 'Primary' sequences.
+-- | Fast hash functions for 'Primary' sequences. A hash is just an 'Int', so
+-- use these only for short sequences.
 
 module Biobase.RNA.Hashes where
 
 import Control.DeepSeq
 import Control.Exception.Base (assert)
 import Data.Ix
+import Data.Primitive.Types
+import qualified Data.Vector.Generic as VG
+import qualified Data.Vector.Generic.Mutable as VGM
 import qualified Data.Vector.Unboxed as VU
 
 import Biobase.RNA
 
+
+
 newtype HashedPrimary = HashedPrimary Int
   deriving (Eq,Ord,Ix,NFData,Read,Show,Enum,Bounded)
+
+deriving instance Prim HashedPrimary
+deriving instance VGM.MVector VU.MVector HashedPrimary
+deriving instance VG.Vector VU.Vector HashedPrimary
+deriving instance VU.Unbox HashedPrimary
 
 -- | Given a piece of primary sequence information, reduce it to an index.
 --
diff --git a/Biobase/ScoreTypes.hs b/Biobase/ScoreTypes.hs
new file mode 100644
--- /dev/null
+++ b/Biobase/ScoreTypes.hs
@@ -0,0 +1,136 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+-- | With more programs being present, a number of different types are present.
+-- Right now, they mostly are just "type"s, or flat Int's / Double's. This
+-- module provides a set of newtype wrappers to make explicit what kind of
+-- value is being computed. In the future, all programs should make use of
+-- these.
+--
+-- All units come with unboxed vector equipment.
+--
+-- TODO the numeric-prelude knows about Unit.SI.
+--
+-- TODO we should use "Kelvin" from somewhere else, say the numerical-prelude
+-- but this would make Biobase even heavier.
+
+module Biobase.ScoreTypes where
+
+import Data.Primitive.Types
+import qualified Data.Vector.Generic as VG
+import qualified Data.Vector.Generic.Mutable as VGM
+import qualified Data.Vector.Unboxed as VU
+
+import Biobase.Constants
+
+
+
+-- | The ViennaRNA base unit. A bit strange, but values are tabulated in the
+-- energy parameter file as 1/100 kCal/mol.
+
+newtype DecaCalMol = DCM { unDCM :: Int }
+  deriving (Eq,Ord,Read,Show)
+
+-- | Other programs just calculate with fractions of kCal/Mol. This needs to be
+-- double as errors in energies are around 10 cal/mol.
+
+newtype KCalMol = KCM { unKCM :: Double }
+  deriving (Eq,Ord,Read,Show)
+
+-- | For data generated from statistical ensembles, we only have
+-- pseudo-energies.
+
+newtype PseudoDecaCalMol = PDCM { unPDCM :: Int }
+  deriving (Eq,Ord,Read,Show)
+
+-- | For data generated from statistical ensembles, we only have
+-- pseudo-energies.
+
+newtype PseudoKCalMol = PKCM { unPKCM :: Double }
+  deriving (Eq,Ord,Read,Show)
+
+-- | The Boltzmann statistical weight "exp(-e / kT)" of an energy
+
+newtype BoltzmannW = BoltzmannW { unBoltzmannW :: Double }
+  deriving (Eq,Ord,Read,Show)
+
+-- | Temperature in Kelvin
+
+newtype Kelvin = Kelvin { unKelvin :: Double }
+  deriving (Eq,Ord,Read,Show)
+
+
+
+-- * Conversion between units. Not all conversions are meaningful.
+
+-- | Convert between two similar enough units. There is no all vs. all
+-- conversion.
+--
+-- NOTE If you need to convert pseudo-energies into "real" ones, do it
+-- explicitly by calling 'PDCM . unDCM' or similar. Conversions here are
+-- supposed to be somewhat safe.
+
+class Convert a b where
+  convert :: a -> b
+
+instance Convert DecaCalMol KCalMol where
+  convert (DCM x) = KCM $ fromIntegral x / 100
+
+instance Convert KCalMol DecaCalMol where
+  convert (KCM x) = DCM . round $ x * 100
+
+instance Convert PseudoDecaCalMol PseudoKCalMol where
+  convert (PDCM x) = PKCM $ fromIntegral x / 100
+
+instance Convert PseudoKCalMol PseudoDecaCalMol where
+  convert (PKCM x) = PDCM . round $ x * 100
+
+-- | convert from and to Boltzmann weights
+
+class BoltzmannWeighted a where
+  boltzmannWeighted :: a -> Kelvin -> BoltzmannW
+
+instance BoltzmannWeighted DecaCalMol where
+  boltzmannWeighted (DCM x) (Kelvin t) =
+    let k = gasconst
+    in  BoltzmannW . exp . negate $ fromIntegral x / (k * t * 100)
+
+instance BoltzmannWeighted KCalMol where
+  boltzmannWeighted (KCM x) (Kelvin t) =
+    let k = gasconst
+    in  BoltzmannW . exp . negate $ x / (k * t)
+
+instance BoltzmannWeighted PseudoDecaCalMol where
+  boltzmannWeighted (PDCM x) (Kelvin t) =
+    let k = gasconst
+    in  BoltzmannW . exp . negate $ fromIntegral x / (k * t * 100)
+
+instance BoltzmannWeighted PseudoKCalMol where
+  boltzmannWeighted (PKCM x) (Kelvin t) =
+    let k = gasconst
+    in  BoltzmannW . exp . negate $ x / (k * t)
+
+-- | Boltzmann weighting at default temperature of 37 Celsius.
+
+toBoltzmannW x = boltzmannWeighted x defTemp
+
+defTemp = Kelvin $ kelvinC0 + 37
+
+
+
+-- * unboxed vector instances
+
+#define DVU(d) \
+deriving instance Prim d; \
+deriving instance VU.Unbox d; \
+deriving instance VGM.MVector VU.MVector d; \
+deriving instance VG.Vector VU.Vector d \
+
+DVU(KCalMol)
+DVU(DecaCalMol)
+DVU(PseudoKCalMol)
+DVU(PseudoDecaCalMol)
+DVU(BoltzmannW)
+DVU(Kelvin)
diff --git a/Biobase/Structure.hs b/Biobase/Structure.hs
--- a/Biobase/Structure.hs
+++ b/Biobase/Structure.hs
@@ -1,57 +1,112 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
 
+-- | Types for RNA secondary structure. Types vary from the simplest array
+-- (D1Secondary) to rather complex ones.
 --
--- Basic definitions for RNA secondary structure.
+-- TODO The complex ones are still coming in from other libraries.
 --
-
--- TODO would RNA tertiary structure be here as well?
--- TODO maybe, we should just put the sequence into Secondary as well?
+-- TODO can we use Char8 instead of Char?
 
 {-# LANGUAGE RecordWildCards #-}
 
 module Biobase.Structure where
 
+import qualified Data.Vector.Unboxed as VU
+import Data.Vector.Unboxed.Read
 import Data.List (sort,groupBy)
 
-import Biobase.RNA
 
 
+-- * Array-based representation, no notion of structure
 
--- | A complex of one or more primary and secondary structures
+-- | Create secondary structure by various means.
 
-data Complex = Complex
-  { comments :: String
-  , structures :: [(Primary,Secondary)]
-  }
-  deriving (Show)
+class MkD1Secondary a where
+  mkD1S :: a -> D1Secondary
+  fromD1S :: D1Secondary -> a
 
+-- | Most primitive secondary structure generation
 
+instance MkD1Secondary (Int,[(Int,Int)]) where
+  mkD1S (len,ps) = D1S $ VU.replicate len (-1) VU.// xs where
+    xs = concatMap (\(i,j) -> [(i,j),(j,i)]) ps
+  fromD1S (D1S s) = (VU.length s, filter ((>=0).snd). zip [0..] $ VU.toList s)
 
--- | A secondary structure. It is explicit that we store the length of the
--- sequence. (length n, last index (n-1) problem)
+-- | A second primitive generator, requiring dictionary and String. This one
+-- generates pairs that are then used by the above instance. The dict is a list
+-- of possible brackets: ["()"] being the minimal set.
+--
+-- NOTE no dictionary is returned by "fromD1S".
+--
+-- TODO return dictionary that is actually seen?
 
-data Secondary = Secondary
-  { len      :: Int
-  , pairings :: [(Int,Int)]
-  }
-  deriving (Show)
+instance MkD1Secondary ([String],String) where
+  mkD1S (dict,xs) = mkD1S (length xs,ps) where
+    ps :: [(Int,Int)]
+    ps = dotBracket dict xs
+  fromD1S (D1S s) = ([], zipWith f [0..] $ VU.toList s) where
+    f k (-1) = '.'
+    f k p
+      | k>p = ')'
+      | otherwise = '('
 
+-- | Generate Secondary given that we have an unboxed vector of characters
 
+instance MkD1Secondary ([String],VU.Vector Char) where
+  mkD1S (dict,xs) = mkD1S (dict, VU.toList xs)
+  fromD1S s = let (dict,res) = fromD1S s in (dict,VU.fromList res)
 
+-- | A "fast" instance for getting the pair list of vienna-structures.
+
+instance MkD1Secondary String where
+  mkD1S xs = mkD1S (["()"],xs)
+  fromD1S s = let (_::[String],res) = fromD1S s in res
+
+instance MkD1Secondary (VU.Vector Char) where
+  mkD1S xs = mkD1S (["()"],xs)
+  fromD1S s = let (_::[String],res::VU.Vector Char) = fromD1S s in res
+
+newtype D1Secondary = D1S {unD1S :: VU.Vector Int}
+  deriving (Read,Show,Eq)
+
+
+
+-- * Helper functions
+
+-- | Secondary structure parser which allows pseudoknots, if they use different
+-- kinds of brackets.
+
+dotBracket :: [String] -> String -> [(Int,Int)]
+dotBracket dict xs = sort . concatMap (f xs) $ dict where
+  f xs [l,r] = g 0 [] . map (\x -> if x `elem` [l,r] then x else '.') $ xs where
+    g :: Int -> [Int] -> String -> [(Int,Int)]
+    g _ st [] = []
+    g k st ('.':xs) = g (k+1) st xs
+    g k sst (x:xs)
+      | l==x = g (k+1) (k:sst) xs
+    g k (s:st) (x:xs)
+      | r==x = (s,k) : g (k+1) st xs
+    g a b c = error $ show (a,b,c)
+
+
+
+-- * Tree-based representation: structure is given by the tree
+
 -- | secondary structure representation using an explicit tree, SSExt encodes
 -- the length of the underlying sequence. Each node can contain additional
 -- information under 'a'.
 
-
 data SSTree a = SSTree Int Int a [SSTree a]
               | SSExt  Int     a [SSTree a]
   deriving (Read,Show,Eq)
 
-
-
--- | generate an SSTree from a secondary structure
+-- | generate an SSTree from a secondary structure.
 
-toSSTree :: Secondary -> SSTree ()
-toSSTree Secondary{..} = ext $ sort pairings where
+mkSSTree :: D1Secondary -> SSTree ()
+mkSSTree s = ext $ sort ps where
+  (len,ps) = fromD1S s
   ext [] = SSExt len () []
   ext xs = SSExt len () . map tree $ groupBy (\l r -> snd l > fst r) xs
   tree [(i,j)]    = SSTree i j () []
diff --git a/Biobase/Structure/Constraint.hs b/Biobase/Structure/Constraint.hs
new file mode 100644
--- /dev/null
+++ b/Biobase/Structure/Constraint.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE StandaloneDeriving #-}
+
+module Biobase.Structure.Constraint where
+
+import Data.Primitive.Types
+import qualified Data.Vector.Generic as VG
+import qualified Data.Vector.Generic.Mutable as VGM
+import qualified Data.Vector.Unboxed as VU
+
+import Biobase.Structure
+
+
+
+-- | We can create a constraint from different sources
+
+class MkConstraint a where
+  mkConstraint :: a -> Constraint
+
+-- | A constraint is nothing more than a vector of constraint characters
+-- together with a possible pairing for each character.
+
+newtype Constraint = Constraint {unConstraint :: VU.Vector (Char,Int)}
+  deriving (Show,Read,Eq)
+
+bonusCC = VU.fromList "()<>|"
+{-# NOINLINE bonusCC #-}
+
+nobonusCC = VU.fromList ".x"
+{-# NOINLINE nobonusCC #-}
+
+
+
+-- * Instances
+
+instance MkConstraint String where
+  mkConstraint xs = mkConstraint . VU.fromList $ xs
+
+instance MkConstraint (VU.Vector Char) where
+  mkConstraint cs = Constraint $ VU.zip cs ks where
+    (D1S ks) = mkD1S cs
diff --git a/Biobase/Structure/DotBracket.hs b/Biobase/Structure/DotBracket.hs
deleted file mode 100644
--- a/Biobase/Structure/DotBracket.hs
+++ /dev/null
@@ -1,37 +0,0 @@
-
---
--- transform to and from dotbracket notation for RNA secondary structures.
---
-
-{-# LANGUAGE RecordWildCards #-}
-
-module Biobase.Structure.DotBracket where
-
-import Data.Array.IArray
-import Data.List (sort)
-
-import Biobase.RNA
-import Biobase.Structure
-
-
-
--- | Given the secondary structure notation, generate the dot-bracket string.
-
-dotbracket :: Secondary -> String
-dotbracket Secondary{..} = elems rbr where
-  arr = listArray (0,len-1) $ replicate len '.' :: Array Int Char
-  lbr = arr // map (\(l,_) -> (l,'(')) pairings
-  rbr = lbr // map (\(_,r) -> (r,')')) pairings
-
-
-
--- | transforms a pseudoknot-free dotbracket string into a pairlist
-
-dotbracketToPairlist :: String -> Secondary
-dotbracketToPairlist str = Secondary (length str) (sort $ f 0 [] str) where
-  f :: Int -> [Int] -> String -> [(Int,Int)]
-  f _ st [] = []
-  f k st ('.':xs) = f (k+1) st xs
-  f k st ('(':xs) = f (k+1) (k:st) xs
-  f k (s:st) (')':xs) = (s,k) : f (k+1) st xs
-  f a b c = error $ show (a,b,c)
diff --git a/Biobase/Structure/Shapes.hs b/Biobase/Structure/Shapes.hs
--- a/Biobase/Structure/Shapes.hs
+++ b/Biobase/Structure/Shapes.hs
@@ -11,7 +11,6 @@
 
 import Biobase.RNA
 import Biobase.Structure
-import Biobase.Structure.DotBracket
 
 
 
