diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,16 @@
+0.18.0.0
+--------
+
+    * Many new functions and instances in the Static module
+
+    * meanCov and gaussianSample use Herm type
+
+    * thinQR, thinRQ
+
+    * compactSVDTol
+
+    * unitary changed to normalize, also admits Vector (Complex Double)
+
 0.17.0.0
 --------
 
@@ -275,4 +288,3 @@
     * added NFData instances for Matrix and Vector.
 
     * liftVector, liftVector2 replaced by mapVector, zipVector.
-
diff --git a/THANKS.md b/THANKS.md
--- a/THANKS.md
+++ b/THANKS.md
@@ -160,7 +160,7 @@
 - Denis Laxalde separated the gsl tests from the base ones.
 
 - Dominic Steinitz (idontgetoutmuch) reported a bug in the static diagonal creation functions and
-  added Cholesky to Static.
+  added Cholesky to Static. He also added support for tridiagonal matrix solver and fixed several bugs.
 
 - Dylan Thurston reported an error in the glpk documentation and ambiguity in
   the description of linearSolve.
@@ -170,7 +170,8 @@
 
 - Ian Ross reported the max/minIndex bug.
 
-- Niklas Hambüchen improved the documentation.
+- Niklas Hambüchen improved the documentation and fixed compilation with GHC-8.2
+  adding type signatures. Added disable-default-paths flag.
 
 - "erdeszt" optimized "conv" using a direct vector reverse.
 
@@ -192,7 +193,8 @@
 
 - Matt Peddie wrote the interfaces to the interpolation and simulated annealing modules.
 
-- "maxc01" solved uninstallability in FreeBSD and improved urandom
+- "maxc01" solved uninstallability in FreeBSD, improved urandom, and fixed a Windows
+  link error using rand_s.
 
 - "ntfrgl" added {take,drop}Last{Rows,Columns} and odeSolveVWith with generalized step control function
    and fixed link errors related to mod/mod_l.
@@ -202,5 +204,33 @@
 - Ilan Godik and Douglas McClean helped with Windows support.
 
 - Vassil Keremidchiev fixed the cabal options for OpenBlas, fixed several installation
-  issues, and added support for stack-based build.
+  issues, and added support for stack-based build. He also added support for LTS 8.15
+  under Windows.
+
+- Greg Nwosu fixed arm compilation
+
+- Patrik Jansson changed meanCov and gaussianSample to use Herm type. Fixed stack.yaml.
+
+- Justin Le added NFData instances for Static types, added mapping and outer product
+  methods to Domain, and many other functions to the Static module.
+
+- Sidharth Kapur added Normed and numeric instances for several Static types,
+fixed the CPP issue in cabal files, and made many other contributions.
+
+- Matt Renaud improved the documentation.
+
+- Joshua Moerman fixed cabal/stack flags for windows.
+
+- Francesco Mazzoli, Niklas Hambüchen, Patrick Chilton, and Andras Slemmer
+  discovered a serious and subtle bug in the wrapper helpers causing memory corruption.
+  Andras Slemmer fixed the bug. Thank you all.
+
+- Kevin Slagle implemented thinQR and thinRQ, much faster than the original qr,
+  and added compactSVDTol. He also added an optimized reorderVector for hTensor.
+
+- "fedeinthemix" suggested a better name and a more general type for unitary.
+
+- Huw Campbell fixed a bug in equal.
+
+- Hiromi Ishii fixed compilation problems for ghc-8.4
 
diff --git a/hmatrix.cabal b/hmatrix.cabal
--- a/hmatrix.cabal
+++ b/hmatrix.cabal
@@ -1,11 +1,11 @@
 Name:               hmatrix
-Version:            0.17.0.2
+Version:            0.20.2
 License:            BSD3
 License-file:       LICENSE
 Author:             Alberto Ruiz
-Maintainer:         Alberto Ruiz
+Maintainer:         Dominic Steinitz
 Stability:          provisional
-Homepage:           https://github.com/albertoruiz/hmatrix
+Homepage:           https://github.com/haskell-numerics/hmatrix
 Synopsis:           Numeric Linear Algebra
 Description:        Linear systems, matrix decompositions, and other numerical computations based on BLAS and LAPACK.
                     .
@@ -16,9 +16,9 @@
                     Code examples: <http://dis.um.es/~alberto/hmatrix/hmatrix.html>
 
 Category:           Math
-tested-with:        GHC==8.0
+tested-with:        GHC==8.10
 
-cabal-version:      >=1.8
+cabal-version:       >=1.18
 
 build-type:         Simple
 
@@ -29,10 +29,22 @@
 flag openblas
     description:    Link with OpenBLAS (https://github.com/xianyi/OpenBLAS) optimized libraries.
     default:        False
-    manual: True
+    manual:         True
 
+flag disable-default-paths
+    description:    When enabled, don't add default hardcoded include/link dirs by default. Needed for hermetic builds like in nix.
+    default:        False
+    manual:         True
+
+flag no-random_r
+    description:    When enabled, don't depend on the random_r() C function.
+    default:        False
+    manual:         True
+
 library
 
+    default-language:   Haskell2010
+
     Build-Depends:      base >= 4.8 && < 5,
                         binary,
                         array,
@@ -40,8 +52,10 @@
                         random,
                         split,
                         bytestring,
+                        primitive,
                         storable-complex,
-                        vector >= 0.8
+                        semigroups,
+                        vector >= 0.11
 
     hs-source-dirs:     src
 
@@ -55,7 +69,6 @@
                         Internal.Devel
                         Internal.Vectorized
                         Internal.Matrix
-                        Internal.Foreign
                         Internal.ST
                         Internal.IO
                         Internal.Element
@@ -79,13 +92,12 @@
                         src/Internal/C/vector-aux.c
 
 
-    extensions:         ForeignFunctionInterface,
-                        CPP
+    other-extensions:   ForeignFunctionInterface
 
     ghc-options:        -Wall
                         -fno-warn-missing-signatures
                         -fno-warn-orphans
-                        -fprof-auto
+                        -fno-prof-auto
 
     cc-options:         -O4 -Wall
 
@@ -94,43 +106,51 @@
     if arch(i386)
         cc-options:     -msse2
 
-    cpp-options:        -DBINARY
 
+    if flag(no-random_r)
+        cc-options: -DNO_RANDOM_R
+
     if os(OSX)
         if flag(openblas)
-            extra-lib-dirs:     /opt/local/lib/openblas/lib
+            if !flag(disable-default-paths)
+                extra-lib-dirs:     /opt/local/lib/openblas/lib
             extra-libraries:    openblas
         else
             extra-libraries:    blas lapack
 
-        extra-lib-dirs: /opt/local/lib/
-        include-dirs: /opt/local/include/
-        extra-lib-dirs: /usr/local/lib/
-        include-dirs: /usr/local/include/
+        if !flag(disable-default-paths)
+            extra-lib-dirs: /opt/local/lib/
+            include-dirs: /opt/local/include/
+            extra-lib-dirs: /usr/local/lib/
+            include-dirs: /usr/local/include/
         if arch(i386)
             cc-options: -arch i386
         frameworks: Accelerate
 
     if os(freebsd)
         if flag(openblas)
-            extra-lib-dirs:     /usr/local/lib/openblas/lib
+            if !flag(disable-default-paths)
+                extra-lib-dirs:     /usr/local/lib/openblas/lib
             extra-libraries:    openblas
         else
             extra-libraries:    blas lapack
 
-       extra-lib-dirs: /usr/local/lib
-       include-dirs: /usr/local/include
-       extra-libraries: gfortran
+        if !flag(disable-default-paths)
+            extra-lib-dirs: /usr/local/lib
+            include-dirs: /usr/local/include
+        extra-libraries: gfortran
+        extra-lib-dirs: /usr/local/lib/gcc9 /usr/local/lib/gcc8 /usr/local/lib/gcc7
 
     if os(windows)
         if flag(openblas)
-            extra-libraries:    libopenblas
+            extra-libraries:    openblas
         else
             extra-libraries:    blas lapack
 
     if os(linux)
         if flag(openblas)
-            extra-lib-dirs:     /usr/lib/openblas/lib
+            if !flag(disable-default-paths)
+                extra-lib-dirs:     /usr/lib/openblas/lib
             extra-libraries:    openblas
         else
             extra-libraries:    blas lapack
@@ -141,5 +161,4 @@
 
 source-repository head
     type:     git
-    location: https://github.com/albertoruiz/hmatrix
-
+    location: https://github.com/haskell-numerics/hmatrix
diff --git a/src/Internal/Algorithms.hs b/src/Internal/Algorithms.hs
--- a/src/Internal/Algorithms.hs
+++ b/src/Internal/Algorithms.hs
@@ -1,9 +1,10 @@
 {-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE TypeFamilies #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 -----------------------------------------------------------------------------
 {- |
 Module      :  Internal.Algorithms
@@ -20,16 +21,24 @@
 -}
 -----------------------------------------------------------------------------
 
-module Internal.Algorithms where
+module Internal.Algorithms (
+  module Internal.Algorithms,
+  UpLo(..)
+) where
 
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
+
 import Internal.Vector
 import Internal.Matrix
 import Internal.Element
 import Internal.Conversion
-import Internal.LAPACK as LAPACK
+import Internal.LAPACK
 import Internal.Numeric
 import Data.List(foldl1')
 import qualified Data.Array as A
+import qualified Data.Vector.Storable as Vector
 import Internal.ST
 import Internal.Vectorized(range)
 import Control.DeepSeq
@@ -57,13 +66,17 @@
     mbLinearSolve' :: Matrix t -> Matrix t -> Maybe (Matrix t)
     linearSolve' :: Matrix t -> Matrix t -> Matrix t
     cholSolve'   :: Matrix t -> Matrix t -> Matrix t
+    triSolve'   :: UpLo -> Matrix t -> Matrix t -> Matrix t
+    triDiagSolve' :: Vector t -> Vector t -> Vector t -> Matrix t -> Matrix t
     ldlPacked'   :: Matrix t -> (Matrix t, [Int])
     ldlSolve'    :: (Matrix t, [Int]) -> Matrix t -> Matrix t
     linearSolveSVD' :: Matrix t -> Matrix t -> Matrix t
     linearSolveLS'  :: Matrix t -> Matrix t -> Matrix t
     eig'         :: Matrix t -> (Vector (Complex Double), Matrix (Complex Double))
+    geig'        :: Matrix t -> Matrix t -> (Vector (Complex Double), Vector t, Matrix (Complex Double))
     eigSH''      :: Matrix t -> (Vector Double, Matrix t)
     eigOnly      :: Matrix t -> Vector (Complex Double)
+    geigOnly     :: Matrix t -> Matrix t -> (Vector (Complex Double), Vector t)
     eigOnlySH    :: Matrix t -> Vector Double
     cholSH'      :: Matrix t -> Matrix t
     mbCholSH'    :: Matrix t -> Maybe (Matrix t)
@@ -82,11 +95,15 @@
     linearSolve' = linearSolveR                 -- (luSolve . luPacked) ??
     mbLinearSolve' = mbLinearSolveR
     cholSolve' = cholSolveR
+    triSolve' = triSolveR
+    triDiagSolve' = triDiagSolveR
     linearSolveLS' = linearSolveLSR
     linearSolveSVD' = linearSolveSVDR Nothing
     eig' = eigR
     eigSH'' = eigS
+    geig' = eigG
     eigOnly = eigOnlyR
+    geigOnly = eigOnlyG
     eigOnlySH = eigOnlyS
     cholSH' = cholS
     mbCholSH' = mbCholS
@@ -111,10 +128,14 @@
     linearSolve' = linearSolveC
     mbLinearSolve' = mbLinearSolveC
     cholSolve' = cholSolveC
+    triSolve' = triSolveC
+    triDiagSolve' = triDiagSolveC
     linearSolveLS' = linearSolveLSC
     linearSolveSVD' = linearSolveSVDC Nothing
     eig' = eigC
+    geig' = eigGC
     eigOnly = eigOnlyC
+    geigOnly = eigOnlyGC
     eigSH'' = eigH
     eigOnlySH = eigOnlyH
     cholSH' = cholH
@@ -158,7 +179,8 @@
 -0.690  -0.352   0.433  -0.233   0.398
 
 >>> s
-fromList [35.18264833189422,1.4769076999800903,1.089145439970417e-15]
+[35.18264833189422,1.4769076999800903,1.089145439970417e-15]
+it :: Vector Double
 
 >>> disp 3 v
 3x3
@@ -212,7 +234,8 @@
 -0.690  -0.352   0.433
 
 >>> s
-fromList [35.18264833189422,1.4769076999800903,1.089145439970417e-15]
+[35.18264833189422,1.4769076999800903,1.089145439970417e-15]
+it :: Vector Double
 
 >>> disp 3 v
 3x3
@@ -271,7 +294,8 @@
 -0.690  -0.352
 
 >>> s
-fromList [35.18264833189422,1.4769076999800903]
+[35.18264833189422,1.476907699980091]
+it :: Vector Double
 
 >>> disp 3 u
 5x2
@@ -291,9 +315,13 @@
 
 -}
 compactSVD :: Field t  => Matrix t -> (Matrix t, Vector Double, Matrix t)
-compactSVD m = (u', subVector 0 d s, v') where
+compactSVD = compactSVDTol 1
+
+-- | @compactSVDTol r@ is similar to 'compactSVD' (for which @r=1@), but uses tolerance @tol=r*g*eps*(max rows cols)@ to distinguish nonzero singular values, where @g@ is the greatest singular value. If @g<r*eps@, then only one singular value is returned.
+compactSVDTol :: Field t  => Double -> Matrix t -> (Matrix t, Vector Double, Matrix t)
+compactSVDTol r m = (u', subVector 0 d s, v') where
     (u,s,v) = thinSVD m
-    d = rankSVD (1*eps) m s `max` 1
+    d = rankSVD (r*eps) m s `max` 1
     u' = takeColumns d u
     v' = takeColumns d v
 
@@ -345,6 +373,79 @@
     -> Matrix t -- ^ solution
 cholSolve = {-# SCC "cholSolve" #-} cholSolve'
 
+-- | Solve a triangular linear system. If `Upper` is specified then
+-- all elements below the diagonal are ignored; if `Lower` is
+-- specified then all elements above the diagonal are ignored.
+triSolve
+  :: Field t
+  => UpLo     -- ^ `Lower` or `Upper`
+  -> Matrix t -- ^ coefficient matrix
+  -> Matrix t -- ^ right hand sides
+  -> Matrix t -- ^ solution
+triSolve = {-# SCC "triSolve" #-} triSolve'
+
+-- | Solve a tridiagonal linear system. Suppose you wish to solve \(Ax = b\) where
+--
+-- \[
+-- A =
+-- \begin{bmatrix}
+--    1.0 & 4.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0
+-- \\ 3.0 & 1.0 & 4.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0
+-- \\ 0.0 & 3.0 & 1.0 & 4.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0
+-- \\ 0.0 & 0.0 & 3.0 & 1.0 & 4.0 & 0.0 & 0.0 & 0.0 & 0.0
+-- \\ 0.0 & 0.0 & 0.0 & 3.0 & 1.0 & 4.0 & 0.0 & 0.0 & 0.0
+-- \\ 0.0 & 0.0 & 0.0 & 0.0 & 3.0 & 1.0 & 4.0 & 0.0 & 0.0
+-- \\ 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 3.0 & 1.0 & 4.0 & 0.0
+-- \\ 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 3.0 & 1.0 & 4.0
+-- \\ 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 0.0 & 3.0 & 1.0
+-- \end{bmatrix}
+-- \quad
+-- b =
+-- \begin{bmatrix}
+--    1.0 &  1.0 &  1.0
+-- \\ 1.0 & -1.0 &  2.0
+-- \\ 1.0 &  1.0 &  3.0
+-- \\ 1.0 & -1.0 &  4.0
+-- \\ 1.0 &  1.0 &  5.0
+-- \\ 1.0 & -1.0 &  6.0
+-- \\ 1.0 &  1.0 &  7.0
+-- \\ 1.0 & -1.0 &  8.0
+-- \\ 1.0 &  1.0 &  9.0
+-- \end{bmatrix}
+-- \]
+--
+-- then
+--
+-- @
+-- dL =  fromList [3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0, 3.0]
+-- d  =  fromList [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
+-- dU =  fromList [4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0, 4.0]
+--
+-- b = (9><3)
+--     [
+--       1.0,   1.0,   1.0,
+--       1.0,  -1.0,   2.0,
+--       1.0,   1.0,   3.0,
+--       1.0,  -1.0,   4.0,
+--       1.0,   1.0,   5.0,
+--       1.0,  -1.0,   6.0,
+--       1.0,   1.0,   7.0,
+--       1.0,  -1.0,   8.0,
+--       1.0,   1.0,   9.0
+--     ]
+--
+-- x = triDiagSolve dL d dU b
+-- @
+--
+triDiagSolve
+  :: Field t
+  => Vector t -- ^ lower diagonal: \(n - 1\) elements
+  -> Vector t -- ^ diagonal: \(n\) elements
+  -> Vector t -- ^ upper diagonal: \(n - 1\) elements
+  -> Matrix t -- ^ right hand sides
+  -> Matrix t -- ^ solution
+triDiagSolve = {-# SCC "triDiagSolve" #-} triDiagSolve'
+
 -- | Minimum norm solution of a general linear least squares problem Ax=B using the SVD. Admits rank-deficient systems but it is slower than 'linearSolveLS'. The effective rank of A is determined by treating as zero those singular valures which are less than 'eps' times the largest singular value.
 linearSolveSVD :: Field t => Matrix t -> Matrix t -> Matrix t
 linearSolveSVD = {-# SCC "linearSolveSVD" #-} linearSolveSVD'
@@ -420,10 +521,25 @@
 eig :: Field t => Matrix t -> (Vector (Complex Double), Matrix (Complex Double))
 eig = {-# SCC "eig" #-} eig'
 
+-- | Generalized eigenvalues (not ordered) and eigenvectors (as columns) of a pair of nonsymmetric matrices.
+-- Eigenvalues are represented as pairs of alpha, beta, where eigenvalue = alpha / beta. Alpha is always
+-- complex, but betas has the same type as the input matrix.
+--
+-- If @(alphas, betas, v) = geig a b@, then @a \<> v == b \<> v \<> diag (alphas / betas)@
+--
+-- Note that beta can be 0 and that has reasonable interpretation.
+geig :: Field t => Matrix t -> Matrix t -> (Vector (Complex Double), Vector t, Matrix (Complex Double))
+geig = {-# SCC "geig" #-} geig'
+
 -- | Eigenvalues (not ordered) of a general square matrix.
 eigenvalues :: Field t => Matrix t -> Vector (Complex Double)
 eigenvalues = {-# SCC "eigenvalues" #-} eigOnly
 
+-- | Generalized eigenvalues of a pair of matrices. Represented as pairs of alpha, beta,
+-- where eigenvalue is alpha / beta as in 'geig'.
+geigenvalues :: Field t => Matrix t -> Matrix t -> (Vector (Complex Double), Vector t)
+geigenvalues = {-# SCC "geigenvalues" #-} geigOnly
+
 -- | Similar to 'eigSH' without checking that the input matrix is hermitian or symmetric. It works with the upper triangular part.
 eigSH' :: Field t => Matrix t -> (Vector Double, Matrix t)
 eigSH' = {-# SCC "eigSH'" #-} eigSH''
@@ -446,7 +562,7 @@
 >>> let (l, v) = eigSH a
 
 >>> l
-fromList [11.344814282762075,0.17091518882717918,-0.5157294715892575]
+[11.344814282762075,0.17091518882717918,-0.5157294715892575]
 
 >>> disp 3 $ v <> diag l <> tr v
 3x3
@@ -475,9 +591,14 @@
 -- | QR factorization.
 --
 -- If @(q,r) = qr m@ then @m == q \<> r@, where q is unitary and r is upper triangular.
+-- Note: the current implementation is very slow for large matrices. 'thinQR' is much faster.
 qr :: Field t => Matrix t -> (Matrix t, Matrix t)
 qr = {-# SCC "qr" #-} unpackQR . qr'
 
+-- | A version of 'qr' which returns only the @min (rows m) (cols m)@ columns of @q@ and rows of @r@.
+thinQR :: Field t => Matrix t -> (Matrix t, Matrix t)
+thinQR = {-# SCC "thinQR" #-} thinUnpackQR . qr'
+
 -- | Compute the QR decomposition of a matrix in compact form.
 qrRaw :: Field t => Matrix t -> QR t
 qrRaw m = QR x v
@@ -494,9 +615,17 @@
 -- | RQ factorization.
 --
 -- If @(r,q) = rq m@ then @m == r \<> q@, where q is unitary and r is upper triangular.
+-- Note: the current implementation is very slow for large matrices. 'thinRQ' is much faster.
 rq :: Field t => Matrix t -> (Matrix t, Matrix t)
-rq m =  {-# SCC "rq" #-} (r,q) where
-    (q',r') = qr $ trans $ rev1 m
+rq = {-# SCC "rq" #-} rqFromQR qr
+
+-- | A version of 'rq' which returns only the @min (rows m) (cols m)@ columns of @r@ and rows of @q@.
+thinRQ :: Field t => Matrix t -> (Matrix t, Matrix t)
+thinRQ = {-# SCC "thinQR" #-} rqFromQR thinQR
+
+rqFromQR :: Field t => (Matrix t -> (Matrix t, Matrix t)) -> Matrix t -> (Matrix t, Matrix t)
+rqFromQR qr0 m = (r,q) where
+    (q',r') = qr0 $ trans $ rev1 m
     r = rev2 (trans r')
     q = rev2 (trans q')
     rev1 = flipud . fliprl
@@ -724,6 +853,12 @@
           hs = zipWith haussholder (toList tau) vs
           q = foldl1' mXm hs
 
+thinUnpackQR :: (Field t) => (Matrix t, Vector t) -> (Matrix t, Matrix t)
+thinUnpackQR (pq, tau) = (q, r)
+  where mn = uncurry min $ size pq
+        q = qrgr mn $ QR pq tau
+        r = fromRows $ zipWith (\i v -> Vector.replicate i 0 Vector.++ Vector.drop i v) [0..mn-1] (toRows pq)
+
 unpackHess :: (Field t) => (Matrix t -> (Matrix t,Vector t)) -> Matrix t -> (Matrix t, Matrix t)
 unpackHess hf m
     | rows m == 1 = ((1><1)[1],m)
@@ -1027,4 +1162,3 @@
 --   for usage in 'chol', 'eigSH', etc. Only a triangular part of the matrix will be used.
 trustSym :: Matrix t -> Herm t
 trustSym x = (Herm x)
-
diff --git a/src/Internal/C/lapack-aux.c b/src/Internal/C/lapack-aux.c
--- a/src/Internal/C/lapack-aux.c
+++ b/src/Internal/C/lapack-aux.c
@@ -45,6 +45,9 @@
                      for(q=0;q<M##r*M##c;q++) printf("%.1f ",M##p[q]); printf("\n");}
 
 #define CHECK(RES,CODE) MACRO(if(RES) return CODE;)
+#define MARK(RES,CODE) MACRO(if(RES) { ret = CODE; })
+#define CONVERGED(RES,CODE) MACRO(if(RES > 0) { ret = CODE; } else if(RES < 0) { ret = RES; })
+#define UNWIND(RES,CODE,LABEL) MACRO(if(RES) { ret = CODE; goto LABEL; })
 
 #define BAD_SIZE 2000
 #define BAD_CODE 2001
@@ -116,6 +119,7 @@
 	integer *info);
 
 int svd_l_R(ODMAT(a),ODMAT(u), DVEC(s),ODMAT(v)) {
+    integer ret = 0;
     integer m = ar;
     integer n = ac;
     integer q = MIN(m,n);
@@ -152,9 +156,12 @@
              vp,&ldvt,
              &ans, &lwork,
              &res);
+    CHECK(res,res);
+
     lwork = ceil(ans);
     double * work = (double*)malloc(lwork*sizeof(double));
     CHECK(!work,MEM);
+
     dgesvd_ (jobu,jobvt,
              &m,&n,ap,&m,
              sp,
@@ -162,9 +169,10 @@
              vp,&ldvt,
              work, &lwork,
              &res);
-    CHECK(res,res);
+
+    MARK(res, res);
     free(work);
-    OK
+    return ret;
 }
 
 // (alternative version)
@@ -175,9 +183,10 @@
 	integer *iwork, integer *info);
 
 int svd_l_Rdd(ODMAT(a),ODMAT(u), DVEC(s),ODMAT(v)) {
-    integer m = ar;
-    integer n = ac;
-    integer q = MIN(m,n);
+    integer ret = 0;
+    integer m   = ar;
+    integer n   = ac;
+    integer q   = MIN(m,n);
     REQUIRES(sn==q,BAD_SIZE);
     REQUIRES((up == NULL && vp == NULL)
              || (ur==m && vc==n
@@ -195,20 +204,27 @@
     }
     DEBUGMSG("svd_l_Rdd");
     integer* iwk = (integer*) malloc(8*q*sizeof(integer));
-    CHECK(!iwk,MEM);
+    UNWIND(!iwk,MEM,cleanup0);
     integer lwk = -1;
     integer res;
     // ask for optimal lwk
     double ans;
     dgesdd_ (jobz,&m,&n,ap,&m,sp,up,&m,vp,&ldvt,&ans,&lwk,iwk,&res);
+    UNWIND(res,res,cleanup1);
+
     lwk = ans;
     double * workv = (double*)malloc(lwk*sizeof(double));
-    CHECK(!workv,MEM);
+    UNWIND(!workv,MEM,cleanup1);
+
     dgesdd_ (jobz,&m,&n,ap,&m,sp,up,&m,vp,&ldvt,workv,&lwk,iwk,&res);
-    CHECK(res,res);
-    free(iwk);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
     free(workv);
-    OK
+cleanup1:
+    free(iwk);
+cleanup0:
+    return ret;
 }
 
 //////////////////// complex svd ////////////////////////////////////
@@ -219,11 +235,14 @@
     integer *lwork, doublereal *rwork, integer *info);
 
 int svd_l_C(OCMAT(a),OCMAT(u), DVEC(s),OCMAT(v)) {
-    integer m = ar;
-    integer n = ac;
-    integer q = MIN(m,n);
+    integer ret = 0;
+    integer m   = ar;
+    integer n   = ac;
+    integer q   = MIN(m,n);
     REQUIRES(sn==q,BAD_SIZE);
     REQUIRES(up==NULL || (ur==m && (uc==m || uc==q)),BAD_SIZE);
+    REQUIRES(vp==NULL || (vc==n && (vr==n || vr==q)),BAD_SIZE);
+
     char* jobu  = "A";
     if (up==NULL) {
         jobu = "N";
@@ -232,7 +251,6 @@
             jobu = "S";
         }
     }
-    REQUIRES(vp==NULL || (vc==n && (vr==n || vr==q)),BAD_SIZE);
     char* jobvt  = "A";
     integer ldvt = n;
     if (vp==NULL) {
@@ -245,7 +263,8 @@
     }DEBUGMSG("svd_l_C");
 
     double *rwork = (double*) malloc(5*q*sizeof(double));
-    CHECK(!rwork,MEM);
+    UNWIND(!rwork,MEM,cleanup0);
+
     integer lwork = -1;
     integer res;
     // ask for optimal lwork
@@ -258,9 +277,12 @@
              &ans, &lwork,
              rwork,
              &res);
+    UNWIND(res,res,cleanup1);
+
     lwork = ceil(ans.r);
     doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
-    CHECK(!work,MEM);
+    UNWIND(!work,MEM,cleanup1);
+
     zgesvd_ (jobu,jobvt,
              &m,&n,ap,&m,
              sp,
@@ -269,10 +291,14 @@
              work, &lwork,
              rwork,
              &res);
-    CHECK(res,res);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
     free(work);
+cleanup1:
     free(rwork);
-    OK
+cleanup0:
+    return ret;
 }
 
 int zgesdd_ (char *jobz, integer *m, integer *n,
@@ -281,49 +307,68 @@
     integer *lwork, doublereal *rwork, integer* iwork, integer *info);
 
 int svd_l_Cdd(OCMAT(a),OCMAT(u), DVEC(s),OCMAT(v)) {
-    integer m = ar;
-    integer n = ac;
-    integer q = MIN(m,n);
-    REQUIRES(sn==q,BAD_SIZE);
+    integer ret = 0;
+    integer m   = ar;
+    integer n   = ac;
+    integer mx  = MAX(m,n);
+    integer mn  = MIN(m,n);
+    REQUIRES(sn==mn,BAD_SIZE);
     REQUIRES((up == NULL && vp == NULL)
              || (ur==m && vc==n
-                &&   ((uc == q && vr == q)
+                &&   ((uc == mn && vr == mn)
                    || (uc == m && vc==n))),BAD_SIZE);
     char* jobz  = "A";
     integer ldvt = n;
     if (up==NULL) {
         jobz = "N";
     } else {
-        if (uc==q && vr == q) {
+        if (uc==mn && vr == mn) {
             jobz = "S";
-            ldvt = q;
+            ldvt = mn;
         }
     }
     DEBUGMSG("svd_l_Cdd");
-    integer* iwk = (integer*) malloc(8*q*sizeof(integer));
-    CHECK(!iwk,MEM);
+    integer* iwk = (integer*) malloc(8*mn*sizeof(integer));
+    UNWIND(!iwk,MEM,cleanup0);
+
+    // Docs: http://www.netlib.org/lapack/explore-html/d8/d54/zgesdd_8f_source.html
+    // RWORK is DOUBLE PRECISION array, dimension (MAX(1,LRWORK))
+    // Let mx = max(M,N) and mn = min(M,N).
+    // If JOBZ = 'N',    LRWORK >= 5*mn (LAPACK <= 3.6 needs 7*mn);
+    // else if mx >> mn, LRWORK >= 5*mn*mn + 5*mn;
+    // else              LRWORK >= max( 5*mn*mn + 5*mn,
+    //                                  2*mx*mn + 2*mn*mn + mn ).
     int lrwk;
-    if (0 && *jobz == 'N') {
-        lrwk = 5*q; // does not work, crash at free below
+    if (*jobz == 'N') {
+        lrwk = 7*mn;
     } else {
-        lrwk = 5*q*q + 7*q;
+        lrwk = MAX(5*mn*mn + 7*mn, 2*mx*mn + 2*mn*mn + mn);
     }
-    double *rwk = (double*)malloc(lrwk*sizeof(double));;
-    CHECK(!rwk,MEM);
+    double *rwk = (double*)malloc(MAX(1, lrwk)*sizeof(double));;
+    UNWIND(!rwk,MEM,cleanup1);
+
     integer lwk = -1;
     integer res;
     // ask for optimal lwk
     doublecomplex ans;
     zgesdd_ (jobz,&m,&n,ap,&m,sp,up,&m,vp,&ldvt,&ans,&lwk,rwk,iwk,&res);
+    UNWIND(res,res,cleanup2);
+
     lwk = ans.r;
     doublecomplex * workv = (doublecomplex*)malloc(lwk*sizeof(doublecomplex));
-    CHECK(!workv,MEM);
+    UNWIND(!workv,MEM,cleanup2);
+
     zgesdd_ (jobz,&m,&n,ap,&m,sp,up,&m,vp,&ldvt,workv,&lwk,rwk,iwk,&res);
-    CHECK(res,res);
+    UNWIND(res,res,cleanup3);
+
+cleanup3:
     free(workv);
+cleanup2:
     free(rwk);
+cleanup1:
     free(iwk);
-    OK
+cleanup0:
+    return ret;
 }
 
 //////////////////// general complex eigensystem ////////////
@@ -334,15 +379,18 @@
 	integer *lwork, doublereal *rwork, integer *info);
 
 int eig_l_C(OCMAT(a), OCMAT(u), CVEC(s),OCMAT(v)) {
-    integer n = ar;
+    integer ret = 0;
+    integer n   = ar;
     REQUIRES(ac==n && sn==n, BAD_SIZE);
     REQUIRES(up==NULL || (ur==n && uc==n), BAD_SIZE);
     char jobvl = up==NULL?'N':'V';
     REQUIRES(vp==NULL || (vr==n && vc==n), BAD_SIZE);
     char jobvr = vp==NULL?'N':'V';
     DEBUGMSG("eig_l_C");
+
     double *rwork = (double*) malloc(2*n*sizeof(double));
-    CHECK(!rwork,MEM);
+    UNWIND(!rwork,MEM,cleanup0);
+
     integer lwork = -1;
     integer res;
     // ask for optimal lwork
@@ -355,9 +403,13 @@
              &ans, &lwork,
              rwork,
              &res);
+
+    UNWIND(res,res,cleanup1);
+
     lwork = ceil(ans.r);
     doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
-    CHECK(!work,MEM);
+    UNWIND(!work,MEM,cleanup1);
+
     zgeev_  (&jobvl,&jobvr,
              &n,ap,&n,
              sp,
@@ -366,10 +418,15 @@
              work, &lwork,
              rwork,
              &res);
-    CHECK(res,res);
+
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
     free(work);
+cleanup1:
     free(rwork);
-    OK
+cleanup0:
+    return ret;
 }
 
 
@@ -382,7 +439,8 @@
 	integer *lwork, integer *info);
 
 int eig_l_R(ODMAT(a),ODMAT(u), CVEC(s),ODMAT(v)) {
-    integer n = ar;
+    integer ret = 0;
+    integer n   = ar;
     REQUIRES(ac==n && sn==n, BAD_SIZE);
     REQUIRES(up==NULL || (ur==n && uc==n), BAD_SIZE);
     char jobvl = up==NULL?'N':'V';
@@ -400,6 +458,8 @@
              vp,&n,
              &ans, &lwork,
              &res);
+    CHECK(res,res);
+
     lwork = ceil(ans);
     double * work = (double*)malloc(lwork*sizeof(double));
     CHECK(!work,MEM);
@@ -410,12 +470,115 @@
              vp,&n,
              work, &lwork,
              &res);
+    MARK(res,res);
+
+    free(work);
+    return ret;
+}
+
+//////////////////// generalized real eigensystem ////////////
+
+int dggev_(char *jobvl, char *jobvr, integer *n,
+    doublereal *a, integer *lda, doublereal *b, integer *ldb,
+    doublereal *alphar, doublereal *alphai, doublereal *beta,
+    doublereal *vl, integer *ldvl, doublereal *vr, integer *ldvr,
+    doublereal *work,
+	integer *lwork, integer *info);
+
+int eig_l_G(ODMAT(a), ODMAT(b), CVEC(alpha), DVEC(beta), ODMAT(vl), ODMAT(vr)) {
+    integer ret = 0;
+    integer n   = ar;
+    REQUIRES(ac == n && br == n && bc == n && alphan == n && betan == n, BAD_SIZE);
+    REQUIRES(vlp==NULL || (vlr==n && vlc==n), BAD_SIZE);
+    char jobvl = vlp==NULL?'N':'V';
+    REQUIRES(vrp==NULL || (vrr==n && vrc==n), BAD_SIZE);
+    char jobvr = vrp==NULL?'N':'V';
+    DEBUGMSG("eig_l_G");
+    integer lwork = -1;
+    integer res;
+    // ask for optimal lwork
+    double ans;
+    dggev_  (&jobvl,&jobvr,
+             &n,
+             ap,&n,bp,&n,
+             (double*)alphap, (double*)alphap+n, betap,
+             vlp, &n, vrp, &n,
+             &ans, &lwork,
+             &res);
     CHECK(res,res);
+
+    lwork = ceil(ans);
+    double * work = (double*)malloc(lwork*sizeof(double));
+    CHECK(!work,MEM);
+
+    dggev_  (&jobvl,&jobvr,
+             &n,
+             ap,&n,bp,&n,
+             (double*)alphap, (double*)alphap+n, betap,
+             vlp, &n, vrp, &n,
+             work, &lwork,
+             &res);
+    MARK(res,res);
+
     free(work);
-    OK
+    return ret;
 }
 
+//////////////////// generalized complex eigensystem ////////////
 
+int zggev_(char *jobvl, char *jobvr, integer *n,
+    doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb,
+    doublecomplex *alphar, doublecomplex *beta,
+    doublecomplex *vl, integer *ldvl, doublecomplex *vr, integer *ldvr,
+    doublecomplex *work, integer *lwork,
+    doublereal *rwork, integer *info);
+
+int eig_l_GC(OCMAT(a), OCMAT(b), CVEC(alpha), CVEC(beta), OCMAT(vl), OCMAT(vr)) {
+    integer ret = 0;
+    integer n   = ar;
+    REQUIRES(ac == n && br == n && bc == n && alphan == n && betan == n, BAD_SIZE);
+    REQUIRES(vlp==NULL || (vlr==n && vlc==n), BAD_SIZE);
+    char jobvl = vlp==NULL?'N':'V';
+    REQUIRES(vrp==NULL || (vrr==n && vrc==n), BAD_SIZE);
+    char jobvr = vrp==NULL?'N':'V';
+    DEBUGMSG("eig_l_GC");
+    double *rwork = (double*) malloc(8*n*sizeof(double));
+    UNWIND(!rwork,MEM,cleanup0);
+
+    integer lwork = -1;
+    integer res;
+    // ask for optimal lwork
+    doublecomplex ans;
+    zggev_  (&jobvl,&jobvr,
+             &n,
+             ap,&n,bp,&n,
+             alphap, betap,
+             vlp, &n, vrp, &n,
+             &ans, &lwork,
+             rwork, &res);
+    UNWIND(res,res,cleanup1);
+
+    lwork = ceil(ans.r);
+    doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
+    UNWIND(!work,MEM,cleanup1);
+
+    zggev_  (&jobvl,&jobvr,
+             &n,
+             ap,&n,bp,&n,
+             alphap, betap,
+             vlp, &n, vrp, &n,
+             work, &lwork,
+             rwork, &res);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
+    free(work);
+cleanup1:
+    free(rwork);
+cleanup0:
+    return ret;
+}
+
 //////////////////// symmetric real eigensystem ////////////
 
 int dsyev_(char *jobz, char *uplo, integer *n, doublereal *a,
@@ -423,7 +586,8 @@
 	integer *info);
 
 int eig_l_S(int wantV,DVEC(s),ODMAT(v)) {
-    integer n = sn;
+    integer ret = 0;
+    integer n   = sn;
     REQUIRES(vr==n && vc==n, BAD_SIZE);
     char jobz = wantV?'V':'N';
     DEBUGMSG("eig_l_S");
@@ -437,17 +601,21 @@
              sp,
              &ans, &lwork,
              &res);
+    CHECK(res,res);
+
     lwork = ceil(ans);
     double * work = (double*)malloc(lwork*sizeof(double));
     CHECK(!work,MEM);
+
     dsyev_  (&jobz,&uplo,
              &n,vp,&n,
              sp,
              work, &lwork,
              &res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(work);
-    OK
+    return ret;
 }
 
 //////////////////// hermitian complex eigensystem ////////////
@@ -457,12 +625,15 @@
 	doublereal *rwork, integer *info);
 
 int eig_l_H(int wantV,DVEC(s),OCMAT(v)) {
-    integer n = sn;
+    integer ret = 0;
+    integer n   = sn;
+
     REQUIRES(vr==n && vc==n, BAD_SIZE);
     char jobz = wantV?'V':'N';
     DEBUGMSG("eig_l_H");
     double *rwork = (double*) malloc((3*n-2)*sizeof(double));
-    CHECK(!rwork,MEM);
+    UNWIND(!rwork,MEM,cleanup0);
+
     integer lwork = -1;
     char uplo = 'U';
     integer res;
@@ -474,19 +645,26 @@
              &ans, &lwork,
              rwork,
              &res);
+    UNWIND(res,res,cleanup1);
+
     lwork = ceil(ans.r);
     doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
-    CHECK(!work,MEM);
+    UNWIND(!work,MEM,cleanup1);
+
     zheev_  (&jobz,&uplo,
              &n,vp,&n,
              sp,
              work, &lwork,
              rwork,
              &res);
-    CHECK(res,res);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
     free(work);
+cleanup1:
     free(rwork);
-    OK
+cleanup0:
+    return ret;
 }
 
 //////////////////// general real linear system ////////////
@@ -495,23 +673,25 @@
 	*lda, integer *ipiv, doublereal *b, integer *ldb, integer *info);
 
 int linearSolveR_l(ODMAT(a),ODMAT(b)) {
-    integer n = ar;
+    integer ret  = 0;
+    integer n    = ar;
     integer nhrs = bc;
+
     REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
     DEBUGMSG("linearSolveR_l");
     integer * ipiv = (integer*)malloc(n*sizeof(integer));
+    CHECK(!ipiv,MEM);
+
     integer res;
     dgesv_  (&n,&nhrs,
              ap, &n,
              ipiv,
              bp, &n,
              &res);
-    if(res>0) {
-        return SINGULAR;
-    }
-    CHECK(res,res);
+    CONVERGED(res,SINGULAR);
+
     free(ipiv);
-    OK
+    return ret;
 }
 
 //////////////////// general complex linear system ////////////
@@ -521,23 +701,25 @@
 	info);
 
 int linearSolveC_l(OCMAT(a),OCMAT(b)) {
-    integer n = ar;
+    integer ret  = 0;
+    integer n    = ar;
     integer nhrs = bc;
+
     REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
     DEBUGMSG("linearSolveC_l");
     integer * ipiv = (integer*)malloc(n*sizeof(integer));
+    CHECK(!ipiv,MEM);
+
     integer res;
     zgesv_  (&n,&nhrs,
              ap, &n,
              ipiv,
              bp, &n,
              &res);
-    if(res>0) {
-        return SINGULAR;
-    }
-    CHECK(res,res);
+    CONVERGED(res,SINGULAR);
+
     free(ipiv);
-    OK
+    return ret;
 }
 
 //////// symmetric positive definite real linear system using Cholesky ////////////
@@ -584,6 +766,182 @@
     OK
 }
 
+//////// triangular real linear system ////////////
+
+int dtrtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs,
+	doublereal *a, integer *lda, doublereal *b, integer *ldb, integer *
+	info);
+
+int triSolveR_l_u(KODMAT(a),ODMAT(b)) {
+    integer n = ar;
+    integer lda = aXc;
+    integer nhrs = bc;
+    REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
+    DEBUGMSG("triSolveR_l_u");
+    integer res;
+    dtrtrs_ ("U",
+             "N",
+             "N",
+             &n,&nhrs,
+             (double*)ap, &lda,
+             bp, &n,
+             &res);
+    CHECK(res,res);
+    OK
+}
+
+int triSolveR_l_l(KODMAT(a),ODMAT(b)) {
+    integer n = ar;
+    integer lda = aXc;
+    integer nhrs = bc;
+    REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
+    DEBUGMSG("triSolveR_l_l");
+    integer res;
+    dtrtrs_ ("L",
+             "N",
+             "N",
+             &n,&nhrs,
+             (double*)ap, &lda,
+             bp, &n,
+             &res);
+    CHECK(res,res);
+    OK
+}
+
+//////// triangular complex linear system ////////////
+
+int ztrtrs_(char *uplo, char *trans, char *diag, integer *n, integer *nrhs,
+	doublecomplex *a, integer *lda, doublecomplex *b, integer *ldb,
+	integer *info);
+
+int triSolveC_l_u(KOCMAT(a),OCMAT(b)) {
+    integer n = ar;
+    integer lda = aXc;
+    integer nhrs = bc;
+    REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
+    DEBUGMSG("triSolveC_l_u");
+    integer res;
+    ztrtrs_ ("U",
+             "N",
+             "N",
+             &n,&nhrs,
+             (doublecomplex*)ap, &lda,
+             bp, &n,
+             &res);
+    CHECK(res,res);
+    OK
+}
+
+int triSolveC_l_l(KOCMAT(a),OCMAT(b)) {
+    integer n = ar;
+    integer lda = aXc;
+    integer nhrs = bc;
+    REQUIRES(n>=1 && ar==ac && ar==br,BAD_SIZE);
+    DEBUGMSG("triSolveC_l_u");
+    integer res;
+    ztrtrs_ ("L",
+             "N",
+             "N",
+             &n,&nhrs,
+             (doublecomplex*)ap, &lda,
+             bp, &n,
+             &res);
+    CHECK(res,res);
+    OK
+}
+
+//////// tridiagonal real linear system ////////////
+
+int dgttrf_(integer *n,
+            doublereal *dl, doublereal *d, doublereal *du, doublereal *du2,
+            integer *ipiv,
+            integer *info);
+
+int dgttrs_(char *trans, integer *n, integer *nrhs,
+            doublereal *dl, doublereal *d, doublereal *du, doublereal *du2,
+            integer *ipiv, doublereal *b, integer *ldb,
+            integer *info);
+
+int triDiagSolveR_l(DVEC(dl), DVEC(d), DVEC(du), ODMAT(b)) {
+    integer ret  = 0;
+    integer n    = dn;
+    integer nhrs = bc;
+    REQUIRES(n >= 1 && dln == dn - 1 && dun == dn - 1 && br == n, BAD_SIZE);
+    DEBUGMSG("triDiagSolveR_l");
+    integer res;
+    integer* ipiv = (integer*)malloc(n*sizeof(integer));
+    UNWIND(!ipiv,MEM,cleanup0);
+
+    double* du2 = (double*)malloc((n - 2)*sizeof(double));
+    UNWIND(!du2,MEM,cleanup1);
+
+    dgttrf_ (&n,
+             dlp, dp, dup, du2,
+             ipiv,
+             &res);
+    UNWIND(res,res,cleanup2);
+
+    dgttrs_ ("N",
+             &n,&nhrs,
+             dlp, dp, dup, du2,
+             ipiv, bp, &n,
+             &res);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
+    free(du2);
+cleanup1:
+    free(ipiv);
+cleanup0:
+    return ret;
+}
+
+//////// tridiagonal complex linear system ////////////
+
+int zgttrf_(integer *n,
+            doublecomplex *dl, doublecomplex *d, doublecomplex *du, doublecomplex *du2,
+            integer *ipiv,
+            integer *info);
+
+int zgttrs_(char *trans, integer *n, integer *nrhs,
+            doublecomplex *dl, doublecomplex *d, doublecomplex *du, doublecomplex *du2,
+            integer *ipiv, doublecomplex *b, integer *ldb,
+            integer *info);
+
+int triDiagSolveC_l(CVEC(dl), CVEC(d), CVEC(du), OCMAT(b)) {
+    integer ret  = 0;
+    integer n    = dn;
+    integer nhrs = bc;
+    REQUIRES(n >= 1 && dln == dn - 1 && dun == dn - 1 && br == n, BAD_SIZE);
+    DEBUGMSG("triDiagSolveC_l");
+    integer res;
+    integer* ipiv = (integer*)malloc(n*sizeof(integer));
+    UNWIND(!ipiv,MEM,cleanup0);
+
+    doublecomplex* du2 = (doublecomplex*)malloc((n - 2)*sizeof(doublecomplex));
+    UNWIND(!du2,MEM,cleanup1);
+
+    zgttrf_ (&n,
+             dlp, dp, dup, du2,
+             ipiv,
+             &res);
+    UNWIND(res,res,cleanup2);
+
+    zgttrs_ ("N",
+             &n,&nhrs,
+             dlp, dp, dup, du2,
+             ipiv, bp, &n,
+             &res);
+    UNWIND(res,res,cleanup2);
+
+cleanup2:
+    free(du2);
+cleanup1:
+    free(ipiv);
+cleanup0:
+    return ret;
+}
+
 //////////////////// least squares real linear system ////////////
 
 int dgels_(char *trans, integer *m, integer *n, integer *
@@ -591,10 +949,11 @@
 	doublereal *work, integer *lwork, integer *info);
 
 int linearSolveLSR_l(ODMAT(a),ODMAT(b)) {
-    integer m = ar;
-    integer n = ac;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
     integer nrhs = bc;
-    integer ldb = bXc;
+    integer ldb  = bXc;
     REQUIRES(m>=1 && n>=1 && br==MAX(m,n), BAD_SIZE);
     DEBUGMSG("linearSolveLSR_l");
     integer res;
@@ -605,19 +964,21 @@
              bp,&ldb,
              &ans,&lwork,
              &res);
+    CHECK(res,res);
+
     lwork = ceil(ans);
     double * work = (double*)malloc(lwork*sizeof(double));
+    CHECK(!work,MEM);
+
     dgels_  ("N",&m,&n,&nrhs,
              ap,&m,
              bp,&ldb,
              work,&lwork,
              &res);
-    if(res>0) {
-        return SINGULAR;
-    }
-    CHECK(res,res);
+    CONVERGED(res,SINGULAR);
+
     free(work);
-    OK
+    return ret;
 }
 
 //////////////////// least squares complex linear system ////////////
@@ -627,10 +988,11 @@
 	doublecomplex *work, integer *lwork, integer *info);
 
 int linearSolveLSC_l(OCMAT(a),OCMAT(b)) {
-    integer m = ar;
-    integer n = ac;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
     integer nrhs = bc;
-    integer ldb = bXc;
+    integer ldb  = bXc;
     REQUIRES(m>=1 && n>=1 && br==MAX(m,n), BAD_SIZE);
     DEBUGMSG("linearSolveLSC_l");
     integer res;
@@ -641,19 +1003,21 @@
              bp,&ldb,
              &ans,&lwork,
              &res);
+    CHECK(res,res);
+
     lwork = ceil(ans.r);
     doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
+    CHECK(!work,MEM);
+
     zgels_  ("N",&m,&n,&nrhs,
              ap,&m,
              bp,&ldb,
              work,&lwork,
              &res);
-    if(res>0) {
-        return SINGULAR;
-    }
-    CHECK(res,res);
+    CONVERGED(res,SINGULAR);
+
     free(work);
-    OK
+    return ret;
 }
 
 //////////////////// least squares real linear system using SVD ////////////
@@ -664,13 +1028,17 @@
 	integer *info);
 
 int linearSolveSVDR_l(double rcond,ODMAT(a),ODMAT(b)) {
-    integer m = ar;
-    integer n = ac;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
     integer nrhs = bc;
-    integer ldb = bXc;
+    integer ldb  = bXc;
     REQUIRES(m>=1 && n>=1 && br==MAX(m,n), BAD_SIZE);
     DEBUGMSG("linearSolveSVDR_l");
-    double*S = (double*)malloc(MIN(m,n)*sizeof(double));
+
+    double * S   = (double*)malloc(MIN(m,n)*sizeof(double));
+    UNWIND(!S,MEM,cleanup0);
+
     integer res;
     integer lwork = -1;
     integer rank;
@@ -682,8 +1050,12 @@
              &rcond,&rank,
              &ans,&lwork,
              &res);
+    UNWIND(res,res,cleanup1);
+
     lwork = ceil(ans);
     double * work = (double*)malloc(lwork*sizeof(double));
+    UNWIND(!work,MEM,cleanup1);
+
     dgelss_  (&m,&n,&nrhs,
              ap,&m,
              bp,&ldb,
@@ -691,13 +1063,15 @@
              &rcond,&rank,
              work,&lwork,
              &res);
-    if(res>0) {
-        return NOCONVER;
-    }
-    CHECK(res,res);
+
+    CONVERGED(res,NOCONVER);
+
     free(work);
+cleanup1:
     free(S);
-    OK
+cleanup0:
+    return ret;
+
 }
 
 //////////////////// least squares complex linear system using SVD ////////////
@@ -709,14 +1083,20 @@
     integer *info);
 
 int linearSolveSVDC_l(double rcond, OCMAT(a),OCMAT(b)) {
-    integer m = ar;
-    integer n = ac;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
     integer nrhs = bc;
-    integer ldb = bXc;
+    integer ldb  = bXc;
     REQUIRES(m>=1 && n>=1 && br==MAX(m,n), BAD_SIZE);
     DEBUGMSG("linearSolveSVDC_l");
+
     double*S = (double*)malloc(MIN(m,n)*sizeof(double));
+    UNWIND(!S,MEM,cleanup0);
+
     double*RWORK = (double*)malloc(5*MIN(m,n)*sizeof(double));
+    UNWIND(!S,MEM,cleanup1);
+
     integer res;
     integer lwork = -1;
     integer rank;
@@ -729,8 +1109,12 @@
              &ans,&lwork,
              RWORK,
              &res);
+    UNWIND(res,res,cleanup2);
+
     lwork = ceil(ans.r);
     doublecomplex * work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
+    UNWIND(!work,MEM,cleanup2);
+
     zgelss_  (&m,&n,&nrhs,
              ap,&m,
              bp,&ldb,
@@ -739,14 +1123,16 @@
              work,&lwork,
              RWORK,
              &res);
-    if(res>0) {
-        return NOCONVER;
-    }
-    CHECK(res,res);
+    CONVERGED(res,NOCONVER);
+
     free(work);
+cleanup2:
     free(RWORK);
+cleanup1:
     free(S);
-    OK
+cleanup0:
+    return ret;
+
 }
 
 //////////////////// Cholesky factorization /////////////////////////
@@ -799,36 +1185,43 @@
 	lda, doublereal *tau, doublereal *work, integer *info);
 
 int qr_l_R(DVEC(tau), ODMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
     REQUIRES(m>=1 && n >=1 && taun == mn, BAD_SIZE);
     DEBUGMSG("qr_l_R");
     double *WORK = (double*)malloc(n*sizeof(double));
     CHECK(!WORK,MEM);
+
     integer res;
     dgeqr2_ (&m,&n,rp,&m,taup,WORK,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 int zgeqr2_(integer *m, integer *n, doublecomplex *a,
 	integer *lda, doublecomplex *tau, doublecomplex *work, integer *info);
 
 int qr_l_C(CVEC(tau), OCMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
     REQUIRES(m>=1 && n >=1 && taun == mn, BAD_SIZE);
     DEBUGMSG("qr_l_C");
+
     doublecomplex *WORK = (doublecomplex*)malloc(n*sizeof(doublecomplex));
     CHECK(!WORK,MEM);
+
     integer res;
     zgeqr2_ (&m,&n,rp,&m,taup,WORK,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 int dorgqr_(integer *m, integer *n, integer *k, doublereal *
@@ -836,18 +1229,21 @@
 	integer *info);
 
 int c_dorgqr(KDVEC(tau), ODMAT(r)) {
-    integer m = rr;
-    integer n = MIN(rc,rr);
-    integer k = taun;
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = MIN(rc,rr);
+    integer k   = taun;
     DEBUGMSG("c_dorgqr");
     integer lwork = 8*n; // FIXME
     double *WORK = (double*)malloc(lwork*sizeof(double));
     CHECK(!WORK,MEM);
+
     integer res;
     dorgqr_ (&m,&n,&k,rp,&m,(double*)taup,WORK,&lwork,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 int zungqr_(integer *m, integer *n, integer *k,
@@ -855,18 +1251,21 @@
 	work, integer *lwork, integer *info);
 
 int c_zungqr(KCVEC(tau), OCMAT(r)) {
-    integer m = rr;
-    integer n = MIN(rc,rr);
-    integer k = taun;
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = MIN(rc,rr);
+    integer k   = taun;
     DEBUGMSG("z_ungqr");
     integer lwork = 8*n; // FIXME
     doublecomplex *WORK = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
     CHECK(!WORK,MEM);
+
     integer res;
     zungqr_ (&m,&n,&k,rp,&m,(doublecomplex*)taup,WORK,&lwork,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 
@@ -877,20 +1276,23 @@
 	integer *lwork, integer *info);
 
 int hess_l_R(DVEC(tau), ODMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
     REQUIRES(m>=1 && n == m && taun == mn-1, BAD_SIZE);
     DEBUGMSG("hess_l_R");
     integer lwork = 5*n; // FIXME
     double *WORK = (double*)malloc(lwork*sizeof(double));
     CHECK(!WORK,MEM);
+
     integer res;
     integer one = 1;
     dgehrd_ (&n,&one,&n,rp,&n,taup,WORK,&lwork,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 
@@ -899,20 +1301,23 @@
 	work, integer *lwork, integer *info);
 
 int hess_l_C(CVEC(tau), OCMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
     REQUIRES(m>=1 && n == m && taun == mn-1, BAD_SIZE);
     DEBUGMSG("hess_l_C");
     integer lwork = 5*n; // FIXME
     doublecomplex *WORK = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
     CHECK(!WORK,MEM);
+
     integer res;
     integer one = 1;
     zgehrd_ (&n,&one,&n,rp,&n,taup,WORK,&lwork,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(WORK);
-    OK
+    return ret;
 }
 
 //////////////////// Schur factorization /////////////////////////
@@ -923,28 +1328,35 @@
 	integer *lwork, logical *bwork, integer *info);
 
 int schur_l_R(ODMAT(u), ODMAT(s)) {
-    integer m = sr;
-    integer n = sc;
+    integer ret = 0;
+    integer m   = sr;
+    integer n   = sc;
     REQUIRES(m>=1 && n==m && ur==n && uc==n, BAD_SIZE);
     DEBUGMSG("schur_l_R");
     integer lwork = 6*n; // FIXME
     double *WORK = (double*)malloc(lwork*sizeof(double));
-    double *WR = (double*)malloc(n*sizeof(double));
-    double *WI = (double*)malloc(n*sizeof(double));
+    UNWIND(!WORK,MEM,cleanup0);
+    double *WR   = (double*)malloc(n*sizeof(double));
+    UNWIND(!WORK,MEM,cleanup1);
+    double *WI   = (double*)malloc(n*sizeof(double));
+    UNWIND(!WORK,MEM,cleanup2);
     // WR and WI not really required in this call
     logical *BWORK = (logical*)malloc(n*sizeof(logical));
+    UNWIND(!BWORK,MEM,cleanup3);
     integer res;
     integer sdim;
     dgees_ ("V","N",NULL,&n,sp,&n,&sdim,WR,WI,up,&n,WORK,&lwork,BWORK,&res);
-    if(res>0) {
-        return NOCONVER;
-    }
-    CHECK(res,res);
-    free(WR);
-    free(WI);
+    CONVERGED(res,NOCONVER);
+
     free(BWORK);
+cleanup3:
+    free(WI);
+cleanup2:
+    free(WR);
+cleanup1:
     free(WORK);
-    OK
+cleanup0:
+    return ret;
 }
 
 
@@ -954,29 +1366,40 @@
 	doublereal *rwork, logical *bwork, integer *info);
 
 int schur_l_C(OCMAT(u), OCMAT(s)) {
-    integer m = sr;
-    integer n = sc;
+    integer ret = 0;
+    integer m   = sr;
+    integer n   = sc;
     REQUIRES(m>=1 && n==m && ur==n && uc==n, BAD_SIZE);
     DEBUGMSG("schur_l_C");
     integer lwork = 6*n; // FIXME
     doublecomplex *WORK = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
-    doublecomplex *W = (doublecomplex*)malloc(n*sizeof(doublecomplex));
+    UNWIND(!WORK,MEM,cleanup0);
+
+    doublecomplex *W    = (doublecomplex*)malloc(n*sizeof(doublecomplex));
+    UNWIND(!W,MEM,cleanup1);
+
     // W not really required in this call
     logical *BWORK = (logical*)malloc(n*sizeof(logical));
-    double *RWORK = (double*)malloc(n*sizeof(double));
+    UNWIND(!BWORK,MEM,cleanup2);
+
+    double  *RWORK = (double*)malloc(n*sizeof(double));
+    UNWIND(!RWORK,MEM,cleanup3);
     integer res;
     integer sdim;
     zgees_ ("V","N",NULL,&n,sp,&n,&sdim,W,
                             up,&n,
                             WORK,&lwork,RWORK,BWORK,&res);
-    if(res>0) {
-        return NOCONVER;
-    }
-    CHECK(res,res);
-    free(W);
+    CONVERGED(res,NOCONVER);
+
+    free(RWORK);
+cleanup3:
     free(BWORK);
+cleanup2:
+    free(W);
+cleanup1:
     free(WORK);
-    OK
+cleanup0:
+    return ret;
 }
 
 //////////////////// LU factorization /////////////////////////
@@ -985,24 +1408,30 @@
 	lda, integer *ipiv, integer *info);
 
 int lu_l_R(DVEC(ipiv), ODMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
     REQUIRES(m>=1 && n >=1 && ipivn == mn, BAD_SIZE);
     DEBUGMSG("lu_l_R");
     integer* auxipiv = (integer*)malloc(mn*sizeof(integer));
+    UNWIND(!auxipiv,MEM,cleanup0);
+
     integer res;
     dgetrf_ (&m,&n,rp,&m,auxipiv,&res);
     if(res>0) {
         res = 0; // FIXME
     }
-    CHECK(res,res);
-    int k;
-    for (k=0; k<mn; k++) {
+    UNWIND(res,res,cleanup1);
+
+    for (int k=0; k<mn; k++) {
         ipivp[k] = auxipiv[k];
     }
+
+cleanup1:
     free(auxipiv);
-    OK
+cleanup0:
+    return ret;
 }
 
 
@@ -1010,24 +1439,31 @@
 	integer *lda, integer *ipiv, integer *info);
 
 int lu_l_C(DVEC(ipiv), OCMAT(r)) {
-    integer m = rr;
-    integer n = rc;
-    integer mn = MIN(m,n);
+    integer ret = 0;
+    integer m   = rr;
+    integer n   = rc;
+    integer mn  = MIN(m,n);
+
     REQUIRES(m>=1 && n >=1 && ipivn == mn, BAD_SIZE);
     DEBUGMSG("lu_l_C");
     integer* auxipiv = (integer*)malloc(mn*sizeof(integer));
+    UNWIND(!auxipiv,MEM,cleanup0);
+
     integer res;
     zgetrf_ (&m,&n,rp,&m,auxipiv,&res);
     if(res>0) {
         res = 0; // FIXME
     }
-    CHECK(res,res);
-    int k;
-    for (k=0; k<mn; k++) {
+    UNWIND(res,res,cleanup1);
+
+    for (int k=0; k<mn; k++) {
         ipivp[k] = auxipiv[k];
     }
+
+cleanup1:
     free(auxipiv);
-    OK
+cleanup0:
+    return ret;
 }
 
 
@@ -1038,23 +1474,26 @@
 	ldb, integer *info);
 
 int luS_l_R(KODMAT(a), KDVEC(ipiv), ODMAT(b)) {
-  integer m = ar;
-  integer n = ac;
-  integer lda = aXc;
-  integer mrhs = br;
-  integer nrhs = bc;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
+    integer lda  = aXc;
+    integer mrhs = br;
+    integer nrhs = bc;
 
-  REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
-  integer* auxipiv = (integer*)malloc(n*sizeof(integer));
-  int k;
-  for (k=0; k<n; k++) {
-    auxipiv[k] = (integer)ipivp[k];
-  }
-  integer res;
-  dgetrs_ ("N",&n,&nrhs,(/*no const (!?)*/ double*)ap,&lda,auxipiv,bp,&mrhs,&res);
-  CHECK(res,res);
-  free(auxipiv);
-  OK
+    REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
+    integer* auxipiv = (integer*)malloc(n*sizeof(integer));
+    CHECK(!auxipiv,MEM);
+
+    for (int k=0; k<n; k++) {
+      auxipiv[k] = (integer)ipivp[k];
+    }
+    integer res;
+    dgetrs_ ("N",&n,&nrhs,(/*no const (!?)*/ double*)ap,&lda,auxipiv,bp,&mrhs,&res);
+    MARK(res,res);
+
+    free(auxipiv);
+    return ret;
 }
 
 
@@ -1063,23 +1502,26 @@
 	integer *ldb, integer *info);
 
 int luS_l_C(KOCMAT(a), KDVEC(ipiv), OCMAT(b)) {
-    integer m = ar;
-    integer n = ac;
-    integer lda = aXc;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
+    integer lda  = aXc;
     integer mrhs = br;
     integer nrhs = bc;
 
     REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
     integer* auxipiv = (integer*)malloc(n*sizeof(integer));
-    int k;
-    for (k=0; k<n; k++) {
+    CHECK(!auxipiv,MEM);
+
+    for (int k=0; k<n; k++) {
         auxipiv[k] = (integer)ipivp[k];
     }
     integer res;
     zgetrs_ ("N",&n,&nrhs,(doublecomplex*)ap,&lda,auxipiv,bp,&mrhs,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(auxipiv);
-    OK
+    return ret;
 }
 
 
@@ -1089,10 +1531,15 @@
             doublereal *work, integer *lwork, integer *info);
 
 int ldl_R(DVEC(ipiv), ODMAT(r)) {
-    integer n = rr;
+    integer ret = 0;
+    integer n   = rr;
+
     REQUIRES(n>=1 && rc==n && ipivn == n, BAD_SIZE);
     DEBUGMSG("ldl_R");
+
     integer* auxipiv = (integer*)malloc(n*sizeof(integer));
+    UNWIND(!auxipiv,MEM,cleanup0);
+
     integer res;
     integer lda = rXc;
     integer lwork = -1;
@@ -1100,15 +1547,22 @@
     dsytrf_ ("L",&n,rp,&lda,auxipiv,&ans,&lwork,&res);
     lwork = ceil(ans);
     doublereal* work = (doublereal*)malloc(lwork*sizeof(doublereal));
+    UNWIND(!work,MEM,cleanup1);
+
     dsytrf_ ("L",&n,rp,&lda,auxipiv,work,&lwork,&res);
-    CHECK(res,res);
+    UNWIND(res,res,cleanup2);
+
     int k;
     for (k=0; k<n; k++) {
         ipivp[k] = auxipiv[k];
     }
-    free(auxipiv);
+
+cleanup2:
     free(work);
-    OK
+cleanup1:
+    free(auxipiv);
+cleanup0:
+    return ret;
 }
 
 
@@ -1116,10 +1570,14 @@
             doublecomplex *work, integer *lwork, integer *info);
 
 int ldl_C(DVEC(ipiv), OCMAT(r)) {
-    integer n = rr;
+    integer ret = 0;
+    integer n   = rr;
+
     REQUIRES(n>=1 && rc==n && ipivn == n, BAD_SIZE);
     DEBUGMSG("ldl_R");
     integer* auxipiv = (integer*)malloc(n*sizeof(integer));
+    UNWIND(!auxipiv,MEM,cleanup0);
+
     integer res;
     integer lda = rXc;
     integer lwork = -1;
@@ -1127,15 +1585,21 @@
     zhetrf_ ("L",&n,rp,&lda,auxipiv,&ans,&lwork,&res);
     lwork = ceil(ans.r);
     doublecomplex* work = (doublecomplex*)malloc(lwork*sizeof(doublecomplex));
+    UNWIND(!work,MEM,cleanup1);
+
     zhetrf_ ("L",&n,rp,&lda,auxipiv,work,&lwork,&res);
-    CHECK(res,res);
+    UNWIND(res,res,cleanup2);
     int k;
     for (k=0; k<n; k++) {
         ipivp[k] = auxipiv[k];
     }
-    free(auxipiv);
+
+cleanup2:
     free(work);
-    OK
+cleanup1:
+    free(auxipiv);
+cleanup0:
+    return ret;
 
 }
 
@@ -1145,23 +1609,26 @@
             integer *ipiv, doublereal *b, integer *ldb, integer *info);
 
 int ldl_S_R(KODMAT(a), KDVEC(ipiv), ODMAT(b)) {
-  integer m = ar;
-  integer n = ac;
-  integer lda = aXc;
-  integer mrhs = br;
-  integer nrhs = bc;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
+    integer lda  = aXc;
+    integer mrhs = br;
+    integer nrhs = bc;
 
-  REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
-  integer* auxipiv = (integer*)malloc(n*sizeof(integer));
-  int k;
-  for (k=0; k<n; k++) {
-    auxipiv[k] = (integer)ipivp[k];
-  }
-  integer res;
-  dsytrs_ ("L",&n,&nrhs,(/*no const (!?)*/ double*)ap,&lda,auxipiv,bp,&mrhs,&res);
-  CHECK(res,res);
-  free(auxipiv);
-  OK
+    REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
+    integer* auxipiv = (integer*)malloc(n*sizeof(integer));
+    CHECK(!auxipiv,MEM);
+
+    for (int k=0; k<n; k++) {
+      auxipiv[k] = (integer)ipivp[k];
+    }
+    integer res;
+    dsytrs_ ("L",&n,&nrhs,(/*no const (!?)*/ double*)ap,&lda,auxipiv,bp,&mrhs,&res);
+    MARK(res,res);
+
+    free(auxipiv);
+    return ret;
 }
 
 
@@ -1169,23 +1636,26 @@
             integer *ipiv, doublecomplex *b, integer *ldb, integer *info);
 
 int ldl_S_C(KOCMAT(a), KDVEC(ipiv), OCMAT(b)) {
-    integer m = ar;
-    integer n = ac;
-    integer lda = aXc;
+    integer ret  = 0;
+    integer m    = ar;
+    integer n    = ac;
+    integer lda  = aXc;
     integer mrhs = br;
     integer nrhs = bc;
 
     REQUIRES(m==n && m==mrhs && m==ipivn,BAD_SIZE);
     integer* auxipiv = (integer*)malloc(n*sizeof(integer));
-    int k;
-    for (k=0; k<n; k++) {
+    CHECK(!auxipiv,MEM);
+
+    for (int k=0; k<n; k++) {
         auxipiv[k] = (integer)ipivp[k];
     }
     integer res;
     zhetrs_ ("L",&n,&nrhs,(doublecomplex*)ap,&lda,auxipiv,bp,&mrhs,&res);
-    CHECK(res,res);
+    MARK(res,res);
+
     free(auxipiv);
-    OK
+    return ret;
 }
 
 
diff --git a/src/Internal/C/vector-aux.c b/src/Internal/C/vector-aux.c
--- a/src/Internal/C/vector-aux.c
+++ b/src/Internal/C/vector-aux.c
@@ -932,19 +932,34 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-#if defined (__APPLE__) || (__FreeBSD__)
-/* FreeBSD and Mac OS X do not provide random_r(), thread safety cannot be
-   guaranteed.
+#if defined (__APPLE__) || (__FreeBSD__) || defined(NO_RANDOM_R) || defined(_WIN32) || defined(WIN32)
+/* Windows use thread-safe random
+   See: http://stackoverflow.com/questions/143108/is-windows-rand-s-thread-safe
+*/
+#if defined (__APPLE__) || (__FreeBSD__) || defined(NO_RANDOM_R)
+
+/* For FreeBSD, Mac OS X, and other libcs (like `musl`) that do not provide
+   random_r(), or if the use of random_r() is explicitly disabled, thread safety
+   cannot be guaranteed.
+   As per current understanding, this should at worst lead to less "random"
+   numbers being generated, in particular
+     * if another thread somebody calls lcong48() at the same time as nrand48()
+       is called
+     * in addition to that, for glibc with NO_RANDOM_R enabled when ndrand48()
+       is called for the first time by multiple threads in parallel due to the
+       initialisation function placed within it
+   See: http://www.evanjones.ca/random-thread-safe.html
+
    For FreeBSD and Mac OS X, nrand48() is much better than random().
    See: http://www.evanjones.ca/random-thread-safe.html
-*/
-#pragma message "randomVector is not thread-safe in OSX and FreeBSD"
-#endif
 
-#if defined (__APPLE__) || (__FreeBSD__) || defined(_WIN32) || defined(WIN32)
-/* Windows use thread-safe random
-   See: http://stackoverflow.com/questions/143108/is-windows-rand-s-thread-safe
+   TODO: As mentioned in the linked article, this could be fixed:
+         "the best solution for truly portable applications is to include
+          your own random number generator implementation,
+          and not rely on the system's C library".
 */
+#pragma message "randomVector is not thread-safe in OSX and FreeBSD or with NO_RANDOM_R; this likely leads to less random numbers at worst; see http://www.evanjones.ca/random-thread-safe.html"
+
 inline double urandom() {
     /* the probalility of matching will be theoretically p^3(in fact, it is not)
        p is matching probalility of random().
@@ -959,6 +974,22 @@
     return (double)nrand48(state) / (double)max_random;
 }
 
+#else
+
+#define _CRT_RAND_S
+inline double urandom() {
+    unsigned int number;
+    errno_t err;
+    err = rand_s(&number);
+    if (err!=0) {
+        printf("something wrong\n");
+        return -1;
+    }
+    return (double)number / (double)UINT_MAX;
+}
+
+#endif
+
 double gaussrand(int *phase, double *pV1, double *pV2, double *pS)
 {
 	double V1=*pV1, V2=*pV2, S=*pS;
@@ -985,10 +1016,39 @@
 
 }
 
+#if defined(_WIN32) || defined(WIN32)
+
 int random_vector(unsigned int seed, int code, DVEC(r)) {
     int phase = 0;
     double V1,V2,S;
 
+    srand(seed);
+
+    int k;
+    switch (code) {
+      case 0: { // uniform
+        for (k=0; k<rn; k++) {
+            rp[k] = urandom();
+        }
+        OK
+      }
+      case 1: { // gaussian
+        for (k=0; k<rn; k++) {
+            rp[k] = gaussrand(&phase,&V1,&V2,&S);
+        }
+        OK
+      }
+
+      default: ERROR(BAD_CODE);
+    }
+}
+
+#else
+
+int random_vector(unsigned int seed, int code, DVEC(r)) {
+    int phase = 0;
+    double V1,V2,S;
+
     srandom(seed);
 
     int k;
@@ -1010,6 +1070,8 @@
     }
 }
 
+#endif
+
 #else
 
 inline double urandom(struct random_data * buffer) {
@@ -1484,3 +1546,54 @@
     CHOOSE_IMP
 }
 
+//////////////////// reorder /////////////////////////
+
+#define REORDER_IMP                                                                     \
+    REQUIRES(kn == stridesn && stridesn == dimsn ,BAD_SIZE);                            \
+    int i,j,l;                                                                          \
+    for (i=1,j=0,l=0;l<kn;++l) {                                                        \
+        kp[l] = 0;                                                                      \
+        i *= dimsp[l];                                                                  \
+        j += (dimsp[l]-1) * stridesp[l];                                                \
+    }                                                                                   \
+    REQUIRES(i <= vn && j < rn ,BAD_SIZE);                                              \
+    for (i=0,j=0;;i++) {                                                                \
+        rp[i] = vp[j];                                                                  \
+        for(l=kn-1;;l--) {                                                              \
+            ++kp[l];                                                                    \
+            if (kp[l] < dimsp[l]) {                                                     \
+                j += stridesp[l];                                                       \
+                break;                                                                  \
+            } else {                                                                    \
+                if (l == 0) {                                                           \
+                    return 0;                                                           \
+                }                                                                       \
+                kp[l] = 0;                                                              \
+                j -= (dimsp[l]-1) * stridesp[l];                                        \
+            }                                                                           \
+        }                                                                               \
+    }
+
+int reorderF(IVEC(k), KIVEC(strides),KIVEC(dims),KFVEC(v),FVEC(r)) {
+    REORDER_IMP
+}
+
+int reorderD(IVEC(k), KIVEC(strides),KIVEC(dims),KDVEC(v),DVEC(r)) {
+    REORDER_IMP
+}
+
+int reorderI(IVEC(k), KIVEC(strides),KIVEC(dims),KIVEC(v),IVEC(r)) {
+    REORDER_IMP
+}
+
+int reorderL(IVEC(k), KIVEC(strides),KIVEC(dims),KLVEC(v),LVEC(r)) {
+    REORDER_IMP
+}
+
+int reorderC(IVEC(k), KIVEC(strides),KIVEC(dims),KCVEC(v),CVEC(r)) {
+    REORDER_IMP
+}
+
+int reorderQ(IVEC(k), KIVEC(strides),KIVEC(dims),KQVEC(v),QVEC(r)) {
+    REORDER_IMP
+}
diff --git a/src/Internal/CG.hs b/src/Internal/CG.hs
--- a/src/Internal/CG.hs
+++ b/src/Internal/CG.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
 {-# LANGUAGE RecordWildCards #-}
 
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 module Internal.CG(
     cgSolve, cgSolve',
     CGState(..), R, V
@@ -177,9 +179,9 @@
           where
             m1 = convomat n k
             m2 = map (((+n) *** id) *** id) m1
-            
+
         testb n = vect $ take n $ cycle ([0..10]++[9,8..1])
-        
+
         denseSolve a = flatten . linearSolveLS a . asColumn
 
         -- mkDiag v = mkDiagR (dim v) (dim v) v
diff --git a/src/Internal/Chain.hs b/src/Internal/Chain.hs
--- a/src/Internal/Chain.hs
+++ b/src/Internal/Chain.hs
@@ -1,5 +1,7 @@
 {-# LANGUAGE FlexibleContexts #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Internal.Chain
diff --git a/src/Internal/Container.hs b/src/Internal/Container.hs
--- a/src/Internal/Container.hs
+++ b/src/Internal/Container.hs
@@ -1,8 +1,8 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE UndecidableInstances #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -28,17 +28,21 @@
 import Internal.Matrix
 import Internal.Element
 import Internal.Numeric
-import Internal.Algorithms(Field,linearSolveSVD)
-
+import Internal.Algorithms(Field,linearSolveSVD,Herm,mTm)
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 ------------------------------------------------------------------
 
 {- | Creates a real vector containing a range of values:
 
 >>> linspace 5 (-3,7::Double)
-fromList [-3.0,-0.5,2.0,4.5,7.0]@
+[-3.0,-0.5,2.0,4.5,7.0]
+it :: Vector Double
 
->>> linspace 5 (8,2+i) :: Vector (Complex Double)
-fromList [8.0 :+ 0.0,6.5 :+ 0.25,5.0 :+ 0.5,3.5 :+ 0.75,2.0 :+ 1.0]
+>>> linspace 5 (8,3:+2) :: Vector (Complex Double)
+[8.0 :+ 0.0,6.75 :+ 0.5,5.5 :+ 1.0,4.25 :+ 1.5,3.0 :+ 2.0]
+it :: Vector (Complex Double)
 
 Logarithmic spacing can be defined as follows:
 
@@ -82,7 +86,8 @@
 >>> let v = vector [10,20,30]
 
 >>> m #> v
-fromList [140.0,320.0]
+[140.0,320.0]
+it :: Vector Numeric.LinearAlgebra.Data.R
 
 -}
 infixr 8 #>
@@ -131,10 +136,12 @@
 
 >>> let x = a <\> v
 >>> x
-fromList [3.0799999999999996,5.159999999999999]
+[3.0799999999999996,5.159999999999999]
+it :: Vector Numeric.LinearAlgebra.Data.R
 
 >>> a #> x
-fromList [13.399999999999999,26.799999999999997,1.0]
+[13.399999999999999,26.799999999999997,0.9999999999999991]
+it :: Vector Numeric.LinearAlgebra.Data.R
 
 It also admits multiple right-hand sides stored as columns in a matrix.
 
@@ -162,7 +169,8 @@
   where
     -- |
     -- >>> build 5 (**2) :: Vector Double
-    -- fromList [0.0,1.0,4.0,9.0,16.0]
+    -- [0.0,1.0,4.0,9.0,16.0]
+    -- it :: Vector Double
     --
     -- Hilbert matrix of order N:
     --
@@ -179,7 +187,7 @@
   where
     build = build'
 
-instance Container Matrix e => Build (Int,Int) (e -> e -> e) Matrix e
+instance (Num e, Container Vector e) => Build (Int,Int) (e -> e -> e) Matrix e
   where
     build = build'
 
@@ -199,21 +207,20 @@
 
 {- | Compute mean vector and covariance matrix of the rows of a matrix.
 
->>> meanCov $ gaussianSample 666 1000 (fromList[4,5]) (diagl[2,3])
-(fromList [4.010341078059521,5.0197204699640405],
-(2><2)
- [     1.9862461923890056, -1.0127225830525157e-2
- , -1.0127225830525157e-2,     3.0373954915729318 ])
-
+>>> meanCov $ gaussianSample 666 1000 (fromList[4,5]) (trustSym $ diagl [2,3])
+([3.9933155655086696,5.061409102770331],Herm (2><2)
+ [    1.9963242906624408, -4.227815571404954e-2
+ , -4.227815571404954e-2,    3.2003833097832857 ])
+it :: (Vector Double, Herm Double)
 -}
-meanCov :: Matrix Double -> (Vector Double, Matrix Double)
+meanCov :: Matrix Double -> (Vector Double, Herm Double)
 meanCov x = (med,cov) where
     r    = rows x
     k    = 1 / fromIntegral r
     med  = konst k r `vXm` x
     meds = konst 1 r `outer` med
     xc   = x `sub` meds
-    cov  = scale (recip (fromIntegral (r-1))) (trans xc `mXm` xc)
+    cov  = scale (recip (fromIntegral (r-1))) (mTm xc)
 
 --------------------------------------------------------------------------------
 
@@ -293,5 +300,3 @@
     | otherwise = error $ "out of range index in remap"
   where
     [i',j'] = conformMs [i,j]
-    
-
diff --git a/src/Internal/Conversion.hs b/src/Internal/Conversion.hs
--- a/src/Internal/Conversion.hs
+++ b/src/Internal/Conversion.hs
@@ -3,7 +3,6 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FunctionalDependencies #-}
-{-# LANGUAGE UndecidableInstances #-}
 
 -----------------------------------------------------------------------------
 -- |
diff --git a/src/Internal/Convolution.hs b/src/Internal/Convolution.hs
--- a/src/Internal/Convolution.hs
+++ b/src/Internal/Convolution.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 -----------------------------------------------------------------------------
 {- |
@@ -23,6 +24,9 @@
 import Internal.Element
 import Internal.Conversion
 import Internal.Container
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 
 vectSS :: Element t => Int -> Vector t -> Matrix t
@@ -37,7 +41,8 @@
 {- ^ correlation
 
 >>> corr (fromList[1,2,3]) (fromList [1..10])
-fromList [14.0,20.0,26.0,32.0,38.0,44.0,50.0,56.0]
+[14.0,20.0,26.0,32.0,38.0,44.0,50.0,56.0]
+it :: (Enum t, Product t, Container Vector t) => Vector t
 
 -}
 corr ker v
@@ -50,7 +55,8 @@
 {- ^ convolution ('corr' with reversed kernel and padded input, equivalent to polynomial product)
 
 >>> conv (fromList[1,1]) (fromList [-1,1])
-fromList [-1.0,0.0,1.0]
+[-1.0,0.0,1.0]
+it :: (Product t, Container Vector t) => Vector t
 
 -}
 conv ker v
diff --git a/src/Internal/Devel.hs b/src/Internal/Devel.hs
--- a/src/Internal/Devel.hs
+++ b/src/Internal/Devel.hs
@@ -16,7 +16,8 @@
 import Foreign.C.Types ( CInt )
 --import Foreign.Storable.Complex ()
 import Foreign.Ptr(Ptr)
-import Control.Exception as E ( SomeException, catch )
+import           Control.Exception (SomeException, SomeAsyncException (..))
+import qualified Control.Exception as Exception
 import Internal.Vector(Vector,avec)
 import Foreign.Storable(Storable)
 
@@ -54,14 +55,27 @@
 
 -- | postfix error code check
 infixl 0 #|
+(#|) :: IO CInt -> String -> IO ()
 (#|) = flip check
 
 -- | Error capture and conversion to Maybe
 mbCatch :: IO x -> IO (Maybe x)
-mbCatch act = E.catch (Just `fmap` act) f
-    where f :: SomeException -> IO (Maybe x)
-          f _ = return Nothing
+mbCatch act =
+  hush <$>
+    Exception.tryJust
+      (\e -> if isSyncException e then Just e else Nothing)
+      act
 
+  where
+    hush :: Either a b -> Maybe b
+    hush = either (const Nothing) Just
+
+    isSyncException :: SomeException -> Bool
+    isSyncException e =
+      case Exception.fromException e of
+        Just (SomeAsyncException _) -> False
+        Nothing -> True
+
 --------------------------------------------------------------------------------
 
 type CM b r = CInt -> CInt -> Ptr b -> r
@@ -80,8 +94,8 @@
   where
     type Trans c b
     type TransRaw c b
-    apply      :: (Trans c b) -> c -> b
-    applyRaw   :: (TransRaw c b) -> c -> b
+    apply      :: c -> (b -> IO r) -> (Trans c b) -> IO r
+    applyRaw   :: c -> (b -> IO r) -> (TransRaw c b) -> IO r
     infixl 1 `apply`, `applyRaw`
 
 instance Storable t => TransArray (Vector t)
@@ -92,4 +106,3 @@
     {-# INLINE apply #-}
     applyRaw = avec
     {-# INLINE applyRaw #-}
-
diff --git a/src/Internal/Element.hs b/src/Internal/Element.hs
--- a/src/Internal/Element.hs
+++ b/src/Internal/Element.hs
@@ -1,10 +1,10 @@
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE CPP #-}
 
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Data.Packed.Matrix
@@ -32,14 +32,14 @@
 import Foreign.Storable(Storable)
 import System.IO.Unsafe(unsafePerformIO)
 import Control.Monad(liftM)
+import Foreign.C.Types(CInt)
 
 -------------------------------------------------------------------
 
-#ifdef BINARY
 
 import Data.Binary
 
-instance (Binary (Vector a), Element a) => Binary (Matrix a) where
+instance (Binary a, Element a) => Binary (Matrix a) where
     put m = do
             put (cols m)
             put (flatten m)
@@ -48,7 +48,6 @@
           v <- get
           return (reshape c v)
 
-#endif
 
 -------------------------------------------------------------------
 
@@ -56,8 +55,10 @@
     show m | rows m == 0 || cols m == 0 = sizes m ++" []"
     show m = (sizes m++) . dsp . map (map show) . toLists $ m
 
+sizes :: Matrix t -> [Char]
 sizes m = "("++show (rows m)++"><"++show (cols m)++")\n"
 
+dsp :: [[[Char]]] -> [Char]
 dsp as = (++" ]") . (" ["++) . init . drop 2 . unlines . map (" , "++) . map unwords' $ transpose mtp
     where
         mt = transpose as
@@ -76,6 +77,7 @@
               rs = read . snd . breakAt '(' .init . fst . breakAt '>' $ dims
 
 
+breakAt :: Eq a => a -> [a] -> ([a], [a])
 breakAt c l = (a++[c],tail b) where
     (a,b) = break (==c) l
 
@@ -91,7 +93,8 @@
     | Drop Int
     | DropLast Int
   deriving Show
-  
+
+ppext :: Extractor -> [Char]
 ppext All = ":"
 ppext (Range a 1 c) = printf "%d:%d" a c
 ppext (Range a b c) = printf "%d:%d:%d" a b c
@@ -131,10 +134,14 @@
 infixl 9 ??
 (??)  :: Element t => Matrix t -> (Extractor,Extractor) -> Matrix t
 
+minEl :: Vector CInt -> CInt
 minEl = toScalarI Min
+maxEl :: Vector CInt -> CInt
 maxEl = toScalarI Max
+cmodi :: Foreign.C.Types.CInt -> Vector Foreign.C.Types.CInt -> Vector Foreign.C.Types.CInt
 cmodi = vectorMapValI ModVS
 
+extractError :: Matrix t1 -> (Extractor, Extractor) -> t
 extractError m (e1,e2)= error $ printf "can't extract (%s,%s) from matrix %dx%d" (ppext e1::String) (ppext e2::String) (rows m) (cols m)
 
 m ?? (Range a s b,e) | s /= 1 = m ?? (Pos (idxs [a,a+s .. b]), e)
@@ -235,8 +242,10 @@
 fromBlocks :: Element t => [[Matrix t]] -> Matrix t
 fromBlocks = fromBlocksRaw . adaptBlocks
 
+fromBlocksRaw :: Element t => [[Matrix t]] -> Matrix t
 fromBlocksRaw mms = joinVert . map joinHoriz $ mms
 
+adaptBlocks :: Element t => [[Matrix t]] -> [[Matrix t]]
 adaptBlocks ms = ms' where
     bc = case common length ms of
           Just c -> c
@@ -489,6 +498,9 @@
     m2' = conformMTo (r,c) m2
 
 -- FIXME do not flatten if equal order
+lM :: (Storable t, Element t1, Element t2)
+   => (Vector t1 -> Vector t2 -> Vector t)
+   -> Matrix t1 -> Matrix t2 -> Matrix t
 lM f m1 m2 = matrixFromVector
                 RowMajor
                 (max' (rows m1) (rows m2))
@@ -507,6 +519,7 @@
 
 ------------------------------------------------------------
 
+toBlockRows :: Element t => [Int] -> Matrix t -> [Matrix t]
 toBlockRows [r] m
     | r == rows m = [m]
 toBlockRows rs m
@@ -516,6 +529,7 @@
     szs = map (* cols m) rs
     g k = (k><0)[]
 
+toBlockCols :: Element t => [Int] -> Matrix t -> [Matrix t]
 toBlockCols [c] m | c == cols m = [m]
 toBlockCols cs m = map trans . toBlockRows cs . trans $ m
 
@@ -579,7 +593,7 @@
 mapMatrixWithIndexM
   :: (Element a, Storable b, Monad m) =>
       ((Int, Int) -> a -> m b) -> Matrix a -> m (Matrix b)
-mapMatrixWithIndexM g m = liftM (reshape c) . mapVectorWithIndexM (mk c g) . flatten $ m 
+mapMatrixWithIndexM g m = liftM (reshape c) . mapVectorWithIndexM (mk c g) . flatten $ m
     where
       c = cols m
 
@@ -601,4 +615,3 @@
 
 mapMatrix :: (Element a, Element b) => (a -> b) -> Matrix a -> Matrix b
 mapMatrix f = liftMatrix (mapVector f)
-
diff --git a/src/Internal/Foreign.hs b/src/Internal/Foreign.hs
deleted file mode 100644
--- a/src/Internal/Foreign.hs
+++ /dev/null
@@ -1,102 +0,0 @@
-{-# LANGUAGE MagicHash, UnboxedTuples #-}
--- | FFI and hmatrix helpers.
---
--- Sample usage, to upload a perspective matrix to a shader.
---
--- @ glUniformMatrix4fv 0 1 (fromIntegral gl_TRUE) \`appMatrix\` perspective 0.01 100 (pi\/2) (4\/3) 
--- @
---
-
-module Internal.Foreign 
-    ( app
-    , appVector, appVectorLen
-    , appMatrix, appMatrixLen, appMatrixRaw, appMatrixRawLen
-    , unsafeMatrixToVector, unsafeMatrixToForeignPtr
-    ) where
-
-import Foreign.C.Types(CInt)
-import Internal.Vector
-import Internal.Matrix
-import qualified Data.Vector.Storable as S
-import Foreign (Ptr, ForeignPtr, Storable)
-import GHC.Base (IO(..), realWorld#)
-
-{-# INLINE unsafeInlinePerformIO #-}
--- | If we use unsafePerformIO, it may not get inlined, so in a function that returns IO (which are all safe uses of app* in this module), there would be
--- unecessary calls to unsafePerformIO or its internals.
-unsafeInlinePerformIO :: IO a -> a
-unsafeInlinePerformIO (IO f) = case f realWorld# of
-    (# _, x #) -> x
-
-{-# INLINE app #-}
--- | Only useful since it is left associated with a precedence of 1, unlike 'Prelude.$', which is right associative.
--- e.g.
---
--- @
--- someFunction
---     \`appMatrixLen\` m
---     \`appVectorLen\` v
---     \`app\` other
---     \`app\` arguments
---     \`app\` go here
--- @
---
--- One could also write:
---
--- @
--- (someFunction 
---     \`appMatrixLen\` m
---     \`appVectorLen\` v) 
---     other 
---     arguments 
---     (go here)
--- @
---
-app :: (a -> b) -> a -> b
-app f = f
-
-{-# INLINE appVector #-}
-appVector :: Storable a => (Ptr a -> b) -> Vector a -> b
-appVector f x = unsafeInlinePerformIO (S.unsafeWith x (return . f))
-
-{-# INLINE appVectorLen #-}
-appVectorLen :: Storable a => (CInt -> Ptr a -> b) -> Vector a -> b
-appVectorLen f x = unsafeInlinePerformIO (S.unsafeWith x (return . f (fromIntegral (S.length x))))
-
-{-# INLINE appMatrix #-}
-appMatrix :: Element a => (Ptr a -> b) -> Matrix a -> b
-appMatrix f x = unsafeInlinePerformIO (S.unsafeWith (flatten x) (return . f))
-
-{-# INLINE appMatrixLen #-}
-appMatrixLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
-appMatrixLen f x = unsafeInlinePerformIO (S.unsafeWith (flatten x) (return . f r c))
-  where
-    r = fromIntegral (rows x)
-    c = fromIntegral (cols x)
-
-{-# INLINE appMatrixRaw #-}
-appMatrixRaw :: Storable a => (Ptr a -> b) -> Matrix a -> b
-appMatrixRaw f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f))
-
-{-# INLINE appMatrixRawLen #-}
-appMatrixRawLen :: Element a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
-appMatrixRawLen f x = unsafeInlinePerformIO (S.unsafeWith (xdat x) (return . f r c))
-  where
-    r = fromIntegral (rows x)
-    c = fromIntegral (cols x)
-
-infixl 1 `app`
-infixl 1 `appVector`
-infixl 1 `appMatrix`
-infixl 1 `appMatrixRaw`
-
-{-# INLINE unsafeMatrixToVector #-}
--- | This will disregard the order of the matrix, and simply return it as-is. 
--- If the order of the matrix is RowMajor, this function is identical to 'flatten'.
-unsafeMatrixToVector :: Matrix a -> Vector a
-unsafeMatrixToVector = xdat
-
-{-# INLINE unsafeMatrixToForeignPtr #-}
-unsafeMatrixToForeignPtr :: Storable a => Matrix a -> (ForeignPtr a, Int)
-unsafeMatrixToForeignPtr m = S.unsafeToForeignPtr0 (xdat m)
-
diff --git a/src/Internal/IO.hs b/src/Internal/IO.hs
--- a/src/Internal/IO.hs
+++ b/src/Internal/IO.hs
@@ -20,7 +20,7 @@
 import Internal.Vector
 import Internal.Matrix
 import Internal.Vectorized
-import Text.Printf(printf)
+import Text.Printf(printf, PrintfArg, PrintfType)
 import Data.List(intersperse,transpose)
 import Data.Complex
 
@@ -78,12 +78,18 @@
 dispf :: Int -> Matrix Double -> String
 dispf d x = sdims x ++ "\n" ++ formatFixed (if isInt x then 0 else d) x
 
+sdims :: Matrix t -> [Char]
 sdims x = show (rows x) ++ "x" ++ show (cols x)
 
+formatFixed :: (Show a, Text.Printf.PrintfArg t, Element t)
+            => a -> Matrix t -> String
 formatFixed d x = format "  " (printf ("%."++show d++"f")) $ x
 
+isInt :: Matrix Double -> Bool
 isInt = all lookslikeInt . toList . flatten
 
+formatScaled :: (Text.Printf.PrintfArg b, RealFrac b, Floating b, Num t, Element b, Show t)
+             => t -> Matrix b -> [Char]
 formatScaled dec t = "E"++show o++"\n" ++ ss
     where ss = format " " (printf fmt. g) t
           g x | o >= 0    = x/10^(o::Int)
@@ -133,14 +139,18 @@
     s2 = if b<0 then "-" else ""
     s3 = if b<0 then "-" else "+"
 
+shcr :: (Show a, Show t1, Text.Printf.PrintfType t, Text.Printf.PrintfArg t1, RealFrac t1)
+     => a -> t1 -> t
 shcr d a | lookslikeInt a = printf "%.0f" a
          | otherwise      = printf ("%."++show d++"f") a
 
-
+lookslikeInt :: (Show a, RealFrac a) => a -> Bool
 lookslikeInt x = show (round x :: Int) ++".0" == shx || "-0.0" == shx
    where shx = show x
 
+isZero :: Show a => a -> Bool
 isZero x = show x `elem` ["0.0","-0.0"]
+isOne :: Show a => a -> Bool
 isOne  x = show x `elem` ["1.0","-1.0"]
 
 -- | Pretty print a complex matrix with at most n decimal digits.
@@ -168,6 +178,6 @@
       else
         return (reshape c v)
 
-
+loadMatrix' :: FilePath -> IO (Maybe (Matrix Double))
 loadMatrix' name = mbCatch (loadMatrix name)
 
diff --git a/src/Internal/LAPACK.hs b/src/Internal/LAPACK.hs
--- a/src/Internal/LAPACK.hs
+++ b/src/Internal/LAPACK.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE ViewPatterns #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Numeric.LinearAlgebra.LAPACK
@@ -16,9 +18,11 @@
 
 module Internal.LAPACK where
 
+import Data.Bifunctor (first)
+
 import Internal.Devel
 import Internal.Vector
-import Internal.Matrix hiding ((#))
+import Internal.Matrix hiding ((#), (#!))
 import Internal.Conversion
 import Internal.Element
 import Foreign.Ptr(nullPtr)
@@ -28,10 +32,13 @@
 
 -----------------------------------------------------------------------------------
 
-infixl 1 #
+infixr 1 #
 a # b = apply a b
 {-# INLINE (#) #-}
 
+a #! b = a # b # id
+{-# INLINE (#!) #-}
+
 -----------------------------------------------------------------------------------
 
 type TMMM t = t ::> t ::> t ::> Ok
@@ -56,7 +63,7 @@
     when (cols a /= rows b) $ error $ "inconsistent dimensions in matrix product "++
                                        show (rows a,cols a) ++ " x " ++ show (rows b, cols b)
     s <- createMatrix ColumnMajor (rows a) (cols b)
-    f (isT a) (isT b) # (tt a) # (tt b) # s #| st
+    ((tt a) # (tt b) #! s) (f (isT a) (isT b)) #| st
     return s
 
 -- | Matrix product based on BLAS's /dgemm/.
@@ -80,7 +87,7 @@
     when (cols a /= rows b) $ error $
         "inconsistent dimensions in matrix product "++ shSize a ++ " x " ++ shSize b
     s <- createMatrix ColumnMajor (rows a) (cols b)
-    c_multiplyI m # a # b # s #|"c_multiplyI"
+    (a # b #! s) (c_multiplyI m) #|"c_multiplyI"
     return s
 
 multiplyL :: Z -> Matrix Z -> Matrix Z -> Matrix Z
@@ -88,7 +95,7 @@
     when (cols a /= rows b) $ error $
         "inconsistent dimensions in matrix product "++ shSize a ++ " x " ++ shSize b
     s <- createMatrix ColumnMajor (rows a) (cols b)
-    c_multiplyL m # a # b # s #|"c_multiplyL"
+    (a # b #! s) (c_multiplyL m) #|"c_multiplyL"
     return s
 
 -----------------------------------------------------------------------------
@@ -121,7 +128,7 @@
     u <- createMatrix ColumnMajor r r
     s <- createVector (min r c)
     v <- createMatrix ColumnMajor c c
-    f # a # u # s # v #| st
+    (a # u # s #! v) f #| st
     return (u,s,v)
   where
     r = rows x
@@ -149,7 +156,7 @@
     u <- createMatrix ColumnMajor r q
     s <- createVector q
     v <- createMatrix ColumnMajor q c
-    f # a # u # s # v #| st
+    (a # u # s #! v) f #| st
     return (u,s,v)
   where
     r = rows x
@@ -176,7 +183,7 @@
 svAux f st x = unsafePerformIO $ do
     a <- copy ColumnMajor x
     s <- createVector q
-    g # a # s #| st
+    (a #! s) g #| st
     return s
   where
     r = rows x
@@ -197,7 +204,7 @@
     a <- copy ColumnMajor x
     s <- createVector q
     v <- createMatrix ColumnMajor c c
-    g # a # s # v #| st
+    (a # s #! v) g #| st
     return (s,v)
   where
     r = rows x
@@ -218,7 +225,7 @@
     a <- copy ColumnMajor x
     u <- createMatrix ColumnMajor r r
     s <- createVector q
-    g # a # u # s #| st
+    (a # u #! s) g #| st
     return (u,s)
   where
     r = rows x
@@ -229,7 +236,9 @@
 -----------------------------------------------------------------------------
 
 foreign import ccall unsafe "eig_l_R" dgeev :: R ::> R ::> C :> R ::> Ok
+foreign import ccall unsafe "eig_l_G" dggev :: R ::> R ::> C :> R :> R ::> R ::> Ok
 foreign import ccall unsafe "eig_l_C" zgeev :: C ::> C ::> C :> C ::> Ok
+foreign import ccall unsafe "eig_l_GC" zggev :: C ::> C ::> C :> C :> C ::> C ::> Ok
 foreign import ccall unsafe "eig_l_S" dsyev :: CInt -> R :> R ::> Ok
 foreign import ccall unsafe "eig_l_H" zheev :: CInt -> R :> C ::> Ok
 
@@ -237,7 +246,7 @@
     a <- copy ColumnMajor m
     l <- createVector r
     v <- createMatrix ColumnMajor r r
-    g # a # l # v #| st
+    (a # l #! v) g #| st
     return (l,v)
   where
     r = rows m
@@ -252,7 +261,7 @@
 eigOnlyAux f st m = unsafePerformIO $ do
     a <- copy ColumnMajor m
     l <- createVector r
-    g # a # l #| st
+    (a #! l) g #| st
     return l
   where
     r = rows m
@@ -277,7 +286,7 @@
     a <- copy ColumnMajor m
     l <- createVector r
     v <- createMatrix ColumnMajor r r
-    g # a # l # v #| "eigR"
+    (a # l #! v) g #| "eigR"
     return (l,v)
   where
     r = rows m
@@ -293,19 +302,75 @@
     | otherwise = comp' v1 : fixeig ((r2:+i2):r) (v2:vs)
 fixeig _ _ = error "fixeig with impossible inputs"
 
+-- For dggev alpha(i) / beta(i), alpha(i+1) / beta(i+1) form a complex conjugate pair when Im alpha(i) != 0.
+-- However, this does not lead to Re alpha(i) == Re alpha(i+1), since beta(i) and beta(i+1)
+-- can be different. Therefore old 'fixeig' would fail for 'eigG'.
+fixeigG  []  _  = []
+fixeigG [_] [v] = [comp' v]
+fixeigG ((_:+ai1) : an : as) (v1:v2:vs)
+    | abs ai1 > 1e-13 = toComplex' (v1, v2) : toComplex' (v1, mapVector negate v2) : fixeigG as vs
+    | otherwise = comp' v1 : fixeigG (an:as) (v2:vs)
+fixeigG _ _ = error "fixeigG with impossible inputs"
 
 -- | Eigenvalues of a general real matrix, using LAPACK's /dgeev/ with jobz == \'N\'.
 -- The eigenvalues are not sorted.
 eigOnlyR :: Matrix Double -> Vector (Complex Double)
 eigOnlyR = fixeig1 . eigOnlyAux dgeev "eigOnlyR"
 
+-- | Generalized eigenvalues and right eigenvectors of a pair of real matrices, using LAPACK's /dggev/.
+-- The eigenvectors are the columns of v. The eigenvalues are represented as alphas / betas and not sorted.
+eigG :: Matrix Double -> Matrix Double -> (Vector (Complex Double), Vector Double, Matrix (Complex Double))
+eigG a b = (alpha', beta, v'')
+  where
+    (alpha, beta, v) = eigGaux dggev a b "eigG"
+    alpha' = fixeig1 alpha
+    v' = toRows $ trans v
+    v'' = fromColumns $ fixeigG (toList alpha') v'
 
+eigGaux f ma mb st = unsafePerformIO $ do
+    a <- copy ColumnMajor ma
+    b <- copy ColumnMajor mb
+    alpha <- createVector r
+    beta <- createVector r
+    vr <- createMatrix ColumnMajor r r
+
+    (a # b # alpha # beta #! vr) g #| st
+
+    return (alpha, beta, vr)
+  where
+    r = rows ma
+    g ar ac xra xca pa br bc xrb xcb pb alphan palpha betan pbeta = f ar ac xra xca pa br bc xrb xcb pb alphan palpha betan pbeta 0 0 0 0 nullPtr 
+
+eigGOnlyAux f ma mb st = unsafePerformIO $ do
+    a <- copy ColumnMajor ma
+    b <- copy ColumnMajor mb
+    alpha <- createVector r
+    beta <- createVector r
+
+    (a # b # alpha #! beta) g #| st
+
+    return (alpha, beta)
+  where
+    r = rows ma
+    g ar ac xra xca pa br bc xrb xcb pb alphan palpha betan pbeta = f ar ac xra xca pa br bc xrb xcb pb alphan palpha betan pbeta 0 0 0 0 nullPtr 0 0 0 0 nullPtr
+
+-- | Generalized eigenvalues and right eigenvectors of a pair of complex matrices, using LAPACK's /zggev/.
+-- The eigenvectors are the columns of v. The eigenvalues are represented as alphas / betas and not sorted.
+eigGC :: Matrix (Complex Double) -> Matrix (Complex Double) -> (Vector (Complex Double), Vector (Complex Double), Matrix (Complex Double))
+eigGC a b = eigGaux zggev a b "eigGC"
+
+eigOnlyG :: Matrix Double -> Matrix Double -> (Vector (Complex Double), Vector Double)
+eigOnlyG a b = first fixeig1 $ eigGOnlyAux dggev a b "eigOnlyG"
+
+eigOnlyGC :: Matrix (Complex Double) -> Matrix (Complex Double) -> (Vector (Complex Double), Vector (Complex Double))
+eigOnlyGC a b = eigGOnlyAux zggev a b "eigOnlyGC"
+
 -----------------------------------------------------------------------------
 
 eigSHAux f st m = unsafePerformIO $ do
     l <- createVector r
     v <- copy ColumnMajor m
-    f # l # v #| st
+    (l #! v) f #| st
     return (l,v)
   where
     r = rows m
@@ -356,7 +421,7 @@
     | n1==n2 && n1==r = unsafePerformIO . g $ do
         a' <- copy ColumnMajor a
         s  <- copy ColumnMajor b
-        f # a' # s #| st
+        (a' #! s) f #| st
         return s
     | otherwise = error $ st ++ " of nonsquare matrix"
   where
@@ -387,7 +452,7 @@
 linearSolveSQAux2 g f st a b
     | n1==n2 && n1==r = unsafePerformIO . g $ do
         s <- copy ColumnMajor b
-        f # a # s #| st
+        (a #! s) f #| st
         return s
     | otherwise = error $ st ++ " of nonsquare matrix"
   where
@@ -403,6 +468,60 @@
 cholSolveC :: Matrix (Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double)
 cholSolveC a b = linearSolveSQAux2 id zpotrs "cholSolveC" (fmat a) b
 
+--------------------------------------------------------------------------------
+foreign import ccall unsafe "triSolveR_l_u" dtrtrs_u  :: R ::> R ::> Ok
+foreign import ccall unsafe "triSolveC_l_u" ztrtrs_u  :: C ::> C ::> Ok
+foreign import ccall unsafe "triSolveR_l_l" dtrtrs_l  :: R ::> R ::> Ok
+foreign import ccall unsafe "triSolveC_l_l" ztrtrs_l  :: C ::> C ::> Ok
+
+
+linearSolveTRAux2 g f st a b
+    | n1==n2 && n1==r = unsafePerformIO . g $ do
+        s <- copy ColumnMajor b
+        (a #! s) f #| st
+        return s
+    | otherwise = error $ st ++ " of nonsquare matrix"
+  where
+    n1 = rows a
+    n2 = cols a
+    r  = rows b
+
+data UpLo = Lower | Upper
+
+-- | Solves a triangular system of linear equations.
+triSolveR :: UpLo -> Matrix Double -> Matrix Double -> Matrix Double
+triSolveR Lower a b = linearSolveTRAux2 id dtrtrs_l "triSolveR" (fmat a) b
+triSolveR Upper a b = linearSolveTRAux2 id dtrtrs_u "triSolveR" (fmat a) b
+
+-- | Solves a triangular system of linear equations.
+triSolveC :: UpLo -> Matrix (Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double)
+triSolveC Lower a b = linearSolveTRAux2 id ztrtrs_l "triSolveC" (fmat a) b
+triSolveC Upper a b = linearSolveTRAux2 id ztrtrs_u "triSolveC" (fmat a) b
+
+--------------------------------------------------------------------------------
+foreign import ccall unsafe "triDiagSolveR_l" dgttrs  :: R :> R :> R :> R ::> Ok
+foreign import ccall unsafe "triDiagSolveC_l" zgttrs  :: C :> C :> C :> C ::> Ok
+
+linearSolveGTAux2 g f st dl d du b
+    | ndl  == nd - 1 &&
+      ndu  == nd - 1 &&
+      nd   == r = unsafePerformIO . g $ do
+        dl' <- head . toRows <$> copy ColumnMajor (fromRows [dl])
+        du' <- head . toRows <$> copy ColumnMajor (fromRows [du])
+        s <- copy ColumnMajor b
+        (dl' # d # du' #! s) f #| st
+        return s
+    | otherwise = error $ st ++ " of nonsquare matrix"
+  where
+    ndl  = dim dl
+    nd   = dim d
+    ndu  = dim du
+    r    = rows b
+
+-- | Solves a tridiagonal system of linear equations.
+triDiagSolveR dl d du b = linearSolveGTAux2 id dgttrs "triDiagSolveR" dl d du b
+triDiagSolveC dl d du b = linearSolveGTAux2 id zgttrs "triDiagSolveC" dl d du b
+
 -----------------------------------------------------------------------------------
 
 foreign import ccall unsafe "linearSolveLSR_l"   dgels ::           R ::> R ::> Ok
@@ -415,7 +534,7 @@
         a' <- copy ColumnMajor a
         r  <- createMatrix ColumnMajor (max m n) nrhs
         setRect 0 0 b r
-        f # a' # r #| st
+        (a' #! r) f #| st
         return r
     | otherwise = error $ "different number of rows in linearSolve ("++st++")"
   where
@@ -458,7 +577,7 @@
 
 cholAux f st a = do
     r <- copy ColumnMajor a
-    f # r #| st
+    (r # id) f #| st
     return r
 
 -- | Cholesky factorization of a complex Hermitian positive definite matrix, using LAPACK's /zpotrf/.
@@ -495,7 +614,7 @@
 qrAux f st a = unsafePerformIO $ do
     r <- copy ColumnMajor a
     tau <- createVector mn
-    f # tau # r #| st
+    (tau #! r) f #| st
     return (r,tau)
   where
     m = rows a
@@ -514,7 +633,7 @@
 
 qrgrAux f st n (a, tau) = unsafePerformIO $ do
     res <- copy ColumnMajor (subMatrix (0,0) (rows a,n) a)
-    f # (subVector 0 n tau') # res #| st
+    ((subVector 0 n tau') #! res) f #| st
     return res
   where
     tau' = vjoin [tau, constantD 0 n]
@@ -534,7 +653,7 @@
 hessAux f st a = unsafePerformIO $ do
     r <- copy ColumnMajor a
     tau <- createVector (mn-1)
-    f # tau # r #| st
+    (tau #! r) f #| st
     return (r,tau)
   where
     m = rows a
@@ -556,7 +675,7 @@
 schurAux f st a = unsafePerformIO $ do
     u <- createMatrix ColumnMajor n n
     s <- copy ColumnMajor a
-    f # u # s #| st
+    (u #! s) f #| st
     return (u,s)
   where
     n = rows a
@@ -576,7 +695,7 @@
 luAux f st a = unsafePerformIO $ do
     lu <- copy ColumnMajor a
     piv <- createVector (min n m)
-    f # piv # lu #| st
+    (piv #! lu) f #| st
     return (lu, map (pred.round) (toList piv))
   where
     n = rows a
@@ -598,7 +717,7 @@
 lusAux f st a piv b
     | n1==n2 && n2==n =unsafePerformIO $ do
          x <- copy ColumnMajor b
-         f # a # piv' # x #| st
+         (a # piv' #! x) f #| st
          return x
     | otherwise = error st
   where
@@ -622,7 +741,7 @@
 ldlAux f st a = unsafePerformIO $ do
     ldl <- copy ColumnMajor a
     piv <- createVector (rows a)
-    f # piv # ldl #| st
+    (piv #! ldl) f #| st
     return (ldl, map (pred.round) (toList piv))
 
 -----------------------------------------------------------------------------------
@@ -637,4 +756,3 @@
 -- | Solve a complex linear system from a precomputed LDL decomposition ('ldlC'), using LAPACK's /zsytrs/.
 ldlsC :: Matrix (Complex Double) -> [Int] -> Matrix (Complex Double) -> Matrix (Complex Double)
 ldlsC a piv b = lusAux zsytrs "ldlsC" (fmat a) piv b
-
diff --git a/src/Internal/Matrix.hs b/src/Internal/Matrix.hs
--- a/src/Internal/Matrix.hs
+++ b/src/Internal/Matrix.hs
@@ -5,10 +5,9 @@
 {-# LANGUAGE TypeOperators            #-}
 {-# LANGUAGE TypeFamilies             #-}
 {-# LANGUAGE ViewPatterns             #-}
+{-# LANGUAGE DeriveGeneric            #-}
 {-# LANGUAGE ConstrainedClassMethods  #-}
 
-
-
 -- |
 -- Module      :  Internal.Matrix
 -- Copyright   :  (c) Alberto Ruiz 2007-15
@@ -23,7 +22,7 @@
 
 import Internal.Vector
 import Internal.Devel
-import Internal.Vectorized hiding ((#))
+import Internal.Vectorized hiding ((#), (#!))
 import Foreign.Marshal.Alloc ( free )
 import Foreign.Marshal.Array(newArray)
 import Foreign.Ptr ( Ptr )
@@ -58,19 +57,24 @@
 cols = icols
 {-# INLINE cols #-}
 
+size :: Matrix t -> (Int, Int)
 size m = (irows m, icols m)
 {-# INLINE size #-}
 
+rowOrder :: Matrix t -> Bool
 rowOrder m = xCol m == 1 || cols m == 1
 {-# INLINE rowOrder #-}
 
+colOrder :: Matrix t -> Bool
 colOrder m = xRow m == 1 || rows m == 1
 {-# INLINE colOrder #-}
 
+is1d :: Matrix t -> Bool
 is1d (size->(r,c)) = r==1 || c==1
 {-# INLINE is1d #-}
 
 -- data is not contiguous
+isSlice :: Storable t => Matrix t -> Bool
 isSlice m@(size->(r,c)) = r*c < dim (xdat m)
 {-# INLINE isSlice #-}
 
@@ -111,15 +115,15 @@
 
 -- C-Haskell matrix adapters
 {-# INLINE amatr #-}
-amatr :: Storable a => (CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
-amatr f x = inlinePerformIO (unsafeWith (xdat x) (return . f r c))
+amatr :: Storable a => Matrix a -> (f -> IO r) -> (CInt -> CInt -> Ptr a -> f) -> IO r
+amatr x f g = unsafeWith (xdat x) (f . g r c)
   where
     r  = fi (rows x)
     c  = fi (cols x)
 
 {-# INLINE amat #-}
-amat :: Storable a => (CInt -> CInt -> CInt -> CInt -> Ptr a -> b) -> Matrix a -> b
-amat f x = inlinePerformIO (unsafeWith (xdat x) (return . f r c sr sc))
+amat :: Storable a => Matrix a -> (f -> IO r) -> (CInt -> CInt -> CInt -> CInt -> Ptr a -> f) -> IO r
+amat x f g = unsafeWith (xdat x) (f . g r c sr sc)
   where
     r  = fi (rows x)
     c  = fi (cols x)
@@ -136,20 +140,28 @@
     applyRaw = amatr
     {-# INLINE applyRaw #-}
 
-infixl 1 #
+infixr 1 #
+(#) :: TransArray c => c -> (b -> IO r) -> Trans c b -> IO r
 a # b = apply a b
 {-# INLINE (#) #-}
 
+(#!) :: (TransArray c, TransArray c1) => c1 -> c -> Trans c1 (Trans c (IO r)) -> IO r
+a #! b = a # b # id
+{-# INLINE (#!) #-}
+
 --------------------------------------------------------------------------------
 
+copy :: Element t => MatrixOrder -> Matrix t -> IO (Matrix t)
 copy ord m = extractR ord m 0 (idxs[0,rows m-1]) 0 (idxs[0,cols m-1])
 
+extractAll :: Element t => MatrixOrder -> Matrix t -> Matrix t
 extractAll ord m = unsafePerformIO (copy ord m)
 
 {- | Creates a vector by concatenation of rows. If the matrix is ColumnMajor, this operation requires a transpose.
 
 >>> flatten (ident 3)
-fromList [1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]
+[1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0]
+it :: (Num t, Element t) => Vector t
 
 -}
 flatten :: Element t => Matrix t -> Vector t
@@ -221,11 +233,13 @@
 {-# INLINE (@@>) #-}
 
 --  Unsafe matrix access without range checking
+atM' :: Storable t => Matrix t -> Int -> Int -> t
 atM' m i j = xdat m `at'` (i * (xRow m) + j * (xCol m))
 {-# INLINE atM' #-}
 
 ------------------------------------------------------------------
 
+matrixFromVector :: Storable t => MatrixOrder -> Int -> Int -> Vector t -> Matrix t
 matrixFromVector _ 1 _ v@(dim->d) = Matrix { irows = 1, icols = d, xdat = v, xRow = d, xCol = 1 }
 matrixFromVector _ _ 1 v@(dim->d) = Matrix { irows = d, icols = 1, xdat = v, xRow = 1, xCol = d }
 matrixFromVector o r c v
@@ -283,6 +297,7 @@
     remapM   :: Matrix CInt -> Matrix CInt -> Matrix a -> Matrix a
     rowOp    :: Int -> a -> Int -> Int -> Int -> Int -> Matrix a -> IO ()
     gemm     :: Vector a -> Matrix a -> Matrix a -> Matrix a -> IO ()
+    reorderV :: Vector CInt-> Vector CInt-> Vector a -> Vector a -- see reorderVector for documentation
 
 
 instance Element Float where
@@ -296,6 +311,7 @@
     remapM     = remapF
     rowOp      = rowOpAux c_rowOpF
     gemm       = gemmg c_gemmF
+    reorderV   = reorderAux c_reorderF
 
 instance Element Double where
     constantD  = constantAux cconstantR
@@ -308,6 +324,7 @@
     remapM     = remapD
     rowOp      = rowOpAux c_rowOpD
     gemm       = gemmg c_gemmD
+    reorderV   = reorderAux c_reorderD
 
 instance Element (Complex Float) where
     constantD  = constantAux cconstantQ
@@ -320,6 +337,7 @@
     remapM     = remapQ
     rowOp      = rowOpAux c_rowOpQ
     gemm       = gemmg c_gemmQ
+    reorderV   = reorderAux c_reorderQ
 
 instance Element (Complex Double) where
     constantD  = constantAux cconstantC
@@ -332,6 +350,7 @@
     remapM     = remapC
     rowOp      = rowOpAux c_rowOpC
     gemm       = gemmg c_gemmC
+    reorderV   = reorderAux c_reorderC
 
 instance Element (CInt) where
     constantD  = constantAux cconstantI
@@ -344,6 +363,7 @@
     remapM     = remapI
     rowOp      = rowOpAux c_rowOpI
     gemm       = gemmg c_gemmI
+    reorderV   = reorderAux c_reorderI
 
 instance Element Z where
     constantD  = constantAux cconstantL
@@ -356,6 +376,7 @@
     remapM     = remapL
     rowOp      = rowOpAux c_rowOpL
     gemm       = gemmg c_gemmL
+    reorderV   = reorderAux c_reorderL
 
 -------------------------------------------------------------------
 
@@ -378,18 +399,21 @@
 
 --------------------------------------------------------------------------
 
+maxZ :: (Num t1, Ord t1, Foldable t) => t t1 -> t1
 maxZ xs = if minimum xs == 0 then 0 else maximum xs
 
+conformMs :: Element t => [Matrix t] -> [Matrix t]
 conformMs ms = map (conformMTo (r,c)) ms
   where
     r = maxZ (map rows ms)
     c = maxZ (map cols ms)
 
-
+conformVs :: Element t => [Vector t] -> [Vector t]
 conformVs vs = map (conformVTo n) vs
   where
     n = maxZ (map dim vs)
 
+conformMTo :: Element t => (Int, Int) -> Matrix t -> Matrix t
 conformMTo (r,c) m
     | size m == (r,c) = m
     | size m == (1,1) = matrixFromVector RowMajor r c (constantD (m@@>(0,0)) (r*c))
@@ -397,18 +421,24 @@
     | size m == (1,c) = repRows r m
     | otherwise = error $ "matrix " ++ shSize m ++ " cannot be expanded to " ++ shDim (r,c)
 
+conformVTo :: Element t => Int -> Vector t -> Vector t
 conformVTo n v
     | dim v == n = v
     | dim v == 1 = constantD (v@>0) n
     | otherwise = error $ "vector of dim=" ++ show (dim v) ++ " cannot be expanded to dim=" ++ show n
 
+repRows :: Element t => Int -> Matrix t -> Matrix t
 repRows n x = fromRows (replicate n (flatten x))
+repCols :: Element t => Int -> Matrix t -> Matrix t
 repCols n x = fromColumns (replicate n (flatten x))
 
+shSize :: Matrix t -> [Char]
 shSize = shDim . size
 
+shDim :: (Show a, Show a1) => (a1, a) -> [Char]
 shDim (r,c) = "(" ++ show r ++"x"++ show c ++")"
 
+emptyM :: Storable t => Int -> Int -> Matrix t
 emptyM r c = matrixFromVector RowMajor r c (fromList[])
 
 ----------------------------------------------------------------------
@@ -423,11 +453,17 @@
 
 ---------------------------------------------------------------
 
+extractAux :: (Eq t3, Eq t2, TransArray c, Storable a, Storable t1,
+                Storable t, Num t3, Num t2, Integral t1, Integral t)
+           => (t3 -> t2 -> CInt -> Ptr t1 -> CInt -> Ptr t
+                  -> Trans c (CInt -> CInt -> CInt -> CInt -> Ptr a -> IO CInt))
+           -> MatrixOrder -> c -> t3 -> Vector t1 -> t2 -> Vector t -> IO (Matrix a)
 extractAux f ord m moder vr modec vc = do
     let nr = if moder == 0 then fromIntegral $ vr@>1 - vr@>0 + 1 else dim vr
         nc = if modec == 0 then fromIntegral $ vc@>1 - vc@>0 + 1 else dim vc
     r <- createMatrix ord nr nc
-    f moder modec # vr # vc # m # r  #|"extract"
+    (vr # vc # m #! r) (f moder modec)  #|"extract"
+
     return r
 
 type Extr x = CInt -> CInt -> CIdxs (CIdxs (OM x (OM x (IO CInt))))
@@ -441,7 +477,10 @@
 
 ---------------------------------------------------------------
 
-setRectAux f i j m r = f (fi i) (fi j) # m # r #|"setRect"
+setRectAux :: (TransArray c1, TransArray c)
+           => (CInt -> CInt -> Trans c1 (Trans c (IO CInt)))
+           -> Int -> Int -> c1 -> c -> IO ()
+setRectAux f i j m r = (m #! r) (f (fi i) (fi j)) #|"setRect"
 
 type SetRect x = I -> I -> x ::> x::> Ok
 
@@ -454,19 +493,29 @@
 
 --------------------------------------------------------------------------------
 
+sortG :: (Storable t, Storable a)
+      => (CInt -> Ptr t -> CInt -> Ptr a -> IO CInt) -> Vector t -> Vector a
 sortG f v = unsafePerformIO $ do
     r <- createVector (dim v)
-    f # v # r #|"sortG"
+    (v #! r) f #|"sortG"
     return r
 
+sortIdxD :: Vector Double -> Vector CInt
 sortIdxD = sortG c_sort_indexD
+sortIdxF :: Vector Float -> Vector CInt
 sortIdxF = sortG c_sort_indexF
+sortIdxI :: Vector CInt -> Vector CInt
 sortIdxI = sortG c_sort_indexI
+sortIdxL :: Vector Z -> Vector I
 sortIdxL = sortG c_sort_indexL
 
+sortValD :: Vector Double -> Vector Double
 sortValD = sortG c_sort_valD
+sortValF :: Vector Float -> Vector Float
 sortValF = sortG c_sort_valF
+sortValI :: Vector CInt -> Vector CInt
 sortValI = sortG c_sort_valI
+sortValL :: Vector Z -> Vector Z
 sortValL = sortG c_sort_valL
 
 foreign import ccall unsafe "sort_indexD" c_sort_indexD :: CV Double (CV CInt (IO CInt))
@@ -481,14 +530,21 @@
 
 --------------------------------------------------------------------------------
 
+compareG :: (TransArray c, Storable t, Storable a)
+         => Trans c (CInt -> Ptr t -> CInt -> Ptr a -> IO CInt)
+         -> c -> Vector t -> Vector a
 compareG f u v = unsafePerformIO $ do
     r <- createVector (dim v)
-    f # u # v # r #|"compareG"
+    (u # v #! r) f #|"compareG"
     return r
 
+compareD :: Vector Double -> Vector Double -> Vector CInt
 compareD = compareG c_compareD
+compareF :: Vector Float -> Vector Float -> Vector CInt
 compareF = compareG c_compareF
+compareI :: Vector CInt -> Vector CInt -> Vector CInt
 compareI = compareG c_compareI
+compareL :: Vector Z -> Vector Z -> Vector CInt
 compareL = compareG c_compareL
 
 foreign import ccall unsafe "compareD" c_compareD :: CV Double (CV Double (CV CInt (IO CInt)))
@@ -498,16 +554,33 @@
 
 --------------------------------------------------------------------------------
 
+selectG :: (TransArray c, TransArray c1, TransArray c2, Storable t, Storable a)
+        => Trans c2 (Trans c1 (CInt -> Ptr t -> Trans c (CInt -> Ptr a -> IO CInt)))
+        -> c2 -> c1 -> Vector t -> c -> Vector a
 selectG f c u v w = unsafePerformIO $ do
     r <- createVector (dim v)
-    f # c # u # v # w # r #|"selectG"
+    (c # u # v # w #! r) f #|"selectG"
     return r
 
+selectD :: Vector CInt -> Vector Double -> Vector Double -> Vector Double -> Vector Double
 selectD = selectG c_selectD
+selectF :: Vector CInt -> Vector Float -> Vector Float -> Vector Float -> Vector Float
 selectF = selectG c_selectF
+selectI :: Vector CInt -> Vector CInt -> Vector CInt -> Vector CInt -> Vector CInt
 selectI = selectG c_selectI
+selectL :: Vector CInt -> Vector Z -> Vector Z -> Vector Z -> Vector Z
 selectL = selectG c_selectL
+selectC :: Vector CInt
+        -> Vector (Complex Double)
+        -> Vector (Complex Double)
+        -> Vector (Complex Double)
+        -> Vector (Complex Double)
 selectC = selectG c_selectC
+selectQ :: Vector CInt
+        -> Vector (Complex Float)
+        -> Vector (Complex Float)
+        -> Vector (Complex Float)
+        -> Vector (Complex Float)
 selectQ = selectG c_selectQ
 
 type Sel x = CV CInt (CV x (CV x (CV x (CV x (IO CInt)))))
@@ -521,16 +594,29 @@
 
 ---------------------------------------------------------------------------
 
+remapG :: (TransArray c, TransArray c1, Storable t, Storable a)
+       => (CInt -> CInt -> CInt -> CInt -> Ptr t
+                -> Trans c1 (Trans c (CInt -> CInt -> CInt -> CInt -> Ptr a -> IO CInt)))
+       -> Matrix t -> c1 -> c -> Matrix a
 remapG f i j m = unsafePerformIO $ do
     r <- createMatrix RowMajor (rows i) (cols i)
-    f # i # j # m # r #|"remapG"
+    (i # j # m #! r) f #|"remapG"
     return r
 
+remapD :: Matrix CInt -> Matrix CInt -> Matrix Double -> Matrix Double
 remapD = remapG c_remapD
+remapF :: Matrix CInt -> Matrix CInt -> Matrix Float -> Matrix Float
 remapF = remapG c_remapF
+remapI :: Matrix CInt -> Matrix CInt -> Matrix CInt -> Matrix CInt
 remapI = remapG c_remapI
+remapL :: Matrix CInt -> Matrix CInt -> Matrix Z -> Matrix Z
 remapL = remapG c_remapL
+remapC :: Matrix CInt
+       -> Matrix CInt
+       -> Matrix (Complex Double)
+       -> Matrix (Complex Double)
 remapC = remapG c_remapC
+remapQ :: Matrix CInt -> Matrix CInt -> Matrix (Complex Float) -> Matrix (Complex Float)
 remapQ = remapG c_remapQ
 
 type Rem x = OM CInt (OM CInt (OM x (OM x (IO CInt))))
@@ -544,9 +630,12 @@
 
 --------------------------------------------------------------------------------
 
+rowOpAux :: (TransArray c, Storable a) =>
+            (CInt -> Ptr a -> CInt -> CInt -> CInt -> CInt -> Trans c (IO CInt))
+         -> Int -> a -> Int -> Int -> Int -> Int -> c -> IO ()
 rowOpAux f c x i1 i2 j1 j2 m = do
     px <- newArray [x]
-    f (fi c) px (fi i1) (fi i2) (fi j1) (fi j2) # m #|"rowOp"
+    (m # id) (f (fi c) px (fi i1) (fi i2) (fi j1) (fi j2)) #|"rowOp"
     free px
 
 type RowOp x = CInt -> Ptr x -> CInt -> CInt -> CInt -> CInt -> x ::> Ok
@@ -562,7 +651,10 @@
 
 --------------------------------------------------------------------------------
 
-gemmg f v m1 m2 m3 = f # v # m1 # m2 # m3 #|"gemmg"
+gemmg :: (TransArray c1, TransArray c, TransArray c2, TransArray c3)
+      => Trans c3 (Trans c2 (Trans c1 (Trans c (IO CInt))))
+      -> c3 -> c2 -> c1 -> c -> IO ()
+gemmg f v m1 m2 m3 = (v # m1 # m2 #! m3) f #|"gemmg"
 
 type Tgemm x = x :> x ::> x ::> x ::> Ok
 
@@ -577,6 +669,37 @@
 
 --------------------------------------------------------------------------------
 
+reorderAux :: (TransArray c, Storable t, Storable a1, Storable t1, Storable a) =>
+              (CInt -> Ptr a -> CInt -> Ptr t1
+                    -> Trans c (CInt -> Ptr t -> CInt -> Ptr a1 -> IO CInt))
+           -> Vector t1 -> c -> Vector t -> Vector a1
+reorderAux f s d v = unsafePerformIO $ do
+    k <- createVector (dim s)
+    r <- createVector (dim v)
+    (k # s # d # v #! r) f #| "reorderV"
+    return r
+
+type Reorder x = CV CInt (CV CInt (CV CInt (CV x (CV x (IO CInt)))))
+
+foreign import ccall unsafe "reorderD" c_reorderD :: Reorder Double
+foreign import ccall unsafe "reorderF" c_reorderF :: Reorder Float
+foreign import ccall unsafe "reorderI" c_reorderI :: Reorder CInt
+foreign import ccall unsafe "reorderC" c_reorderC :: Reorder (Complex Double)
+foreign import ccall unsafe "reorderQ" c_reorderQ :: Reorder (Complex Float)
+foreign import ccall unsafe "reorderL" c_reorderL :: Reorder Z
+
+-- | Transpose an array with dimensions @dims@ by making a copy using @strides@. For example, for an array with 3 indices,
+--   @(reorderVector strides dims v) ! ((i * dims ! 1 + j) * dims ! 2 + k) == v ! (i * strides ! 0 + j * strides ! 1 + k * strides ! 2)@
+--   This function is intended to be used internally by tensor libraries.
+reorderVector :: Element a
+                    => Vector CInt -- ^ @strides@: array strides
+                    -> Vector CInt -- ^ @dims@: array dimensions of new array @v@
+                    -> Vector a    -- ^ @v@: flattened input array
+                    -> Vector a    -- ^ @v'@: flattened output array
+reorderVector = reorderV
+
+--------------------------------------------------------------------------------
+
 foreign import ccall unsafe "saveMatrix" c_saveMatrix
     :: CString -> CString -> Double ::> Ok
 
@@ -590,10 +713,9 @@
 saveMatrix name format m = do
     cname   <- newCString name
     cformat <- newCString format
-    c_saveMatrix cname cformat # m #|"saveMatrix"
+    (m # id) (c_saveMatrix cname cformat) #|"saveMatrix"
     free cname
     free cformat
     return ()
 
 --------------------------------------------------------------------------------
-
diff --git a/src/Internal/Modular.hs b/src/Internal/Modular.hs
--- a/src/Internal/Modular.hs
+++ b/src/Internal/Modular.hs
@@ -1,17 +1,15 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
-{-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE Rank2Types #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE UndecidableInstances #-}
-{-# LANGUAGE GADTs #-}
 {-# LANGUAGE TypeFamilies  #-}
 {-# LANGUAGE TypeOperators #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 {- |
 Module      :  Internal.Modular
 Copyright   :  (c) Alberto Ruiz 2015
@@ -38,13 +36,20 @@
                      gaussElim, gaussElim_1, gaussElim_2,
                      luST, luSolve', luPacked', magnit, invershur)
 import Internal.ST(mutable)
+#if MIN_VERSION_base(4,11,0)
+import GHC.TypeLits hiding (Mod)
+#else
 import GHC.TypeLits
+#endif
 import Data.Proxy(Proxy)
 import Foreign.ForeignPtr(castForeignPtr)
 import Foreign.Storable
 import Data.Ratio
 import Data.Complex
 import Control.DeepSeq ( NFData(..) )
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 
 
@@ -72,11 +77,11 @@
   where
     compare a b = compare (unMod a) (unMod b)
 
-instance (Integral t, KnownNat m, Integral (Mod m t)) => Real (Mod m t)
+instance (Integral t, Real t, KnownNat m) => Real (Mod m t)
   where
     toRational x = toInteger x % 1
 
-instance (Integral t, KnownNat m, Num (Mod m t)) => Integral (Mod m t)
+instance (Integral t, KnownNat m) => Integral (Mod m t)
   where
     toInteger = toInteger . unMod
     quotRem a b = (Mod q, Mod r)
@@ -84,7 +89,7 @@
          (q,r) = quotRem (unMod a) (unMod b)
 
 -- | this instance is only valid for prime m
-instance (Show (Mod m t), Num (Mod m t), Eq t, KnownNat m) => Fractional (Mod m t)
+instance (Integral t, Show t, Eq t, KnownNat m) => Fractional (Mod m t)
   where
     recip x
         | x*r == 1  = r
@@ -114,7 +119,7 @@
   where
     show = show . unMod
 
-instance forall n t . (Integral t, KnownNat n) => Num (Mod n t)
+instance (Integral t, KnownNat n) => Num (Mod n t)
   where
     (+) = l2 (\m a b -> (a + b) `mod` (fromIntegral m))
     (*) = l2 (\m a b -> (a * b) `mod` (fromIntegral m))
@@ -140,6 +145,7 @@
     gemm u a b c = gemmg (c_gemmMI m') (f2i u) (f2iM a) (f2iM b) (f2iM c)
       where
         m' = fromIntegral . natVal $ (undefined :: Proxy m)
+    reorderV strides dims = i2f . reorderAux c_reorderI strides dims . f2i
 
 instance KnownNat m => Element (Mod m Z)
   where
@@ -157,13 +163,14 @@
     gemm u a b c = gemmg (c_gemmML m') (f2i u) (f2iM a) (f2iM b) (f2iM c)
       where
         m' = fromIntegral . natVal $ (undefined :: Proxy m)
+    reorderV strides dims = i2f . reorderAux c_reorderL strides dims . f2i
 
 
-instance forall m . KnownNat m => CTrans (Mod m I)
-instance forall m . KnownNat m => CTrans (Mod m Z)
+instance KnownNat m => CTrans (Mod m I)
+instance KnownNat m => CTrans (Mod m Z)
 
 
-instance forall m . KnownNat m => Container Vector (Mod m I)
+instance KnownNat m => Container Vector (Mod m I)
   where
     conj' = id
     size' = dim
@@ -203,7 +210,7 @@
     fromZ'   = vmod . fromZ'
     toZ'     = toZ' . f2i
 
-instance forall m . KnownNat m => Container Vector (Mod m Z)
+instance KnownNat m => Container Vector (Mod m Z)
   where
     conj' = id
     size' = dim
@@ -311,7 +318,7 @@
 
 lift2m f a b = liftMatrix vmod (f (f2iM a) (f2iM b))
 
-instance forall m . KnownNat m => Num (Vector (Mod m I))
+instance KnownNat m => Num (Vector (Mod m I))
   where
     (+) = lift2 (+)
     (*) = lift2 (*)
@@ -321,7 +328,7 @@
     negate = lift1 negate
     fromInteger x = fromInt (fromInteger x)
 
-instance forall m . KnownNat m => Num (Vector (Mod m Z))
+instance KnownNat m => Num (Vector (Mod m Z))
   where
     (+) = lift2 (+)
     (*) = lift2 (*)
diff --git a/src/Internal/Numeric.hs b/src/Internal/Numeric.hs
--- a/src/Internal/Numeric.hs
+++ b/src/Internal/Numeric.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
@@ -6,6 +5,8 @@
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE UndecidableInstances #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Data.Packed.Internal.Numeric
@@ -26,6 +27,7 @@
 import Internal.Vectorized
 import Internal.LAPACK(multiplyR,multiplyC,multiplyF,multiplyQ,multiplyI,multiplyL)
 import Data.List.Split(chunksOf)
+import qualified Data.Vector.Storable as V
 
 --------------------------------------------------------------------------------
 
@@ -103,8 +105,8 @@
     add' = vectorZipI Add
     sub = vectorZipI Sub
     mul = vectorZipI Mul
-    equal u v = dim u == dim v && maxElement' (vectorMapI Abs (sub u v)) == 0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -142,8 +144,8 @@
     add' = vectorZipL Add
     sub = vectorZipL Sub
     mul = vectorZipL Mul
-    equal u v = dim u == dim v && maxElement' (vectorMapL Abs (sub u v)) == 0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -182,8 +184,8 @@
     add' = vectorZipF Add
     sub = vectorZipF Sub
     mul = vectorZipF Mul
-    equal u v = dim u == dim v && maxElement (vectorMapF Abs (sub u v)) == 0.0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -219,8 +221,8 @@
     add' = vectorZipR Add
     sub = vectorZipR Sub
     mul = vectorZipR Mul
-    equal u v = dim u == dim v && maxElement (vectorMapR Abs (sub u v)) == 0.0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -256,8 +258,8 @@
     add' = vectorZipC Add
     sub = vectorZipC Sub
     mul = vectorZipC Mul
-    equal u v = dim u == dim v && maxElement (mapVector magnitude (sub u v)) == 0.0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -292,8 +294,8 @@
     add' = vectorZipQ Add
     sub = vectorZipQ Sub
     mul = vectorZipQ Mul
-    equal u v = dim u == dim v && maxElement (mapVector magnitude (sub u v)) == 0.0
-    scalar' x = fromList [x]
+    equal = (==)
+    scalar' = V.singleton
     konst' = constantD
     build' = buildV
     cmap' = mapVector
@@ -788,13 +790,7 @@
 type instance RealOf I = I
 type instance RealOf Z = Z
 
-type family ComplexOf x
-
-type instance ComplexOf Double = Complex Double
-type instance ComplexOf (Complex Double) = Complex Double
-
-type instance ComplexOf Float = Complex Float
-type instance ComplexOf (Complex Float) = Complex Float
+type ComplexOf x = Complex (RealOf x)
 
 type family SingleOf x
 
diff --git a/src/Internal/Random.hs b/src/Internal/Random.hs
--- a/src/Internal/Random.hs
+++ b/src/Internal/Random.hs
@@ -31,13 +31,13 @@
 gaussianSample :: Seed
                -> Int -- ^ number of rows
                -> Vector Double -- ^ mean vector
-               -> Matrix Double -- ^ covariance matrix
+               -> Herm Double   -- ^ covariance matrix
                -> Matrix Double -- ^ result
 gaussianSample seed n med cov = m where
     c = dim med
     meds = konst' 1 n `outer` med
     rs = reshape c $ randomVector seed Gaussian (c * n)
-    m = rs `mXm` cholSH cov `add` meds
+    m = rs `mXm` chol cov `add` meds
 
 -- | Obtains a matrix whose rows are pseudorandom samples from a multivariate
 -- uniform distribution.
diff --git a/src/Internal/ST.hs b/src/Internal/ST.hs
--- a/src/Internal/ST.hs
+++ b/src/Internal/ST.hs
@@ -81,6 +81,8 @@
 unsafeFreezeVector (STVector x) = unsafeIOToST . return $ x
 
 {-# INLINE safeIndexV #-}
+safeIndexV :: Storable t2
+           => (STVector s t2 -> Int -> t) -> STVector t1 t2 -> Int -> t
 safeIndexV f (STVector v) k
     | k < 0 || k>= dim v = error $ "out of range error in vector (dim="
                                    ++show (dim v)++", pos="++show k++")"
@@ -150,9 +152,12 @@
 freezeMatrix :: (Element t) => STMatrix s t -> ST s (Matrix t)
 freezeMatrix m = liftSTMatrix id m
 
+cloneMatrix :: Element t => Matrix t -> IO (Matrix t)
 cloneMatrix m = copy (orderOf m) m
 
 {-# INLINE safeIndexM #-}
+safeIndexM :: (STMatrix s t2 -> Int -> Int -> t)
+           -> STMatrix t1 t2 -> Int -> Int -> t
 safeIndexM f (STMatrix m) r c
     | r<0 || r>=rows m ||
       c<0 || c>=cols m = error $ "out of range error in matrix (size="
@@ -184,6 +189,7 @@
               | Col Int
               | FromCol Int
 
+getColRange :: Int -> ColRange -> (Int, Int)
 getColRange c AllCols = (0,c-1)
 getColRange c (ColRange a b) = (a `mod` c, b `mod` c)
 getColRange c (Col a) = (a `mod` c, a `mod` c)
@@ -194,6 +200,7 @@
               | Row Int
               | FromRow Int
 
+getRowRange :: Int -> RowRange -> (Int, Int)
 getRowRange r AllRows = (0,r-1)
 getRowRange r (RowRange a b) = (a `mod` r, b `mod` r)
 getRowRange r (Row a) = (a `mod` r, a `mod` r)
@@ -223,6 +230,7 @@
     i2' = i2 `mod` (rows m)
 
 
+extractMatrix :: Element a => STMatrix t a -> RowRange -> ColRange -> ST s (Matrix a)
 extractMatrix (STMatrix m) rr rc = unsafeIOToST (extractR (orderOf m) m 0 (idxs[i1,i2]) 0 (idxs[j1,j2]))
   where
     (i1,i2) = getRowRange (rows m) rr
@@ -231,6 +239,7 @@
 -- | r0 c0 height width
 data Slice s t = Slice (STMatrix s t) Int Int Int Int
 
+slice :: Element a => Slice t a -> Matrix a
 slice (Slice (STMatrix m) r0 c0 nr nc) = subMatrix (r0,c0) (nr,nc) m
 
 gemmm :: Element t => t -> Slice s t -> t -> Slice s t -> Slice s t -> ST s ()
@@ -238,12 +247,11 @@
   where
     res = unsafeIOToST (gemm v a b r)
     v = fromList [alpha,beta]
-    
 
+
 mutable :: Element t => (forall s . (Int, Int) -> STMatrix s t -> ST s u) -> Matrix t -> (Matrix t,u)
 mutable f a = runST $ do
    x <- thawMatrix a
    info <- f (rows a, cols a) x
    r <- unsafeFreezeMatrix x
    return (r,info)
-
diff --git a/src/Internal/Sparse.hs b/src/Internal/Sparse.hs
--- a/src/Internal/Sparse.hs
+++ b/src/Internal/Sparse.hs
@@ -1,9 +1,11 @@
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE RecordWildCards #-}
 
 module Internal.Sparse(
-    GMatrix(..), CSR(..), mkCSR, fromCSR,
+    GMatrix(..), CSR(..), mkCSR, fromCSR, impureCSR,
     mkSparse, mkDiagR, mkDense,
     AssocMatrix,
     toDense,
@@ -14,10 +16,12 @@
 import Internal.Matrix
 import Internal.Numeric
 import qualified Data.Vector.Storable as V
-import Data.Function(on)
+import qualified Data.Vector.Storable.Mutable as M
 import Control.Arrow((***))
-import Control.Monad(when)
-import Data.List(groupBy, sort)
+import Control.Monad(when, foldM)
+import Control.Monad.ST (runST)
+import Control.Monad.Primitive (PrimMonad)
+import Data.List(sort)
 import Foreign.C.Types(CInt(..))
 
 import Internal.Devel
@@ -25,10 +29,7 @@
 import Foreign(Ptr)
 import Text.Printf(printf)
 
-infixl 0 ~!~
-c ~!~ msg = when c (error msg)
-
-type AssocMatrix = [((Int,Int),Double)]
+type AssocMatrix = [(IndexOf Matrix, Double)]
 
 data CSR = CSR
         { csrVals  :: Vector Double
@@ -47,23 +48,79 @@
         } deriving Show
 
 
+-- | Produce a CSR sparse matrix from a association matrix.
 mkCSR :: AssocMatrix -> CSR
-mkCSR sm' = CSR{..}
+mkCSR ms =
+  runST $ impureCSR runFold $ sort ms
+    where
+  runFold next initialise xtract as0 = do
+    i0  <- initialise
+    acc <- foldM next i0 as0
+    xtract acc
+
+-- | Produce a CSR sparse matrix by applying a generic folding function.
+--
+--   This allows one to build a CSR from an effectful streaming source
+--   when combined with libraries like pipes, io-streams, or streaming.
+--
+--   For example
+--
+--   > impureCSR Pipes.Prelude.foldM :: PrimMonad m => Producer AssocEntry m () -> m CSR
+--   > impureCSR Streaming.Prelude.foldM :: PrimMonad m => Stream (Of AssocEntry) m r -> m (Of CSR r)
+--
+impureCSR
+    :: PrimMonad m
+    => (forall x . (x -> (IndexOf Matrix, Double) -> m x) -> m x -> (x -> m CSR) -> r)
+    -> r
+impureCSR f = f next begin done
   where
-    sm = sort sm'
-    rws = map ((fromList *** fromList)
-              . unzip
-              . map ((succ.fi.snd) *** id)
-              )
-        . groupBy ((==) `on` (fst.fst))
-        $ sm
-    rszs = map (fi . dim . fst) rws
-    csrRows = fromList (scanl (+) 1 rszs)
-    csrVals = vjoin (map snd rws)
-    csrCols = vjoin (map fst rws)
-    csrNRows = dim csrRows - 1
-    csrNCols = fromIntegral (V.maximum csrCols)
+    sfi = succ . fi
+    begin = do
+      mv <- M.unsafeNew 64
+      mr <- M.unsafeNew 64
+      mc <- M.unsafeNew 64
+      return (mv, mr, mc, 0, 0, 0, -1)
 
+    next (!mv, !mr, !mc, !idxVC, !idxR, !maxC, !curRow) ((r,c),d) = do
+      when (r < curRow) $
+        error (printf "impureCSR: row %i specified after %i" r curRow)
+
+      let lenVC = M.length mv
+          lenR  = M.length mr
+          maxC' = max maxC c
+
+      (mv', mc') <-
+        if idxVC >= lenVC then do
+          mv' <- M.unsafeGrow mv lenVC
+          mc' <- M.unsafeGrow mc lenVC
+          return (mv', mc')
+        else
+          return (mv, mc)
+
+      mr' <-
+        if idxR >= lenR - 1 then
+          M.unsafeGrow mr lenR
+        else
+          return mr
+
+      M.unsafeWrite mc' idxVC (sfi c)
+      M.unsafeWrite mv' idxVC d
+
+      idxR' <-
+        foldM
+          (\idxR' _ -> idxR' + 1 <$ M.unsafeWrite mr' idxR' (sfi idxVC))
+          idxR [1 .. (r-curRow)]
+
+      return (mv', mr', mc', idxVC + 1, idxR', maxC', r)
+
+    done (!mv, !mr, !mc, !idxVC, !idxR, !maxC, !curR) = do
+      M.unsafeWrite mr idxR (sfi idxVC)
+      vv <- V.unsafeFreeze (M.unsafeTake idxVC mv)
+      vc <- V.unsafeFreeze (M.unsafeTake idxVC mc)
+      vr <- V.unsafeFreeze (M.unsafeTake (idxR + 1)  mr)
+      return $ CSR vv vc vr (succ curR) (succ maxC)
+
+
 {- | General matrix with specialized internal representations for
      dense, sparse, diagonal, banded, and constant elements.
 
@@ -122,11 +179,12 @@
 fromCSR :: CSR -> GMatrix
 fromCSR csr = SparseR {..}
   where
-    gmCSR @ CSR {..} = csr
+    gmCSR@CSR {..} = csr
     nRows = csrNRows
     nCols = csrNCols
 
 
+mkDiagR :: Int -> Int -> Vector Double -> GMatrix
 mkDiagR r c v
     | dim v <= min r c = Diag{..}
     | otherwise = error $ printf "mkDiagR: incorrect sizes (%d,%d) [%d]" r c (dim v)
@@ -142,15 +200,19 @@
 
 gmXv :: GMatrix -> Vector Double -> Vector Double
 gmXv SparseR { gmCSR = CSR{..}, .. } v = unsafePerformIO $ do
-    dim v /= nCols ~!~ printf "gmXv (CSR): incorrect sizes: (%d,%d) x %d" nRows nCols (dim v)
+    when (dim v /= nCols) $
+      error (printf "gmXv (CSR): incorrect sizes: (%d,%d) x %d" nRows nCols (dim v))
+
     r <- createVector nRows
-    c_smXv # csrVals # csrCols # csrRows # v # r #|"CSRXv"
+    (csrVals # csrCols # csrRows # v #! r) c_smXv #|"CSRXv"
     return r
 
 gmXv SparseC { gmCSC = CSC{..}, .. } v = unsafePerformIO $ do
-    dim v /= nCols ~!~ printf "gmXv (CSC): incorrect sizes: (%d,%d) x %d" nRows nCols (dim v)
+    when (dim v /= nCols) $
+      error (printf "gmXv (CSC): incorrect sizes: (%d,%d) x %d" nRows nCols (dim v))
+
     r <- createVector nRows
-    c_smTXv # cscVals # cscRows # cscCols # v # r #|"CSCXv"
+    (cscVals # cscRows # cscCols # v #! r) c_smTXv #|"CSCXv"
     return r
 
 gmXv Diag{..} v
@@ -170,8 +232,10 @@
 {- | general matrix - vector product
 
 >>> let m = mkSparse [((0,999),1.0),((1,1999),2.0)]
+m :: GMatrix
 >>> m !#> vector [1..2000]
-fromList [1000.0,4000.0]
+[1000.0,4000.0]
+it :: Vector Double
 
 -}
 infixr 8 !#>
@@ -211,4 +275,3 @@
     tr (Diag v n m) = Diag v m n
     tr (Dense a n m) = Dense (tr a) m n
     tr' = tr
-
diff --git a/src/Internal/Static.hs b/src/Internal/Static.hs
--- a/src/Internal/Static.hs
+++ b/src/Internal/Static.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 #if __GLASGOW_HASKELL__ >= 708
 
 {-# LANGUAGE DataKinds #-}
@@ -11,7 +12,11 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE DeriveGeneric #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 {- |
 Module      :  Internal.Static
 Copyright   :  (c) Alberto Ruiz 2006-14
@@ -28,18 +33,35 @@
 import Numeric.LinearAlgebra hiding (konst,size,R,C)
 import Internal.Vector as D hiding (R,C)
 import Internal.ST
+import Control.DeepSeq
 import Data.Proxy(Proxy)
 import Foreign.Storable(Storable)
 import Text.Printf
 
+import Data.Binary
+import GHC.Generics (Generic)
+import Data.Proxy (Proxy(..))
+
 --------------------------------------------------------------------------------
 
 type ℝ = Double
 type ℂ = Complex Double
 
 newtype Dim (n :: Nat) t = Dim t
-  deriving Show
+  deriving (Show, Generic)
 
+instance (KnownNat n, Binary a) => Binary (Dim n a) where
+  get = do
+    k <- get
+    let n = natVal (Proxy :: Proxy n)
+    if n == k
+      then Dim <$> get
+      else fail ("Expected dimension " ++ (show n) ++ ", but found dimension " ++ (show k))
+
+  put (Dim x) = do
+    put (natVal (Proxy :: Proxy n))
+    put x
+
 lift1F
   :: (c t -> c t)
   -> Dim n (c t) -> Dim n (c t)
@@ -50,18 +72,22 @@
   -> Dim n (c t) -> Dim n (c t) -> Dim n (c t)
 lift2F f (Dim u) (Dim v) = Dim (f u v)
 
+instance NFData t => NFData (Dim n t) where
+    rnf (Dim (force -> !_)) = ()
+
 --------------------------------------------------------------------------------
 
 newtype R n = R (Dim n (Vector ℝ))
-  deriving (Num,Fractional,Floating)
+  deriving (Num,Fractional,Floating,Generic,Binary)
 
 newtype C n = C (Dim n (Vector ℂ))
-  deriving (Num,Fractional,Floating)
+  deriving (Num,Fractional,Floating,Generic)
 
 newtype L m n = L (Dim m (Dim n (Matrix ℝ)))
-
-newtype M m n = M (Dim m (Dim n (Matrix  ℂ)))
+  deriving (Generic, Binary)
 
+newtype M m n = M (Dim m (Dim n (Matrix ℂ)))
+  deriving (Generic)
 
 mkR :: Vector ℝ -> R n
 mkR = R . Dim
@@ -75,6 +101,18 @@
 mkM :: Matrix ℂ -> M m n
 mkM x = M (Dim (Dim x))
 
+instance NFData (R n) where
+    rnf (R (force -> !_)) = ()
+
+instance NFData (C n) where
+    rnf (C (force -> !_)) = ()
+
+instance NFData (L n m) where
+    rnf (L (force -> !_)) = ()
+
+instance NFData (M n m) where
+    rnf (M (force -> !_)) = ()
+
 --------------------------------------------------------------------------------
 
 type V n t = Dim n (Vector t)
@@ -92,9 +130,9 @@
   where
     du = fromIntegral . natVal $ (undefined :: Proxy n)
     dv = fromIntegral . natVal $ (undefined :: Proxy m)
-    u' | du > 1 && LA.size u == 1 = LA.konst (u D.@> 0) du
+    u' | du /= 1 && LA.size u == 1 = LA.konst (u D.@> 0) du
        | otherwise = u
-    v' | dv > 1 && LA.size v == 1 = LA.konst (v D.@> 0) dv
+    v' | dv /= 1 && LA.size v == 1 = LA.konst (v D.@> 0) dv
        | otherwise = v
 
 
@@ -173,7 +211,7 @@
 singleM m = rows m == 1 && cols m == 1
 
 
-instance forall n. KnownNat n => Sized ℂ (C n) Vector
+instance KnownNat n => Sized ℂ (C n) Vector
   where
     size _ = fromIntegral . natVal $ (undefined :: Proxy n)
     konst x = mkC (LA.scalar x)
@@ -189,7 +227,7 @@
         r = mkC v :: C n
 
 
-instance forall n. KnownNat n => Sized ℝ (R n) Vector
+instance KnownNat n => Sized ℝ (R n) Vector
   where
     size _ = fromIntegral . natVal $ (undefined :: Proxy n)
     konst x = mkR (LA.scalar x)
@@ -206,7 +244,7 @@
 
 
 
-instance forall m n . (KnownNat m, KnownNat n) => Sized ℝ (L m n) Matrix
+instance (KnownNat m, KnownNat n) => Sized ℝ (L m n) Matrix
   where
     size _ = ((fromIntegral . natVal) (undefined :: Proxy m)
              ,(fromIntegral . natVal) (undefined :: Proxy n))
@@ -224,7 +262,7 @@
         r = mkL x :: L m n
 
 
-instance forall m n . (KnownNat m, KnownNat n) => Sized ℂ (M m n) Matrix
+instance (KnownNat m, KnownNat n) => Sized ℂ (M m n) Matrix
   where
     size _ = ((fromIntegral . natVal) (undefined :: Proxy m)
              ,(fromIntegral . natVal) (undefined :: Proxy n))
@@ -282,43 +320,43 @@
 
 --------------------------------------------------------------------------------
 
-instance forall n . KnownNat n => Show (R n)
+instance KnownNat n => Show (R n)
   where
     show s@(R (Dim v))
-      | singleV v = "("++show (v!0)++" :: R "++show d++")"
-      | otherwise   = "(vector"++ drop 8 (show v)++" :: R "++show d++")"
+      | singleV v = "(" ++ show (v!0) ++ " :: R " ++ show d ++ ")"
+      | otherwise = "(vector " ++ show v ++ " :: R " ++ show d ++")"
       where
         d = size s
 
-instance forall n . KnownNat n => Show (C n)
+instance KnownNat n => Show (C n)
   where
     show s@(C (Dim v))
-      | singleV v = "("++show (v!0)++" :: C "++show d++")"
-      | otherwise   = "(vector"++ drop 8 (show v)++" :: C "++show d++")"
+      | singleV v = "(" ++ show (v!0) ++ " :: C " ++ show d ++ ")"
+      | otherwise = "(vector " ++ show v ++ " :: C " ++ show d ++")"
       where
         d = size s
 
-instance forall m n . (KnownNat m, KnownNat n) => Show (L m n)
+instance (KnownNat m, KnownNat n) => Show (L m n)
   where
-    show (isDiag -> Just (z,y,(m',n'))) = printf "(diag %s %s :: L %d %d)" (show z) (drop 9 $ show y) m' n'
+    show (isDiag -> Just (z,y,(m',n'))) = printf "(diag %s %s :: L %d %d)" (show z) (show y) m' n'
     show s@(L (Dim (Dim x)))
        | singleM x = printf "(%s :: L %d %d)" (show (x `atIndex` (0,0))) m' n'
-       | otherwise = "(matrix"++ dropWhile (/='\n') (show x)++" :: L "++show m'++" "++show n'++")"
+       | otherwise = "(matrix" ++ dropWhile (/='\n') (show x) ++ " :: L " ++ show m' ++ " " ++ show n' ++ ")"
       where
         (m',n') = size s
 
-instance forall m n . (KnownNat m, KnownNat n) => Show (M m n)
+instance (KnownNat m, KnownNat n) => Show (M m n)
   where
-    show (isDiagC -> Just (z,y,(m',n'))) = printf "(diag %s %s :: M %d %d)" (show z) (drop 9 $ show y) m' n'
+    show (isDiagC -> Just (z,y,(m',n'))) = printf "(diag %s %s :: M %d %d)" (show z) (show y) m' n'
     show s@(M (Dim (Dim x)))
        | singleM x = printf "(%s :: M %d %d)" (show (x `atIndex` (0,0))) m' n'
-       | otherwise = "(matrix"++ dropWhile (/='\n') (show x)++" :: M "++show m'++" "++show n'++")"
+       | otherwise = "(matrix" ++ dropWhile (/='\n') (show x) ++ " :: M " ++ show m' ++ " " ++ show n' ++ ")"
       where
         (m',n') = size s
 
 --------------------------------------------------------------------------------
 
-instance forall n t . (Num (Vector t), Numeric t )=> Num (Dim n (Vector t))
+instance (Num (Vector t), Numeric t )=> Num (Dim n (Vector t))
   where
     (+) = lift2F (+)
     (*) = lift2F (*)
@@ -328,7 +366,7 @@
     negate = lift1F negate
     fromInteger x = Dim (fromInteger x)
 
-instance (Num (Vector t), Num (Matrix t), Fractional t, Numeric t) => Fractional (Dim n (Vector t))
+instance (Num (Vector t), Fractional t, Numeric t) => Fractional (Dim n (Vector t))
   where
     fromRational x = Dim (fromRational x)
     (/) = lift2F (/)
@@ -353,7 +391,7 @@
     pi    = Dim pi
 
 
-instance (Num (Matrix t), Numeric t) => Num (Dim m (Dim n (Matrix t)))
+instance (Num (Vector t), Numeric t) => Num (Dim m (Dim n (Matrix t)))
   where
     (+) = (lift2F . lift2F) (+)
     (*) = (lift2F . lift2F) (*)
@@ -363,12 +401,12 @@
     negate = (lift1F . lift1F) negate
     fromInteger x = Dim (Dim (fromInteger x))
 
-instance (Num (Vector t), Num (Matrix t), Fractional t, Numeric t) => Fractional (Dim m (Dim n (Matrix t)))
+instance (Num (Vector t), Fractional t, Numeric t) => Fractional (Dim m (Dim n (Matrix t)))
   where
     fromRational x = Dim (Dim (fromRational x))
     (/) = (lift2F.lift2F) (/)
 
-instance (Num (Vector t), Floating (Matrix t), Fractional t, Numeric t) => Floating (Dim m (Dim n (Matrix t))) where
+instance (Floating (Vector t), Floating t, Numeric t) => Floating (Dim m (Dim n (Matrix t))) where
     sin   = (lift1F . lift1F) sin
     cos   = (lift1F . lift1F) cos
     tan   = (lift1F . lift1F) tan
@@ -482,6 +520,18 @@
     (**)  = lift2MD (**)
     pi    = M pi
 
+instance Additive (R n) where
+    add = (+)
+
+instance Additive (C n) where
+    add = (+)
+
+instance (KnownNat m, KnownNat n) => Additive (L m n) where
+    add = (+)
+
+instance (KnownNat m, KnownNat n) => Additive (M m n) where
+    add = (+)
+
 --------------------------------------------------------------------------------
 
 
@@ -518,6 +568,17 @@
         putStr "C " >> putStr (tail . dropWhile (/='x') $ su)
 
 --------------------------------------------------------------------------------
+
+overMatL' :: (KnownNat m, KnownNat n)
+          => (LA.Matrix ℝ -> LA.Matrix ℝ) -> L m n -> L m n
+overMatL' f = mkL . f . unwrap
+{-# INLINE overMatL' #-}
+
+overMatM' :: (KnownNat m, KnownNat n)
+          => (LA.Matrix ℂ -> LA.Matrix ℂ) -> M m n -> M m n
+overMatM' f = mkM . f . unwrap
+{-# INLINE overMatM' #-}
+
 
 #else
 
diff --git a/src/Internal/Util.hs b/src/Internal/Util.hs
--- a/src/Internal/Util.hs
+++ b/src/Internal/Util.hs
@@ -1,9 +1,13 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE ViewPatterns #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 -----------------------------------------------------------------------------
 {- |
@@ -41,7 +45,7 @@
     ℕ,ℤ,ℝ,ℂ,iC,
     Normed(..), norm_Frob, norm_nuclear,
     magnit,
-    unitary,
+    normalize,
     mt,
     (~!~),
     pairwiseD2,
@@ -79,6 +83,9 @@
 import Data.Complex
 import Data.Function(on)
 import Internal.ST
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 type ℝ = Double
 type ℕ = Int
@@ -92,7 +99,8 @@
 {- | Create a real vector.
 
 >>> vector [1..5]
-fromList [1.0,2.0,3.0,4.0,5.0]
+[1.0,2.0,3.0,4.0,5.0]
+it :: Vector R
 
 -}
 vector :: [R] -> Vector R
@@ -255,6 +263,7 @@
 -- ^ 2-norm of real vector
 norm = pnorm PNorm2
 
+-- | p-norm for vectors, operator norm for matrices
 class Normed a
   where
     norm_0   :: a -> R
@@ -319,10 +328,11 @@
     norm_2 = norm_2 . double
     norm_Inf = norm_Inf . double
 
-
+-- | Frobenius norm (Schatten p-norm with p=2)
 norm_Frob :: (Normed (Vector t), Element t) => Matrix t -> R
 norm_Frob = norm_2 . flatten
 
+-- | Sum of singular values (Schatten p-norm with p=1)
 norm_nuclear :: Field t => Matrix t -> R
 norm_nuclear = sumElements . singularValues
 
@@ -341,8 +351,8 @@
 
 
 -- | Obtains a vector in the same direction with 2-norm=1
-unitary :: Vector Double -> Vector Double
-unitary v = v / scalar (norm v)
+normalize :: (Normed (Vector t), Num (Vector t), Field t) => Vector t -> Vector t
+normalize v = v / real (scalar (norm_2 v))
 
 
 -- | trans . inv
@@ -369,7 +379,8 @@
 On a matrix it gets the k-th row as a vector:
 
 >>> matrix 5 [1..15] ! 1
-fromList [6.0,7.0,8.0,9.0,10.0]
+[6.0,7.0,8.0,9.0,10.0]
+it :: Vector Double
 
 >>> matrix 5 [1..15] ! 1 ! 3
 9.0
@@ -406,7 +417,7 @@
 
 instance Element t => Indexable (Matrix t) (Vector t)
   where
-    m!j = subVector (j*c) c (flatten m)
+    m ! j = subVector (j*c) c (flatten m)
       where
         c = cols m
 
@@ -611,6 +622,9 @@
     s1 = fromRows $ pivotDown (rows x) 0 rs      -- interesting
     s2 = pivotUp (rows x-1) (toRows $ flipud s1)
 
+pivotDown
+  :: forall t . (Fractional t, Num (Vector t), Ord t, Indexable (Vector t) t, Numeric t)
+  => Int -> Int -> [Vector t] -> [Vector t]
 pivotDown t n xs
     | t == n    = []
     | otherwise = y : pivotDown t (n+1) ys
@@ -618,8 +632,9 @@
     y:ys = redu (pivot n xs)
 
     pivot k = (const k &&& id)
-            . sortBy (flip compare `on` (abs. (!k)))
+            . sortBy (flip compare `on` (abs. (! k)))
 
+    redu :: (Int, [Vector t]) -> [Vector t]
     redu (k,x:zs)
         | p == 0 = error "gauss: singular!"  -- FIXME
         | otherwise = u : map f zs
@@ -630,12 +645,16 @@
     redu (_,[]) = []
 
 
+pivotUp
+  :: forall t . (Fractional t, Num (Vector t), Ord t, Indexable (Vector t) t, Numeric t)
+  => Int -> [Vector t] -> [Vector t]
 pivotUp n xs
     | n == -1 = []
     | otherwise = y : pivotUp (n-1) ys
   where
     y:ys = redu' (n,xs)
 
+    redu' :: (Int, [Vector t]) -> [Vector t]
     redu' (k,x:zs) = u : map f zs
       where
         u = x
@@ -893,4 +912,3 @@
          , remap r (tr c) p == ep
          , tr p ?? (PosCyc (idxs[-5,13]), Pos (idxs[3,7,1])) == (2><3) [35,75,15,33,73,13]
          ]
-
diff --git a/src/Internal/Vector.hs b/src/Internal/Vector.hs
--- a/src/Internal/Vector.hs
+++ b/src/Internal/Vector.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE MagicHash, CPP, UnboxedTuples, BangPatterns, FlexibleContexts #-}
+{-# LANGUAGE MagicHash, UnboxedTuples, BangPatterns, FlexibleContexts #-}
 {-# LANGUAGE TypeSynonymInstances #-}
 
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 -- |
 -- Module      :  Internal.Vector
@@ -39,12 +40,11 @@
 import qualified Data.Vector.Storable as Vector
 import Data.Vector.Storable(Vector, fromList, unsafeToForeignPtr, unsafeFromForeignPtr, unsafeWith)
 
-#ifdef BINARY
 import Data.Binary
+import Data.Binary.Put
 import Control.Monad(replicateM)
 import qualified Data.ByteString.Internal as BS
 import Data.Vector.Storable.Internal(updPtr)
-#endif
 
 type I = CInt
 type Z = Int64
@@ -64,13 +64,13 @@
 -- | Number of elements
 dim :: (Storable t) => Vector t -> Int
 dim = Vector.length
+{-# INLINE dim #-}
 
 
 -- C-Haskell vector adapter
 {-# INLINE avec #-}
-avec :: Storable a => (CInt -> Ptr a -> b) -> Vector a -> b
-avec f v = inlinePerformIO (unsafeWith v (return . f (fromIntegral (Vector.length v))))
-infixl 1 `avec`
+avec :: Storable a => Vector a -> (f -> IO r) -> ((CInt -> Ptr a -> f) -> IO r)
+avec v f g = unsafeWith v $ \ptr -> f (g (fromIntegral (Vector.length v)) ptr)
 
 -- allocates memory for a new vector
 createVector :: Storable a => Int -> IO (Vector a)
@@ -94,6 +94,7 @@
 
 -}
 
+safeRead :: Storable a => Vector a -> (Ptr a -> IO c) -> c
 safeRead v = inlinePerformIO . unsafeWith v
 {-# INLINE safeRead #-}
 
@@ -115,7 +116,8 @@
      be used, for instance, with infinite lists.
 
 >>> 5 |> [1..]
-fromList [1.0,2.0,3.0,4.0,5.0]
+[1.0,2.0,3.0,4.0,5.0]
+it :: (Enum a, Num a, Foreign.Storable.Storable a) => Vector a
 
 -}
 (|>) :: (Storable a) => Int -> [a] -> Vector a
@@ -134,7 +136,8 @@
 {- | takes a number of consecutive elements from a Vector
 
 >>> subVector 2 3 (fromList [1..10])
-fromList [3.0,4.0,5.0]
+[3.0,4.0,5.0]
+it :: (Enum t, Num t, Foreign.Storable.Storable t) => Vector t
 
 -}
 subVector :: Storable t => Int       -- ^ index of the starting element
@@ -142,6 +145,7 @@
                         -> Vector t  -- ^ source
                         -> Vector t  -- ^ result
 subVector = Vector.slice
+{-# INLINE subVector #-}
 
 
 
@@ -167,7 +171,8 @@
 {- | concatenate a list of vectors
 
 >>> vjoin [fromList [1..5::Double], konst 1 3]
-fromList [1.0,2.0,3.0,4.0,5.0,1.0,1.0,1.0]
+[1.0,2.0,3.0,4.0,5.0,1.0,1.0,1.0]
+it :: Vector Double
 
 -}
 vjoin :: Storable t => [Vector t] -> Vector t
@@ -189,7 +194,8 @@
 {- | Extract consecutive subvectors of the given sizes.
 
 >>> takesV [3,4] (linspace 10 (1,10::Double))
-[fromList [1.0,2.0,3.0],fromList [4.0,5.0,6.0,7.0]]
+[[1.0,2.0,3.0],[4.0,5.0,6.0,7.0]]
+it :: [Vector Double]
 
 -}
 takesV :: Storable t => [Int] -> Vector t -> [Vector t]
@@ -201,7 +207,7 @@
 
 ---------------------------------------------------------------
 
--- | transforms a complex vector into a real vector with alternating real and imaginary parts 
+-- | transforms a complex vector into a real vector with alternating real and imaginary parts
 asReal :: (RealFloat a, Storable a) => Vector (Complex a) -> Vector a
 asReal v = unsafeFromForeignPtr (castForeignPtr fp) (2*i) (2*n)
     where (fp,i,n) = unsafeToForeignPtr v
@@ -246,7 +252,7 @@
 {-# INLINE zipVectorWith #-}
 
 -- | unzipWith for Vectors
-unzipVectorWith :: (Storable (a,b), Storable c, Storable d) 
+unzipVectorWith :: (Storable (a,b), Storable c, Storable d)
                    => ((a,b) -> (c,d)) -> Vector (a,b) -> (Vector c,Vector d)
 unzipVectorWith f u = unsafePerformIO $ do
       let n = dim u
@@ -257,7 +263,7 @@
               unsafeWith w $ \pw -> do
                   let go (-1) = return ()
                       go !k   = do z <- peekElemOff pu k
-                                   let (x,y) = f z 
+                                   let (x,y) = f z
                                    pokeElemOff      pv k x
                                    pokeElemOff      pw k y
                                    go (k-1)
@@ -284,11 +290,13 @@
         go (dim v -1) x
 {-# INLINE foldVectorWithIndex #-}
 
+foldLoop :: (Int -> t -> t) -> t -> Int -> t
 foldLoop f s0 d = go (d - 1) s0
      where
        go 0 s = f (0::Int) s
        go !j !s = go (j - 1) (f j s)
 
+foldVectorG :: Storable t1 => (Int -> (Int -> t1) -> t -> t) -> t -> Vector t1 -> t
 foldVectorG f s0 v = foldLoop g s0 (dim v)
     where g !k !s = f k (safeRead v . flip peekElemOff) s
           {-# INLINE g #-} -- Thanks to Ryan Ingram (http://permalink.gmane.org/gmane.comp.lang.haskell.cafe/46479)
@@ -305,11 +313,11 @@
     return w
     where mapVectorM' w' !k !t
               | k == t               = do
-                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                        y <- f x
                                        return $! inlinePerformIO $! unsafeWith w' $! \q -> pokeElemOff q k y
               | otherwise            = do
-                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                        y <- f x
                                        _ <- return $! inlinePerformIO $! unsafeWith w' $! \q -> pokeElemOff q k y
                                        mapVectorM' w' (k+1) t
@@ -324,7 +332,7 @@
                                     x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                     f x
               | otherwise         = do
-                                    x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                    x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                     _ <- f x
                                     mapVectorM' (k+1) t
 {-# INLINE mapVectorM_ #-}
@@ -338,11 +346,11 @@
     return w
     where mapVectorM' w' !k !t
               | k == t               = do
-                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                        y <- f k x
                                        return $! inlinePerformIO $! unsafeWith w' $! \q -> pokeElemOff q k y
               | otherwise            = do
-                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                       x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                        y <- f k x
                                        _ <- return $! inlinePerformIO $! unsafeWith w' $! \q -> pokeElemOff q k y
                                        mapVectorM' w' (k+1) t
@@ -357,7 +365,7 @@
                                     x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                     f k x
               | otherwise         = do
-                                    x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k 
+                                    x <- return $! inlinePerformIO $! unsafeWith v $! \p -> peekElemOff p k
                                     _ <- f k x
                                     mapVectorM' (k+1) t
 {-# INLINE mapVectorWithIndexM_ #-}
@@ -380,7 +388,6 @@
 --------------------------------------------------------------------------------
 
 
-#ifdef BINARY
 
 -- a 64K cache, with a Double taking 13 bytes in Bytestring,
 -- implies a chunk size of 5041
@@ -392,8 +399,10 @@
                m = d `mod` chunk
            in if m /= 0 then reverse (m:(replicate c chunk)) else (replicate c chunk)
 
+putVector :: (Storable t, Binary t) => Vector t -> Data.Binary.Put.PutM ()
 putVector v = mapM_ put $! toList v
 
+getVector :: (Storable a, Binary a) => Int -> Get (Vector a)
 getVector d = do
               xs <- replicateM d get
               return $! fromList xs
@@ -432,7 +441,6 @@
 
     -- get = fmap bs2v get
 
-#endif
 
 
 -------------------------------------------------------------------
@@ -458,4 +466,3 @@
 unzipVector = unzipVectorWith id
 
 -------------------------------------------------------------------
-
diff --git a/src/Internal/Vectorized.hs b/src/Internal/Vectorized.hs
--- a/src/Internal/Vectorized.hs
+++ b/src/Internal/Vectorized.hs
@@ -27,10 +27,16 @@
 import System.IO.Unsafe(unsafePerformIO)
 import Control.Monad(when)
 
-infixl 1 #
+infixr 1 #
+(#) :: TransArray c => c -> (b -> IO r) -> TransRaw c b -> IO r
 a # b = applyRaw a b
 {-# INLINE (#) #-}
 
+(#!) :: (TransArray c, TransArray c1) => c1 -> c -> TransRaw c1 (TransRaw c (IO r)) -> IO r
+a #! b = a # b # id
+{-# INLINE (#!) #-}
+
+fromei :: Enum a => a -> CInt
 fromei x = fromIntegral (fromEnum x) :: CInt
 
 data FunCodeV = Sin
@@ -97,13 +103,23 @@
 sumC :: Vector (Complex Double) -> Complex Double
 sumC = sumg c_sumC
 
+sumI :: ( TransRaw c (CInt -> Ptr a -> IO CInt) ~ (CInt -> Ptr I -> I :> Ok)
+        , TransArray c
+        , Storable a
+        )
+     => I -> c -> a
 sumI m = sumg (c_sumI m)
 
+sumL :: ( TransRaw c (CInt -> Ptr a -> IO CInt) ~ (CInt -> Ptr Z -> Z :> Ok)
+        , TransArray c
+        , Storable a
+        ) => Z -> c -> a
 sumL m = sumg (c_sumL m)
 
+sumg :: (TransArray c, Storable a) => TransRaw c (CInt -> Ptr a -> IO CInt) -> c -> a
 sumg f x = unsafePerformIO $ do
     r <- createVector 1
-    f # x # r #| "sum"
+    (x #! r) f #| "sum"
     return $ r @> 0
 
 type TVV t = t :> t :> Ok
@@ -137,9 +153,11 @@
 prodL :: Z-> Vector Z -> Z
 prodL = prodg . c_prodL
 
+prodg :: (TransArray c, Storable a)
+      => TransRaw c (CInt -> Ptr a -> IO CInt) -> c -> a
 prodg f x = unsafePerformIO $ do
     r <- createVector 1
-    f # x # r #| "prod"
+    (x #! r) f #| "prod"
     return $ r @> 0
 
 
@@ -152,26 +170,38 @@
 
 ------------------------------------------------------------------
 
+toScalarAux :: (Enum a, TransArray c, Storable a1)
+            => (CInt -> TransRaw c (CInt -> Ptr a1 -> IO CInt)) -> a -> c -> a1
 toScalarAux fun code v = unsafePerformIO $ do
     r <- createVector 1
-    fun (fromei code) # v # r #|"toScalarAux"
+    (v #! r) (fun (fromei code)) #|"toScalarAux"
     return (r @> 0)
 
+
+vectorMapAux :: (Enum a, Storable t, Storable a1)
+             => (CInt -> CInt -> Ptr t -> CInt -> Ptr a1 -> IO CInt)
+             -> a -> Vector t -> Vector a1
 vectorMapAux fun code v = unsafePerformIO $ do
     r <- createVector (dim v)
-    fun (fromei code) # v # r #|"vectorMapAux"
+    (v #! r) (fun (fromei code)) #|"vectorMapAux"
     return r
 
+vectorMapValAux :: (Enum a, Storable a2, Storable t, Storable a1)
+                => (CInt -> Ptr a2 -> CInt -> Ptr t -> CInt -> Ptr a1 -> IO CInt)
+                -> a -> a2 -> Vector t -> Vector a1
 vectorMapValAux fun code val v = unsafePerformIO $ do
     r <- createVector (dim v)
     pval <- newArray [val]
-    fun (fromei code) pval # v # r #|"vectorMapValAux"
+    (v #! r) (fun (fromei code) pval) #|"vectorMapValAux"
     free pval
     return r
 
+vectorZipAux :: (Enum a, TransArray c, Storable t, Storable a1)
+             => (CInt -> CInt -> Ptr t -> TransRaw c (CInt -> Ptr a1 -> IO CInt))
+             -> a -> Vector t -> c -> Vector a1
 vectorZipAux fun code u v = unsafePerformIO $ do
     r <- createVector (dim u)
-    fun (fromei code) # u # v # r #|"vectorZipAux"
+    (u # v #! r) (fun (fromei code)) #|"vectorZipAux"
     return r
 
 ---------------------------------------------------------------------
@@ -368,16 +398,17 @@
              -> Vector Double
 randomVector seed dist n = unsafePerformIO $ do
     r <- createVector n
-    c_random_vector (fi seed) ((fi.fromEnum) dist) # r #|"randomVector"
+    (r # id) (c_random_vector (fi seed) ((fi.fromEnum) dist)) #|"randomVector"
     return r
 
 foreign import ccall unsafe "random_vector" c_random_vector :: CInt -> CInt -> Double :> Ok
 
 --------------------------------------------------------------------------------
 
+roundVector :: Vector Double -> Vector Double
 roundVector v = unsafePerformIO $ do
     r <- createVector (dim v)
-    c_round_vector # v # r #|"roundVector"
+    (v #! r) c_round_vector #|"roundVector"
     return r
 
 foreign import ccall unsafe "round_vector" c_round_vector :: TVV Double
@@ -386,12 +417,13 @@
 
 -- |
 -- >>> range 5
--- fromList [0,1,2,3,4]
+-- [0,1,2,3,4]
+-- it :: Vector I
 --
 range :: Int -> Vector I
 range n = unsafePerformIO $ do
     r <- createVector n
-    c_range_vector # r #|"range"
+    (r # id) c_range_vector #|"range"
     return r
 
 foreign import ccall unsafe "range_vector" c_range_vector :: CInt :> Ok
@@ -429,9 +461,11 @@
 long2intV = tog c_long2int
 
 
+tog :: (Storable t, Storable a)
+    => (CInt -> Ptr t -> CInt -> Ptr a -> IO CInt) -> Vector t -> Vector a
 tog f v = unsafePerformIO $ do
     r <- createVector (dim v)
-    f # v # r #|"tog"
+    (v #! r) f #|"tog"
     return r
 
 foreign import ccall unsafe "float2double" c_float2double :: Float :> Double :> Ok
@@ -448,9 +482,11 @@
 
 ---------------------------------------------------------------
 
+stepg :: (Storable t, Storable a)
+      => (CInt -> Ptr t -> CInt -> Ptr a -> IO CInt) -> Vector t -> Vector a
 stepg f v = unsafePerformIO $ do
     r <- createVector (dim v)
-    f # v # r #|"step"
+    (v #! r) f #|"step"
     return r
 
 stepD :: Vector Double -> Vector Double
@@ -473,9 +509,11 @@
 
 --------------------------------------------------------------------------------
 
+conjugateAux :: (Storable t, Storable a)
+             => (CInt -> Ptr t -> CInt -> Ptr a -> IO CInt) -> Vector t -> Vector a
 conjugateAux fun x = unsafePerformIO $ do
     v <- createVector (dim x)
-    fun # x # v #|"conjugateAux"
+    (x #! v) fun #|"conjugateAux"
     return v
 
 conjugateQ :: Vector (Complex Float) -> Vector (Complex Float)
@@ -493,15 +531,17 @@
         let n = dim v
         r <- createVector n
         let f _ s _ d =  copyArray d s n >> return 0
-        f # v # r #|"cloneVector"
+        (v #! r) f #|"cloneVector"
         return r
 
 --------------------------------------------------------------------------------
 
+constantAux :: (Storable a1, Storable a)
+            => (Ptr a1 -> CInt -> Ptr a -> IO CInt) -> a1 -> Int -> Vector a
 constantAux fun x n = unsafePerformIO $ do
     v <- createVector n
     px <- newArray [x]
-    fun px # v #|"constantAux"
+    (v # id) (fun px) #|"constantAux"
     free px
     return v
 
@@ -515,4 +555,3 @@
 foreign import ccall unsafe "constantL" cconstantL :: TConst Z
 
 ----------------------------------------------------------------------
-
diff --git a/src/Numeric/LinearAlgebra.hs b/src/Numeric/LinearAlgebra.hs
--- a/src/Numeric/LinearAlgebra.hs
+++ b/src/Numeric/LinearAlgebra.hs
@@ -1,5 +1,8 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
 -----------------------------------------------------------------------------
 {- |
 Module      :  Numeric.LinearAlgebra
@@ -22,10 +25,12 @@
 
     -- * Numeric classes
     -- |
-    -- The standard numeric classes are defined elementwise:
+    -- The standard numeric classes are defined elementwise (commonly referred to
+    -- as the Hadamard product or the Schur product):
     --
     -- >>>  vector [1,2,3] * vector [3,0,-2]
-    -- fromList [3.0,0.0,-6.0]
+    -- [3.0,0.0,-6.0]
+    -- it :: Vector R
     --
     -- >>> matrix 3 [1..9] * ident 3
     -- (3><3)
@@ -93,6 +98,11 @@
     ldlSolve, ldlPacked,
     -- ** Positive definite
     cholSolve,
+    -- ** Triangular
+    UpLo(..),
+    triSolve,
+    -- ** Tridiagonal
+    triDiagSolve,
     -- ** Sparse
     cgSolve,
     cgSolve',
@@ -116,16 +126,17 @@
     svd,
     thinSVD,
     compactSVD,
+    compactSVDTol,
     singularValues,
     leftSV, rightSV,
 
     -- * Eigendecomposition
-    eig, eigSH,
-    eigenvalues, eigenvaluesSH,
+    eig, geig, eigSH,
+    eigenvalues, geigenvalues, eigenvaluesSH,
     geigSH,
 
     -- * QR
-    qr, rq, qrRaw, qrgr,
+    qr, thinQR, rq, thinRQ, qrRaw, qrgr,
 
     -- * Cholesky
     chol, mbChol,
@@ -152,7 +163,7 @@
     Seed, RandDist(..), randomVector, rand, randn, gaussianSample, uniformSample,
 
     -- * Misc
-    meanCov, rowOuters, pairwiseD2, unitary, peps, relativeError, magnit,
+    meanCov, rowOuters, pairwiseD2, normalize, peps, relativeError, magnit,
     haussholder, optimiseMult, udot, nullspaceSVD, orthSVD, ranksv,
     iC, sym, mTm, trustSym, unSym,
     -- * Auxiliary classes
@@ -183,6 +194,9 @@
 import Internal.Sparse((!#>))
 import Internal.CG
 import Internal.Conversion
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 {- | dense matrix product
 
diff --git a/src/Numeric/LinearAlgebra/Devel.hs b/src/Numeric/LinearAlgebra/Devel.hs
--- a/src/Numeric/LinearAlgebra/Devel.hs
+++ b/src/Numeric/LinearAlgebra/Devel.hs
@@ -12,16 +12,9 @@
 --------------------------------------------------------------------------------
 
 module Numeric.LinearAlgebra.Devel(
-    -- * FFI helpers
-    -- | Sample usage, to upload a perspective matrix to a shader.
-    --
-    -- @ glUniformMatrix4fv 0 1 (fromIntegral gl_TRUE) \`appMatrix\` perspective 0.01 100 (pi\/2) (4\/3)
-    -- @
-    module Internal.Foreign,
-
     -- * FFI tools
     -- | See @examples/devel@ in the repository.
-    
+
     createVector, createMatrix,
     TransArray(..),
     MatrixOrder(..), orderOf, cmat, fmat,
@@ -34,7 +27,7 @@
     -- * ST
     -- | In-place manipulation inside the ST monad.
     -- See @examples/inplace.hs@ in the repository.
-    
+
     -- ** Mutable Vectors
     STVector, newVector, thawVector, freezeVector, runSTVector,
     readVector, writeVector, modifyVector, liftSTVector,
@@ -58,15 +51,14 @@
     liftMatrix, liftMatrix2, liftMatrix2Auto,
 
     -- * Sparse representation
-    CSR(..), fromCSR, mkCSR,
+    CSR(..), fromCSR, mkCSR, impureCSR,
     GMatrix(..),
 
     -- * Misc
-    toByteString, fromByteString, showInternal
+    toByteString, fromByteString, showInternal, reorderVector
 
 ) where
 
-import Internal.Foreign
 import Internal.Devel
 import Internal.ST
 import Internal.Vector
diff --git a/src/Numeric/LinearAlgebra/HMatrix.hs b/src/Numeric/LinearAlgebra/HMatrix.hs
--- a/src/Numeric/LinearAlgebra/HMatrix.hs
+++ b/src/Numeric/LinearAlgebra/HMatrix.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 --------------------------------------------------------------------------------
 {- |
 Module      :  Numeric.LinearAlgebra.HMatrix
@@ -19,12 +20,17 @@
 import Numeric.LinearAlgebra
 import Internal.Util
 import Internal.Algorithms(cholSH, mbCholSH, eigSH', eigenvaluesSH', geigSH')
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 infixr 8 <·>
 (<·>) :: Numeric t => Vector t -> Vector t -> t
 (<·>) = dot
 
+app :: Numeric t => Matrix t -> Vector t -> Vector t
 app m v = m #> v
 
+mul :: Numeric t => Matrix t -> Matrix t -> Matrix t
 mul a b = a <> b
 
diff --git a/src/Numeric/LinearAlgebra/Static.hs b/src/Numeric/LinearAlgebra/Static.hs
--- a/src/Numeric/LinearAlgebra/Static.hs
+++ b/src/Numeric/LinearAlgebra/Static.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE KindSignatures #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -13,6 +14,8 @@
 {-# LANGUAGE GADTs #-}
 {-# LANGUAGE TypeFamilies #-}
 
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
 
 {- |
 Module      :  Numeric.LinearAlgebra.Static
@@ -42,19 +45,31 @@
     blockAt,
     matrix,
     -- * Complex
-    C, M, Her, her, 𝑖,
+    ℂ, C, M, Her, her, 𝑖,
+    toComplex,
+    fromComplex,
+    complex,
+    real,
+    imag,
+    sqMagnitude,
+    magnitude,
     -- * Products
     (<>),(#>),(<.>),
     -- * Linear Systems
     linSolve, (<\>),
     -- * Factorizations
     svd, withCompactSVD, svdTall, svdFlat, Eigen(..),
-    withNullspace, qr, chol,
+    withNullspace, withOrth, qr, chol,
+    -- * Norms
+    Normed(..),
+    -- * Random arrays
+    Seed, RandDist(..),
+    randomVector, rand, randn, gaussianSample, uniformSample,
     -- * Misc
-    mean,
+    mean, meanCov,
     Disp(..), Domain(..),
-    withVector, withMatrix,
-    toRows, toColumns,
+    withVector, withMatrix, exactLength, exactDims,
+    toRows, toColumns, withRows, withColumns,
     Sized(..), Diag(..), Sym, sym, mTm, unSym, (<·>)
 ) where
 
@@ -65,18 +80,28 @@
     row,col,vector,matrix,linspace,toRows,toColumns,
     (<\>),fromList,takeDiag,svd,eig,eigSH,
     eigenvalues,eigenvaluesSH,build,
-    qr,size,dot,chol,range,R,C,sym,mTm,unSym)
+    qr,size,dot,chol,range,R,C,sym,mTm,unSym,
+    randomVector,rand,randn,gaussianSample,uniformSample,meanCov,
+    toComplex, fromComplex, complex, real, magnitude
+    )
 import qualified Numeric.LinearAlgebra as LA
-import Data.Proxy(Proxy)
+import qualified Numeric.LinearAlgebra.Devel as LA
+import Data.Proxy(Proxy(..))
 import Internal.Static
 import Control.Arrow((***))
+import Text.Printf
+import Data.Type.Equality ((:~:)(Refl))
+import qualified Data.Bifunctor as BF (first)
+#if MIN_VERSION_base(4,11,0)
+import Prelude hiding ((<>))
+#endif
 
 ud1 :: R n -> Vector ℝ
 ud1 (R (Dim v)) = v
 
 
 infixl 4 &
-(&) :: forall n . (KnownNat n, 1 <= n)
+(&) :: forall n . KnownNat n
     => R n -> ℝ -> R (n+1)
 u & x = u # (konst x :: R 1)
 
@@ -204,11 +229,11 @@
 
 
 infixr 8 <·>
-(<·>) :: R n -> R n -> ℝ
+(<·>) :: KnownNat n => R n -> R n -> ℝ
 (<·>) = dotR
 
 infixr 8 <.>
-(<.>) :: R n -> R n -> ℝ
+(<.>) :: KnownNat n => R n -> R n -> ℝ
 (<.>) = dotR
 
 --------------------------------------------------------------------------------
@@ -218,21 +243,39 @@
     takeDiag :: m -> d
 
 
-instance forall n . (KnownNat n) => Diag (L n n) (R n)
+instance KnownNat n => Diag (L n n) (R n)
   where
-    takeDiag m = mkR (LA.takeDiag (extract m))
+    takeDiag x = mkR (LA.takeDiag (extract x))
 
 
-instance forall m n . (KnownNat m, KnownNat n, m <= n+1) => Diag (L m n) (R m)
+instance KnownNat n => Diag (M n n) (C n)
   where
-    takeDiag m = mkR (LA.takeDiag (extract m))
+    takeDiag x = mkC (LA.takeDiag (extract x))
 
+--------------------------------------------------------------------------------
 
-instance forall m n . (KnownNat m, KnownNat n, n <= m+1) => Diag (L m n) (R n)
-  where
-    takeDiag m = mkR (LA.takeDiag (extract m))
 
+toComplex :: KnownNat n => (R n, R n) -> C n
+toComplex (r,i) = mkC $ LA.toComplex (ud1 r, ud1 i)
 
+fromComplex :: KnownNat n => C n -> (R n, R n)
+fromComplex (C (Dim v)) = let (r,i) = LA.fromComplex v in (mkR r, mkR i)
+
+complex :: KnownNat n => R n -> C n
+complex r = mkC $ LA.toComplex (ud1 r, LA.konst 0 (size r))
+
+real :: KnownNat n => C n -> R n
+real = fst . fromComplex
+
+imag :: KnownNat n => C n -> R n 
+imag = snd . fromComplex
+
+sqMagnitude :: KnownNat n => C n -> R n
+sqMagnitude c = let (r,i) = fromComplex c in r**2 + i**2
+
+magnitude :: KnownNat n => C n -> R n
+magnitude = sqrt . sqMagnitude
+
 --------------------------------------------------------------------------------
 
 linSolve :: (KnownNat m, KnownNat n) => L m m -> L m n -> Maybe (L m n)
@@ -289,7 +332,21 @@
 her m = Her $ (m + LA.tr m)/2
 
 
+instance (KnownNat n) => Disp (Sym n)
+  where
+    disp n (Sym x) = do
+        let a = extract x
+        let su = LA.dispf n a
+        printf "Sym %d" (cols a) >> putStr (dropWhile (/='\n') $ su)
 
+instance (KnownNat n) => Disp (Her n)
+  where
+    disp n (Her x) = do
+        let a = extract x
+        let su = LA.dispcf n a
+        printf "Her %d" (cols a) >> putStr (dropWhile (/='\n') $ su)
+
+
 instance KnownNat n => Eigen (Sym n) (R n) (L n n)
   where
     eigenvalues (Sym (extract -> m)) =  mkR . LA.eigenvaluesSH . LA.trustSym $ m
@@ -319,6 +376,15 @@
        Nothing -> error "static/dynamic mismatch"
        Just (SomeNat (_ :: Proxy k)) -> f (mkL a :: L n k)
 
+withOrth
+    :: forall m n z . (KnownNat m, KnownNat n)
+    => L m n
+    -> (forall k. (KnownNat k) => L n k -> z)
+    -> z
+withOrth (LA.orth . extract -> a) f =
+    case someNatVal $ fromIntegral $ cols a of
+       Nothing -> error "static/dynamic mismatch"
+       Just (SomeNat (_ :: Proxy k)) -> f (mkL a :: L n k)
 
 withCompactSVD
     :: forall m n z . (KnownNat m, KnownNat n)
@@ -349,7 +415,7 @@
 
 
 headTail :: (KnownNat n, 1<=n) => R n -> (ℝ, R (n-1))
-headTail = ((!0) . extract *** id) . split
+headTail = ((! 0) . extract *** id) . split
 
 
 splitRows :: forall p m n . (KnownNat p, KnownNat m, KnownNat n, p<=m) => L m n -> (L p n, L (m-p) n)
@@ -365,11 +431,31 @@
 toRows :: forall m n . (KnownNat m, KnownNat n) => L m n -> [R n]
 toRows (LA.toRows . extract -> vs) = map mkR vs
 
+withRows
+    :: forall n z . KnownNat n
+    => [R n]
+    -> (forall m . KnownNat m => L m n -> z)
+    -> z
+withRows (LA.fromRows . map extract -> m) f =
+    case someNatVal $ fromIntegral $ LA.rows m of
+       Nothing -> error "static/dynamic mismatch"
+       Just (SomeNat (_ :: Proxy m)) -> f (mkL m :: L m n)
 
 toColumns :: forall m n . (KnownNat m, KnownNat n) => L m n -> [R m]
 toColumns (LA.toColumns . extract -> vs) = map mkR vs
 
+withColumns
+    :: forall m z . KnownNat m
+    => [R m]
+    -> (forall n . KnownNat n => L m n -> z)
+    -> z
+withColumns (LA.fromColumns . map extract -> m) f =
+    case someNatVal $ fromIntegral $ LA.cols m of
+       Nothing -> error "static/dynamic mismatch"
+       Just (SomeNat (_ :: Proxy n)) -> f (mkL m :: L m n)
 
+
+
 --------------------------------------------------------------------------------
 
 build
@@ -392,6 +478,15 @@
        Nothing -> error "static/dynamic mismatch"
        Just (SomeNat (_ :: Proxy m)) -> f (mkR v :: R m)
 
+-- | Useful for constraining two dependently typed vectors to match each
+-- other in length when they are unknown at compile-time.
+exactLength
+    :: forall n m . (KnownNat n, KnownNat m)
+    => R m
+    -> Maybe (R n)
+exactLength v = do
+    Refl <- sameNat (Proxy :: Proxy n) (Proxy :: Proxy m)
+    return $ mkR (unwrap v)
 
 withMatrix
     :: forall z
@@ -407,6 +502,64 @@
                Just (SomeNat (_ :: Proxy n)) ->
                   f (mkL a :: L m n)
 
+-- | Useful for constraining two dependently typed matrices to match each
+-- other in dimensions when they are unknown at compile-time.
+exactDims
+    :: forall n m j k . (KnownNat n, KnownNat m, KnownNat j, KnownNat k)
+    => L m n
+    -> Maybe (L j k)
+exactDims m = do
+    Refl <- sameNat (Proxy :: Proxy m) (Proxy :: Proxy j)
+    Refl <- sameNat (Proxy :: Proxy n) (Proxy :: Proxy k)
+    return $ mkL (unwrap m)
+
+randomVector
+    :: forall n . KnownNat n
+    => Seed
+    -> RandDist
+    -> R n
+randomVector s d = mkR (LA.randomVector s d
+                          (fromInteger (natVal (Proxy :: Proxy n)))
+                       )
+
+rand
+    :: forall m n . (KnownNat m, KnownNat n)
+    => IO (L m n)
+rand = mkL <$> LA.rand (fromInteger (natVal (Proxy :: Proxy m)))
+                       (fromInteger (natVal (Proxy :: Proxy n)))
+
+randn
+    :: forall m n . (KnownNat m, KnownNat n)
+    => IO (L m n)
+randn = mkL <$> LA.randn (fromInteger (natVal (Proxy :: Proxy m)))
+                         (fromInteger (natVal (Proxy :: Proxy n)))
+
+gaussianSample
+    :: forall m n . (KnownNat m, KnownNat n)
+    => Seed
+    -> R n
+    -> Sym n
+    -> L m n
+gaussianSample s (extract -> mu) (Sym (extract -> sigma)) =
+    mkL $ LA.gaussianSample s (fromInteger (natVal (Proxy :: Proxy m)))
+                            mu (LA.trustSym sigma)
+
+uniformSample
+    :: forall m n . (KnownNat m, KnownNat n)
+    => Seed
+    -> R n    -- ^ minimums of each row
+    -> R n    -- ^ maximums of each row
+    -> L m n
+uniformSample s (extract -> mins) (extract -> maxs) =
+    mkL $ LA.uniformSample s (fromInteger (natVal (Proxy :: Proxy m)))
+                           (zip (LA.toList mins) (LA.toList maxs))
+
+meanCov
+    :: forall m n . (KnownNat m, KnownNat n, 1 <= m)
+    => L m n
+    -> (R n, Sym n)
+meanCov (extract -> vs) = mkR *** (Sym . mkL . LA.unSym) $ LA.meanCov vs
+
 --------------------------------------------------------------------------------
 
 class Domain field vec mat | mat -> vec field, vec -> mat field, field -> mat vec
@@ -416,6 +569,15 @@
     dot :: forall n . (KnownNat n) => vec n -> vec n -> field
     cross :: vec 3 -> vec 3 -> vec 3
     diagR ::  forall m n k . (KnownNat m, KnownNat n, KnownNat k) => field -> vec k -> mat m n
+    dvmap :: forall n. KnownNat n => (field -> field) -> vec n -> vec n
+    dmmap :: forall n m. (KnownNat m, KnownNat n) => (field -> field) -> mat n m -> mat n m
+    outer :: forall n m. (KnownNat m, KnownNat n) => vec n -> vec m -> mat n m
+    zipWithVector :: forall n. KnownNat n => (field -> field -> field) -> vec n -> vec n -> vec n
+    det :: forall n. KnownNat n => mat n n -> field
+    invlndet :: forall n. KnownNat n => mat n n -> (mat n n, (field, field))
+    expm :: forall n. KnownNat n => mat n n -> mat n n
+    sqrtm :: forall n. KnownNat n => mat n n -> mat n n
+    inv :: forall n. KnownNat n => mat n n -> mat n n
 
 
 instance Domain ℝ R L
@@ -425,6 +587,15 @@
     dot = dotR
     cross = crossR
     diagR = diagRectR
+    dvmap = mapR
+    dmmap = mapL
+    outer = outerR
+    zipWithVector = zipWithR
+    det = detL
+    invlndet = invlndetL
+    expm = expmL
+    sqrtm = sqrtmL
+    inv = invL
 
 instance Domain ℂ C M
   where
@@ -433,6 +604,15 @@
     dot = dotC
     cross = crossC
     diagR = diagRectC
+    dvmap = mapC
+    dmmap = mapM'
+    outer = outerC
+    zipWithVector = zipWithC
+    det = detM
+    invlndet = invlndetM
+    expm = expmM
+    sqrtm = sqrtmM
+    inv = invM
 
 --------------------------------------------------------------------------------
 
@@ -447,9 +627,9 @@
     a' = subVector 0 n a
     b' = subVector 0 n b
 
-mulR (isDiag -> Just (0,a,_)) (extract -> b) = mkL (asColumn a * takeRows (LA.size a) b)
+-- mulR (isDiag -> Just (0,a,_)) (extract -> b) = mkL (asColumn a * takeRows (LA.size a) b)
 
-mulR (extract -> a) (isDiag -> Just (0,b,_)) = mkL (takeColumns (LA.size b) a * asRow b)
+-- mulR (extract -> a) (isDiag -> Just (0,b,_)) = mkL (takeColumns (LA.size b) a * asRow b)
 
 mulR a b = mkL (extract a LA.<> extract b)
 
@@ -459,10 +639,8 @@
 appR m v = mkR (extract m LA.#> extract v)
 
 
-dotR :: R n -> R n -> ℝ
-dotR (ud1 -> u) (ud1 -> v)
-    | singleV u || singleV v = sumElements (u * v)
-    | otherwise = udot u v
+dotR :: KnownNat n => R n -> R n -> ℝ
+dotR (extract -> u) (extract -> v) = LA.dot u v
 
 
 crossR :: R 3 -> R 3 -> R 3
@@ -472,6 +650,33 @@
     z2 = x!2*y!0-x!0*y!2
     z3 = x!0*y!1-x!1*y!0
 
+outerR :: (KnownNat m, KnownNat n) => R n -> R m -> L n m
+outerR (extract -> x) (extract -> y) = mkL (LA.outer x y)
+
+mapR :: KnownNat n => (ℝ -> ℝ) -> R n -> R n
+mapR f (unwrap -> v) = mkR (LA.cmap f v)
+
+zipWithR :: KnownNat n => (ℝ -> ℝ -> ℝ) -> R n -> R n -> R n
+zipWithR f (extract -> x) (extract -> y) = mkR (LA.zipVectorWith f x y)
+
+mapL :: (KnownNat n, KnownNat m) => (ℝ -> ℝ) -> L n m -> L n m
+mapL f = overMatL' (LA.cmap f)
+
+detL :: KnownNat n => Sq n -> ℝ
+detL = LA.det . unwrap
+
+invlndetL :: KnownNat n => Sq n -> (L n n, (ℝ, ℝ))
+invlndetL = BF.first mkL . LA.invlndet . unwrap
+
+expmL :: KnownNat n => Sq n -> Sq n
+expmL = overMatL' LA.expm
+
+sqrtmL :: KnownNat n => Sq n -> Sq n
+sqrtmL = overMatL' LA.sqrtm
+
+invL :: KnownNat n => Sq n -> Sq n
+invL = overMatL' LA.inv
+
 --------------------------------------------------------------------------------
 
 mulC :: forall m k n. (KnownNat m, KnownNat k, KnownNat n) => M m k -> M k n -> M m n
@@ -485,9 +690,9 @@
     a' = subVector 0 n a
     b' = subVector 0 n b
 
-mulC (isDiagC -> Just (0,a,_)) (extract -> b) = mkM (asColumn a * takeRows (LA.size a) b)
+-- mulC (isDiagC -> Just (0,a,_)) (extract -> b) = mkM (asColumn a * takeRows (LA.size a) b)
 
-mulC (extract -> a) (isDiagC -> Just (0,b,_)) = mkM (takeColumns (LA.size b) a * asRow b)
+-- mulC (extract -> a) (isDiagC -> Just (0,b,_)) = mkM (takeColumns (LA.size b) a * asRow b)
 
 mulC a b = mkM (extract a LA.<> extract b)
 
@@ -498,9 +703,7 @@
 
 
 dotC :: KnownNat n => C n -> C n -> ℂ
-dotC (unwrap -> u) (unwrap -> v)
-    | singleV u || singleV v = sumElements (conj u * v)
-    | otherwise = u LA.<.> v
+dotC (extract -> u) (extract -> v) = LA.dot u v
 
 
 crossC :: C 3 -> C 3 -> C 3
@@ -510,6 +713,33 @@
     z2 = x!2*y!0-x!0*y!2
     z3 = x!0*y!1-x!1*y!0
 
+outerC :: (KnownNat m, KnownNat n) => C n -> C m -> M n m
+outerC (extract -> x) (extract -> y) = mkM (LA.outer x y)
+
+mapC :: KnownNat n => (ℂ -> ℂ) -> C n -> C n
+mapC f (unwrap -> v) = mkC (LA.cmap f v)
+
+zipWithC :: KnownNat n => (ℂ -> ℂ -> ℂ) -> C n -> C n -> C n
+zipWithC f (extract -> x) (extract -> y) = mkC (LA.zipVectorWith f x y)
+
+mapM' :: (KnownNat n, KnownNat m) => (ℂ -> ℂ) -> M n m -> M n m
+mapM' f = overMatM' (LA.cmap f)
+
+detM :: KnownNat n => M n n -> ℂ
+detM = LA.det . unwrap
+
+invlndetM :: KnownNat n => M n n -> (M n n, (ℂ, ℂ))
+invlndetM = BF.first mkM . LA.invlndet . unwrap
+
+expmM :: KnownNat n => M n n -> M n n
+expmM = overMatM' LA.expm
+
+sqrtmM :: KnownNat n => M n n -> M n n
+sqrtmM = overMatM' LA.sqrtm
+
+invM :: KnownNat n => M n n -> M n n
+invM = overMatM' LA.inv
+
 --------------------------------------------------------------------------------
 
 diagRectR :: forall m n k . (KnownNat m, KnownNat n, KnownNat k) => ℝ -> R k -> L m n
@@ -616,3 +846,67 @@
   where
     checkT _ = test
 
+--------------------------------------------------------------------------------
+
+instance KnownNat n => Normed (R n)
+  where
+    norm_0 v = norm_0 (extract v)
+    norm_1 v = norm_1 (extract v)
+    norm_2 v = norm_2 (extract v)
+    norm_Inf v = norm_Inf (extract v)
+
+instance (KnownNat m, KnownNat n) => Normed (L m n)
+  where
+    norm_0 m = norm_0 (extract m)
+    norm_1 m = norm_1 (extract m)
+    norm_2 m = norm_2 (extract m)
+    norm_Inf m = norm_Inf (extract m)
+
+mkSym f = Sym . f . unSym
+mkSym2 f x y = Sym (f (unSym x) (unSym y))
+
+instance KnownNat n =>  Num (Sym n)
+  where
+    (+) = mkSym2 (+)
+    (*) = mkSym2 (*)
+    (-) = mkSym2 (-)
+    abs = mkSym abs
+    signum = mkSym signum
+    negate = mkSym negate
+    fromInteger = Sym . fromInteger
+
+instance KnownNat n => Fractional (Sym n)
+  where
+    fromRational = Sym . fromRational
+    (/) = mkSym2 (/)
+
+instance KnownNat n => Floating (Sym n)
+  where
+    sin   = mkSym sin
+    cos   = mkSym cos
+    tan   = mkSym tan
+    asin  = mkSym asin
+    acos  = mkSym acos
+    atan  = mkSym atan
+    sinh  = mkSym sinh
+    cosh  = mkSym cosh
+    tanh  = mkSym tanh
+    asinh = mkSym asinh
+    acosh = mkSym acosh
+    atanh = mkSym atanh
+    exp   = mkSym exp
+    log   = mkSym log
+    sqrt  = mkSym sqrt
+    (**)  = mkSym2 (**)
+    pi    = Sym pi
+
+instance KnownNat n => Additive (Sym n) where
+    add = (+)
+
+instance KnownNat n => Transposable (Sym n) (Sym n) where
+    tr  = id
+    tr' = id
+
+instance KnownNat n => Transposable (Her n) (Her n) where
+    tr          = id
+    tr' (Her m) = Her (tr' m)
diff --git a/src/Numeric/Matrix.hs b/src/Numeric/Matrix.hs
--- a/src/Numeric/Matrix.hs
+++ b/src/Numeric/Matrix.hs
@@ -4,6 +4,8 @@
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Numeric.Matrix
@@ -32,8 +34,12 @@
 import Internal.Numeric
 import qualified Data.Monoid as M
 import Data.List(partition)
+import qualified Data.Foldable as F
+import qualified Data.Semigroup as S
 import Internal.Chain
+import Foreign.Storable(Storable)
 
+
 -------------------------------------------------------------------
 
 instance Container Matrix a => Eq (Matrix a) where
@@ -77,18 +83,31 @@
 
 --------------------------------------------------------------------------------
 
+isScalar :: Matrix t -> Bool
 isScalar m = rows m == 1 && cols m == 1
 
+adaptScalarM :: (Foreign.Storable.Storable t1, Foreign.Storable.Storable t2)
+             => (t1 -> Matrix t2 -> t)
+             -> (Matrix t1 -> Matrix t2 -> t)
+             -> (Matrix t1 -> t2 -> t)
+             -> Matrix t1
+             -> Matrix t2
+             -> t
 adaptScalarM f1 f2 f3 x y
     | isScalar x = f1   (x @@>(0,0) ) y
     | isScalar y = f3 x (y @@>(0,0) )
     | otherwise = f2 x y
 
+instance (Container Vector t, Eq t, Num (Vector t), Product t) => S.Semigroup (Matrix t)
+  where
+    (<>) = mappend
+    sconcat = mconcat . F.toList
+
 instance (Container Vector t, Eq t, Num (Vector t), Product t) => M.Monoid (Matrix t)
   where
     mempty = 1
     mappend = adaptScalarM scale mXm (flip scale)
-    
+
     mconcat xs = work (partition isScalar xs)
       where
         work (ss,[]) = product ss
@@ -98,4 +117,3 @@
             | otherwise              = scale x00 m
           where
             x00 = x @@> (0,0)
-
diff --git a/src/Numeric/Vector.hs b/src/Numeric/Vector.hs
--- a/src/Numeric/Vector.hs
+++ b/src/Numeric/Vector.hs
@@ -3,6 +3,9 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
+
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Numeric.Vector
@@ -14,7 +17,7 @@
 --
 -- Provides instances of standard classes 'Show', 'Read', 'Eq',
 -- 'Num', 'Fractional',  and 'Floating' for 'Vector'.
--- 
+--
 -----------------------------------------------------------------------------
 
 module Numeric.Vector () where
@@ -23,9 +26,17 @@
 import Internal.Vector
 import Internal.Numeric
 import Internal.Conversion
+import Foreign.Storable(Storable)
 
 -------------------------------------------------------------------
 
+adaptScalar :: (Foreign.Storable.Storable t1, Foreign.Storable.Storable t2)
+            => (t1 -> Vector t2 -> t)
+            -> (Vector t1 -> Vector t2 -> t)
+            -> (Vector t1 -> t2 -> t)
+            -> Vector t1
+            -> Vector t2
+            -> t
 adaptScalar f1 f2 f3 x y
     | dim x == 1 = f1   (x@>0) y
     | dim y == 1 = f3 x (y@>0)
@@ -172,4 +183,3 @@
     sqrt  = vectorMapQ Sqrt
     (**)  = adaptScalar (vectorMapValQ PowSV) (vectorZipQ Pow) (flip (vectorMapValQ PowVS))
     pi    = fromList [pi]
-
