diff --git a/Algebra/Structure/SemiRing.hs b/Algebra/Structure/SemiRing.hs
new file mode 100644
--- /dev/null
+++ b/Algebra/Structure/SemiRing.hs
@@ -0,0 +1,194 @@
+
+-- | A set with two binary operations, one for addition (@srplus@), one for
+-- multiplication (@srmul@). Together with a neutral element for @srplus@,
+-- named @srzero@, and one for @srmul@, named @srone@.
+
+module Algebra.Structure.SemiRing where
+
+import Control.DeepSeq (NFData(..))
+import Data.Coerce
+import Data.Monoid hiding ((<>))
+import Data.Semigroup
+import Data.Vector.Unboxed.Deriving
+import Data.Vector.Unboxed (Unbox)
+import GHC.Generics
+import Unsafe.Coerce
+
+import Numeric.Limits
+
+
+
+-- * The 'SemiRing' type class.
+
+-- | The semiring operations and neutral elements.
+
+class SemiRing a where
+  srplus  ∷ a → a → a
+  srmul   ∷ a → a → a
+  srzero  ∷ a
+  srone   ∷ a
+
+-- | Unicode variant of @srplus@.
+
+infixl 6 ⊕
+infixl 6 `srplus`
+(⊕) ∷ SemiRing a ⇒ a → a → a
+(⊕) = srplus
+{-# Inline (⊕) #-}
+
+-- | Unicode variant of @srmul@.
+
+infixl 7 ⊗
+infixl 7 `srmul`
+(⊗) ∷ SemiRing a ⇒ a → a → a
+(⊗) = srmul
+{-# Inline (⊗) #-}
+
+
+
+-- * Newtype wrappers for 'SemiRing' that make the semiring to use explicit.
+-- This is important, because several types, say Prob(ability) have multiple
+-- useful semiring instances.
+--
+-- 'Data.Monoid' in @base@ provides a number of newtype wrappers (@Sum@,
+-- @Product@, etc) for monoids, which have one binary operation and identity.
+-- There is, obviously, overlap with the structures constructed here.
+
+-- | The Viterbi SemiRing. It maximizes over the product.
+
+newtype Viterbi x = Viterbi { getViterbi ∷ x }
+  deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)
+
+derivingUnbox "Viterbi"
+  [t| forall x . Unbox x ⇒ Viterbi x → x |]  [| getViterbi |]  [| Viterbi |]
+
+instance NFData x ⇒ NFData (Viterbi x) where
+  rnf (Viterbi x) = rnf x
+  {-# Inline rnf #-}
+
+-- |
+--
+-- TODO Shall we have generic instances, or specific ones like @SemiRing
+-- (Viterbi Prob)@?
+--
+-- TODO Consider either a constraint @ProbLike x@ or the above.
+
+instance (Ord x, Num x) ⇒ SemiRing (Viterbi x) where
+  srplus (Viterbi x) (Viterbi y) = Viterbi $ max x y
+  srmul  (Viterbi x) (Viterbi y) = Viterbi $ x * y
+  srzero = Viterbi 0
+  srone  = Viterbi 1
+  {-# Inline srplus #-}
+  {-# Inline srmul  #-}
+  {-# Inline srzero #-}
+  {-# Inline srone  #-}
+
+-- | The tropical MinPlus SemiRing. It minimizes over the sum.
+
+newtype MinPlus x = MinPlus { getMinPlus ∷ x }
+  deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)
+
+derivingUnbox "MinPlus"
+  [t| forall x . Unbox x ⇒ MinPlus x → x |]  [| getMinPlus |]  [| MinPlus |]
+
+instance NFData x ⇒ NFData (MinPlus x) where
+  rnf (MinPlus x) = rnf x
+  {-# Inline rnf #-}
+
+-- |
+--
+-- TODO Shall we have generic instances, or specific ones like @SemiRing
+-- (Viterbi Prob)@?
+--
+-- TODO Consider either a constraint @ProbLike x@ or the above.
+
+instance (Ord x, Num x, NumericLimits x) ⇒ SemiRing (MinPlus x) where
+  srplus (MinPlus x) (MinPlus y) = MinPlus $ min x y
+  srmul  (MinPlus x) (MinPlus y) = MinPlus $ x + y
+  srzero = MinPlus maxFinite
+  srone  = 0
+  {-# Inline srplus #-}
+  {-# Inline srmul  #-}
+  {-# Inline srzero #-}
+  {-# Inline srone  #-}
+
+
+
+-- | The tropical MaxPlus SemiRing. It maximizes over the sum.
+
+newtype MaxPlus x = MaxPlus { getMaxPlus ∷ x }
+  deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num)
+
+derivingUnbox "MaxPlus"
+  [t| forall x . Unbox x ⇒ MaxPlus x → x |]  [| getMaxPlus |]  [| MaxPlus |]
+
+instance NFData x ⇒ NFData (MaxPlus x) where
+  rnf (MaxPlus x) = rnf x
+  {-# Inline rnf #-}
+
+instance NumericLimits x ⇒ NumericLimits (MaxPlus x) where
+  minFinite = MaxPlus minFinite
+  maxFinite = MaxPlus maxFinite
+
+-- |
+--
+-- TODO Shall we have generic instances, or specific ones like @SemiRing
+-- (Viterbi Prob)@?
+--
+-- TODO Consider either a constraint @ProbLike x@ or the above.
+
+instance (Ord x, Num x, NumericLimits x) ⇒ SemiRing (MaxPlus x) where
+  srplus (MaxPlus x) (MaxPlus y) = MaxPlus $ max x y
+  srmul  (MaxPlus x) (MaxPlus y) = MaxPlus $ x + y
+  srzero = MaxPlus minFinite
+  srone  = 0
+  {-# Inline srplus #-}
+  {-# Inline srmul  #-}
+  {-# Inline srzero #-}
+  {-# Inline srone  #-}
+
+
+
+-- * Generic semiring structure encoding.
+
+-- | The generic semiring, defined over two 'Semigroup' and 'Monoid'
+-- constructions.
+--
+-- It can be used like this:
+-- @
+-- srzero ∷ GSemiRing Min Sum Int  == maxBound
+-- srone  ∷ GSemiRing Min Sum Int  == 0
+-- @
+--
+-- It is generally useful to still provide explicit instances, since @Min@
+-- requires a @Bounded@ instance.
+
+newtype GSemiRing (zeroMonoid ∷ * → *) (oneMonoid ∷ * → *) (x ∷ *) = GSemiRing { getSemiRing ∷ x }
+  deriving (Eq, Ord, Read, Show, Generic)
+
+instance
+  forall zeroMonoid oneMonoid x
+  . ( Semigroup (zeroMonoid x)
+    , Monoid    (zeroMonoid x)
+    , Semigroup ( oneMonoid x)
+    , Monoid    ( oneMonoid x)
+    )
+  ⇒ SemiRing (GSemiRing zeroMonoid oneMonoid x) where
+  srplus (GSemiRing x) (GSemiRing y) =
+    let x' ∷ zeroMonoid x = unsafeCoerce x
+        y' ∷ zeroMonoid x = unsafeCoerce y
+    in  unsafeCoerce $ x' <> y'
+  srmul (GSemiRing x) (GSemiRing y) =
+    let x' ∷ oneMonoid x = unsafeCoerce x
+        y' ∷ oneMonoid x = unsafeCoerce y
+    in  unsafeCoerce $ x' <> y'
+  srzero = unsafeCoerce (mempty ∷ zeroMonoid x)
+  srone  = unsafeCoerce (mempty ∷  oneMonoid x)
+  {-# Inline srplus #-}
+  {-# Inline srmul  #-}
+  {-# Inline srzero #-}
+  {-# Inline srone  #-}
+
+-- ** Variants of 'Semigroup' structures, that use @NumericLimits@ instead of
+-- @Bounded@.
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Christian Hoener zu Siederdissen 2018
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Christian Hoener zu Siederdissen nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Numeric/Discretized.hs b/Numeric/Discretized.hs
new file mode 100644
--- /dev/null
+++ b/Numeric/Discretized.hs
@@ -0,0 +1,100 @@
+
+-- | Discretized floating point numbers, where the scaling factor is kept
+-- as two phantom types denoting the rational number used for scaling.
+
+module Numeric.Discretized where
+
+import Control.Applicative
+import Data.Proxy
+import Data.Ratio
+import Debug.Trace
+import GHC.Generics
+import GHC.TypeLits
+import GHC.Real (Ratio(..))
+
+
+
+-- | A discretized value takes a floating point number @n@ and produces @n *
+-- fromIntegral l / fromIntegral u@ where both @u@ and @l@ are given as
+-- @TypeLits@. I.e. a scaling factor of @ (u / l) = (1 / 100)@ does all
+-- calculations in subdivisions of 100.
+--
+-- The main use of a 'Discretized' value is to enable calculations with 'Int'
+-- while somewhat pretending to use floating point values.
+--
+-- Be careful with certain operations like @(*)@ as they will easily cause the
+-- numbers to arbitrarily wrong. @(+)@ and @(-)@ are fine, however.
+--
+-- NOTE Export and import of data is in the form of floating points, which can
+-- lead to additional loss of precision if one is careless!
+--
+-- TODO fast 'Show' methods required!
+--
+-- TODO blaze stuff?
+--
+-- TODO We might want to discretize @LogDomain@ style values. This requires
+-- some thought on in which direction to wrap. Maybe, we want to log-domain
+-- Discretized values, which probably just works.
+
+newtype Discretized (u ∷ Nat) (l ∷ Nat) = Discretized { getDiscretized ∷ Int }
+  deriving (Eq,Ord,Generic,Show,Read)
+
+instance (KnownNat u, KnownNat l) ⇒ Num (Discretized u l) where
+  Discretized x + Discretized y = Discretized (x+y)
+  Discretized x - Discretized y = Discretized (x-y)
+  Discretized x * Discretized y =
+    let u = fromInteger $ natVal @u Proxy
+        l = fromInteger $ natVal @l Proxy
+    in  Discretized $ (x*y*u) `div` l
+  abs (Discretized x) = Discretized (abs x)
+  signum (Discretized x) = Discretized $ signum x
+  fromInteger = Discretized . fromInteger
+  {-# Inline (+) #-}
+  {-# Inline (-) #-}
+  {-# Inline (*) #-}
+  {-# Inline abs #-}
+  {-# Inline signum #-}
+  {-# Inline fromInteger #-}
+
+instance Enum (Discretized u l) where
+  toEnum = Discretized
+  {-# Inline toEnum #-}
+  fromEnum = getDiscretized
+  {-# Inline fromEnum #-}
+
+instance (Enum (Discretized u l), KnownNat u, KnownNat l) ⇒ Integral (Discretized u l) where
+
+instance (KnownNat u, KnownNat l) ⇒ Fractional (Discretized u l) where
+  Discretized x / Discretized y =
+    let u = fromInteger $ natVal @u Proxy
+        l = fromInteger $ natVal @l Proxy
+    in  Discretized $ (x * l) `div` (y * u)
+  {-# Inline (/) #-}
+  recip (Discretized x) =
+    let u = fromInteger $ natVal @u Proxy
+        l = fromInteger $ natVal @l Proxy
+    in  error "need to find approximately ok transformation"
+  {-# Inline recip #-}
+  fromRational (a :% b) =
+    let u = natVal @u Proxy
+        l = natVal @l Proxy
+    in  Discretized . fromInteger $ (a * l) `div` (b * u)
+
+instance (KnownNat u, KnownNat l) ⇒ Real (Discretized u l) where
+  toRational (Discretized d) =
+    let u = natVal @u Proxy
+        l = natVal @l Proxy
+    in  (fromIntegral d * u) % l
+  {-# Inline toRational #-}
+
+-- | Discretizes any @Real a@ into the @Discretized@ value. This conversion
+-- is /lossy/!
+
+discretize ∷ forall a u l . (Real a, KnownNat u, KnownNat l) ⇒ a → Discretized u l
+discretize a =
+  let u = natVal @u Proxy
+      l = natVal @l Proxy
+      k = toRational a
+  in  Discretized . fromIntegral $ numerator k * l `div` (denominator k * u)
+{-# Inline discretize #-}
+
diff --git a/Numeric/Limits.hs b/Numeric/Limits.hs
new file mode 100644
--- /dev/null
+++ b/Numeric/Limits.hs
@@ -0,0 +1,46 @@
+
+-- | Approximate and exact limits around 0 and towards transfinite numbers.
+
+module Numeric.Limits where
+
+
+
+-- | The class of limits into the transfinite.
+
+class NumericLimits x where
+  -- "A" minimal finite number that can still be worked with. (And should not
+  -- trip the CPU transfinite number handling)
+  minFinite ∷ x
+  -- "A" maximal finite number.
+  maxFinite ∷ x
+
+-- | The smallest value @/= 0@ for numeric values.
+
+class NumericEpsilon x where
+  -- | Numeric epsilon.
+  epsilon ∷ x
+
+
+
+instance NumericLimits Word where
+  minFinite = minBound `div` 100000
+  maxFinite = maxBound `div` 100000
+  {-# Inline minFinite #-}
+  {-# Inline maxFinite #-}
+
+instance NumericLimits Int where
+  minFinite = minBound `div` 100000
+  maxFinite = maxBound `div` 100000
+  {-# Inline minFinite #-}
+  {-# Inline maxFinite #-}
+
+instance NumericLimits Double where
+  minFinite = -1.79e308
+  maxFinite =  1.79e308
+  {-# Inline minFinite #-}
+  {-# Inline maxFinite #-}
+
+instance NumericEpsilon Double where
+  epsilon = 2.2e-16
+  {-# Inline epsilon #-}
+
diff --git a/Numeric/LogDomain.hs b/Numeric/LogDomain.hs
new file mode 100644
--- /dev/null
+++ b/Numeric/LogDomain.hs
@@ -0,0 +1,26 @@
+
+-- | This module provides log-domain functionality. Ed Kmett provides, with
+-- @log-domain@, a generic way to handle numbers in the log-domain, some which
+-- is used under the hood here. We want some additional type safety and also
+-- connect with the 'SemiRing' module.
+
+module Numeric.LogDomain where
+
+import Control.Monad.Except
+
+
+
+-- | Instances for @LogDomain x@ should be for specific types.
+
+class LogDomain x where
+  -- | The data family to connect a type @x@ with the type @Ln x@ in the
+  -- log-domain.
+  data Ln x ∷ *
+  -- | Transport a value in @x@ into the log-domain. @logdom@ should throw an
+  -- exception if @log x@ is not valid.
+  logdom ∷ (MonadError String m) ⇒ x → m (Ln x)
+  -- | Unsafely transport x into the log-domain.
+  unsafelogdom ∷ x → Ln x
+  -- | Transport a value @Ln x@ back into the linear domain @x@.
+  lindom ∷ Ln x → x
+
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+[![Build Status](https://travis-ci.org/choener/SciBaseTypes.svg?branch=master)](https://travis-ci.org/choener/SciBaseTypes)
+
+# SciBaseTypes
+
+Base types, classes and functions shared across statistics, bioinformatics (the
+Sci in sciences), and humanities. Some of the things defined here should be
+lifted into their own libraries, once fleshed out.
+
+
+
+#### Contact
+
+Christian Hoener zu Siederdissen  
+Leipzig University, Leipzig, Germany  
+choener@bioinf.uni-leipzig.de  
+http://www.bioinf.uni-leipzig.de/~choener/  
+
diff --git a/SciBaseTypes.cabal b/SciBaseTypes.cabal
new file mode 100644
--- /dev/null
+++ b/SciBaseTypes.cabal
@@ -0,0 +1,126 @@
+Name:           SciBaseTypes
+Version:        0.0.0.1
+License:        BSD3
+License-file:   LICENSE
+Author:         Christian Hoener zu Siederdissen
+Maintainer:     choener@bioinf.uni-leipzig.de
+Copyright:      Christian Hoener zu Siederdissen, 2018
+homepage:       https://github.com/choener/SciBaseTypes
+bug-reports:    https://github.com/choener/SciBaseTypes/issues
+Stability:      Experimental
+Category:       Data
+Build-type:     Simple
+Cabal-version:  >= 1.10
+tested-with:    GHC == 8.4.4
+Synopsis:       Base types and classes for statistics, sciences and humanities
+Description:
+                This library provides a set of basic types and classes for
+                statistics, sciences, and the humanities.
+
+
+
+extra-source-files:
+  changelog.md
+  README.md
+
+
+
+library
+  exposed-modules:
+    Algebra.Structure.SemiRing
+    Numeric.Discretized
+    Numeric.Limits
+    Numeric.LogDomain
+    StatisticalMechanics.Ensemble
+    Statistics.Odds
+    Statistics.Probability
+
+  build-depends: base                     >= 4.7      &&  < 5.0
+               , aeson                    >= 1.0
+               , binary                   >= 0.7
+               , cereal                   >= 0.4
+               , deepseq                  >= 1.4
+               , hashable                 >= 1.2
+               , lens                     >= 4.0
+               , log-domain               >= 0.12
+               , mtl                      >= 2.0
+               , vector                   >= 0.10
+               , vector-th-unbox          >= 0.2
+  ghc-options:
+    -O2
+    -funbox-strict-fields
+  default-language:
+    Haskell2010
+  default-extensions: BangPatterns
+                    , ConstraintKinds
+                    , DataKinds
+                    , DeriveGeneric
+                    , FlexibleContexts
+                    , GeneralizedNewtypeDeriving
+                    , MultiParamTypeClasses
+                    , PolyKinds
+                    , RankNTypes
+                    , ScopedTypeVariables
+                    , StandaloneDeriving
+                    , TemplateHaskell
+                    , TupleSections
+                    , TypeApplications
+                    , TypeFamilies
+                    , UndecidableInstances
+                    , UnicodeSyntax
+
+
+
+benchmark BenchmarkSciBaseTypes
+  build-depends: base
+               , SciBaseTypes
+  hs-source-dirs:
+    tests
+  main-is:
+    Benchmark.hs
+  default-language:
+    Haskell2010
+  type:
+    exitcode-stdio-1.0
+  default-extensions: BangPatterns
+                    , FlexibleContexts
+                    , ScopedTypeVariables
+                    , TypeFamilies
+                    , UnicodeSyntax
+  ghc-options:
+    -O2
+    -funbox-strict-fields
+    -funfolding-use-threshold1000
+    -funfolding-keeness-factor1000
+
+
+
+test-suite properties
+  type:
+    exitcode-stdio-1.0
+  main-is:
+    properties.hs
+  ghc-options:
+    -threaded -rtsopts -with-rtsopts=-N
+  hs-source-dirs:
+    tests
+  default-language:
+    Haskell2010
+  default-extensions: BangPatterns
+                    , ScopedTypeVariables
+                    , TemplateHaskell
+                    , TypeFamilies
+                    , UnicodeSyntax
+  build-depends: base
+               , SciBaseTypes
+               , QuickCheck                   >= 2.7
+               , tasty                        >= 0.11
+               , tasty-quickcheck             >= 0.8
+               , tasty-th                     >= 0.1
+
+
+
+source-repository head
+  type: git
+  location: git://github.com/choener/SciBaseTypes
+
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
diff --git a/StatisticalMechanics/Ensemble.hs b/StatisticalMechanics/Ensemble.hs
new file mode 100644
--- /dev/null
+++ b/StatisticalMechanics/Ensemble.hs
@@ -0,0 +1,27 @@
+
+-- | This module provides generic functionality to deal with ensembles in
+-- statistical mechanics.
+
+module StatisticalMechanics.Ensemble where
+
+
+
+-- | The state probability functions provide conversion from some types @a@
+-- into non-normalized probabilities. For "real" applications, using the
+-- @logProbability@ function is preferred. This functions allows for easy
+-- abstraction when types @a@ are given as fractions of some actual value (say:
+-- deka-cal), or are discretized.
+--
+-- The returned values are not normalized, because we do not now the total
+-- evidence @Z@ until integration over all states has happened -- which is not
+-- feasible in a number of problems.
+--
+-- TODO replace @()@ with temperature and results with non-normalized @P@ or
+-- @LogP@, depending.
+
+class StateProbability a where
+  -- | Given a temperature and a state "energy", return the corresponding
+  -- non-normalized probability.
+  stateProbability    ∷ () → a → ()
+  stateLogProbability ∷ () → a → ()
+
diff --git a/Statistics/Odds.hs b/Statistics/Odds.hs
new file mode 100644
--- /dev/null
+++ b/Statistics/Odds.hs
@@ -0,0 +1,51 @@
+
+-- | Provides newtypes for odds, log-odds, and discretized versions.
+
+module Statistics.Odds where
+
+import Control.DeepSeq (NFData(..))
+import Data.Aeson (FromJSON,ToJSON)
+import Data.Binary (Binary)
+import Data.Hashable (Hashable)
+import Data.Serialize (Serialize)
+import Data.Vector.Unboxed.Deriving
+import GHC.Generics (Generic)
+
+import Numeric.Limits
+
+
+
+-- | Odds.
+
+newtype Odds = Odds { getOdds ∷ Double }
+  deriving (Generic,Eq,Ord,Show,Read,Num)
+
+-- | Encodes log-odds that have been rounded or clamped to integral numbers.
+-- One advantage this provides is more efficient "maximum/minimum" calculations
+-- compared to using @Double@s.
+--
+-- Note that these are "explicit" log-odds. Each numeric operation uses the
+-- underlying operation on @Int@.
+
+newtype DiscLogOdds = DiscLogOdds { getDiscLogOdds ∷ Int }
+  deriving (Generic,Eq,Ord,Show,Read,Num)
+
+derivingUnbox "DiscretizedLogOdds"
+  [t| DiscLogOdds → Int |]  [| getDiscLogOdds |]  [| DiscLogOdds |]
+
+instance Binary    DiscLogOdds
+instance Serialize DiscLogOdds
+instance FromJSON  DiscLogOdds
+instance ToJSON    DiscLogOdds
+instance Hashable  DiscLogOdds
+
+instance NFData DiscLogOdds where
+  rnf (DiscLogOdds k) = rnf k
+  {-# Inline rnf #-}
+
+instance NumericLimits DiscLogOdds where
+  minFinite = DiscLogOdds minFinite
+  {-# Inline minFinite #-}
+  maxFinite = DiscLogOdds maxFinite
+  {-# Inline maxFinite #-}
+
diff --git a/Statistics/Probability.hs b/Statistics/Probability.hs
new file mode 100644
--- /dev/null
+++ b/Statistics/Probability.hs
@@ -0,0 +1,123 @@
+
+-- | Probability-related types.
+--
+-- TODO instances for serialization and further stuff
+-- TODO vector instances
+
+module Statistics.Probability where
+
+import Control.Lens
+import Numeric.Log
+import Data.Vector.Unboxed.Deriving
+import Data.Vector.Unboxed (Unbox)
+
+import Algebra.Structure.SemiRing
+import Numeric.LogDomain
+import Numeric.Limits
+
+
+
+data IsNormalized = Normalized | NotNormalized
+
+
+
+-- * Probability in linear space
+
+-- | @Prob@ wraps a @Double@ that encodes probabilities. If @Prob@ is tagged as
+-- @Normalized@, the contained values are in the range @[0,...,1]@, otherwise
+-- they are in the range @[0,...,∞]@.
+
+newtype Prob (n ∷ IsNormalized) x = Prob { getProb ∷ x }
+  deriving (Eq,Ord,Show,Read)
+
+derivingUnbox "Prob"
+  [t| forall n x. Unbox x ⇒ Prob n x → x |]  [| getProb |]  [| Prob |]
+
+deriving instance (Enum       x) ⇒ Enum       (Prob n x)
+deriving instance (Num        x) ⇒ Num        (Prob n x)
+deriving instance (Fractional x) ⇒ Fractional (Prob n x)
+deriving instance (Floating   x) ⇒ Floating   (Prob n x)
+deriving instance (Real       x) ⇒ Real       (Prob n x)
+deriving instance (RealFrac   x) ⇒ RealFrac   (Prob n x)
+deriving instance (RealFloat  x) ⇒ RealFloat  (Prob n x)
+
+instance (Num r) ⇒ SemiRing (Prob n r) where
+  srplus = (+)
+  srmul  = (*)
+  srzero = 0
+  srone  = 1
+
+-- | Turns a value into a normalized probability. @error@ if the value is not
+-- in the range @[0,...,1]@.
+
+prob ∷ (Ord x, Num x, Show x) ⇒ x → Prob Normalized x
+prob x
+  | x >= 0 && x <= 1 = Prob x
+  | otherwise        = error $ show x ++ " not in range of [0,...,1]"
+{-# Inline prob #-}
+
+-- | Simple wrapper around @Prob@ that fixes non-normalization.
+
+prob' ∷ (Ord x, Num x, Show x) ⇒ x → Prob NotNormalized x
+prob' = Prob
+{-# Inline prob' #-}
+
+
+
+-- * Probability in log space. A number of operations internally cast to @Log@
+-- from @log-domain@, but the values themselves are *not* newtype-wrapped @Log
+-- x@ values. This is because we want to be *explicit* that these are
+-- log-probabilities.
+--
+-- @Log@ numbers in cases like @fromIntegral 1 :: Log Double@ are treated as
+-- not being in the log-domain, hence @fromIntegral performs a @log@
+-- operations.
+
+newtype LogProb (n ∷ IsNormalized) x = LogProb { getLogProb ∷ x }
+  deriving (Eq,Ord,Show)
+
+derivingUnbox "LogProb"
+  [t| forall n x. Unbox x ⇒ LogProb n x → x |]  [| getLogProb |]  [| LogProb |]
+
+instance (Precise x, RealFloat x) ⇒ Num (LogProb n x) where
+  (+) = withLog2 (+)
+  (*) = withLog2 (*)
+  abs = withLog1 abs
+  signum = withLog1 signum
+  fromInteger = LogProb . fromInteger
+  negate = withLog1 negate
+  (-) = withLog2 (-)
+
+instance (Num d, Fractional d) ⇒ NumericLimits (LogProb n d) where
+  minFinite = LogProb 0
+  maxFinite = LogProb (1/0)
+
+withLog1 ∷ (Log x → Log y) → LogProb n x → LogProb n y
+withLog1 op (LogProb x) = LogProb . ln $ op (Exp x)
+{-# Inline withLog1 #-}
+
+withLog2 ∷ (Log x → Log y → Log z) → LogProb n x → LogProb n y → LogProb n z
+withLog2 op (LogProb x) (LogProb y) = LogProb . ln $ op (Exp x) (Exp y)
+{-# Inline withLog2 #-}
+
+
+-- * Conversion between probability in linear and log-space.
+
+-- | Turn probability into log-probability.
+
+p2lp ∷ (Floating x) ⇒ Prob n x → LogProb n x
+p2lp (Prob x) = LogProb $ log x
+{-# Inline p2lp #-}
+
+-- | Turn log-probability into probability.
+
+lp2p ∷ (Floating x) ⇒ LogProb n x → Prob n x
+lp2p (LogProb x) = Prob $ exp x
+{-# Inline lp2p #-}
+
+-- | An isomorphism between @Prob@ and @LogProb@.
+
+aslp ∷ (Floating x) ⇒ Iso' (Prob n x) (LogProb n x)
+aslp = iso p2lp lp2p
+{-# Inline aslp #-}
+
diff --git a/changelog.md b/changelog.md
new file mode 100644
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,4 @@
+0.0.0.1
+-------
+
+- initial creation
diff --git a/tests/Benchmark.hs b/tests/Benchmark.hs
new file mode 100644
--- /dev/null
+++ b/tests/Benchmark.hs
@@ -0,0 +1,8 @@
+
+module Main where
+
+
+
+main ∷ IO ()
+main = return ()
+
diff --git a/tests/properties.hs b/tests/properties.hs
new file mode 100644
--- /dev/null
+++ b/tests/properties.hs
@@ -0,0 +1,8 @@
+
+module Main where
+
+-- * Test @Numeric.Discretized@.
+
+main ∷ IO ()
+main = return ()
+
