linear-algebra-cblas-0.1: lib/Numeric/LinearAlgebra/Vector/Base.hs
{-# LANGUAGE Rank2Types #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_HADDOCK hide #-}
-----------------------------------------------------------------------------
-- |
-- Module : Numeric.LinearAlgebra.Vector.Base
-- Copyright : Copyright (c) , Patrick Perry <patperry@gmail.com>
-- License : BSD3
-- Maintainer : Patrick Perry <patperry@gmail.com>
-- Stability : experimental
--
module Numeric.LinearAlgebra.Vector.Base (
Vector,
dim,
fromList,
zero,
constant,
at,
unsafeAt,
indices,
elems,
assocs,
update,
unsafeUpdate,
accum,
unsafeAccum,
map,
zipWith,
unsafeZipWith,
concat,
slice,
splitAt,
drop,
take,
unsafeSlice,
unsafeFromForeignPtr,
unsafeToForeignPtr,
unsafeWith,
) where
import Prelude hiding ( concat, drop, map, read, splitAt, take, zipWith,
negate, signum, abs, div, recip, sqrt, exp, log, sin, cos, tan, asin,
acos, atan, sinh, cosh, tanh, asinh, acosh, atanh )
import qualified Prelude as P
import Data.AEq( AEq(..) )
import Data.Vector.Storable( Vector )
import qualified Data.Vector.Storable as Vector
import Foreign( ForeignPtr, Ptr, Storable )
import Text.Printf( printf )
-- | The dimension of a vector. This is equal to the number of
-- elements in the vector.
dim :: (Storable e) => Vector e -> Int
dim = Vector.length
{-# INLINE dim #-}
-- | Create a vector of the given dimension with elements initialized
-- to the values from the list. The list must have at least as many
-- elements as the dimension of the vector; elements in the list past
-- the dimension of the vector are discarded.
fromList :: (Storable e) => Int -> [e] -> Vector e
fromList n es = Vector.fromListN n $ es ++ repeat (error msg)
where
msg = printf ( "fromList"
++ " %d"
++ " <list with length less than %d>"
++ ": not enough elements"
) n n
{-# INLINE fromList #-}
-- | Create a zero vector of the given dimension with all elements initialized
-- to the given zero.
zero :: (Storable e, Num e) => Int -> Vector e
zero n = constant n 0
{-# INLINE zero #-}
-- | Create a vector of the given dimension with all elements initialized
-- to the given value.
constant :: (Storable e) => Int -> e -> Vector e
constant n e
| n < 0 = error $
printf ("constant %d: negative dimension") n
| otherwise =
Vector.fromListN n $ repeat e
{-# INLINE constant #-}
-- | Returns the element of a vector at the specified index.
at :: (Storable e) => Vector e -> Int -> e
at v i
| i < 0 || i >= n = error $
printf "at <vector with dim %d> %d: invalid index" n i
| otherwise =
unsafeAt v i
where
n = dim v
{-# INLINE at #-}
-- | Same as 'at' but does not range-check index.
unsafeAt :: (Storable e) => Vector e -> Int -> e
unsafeAt v i = Vector.unsafeIndex v i
{-# INLINE unsafeAt #-}
-- | Get the indices of the elements in the vector, @[ 0..n-1 ]@, where
-- @n@ is the dimension of the vector.
indices :: (Storable e) => Vector e -> [Int]
indices x = [ 0..n-1 ] where n = dim x
{-# INLINE indices #-}
-- | Returns a list of the elements of a vector, in the same order as their
-- indices.
elems :: (Storable e) => Vector e -> [e]
elems = Vector.toList
{-# INLINE elems #-}
-- | Returns the contents of a vector as a list of associations.
assocs :: (Storable e) => Vector e -> [(Int,e)]
assocs x = zip (indices x) (elems x)
{-# INLINE assocs #-}
-- | Same as 'update' but does not range-check indices.
unsafeUpdate :: (Storable e) => Vector e -> [(Int,e)] -> Vector e
unsafeUpdate = Vector.unsafeUpd
-- | Create a new vector by replacing the values at the specified indices.
update :: (Storable e) => Vector e -> [(Int,e)] -> Vector e
update = (Vector.//)
-- | @accum f@ takes a vector and an association list and accumulates
-- pairs from the list into the vector with the accumulating function @f@.
accum :: (Storable e)
=> (e -> e' -> e)
-> Vector e
-> [(Int, e')]
-> Vector e
accum = Vector.accum
{-# INLINE accum #-}
-- | Same as 'accum' but does not range-check indices.
unsafeAccum :: (Storable e)
=> (e -> e' -> e)
-> Vector e
-> [(Int, e')]
-> Vector e
unsafeAccum = Vector.unsafeAccum
{-# INLINE unsafeAccum #-}
-- | Construct a new vector by applying a function to every element of
-- a vector.
map :: (Storable e, Storable e')
=> (e -> e')
-> Vector e
-> Vector e'
map = Vector.map
{-# INLINE map #-}
-- | Construct a new vector by applying a function to every pair of elements
-- of two vectors. The two vectors must have identical dimensions.
zipWith :: (Storable e, Storable e', Storable f)
=> (e -> e' -> f)
-> Vector e
-> Vector e'
-> Vector f
zipWith f v v'
| n /= n' = error $
printf ("zipWith <function> <vector with dim %d>"
++ " <vector with dim %d>: lengths differ") n n'
| otherwise =
unsafeZipWith f v v'
where
n = dim v
n' = dim v'
{-# INLINE zipWith #-}
-- | Same as 'zipWith' but does not check if the input vectors
-- have the same dimensions.
unsafeZipWith :: (Storable e, Storable e', Storable f)
=> (e -> e' -> f)
-> Vector e
-> Vector e'
-> Vector f
unsafeZipWith = Vector.zipWith
{-# INLINE unsafeZipWith #-}
-- | Create a new vector by concatenating a list of vectors.
concat :: (Storable e) => [Vector e] -> Vector e
concat = Vector.concat
{-# INLINE concat #-}
-- | Same as 'slice' but does not range-change indices.
unsafeSlice :: (Storable e)
=> Int
-> Int
-> Vector e
-> Vector e
unsafeSlice = Vector.unsafeSlice
{-# INLINE unsafeSlice #-}
-- | @slice i n v@ creates a subvector view of @v@ starting at
-- index @i@ and having dimension @n@.
slice :: (Storable e)
=> Int
-> Int
-> Vector e
-> Vector e
slice i n' v
| i < 0 || n' < 0 || i + n' > n = error $
printf "slice %d %d <vector with dim %d>: index out of range"
i n' n
| otherwise =
unsafeSlice i n' v
where
n = dim v
{-# INLINE slice #-}
-- | @drop i v@ is equal to @slice i (n-i) v@, where @n@ is
-- the dimension of the vector.
drop :: (Storable e) => Int -> Vector e -> Vector e
drop i v = slice i (dim v - i) v
{-# INLINE drop #-}
-- | @take n v@ is equal to @slice 0 n v@.
take :: (Storable e) => Int -> Vector e -> Vector e
take n v = slice 0 n v
{-# INLINE take #-}
-- | Split a vector into two blocks and returns views into the blocks. If
-- @(v1, v2) = splitAt i v@, then
-- @v1 = slice 0 i v@ and
-- @v2 = slice i (dim v - i) v@.
splitAt :: (Storable e) => Int -> Vector e -> (Vector e, Vector e)
splitAt i v
| i < 0 || i > n = error $
printf "splitAt %d <vector with dim %d>: invalid index" i n
| otherwise = let
v1 = unsafeSlice 0 i v
v2 = unsafeSlice i (n-i) v
in (v1, v2)
where
n = dim v
-- | Create a vector from a 'ForeignPtr' with an offset and a dimension. The
-- data may not be modified through the ForeignPtr afterwards.
unsafeFromForeignPtr :: (Storable e)
=> ForeignPtr e -- ^ pointer
-> Int -- ^ offset
-> Int -- ^ dimension
-> Vector e
unsafeFromForeignPtr = Vector.unsafeFromForeignPtr
{-# INLINE unsafeFromForeignPtr #-}
-- | Yield the underlying 'ForeignPtr' together with the offset to the data
-- and its length. The data may not be modified through the 'ForeignPtr'.
unsafeToForeignPtr :: (Storable e) => Vector e -> (ForeignPtr e, Int, Int)
unsafeToForeignPtr = Vector.unsafeToForeignPtr
{-# INLINE unsafeToForeignPtr #-}
-- | Pass a pointer to the vector's data to the 'IO' action. The data may
-- not be modified through the 'Ptr'.
unsafeWith :: (Storable e) => Vector e -> (Ptr e -> IO a) -> IO a
unsafeWith = Vector.unsafeWith
instance (Storable e, AEq e) => AEq (Vector e) where
(===) = compareWith (===)
{-# INLINE (===) #-}
(~==) = compareWith (~==)
{-# INLINE (~==) #-}
compareWith :: (Storable e, Storable e')
=> (e -> e' -> Bool)
-> Vector e
-> Vector e'
-> Bool
compareWith cmp v v' =
dim v == dim v'
&& and (P.zipWith cmp (elems v) (elems v'))
{-# INLINE compareWith #-}