diff options
author | Alberto Ruiz <aruiz@um.es> | 2007-09-11 10:25:24 +0000 |
---|---|---|
committer | Alberto Ruiz <aruiz@um.es> | 2007-09-11 10:25:24 +0000 |
commit | 834b4837799611fd7fbaa9609ea587e041cb0ca1 (patch) | |
tree | 1854b519b6a3dd10e3961796bdfccb52cbc00a4d /lib/Data/Packed/Internal/Tensor.hs | |
parent | 89651db9f2577ba42dbbb91c85565a12f34d0fb2 (diff) |
tensor lib moved to easyVision project
Diffstat (limited to 'lib/Data/Packed/Internal/Tensor.hs')
-rw-r--r-- | lib/Data/Packed/Internal/Tensor.hs | 347 |
1 files changed, 0 insertions, 347 deletions
diff --git a/lib/Data/Packed/Internal/Tensor.hs b/lib/Data/Packed/Internal/Tensor.hs deleted file mode 100644 index dea1636..0000000 --- a/lib/Data/Packed/Internal/Tensor.hs +++ /dev/null | |||
@@ -1,347 +0,0 @@ | |||
1 | {-# OPTIONS_GHC -fglasgow-exts #-} | ||
2 | |||
3 | ----------------------------------------------------------------------------- | ||
4 | -- | | ||
5 | -- Module : Data.Packed.Internal.Tensor | ||
6 | -- Copyright : (c) Alberto Ruiz 2007 | ||
7 | -- License : GPL-style | ||
8 | -- | ||
9 | -- Maintainer : Alberto Ruiz <aruiz@um.es> | ||
10 | -- Stability : provisional | ||
11 | -- Portability : portable (uses FFI) | ||
12 | -- | ||
13 | -- support for basic tensor operations | ||
14 | -- | ||
15 | ----------------------------------------------------------------------------- | ||
16 | |||
17 | module Data.Packed.Internal.Tensor where | ||
18 | |||
19 | import Data.Packed.Internal | ||
20 | import Foreign.Storable | ||
21 | import Data.List(sort,elemIndex,nub,foldl1',foldl') | ||
22 | import GSL.Vector | ||
23 | import Data.Packed.Matrix | ||
24 | import Data.Packed.Vector | ||
25 | import LinearAlgebra.Linear | ||
26 | |||
27 | data IdxType = Covariant | Contravariant deriving (Show,Eq) | ||
28 | |||
29 | type IdxName = String | ||
30 | |||
31 | data IdxDesc = IdxDesc { idxDim :: Int, | ||
32 | idxType :: IdxType, | ||
33 | idxName :: IdxName } deriving Eq | ||
34 | |||
35 | instance Show IdxDesc where | ||
36 | show (IdxDesc n t name) = name ++ sym t ++"["++show n++"]" | ||
37 | where sym Covariant = "_" | ||
38 | sym Contravariant = "^" | ||
39 | |||
40 | |||
41 | data Tensor t = T { dims :: [IdxDesc] | ||
42 | , ten :: Vector t | ||
43 | } | ||
44 | |||
45 | -- | returns the coordinates of a tensor in row - major order | ||
46 | coords :: Tensor t -> Vector t | ||
47 | coords = ten | ||
48 | |||
49 | instance (Show a, Field a) => Show (Tensor a) where | ||
50 | show T {dims = [], ten = t} = "scalar "++show (t `at` 0) | ||
51 | show t = "("++shdims (dims t) ++") "++ showdt t | ||
52 | |||
53 | asMatrix t = reshape (idxDim $ dims t!!1) (ten t) | ||
54 | |||
55 | showdt t | rank t == 1 = show (toList (ten t)) | ||
56 | | rank t == 2 = ('\n':) . dsp . map (map show) . toLists $ asMatrix $ t | ||
57 | | otherwise = concatMap showdt $ parts t (head (names t)) | ||
58 | |||
59 | -- | a nice description of the tensor structure | ||
60 | shdims :: [IdxDesc] -> String | ||
61 | shdims [] = "" | ||
62 | shdims [d] = show d | ||
63 | shdims (d:ds) = show d ++ "><"++ shdims ds | ||
64 | |||
65 | -- | tensor rank (number of indices) | ||
66 | rank :: Tensor t -> Int | ||
67 | rank = length . dims | ||
68 | |||
69 | names :: Tensor t -> [IdxName] | ||
70 | names t = map idxName (dims t) | ||
71 | |||
72 | -- | number of contravariant and covariant indices | ||
73 | structure :: Tensor t -> (Int,Int) | ||
74 | structure t = (rank t - n, n) where | ||
75 | n = length $ filter isCov (dims t) | ||
76 | isCov d = idxType d == Covariant | ||
77 | |||
78 | -- | creates a rank-zero tensor from a scalar | ||
79 | scalar :: Storable t => t -> Tensor t | ||
80 | scalar x = T [] (fromList [x]) | ||
81 | |||
82 | -- | Creates a tensor from a signed list of dimensions (positive = contravariant, negative = covariant) and a Vector containing the coordinates in row major order. | ||
83 | tensor :: [Int] -> Vector a -> Tensor a | ||
84 | tensor dssig vec = T d v `withIdx` seqind where | ||
85 | n = product (map abs dssig) | ||
86 | v = if dim vec == n then vec else error "wrong arguments for tensor" | ||
87 | d = map cr dssig | ||
88 | cr n | n > 0 = IdxDesc {idxName = "", idxDim = n, idxType = Contravariant} | ||
89 | | n < 0 = IdxDesc {idxName = "", idxDim = -n, idxType = Covariant } | ||
90 | |||
91 | |||
92 | tensorFromVector :: IdxType -> Vector t -> Tensor t | ||
93 | tensorFromVector tp v = T {dims = [IdxDesc (dim v) tp "1"], ten = v} | ||
94 | |||
95 | tensorFromMatrix :: Field t => IdxType -> IdxType -> Matrix t -> Tensor t | ||
96 | tensorFromMatrix tpr tpc m = T {dims = [IdxDesc (rows m) tpr "1",IdxDesc (cols m) tpc "2"] | ||
97 | , ten = cdat m} | ||
98 | |||
99 | |||
100 | liftTensor :: (Vector a -> Vector b) -> Tensor a -> Tensor b | ||
101 | liftTensor f (T d v) = T d (f v) | ||
102 | |||
103 | liftTensor2 :: (Vector a -> Vector b -> Vector c) -> Tensor a -> Tensor b -> Tensor c | ||
104 | liftTensor2 f (T d1 v1) (T d2 v2) | compat d1 d2 = T d1 (f v1 v2) | ||
105 | | otherwise = error "liftTensor2 with incompatible tensors" | ||
106 | where compat a b = length a == length b | ||
107 | |||
108 | |||
109 | |||
110 | |||
111 | -- | express the tensor as a matrix with the given index in columns | ||
112 | findIdx :: (Field t) => IdxName -> Tensor t | ||
113 | -> (([IdxDesc], [IdxDesc]), Matrix t) | ||
114 | findIdx name t = ((d1,d2),m) where | ||
115 | (d1,d2) = span (\d -> idxName d /= name) (dims t) | ||
116 | c = product (map idxDim d2) | ||
117 | m = matrixFromVector RowMajor c (ten t) | ||
118 | |||
119 | -- | express the tensor as a matrix with the given index in rows | ||
120 | putFirstIdx :: (Field t) => String -> Tensor t -> ([IdxDesc], Matrix t) | ||
121 | putFirstIdx name t = (nd,m') | ||
122 | where ((d1,d2),m) = findIdx name t | ||
123 | m' = matrixFromVector RowMajor c $ cdat $ trans m | ||
124 | nd = d2++d1 | ||
125 | c = dim (ten t) `div` (idxDim $ head d2) | ||
126 | |||
127 | |||
128 | -- | renames all the indices in the current order (repeated indices may get different names) | ||
129 | withIdx :: Tensor t -> [IdxName] -> Tensor t | ||
130 | withIdx (T d v) l = T d' v | ||
131 | where d' = zipWith f d l | ||
132 | f i n = i {idxName=n} | ||
133 | |||
134 | |||
135 | -- | raises or lowers all the indices of a tensor (with euclidean metric) | ||
136 | raise :: Tensor t -> Tensor t | ||
137 | raise (T d v) = T (map raise' d) v | ||
138 | where raise' idx@IdxDesc {idxType = Covariant } = idx {idxType = Contravariant} | ||
139 | raise' idx@IdxDesc {idxType = Contravariant } = idx {idxType = Covariant} | ||
140 | |||
141 | |||
142 | -- | index transposition to a desired order. You can specify only a subset of the indices, which will be moved to the front of indices list | ||
143 | tridx :: (Field t) => [IdxName] -> Tensor t -> Tensor t | ||
144 | tridx [] t = t | ||
145 | tridx (name:rest) t = T (d:ds) (join ts) where | ||
146 | ((_,d:_),_) = findIdx name t | ||
147 | ps = map (tridx rest) (parts t name) | ||
148 | ts = map ten ps | ||
149 | ds = dims (head ps) | ||
150 | |||
151 | |||
152 | |||
153 | -- | extracts a given part of a tensor | ||
154 | part :: (Field t) => Tensor t -> (IdxName, Int) -> Tensor t | ||
155 | part t (name,k) = if k<0 || k>=l | ||
156 | then error $ "part "++show (name,k)++" out of range" -- in "++show t | ||
157 | else T {dims = ds, ten = toRows m !! k} | ||
158 | where (d:ds,m) = putFirstIdx name t | ||
159 | l = idxDim d | ||
160 | |||
161 | -- | creates a list with all parts of a tensor along a given index | ||
162 | parts :: (Field t) => Tensor t -> IdxName -> [Tensor t] | ||
163 | parts t name = map f (toRows m) | ||
164 | where (d:ds,m) = putFirstIdx name t | ||
165 | l = idxDim d | ||
166 | f t = T {dims=ds, ten=t} | ||
167 | |||
168 | |||
169 | compatIdx :: (Field t1, Field t) => Tensor t1 -> IdxName -> Tensor t -> IdxName -> Bool | ||
170 | compatIdx t1 n1 t2 n2 = compatIdxAux d1 d2 where | ||
171 | d1 = head $ snd $ fst $ findIdx n1 t1 | ||
172 | d2 = head $ snd $ fst $ findIdx n2 t2 | ||
173 | compatIdxAux IdxDesc {idxDim = n1, idxType = t1} | ||
174 | IdxDesc {idxDim = n2, idxType = t2} | ||
175 | = t1 /= t2 && n1 == n2 | ||
176 | |||
177 | |||
178 | outer' u v = dat (outer u v) | ||
179 | |||
180 | -- | tensor product without without any contractions | ||
181 | rawProduct :: (Field t, Num t) => Tensor t -> Tensor t -> Tensor t | ||
182 | rawProduct (T d1 v1) (T d2 v2) = T (d1++d2) (outer' v1 v2) | ||
183 | |||
184 | -- | contraction of the product of two tensors | ||
185 | contraction2 :: (Field t, Num t) => Tensor t -> IdxName -> Tensor t -> IdxName -> Tensor t | ||
186 | contraction2 t1 n1 t2 n2 = | ||
187 | if compatIdx t1 n1 t2 n2 | ||
188 | then T (tail d1 ++ tail d2) (cdat m) | ||
189 | else error "wrong contraction2" | ||
190 | where (d1,m1) = putFirstIdx n1 t1 | ||
191 | (d2,m2) = putFirstIdx n2 t2 | ||
192 | m = multiply RowMajor (trans m1) m2 | ||
193 | |||
194 | -- | contraction of a tensor along two given indices | ||
195 | contraction1 :: (Linear Vector t) => Tensor t -> IdxName -> IdxName -> Tensor t | ||
196 | contraction1 t name1 name2 = | ||
197 | if compatIdx t name1 t name2 | ||
198 | then sumT y | ||
199 | else error $ "wrong contraction1: "++(shdims$dims$t)++" "++name1++" "++name2 | ||
200 | where d = dims (head y) | ||
201 | x = (map (flip parts name2) (parts t name1)) | ||
202 | y = map head $ zipWith drop [0..] x | ||
203 | |||
204 | -- | contraction of a tensor along a repeated index | ||
205 | contraction1c :: (Linear Vector t) => Tensor t -> IdxName -> Tensor t | ||
206 | contraction1c t n = contraction1 renamed n' n | ||
207 | where n' = n++"'" -- hmmm | ||
208 | renamed = withIdx t auxnames | ||
209 | auxnames = h ++ (n':r) | ||
210 | (h,_:r) = break (==n) (map idxName (dims t)) | ||
211 | |||
212 | -- | alternative and inefficient version of contraction2 | ||
213 | contraction2' :: (Linear Vector t) => Tensor t -> IdxName -> Tensor t -> IdxName -> Tensor t | ||
214 | contraction2' t1 n1 t2 n2 = | ||
215 | if compatIdx t1 n1 t2 n2 | ||
216 | then contraction1 (rawProduct t1 t2) n1 n2 | ||
217 | else error "wrong contraction'" | ||
218 | |||
219 | -- | applies a sequence of contractions | ||
220 | contractions :: (Linear Vector t) => Tensor t -> [(IdxName, IdxName)] -> Tensor t | ||
221 | contractions t pairs = foldl' contract1b t pairs | ||
222 | where contract1b t (n1,n2) = contraction1 t n1 n2 | ||
223 | |||
224 | -- | applies a sequence of contractions of same index | ||
225 | contractionsC :: (Linear Vector t) => Tensor t -> [IdxName] -> Tensor t | ||
226 | contractionsC t is = foldl' contraction1c t is | ||
227 | |||
228 | |||
229 | -- | applies a contraction on the first indices of the tensors | ||
230 | contractionF :: (Linear Vector t) => Tensor t -> Tensor t -> Tensor t | ||
231 | contractionF t1 t2 = contraction2 t1 n1 t2 n2 | ||
232 | where n1 = fn t1 | ||
233 | n2 = fn t2 | ||
234 | fn = idxName . head . dims | ||
235 | |||
236 | -- | computes all compatible contractions of the product of two tensors that would arise if the index names were equal | ||
237 | possibleContractions :: (Linear Vector t) => Tensor t -> Tensor t -> [Tensor t] | ||
238 | possibleContractions t1 t2 = [ contraction2 t1 n1 t2 n2 | n1 <- names t1, n2 <- names t2, compatIdx t1 n1 t2 n2 ] | ||
239 | |||
240 | |||
241 | |||
242 | desiredContractions2 :: Tensor t -> Tensor t1 -> [(IdxName, IdxName)] | ||
243 | desiredContractions2 t1 t2 = [ (n1,n2) | n1 <- names t1, n2 <- names t2, n1==n2] | ||
244 | |||
245 | desiredContractions1 :: Tensor t -> [IdxName] | ||
246 | desiredContractions1 t = [ n1 | (a,n1) <- x , (b,n2) <- x, a/=b, n1==n2] | ||
247 | where x = zip [0..] (names t) | ||
248 | |||
249 | -- | tensor product with the convention that repeated indices are contracted. | ||
250 | mulT :: (Linear Vector t) => Tensor t -> Tensor t -> Tensor t | ||
251 | mulT t1 t2 = r where | ||
252 | t1r = contractionsC t1 (desiredContractions1 t1) | ||
253 | t2r = contractionsC t2 (desiredContractions1 t2) | ||
254 | cs = desiredContractions2 t1r t2r | ||
255 | r = case cs of | ||
256 | [] -> rawProduct t1r t2r | ||
257 | (n1,n2):as -> contractionsC (contraction2 t1r n1 t2r n2) (map fst as) | ||
258 | |||
259 | ----------------------------------------------------------------- | ||
260 | |||
261 | -- | tensor addition (for tensors with the same structure) | ||
262 | addT :: (Linear Vector a) => Tensor a -> Tensor a -> Tensor a | ||
263 | addT a b = liftTensor2 add a b | ||
264 | |||
265 | sumT :: (Linear Vector a) => [Tensor a] -> Tensor a | ||
266 | sumT l = foldl1' addT l | ||
267 | |||
268 | ----------------------------------------------------------------- | ||
269 | |||
270 | -- sent to Haskell-Cafe by Sebastian Sylvan | ||
271 | perms :: [t] -> [[t]] | ||
272 | perms [x] = [[x]] | ||
273 | perms xs = [y:ps | (y,ys) <- selections xs , ps <- perms ys] | ||
274 | where | ||
275 | selections [] = [] | ||
276 | selections (x:xs) = (x,xs) : [(y,x:ys) | (y,ys) <- selections xs] | ||
277 | |||
278 | interchanges :: (Ord a) => [a] -> Int | ||
279 | interchanges ls = sum (map (count ls) ls) | ||
280 | where count l p = length $ filter (>p) $ take pel l | ||
281 | where Just pel = elemIndex p l | ||
282 | |||
283 | signature :: (Num t, Ord a) => [a] -> t | ||
284 | signature l | length (nub l) < length l = 0 | ||
285 | | even (interchanges l) = 1 | ||
286 | | otherwise = -1 | ||
287 | |||
288 | |||
289 | sym :: (Linear Vector t) => Tensor t -> Tensor t | ||
290 | sym t = T (dims t) (ten (sym' (withIdx t seqind))) | ||
291 | where sym' t = sumT $ map (flip tridx t) (perms (names t)) | ||
292 | where nms = map idxName . dims | ||
293 | |||
294 | antisym :: (Linear Vector t) => Tensor t -> Tensor t | ||
295 | antisym t = T (dims t) (ten (antisym' (withIdx t seqind))) | ||
296 | where antisym' t = sumT $ map (scsig . flip tridx t) (perms (names t)) | ||
297 | scsig t = scalar (signature (nms t)) `rawProduct` t | ||
298 | where nms = map idxName . dims | ||
299 | |||
300 | -- | the wedge product of two tensors (implemented as the antisymmetrization of the ordinary tensor product). | ||
301 | wedge :: (Linear Vector t, Fractional t) => Tensor t -> Tensor t -> Tensor t | ||
302 | wedge a b = antisym (rawProduct (norper a) (norper b)) | ||
303 | where norper t = rawProduct t (scalar (recip $ fromIntegral $ fact (rank t))) | ||
304 | |||
305 | -- antinorper t = rawProduct t (scalar (fromIntegral $ fact (rank t))) | ||
306 | |||
307 | -- | The euclidean inner product of two completely antisymmetric tensors | ||
308 | innerAT :: (Fractional t, Field t) => Tensor t -> Tensor t -> t | ||
309 | innerAT t1 t2 = dot (ten t1) (ten t2) / fromIntegral (fact $ rank t1) | ||
310 | |||
311 | fact :: (Num t, Enum t) => t -> t | ||
312 | fact n = product [1..n] | ||
313 | |||
314 | seqind' :: [[String]] | ||
315 | seqind' = map return seqind | ||
316 | |||
317 | seqind :: [String] | ||
318 | seqind = map show [1..] | ||
319 | |||
320 | -- | completely antisymmetric covariant tensor of dimension n | ||
321 | leviCivita :: (Linear Vector t) => Int -> Tensor t | ||
322 | leviCivita n = antisym $ foldl1 rawProduct $ zipWith withIdx auxbase seqind' | ||
323 | where auxbase = map tc (toRows (ident n)) | ||
324 | tc = tensorFromVector Covariant | ||
325 | |||
326 | -- | contraction of leviCivita with a list of vectors (and raise with euclidean metric) | ||
327 | innerLevi :: (Linear Vector t) => [Tensor t] -> Tensor t | ||
328 | innerLevi vs = raise $ foldl' contractionF (leviCivita n) vs | ||
329 | where n = idxDim . head . dims . head $ vs | ||
330 | |||
331 | |||
332 | -- | obtains the dual of a multivector (with euclidean metric) | ||
333 | dual :: (Linear Vector t, Fractional t) => Tensor t -> Tensor t | ||
334 | dual t = raise $ leviCivita n `mulT` withIdx t seqind `rawProduct` x | ||
335 | where n = idxDim . head . dims $ t | ||
336 | x = scalar (recip $ fromIntegral $ fact (rank t)) | ||
337 | |||
338 | |||
339 | -- | shows only the relevant components of an antisymmetric tensor | ||
340 | niceAS :: (Field t, Fractional t) => Tensor t -> [(t, [Int])] | ||
341 | niceAS t = filter ((/=0.0).fst) $ zip vals base | ||
342 | where vals = map ((`at` 0).ten.foldl' partF t) (map (map pred) base) | ||
343 | base = asBase r n | ||
344 | r = length (dims t) | ||
345 | n = idxDim . head . dims $ t | ||
346 | partF t i = part t (name,i) where name = idxName . head . dims $ t | ||
347 | asBase r n = filter (\x-> (x==nub x && x==sort x)) $ sequence $ replicate r [1..n] | ||