diff --git a/spectral-clustering.cabal b/spectral-clustering.cabal
--- a/spectral-clustering.cabal
+++ b/spectral-clustering.cabal
@@ -1,6 +1,6 @@
 cabal-version: >=1.10
 name: spectral-clustering
-version: 0.3.1.3
+version: 0.3.2.1
 license: GPL-3
 license-file: LICENSE
 copyright: 2019 Gregory W. Schwartz
@@ -32,6 +32,6 @@
         hmatrix-svdlibc >=0.5.0.1,
         mwc-random >=0.13.6.0,
         safe >=0.3.17,
-        sparse-linear-algebra >=0.3.1,
+        sparse-linear-algebra >=0.3.2,
         statistics >=0.14.0.2,
         vector >=0.12.0.1
diff --git a/src/Math/Clustering/Spectral/Sparse.hs b/src/Math/Clustering/Spectral/Sparse.hs
--- a/src/Math/Clustering/Spectral/Sparse.hs
+++ b/src/Math/Clustering/Spectral/Sparse.hs
@@ -12,6 +12,7 @@
     , B2 (..)
     , AdjacencyMatrix (..)
     , LabelVector (..)
+    , secondLeft
     , spectral
     , spectralCluster
     , spectralClusterK
@@ -27,7 +28,7 @@
 import Data.Bool (bool)
 import Data.Maybe (fromMaybe)
 import Data.Function (on)
-import Data.List (sortBy, foldl1', maximumBy, transpose)
+import Data.List (sortBy, foldl1', foldl', maximumBy, transpose)
 import Safe (headMay)
 import qualified AI.Clustering.KMeans as K
 import qualified Data.Map.Strict as Map
@@ -63,63 +64,54 @@
 b1ToB2 :: B1 -> B2
 b1ToB2 (B1 b1) =
     B2
-        . S.fromListSM (n, m)
-        . fmap (\ (!i, !j, !x)
-               -> (i, j, (log (fromIntegral n / (S.lookupDenseSV j dVec))) * x)
-               )
-        . S.toListSM
+        . S.sparsifySM
+        . S.imapSM (\ _ !j !x -> (log (n / getValD j)) * x)
         $ b1
   where
-    dVec :: S.SpVector Double
-    dVec = S.vr
-         . fmap (sum . fmap (\x -> if x > 0 then 1 else 0))
+    getValD j = fromMaybe (error $ "b1ToB2: Column not found: " <> show j <> " from vector of length " <> show (U.length dVec) <> " in matrix of dim " <> show (S.dimSM b1))
+              $ dVec U.!? j
+    dVec :: U.Vector Double
+    dVec = U.fromList
+         . fmap (foldl' (+) 0 . fmap (\x -> if x > 0 then 1 else 0))
          . S.toRowsL -- faster than toColsL.
          . S.transposeSM
          $ b1
-    n = S.nrows b1
+    n = fromIntegral $ S.nrows b1
     m = S.ncols b1
 
 -- | Euclidean norm each row.
 b2ToB :: B2 -> B
 b2ToB (B2 b2) =
     B
-        . S.fromListSM (n, m)
-        . fmap (\(!i, !j, !x) -> (i, j, x / (S.lookupDenseSV i eVec)))
-        . S.toListSM
+        . S.imapSM (\ !i _ !x -> x / (getValE i))
         $ b2
   where
-    eVec :: S.SpVector Double
-    eVec = S.vr . fmap S.norm2 . S.toRowsL $ b2
-    n = S.nrows b2
-    m = S.ncols b2
+    getValE i = fromMaybe (error $ "b2ToB: Row not found: " <> show i <> " from vector of length " <> show (U.length eVec) <> " in matrix of dim " <> show (S.dimSM b2))
+              $ eVec U.!? i
+    eVec :: U.Vector Double
+    eVec = U.fromList . fmap S.norm2 . S.toRowsL $ b2
 
 -- | Find the Euclidean norm of a vector.
 norm2 :: S.SpVector Double -> Double
-norm2 = sqrt . sum . fmap (** 2)
+norm2 = sqrt . foldl' (+) 0 . fmap (** 2)
 
 -- | Get the signed diagonal transformed B matrix.
 bToD :: B -> D
 bToD (B b) = D
-           -- . S.diagonalSM
            . flip S.extractCol 0
-           $ (fmap abs b)
-       S.#~# ((fmap abs $ S.transposeSM b) S.#~# (S.fromColsL [S.onesSV n]))
+           $ b'
+       S.#~# (S.transposeSM b' S.#~# (S.fromColsL [S.onesSV n]))
   where
+    b' = fmap abs b
     n = S.nrows b
 
 -- | Get the matrix C as input for SVD.
 bdToC :: B -> D -> C
-bdToC (B b) (D d) = C
-                  . S.fromListSM (S.dimSM b)
-                  . fmap (\ (!i, !j, !x)
-                        -> (i, j, (S.lookupDenseSV i d') * x)
-                        )
-                  . S.toListSM
-                  $ b
+bdToC (B b) (D d) = C . S.imapSM (\ !i _ !x -> (S.lookupDenseSV i d') * x) $ b
   where
     d' = S.sparsifySV $ fmap (\x -> x ** (-1 / 2)) d
 
--- | Obtain the second left singular vector (or N earlier) and E on of a sparse
+-- | Obtain the second left singular vector (or from N) and E on of a sparse
 -- matrix.
 secondLeft :: Int -> Int -> S.SpMatrix Double -> [S.SpVector Double]
 secondLeft n e m =
@@ -185,8 +177,7 @@
             . S.toRowsL
             . S.fromColsL
             . fmap S.normalize2
-            . S.toColsL
-            . S.transpose
+            . S.toRowsL
             . S.fromColsL
 
 -- | Consensus kmeans.
@@ -237,7 +228,7 @@
     lNorm    = i S.^+^ (S.transpose invRootD S.#~# (mat S.#~# invRootD))
     invRootD = S.diagonalSM
              . S.vr
-             . fmap ((\x -> if x == 0 then x else x ** (- 1 / 2)) . sum)
+             . fmap ((\x -> if x == 0 then x else x ** (- 1 / 2)) . foldl' (+) 0)
              . S.toRowsL
              . fmap abs -- signed diagonal
              $ mat
