ideas-0.6: src/Domain/LinearAlgebra/Vector.hs
-----------------------------------------------------------------------------
-- Copyright 2010, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer : bastiaan.heeren@ou.nl
-- Stability : provisional
-- Portability : portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Domain.LinearAlgebra.Vector
( Vector, VectorSpace
, makeVectorSpace, vectors, sameDimension, gramSchmidt
, fromList, toList, liftV, liftV2, showVectorWith
, toUnit, isUnit, isZero, makeOrthogonal, orthogonal, orthonormalList
, scale, norm, distance, vectorSum, innerProduct, dimension
) where
import Control.Monad
import Common.Traversable
import Data.List
-------------------------------------------------------------------------------
-- Data types
newtype Vector a = V [a]
deriving (Eq, Ord)
newtype VectorSpace a = VS [Vector a]
deriving (Eq, Ord)
-------------------------------------------------------------------------------
-- Instances
instance Functor Vector where
fmap f (V xs) = V (map f xs)
instance Once Vector where
onceM f (V xs) = liftM V (onceM f xs)
instance Switch Vector where
switch (V xs) = liftM V (switch xs)
instance Show a => Show (Vector a) where
show = showVectorWith show
instance Num a => Num (Vector a) where
(+) = liftV2 (+)
(*) = liftV2 (*)
(-) = liftV2 (-)
negate = liftV negate
abs = liftV abs
signum = liftV signum
fromInteger = fromList . return . fromInteger
instance Functor VectorSpace where
fmap f (VS xs) = VS (map (fmap f) xs)
instance Show a => Show (VectorSpace a) where
show = show . vectors
-------------------------------------------------------------------------------
-- Vector Space operations
-- Check whether all vectors have same dimension
sameDimension :: [Vector a] -> Bool
sameDimension xs =
case map dimension xs of
[] -> True
n:ns -> all (==n) ns
-- | Checks that all vectors in vector space have same dimension
makeVectorSpace :: [Vector a] -> VectorSpace a
makeVectorSpace xs
| sameDimension xs = VS xs
| otherwise = error "makeVectorSpace: different dimensions"
vectors :: VectorSpace a -> [Vector a]
vectors (VS xs) = xs
gramSchmidt :: Floating a => VectorSpace a -> VectorSpace a
gramSchmidt (VS xs) = VS (reverse (foldr op [] xs))
where
op a as = toUnit (foldr makeOrthogonal a as):as
-------------------------------------------------------------------------------
-- Vector operations
showVectorWith :: (a -> String) -> Vector a -> String
showVectorWith f (V xs) = "(" ++ concat (intersperse "," (map f xs)) ++ ")"
toList :: Vector a -> [a]
toList (V xs) = xs
fromList :: [a] -> Vector a
fromList = V
-- local helper function
liftV :: (a -> b) -> Vector a -> Vector b
liftV op = fromList . map op . toList
-- local helper function
liftV2 :: (a -> b -> c) -> Vector a -> Vector b -> Vector c
liftV2 op v1 v2 = fromList $ zipWith op (toList v1) (toList v2)
toUnit :: Floating a => Vector a -> Vector a
toUnit v = scale (1 / norm v) v
isUnit :: Floating a => Vector a -> Bool
isUnit v = norm v == 1
isZero :: Num a => Vector a -> Bool
isZero = all (==0) . toList
makeOrthogonal :: Num a => Vector a -> Vector a -> Vector a
makeOrthogonal v1 v2 = v2 - scale (innerProduct v1 v2) v1
orthogonal :: Num a => Vector a -> Vector a -> Bool
orthogonal v1 v2 = innerProduct v1 v2 == 0
scale :: Num a => a -> Vector a -> Vector a
scale a = liftV (*a)
orthonormalList :: Floating a => [Vector a] -> Bool
orthonormalList xs = all isUnit xs && all (uncurry orthogonal) pairs
where
pairs = [ (a, b) | (i, a) <- zip [0..] xs, (j, b) <- zip [0..] xs, i < j ]
-- length of the vector (also called norm)
norm :: Floating a => Vector a -> a
norm v = sqrt $ innerProduct v v
distance :: Floating a => Vector a -> Vector a -> a
distance v1 v2 = norm (v1 - v2)
vectorSum :: Num a => Vector a -> a
vectorSum = sum . toList
innerProduct :: Num a => Vector a -> Vector a -> a
innerProduct v1 v2 = vectorSum (v1 * v2)
dimension :: Vector a -> Int
dimension = length . toList