packages feed

sparse-linear-algebra 0.2.0.5 → 0.2.0.7

raw patch · 11 files changed

+673/−246 lines, 11 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.Sparse.Common: extractDiagonalDSM :: Num a => SpMatrix a -> SpVector a
- Data.Sparse.SpMatrix: validIxSM :: SpMatrix a -> (Int, Int) -> Bool
- Numeric.LinearAlgebra.Data: type Cols = Int
- Numeric.LinearAlgebra.Data: type IxCol = Int
- Numeric.LinearAlgebra.Data: type IxRow = Int
- Numeric.LinearAlgebra.Data: type Rows = Int
- Numeric.LinearAlgebra.Sparse: BCG :: SpVector Double -> BCG
- Numeric.LinearAlgebra.Sparse: BCG_ :: LinSolveMethod
- Numeric.LinearAlgebra.Sparse: BICGSTAB :: SpVector Double -> BICGSTAB
- Numeric.LinearAlgebra.Sparse: BICGSTAB_ :: LinSolveMethod
- Numeric.LinearAlgebra.Sparse: CGS :: SpVector Double -> CGS
- Numeric.LinearAlgebra.Sparse: CGS_ :: LinSolveMethod
- Numeric.LinearAlgebra.Sparse: [_x, _r, _p, _u] :: CGS -> SpVector Double
- Numeric.LinearAlgebra.Sparse: [_xBcg, _rBcg, _rHatBcg, _pBcg, _pHatBcg] :: BCG -> SpVector Double
- Numeric.LinearAlgebra.Sparse: [_xBicgstab, _rBicgstab, _pBicgstab] :: BICGSTAB -> SpVector Double
- Numeric.LinearAlgebra.Sparse: bcgStep :: SpMatrix Double -> BCG -> BCG
- Numeric.LinearAlgebra.Sparse: candidateRows :: IntMap (IntMap a) -> IxRow -> IxCol -> Maybe [Key]
- Numeric.LinearAlgebra.Sparse: class PrintDense a
- Numeric.LinearAlgebra.Sparse: firstNonZeroColumn :: IntMap a -> IxRow -> Bool
- Numeric.LinearAlgebra.Sparse: givensCoef :: (Ord a, Floating a) => a -> a -> (a, a, a)
- Numeric.LinearAlgebra.Sparse: gmats :: SpMatrix Double -> [SpMatrix Double]
- Numeric.LinearAlgebra.Sparse: hhV :: SpVector Double -> (SpVector Double, Double)
- Numeric.LinearAlgebra.Sparse: hypot :: Floating a => a -> a -> a
- Numeric.LinearAlgebra.Sparse: instance (GHC.Show.Show a, GHC.Num.Num a) => Numeric.LinearAlgebra.Sparse.PrintDense (Data.Sparse.SpMatrix.SpMatrix a)
- Numeric.LinearAlgebra.Sparse: instance (GHC.Show.Show a, GHC.Num.Num a) => Numeric.LinearAlgebra.Sparse.PrintDense (Data.Sparse.SpVector.SpVector a)
- Numeric.LinearAlgebra.Sparse: loopUntilAcc :: Int -> ([t] -> Bool) -> (t -> t) -> t -> t
- Numeric.LinearAlgebra.Sparse: meanl :: (Foldable t, Fractional a) => t a -> a
- Numeric.LinearAlgebra.Sparse: modifyUntil :: MonadState s m => (s -> Bool) -> (s -> s) -> m s
- Numeric.LinearAlgebra.Sparse: newline :: IO ()
- Numeric.LinearAlgebra.Sparse: norm2l :: (Foldable t, Functor t, Floating a) => t a -> a
- Numeric.LinearAlgebra.Sparse: normDiffConverged :: (Foldable t, Functor t) => (a -> SpVector Double) -> t a -> Bool
- Numeric.LinearAlgebra.Sparse: permutAA :: Num b => SpMatrix a -> IxRow -> IxCol -> Maybe (SpMatrix b)
- Numeric.LinearAlgebra.Sparse: pinv :: SpMatrix Double -> SpVector Double -> SpVector Double
- Numeric.LinearAlgebra.Sparse: prd :: PrintDense a => a -> IO ()
- Numeric.LinearAlgebra.Sparse: printDenseSM :: (Show t, Num t) => SpMatrix t -> IO ()
- Numeric.LinearAlgebra.Sparse: printDenseSV :: (Show t, Num t) => SpVector t -> IO ()
- Numeric.LinearAlgebra.Sparse: runAppendN :: ([t] -> Bool) -> (t -> t) -> Int -> t -> [t]
- Numeric.LinearAlgebra.Sparse: showNonZero :: (Show a, Num a, Eq a) => a -> String
- Numeric.LinearAlgebra.Sparse: sign :: (Ord a, Num a) => a -> a
- Numeric.LinearAlgebra.Sparse: toDenseListClip :: (Show a, Num a) => SpVector a -> Int -> String
- Numeric.LinearAlgebra.Sparse: toDenseRow :: Num a => SpMatrix a -> Key -> [a]
- Numeric.LinearAlgebra.Sparse: toDenseRowClip :: (Show a, Num a) => SpMatrix a -> Key -> Int -> String
- Numeric.LinearAlgebra.Sparse: untilConverged :: MonadState a m => (a -> SpVector Double) -> (a -> a) -> m a
+ Data.Sparse.Common: extractColDense :: Num a => SpMatrix a -> IxCol -> SpVector a
+ Data.Sparse.Common: extractDiagDense :: Num a => SpMatrix a -> SpVector a
+ Data.Sparse.Common: extractRowDense :: Num a => SpMatrix a -> IxRow -> SpVector a
+ Data.Sparse.Common: extractSubCol :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpVector a
+ Data.Sparse.Common: extractSubCol_RK :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpVector a
+ Data.Sparse.Common: extractSubRow :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpVector a
+ Data.Sparse.Common: extractSubRow_RK :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpVector a
+ Data.Sparse.Common: extractVectorDenseWith :: Num a => (Int -> (IxRow, IxCol)) -> SpMatrix a -> SpVector a
+ Data.Sparse.Common: insertCol :: SpMatrix a -> SpVector a -> IxCol -> SpMatrix a
+ Data.Sparse.Common: insertColWith :: (IxRow -> IxRow) -> SpMatrix a -> SpVector a -> IxCol -> SpMatrix a
+ Data.Sparse.Common: insertRow :: SpMatrix a -> SpVector a -> Key -> SpMatrix a
+ Data.Sparse.Common: insertRowWith :: (IxCol -> IxCol) -> SpMatrix a -> SpVector a -> Key -> SpMatrix a
+ Data.Sparse.Common: instance (GHC.Show.Show a, GHC.Num.Num a) => Data.Sparse.Common.PrintDense (Data.Sparse.SpMatrix.SpMatrix a)
+ Data.Sparse.Common: instance (GHC.Show.Show a, GHC.Num.Num a) => Data.Sparse.Common.PrintDense (Data.Sparse.SpVector.SpVector a)
+ Data.Sparse.Common: prd :: PrintDense a => a -> IO ()
+ Data.Sparse.SpMatrix: (@@!) :: Num a => SpMatrix a -> (IxRow, IxCol) -> a
+ Data.Sparse.SpMatrix: contractSub :: Num a => SpMatrix a -> SpMatrix a -> IxRow -> IxCol -> Int -> a
+ Data.Sparse.SpMatrix: extractSubColSM :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubColSM_RK :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubRowSM :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubRowSM_RK :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubmatrix :: SpMatrix a -> (IxRow, IxRow) -> (IxCol, IxCol) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubmatrixRebalanceKeys :: SpMatrix a -> (IxRow, IxRow) -> (IxCol, IxCol) -> SpMatrix a
+ Data.Sparse.SpMatrix: isValidIxSM :: SpMatrix a -> (Int, Int) -> Bool
+ Data.Sparse.SpVector: nzSV :: SpVector a -> Int
+ Data.Sparse.SpVector: sizeStrSV :: SpVector a -> String
+ Data.Sparse.Types: type Cols = Int
+ Data.Sparse.Types: type IxCol = Int
+ Data.Sparse.Types: type IxRow = Int
+ Data.Sparse.Types: type Rows = Int
+ Numeric.Eps: isNz :: Double -> Bool
+ Numeric.LinearAlgebra.Sparse: _x :: CGS -> SpVector Double
+ Numeric.LinearAlgebra.Sparse: _xBcg :: BCG -> SpVector Double
+ Numeric.LinearAlgebra.Sparse: _xBicgstab :: BICGSTAB -> SpVector Double
+ Numeric.LinearAlgebra.Sparse: _xCgne :: CGNE -> SpVector Double
+ Numeric.LinearAlgebra.Sparse: _xTfq :: TFQMR -> SpVector Double
+ Numeric.LinearAlgebra.Sparse: cgne :: SpMatrix Double -> SpVector Double -> SpVector Double -> CGNE
+ Numeric.LinearAlgebra.Sparse: data CGNE
+ Numeric.LinearAlgebra.Sparse: data TFQMR
+ Numeric.LinearAlgebra.Sparse: instance GHC.Classes.Eq Numeric.LinearAlgebra.Sparse.CGNE
+ Numeric.LinearAlgebra.Sparse: instance GHC.Classes.Eq Numeric.LinearAlgebra.Sparse.TFQMR
+ Numeric.LinearAlgebra.Sparse: lu :: SpMatrix Double -> (SpMatrix Double, SpMatrix Double)
+ Numeric.LinearAlgebra.Sparse: tfqmr :: SpMatrix Double -> SpVector Double -> SpVector Double -> TFQMR
- Data.Sparse.SpMatrix: extractSubmatrixSM :: SpMatrix a -> (IxRow, IxCol) -> (IxRow, IxCol) -> SpMatrix a
+ Data.Sparse.SpMatrix: extractSubmatrixSM :: (Key -> Key) -> (Key -> Key) -> SpMatrix a -> (IxRow, IxRow) -> (IxCol, IxCol) -> SpMatrix a

Files

README.md view
@@ -16,10 +16,14 @@      * BiConjugate Gradient Stabilized (BiCGSTAB) (non-Hermitian systems) +    * Transpose-Free Quasi-Minimal Residual (TFQMR)+ * Matrix decompositions      * QR factorization +    * LU factorization+ * Eigenvalue algorithms      * QR algorithm@@ -29,6 +33,60 @@ * Utilities : Vector and matrix norms, matrix condition number, Givens rotation, Householder reflection  * Predicates : Matrix orthogonality test (A^T A ~= I)+++---------++## Examples++The module `Numeric.LinearAlgebra.Sparse` contains the interface functions:++To create a sparse matrix from an array of its entries we use `fromListSM` :++    fromListSM :: Foldable t => (Int, Int) -> t (IxRow, IxCol, a) -> SpMatrix a++e.g.++    > amat = fromListSM (3,3) [(0,0,2),(1,0,4),(1,1,3),(1,2,2),(2,2,5)]++And similarly for sparse vectors : `fromListSV :: Int -> [(Int, a)] -> SpVector a`.++Both sparse vectors and matrices can be pretty-printed using `prd`:++    > prd amat+    ( 3 rows, 3 columns ) , 5 NZ ( sparsity 0.5555555555555556 )++    [2,0,0]+    [4,3,2]+    [0,0,5]+++Matrix factorizations are available as `lu` and `qr` respectively, and are straightforward to verify by using the matrix product `##`  :++    > (l, u) = lu amat+    > prd $ l ## u+    ( 3 rows, 3 columns ) , 9 NZ ( sparsity 1.0 )++    [2.0,0.0,0.0]+    [4.0,3.0,2.0]+    [0.0,0.0,5.0]++Linear systems can be solved with either `linSolve` (which also requires choosing a method) or with `<\>` (which uses BiCGSTAB as default) :++    > b = fromListSV 3 [(0,3),(1,2),(2,5)]+    > x = amat <\> b+    > prd x+    ( 3 elements ) ,  3 NZ ( sparsity 1.0 )++    [1.4999999999999998,-1.9999999999999998,0.9999999999999998]++The result can be verified by computing the matrix-vector action `amat #> x`, which should (ideally) be very close to the right-hand side `b` :++    > prd $ amat #> x+    ( 3 elements ) ,  3 NZ ( sparsity 1.0 )++    [2.9999999999999996,1.9999999999999996,4.999999999999999]+   
sparse-linear-algebra.cabal view
@@ -1,7 +1,7 @@ name:                sparse-linear-algebra-version:             0.2.0.5+version:             0.2.0.7 synopsis:            Numerical computation in native Haskell -description:         Currently it provides iterative linear solvers, matrix decompositions, eigenvalue computations and related utilities. Please see README.md for details+description:         Currently the library provides iterative linear solvers, matrix decompositions, eigenvalue computations and related utilities. Please see README.md for details homepage:            https://github.com/ocramz/sparse-linear-algebra license:             GPL-3 license-file:        LICENSE@@ -20,12 +20,12 @@   hs-source-dirs:      src   exposed-modules:     Numeric.LinearAlgebra.Sparse                        Numeric.LinearAlgebra.Class-                       Numeric.LinearAlgebra.Data                        Numeric.LinearAlgebra.Sparse.IntMap                        Data.Sparse.SpVector                        Data.Sparse.SpMatrix                        Data.Sparse.Common                        Data.Sparse.Utils+                       Data.Sparse.Types                        Numeric.Eps   build-depends:       QuickCheck                      , base >= 4.7 && < 5
src/Data/Sparse/Common.hs view
@@ -1,28 +1,64 @@ module Data.Sparse.Common        ( module X,-         svToSM, outerProdSV, (><), toSV, extractCol, extractRow,-         extractDiagonalDSM,-         matVec, (#>), vecMat, (<#)) where+         insertRowWith, insertRow, insertColWith, insertCol,+         outerProdSV, (><), toSV, svToSM, +         extractCol, extractRow,+         extractVectorDenseWith, extractRowDense, extractColDense,+         extractDiagDense,+         extractSubRow, extractSubCol,+         extractSubRow_RK, extractSubCol_RK,+         matVec, (#>), vecMat, (<#),+         prd) where  import Data.Sparse.Utils as X+import Data.Sparse.Types as X import Data.Sparse.SpMatrix as X import Data.Sparse.SpVector as X  import Numeric.Eps as X-import Numeric.LinearAlgebra.Data as X import Numeric.LinearAlgebra.Class as X  import Numeric.LinearAlgebra.Sparse.IntMap as X  import qualified Data.IntMap as IM --- | promote a SV to SM-svToSM :: SpVector a -> SpMatrix a-svToSM (SV n d) = SM (n, 1) $ IM.singleton 0 d  --- ** Outer vector product+-- * Insert row/column vector in matrix +-- | Insert row , using the provided row index transformation function+insertRowWith :: (IxCol -> IxCol) -> SpMatrix a -> SpVector a -> IM.Key -> SpMatrix a+insertRowWith fj (SM (m,n) im) (SV d sv) i+  | not (inBounds0 m i) = error "insertRowSM : index out of bounds"+  | n >= d = SM (m,n) $ IM.insert i (insertOrUnion i sv' im) im+  | otherwise = error $ "insertRowSM : incompatible dimensions " ++ show (n, d)+    where sv' = IM.mapKeys fj sv+          insertOrUnion i sv im = maybe sv (IM.union sv) (IM.lookup i im)++-- | Insert row          +insertRow :: SpMatrix a -> SpVector a -> IM.Key -> SpMatrix a+insertRow = insertRowWith id++-- | Insert column, using the provided row index transformation function+insertColWith :: (IxRow -> IxRow) -> SpMatrix a -> SpVector a -> IxCol -> SpMatrix a+insertColWith fi smm sv j+  | not (inBounds0 n j) = error "insertColSM : index out of bounds"+  | m >= mv = insIM2 smm vl j+  | otherwise = error $ "insertColSM : incompatible dimensions " ++ show (m,mv) where+      (m, n) = dim smm+      mv = dim sv+      vl = toListSV sv+      insIM2 im2 ((i,x):xs) j = insIM2 (insertSpMatrix (fi i) j x im2) xs j+      insIM2 im2 [] _ = im2++-- | Insert column+insertCol :: SpMatrix a -> SpVector a -> IxCol -> SpMatrix a+insertCol = insertColWith id++++-- * Outer vector product+ outerProdSV, (><) :: Num a => SpVector a -> SpVector a -> SpMatrix a outerProdSV v1 v2 = fromListSM (m, n) ixy where   m = dim v1@@ -33,39 +69,79 @@   +-- * Matrix-vector conversions++-- | promote a SV to SM+svToSM :: SpVector a -> SpMatrix a+svToSM (SV n d) = SM (n, 1) $ IM.singleton 0 d+ -- |Demote (n x 1) or (1 x n) SpMatrix to SpVector toSV :: SpMatrix a -> SpVector a-toSV (SM (m,n) im) = SV d $ snd . head $ IM.toList im where+toSV (SM (m,n) im) = SV d (ff im) where+  ff | m > n = IM.map g  -- column case+     | otherwise = g+  g = snd . head . IM.toList   d | m==1 && n==1 = 1     | m==1 && n>1 = n      | n==1 && m>1 = m-    | otherwise = error $ "toSV : incompatible dimensions " ++ show (m,n)+    | otherwise = error $ "toSV : incompatible matrix dimension " ++ show (m,n) --- |Extract jth column, and place into SpVector-extractCol :: SpMatrix a -> IxCol -> SpVector a-extractCol m j = toSV $ extractColSM m j       +-- * Extract a SpVector from an SpMatrix+-- ** Sparse extract --- |Extract ith row, and place into SpVector+-- |Extract ith row extractRow :: SpMatrix a -> IxRow -> SpVector a extractRow m i = toSV $ extractRowSM m i +-- |Extract jth column+extractCol :: SpMatrix a -> IxCol -> SpVector a+extractCol m j = toSV $ extractColSM m j         +-- ** Dense extract (default == 0)+-- | Generic extraction function+extractVectorDenseWith ::+  Num a => (Int -> (IxRow, IxCol)) -> SpMatrix a -> SpVector a+extractVectorDenseWith f mm = fromListDenseSV n $ foldr ins [] ll  where+  ll = [0 .. n - 1]+  (m, n) = dim mm+  ins i acc = mm @@ f i : acc +-- | Extract ith row (dense)+extractRowDense :: Num a => SpMatrix a -> IxRow -> SpVector a+extractRowDense mm iref = extractVectorDenseWith (\j -> (iref, j)) mm +-- | Extract jth column+extractColDense :: Num a => SpMatrix a -> IxCol -> SpVector a+extractColDense mm jref = extractVectorDenseWith (\i -> (i, jref)) mm --- | Extract the diagonal as a SpVector (with default 0)-extractDiagonalDSM :: Num a => SpMatrix a -> SpVector a-extractDiagonalDSM mm = fromListDenseSV n $ foldr ins [] ll  where-  ll = [0 .. n - 1]-  n = nrows mm-  ins i acc = mm@@(i,i) : acc+-- | Extract the diagonal+extractDiagDense :: Num a => SpMatrix a -> SpVector a+extractDiagDense = extractVectorDenseWith (\i -> (i, i))   +-- | extract row interval+extractSubRow :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpVector a+extractSubRow m i (j1, j2)  = toSV $ extractSubRowSM m i (j1, j2) +-- | extract row interval, rebalance keys by subtracting lowest one+extractSubRow_RK :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpVector a+extractSubRow_RK m i (j1, j2)  = toSV $ extractSubRowSM_RK m i (j1, j2)++-- | extract column interval+extractSubCol :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpVector a+extractSubCol m j (i1, i2)  = toSV $ extractSubColSM m j (i1, i2)++-- | extract column interval, rebalance keys by subtracting lowest one+extractSubCol_RK :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpVector a+extractSubCol_RK m j (i1, i2)  = toSV $ extractSubColSM_RK m j (i1, i2)++++ -- ** Matrix action on a vector  {- @@ -92,3 +168,99 @@   | otherwise = error $ "vecMat : mismatching dimensions " ++ show (n, nr)  (<#) = vecMat  +++++++-- * Pretty printing+++showNonZero :: (Show a, Num a, Eq a) => a -> String+showNonZero x  = if x == 0 then " " else show x+++toDenseRow :: Num a => SpMatrix a -> IM.Key -> [a]+toDenseRow (SM (_,ncol) im) irow =+  fmap (\icol -> im `lookupWD_IM` (irow,icol)) [0..ncol-1]++toDenseRowClip :: (Show a, Num a) => SpMatrix a -> IM.Key -> Int -> String+toDenseRowClip sm irow ncomax+  | ncols sm > ncomax = unwords (map show h) ++  " ... " ++ show t+  | otherwise = show dr+     where dr = toDenseRow sm irow+           h = take (ncomax - 2) dr+           t = last dr++newline :: IO ()+newline = putStrLn ""++printDenseSM :: (Show t, Num t) => SpMatrix t -> IO ()+printDenseSM sm = do+  newline+  putStrLn $ sizeStr sm+  newline+  printDenseSM' sm 5 5+  newline+  where    +    printDenseSM' :: (Show t, Num t) => SpMatrix t -> Int -> Int -> IO ()+    printDenseSM' sm'@(SM (nr,_) _) nromax ncomax = mapM_ putStrLn rr_' where+      rr_ = map (\i -> toDenseRowClip sm' i ncomax) [0..nr - 1]+      rr_' | nrows sm > nromax = take (nromax - 2) rr_ ++ [" ... "] ++[last rr_]+           | otherwise = rr_+++toDenseListClip :: (Show a, Num a) => SpVector a -> Int -> String+toDenseListClip sv ncomax+  | dim sv > ncomax = unwords (map show h) ++  " ... " ++ show t+  | otherwise = show dr+     where dr = toDenseListSV sv+           h = take (ncomax - 2) dr+           t = last dr++printDenseSV :: (Show t, Num t) => SpVector t -> IO ()+printDenseSV sv = do+  newline+  putStrLn $ sizeStrSV sv+  newline+  printDenseSV' sv 5+  newline where+    printDenseSV' v nco = putStrLn rr_' where+      rr_ = toDenseListClip v nco :: String+      rr_' | dim sv > nco = unwords [take (nco - 2) rr_ , " ... " , [last rr_]]+           | otherwise = rr_++-- ** Pretty printer typeclass+class PrintDense a where+  prd :: a -> IO ()++instance (Show a, Num a) => PrintDense (SpVector a) where+  prd = printDenseSV++instance (Show a, Num a) => PrintDense (SpMatrix a) where+  prd = printDenseSM++++  ++++++++++++++++++++  
src/Data/Sparse/SpMatrix.hs view
@@ -2,12 +2,10 @@ module Data.Sparse.SpMatrix where  import Data.Sparse.Utils--import Data.Sparse.Utils+import Data.Sparse.Types  import Numeric.Eps import Numeric.LinearAlgebra.Class-import Numeric.LinearAlgebra.Data  import Numeric.LinearAlgebra.Sparse.IntMap @@ -184,19 +182,23 @@  -- | Looks up an element in the matrix with a default (if the element is not found, zero is returned) -lookupWD_SM, (@@) :: Num a => SpMatrix a -> (IxRow, IxCol) -> a+lookupWD_SM, (@@!), (@@) :: Num a => SpMatrix a -> (IxRow, IxCol) -> a lookupWD_SM sm (i,j) =   fromMaybe 0 (lookupSM sm i j)  lookupWD_IM :: Num a => IM.IntMap (IM.IntMap a) -> (IxRow, IxCol) -> a lookupWD_IM im (i,j) = fromMaybe 0 (IM.lookup i im >>= IM.lookup j) --- | Zero-default lookup, infix form-(@@) = lookupWD_SM+-- | Zero-default lookup, infix form (no bound checking)+(@@!) = lookupWD_SM +-- | Zero-default lookup, infix form ("safe" : throws exception if lookup is outside matrix bounds)+m @@ d | isValidIxSM m d = m @@! d+       | otherwise = error $ "@@ : incompatible indices : matrix size is " ++ show (dim m) ++ ", but user looked up " ++ show d   + -- FIXME : to throw an exception or just ignore the out-of-bound access ?  @@ -207,12 +209,18 @@  -- ** Sub-matrices --- | Extract a submatrix given the specified index bounds-extractSubmatrixSM :: SpMatrix a -> (IxRow, IxCol) -> (IxRow, IxCol) -> SpMatrix a-extractSubmatrixSM (SM (r, c) im) (i1, i2) (j1, j2)++-- | Extract a submatrix given the specified index bounds, rebalancing keys with the two supplied functions+extractSubmatrixSM ::+  (IM.Key -> IM.Key) ->   -- row index function+  (IM.Key -> IM.Key) ->   -- column "  "+  SpMatrix a ->+  (IxRow, IxRow) -> (IxCol, IxCol) ->+  SpMatrix a+extractSubmatrixSM fi gi (SM (r, c) im) (i1, i2) (j1, j2)   | q = SM (m', n') imm'-  | otherwise = error $ "extractSubmatrixSM : invalid indexing " ++ show (i1, i2) ++ ", " ++ show (j1, j2) where-  imm' = mapKeysIM2 (\i -> i - i1) (\j -> j - j1) $  -- rebalance keys+  | otherwise = error $ "extractSubmatrixSM : invalid index " ++ show (i1, i2) ++ ", " ++ show (j1, j2) where+  imm' = mapKeysIM2 fi gi $                          -- rebalance keys           IM.filter (not . IM.null) $                -- remove all-null rows           ifilterIM2 ff im                           -- keep `submatrix`   ff i j _ = i1 <= i &&@@ -226,19 +234,52 @@       inBounds0 c j2 &&             i2 >= i1 +-- | Extract a submatrix given the specified index bounds+-- NB : subtracts (i1, j1) from the indices+extractSubmatrixRebalanceKeys ::+  SpMatrix a -> (IxRow, IxRow) -> (IxCol, IxCol) -> SpMatrix a+extractSubmatrixRebalanceKeys mm (i1,i2) (j1,j2) =+  extractSubmatrixSM (\i -> i - i1) (\j -> j - j1) mm (i1,i2) (j1,j2) +-- | Extract a submatrix given the specified index bounds+-- NB : submatrix indices are _preserved_+extractSubmatrix :: SpMatrix a -> (IxRow, IxRow) -> (IxCol, IxCol) -> SpMatrix a+extractSubmatrix = extractSubmatrixSM id id  +++-- *** Extract i'th row+extractRowSM :: SpMatrix a -> IxRow -> SpMatrix a+extractRowSM sm i = extractSubmatrix sm (i, i) (0, ncols sm - 1)+++-- | Extract column within a row range+extractSubRowSM :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpMatrix a+extractSubRowSM sm i (j1, j2) = extractSubmatrix sm (i, i) (j1, j2)++-- | Extract column within a row range, rebalance keys+extractSubRowSM_RK :: SpMatrix a -> IxRow -> (IxCol, IxCol) -> SpMatrix a+extractSubRowSM_RK sm i =+  extractSubmatrixRebalanceKeys sm (i, i) +++ -- *** Extract j'th column+-- | Extract all column extractColSM :: SpMatrix a -> IxCol -> SpMatrix a-extractColSM sm j = extractSubmatrixSM sm (0, nrows sm - 1) (j, j)+extractColSM sm j = extractSubmatrix sm (0, nrows sm - 1) (j, j) +-- | Extract column within a row range+extractSubColSM :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpMatrix a+extractSubColSM sm j (i1, i2) = extractSubmatrix sm (i1, i2) (j, j)  +-- | Extract column within a row range, rebalance keys+extractSubColSM_RK :: SpMatrix a -> IxCol -> (IxRow, IxRow) -> SpMatrix a+extractSubColSM_RK sm j (i1, i2) =+  extractSubmatrixRebalanceKeys sm (i1, i2) (j, j)  --- *** Extract i'th row-extractRowSM :: SpMatrix a -> IxRow -> SpMatrix a-extractRowSM sm i = extractSubmatrixSM sm (i, i) (0, ncols sm - 1)   @@ -255,8 +296,8 @@  -- ** Predicates -- |Are the supplied indices within matrix bounds?-validIxSM :: SpMatrix a -> (Int, Int) -> Bool-validIxSM mm = inBounds02 (dim mm)+isValidIxSM :: SpMatrix a -> (Int, Int) -> Bool+isValidIxSM mm = inBounds02 (dim mm)  -- |Is the matrix square? isSquareSM :: SpMatrix a -> Bool@@ -626,4 +667,12 @@   -+-- *** Matrix contraction+-- | Contract two matrices A and B up to an index `n`, i.e. summing over repeated indices: +-- Aij Bjk , for j in [0 .. n] +contractSub :: Num a => SpMatrix a -> SpMatrix a -> IxRow -> IxCol -> Int -> a+contractSub a b i j n+  | ncols a == nrows b &&+    isValidIxSM a (i,j) &&+    n <= ncols a = sum $ map (\i' -> a@@!(i,i')*b@@!(i',j)) [0 .. n]+  | otherwise = error "contractSub : n must be <= i"
src/Data/Sparse/SpVector.hs view
@@ -2,9 +2,9 @@ module Data.Sparse.SpVector where  import Data.Sparse.Utils+import Data.Sparse.Types  import Numeric.LinearAlgebra.Class-import Numeric.LinearAlgebra.Data import Numeric.LinearAlgebra.Sparse.IntMap  import Data.Maybe@@ -21,8 +21,13 @@ spySV :: Fractional b => SpVector a -> b spySV s = fromIntegral (IM.size (dat s)) / fromIntegral (dim s) +-- | Number of nonzeros+nzSV :: SpVector a -> Int+nzSV sv = IM.size (dat sv)  +sizeStrSV :: SpVector a -> String+sizeStrSV sv = unwords ["(",show (dim sv),"elements ) , ",show (nzSV sv),"NZ ( sparsity", show (spy sv),")"]   
+ src/Data/Sparse/Types.hs view
@@ -0,0 +1,7 @@+module Data.Sparse.Types where++type Rows = Int+type Cols = Int++type IxRow = Int+type IxCol = Int
src/Numeric/Eps.hs view
@@ -15,6 +15,9 @@ almostZero x = abs x <= eps almostOne x = x >= (1-eps) && x < (1+eps) +isNz :: Double -> Bool+isNz = not . almostZero+ withDefault :: (t -> Bool) -> t -> t -> t withDefault q d x | q x = d                   | otherwise = x
− src/Numeric/LinearAlgebra/Data.hs
@@ -1,7 +0,0 @@-module Numeric.LinearAlgebra.Data where--type Rows = Int-type Cols = Int--type IxRow = Int-type IxCol = Int
src/Numeric/LinearAlgebra/Sparse.hs view
@@ -1,6 +1,23 @@ {-# LANGUAGE FlexibleContexts, TypeFamilies, MultiParamTypeClasses, FlexibleInstances  #-} -- {-# OPTIONS_GHC -O2 -rtsopts -with-rtsopts=-K32m -prof#-}-module Numeric.LinearAlgebra.Sparse where+module Numeric.LinearAlgebra.Sparse+       (+         sparsifySV,+         conditionNumberSM,+         hhMat, hhRefl,+         givens,+         eigsQR, eigRayleigh,+         cgne, tfqmr, bicgstab, cgs, bcg,+         _xCgne, _xTfq, _xBicgstab, _x, _xBcg,+         cgsStep, bicgstabStep,+         CGNE, TFQMR, BICGSTAB, CGS, BCG,+         linSolve, LinSolveMethod, (<\>),+         randMat, randVec, randSpMat, randSpVec,+         modifyInspectN, runAppendN',+         diffSqL,+         qr, lu+       )+       where   import Data.Sparse.Common@@ -9,7 +26,7 @@ import Control.Monad.Primitive import Control.Monad (mapM_, forM_, replicateM) import Control.Monad.State.Strict--- import Control.Monad.Writer+import Control.Monad.Writer -- import Control.Monad.Trans -- import Control.Monad.Trans.State (runStateT) -- import Control.Monad.Trans.Writer (runWriterT)@@ -49,7 +66,7 @@                     | otherwise = kappa where   kappa = lmax / lmin   (_, r) = qr m-  u = extractDiagonalDSM r  -- FIXME : need to extract with default element 0 +  u = extractDiagDense r  -- FIXME : need to extract with default element 0    lmax = abs (maximum u)   lmin = abs (minimum u) @@ -118,7 +135,7 @@  givens :: SpMatrix Double -> IxRow -> IxCol -> SpMatrix Double givens mm i j -  | validIxSM mm (i,j) && isSquareSM mm =+  | isValidIxSM mm (i,j) && isSquareSM mm =        sparsifySM $ fromListSM' [(i,i,c),(j,j,c),(j,i,-s),(i,j,s)] (eye (nrows mm))   | otherwise = error "givens : indices out of bounds"         where@@ -180,15 +197,15 @@  -- * Eigenvalue algorithms --- ** All eigenvalues (QR algorithm)+-- ** QR algorithm --- | `eigsQR n mm` performs `n` iterations of the QR algorithm on matrix `mm` +-- | `eigsQR n mm` performs `n` iterations of the QR algorithm on matrix `mm`, and returns a SpVector containing all eigenvalues eigsQR :: Int -> SpMatrix Double -> SpVector Double-eigsQR nitermax m = extractDiagonalDSM $ execState (convergtest eigsStep) m where+eigsQR nitermax m = extractDiagDense $ execState (convergtest eigsStep) m where   eigsStep m = r #~# q where (q, r) = qr m   convergtest g = modifyInspectN nitermax f g where-    f [m1, m2] = let dm1 = extractDiagonalDSM m1-                     dm2 = extractDiagonalDSM m2+    f [m1, m2] = let dm1 = extractDiagDense m1+                     dm2 = extractDiagDense m2                  in norm2 (dm1 ^-^ dm2) <= eps  @@ -196,10 +213,9 @@   --- ** One eigenvalue and eigenvector (Rayleigh iteration)-+-- ** Rayleigh iteration --- | `eigsRayleigh n mm` performs `n` iterations of the Rayleigh algorithm on matrix `mm`. Cubic-order convergence, but it requires a mildly educated guess on the initial eigenpair+-- | `eigsRayleigh n mm` performs `n` iterations of the Rayleigh algorithm on matrix `mm` and returns the eigenpair closest to the initialization. It displays cubic-order convergence, but it also requires an educated guess on the initial eigenpair eigRayleigh :: Int                -- max # iterations      -> SpMatrix Double           -- matrix      -> (SpVector Double, Double) -- initial guess of (eigenvector, eigenvalue)@@ -272,22 +288,131 @@   -- * LU factorization-+-- ** Doolittle algorithm {- Doolittle algorithm for factoring A' = P A, where P is a permutation matrix such that A' has a nonzero as its (0, 0) entry -} +-- | LU factors+lu :: SpMatrix Double -> (SpMatrix Double, SpMatrix Double)+lu aa = (lfin, ufin) where+  (ixf,lf,uf) = execState (modifyUntil q (luUpd aa)) (luInit aa)+  lfin = lf+  ufin = uUpd aa (ixf, lf, uf)+  q (i, _, _) = i == (nrows aa - 1) --- lu aa | isSquareSM aa = undefined---       | otherwise = error "LU factorization not currently defined for rectangular matrices" where---           n = nrows aa---           l0 = eye n---           aa0 = +-- | First iteration of LU+luInit ::+  (Num t, Fractional a) => SpMatrix a -> (t, SpMatrix a, SpMatrix a)+luInit aa = (1, l0, u0) where+  n = nrows aa+  l0 = insertCol (eye n) ((1/u00) .* extractSubCol aa 0 (1,n - 1)) 0  -- initial L+  u0 = insertRow (zeroSM n n) (extractRow aa 0) 0               -- initial U+  u00 = u0 @@ (0,0)  -- make sure this is non-zero by applying permutation --- luStep aa i l u +-- | LU update step+luUpd :: SpMatrix Double+     -> (Int, SpMatrix Double, SpMatrix Double)+     -> (Int, SpMatrix Double, SpMatrix Double)+luUpd aa (i, l, u) = (i', l', u') where+  n = nrows aa  +  u' = uUpdSparse aa (i, l, u)  -- update U+  l' = lUpdSparse aa (i, l, u') -- update L+  i' = i + 1     -- increment i  +uUpd' ::+  Num a =>+  ([(Int, a)] -> [(Int, a)]) ->+  SpMatrix a ->+  (Rows, SpMatrix a, SpMatrix a) ->+  SpMatrix a+uUpd' ff amat (ix, lmat, umat) = insertRow umat uv ix where+  n = nrows amat+  colsix = [ix .. n - 1]+  us = ff $ zip colsix $ map (solveForUij amat lmat umat ix) colsix+  uv = fromListSV n us++uUpd :: Num a => SpMatrix a -> (Rows, SpMatrix a, SpMatrix a) -> SpMatrix a+uUpd = uUpd' id++-- update U while sparsifying+uUpdSparse ::+  SpMatrix Double -> (Rows, SpMatrix Double, SpMatrix Double) -> SpMatrix Double+uUpdSparse = uUpd' (filter (isNz . snd))+++++-- solve for element Uij+solveForUij ::+  Num a => SpMatrix a -> SpMatrix a -> SpMatrix a -> IxRow -> IxCol -> a+solveForUij amat lmat umat i j = a - p where+  a = amat @@! (i, j)+  p = contractSub lmat umat i j (i - 1)+++-- solve for element Lij+solveForLij ::+  SpMatrix Double -> SpMatrix Double -> SpMatrix Double -> IxRow -> IxCol -> Double+solveForLij amat lmat umat i j | isNz uii = (a - p)/uii+                               | otherwise = error $ unwords ["solveForLij : U",show (i,i)," is close to 0. Permute rows in order to have a nonzero diagonal of U"]+  where+   a = amat @@! (i, j)+   uii = umat @@! (i-1, i-1) -- NB this must be /= 0+   p = contractSub lmat umat i j (i - 1)+++++lUpd' :: ([(Rows, Double)] -> [(Int, Double)])+     -> SpMatrix Double+     -> (Rows, SpMatrix Double, SpMatrix Double)+     -> SpMatrix Double+lUpd' ff amat (ix, lmat, umat) = insertCol lmat lv ix where+  n = nrows amat+  rowsix = [ix + 1 .. n - 1]+  ls = ff $ zip rowsix $ map (\i -> solveForLij amat lmat umat i ix) rowsix+  lv = fromListSV n ls++lUpd :: SpMatrix Double -> (Rows, SpMatrix Double, SpMatrix Double) -> SpMatrix Double+lUpd = lUpd' id++lUpdSparse ::+  SpMatrix Double -> (Rows, SpMatrix Double, SpMatrix Double) -> SpMatrix Double+lUpdSparse = lUpd' (filter (isNz . snd))++++++++++++++++++++++-- test data++aa0 = fromListDenseSM 3 [2, -4, -4, -1, 6, -2, -2, 3, 8] :: SpMatrix Double+++++++ -- Produces the permutation matrix necessary to have a nonzero in position (iref, jref). This is used in the LU factorization-permutAA :: Num b => SpMatrix a -> IxRow -> IxCol -> Maybe (SpMatrix b)-permutAA (SM (nro,_) mm) iref jref+permutAA :: Num b => IxRow -> IxCol -> SpMatrix a -> Maybe (SpMatrix b)+permutAA iref jref (SM (nro,_) mm)    | isJust (lookupIM2 iref jref mm) = Nothing -- eye nro   | otherwise = Just $ permutationSM nro [head u] where       u = IM.keys (ifilterIM2 ff mm)@@ -302,19 +427,106 @@   +++-- * Incomplete LU++-- | used for Incomplete LU : remove entries in `m` corresponding to zero entries in `m2`+ripHoles :: SpMatrix t -> SpMatrix a -> SpMatrix a+ripHoles (SM d m) m2 = SM d $ ifilterIM2 f (dat m2) where+  f i j _ = isJust (lookupSM m2 i j)++++++++++++++ -- * Iterative linear solvers   --- -- | residual of candidate solution x0 of a linear system--- residual :: Num a => SpMatrix a -> SpVector a -> SpVector a -> SpVector a--- residual aa b x0 = b ^-^ (aa #> x0) --- converged :: SpMatrix Double -> SpVector Double -> SpVector Double -> Bool--- converged aa b x0 = normSq (residual aa b x0) <= eps+-- ** CGNE +cgneStep :: SpMatrix Double -> CGNE -> CGNE+cgneStep aa (CGNE x r p) = CGNE x1 r1 p1 where+  alphai = r `dot` r / (p `dot` p)+  x1 = x ^+^ (alphai .* p)+  r1 = r ^-^ (alphai .* (aa #> p))+  beta = r1 `dot` r1 / (r `dot` r)+  p1 = transposeSM aa #> r ^+^ (beta .* p) +data CGNE =+  CGNE {_xCgne , _rCgne, _pCgne :: SpVector Double} deriving Eq +cgne :: SpMatrix Double -> SpVector Double -> SpVector Double -> CGNE+cgne aa b x0 = execState (untilConverged _xCgne (cgneStep aa)) cgneInit where+  r0 = b ^-^ (aa #> x0)    -- residual of initial guess solution+  p0 = transposeSM aa #> r0+  cgneInit = CGNE x0 r0 p0+++-- ** TFQMR++-- | one step of TFQMR+tfqmrStep :: SpMatrix Double -> SpVector Double -> TFQMR -> TFQMR+tfqmrStep aa r0hat (TFQMR x w u v d m tau theta eta rho alpha) =+  TFQMR x1 w1 u1 v1 d1 (m+1) tau1 theta1 eta1 rho1 alpha1+  where+  -- alpham = alpha+  w1 = w ^-^ (alpha .* (aa #> u))+  d1 = u ^+^ ((theta**2/alpha*eta) .* d)+  theta1 = norm2 w1 / tau+  c = recip $ sqrt (1 + theta1**2)+  tau1 = tau * theta1 * c+  eta1 = c**2 * alpha+  x1 = x^+^ (eta1 .* d1)+  (alpha1, u1, rho1, v1)+    | even m = let+                   alpha' = rho / (v `dot` r0hat)+                   u' = u ^-^ (alpha' .* v)+               in+                   (alpha', u', rho, v)+    | otherwise = let+                   rho' = w1 `dot` r0hat+                   beta = rho'/rho+                   u' = w1 ^+^ (beta .* u)+                   v' = (aa #> u') ^+^ (beta .* (aa #> u ^+^ (beta .* v)) )+                  in (alpha, u', rho', v')++tfqmr :: SpMatrix Double -> SpVector Double -> SpVector Double -> TFQMR  +tfqmr aa b x0 = execState (untilConverged _xTfq (tfqmrStep aa r0)) tfqmrInit where+  n = dim b+  r0 = b ^-^ (aa #> x0)    -- residual of initial guess solution+  w0 = r0+  u0 = r0+  v0 = aa #> u0+  d0 = zeroSV n+  r0hat = r0+  rho0 = r0hat `dot` r0+  alpha0 = rho0 / (v0 `dot` r0hat)+  m = 0+  tau0 = norm2 r0+  theta0 = 0+  eta0 = 0+  tfqmrInit = TFQMR x0 w0 u0 v0 d0 m tau0 theta0 eta0 rho0 alpha0++data TFQMR =+  TFQMR { _xTfq, _wTfq, _uTfq, _vTfq, _dTfq :: SpVector Double,+          _mTfq :: Int,+          _tauTfq, _thetaTfq, _etaTfq, _rhoTfq, _alphaTfq :: Double}+  deriving Eq+++ -- ** BCG  -- | one step of BCG@@ -449,7 +661,7 @@  -- * Linear solver interface -data LinSolveMethod = BCG_ | CGS_ | BICGSTAB_ deriving (Eq, Show) +data LinSolveMethod = CGNE_ | TFQMR_ | BCG_ | CGS_ | BICGSTAB_ deriving (Eq, Show)   -- -- | Linear solve with _random_ starting vector -- linSolveM ::@@ -472,9 +684,11 @@       solve aa' b' | isDiagonalSM aa' = reciprocal aa' #> b' -- diagonal solve is easy                    | otherwise = solveWith aa' b'        solveWith aa' b' = case method of-                                BCG_ -> _xBcg (bcg aa' b' x0)-                                CGS_ ->  _xBicgstab (bicgstab aa' b' x0 x0)-                                BICGSTAB_ -> _x (cgs aa' b' x0 x0)+        CGNE_ -> _xCgne (cgne aa' b' x0)+        TFQMR_ -> _xTfq (tfqmr aa' b' x0)+        BCG_ -> _xBcg (bcg aa' b' x0)+        CGS_ ->  _xBicgstab (bicgstab aa' b' x0 x0)+        BICGSTAB_ -> _x (cgs aa' b' x0 x0)       x0 = mkSpVectorD n $ replicate n 0.1        (m, n) = dim aa       nb     = dim b@@ -584,7 +798,7 @@  -- | iterate until convergence is verified or we run out of a fixed iteration budget untilConverged :: MonadState a m => (a -> SpVector Double) -> (a -> a) -> m a-untilConverged fproj = modifyInspectN 100 (normDiffConverged fproj)+untilConverged fproj = modifyInspectN 200 (normDiffConverged fproj)  -- | convergence check (FIXME) normDiffConverged :: (Foldable t, Functor t) =>@@ -669,103 +883,3 @@   ii <- replicateM nsp (MWC.uniformR (0, n-1) g :: IO Int)   return $ fromListSV n $ zip ii aav ------- * Pretty printing------showNonZero :: (Show a, Num a, Eq a) => a -> String-showNonZero x  = if x == 0 then " " else show x---toDenseRow :: Num a => SpMatrix a -> IM.Key -> [a]-toDenseRow (SM (_,ncol) im) irow =-  fmap (\icol -> im `lookupWD_IM` (irow,icol)) [0..ncol-1]--toDenseRowClip :: (Show a, Num a) => SpMatrix a -> IM.Key -> Int -> String-toDenseRowClip sm irow ncomax-  | ncols sm > ncomax = unwords (map show h) ++  " ... " ++ show t-  | otherwise = show dr-     where dr = toDenseRow sm irow-           h = take (ncomax - 2) dr-           t = last dr--newline :: IO ()-newline = putStrLn ""--printDenseSM :: (Show t, Num t) => SpMatrix t -> IO ()-printDenseSM sm = do-  newline-  putStrLn $ sizeStr sm-  newline-  printDenseSM' sm 5 5-  newline-  where    -    printDenseSM' :: (Show t, Num t) => SpMatrix t -> Int -> Int -> IO ()-    printDenseSM' sm'@(SM (nr,_) _) nromax ncomax = mapM_ putStrLn rr_' where-      rr_ = map (\i -> toDenseRowClip sm' i ncomax) [0..nr - 1]-      rr_' | nrows sm > nromax = take (nromax - 2) rr_ ++ [" ... "] ++[last rr_]-           | otherwise = rr_---toDenseListClip :: (Show a, Num a) => SpVector a -> Int -> String-toDenseListClip sv ncomax-  | dim sv > ncomax = unwords (map show h) ++  " ... " ++ show t-  | otherwise = show dr-     where dr = toDenseListSV sv-           h = take (ncomax - 2) dr-           t = last dr--printDenseSV :: (Show t, Num t) => SpVector t -> IO ()-printDenseSV sv = do-  newline-  printDenseSV' sv 5-  newline where-    printDenseSV' v nco = putStrLn rr_' where-      rr_ = toDenseListClip v nco :: String-      rr_' | dim sv > nco = unwords [take (nco - 2) rr_ , " ... " , [last rr_]]-           | otherwise = rr_---- ** Pretty printer typeclass-class PrintDense a where-  prd :: a -> IO ()--instance (Show a, Num a) => PrintDense (SpVector a) where-  prd = printDenseSV--instance (Show a, Num a) => PrintDense (SpMatrix a) where-  prd = printDenseSM----  ------------- * Type synonyms for SpMatrix--------------  
src/Numeric/LinearAlgebra/Sparse/IntMap.hs view
@@ -35,23 +35,33 @@   --- | ========= IntMap-of-IntMap (IM2) stuff+-- * set-like brackets  --- insert an element+-- unionWithKeyIM2 f im1 im2 = undefined where++++++-- * Insertion++-- | Insert an element insertIM2 ::   IM.Key -> IM.Key -> a -> IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap a) insertIM2 i j x imm = IM.insert i ro imm where   ro = maybe (IM.singleton j x) (IM.insert j x) (IM.lookup i imm) {-# inline insertIM2 #-}   --- lookup a key+-- * Lookup++-- |Lookup a key lookupIM2 ::   IM.Key -> IM.Key -> IM.IntMap (IM.IntMap a) -> Maybe a lookupIM2 i j imm = IM.lookup i imm >>= IM.lookup j {-# inline lookupIM2 #-}   --- populate an IM2 from a list of (row index, column index, value)  +-- |Ppopulate an IM2 from a list of (row index, column index, value)   fromListIM2 ::   Foldable t =>      t (IM.Key, IM.Key, a) -> IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap a)@@ -59,15 +69,16 @@   ins t (i,j,x) = insertIM2 i j x t  --- | folding+-- * folding --- indexed fold over an IM2+-- |Indexed left fold over an IM2, with general accumulator ifoldlIM2' :: (IM.Key -> IM.Key -> a -> b -> b) -> b -> IM.IntMap (IM.IntMap a) -> b ifoldlIM2' f empty mm = IM.foldlWithKey' accRow empty mm where   accRow acc i r = IM.foldlWithKey' (accElem i) acc r   accElem i acc j x = f i j x acc {-# inline ifoldlIM2' #-} +-- |Indexed left fold over an IM2 ifoldlIM2 ::   (IM.Key -> IM.Key -> t -> IM.IntMap a -> IM.IntMap a) ->   IM.IntMap (IM.IntMap t) ->  @@ -77,6 +88,7 @@   accElem i acc j x   = f i j x acc {-# inline ifoldlIM2 #-}   +-- |Left fold over an IM2, with general accumulator foldlIM2 :: (a -> b -> b) -> b -> IM.IntMap (IM.IntMap a) -> b foldlIM2 f empty mm = IM.foldl accRow empty mm where   accRow acc r = IM.foldl accElem acc r@@ -84,7 +96,7 @@ {-# inline foldlIM2 #-}  --- transposeIM2 : inner indices become outer ones and vice versa. No loss of information because both inner and outer IntMaps are nubbed.+-- | Inner indices become outer ones and vice versa. No loss of information because both inner and outer IntMaps are nubbed. transposeIM2 :: IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap a) transposeIM2 = ifoldlIM2 (flip insertIM2) {-# inline transposeIM2 #-}@@ -98,9 +110,9 @@   --- | filtering+-- * filtering --- map over outer IM and filter all inner IM's+-- |Map over outer IM and filter all inner IM's ifilterIM2 ::   (IM.Key -> IM.Key -> a -> Bool) ->   IM.IntMap (IM.IntMap a) ->@@ -109,9 +121,7 @@   IM.mapWithKey (\irow row -> IM.filterWithKey (f irow) row)  {-# inline ifilterIM2 #-} --- specialized filtering function---- keep only sub-diagonal elements+-- |Specialized filtering : keep only sub-diagonal elements filterSubdiag :: IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap a) filterSubdiag = ifilterIM2 (\i j _ -> i>j) @@ -119,7 +129,7 @@ countSubdiagonalNZ im =   IM.size $ IM.filter (not . IM.null) (filterSubdiag im) --- list of (row, col) indices of (nonzero) subdiagonal elements+-- |List of (row, col) indices of (nonzero) subdiagonal elements subdiagIndices :: IM.IntMap (IM.IntMap a) -> [(IM.Key, IM.Key)] subdiagIndices im = concatMap rpairs $ IM.toList (IM.map IM.keys im') where   im' = filterSubdiag im@@ -137,15 +147,14 @@     --- | mapping---- map over IM2+-- * mapping +-- |Map over IM2 mapIM2 :: (a -> b) -> IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap b) mapIM2 = IM.map . IM.map   -- imapIM2 (\_ _ x -> f x)  --- indexed map over IM2+-- |Indexed map over IM2 imapIM2 ::   (IM.Key -> IM.Key -> a -> b) ->   IM.IntMap (IM.IntMap a) ->@@ -155,8 +164,7 @@   --- mapping keys-+-- |Mapping keys mapKeysIM2 ::   (IM.Key -> IM.Key) -> (IM.Key -> IM.Key) -> IM.IntMap (IM.IntMap a) -> IM.IntMap (IM.IntMap a) mapKeysIM2 fi fj im = IM.map adjCols adjRows where@@ -173,7 +181,4 @@   ----- sparsification : 
test/LibSpec.hs view
@@ -28,7 +28,7 @@  spec :: Spec spec = do-  describe "Math.Linear.Sparse : library" $ do+  describe "Numeric.LinearAlgebra.Sparse : library" $ do     -- prop "subtraction is cancellative" $ \(x :: SpVector Double) ->     --   x ^-^ x `shouldBe` zero     it "dot : inner product" $@@ -43,58 +43,44 @@       (m1 `matMat` m2) `shouldBe` m1m2     it "eye : identity matrix" $       infoSM (eye 10) `shouldBe` SMInfo 10 0.1+    it "insertCol : insert a column in a SpMatrix" $+      insertCol (eye 3) (fromListDenseSV 3 [2,2,2]) 0 `shouldBe` (fromListSM (3,3) [(0,0,2),(1,0,2),(1,1,1),(2,0,2),(2,2,1)])+    it "insertRow : insert a row in a SpMatrix" $+      insertRow (eye 3) (fromListDenseSV 3 [2,2,2]) 1 `shouldBe` (fromListSM (3,3) [(0,0,1), (1,0,2), (1,1,2), (1,2,2), (2,2,1)])+    it "extractCol -> insertCol : identity" $+      insertCol (eye 3) (extractCol (eye 3) 1) 1 `shouldBe` eye 3+    it "extractRow -> insertRow : identity" $+      insertRow (eye 3) (extractRow (eye 3) 1) 1 `shouldBe` eye 3           it "countSubdiagonalNZ : # of nonzero elements below the diagonal" $       countSubdiagonalNZSM m3 `shouldBe` 1+    it "permutPairsSM : permutation matrices are orthogonal" $ do+      let pm0 = permutPairsSM 3 [(0,2), (1,2)]+      pm0 ##^ pm0 `shouldBe` eye 3+      pm0 #^# pm0 `shouldBe` eye 3              it "modifyInspectN : early termination by iteration count" $       execState (modifyInspectN 2 ((< eps) . diffSqL) (/2)) 1 `shouldBe` 1/8     it "modifyInspectN : termination by value convergence" $       execState (modifyInspectN (2^16) ((< eps) . head) (/2)) 1 < eps `shouldBe` True -  describe "Math.Linear.Sparse : Linear solvers" $ do+  describe "Numeric.LinearAlgebra.Sparse : Linear solvers" $ do+    -- it "TFQMR (2 x 2 dense)" $+    --   normSq (_xTfq (tfqmr aa0 b0 x0) ^-^ x0true) <= eps `shouldBe` True     it "BCG (2 x 2 dense)" $       normSq (_xBcg (bcg aa0 b0 x0) ^-^ x0true) <= eps `shouldBe` True     it "BiCGSTAB (2 x 2 dense)" $        normSq (aa0 <\> b0 ^-^ x0true) <= eps `shouldBe` True     it "CGS (2 x 2 dense)" $        normSq (_x (cgs aa0 b0 x0 x0) ^-^ x0true) <= eps `shouldBe` True-  describe "Math.Linear.Sparse : QR decomposition" $ do    +  describe "Numeric.LinearAlgebra.Sparse : QR decomposition" $ do         it "QR (4 x 4 sparse)" $       checkQr tm4 `shouldBe` True     it "QR (3 x 3 dense)" $        checkQr tm2 `shouldBe` True-    -  -- let n = 10-  --     nsp = 3-  -- describe ("random sparse linear system of size " ++ show n ++ " and sparsity " ++ show (fromIntegral nsp/fromIntegral n)) $ it "<\\>" $ do-  --   aa <- randSpMat n nsp-  --   xtrue <- randSpVec n nsp-  --   b <- randSpVec n nsp    -  --   let b = aa #> xtrue-  --   printDenseSM aa-  --   normSq (aa <\> b ^-^ xtrue) <= eps `shouldBe` True-  -- --     normSq (_xBicgstab (bicgstab aa b x0 x0) ^-^ x) <= eps `shouldBe` True+  describe "Numeric.LinearAlgebra.Sparse : LU decomposition" $ do+    it "LU (3 x 3 dense)" $+      checkLu tm2 `shouldBe` True   --- -- run N iterations ---- runNBiC :: Int -> SpMatrix Double -> SpVector Double -> BICGSTAB-runNBiC n aa b = map _xBicgstab $ runAppendN' (bicgstabStep aa x0) n bicgsInit where-   x0 = mkSpVectorD nd $ replicate nd 0.9-   nd = dim r0-   r0 = b ^-^ (aa #> x0)    -   p0 = r0-   bicgsInit = BICGSTAB x0 r0 p0---- runNCGS :: Int -> SpMatrix Double -> SpVector Double -> CGS-runNCGS n aa b = map _x $ runAppendN' (cgsStep aa x0) n cgsInit where-  x0 = mkSpVectorD nd $ replicate nd 0.1-  nd = dim r0-  r0 = b ^-^ (aa #> x0)    -- residual of initial guess solution-  p0 = r0-  u0 = r0-  cgsInit = CGS x0 r0 p0 u0  -- {-  example 0 : 2x2 linear system@@ -193,17 +179,7 @@   --- `ndim` iterations -solveRandomN ndim nsp niter = do-  aa0 <- randSpMat ndim (nsp ^ 2)-  let aa = aa0 ^+^ eye ndim-  xtrue <- randSpVec ndim nsp-  let b = aa #> xtrue-      xhatB = head $ runNBiC niter aa b-      xhatC = head $ runNCGS niter aa b-  printDenseSM aa    -  return (normSq (xhatB ^-^ xtrue), normSq (xhatC ^-^ xtrue))  -- @@ -270,6 +246,14 @@   +{- LU -}++checkLu a = lup == a where+  (l, u) = lu a+  lup = l ## u+++ {- eigenvalues -}  @@ -332,3 +316,40 @@ --  tm4 = sparsifySM $ fromListDenseSM 4 [1,0,0,0,2,5,0,10,3,6,8,11,4,7,9,12]++++++++-- -- run N iterations ++-- -- runNBiC :: Int -> SpMatrix Double -> SpVector Double -> BICGSTAB+-- runNBiC n aa b = map _xBicgstab $ runAppendN' (bicgstabStep aa x0) n bicgsInit where+--    x0 = mkSpVectorD nd $ replicate nd 0.9+--    nd = dim r0+--    r0 = b ^-^ (aa #> x0)    +--    p0 = r0+--    bicgsInit = BICGSTAB x0 r0 p0++-- -- runNCGS :: Int -> SpMatrix Double -> SpVector Double -> CGS+-- runNCGS n aa b = map _x $ runAppendN' (cgsStep aa x0) n cgsInit where+--   x0 = mkSpVectorD nd $ replicate nd 0.1+--   nd = dim r0+--   r0 = b ^-^ (aa #> x0)    -- residual of initial guess solution+--   p0 = r0+--   u0 = r0+--   cgsInit = CGS x0 r0 p0 u0++++-- solveRandomN ndim nsp niter = do+--   aa0 <- randSpMat ndim (nsp ^ 2)+--   let aa = aa0 ^+^ eye ndim+--   xtrue <- randSpVec ndim nsp+--   let b = aa #> xtrue+--       xhatB = head $ runNBiC niter aa b+--       xhatC = head $ runNCGS niter aa b+--   -- printDenseSM aa    +--   return (normSq (xhatB ^-^ xtrue), normSq (xhatC ^-^ xtrue))