diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,7 +2,14 @@
 # Changelog for ELynx
 
 
-## Version 0.3.1; in development
+## Version 0.3.2; in development
+
+
+## Version 0.3.1
+
+-   Use Attoparsec.
+-   Use ByteString consistently.
+-   Remove elynx-tools dependency from libaries.
 
 
 ## Version 0.3.0
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 # The ELynx Suite
 
-Version: 0.3.0.
+Version: 0.3.1.
 Reproducible evolution made easy.
 
 <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>
@@ -90,9 +90,9 @@
 
     slynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -136,9 +136,9 @@
 
     slynx concatenate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE
       Concatenate sequences found in input files.
@@ -157,9 +157,9 @@
 
     slynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site]
       Examine sequences. If data is a multi sequence alignment, additionally analyze columns.
@@ -179,9 +179,9 @@
 
     slynx filter-rows --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] 
                              [--shorter-than LENGTH] [--standard-characters]
@@ -202,9 +202,9 @@
 
     slynx filter-columns --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE 
                                 [--standard-chars DOUBLE]
@@ -226,9 +226,9 @@
 
     slynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] 
                           [-m|--mixture-model MODEL] [-e|--edm-file NAME] 
@@ -305,9 +305,9 @@
 
     slynx sub-sample --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE
                             (-n|--number-of-sites INT)
@@ -335,9 +335,9 @@
 
     slynx translate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT)
                            (-u|--universal-code CODE)
@@ -360,9 +360,9 @@
 
     tlynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -399,9 +399,9 @@
 
     tlynx compare --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] 
                          [-f|--newick-format FORMAT] NAMES
@@ -428,9 +428,9 @@
 
     tlynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT]
       Compute summary statistics of phylogenetic trees.
@@ -452,9 +452,9 @@
 
     tlynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE] 
                           [-M|--condition-on-mrca] [-l|--lambda DOUBLE] 
@@ -491,9 +491,9 @@
 
     elynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: elynx COMMAND
       Validate and redo past ELynx analyses
diff --git a/elynx-tools.cabal b/elynx-tools.cabal
--- a/elynx-tools.cabal
+++ b/elynx-tools.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: ce20a53fa80c7478a01a9fc6ab5b4549475e79e193a58b3e925239f9513502af
+-- hash: a88ba56b54f3dbb5277c662a4a76fedadc3f78e23d8ae3f2132c17f8aee2969e
 
 name:           elynx-tools
-version:        0.3.0
+version:        0.3.1
 synopsis:       Tools for ELynx
 description:    Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
 category:       Bioinformatics
@@ -39,13 +39,10 @@
       ELynx.Tools.LinearAlgebra
       ELynx.Tools.List
       ELynx.Tools.Logger
-      ELynx.Tools.Matrix
       ELynx.Tools.Misc
       ELynx.Tools.Numeric
-      ELynx.Tools.Parallel
       ELynx.Tools.Reproduction
       ELynx.Tools.Text
-      ELynx.Tools.Vector
       Paths_elynx_tools
   autogen-modules:
       Paths_elynx_tools
@@ -54,23 +51,19 @@
   ghc-options: -Wall -fllvm
   build-depends:
       aeson
-    , async
+    , attoparsec
     , base >=4.7 && <5
     , base16-bytestring
     , bytestring
-    , containers
     , cryptohash-sha256
     , deepseq
     , directory
     , fast-logger
     , hmatrix
-    , matrices
-    , megaparsec
     , monad-control
     , monad-logger
     , mwc-random
     , optparse-applicative
-    , parallel
     , primitive
     , template-haskell
     , text
diff --git a/src/ELynx/Tools.hs b/src/ELynx/Tools.hs
--- a/src/ELynx/Tools.hs
+++ b/src/ELynx/Tools.hs
@@ -20,13 +20,10 @@
     module ELynx.Tools.LinearAlgebra,
     module ELynx.Tools.List,
     module ELynx.Tools.Logger,
-    module ELynx.Tools.Matrix,
     module ELynx.Tools.Misc,
     module ELynx.Tools.Numeric,
-    module ELynx.Tools.Parallel,
     module ELynx.Tools.Reproduction,
     module ELynx.Tools.Text,
-    module ELynx.Tools.Vector,
   )
 where
 
@@ -38,10 +35,7 @@
 import ELynx.Tools.LinearAlgebra
 import ELynx.Tools.List
 import ELynx.Tools.Logger
-import ELynx.Tools.Matrix
 import ELynx.Tools.Misc
 import ELynx.Tools.Numeric
-import ELynx.Tools.Parallel
 import ELynx.Tools.Reproduction
 import ELynx.Tools.Text
-import ELynx.Tools.Vector
diff --git a/src/ELynx/Tools/ByteString.hs b/src/ELynx/Tools/ByteString.hs
--- a/src/ELynx/Tools/ByteString.hs
+++ b/src/ELynx/Tools/ByteString.hs
@@ -16,51 +16,33 @@
     alignRight,
     alignLeftWith,
     alignLeft,
-    summarizeByteString,
-    c2w,
-    w2c,
-    bShow,
   )
 where
 
-import Data.ByteString.Internal
-  ( c2w,
-    w2c,
-  )
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Lazy.Char8 as BL
 
 -- | For a given width, align string to the right; use given fill character;
 -- trim on the left if string is longer.
-alignRightWith :: Char -> Int -> L.ByteString -> L.ByteString
+alignRightWith :: Char -> Int -> BL.ByteString -> BL.ByteString
 alignRightWith c n s =
-  L.replicate (fromIntegral n - l) c <> L.take (fromIntegral n) s
+  BL.replicate (fromIntegral n - l) c <> BL.take (fromIntegral n) s
   where
-    l = L.length s
+    l = BL.length s
 
 -- | For a given width, align string to the right; trim on the left if string is
 -- longer.
-alignRight :: Int -> L.ByteString -> L.ByteString
+alignRight :: Int -> BL.ByteString -> BL.ByteString
 alignRight = alignRightWith ' '
 
 -- | For a given width, align string to the left; use given fill character; trim
 -- on the right if string is longer.
-alignLeftWith :: Char -> Int -> L.ByteString -> L.ByteString
+alignLeftWith :: Char -> Int -> BL.ByteString -> BL.ByteString
 alignLeftWith c n s =
-  L.take (fromIntegral n) s <> L.replicate (fromIntegral n - l) c
+  BL.take (fromIntegral n) s <> BL.replicate (fromIntegral n - l) c
   where
-    l = L.length s
+    l = BL.length s
 
 -- | For a given width, align string to the left; trim on the right if string is
 -- longer.
-alignLeft :: Int -> L.ByteString -> L.ByteString
+alignLeft :: Int -> BL.ByteString -> BL.ByteString
 alignLeft = alignLeftWith ' '
-
--- | If a string is longer than a given value, trim it and add some dots.
-summarizeByteString :: Int -> L.ByteString -> L.ByteString
-summarizeByteString l s
-  | L.length s >= fromIntegral l = L.take (fromIntegral l) s <> L.pack "..."
-  | otherwise = s
-
--- | Conversion to 'L.ByteString'.
-bShow :: Show a => a -> L.ByteString
-bShow = L.pack . show
diff --git a/src/ELynx/Tools/Concurrent.hs b/src/ELynx/Tools/Concurrent.hs
--- a/src/ELynx/Tools/Concurrent.hs
+++ b/src/ELynx/Tools/Concurrent.hs
@@ -16,13 +16,10 @@
     splitGen,
 
     -- * Concurrent calculations
-    parComp,
     getChunks,
   )
 where
 
-import Control.Concurrent
-import Control.Concurrent.Async
 import Control.Monad
 import Control.Monad.Primitive
 import qualified Data.Vector as V
@@ -36,24 +33,6 @@
   | otherwise = do
     seeds :: [V.Vector Word32] <- replicateM (n -1) $ uniformVector gen 256
     fmap (gen :) (mapM initialize seeds)
-
--- -- XXX: This just doesn't work... The only thing I found:
--- -- https://stackoverflow.com/a/16250010.
--- parComp :: (PrimMonad m, Monoid b) => Int -> (Int -> Gen (PrimState m) -> m b)
---         -> Gen (PrimState m) -> m b
--- parComp num fun gen = do
---   let ncap   = ceiling (fromIntegral num / fromIntegral chunksize :: Double)
---       chunks = getChunks ncap num
---   gs <- splitGen ncap gen
---   mconcat <$> P.mapM (\(n', g') -> fun n' g') (zip chunks gs)
-
--- | Perform random calculation in parallel. Does only work with 'IO' and the moment.
-parComp :: Int -> (Int -> GenIO -> IO b) -> GenIO -> IO [b]
-parComp num fun gen = do
-  ncap <- getNumCapabilities
-  let chunks = getChunks ncap num
-  gs <- splitGen ncap gen
-  mapConcurrently (uncurry fun) (zip chunks gs)
 
 -- | For a given number of capabilities and number of calculations, get chunk
 -- sizes. The chunk sizes will be as evenly distributed as possible and sum up
diff --git a/src/ELynx/Tools/Definitions.hs b/src/ELynx/Tools/Definitions.hs
--- a/src/ELynx/Tools/Definitions.hs
+++ b/src/ELynx/Tools/Definitions.hs
@@ -11,42 +11,15 @@
 -- Creation date: Fri Jan 25 17:17:41 2019.
 module ELynx.Tools.Definitions
   ( -- * Definitions
-    chunksize,
     eps,
-    eps',
     precision,
-    version,
   )
 where
 
-import Data.Version
-
--- TODO: Move back to automatic version handling.
-
--- XXX: Manually handled, because automatic handling with @Paths_...@ modules
--- results in errors during source tarball creation and upload.
-
--- Careful, this version number has to be synchronized with the one specified in
--- the *.cabal files. This is done with the @bump-version@ script.
-
--- | ELynx version.
-version :: Version
-version = makeVersion [0, 3, 0]
-
 -- | Required precision when comparing 'Double' values.
 eps :: Double
 eps = 1e-12
 
--- | Relaxed required precision when comparing 'Double' values. Often, input
--- files do not provide the required double precision. In this case, it is only
--- possible to check input with relaxed bounds.
-eps' :: Double
-eps' = 1e-5
-
 -- | Default output precision.
 precision :: Int
 precision = 3
-
--- | Default chunk size for parallel evaluations.
-chunksize :: Int
-chunksize = 500
diff --git a/src/ELynx/Tools/InputOutput.hs b/src/ELynx/Tools/InputOutput.hs
--- a/src/ELynx/Tools/InputOutput.hs
+++ b/src/ELynx/Tools/InputOutput.hs
@@ -45,9 +45,9 @@
 import Control.Monad.IO.Class
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy.Char8 as L
+import Data.Attoparsec.ByteString.Lazy
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.List (isSuffixOf)
-import Data.Maybe
 import qualified Data.Text as T
 import ELynx.Tools.Reproduction
   ( Arguments (..),
@@ -59,7 +59,6 @@
   )
 import System.Directory (doesFileExist)
 import System.IO
-import Text.Megaparsec
 
 -- | Get out file path with extension.
 getOutFilePath ::
@@ -91,94 +90,60 @@
 
 -- XXX: For now, all files are read strictly (see help of
 -- Control.DeepSeq.force).
-readFile' :: FilePath -> IO L.ByteString
-readFile' fn = withFile fn ReadMode $ (evaluate . force) <=< L.hGetContents
+readFile' :: FilePath -> IO BL.ByteString
+readFile' fn = withFile fn ReadMode $ (evaluate . force) <=< BL.hGetContents
 
 -- | Read file. If file path ends with ".gz", assume gzipped file and decompress
 -- before read.
-readGZFile :: FilePath -> IO L.ByteString
+readGZFile :: FilePath -> IO BL.ByteString
 readGZFile f
   | ".gz" `isSuffixOf` f = decompress <$> readFile' f
   | otherwise = readFile' f
 
 -- | Write file. If file path ends with ".gz", assume gzipped file and compress
 -- before write.
-writeGZFile :: Force -> FilePath -> L.ByteString -> IO ()
+writeGZFile :: Force -> FilePath -> BL.ByteString -> IO ()
 writeGZFile frc f r
-  | ".gz" `isSuffixOf` f = checkFile frc f >> L.writeFile f (compress r)
-  | otherwise = checkFile frc f >> L.writeFile f r
+  | ".gz" `isSuffixOf` f = checkFile frc f >> BL.writeFile f (compress r)
+  | otherwise = checkFile frc f >> BL.writeFile f r
 
 -- | Parse a possibly gzipped file.
-runParserOnFile ::
-  Parsec e L.ByteString a ->
-  FilePath ->
-  IO (Either (ParseErrorBundle L.ByteString e) a)
-runParserOnFile p f = parse p f <$> readGZFile f
+runParserOnFile :: Parser a -> FilePath -> IO (Either String a)
+runParserOnFile p f = eitherResult . parse p <$> readGZFile f
 
 -- | Parse a possibly gzipped file and extract the result.
-parseFileWith ::
-  (ShowErrorComponent e) =>
-  -- | The parser.
-  Parsec e L.ByteString a ->
-  FilePath ->
-  IO a
+parseFileWith :: Parser a -> FilePath -> IO a
 parseFileWith p f = parseFileOrIOWith p (Just f)
 
 -- | Parse standard input.
-parseIOWith ::
-  (ShowErrorComponent e) =>
-  -- | The parser.
-  Parsec e L.ByteString a ->
-  IO a
-parseIOWith p = parseByteStringWith "Standard input" p <$> L.getContents
+parseIOWith :: Parser a -> IO a
+parseIOWith p = parseFileOrIOWith p Nothing
 
 -- | Parse a possibly gzipped file, or standard input, and extract the result.
-parseFileOrIOWith ::
-  (ShowErrorComponent e) =>
-  -- | The parser.
-  Parsec e L.ByteString a ->
-  -- | If no file path is given, standard input is used.
-  Maybe FilePath ->
-  IO a
+parseFileOrIOWith :: Parser a -> Maybe FilePath -> IO a
 parseFileOrIOWith p mf = do
-  contents <- maybe L.getContents readGZFile mf
-  return $ parseByteStringWith (fromMaybe "Standard input" mf) p contents
+  s <- maybe BL.getContents readGZFile mf
+  return $ parseByteStringWith p s
 
 -- | Parse a 'String' and extract the result.
-parseStringWith ::
-  (ShowErrorComponent e) =>
-  -- | Name of string.
-  String ->
-  -- | Parser.
-  Parsec e L.ByteString a ->
-  -- | Input.
-  String ->
-  a
-parseStringWith s p l = parseByteStringWith s p (L.pack l)
+parseStringWith :: Parser a -> String -> a
+parseStringWith p x = parseByteStringWith p (BL.pack x)
 
--- | Parse a 'L.ByteString' and extract the result.
-parseByteStringWith ::
-  (ShowErrorComponent e) =>
-  -- | Name of byte string.
-  String ->
-  -- | Parser.
-  Parsec e L.ByteString a ->
-  -- | Input.
-  L.ByteString ->
-  a
-parseByteStringWith s p l = case parse p s l of
-  Left err -> error $ errorBundlePretty err
+-- | Parse a 'BL.ByteString' and extract the result.
+parseByteStringWith :: Parser a -> BL.ByteString -> a
+parseByteStringWith p x = case eitherResult $ parse p x of
+  Left err -> error err
   Right val -> val
 
 -- | Write a result with a given name to file with given extension or standard
 -- output. Supports compression.
-out :: Reproducible a => String -> L.ByteString -> String -> ELynx a ()
+out :: Reproducible a => String -> BL.ByteString -> String -> ELynx a ()
 out name res ext = do
   mfp <- getOutFilePath ext
   case mfp of
     Nothing -> do
       $(logInfo) $ T.pack $ "Write " <> name <> " to standard output."
-      liftIO $ L.putStr res
+      liftIO $ BL.putStr res
     Just fp -> do
       $(logInfo) $ T.pack $ "Write " <> name <> " to file '" <> fp <> "'."
       frc <- forceReanalysis . global <$> ask
diff --git a/src/ELynx/Tools/LinearAlgebra.hs b/src/ELynx/Tools/LinearAlgebra.hs
--- a/src/ELynx/Tools/LinearAlgebra.hs
+++ b/src/ELynx/Tools/LinearAlgebra.hs
@@ -34,6 +34,7 @@
 -- | Set the diagonal entries of a matrix to zero.
 matrixSetDiagToZero :: Matrix R -> Matrix R
 matrixSetDiagToZero m = m - diag (takeDiag m)
+{-# INLINE matrixSetDiagToZero #-}
 
 -- | Display a vector with given precision.
 dispv :: Int -> Vector R -> String
diff --git a/src/ELynx/Tools/Logger.hs b/src/ELynx/Tools/Logger.hs
--- a/src/ELynx/Tools/Logger.hs
+++ b/src/ELynx/Tools/Logger.hs
@@ -24,57 +24,15 @@
 
 import Control.Monad.Base (liftBase)
 import Control.Monad.IO.Class
-  ( MonadIO,
-    liftIO,
-  )
 import Control.Monad.Logger
-  ( Loc,
-    LogLevel,
-    LogSource,
-    LoggingT,
-    MonadLogger,
-    filterLogger,
-    logInfo,
-    runLoggingT,
-  )
 import Control.Monad.Trans.Control (MonadBaseControl)
 import Control.Monad.Trans.Reader (ReaderT (runReaderT))
-import qualified Data.ByteString.Char8 as B
+import qualified Data.ByteString.Char8 as BS
 import Data.Text
-  ( Text,
-    pack,
-  )
 import ELynx.Tools.InputOutput (openFile')
 import ELynx.Tools.Reproduction
-  ( Arguments (..),
-    ELynx,
-    Force,
-    GlobalArguments (..),
-    Reproducible (..),
-    Seed (..),
-    ToJSON,
-    logFooter,
-    logHeader,
-    toLogLevel,
-    writeReproduction,
-  )
 import System.IO
-  ( BufferMode (LineBuffering),
-    Handle,
-    IOMode (WriteMode),
-    hClose,
-    hSetBuffering,
-    stderr,
-  )
-import System.Log.FastLogger
-  ( LogStr,
-    fromLogStr,
-  )
 import System.Random.MWC
-  ( createSystemRandom,
-    fromSeed,
-    save,
-  )
 
 -- | Unified way of creating a new section in the log.
 logNewSection :: MonadLogger m => Text -> m ()
@@ -155,11 +113,11 @@
 runELynxStderrLoggingT = (`runLoggingT` output stderr)
 
 output :: Handle -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
-output h _ _ _ msg = B.hPutStrLn h ls where ls = fromLogStr msg
+output h _ _ _ msg = BS.hPutStrLn h ls where ls = fromLogStr msg
 
 output2H :: Handle -> Handle -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
 output2H h1 h2 _ _ _ msg = do
-  B.hPutStrLn h1 ls
-  B.hPutStrLn h2 ls
+  BS.hPutStrLn h1 ls
+  BS.hPutStrLn h2 ls
   where
     ls = fromLogStr msg
diff --git a/src/ELynx/Tools/Matrix.hs b/src/ELynx/Tools/Matrix.hs
deleted file mode 100644
--- a/src/ELynx/Tools/Matrix.hs
+++ /dev/null
@@ -1,101 +0,0 @@
--- |
--- Module      :  ELynx.Tools.Matrix
--- Copyright   :  (c) Dominik Schrempf 2020
--- License     :  GPL-3.0-or-later
---
--- Maintainer  :  dominik.schrempf@gmail.com
--- Stability   :  unstable
--- Portability :  portable
---
--- Creation date: Thu Feb 14 13:33:13 2019.
---
--- Tools for matrices from 'Numeric.LinearAlgebra'.
-module ELynx.Tools.Matrix
-  ( -- * Matrices
-    fMapRowSeq,
-    fMapRowPar,
-    fMapRowParChunk,
-    fMapColSeq,
-    fMapColPar,
-    fMapColParChunk,
-    (|||),
-    (===),
-    subSampleMatrix,
-  )
-where
-
-import Control.Parallel.Strategies
-import Data.List
-import qualified Data.Matrix.Generic as M
-import qualified Data.Vector.Generic as V
-
--- | Map a function on each row of a DIM2 array; sequential version.
-fMapRowSeq ::
-  (V.Vector v a, V.Vector v b) =>
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapRowSeq f m = M.fromRows $ map f (M.toRows m)
-
--- | Map a function on each row of a DIM2 array; parallel version.
-fMapRowPar ::
-  (V.Vector v a, V.Vector v b) =>
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapRowPar f m = M.fromRows $ parMap rseq f (M.toRows m)
-
--- | Map a function on each row of a DIM2 array; parallel version with given chunk size.
-fMapRowParChunk ::
-  (V.Vector v a, V.Vector v b) =>
-  Int ->
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapRowParChunk n f m =
-  M.fromRows (map f (M.toRows m) `using` parListChunk n rseq)
-
--- | Map a function on each row of a DIM2 array; sequential version.
-fMapColSeq ::
-  (V.Vector v a, V.Vector v b) =>
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapColSeq f m = M.fromColumns $ map f (M.toColumns m)
-
--- | Map a function on each row of a DIM2 array; parallel version.
-fMapColPar ::
-  (V.Vector v a, V.Vector v b) =>
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapColPar f m = M.fromColumns $ parMap rseq f (M.toColumns m)
-
--- | Map a function on each row of a DIM2 array; parallel version with given chunk size.
-fMapColParChunk ::
-  (V.Vector v a, V.Vector v b) =>
-  Int ->
-  (v a -> v b) ->
-  M.Matrix v a ->
-  M.Matrix v b
-fMapColParChunk n f m =
-  M.fromColumns (map f (M.toColumns m) `using` parListChunk n rseq)
-
--- | Horizontal concatenation.
-(|||) :: (V.Vector v a) => M.Matrix v a -> M.Matrix v a -> M.Matrix v a
-(|||) l r = M.fromColumns $ lCs ++ rCs
-  where
-    lCs = M.toColumns l
-    rCs = M.toColumns r
-
--- | Vertical concatenation.
-(===) :: (V.Vector v a) => M.Matrix v a -> M.Matrix v a -> M.Matrix v a
-(===) l r = M.fromRows $ lRs ++ rRs
-  where
-    lRs = M.toRows l
-    rRs = M.toRows r
-
--- | Sample the given sites from a matrix.
-subSampleMatrix :: (V.Vector v a) => [Int] -> M.Matrix v a -> M.Matrix v a
-subSampleMatrix is m =
-  M.fromColumns $ foldl' (\a i -> M.takeColumn m i : a) [] is
diff --git a/src/ELynx/Tools/Misc.hs b/src/ELynx/Tools/Misc.hs
--- a/src/ELynx/Tools/Misc.hs
+++ b/src/ELynx/Tools/Misc.hs
@@ -11,10 +11,7 @@
 --
 -- Miscellaneous tools that do not have their own category (yet).
 module ELynx.Tools.Misc
-  ( -- * Not yet classified stuff
-    ensure,
-
-    -- * Weird stuff
+  ( -- * Weird stuff
     compose,
     allValues,
     horizontalConcat,
@@ -38,9 +35,3 @@
 horizontalConcat :: [[[a]]] -> [[a]]
 horizontalConcat [xs] = xs
 horizontalConcat xss = foldl' (zipWith (++)) (head xss) (tail xss)
-
--- | Ensure that a value satisfies a given predicate.
-ensure :: (a -> Bool) -> a -> Maybe a
-ensure p v
-  | p v = Just v
-  | otherwise = Nothing
diff --git a/src/ELynx/Tools/Numeric.hs b/src/ELynx/Tools/Numeric.hs
--- a/src/ELynx/Tools/Numeric.hs
+++ b/src/ELynx/Tools/Numeric.hs
@@ -13,24 +13,14 @@
 module ELynx.Tools.Numeric
   ( -- * Numeric
     harmonic,
-    xLogX,
     roundN,
   )
 where
 
-import ELynx.Tools.Equality
-
 -- | Calculate the nth harmonic number.
 harmonic :: Int -> Double
 harmonic 1 = 1.0
 harmonic n = 1.0 / fromIntegral n + harmonic (n - 1)
-
--- | Calculate x*log(x) but set to 0.0 when x is smaller than 'eps'.
-xLogX :: Double -> Double
-xLogX x
-  | x < 0.0 = error "Argument lower than zero."
-  | x `nearlyEq` 0.0 = 0.0
-  | otherwise = x * log x
 
 -- | Round double to a given precision.
 roundN :: Int -> Double -> Double
diff --git a/src/ELynx/Tools/Parallel.hs b/src/ELynx/Tools/Parallel.hs
deleted file mode 100644
--- a/src/ELynx/Tools/Parallel.hs
+++ /dev/null
@@ -1,21 +0,0 @@
--- |
--- Module      :  ELynx.Tools.Parallel
--- Description :  Utility functions for parallel calculations
--- Copyright   :  (c) Dominik Schrempf 2020
--- License     :  GPL-3.0-or-later
---
--- Maintainer  :  dominik.schrempf@gmail.com
--- Stability   :  unstable
--- Portability :  portable
---
--- Creation date: Tue Apr 21 15:19:44 2020.
-module ELynx.Tools.Parallel
-  ( parMapChunk,
-  )
-where
-
-import Control.Parallel.Strategies
-
--- | Parallel map with given chunk size.
-parMapChunk :: Int -> (a -> b) -> [a] -> [b]
-parMapChunk n f as = map f as `using` parListChunk n rseq
diff --git a/src/ELynx/Tools/Reproduction.hs b/src/ELynx/Tools/Reproduction.hs
--- a/src/ELynx/Tools/Reproduction.hs
+++ b/src/ELynx/Tools/Reproduction.hs
@@ -47,7 +47,6 @@
     createCommandReproducible,
     createCommand,
     elynxParserInfo,
-    megaReadM,
 
     -- * Re-exports
     Generic,
@@ -56,44 +55,25 @@
   )
 where
 
-import Control.Monad (void)
+import Control.Monad
 import Control.Monad.Logger
-  ( LogLevel (..),
-    LoggingT,
-  )
-import Control.Monad.Trans.Reader (ReaderT)
-import Crypto.Hash.SHA256 (hash)
-import Data.Aeson
-  ( FromJSON,
-    ToJSON,
-    encodeFile,
-  )
-import Data.ByteString.Base16 (encode)
-import qualified Data.ByteString.Char8 as B
+import Control.Monad.Trans.Reader hiding (local)
+import Crypto.Hash.SHA256
+import Data.Aeson hiding (encode)
+import Data.ByteString.Base16
+import qualified Data.ByteString.Char8 as BS
 import Data.List hiding (group)
 import Data.Time
 import Data.Vector.Unboxed (Vector)
 import Data.Version
-  ( Version,
-    showVersion,
-  )
-import Data.Void
 import Data.Word
-import ELynx.Tools.Definitions (version)
-import ELynx.Tools.Misc (allValues)
-import GHC.Generics (Generic)
+import ELynx.Tools.Misc
+import GHC.Generics
 import Language.Haskell.TH
 import Options.Applicative hiding (empty)
 import Options.Applicative.Help.Pretty
 import System.Environment
-  ( getArgs,
-    getProgName,
-  )
-import Text.Megaparsec
-  ( Parsec,
-    errorBundlePretty,
-    runParser,
-  )
+import Paths_elynx_tools
 
 -- Be careful; it is necessary to synchronize the version numbers across packages.
 versionString :: String
@@ -340,10 +320,10 @@
 -- | A unique hash of the reproduction data type.
 getReproductionHash :: forall a. Reproducible a => Reproduction a -> String
 getReproductionHash r =
-  B.unpack $
+  BS.unpack $
     encode $
       hash $
-        B.pack $
+        BS.pack $
           unlines $
             -- Reproduction.
             progName r :
@@ -387,8 +367,8 @@
 instance ToJSON a => ToJSON (Reproduction a)
 
 -- | Helper function.
-hashFile :: FilePath -> IO B.ByteString
-hashFile f = encode . hash <$> B.readFile f
+hashFile :: FilePath -> IO BS.ByteString
+hashFile f = encode . hash <$> BS.readFile f
 
 -- | Write an ELynx reproduction file.
 writeReproduction ::
@@ -403,7 +383,7 @@
   let outFs = map (bn ++) (outSuffixes r)
   let fs = inFiles r ++ outFs
   cs <- mapM hashFile fs
-  let cs' = map B.unpack cs
+  let cs' = map BS.unpack cs
       s = Reproduction pn as version Nothing fs cs' r
   void $ encodeFile (bn <> ".elynx") (setHash s)
 
@@ -451,14 +431,6 @@
     (fullDesc <> headerDoc (Just hdr') <> progDescDoc dsc <> footerDoc ftr)
   where
     hdr' = vsep $ map pretty hdr
-
--- | See 'eitherReader', but for Megaparsec.
-megaReadM :: Parsec Void String a -> ReadM a
-megaReadM p = eitherReader $ \input ->
-  let eea = runParser p "" input
-   in case eea of
-        Left eb -> Left $ errorBundlePretty eb
-        Right a -> Right a
 
 -- | Fill a string so that it becomes a paragraph with line breaks. Useful for
 -- descriptions, headers and footers.
diff --git a/src/ELynx/Tools/Text.hs b/src/ELynx/Tools/Text.hs
--- a/src/ELynx/Tools/Text.hs
+++ b/src/ELynx/Tools/Text.hs
@@ -17,7 +17,7 @@
   )
 where
 
-import Data.ByteString.Lazy (ByteString)
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.Text
   ( Text,
     pack,
@@ -30,5 +30,5 @@
 tShow = pack . show
 
 -- | Conversion to 'Text' from bytestring.
-fromBs :: ByteString -> Text
+fromBs :: BL.ByteString -> Text
 fromBs = toStrict . decodeUtf8
diff --git a/src/ELynx/Tools/Vector.hs b/src/ELynx/Tools/Vector.hs
deleted file mode 100644
--- a/src/ELynx/Tools/Vector.hs
+++ /dev/null
@@ -1,60 +0,0 @@
--- |
--- Module      :  ELynx.Tools.Vector
--- Copyright   :  (c) Dominik Schrempf 2020
--- License     :  GPL-3.0-or-later
---
--- Maintainer  :  dominik.schrempf@gmail.com
--- Stability   :  unstable
--- Portability :  portable
---
--- Creation date: Thu Feb 14 13:33:13 2019.
---
--- Tools for vectors from 'Data.Vector.Generic'.
-module ELynx.Tools.Vector
-  ( -- * Vectors
-    sumVec,
-    normalizeSumVec,
-    uniformVec,
-    meanVec,
-    chopVec,
-    randomInsertVec,
-  )
-where
-
-import Control.Monad.Primitive
-import qualified Data.Vector.Generic as V
-import System.Random.MWC
-
--- | Sum of elements.
-sumVec :: (Num a, V.Vector v a) => v a -> a
-sumVec = V.foldl' (+) 0
-
--- | Normalize a vector such that elements sum to a given value.
-normalizeSumVec :: (Fractional a, V.Vector v a) => a -> v a -> v a
-normalizeSumVec c v = V.map (* c') v
-  where
-    s = sumVec v
-    c' = c / s
-
--- | A uniform vector of given length.
-uniformVec :: (Fractional a, V.Vector v a) => Int -> v a
-uniformVec n = V.replicate n (1 / fromIntegral n)
-
--- | Mean of a vector.
-meanVec :: (Fractional a, V.Vector v a) => v a -> a
-meanVec v = sumVec v / fromIntegral (V.length v)
-
--- | Chop list into chunks of given length. If the last chop is shorter than
--- length, it is dropped.
-chopVec :: V.Vector v a => Int -> v a -> [v a]
-chopVec n xs
-  | V.length xs < n = []
-  | otherwise = V.take n xs : chopVec n (V.drop n xs)
-
--- | Insert element into random position of vector.
-randomInsertVec ::
-  (PrimMonad m, V.Vector v a) => a -> v a -> Gen (PrimState m) -> m (v a)
-randomInsertVec e v g = do
-  let l = V.length v
-  i <- uniformR (0, l) g
-  return $ V.take i v V.++ V.singleton e V.++ V.drop i v
