2
{-# LANGUAGE TypeFamilies #-}
3
{-# LANGUAGE FlexibleContexts #-}
4
{-# LANGUAGE FlexibleInstances #-}
5
{-# LANGUAGE MultiParamTypeClasses #-}
6
{-# LANGUAGE UndecidableInstances #-}
8
-----------------------------------------------------------------------------
10
-- Module : Numeric.ContainerBoot
11
-- Copyright : (c) Alberto Ruiz 2010
12
-- License : GPL-style
14
-- Maintainer : Alberto Ruiz <aruiz@um.es>
15
-- Stability : provisional
16
-- Portability : portable
18
-- Module to avoid cyclyc dependencies.
20
-----------------------------------------------------------------------------
22
module Numeric.ContainerBoot (
25
-- * Generic operations
27
-- * Matrix product and related functions
31
-- * Element conversion
36
RealOf, ComplexOf, SingleOf, DoubleOf,
45
import Data.Packed.ST as ST
46
import Numeric.Conversion
47
import Data.Packed.Internal
48
import Numeric.GSL.Vector
50
import Control.Monad(ap)
52
import Numeric.LinearAlgebra.LAPACK(multiplyR,multiplyC,multiplyF,multiplyQ)
54
-------------------------------------------------------------------
56
type family IndexOf (c :: * -> *)
58
type instance IndexOf Vector = Int
59
type instance IndexOf Matrix = (Int,Int)
61
type family ArgOf (c :: * -> *) a
63
type instance ArgOf Vector a = a -> a
64
type instance ArgOf Matrix a = a -> a -> a
66
-------------------------------------------------------------------
68
-- | Basic element-by-element functions for numeric containers
69
class (Complexable c, Fractional e, Element e) => Container c e where
70
-- | create a structure with a single element
72
-- | complex conjugate
74
scale :: e -> c e -> c e
75
-- | scale the element by element reciprocal of the object:
77
-- @scaleRecip 2 (fromList [5,i]) == 2 |> [0.4 :+ 0.0,0.0 :+ (-2.0)]@
78
scaleRecip :: e -> c e -> c e
79
addConstant :: e -> c e -> c e
80
add :: c e -> c e -> c e
81
sub :: c e -> c e -> c e
82
-- | element by element multiplication
83
mul :: c e -> c e -> c e
84
-- | element by element division
85
divide :: c e -> c e -> c e
86
equal :: c e -> c e -> Bool
88
-- element by element inverse tangent
89
arctan2 :: c e -> c e -> c e
91
-- | cannot implement instance Functor because of Element class constraint
92
cmap :: (Element b) => (e -> b) -> c e -> c b
93
-- | constant structure of given size
94
konst :: e -> IndexOf c -> c e
95
-- | create a structure using a function
97
-- Hilbert matrix of order N:
99
-- @hilb n = build (n,n) (\\i j -> 1/(i+j+1))@
100
build :: IndexOf c -> (ArgOf c e) -> c e
101
--build :: BoundsOf f -> f -> (ContainerOf f) e
103
-- | indexing function
104
atIndex :: c e -> IndexOf c -> e
105
-- | index of min element
106
minIndex :: c e -> IndexOf c
107
-- | index of max element
108
maxIndex :: c e -> IndexOf c
109
-- | value of min element
110
minElement :: c e -> e
111
-- | value of max element
112
maxElement :: c e -> e
113
-- the C functions sumX/prodX are twice as fast as using foldVector
114
-- | the sum of elements (faster than using @fold@)
115
sumElements :: c e -> e
116
-- | the product of elements (faster than using @fold@)
117
prodElements :: c e -> e
119
-- | A more efficient implementation of @cmap (\\x -> if x>0 then 1 else 0)@
121
-- @> step $ linspace 5 (-1,1::Double)
122
-- 5 |> [0.0,0.0,0.0,1.0,1.0]@
124
step :: RealElement e => c e -> c e
126
-- | Element by element version of @case compare a b of {LT -> l; EQ -> e; GT -> g}@.
128
-- Arguments with any dimension = 1 are automatically expanded:
130
-- @> cond ((1>\<4)[1..]) ((3>\<1)[1..]) 0 100 ((3>\<4)[1..]) :: Matrix Double
132
-- [ 100.0, 2.0, 3.0, 4.0
133
-- , 0.0, 100.0, 7.0, 8.0
134
-- , 0.0, 0.0, 100.0, 12.0 ]@
136
cond :: RealElement e
144
-- | Find index of elements which satisfy a predicate
146
-- @> find (>0) (ident 3 :: Matrix Double)
147
-- [(0,0),(1,1),(2,2)]@
149
find :: (e -> Bool) -> c e -> [IndexOf c]
151
-- | Create a structure from an association list
153
-- @> assoc 5 0 [(2,7),(1,3)] :: Vector Double
154
-- 5 |> [0.0,3.0,7.0,0.0,0.0]@
156
assoc :: IndexOf c -- ^ size
157
-> e -- ^ default value
158
-> [(IndexOf c, e)] -- ^ association list
161
-- | Modify a structure using an update function
163
-- @> accum (ident 5) (+) [((1,1),5),((0,3),3)] :: Matrix Double
165
-- [ 1.0, 0.0, 0.0, 3.0, 0.0
166
-- , 0.0, 6.0, 0.0, 0.0, 0.0
167
-- , 0.0, 0.0, 1.0, 0.0, 0.0
168
-- , 0.0, 0.0, 0.0, 1.0, 0.0
169
-- , 0.0, 0.0, 0.0, 0.0, 1.0 ]@
171
accum :: c e -- ^ initial structure
172
-> (e -> e -> e) -- ^ update function
173
-> [(IndexOf c, e)] -- ^ association list
176
--------------------------------------------------------------------------
178
instance Container Vector Float where
179
scale = vectorMapValF Scale
180
scaleRecip = vectorMapValF Recip
181
addConstant = vectorMapValF AddConstant
185
divide = vectorZipF Div
186
equal u v = dim u == dim v && maxElement (vectorMapF Abs (sub u v)) == 0.0
187
arctan2 = vectorZipF ATan2
188
scalar x = fromList [x]
194
minIndex = round . toScalarF MinIdx
195
maxIndex = round . toScalarF MaxIdx
196
minElement = toScalarF Min
197
maxElement = toScalarF Max
206
instance Container Vector Double where
207
scale = vectorMapValR Scale
208
scaleRecip = vectorMapValR Recip
209
addConstant = vectorMapValR AddConstant
213
divide = vectorZipR Div
214
equal u v = dim u == dim v && maxElement (vectorMapR Abs (sub u v)) == 0.0
215
arctan2 = vectorZipR ATan2
216
scalar x = fromList [x]
222
minIndex = round . toScalarR MinIdx
223
maxIndex = round . toScalarR MaxIdx
224
minElement = toScalarR Min
225
maxElement = toScalarR Max
234
instance Container Vector (Complex Double) where
235
scale = vectorMapValC Scale
236
scaleRecip = vectorMapValC Recip
237
addConstant = vectorMapValC AddConstant
241
divide = vectorZipC Div
242
equal u v = dim u == dim v && maxElement (mapVector magnitude (sub u v)) == 0.0
243
arctan2 = vectorZipC ATan2
244
scalar x = fromList [x]
250
minIndex = minIndex . fst . fromComplex . (zipVectorWith (*) `ap` mapVector conjugate)
251
maxIndex = maxIndex . fst . fromComplex . (zipVectorWith (*) `ap` mapVector conjugate)
252
minElement = ap (@>) minIndex
253
maxElement = ap (@>) maxIndex
256
step = undefined -- cannot match
260
cond = undefined -- cannot match
262
instance Container Vector (Complex Float) where
263
scale = vectorMapValQ Scale
264
scaleRecip = vectorMapValQ Recip
265
addConstant = vectorMapValQ AddConstant
269
divide = vectorZipQ Div
270
equal u v = dim u == dim v && maxElement (mapVector magnitude (sub u v)) == 0.0
271
arctan2 = vectorZipQ ATan2
272
scalar x = fromList [x]
278
minIndex = minIndex . fst . fromComplex . (zipVectorWith (*) `ap` mapVector conjugate)
279
maxIndex = maxIndex . fst . fromComplex . (zipVectorWith (*) `ap` mapVector conjugate)
280
minElement = ap (@>) minIndex
281
maxElement = ap (@>) maxIndex
284
step = undefined -- cannot match
288
cond = undefined -- cannot match
290
---------------------------------------------------------------
292
instance (Container Vector a) => Container Matrix a where
293
scale x = liftMatrix (scale x)
294
scaleRecip x = liftMatrix (scaleRecip x)
295
addConstant x = liftMatrix (addConstant x)
296
add = liftMatrix2 add
297
sub = liftMatrix2 sub
298
mul = liftMatrix2 mul
299
divide = liftMatrix2 divide
300
equal a b = cols a == cols b && flatten a `equal` flatten b
301
arctan2 = liftMatrix2 arctan2
302
scalar x = (1><1) [x]
303
konst v (r,c) = reshape c (konst v (r*c))
305
conj = liftMatrix conj
306
cmap f = liftMatrix (mapVector f)
308
minIndex m = let (r,c) = (rows m,cols m)
309
i = (minIndex $ flatten m)
310
in (i `div` c,i `mod` c)
311
maxIndex m = let (r,c) = (rows m,cols m)
312
i = (maxIndex $ flatten m)
313
in (i `div` c,i `mod` c)
314
minElement = ap (@@>) minIndex
315
maxElement = ap (@@>) maxIndex
316
sumElements = sumElements . flatten
317
prodElements = prodElements . flatten
318
step = liftMatrix step
324
----------------------------------------------------
326
-- | Matrix product and related functions
327
class Element e => Product e where
329
multiply :: Matrix e -> Matrix e -> Matrix e
330
-- | dot (inner) product
331
dot :: Vector e -> Vector e -> e
332
-- | sum of absolute value of elements (differs in complex case from @norm1@)
333
absSum :: Vector e -> RealOf e
334
-- | sum of absolute value of elements
335
norm1 :: Vector e -> RealOf e
337
norm2 :: Vector e -> RealOf e
338
-- | element of maximum magnitude
339
normInf :: Vector e -> RealOf e
341
instance Product Float where
342
norm2 = toScalarF Norm2
343
absSum = toScalarF AbsSum
345
norm1 = toScalarF AbsSum
346
normInf = maxElement . vectorMapF Abs
349
instance Product Double where
350
norm2 = toScalarR Norm2
351
absSum = toScalarR AbsSum
353
norm1 = toScalarR AbsSum
354
normInf = maxElement . vectorMapR Abs
357
instance Product (Complex Float) where
358
norm2 = toScalarQ Norm2
359
absSum = toScalarQ AbsSum
361
norm1 = sumElements . fst . fromComplex . vectorMapQ Abs
362
normInf = maxElement . fst . fromComplex . vectorMapQ Abs
365
instance Product (Complex Double) where
366
norm2 = toScalarC Norm2
367
absSum = toScalarC AbsSum
369
norm1 = sumElements . fst . fromComplex . vectorMapC Abs
370
normInf = maxElement . fst . fromComplex . vectorMapC Abs
373
----------------------------------------------------------
375
-- synonym for matrix product
376
mXm :: Product t => Matrix t -> Matrix t -> Matrix t
379
-- matrix - vector product
380
mXv :: Product t => Matrix t -> Vector t -> Vector t
381
mXv m v = flatten $ m `mXm` (asColumn v)
383
-- vector - matrix product
384
vXm :: Product t => Vector t -> Matrix t -> Vector t
385
vXm v m = flatten $ (asRow v) `mXm` m
387
{- | Outer product of two vectors.
389
@\> 'fromList' [1,2,3] \`outer\` 'fromList' [5,2,3]
395
outer :: (Product t) => Vector t -> Vector t -> Matrix t
396
outer u v = asColumn u `multiply` asRow v
398
{- | Kronecker product of two matrices.
407
, 10.0, 11.0, 12.0 ]@
411
[ 1.0, 2.0, 3.0, 2.0, 4.0, 6.0, 0.0, 0.0, 0.0
412
, 4.0, 5.0, 6.0, 8.0, 10.0, 12.0, 0.0, 0.0, 0.0
413
, 7.0, 8.0, 9.0, 14.0, 16.0, 18.0, 0.0, 0.0, 0.0
414
, 10.0, 11.0, 12.0, 20.0, 22.0, 24.0, 0.0, 0.0, 0.0
415
, 0.0, 0.0, 0.0, -1.0, -2.0, -3.0, 3.0, 6.0, 9.0
416
, 0.0, 0.0, 0.0, -4.0, -5.0, -6.0, 12.0, 15.0, 18.0
417
, 0.0, 0.0, 0.0, -7.0, -8.0, -9.0, 21.0, 24.0, 27.0
418
, 0.0, 0.0, 0.0, -10.0, -11.0, -12.0, 30.0, 33.0, 36.0 ]@
420
kronecker :: (Product t) => Matrix t -> Matrix t -> Matrix t
421
kronecker a b = fromBlocks
422
. splitEvery (cols a)
423
. map (reshape (cols b))
425
$ flatten a `outer` flatten b
427
-------------------------------------------------------------------
430
class Convert t where
431
real :: Container c t => c (RealOf t) -> c t
432
complex :: Container c t => c t -> c (ComplexOf t)
433
single :: Container c t => c t -> c (SingleOf t)
434
double :: Container c t => c t -> c (DoubleOf t)
435
toComplex :: (Container c t, RealElement t) => (c t, c t) -> c (Complex t)
436
fromComplex :: (Container c t, RealElement t) => c (Complex t) -> (c t, c t)
439
instance Convert Double where
444
toComplex = toComplex'
445
fromComplex = fromComplex'
447
instance Convert Float where
452
toComplex = toComplex'
453
fromComplex = fromComplex'
455
instance Convert (Complex Double) where
460
toComplex = toComplex'
461
fromComplex = fromComplex'
463
instance Convert (Complex Float) where
468
toComplex = toComplex'
469
fromComplex = fromComplex'
471
-------------------------------------------------------------------
475
type instance RealOf Double = Double
476
type instance RealOf (Complex Double) = Double
478
type instance RealOf Float = Float
479
type instance RealOf (Complex Float) = Float
481
type family ComplexOf x
483
type instance ComplexOf Double = Complex Double
484
type instance ComplexOf (Complex Double) = Complex Double
486
type instance ComplexOf Float = Complex Float
487
type instance ComplexOf (Complex Float) = Complex Float
489
type family SingleOf x
491
type instance SingleOf Double = Float
492
type instance SingleOf Float = Float
494
type instance SingleOf (Complex a) = Complex (SingleOf a)
496
type family DoubleOf x
498
type instance DoubleOf Double = Double
499
type instance DoubleOf Float = Double
501
type instance DoubleOf (Complex a) = Complex (DoubleOf a)
503
type family ElementOf c
505
type instance ElementOf (Vector a) = a
506
type instance ElementOf (Matrix a) = a
508
------------------------------------------------------------
511
build' :: BoundsOf f -> f -> ContainerOf f
513
type family BoundsOf x
515
type instance BoundsOf (a->a) = Int
516
type instance BoundsOf (a->a->a) = (Int,Int)
518
type family ContainerOf x
520
type instance ContainerOf (a->a) = Vector a
521
type instance ContainerOf (a->a->a) = Matrix a
523
instance (Element a, Num a) => Build (a->a) where
526
instance (Element a, Num a) => Build (a->a->a) where
529
buildM (rc,cc) f = fromLists [ [f r c | c <- cs] | r <- rs ]
530
where rs = map fromIntegral [0 .. (rc-1)]
531
cs = map fromIntegral [0 .. (cc-1)]
533
buildV n f = fromList [f k | k <- ks]
534
where ks = map fromIntegral [0 .. (n-1)]
536
----------------------------------------------------
540
konst' :: Element e => e -> s -> ContainerOf' s e
542
type family ContainerOf' x y
544
type instance ContainerOf' Int a = Vector a
545
type instance ContainerOf' (Int,Int) a = Matrix a
547
instance Konst Int where
550
instance Konst (Int,Int) where
551
konst' k (r,c) = reshape c $ konst' k (r*c)
553
--------------------------------------------------------
554
-- | conjugate transpose
555
ctrans :: (Container Vector e, Element e) => Matrix e -> Matrix e
556
ctrans = liftMatrix conj . trans
558
-- | Creates a square matrix with a given diagonal.
559
diag :: (Num a, Element a) => Vector a -> Matrix a
560
diag v = diagRect 0 v n n where n = dim v
562
-- | creates the identity matrix of given dimension
563
ident :: (Num a, Element a) => Int -> Matrix a
564
ident n = diag (constantD 1 n)
566
--------------------------------------------------------
568
findV p x = foldVectorWithIndex g [] x where
569
g k z l = if p z then k:l else l
571
findM p x = map ((`divMod` cols x)) $ findV p (flatten x)
573
assocV n z xs = ST.runSTVector $ do
574
v <- ST.newVector z n
575
mapM_ (\(k,x) -> ST.writeVector v k x) xs
578
assocM (r,c) z xs = ST.runSTMatrix $ do
579
m <- ST.newMatrix z r c
580
mapM_ (\((i,j),x) -> ST.writeMatrix m i j x) xs
583
accumV v0 f xs = ST.runSTVector $ do
584
v <- ST.thawVector v0
585
mapM_ (\(k,x) -> ST.modifyVector v k (f x)) xs
588
accumM m0 f xs = ST.runSTMatrix $ do
589
m <- ST.thawMatrix m0
590
mapM_ (\((i,j),x) -> ST.modifyMatrix m i j (f x)) xs
593
----------------------------------------------------------------------
595
condM a b l e t = reshape (cols a'') $ cond a' b' l' e' t'
597
args@(a'':_) = conformMs [a,b,l,e,t]
598
[a', b', l', e', t'] = map flatten args
600
condV f a b l e t = f a' b' l' e' t'
602
[a', b', l', e', t'] = conformVs [a,b,l,e,t]