toList,
zipWith )
import Data.Vector.Fixed.Cont ( Arity, arity )
-import Linear.Vector ( Vec, delete, element_sum )
+import Linear.Vector ( Vec, delete )
import Naturals ( N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, S, Z )
import Normed ( Normed(..) )
--
infixl 7 *
(*) :: (Ring.C a, Arity m, Arity n, Arity p)
- => Mat m n a
- -> Mat n p a
- -> Mat m p a
+ => Mat (S m) (S n) a
+ -> Mat (S n) (S p) a
+ -> Mat (S m) (S p) a
(*) m1 m2 = construct lambda
where
- lambda i j =
- sum [(m1 !!! (i,k)) NP.* (m2 !!! (k,j)) | k <- [0..(ncols m1)-1] ]
+ lambda i j = (transpose $ row m1 i) `dot` (column m2 j)
zero = Mat (V.replicate $ V.replicate (fromInteger 0))
-instance (Ring.C a, Arity m, Arity n, m ~ n) => Ring.C (Mat m n a) where
+instance (Ring.C a, Arity m, Arity n, m ~ n) => Ring.C (Mat (S m) (S n) a) where
-- The first * is ring multiplication, the second is matrix
-- multiplication.
m1 * m2 = m1 * m2
-- >>> frobenius_norm m == 3
-- True
--
-frobenius_norm :: (Algebraic.C a, Ring.C a) => Mat m n a -> a
-frobenius_norm (Mat rows) =
- sqrt $ element_sum $ V.map row_sum rows
+frobenius_norm :: (Arity m, Arity n, Algebraic.C a, Ring.C a)
+ => Mat m n a
+ -> a
+frobenius_norm matrix =
+ sqrt $ element_sum2 $ squares
where
- -- | Square and add up the entries of a row.
- row_sum = element_sum . V.map (^2)
+ squares = map2 (^2) matrix
-- Vector helpers. We want it to be easy to create low-dimension
=> Col (S m) a
-> Col (S m) a
-> a
-v1 `dot` v2 = unscalar $ ((transpose v1) * v2)
+v1 `dot` v2 = element_sum2 $ zipwith2 (NP.*) v1 v2
-- | The angle between @v1@ and @v2@ in Euclidean space.
-- 15
--
trace :: (Arity m, Ring.C a) => Mat m m a -> a
-trace matrix =
- let (Mat rows) = diagonal matrix
- in
- element_sum $ V.map V.head rows
+trace = element_sum2 . diagonal
+
-- | Zip together two matrices.
-- >>> zipwith2 (^) c1 c2
-- ((1),(32),(729))
--
-zipwith2 :: Arity m
- => (a -> a -> b)
- -> Col m a
- -> Col m a
- -> Col m b
+zipwith2 :: (Arity m, Arity n)
+ => (a -> b -> c)
+ -> Mat m n a
+ -> Mat m n b
+ -> Mat m n c
zipwith2 f c1 c2 =
construct lambda
where
row_function rowinit idx r = V.ifoldl (g idx) rowinit r
+-- | Left fold over the entries of a matrix (top-left to bottom-right).
+--
+foldl2 :: forall a b m n.
+ (b -> a -> b)
+ -> b
+ -> Mat m n a
+ -> b
+foldl2 f initial matrix =
+ -- Use the index fold but ignore the index arguments.
+ let g _ _ = f in ifoldl2 g initial matrix
+
+
-- | Fold over the entire matrix passing the coordinates @i@ and @j@
-- (of the row/column) to the accumulation function. The fold occurs
-- from bottom-right to top-left.
where
lambda i j = cofactor matrix i j
+
+
+-- | Retrieve the rows of a matrix as a column matrix. If the given
+-- matrix is m-by-n, the result would be an m-by-1 column whose
+-- entries are 1-by-n row matrices.
+--
+-- Examples:
+--
+-- >>> let m = fromList [[1,2],[3,4]] :: Mat2 Int
+-- >>> (rows2 m) !!! (0,0)
+-- ((1,2))
+-- >>> (rows2 m) !!! (1,0)
+-- ((3,4))
+--
+rows2 :: (Arity m, Arity n)
+ => Mat m n a
+ -> Col m (Row n a)
+rows2 (Mat rows) =
+ Mat $ V.map (mk1. Mat . mk1) rows
+
+
+
+-- | Sum the elements of a matrix.
+--
+-- Examples:
+--
+-- >>> let m = fromList [[1,-1],[3,4]] :: Mat2 Int
+-- >>> element_sum2 m
+-- 7
+--
+element_sum2 :: (Arity m, Arity n, Additive.C a) => Mat m n a -> a
+element_sum2 = foldl2 (+) zero