multilinear 0.4.0.0 → 0.5.0.0
raw patch · 8 files changed
+120/−133 lines, 8 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Multilinear.Generic.MultiCore: _map :: (Unbox a, Unbox b, NFData b) => (a -> b) -> Tensor a -> Tensor b
- Multilinear.Generic.MultiCore: _standardize :: Unbox a => Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Float.Floating a, Control.DeepSeq.NFData a) => GHC.Float.Floating (Multilinear.Generic.MultiCore.Tensor a)
- Multilinear.Generic.MultiCore: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Num.Num a, Control.DeepSeq.NFData a) => GHC.Num.Num (Multilinear.Generic.MultiCore.Tensor a)
- Multilinear.Generic.MultiCore: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Real.Fractional a, Control.DeepSeq.NFData a) => GHC.Real.Fractional (Multilinear.Generic.MultiCore.Tensor a)
- Multilinear.Generic.MultiCore: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Show.Show a) => GHC.Show.Show (Multilinear.Generic.MultiCore.Tensor a)
- Multilinear.Generic.MultiCore: instance Data.Vector.Unboxed.Base.Unbox a => Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a
- Multilinear.Generic.Sequential: _map :: (Unbox a, Unbox b) => (a -> b) -> Tensor a -> Tensor b
- Multilinear.Generic.Sequential: _standardize :: Unbox a => Tensor a -> Tensor a
- Multilinear.Generic.Sequential: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Float.Floating a, Control.DeepSeq.NFData a) => GHC.Float.Floating (Multilinear.Generic.Sequential.Tensor a)
- Multilinear.Generic.Sequential: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Num.Num a, Control.DeepSeq.NFData a) => GHC.Num.Num (Multilinear.Generic.Sequential.Tensor a)
- Multilinear.Generic.Sequential: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Real.Fractional a, Control.DeepSeq.NFData a) => GHC.Real.Fractional (Multilinear.Generic.Sequential.Tensor a)
- Multilinear.Generic.Sequential: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Show.Show a) => GHC.Show.Show (Multilinear.Generic.Sequential.Tensor a)
- Multilinear.Generic.Sequential: instance Data.Vector.Unboxed.Base.Unbox a => Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a
+ Multilinear.Class: standardize :: Multilinear t a => t a -> t a
+ Multilinear.Generic: toMultiCore :: Tensor a -> Tensor a
+ Multilinear.Generic: toSequential :: Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: instance (Control.DeepSeq.NFData a, Data.Vector.Unboxed.Base.Unbox a) => Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a
+ Multilinear.Generic.MultiCore: instance (GHC.Float.Floating a, Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a) => GHC.Float.Floating (Multilinear.Generic.MultiCore.Tensor a)
+ Multilinear.Generic.MultiCore: instance (GHC.Num.Num a, Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a) => GHC.Num.Num (Multilinear.Generic.MultiCore.Tensor a)
+ Multilinear.Generic.MultiCore: instance (GHC.Real.Fractional a, Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a) => GHC.Real.Fractional (Multilinear.Generic.MultiCore.Tensor a)
+ Multilinear.Generic.MultiCore: instance (Multilinear.Class.Multilinear Multilinear.Generic.MultiCore.Tensor a, GHC.Show.Show a) => GHC.Show.Show (Multilinear.Generic.MultiCore.Tensor a)
+ Multilinear.Generic.Sequential: instance (Control.DeepSeq.NFData a, Data.Vector.Unboxed.Base.Unbox a) => Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a
+ Multilinear.Generic.Sequential: instance (GHC.Float.Floating a, Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a) => GHC.Float.Floating (Multilinear.Generic.Sequential.Tensor a)
+ Multilinear.Generic.Sequential: instance (GHC.Real.Fractional a, Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a) => GHC.Real.Fractional (Multilinear.Generic.Sequential.Tensor a)
+ Multilinear.Generic.Sequential: instance (Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a, GHC.Num.Num a) => GHC.Num.Num (Multilinear.Generic.Sequential.Tensor a)
+ Multilinear.Generic.Sequential: instance (Multilinear.Class.Multilinear Multilinear.Generic.Sequential.Tensor a, GHC.Show.Show a) => GHC.Show.Show (Multilinear.Generic.Sequential.Tensor a)
- Multilinear.Class: class (Unbox a) => Multilinear t a
+ Multilinear.Class: class (Generic (t a), NFData a, NFData (t a), Unbox a) => Multilinear t a
- Multilinear.Generic.MultiCore: (+.) :: (Unbox a, Num a, NFData a) => a -> Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: (+.) :: (Num a, Multilinear Tensor a) => a -> Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: (-.) :: (Unbox a, Num a, NFData a) => a -> Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: (-.) :: (Num a, Multilinear Tensor a) => a -> Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: (.*) :: (Unbox a, Num a, NFData a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.MultiCore: (.*) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.MultiCore: (.+) :: (Unbox a, Num a, NFData a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.MultiCore: (.+) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.MultiCore: (.-) :: (Unbox a, Num a, NFData a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.MultiCore: (.-) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.MultiCore: _elemByElem :: (Num a, Unbox a, NFData a) => Tensor a -> Tensor a -> (a -> a -> a) -> (Tensor a -> Tensor a -> Tensor a) -> Tensor a
+ Multilinear.Generic.MultiCore: _elemByElem :: (Num a, Multilinear Tensor a) => Tensor a -> Tensor a -> (a -> a -> a) -> (Tensor a -> Tensor a -> Tensor a) -> Tensor a
- Multilinear.Generic.MultiCore: filter :: Unbox a => (String -> Int -> Bool) -> Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: filter :: Multilinear Tensor a => (String -> Int -> Bool) -> Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: filterIndex :: Unbox a => String -> (Int -> Bool) -> Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: filterIndex :: Multilinear Tensor a => String -> (Int -> Bool) -> Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: map :: (Unbox a, Unbox b, NFData b) => (a -> b) -> Tensor a -> Tensor b
+ Multilinear.Generic.MultiCore: map :: (Multilinear Tensor a, Multilinear Tensor b) => (a -> b) -> Tensor a -> Tensor b
- Multilinear.Generic.MultiCore: zipT :: (Num a, NFData a, Unbox a) => (a -> a -> a) -> Tensor a -> Tensor a -> Tensor a
+ Multilinear.Generic.MultiCore: zipT :: (Num a, Multilinear Tensor a) => (a -> a -> a) -> Tensor a -> Tensor a -> Tensor a
- Multilinear.Generic.MultiCore: zipWith :: (Unbox a, Unbox b, Unbox c, NFData c) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c
+ Multilinear.Generic.MultiCore: zipWith :: (Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c
- Multilinear.Generic.Sequential: (*.) :: (Unbox a, Num a) => a -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: (*.) :: (Num a, Multilinear Tensor a) => a -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: (+.) :: (Unbox a, Num a) => a -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: (+.) :: (Num a, Multilinear Tensor a) => a -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: (-.) :: (Unbox a, Num a) => a -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: (-.) :: (Num a, Multilinear Tensor a) => a -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: (.*) :: (Unbox a, Num a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.Sequential: (.*) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.Sequential: (.+) :: (Unbox a, Num a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.Sequential: (.+) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.Sequential: (.-) :: (Unbox a, Num a) => Tensor a -> a -> Tensor a
+ Multilinear.Generic.Sequential: (.-) :: (Num a, Multilinear Tensor a) => Tensor a -> a -> Tensor a
- Multilinear.Generic.Sequential: _elemByElem :: (Num a, Unbox a, NFData a) => Tensor a -> Tensor a -> (a -> a -> a) -> (Tensor a -> Tensor a -> Tensor a) -> Tensor a
+ Multilinear.Generic.Sequential: _elemByElem :: (Num a, Multilinear Tensor a) => Tensor a -> Tensor a -> (a -> a -> a) -> (Tensor a -> Tensor a -> Tensor a) -> Tensor a
- Multilinear.Generic.Sequential: filter :: Unbox a => (String -> Int -> Bool) -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: filter :: Multilinear Tensor a => (String -> Int -> Bool) -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: filterIndex :: Unbox a => String -> (Int -> Bool) -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: filterIndex :: Multilinear Tensor a => String -> (Int -> Bool) -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: map :: (Unbox a, Unbox b) => (a -> b) -> Tensor a -> Tensor b
+ Multilinear.Generic.Sequential: map :: (Multilinear Tensor a, Multilinear Tensor b) => (a -> b) -> Tensor a -> Tensor b
- Multilinear.Generic.Sequential: zipT :: (Num a, NFData a, Unbox a) => (a -> a -> a) -> Tensor a -> Tensor a -> Tensor a
+ Multilinear.Generic.Sequential: zipT :: (Num a, Multilinear Tensor a) => (a -> a -> a) -> Tensor a -> Tensor a -> Tensor a
- Multilinear.Generic.Sequential: zipWith :: (Unbox a, Unbox b, Unbox c) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c
+ Multilinear.Generic.Sequential: zipWith :: (Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c
Files
- ChangeLog.md +4/−0
- multilinear.cabal +11/−11
- src/Multilinear.hs +1/−3
- src/Multilinear/Class.hs +14/−3
- src/Multilinear/Generic.hs +19/−3
- src/Multilinear/Generic/MultiCore.hs +32/−55
- src/Multilinear/Generic/Sequential.hs +38/−57
- test/sequential/Test/QuickCheck/Multilinear/Generic/Sequential.hs +1/−1
ChangeLog.md view
@@ -1,3 +1,7 @@+# 0.5.0.0, 2018-11-25 +- reformulation of Multilinear class - added Generic and NFData superclasses. This allows any Multilinear tensor to be derived generically in e.g. serialization instances and also fully evaluated for performace reasons +- added simple Sequential <=> MultiCore converters in Multilinear.Generic module + # 0.4.0.0, 2018-11-24 - added multi-core parallelism, sample benchmark is available in ./benchmark/results.zip - more robust QuickCheck tests
multilinear.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 033c8dbef9eab24df7b3396f684551d557968e2a8963865f404a7ca247732d7d+-- hash: 270ef768912c7c25c99a825bb179051c9389d6a254559adb76cceff3d7e9c203 name: multilinear-version: 0.4.0.0+version: 0.5.0.0 synopsis: Comprehensive and efficient (multi)linear algebra implementation. description: Comprehensive and efficient (multi)linear algebra implementation, based on generic tensor formalism and concise Ricci-Curbastro index syntax. More information available on GitHub: <https://github.com/ArturB/multilinear#readme> category: Machine learning@@ -45,7 +45,7 @@ Paths_multilinear hs-source-dirs: src- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W build-depends: base >=4.7 && <5@@ -63,7 +63,7 @@ Paths_multilinear hs-source-dirs: test/multicore- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: QuickCheck@@ -83,7 +83,7 @@ Paths_multilinear hs-source-dirs: test/sequential- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: QuickCheck@@ -102,7 +102,7 @@ Paths_multilinear hs-source-dirs: benchmark/multicore/memory- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5@@ -117,7 +117,7 @@ Paths_multilinear hs-source-dirs: benchmark/multicore/profile- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5@@ -132,7 +132,7 @@ Paths_multilinear hs-source-dirs: benchmark/multicore/time- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5@@ -147,7 +147,7 @@ Paths_multilinear hs-source-dirs: benchmark/sequential/memory- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W build-depends: base >=4.7 && <5@@ -162,7 +162,7 @@ Paths_multilinear hs-source-dirs: benchmark/sequential/profile- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W build-depends: base >=4.7 && <5@@ -177,7 +177,7 @@ Paths_multilinear hs-source-dirs: benchmark/sequential/time- default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving+ default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances GADTs GeneralizedNewtypeDeriving LambdaCase MultiParamTypeClasses ScopedTypeVariables StandaloneDeriving UndecidableInstances ghc-options: -O2 -W build-depends: base >=4.7 && <5
src/Multilinear.hs view
@@ -143,11 +143,9 @@ module Multilinear ( module Multilinear.Class, - module Multilinear.Generic, - module Multilinear.Generic.Sequential + module Multilinear.Generic ) where -- Re-export basic library modules import Multilinear.Class import Multilinear.Generic -import Multilinear.Generic.Sequential
src/Multilinear/Class.hs view
@@ -98,7 +98,6 @@ | [k:4] [3,4,5,6] | [k:4] [4,5,6,7] >>> m1 * m2 - \<i:3\> | [k:4] [30,40,50,60] | [k:4] [40,50,60,70] @@ -146,14 +145,23 @@ Multilinear(..) ) where +import Control.DeepSeq import Data.Maybe import Data.Set import qualified Data.Vector.Unboxed as Unboxed +import GHC.Generics import Multilinear.Index -{-| Multidimensional array treated as multilinear map - tensor -} +{-| Multidimensional array treated as multilinear map - tensor + Superclasses: + - Generic (t a) - enforce Generic instance, allowing to derive e.g. serialization instances for any tensor + - NFData a, NFData (t a) - for performance reasons, every tensor should be able to be fully evaluated + - Unboxed.Unbox a - for performance reasons, every tensor should be implemented using Vector.Unboxed + -} class ( - Unboxed.Unbox a + Generic (t a), + NFData a, NFData (t a), + Unboxed.Unbox a ) => Multilinear t a where {-| Generic tensor constructor, using combinator function on its indices -} @@ -311,3 +319,6 @@ infixl 6 <<<| (<<<|) :: t a -> String -> t a t <<<| n = shiftLeftmost t n + + -- | Move covariant indices to deeper recursion level + standardize :: t a -> t a
src/Multilinear/Generic.hs view
@@ -1,6 +1,6 @@ {-| Module : Multilinear.Generic -Description : Re-export default tensor implementation +Description : Re-export default tensor implementation and provides simple tensor converters Copyright : (c) Artur M. Brodzki, 2018 License : BSD3 Maintainer : artur@brodzki.org @@ -10,7 +10,23 @@ -} module Multilinear.Generic ( - module DefaultTensorImplementation + module Multilinear.Generic.Sequential, + toMultiCore, toSequential ) where -import Multilinear.Generic.Sequential as DefaultTensorImplementation +import Data.Vector as Boxed +import Multilinear.Generic.Sequential +import qualified Multilinear.Generic.Sequential as Sequential +import qualified Multilinear.Generic.MultiCore as MultiCore + +-- | Convert Sequential tensor to MultiCore +toMultiCore :: Sequential.Tensor a -> MultiCore.Tensor a +toMultiCore (Sequential.Scalar x) = MultiCore.Scalar x +toMultiCore (Sequential.SimpleFinite i ts) = MultiCore.SimpleFinite i ts +toMultiCore (Sequential.FiniteTensor i ts) = MultiCore.FiniteTensor i $ Boxed.map toMultiCore ts + +-- | Convert MultiCore tensor to Sequential +toSequential :: MultiCore.Tensor a -> Sequential.Tensor a +toSequential (MultiCore.Scalar x) = Sequential.Scalar x +toSequential (MultiCore.SimpleFinite i ts) = Sequential.SimpleFinite i ts +toSequential (MultiCore.FiniteTensor i ts) = Sequential.FiniteTensor i $ Boxed.map toSequential ts
src/Multilinear/Generic/MultiCore.hs view
@@ -14,8 +14,8 @@ Tensor(..), -- * Auxiliary functions (!), isScalar, isSimple, isFiniteTensor, - tensorIndex, _standardize, _mergeScalars, - _map, _contractedIndices, _elemByElem, zipT, + tensorIndex, _mergeScalars, + _contractedIndices, _elemByElem, zipT, -- * Additional functions (.+), (.-), (.*), (+.), (-.), (*.), Multilinear.Generic.MultiCore.map, @@ -124,18 +124,13 @@ -- | NFData instance instance NFData a => NFData (Tensor a) --- | Move contravariant indices to lower recursion level -{-# INLINE _standardize #-} -_standardize :: (Unboxed.Unbox a) => Tensor a -> Tensor a -_standardize tens = foldl' (<<<|) tens $ Index.indexName <$> (Index.isContravariant `Prelude.filter` indices tens) - -- | Print tensor instance ( - Unboxed.Unbox a, Show a + Multilinear Tensor a, Show a ) => Show (Tensor a) where -- merge errors first and then print whole tensor - show = show' . _standardize + show = show' . standardize where show' x = case x of -- Scalar is showed simply as its value @@ -162,23 +157,6 @@ _ -> FiniteTensor index1 $ _mergeScalars <$> ts1 _ -> x --- | Generic map function, which does not require a,b types to be Num -_map :: ( - Unboxed.Unbox a, Unboxed.Unbox b, NFData b - ) => (a -> b) - -> Tensor a - -> Tensor b -_map f x = case x of - -- Mapping scalar simply maps its value - Scalar v -> Scalar $ f v - -- Mapping complex tensor does mapping element by element - SimpleFinite index ts -> SimpleFinite index (f `Unboxed.map` ts) - FiniteTensor index ts -> - let len = Boxed.length ts - lts = Boxed.toList $ _map f <$> ts - ltsp = lts `Parallel.using` Parallel.parListChunk (len `div` 8) Parallel.rdeepseq - in FiniteTensor index $ Boxed.fromList ltsp - {-| Transpose Vector of Vectors, analogous to Data.List.transpose function. It is assumed, that all vectors on deeper recursion level have the same length. -} _transpose :: Boxed.Vector (Boxed.Vector a) -- ^ Vector of vectors to transpose -> Boxed.Vector (Boxed.Vector a) @@ -204,7 +182,7 @@ {-| Apply a tensor operator (here denoted by (+) ) elem by elem, trying to connect as many common indices as possible -} {-# INLINE _elemByElem' #-} -_elemByElem' :: (Num a, Unboxed.Unbox a, NFData a) +_elemByElem' :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First argument of operator -> Tensor a -- ^ Second argument of operator -> (a -> a -> a) -- ^ Operator on tensor elements if indices are different @@ -253,7 +231,7 @@ {-| Apply a tensor operator elem by elem and merge scalars to simple tensor at the and -} {-# INLINE _elemByElem #-} -_elemByElem :: (Num a, Unboxed.Unbox a, NFData a) +_elemByElem :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First argument of operator -> Tensor a -- ^ Second argument of operator -> (a -> a -> a) -- ^ Operator on tensor elements if indices are different @@ -271,7 +249,7 @@ -- | Zipping two tensors with a combinator, assuming they have the same indices. {-# INLINE zipT #-} zipT :: ( - Num a, NFData a, Unboxed.Unbox a + Num a, Multilinear Tensor a ) => (a -> a -> a) -- ^ The zipping combinator -> Tensor a -- ^ First tensor to zip -> Tensor a -- ^ Second tensor to zip @@ -293,7 +271,7 @@ -- | dot product of two tensors {-# INLINE dot #-} -dot :: (Num a, Unboxed.Unbox a, NFData a) +dot :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First dot product argument -> Tensor a -- ^ Second dot product argument -> Tensor a -- ^ Resulting dot product @@ -347,9 +325,8 @@ " - index1 is " ++ show i1' ++ " and index2 is " ++ show i2' - -- | Tensors can be added, subtracted and multiplicated -instance (Unboxed.Unbox a, Num a, NFData a) => Num (Tensor a) where +instance (Num a, Multilinear Tensor a) => Num (Tensor a) where -- Adding - element by element {-# INLINE (+) #-} @@ -377,7 +354,7 @@ fromInteger x = Scalar $ fromInteger x -- | Tensors can be divided by each other -instance (Unboxed.Unbox a, Fractional a, NFData a) => Fractional (Tensor a) where +instance (Fractional a, Multilinear Tensor a) => Fractional (Tensor a) where -- Tensor dividing: TODO {-# INLINE (/) #-} _ / _ = error "TODO" @@ -389,7 +366,7 @@ -- Real-number functions on tensors. -- Function of tensor is tensor of function of its elements -- E.g. exp [1,2,3,4] = [exp 1, exp2, exp3, exp4] -instance (Unboxed.Unbox a, Floating a, NFData a) => Floating (Tensor a) where +instance (Floating a, Multilinear Tensor a) => Floating (Tensor a) where {-| PI number -} {-# INLINE pi #-} @@ -444,7 +421,7 @@ atanh t = atanh `Multilinear.Generic.MultiCore.map` t -- Multilinear operations -instance (Unboxed.Unbox a) => Multilinear Tensor a where +instance (NFData a, Unboxed.Unbox a) => Multilinear Tensor a where -- Generic tensor constructor -- If only one upper index is given, generate a SimpleFinite tensor with upper index fromIndices [u] [] [s] [] f = @@ -608,11 +585,14 @@ in _mergeScalars result -- there is only one index and therefore it cannot be shifted | otherwise = t1 + + -- | Move contravariant indices to lower recursion level + standardize tens = foldl' (<<<|) tens $ Index.indexName <$> (Index.isContravariant `Prelude.filter` indices tens) -- Add scalar right {-# INLINE (.+) #-} (.+) :: ( - Unboxed.Unbox a, Num a, NFData a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -621,7 +601,7 @@ -- Subtract scalar right {-# INLINE (.-) #-} (.-) :: ( - Unboxed.Unbox a, Num a, NFData a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -630,7 +610,7 @@ -- Multiplicate by scalar right {-# INLINE (.*) #-} (.*) :: ( - Unboxed.Unbox a, Num a, NFData a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -639,7 +619,7 @@ -- Add scalar left {-# INLINE (+.) #-} (+.) :: ( - Unboxed.Unbox a, Num a, NFData a + Num a, Multilinear Tensor a ) => a -> Tensor a -> Tensor a @@ -648,7 +628,7 @@ -- Subtract scalar left {-# INLINE (-.) #-} (-.) :: ( - Unboxed.Unbox a, Num a, NFData a + Num a, Multilinear Tensor a ) => a -> Tensor a -> Tensor a @@ -663,14 +643,11 @@ -> Tensor a x *. t = (x*) `Multilinear.Generic.MultiCore.map` t - -{-| Simple mapping -} -{-| @map f t@ returns tensor @t2@ in which @t2[i1,i2,...] = f t[i1,i2,...]@ -} -{-# INLINE map #-} +-- | Simple mapping map :: ( - Unboxed.Unbox a, Unboxed.Unbox b, NFData b - ) => (a -> b) - -> Tensor a + Multilinear Tensor a, Multilinear Tensor b + ) => (a -> b) + -> Tensor a -> Tensor b map f x = case x of -- Mapping scalar simply maps its value @@ -695,7 +672,7 @@ If for some index all elements are removed, the index itself is removed from tensor. -} {-# INLINE filter #-} filter :: ( - Unboxed.Unbox a + Multilinear Tensor a ) => (String -> Int -> Bool) -- ^ filter function -> Tensor a -- ^ tensor to filter -> Tensor a @@ -718,7 +695,7 @@ {-| Filtering one index of tensor. -} {-# INLINE filterIndex #-} filterIndex :: ( - Unboxed.Unbox a + Multilinear Tensor a ) => String -- ^ Index name to filter -> (Int -> Bool) -- ^ filter function -> Tensor a -- ^ tensor to filter @@ -728,7 +705,7 @@ {-| Zip tensors with binary combinator, assuming they have all indices the same -} {-# INLINE zipWith' #-} zipWith' :: ( - Unboxed.Unbox a, Unboxed.Unbox b, Unboxed.Unbox c, NFData c + Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c ) => (a -> b -> c) -> Tensor a -> Tensor b @@ -736,9 +713,9 @@ -- Zipping two Scalars simply combines their values zipWith' f (Scalar x1) (Scalar x2) = Scalar $ f x1 x2 -- zipping complex tensor with scalar -zipWith' f t (Scalar x) = (`f` x) `_map` t +zipWith' f t (Scalar x) = (`f` x) `Multilinear.Generic.MultiCore.map` t -- zipping scalar with complex tensor -zipWith' f (Scalar x) t = (x `f`) `_map` t +zipWith' f (Scalar x) t = (x `f`) `Multilinear.Generic.MultiCore.map` t -- Two simple tensors case zipWith' f (SimpleFinite index1 v1) (SimpleFinite index2 v2) = if index1 == index2 then @@ -754,12 +731,12 @@ {-# INLINE zipWith #-} zipWith :: ( - Unboxed.Unbox a, Unboxed.Unbox b, Unboxed.Unbox c, NFData c + Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c ) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c zipWith f t1 t2 = - let t1' = _standardize t1 - t2' = _standardize t2 + let t1' = standardize t1 + t2' = standardize t2 in zipWith' f t1' t2'
src/Multilinear/Generic/Sequential.hs view
@@ -14,8 +14,8 @@ Tensor(..), -- * Auxiliary functions (!), isScalar, isSimple, isFiniteTensor, - tensorIndex, _standardize, _mergeScalars, - _map, _contractedIndices, _elemByElem, zipT, + tensorIndex, _mergeScalars, + _contractedIndices, _elemByElem, zipT, -- * Additional functions (.+), (.-), (.*), (+.), (-.), (*.), Multilinear.Generic.Sequential.map, @@ -73,6 +73,9 @@ } -> Tensor a deriving (Eq, Generic) +-- | NFData instance +instance NFData a => NFData (Tensor a) + {-| Return true if tensor is a scalar -} {-# INLINE isScalar #-} isScalar :: Unboxed.Unbox a => Tensor a -> Bool @@ -120,21 +123,14 @@ SimpleFinite ind ts -> Scalar $ ts Unboxed.! (i `mod` Finite.indexSize ind) FiniteTensor ind ts -> ts Boxed.! (i `mod` Finite.indexSize ind) --- | NFData instance -instance NFData a => NFData (Tensor a) - --- | Move contravariant indices to lower recursion level -{-# INLINE _standardize #-} -_standardize :: (Unboxed.Unbox a) => Tensor a -> Tensor a -_standardize tens = foldl' (<<<|) tens $ Index.indexName <$> (Index.isContravariant `Prelude.filter` indices tens) - -- | Print tensor +-- | Assumes tensor is already in Multilinear class, because standardize function instance ( - Unboxed.Unbox a, Show a + Multilinear Tensor a, Show a ) => Show (Tensor a) where -- merge errors first and then print whole tensor - show = show' . _standardize + show = show' . standardize where show' x = case x of -- Scalar is showed simply as its value @@ -161,19 +157,6 @@ _ -> FiniteTensor index1 $ _mergeScalars <$> ts1 _ -> x --- | Generic map function, which does not require a,b types to be Num -_map :: ( - Unboxed.Unbox a, Unboxed.Unbox b - ) => (a -> b) - -> Tensor a - -> Tensor b -_map f x = case x of - -- Mapping scalar simply maps its value - Scalar v -> Scalar $ f v - -- Mapping complex tensor does mapping element by element - SimpleFinite index ts -> SimpleFinite index (f `Unboxed.map` ts) - FiniteTensor index ts -> FiniteTensor index $ _map f <$> ts - {-| Transpose Vector of Vectors, analogous to Data.List.transpose function. It is assumed, that all vectors on deeper recursion level have the same length. -} _transpose :: Boxed.Vector (Boxed.Vector a) -- ^ Vector of vectors to transpose -> Boxed.Vector (Boxed.Vector a) @@ -199,7 +182,7 @@ {-| Apply a tensor operator (here denoted by (+) ) elem by elem, trying to connect as many common indices as possible -} {-# INLINE _elemByElem' #-} -_elemByElem' :: (Num a, Unboxed.Unbox a, NFData a) +_elemByElem' :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First argument of operator -> Tensor a -- ^ Second argument of operator -> (a -> a -> a) -- ^ Operator on tensor elements if indices are different @@ -233,7 +216,7 @@ {-| Apply a tensor operator elem by elem and merge scalars to simple tensor at the and -} {-# INLINE _elemByElem #-} -_elemByElem :: (Num a, Unboxed.Unbox a, NFData a) +_elemByElem :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First argument of operator -> Tensor a -- ^ Second argument of operator -> (a -> a -> a) -- ^ Operator on tensor elements if indices are different @@ -251,7 +234,7 @@ -- | Zipping two tensors with a combinator, assuming they have the same indices. {-# INLINE zipT #-} zipT :: ( - Num a, NFData a, Unboxed.Unbox a + Num a, Multilinear Tensor a ) => (a -> a -> a) -- ^ The zipping combinator -> Tensor a -- ^ First tensor to zip -> Tensor a -- ^ Second tensor to zip @@ -271,7 +254,7 @@ -- | dot product of two tensors {-# INLINE dot #-} -dot :: (Num a, Unboxed.Unbox a, NFData a) +dot :: (Num a, Multilinear Tensor a) => Tensor a -- ^ First dot product argument -> Tensor a -- ^ Second dot product argument -> Tensor a -- ^ Resulting dot product @@ -324,7 +307,7 @@ -- | Tensors can be added, subtracted and multiplicated -instance (Unboxed.Unbox a, Num a, NFData a) => Num (Tensor a) where +instance (Multilinear Tensor a, Num a) => Num (Tensor a) where -- Adding - element by element {-# INLINE (+) #-} @@ -352,7 +335,7 @@ fromInteger x = Scalar $ fromInteger x -- | Tensors can be divided by each other -instance (Unboxed.Unbox a, Fractional a, NFData a) => Fractional (Tensor a) where +instance (Fractional a, Multilinear Tensor a) => Fractional (Tensor a) where -- Tensor dividing: TODO {-# INLINE (/) #-} _ / _ = error "TODO" @@ -364,7 +347,7 @@ -- Real-number functions on tensors. -- Function of tensor is tensor of function of its elements -- E.g. exp [1,2,3,4] = [exp 1, exp2, exp3, exp4] -instance (Unboxed.Unbox a, Floating a, NFData a) => Floating (Tensor a) where +instance (Floating a, Multilinear Tensor a) => Floating (Tensor a) where {-| PI number -} {-# INLINE pi #-} @@ -419,7 +402,7 @@ atanh t = atanh `Multilinear.Generic.Sequential.map` t -- Multilinear operations -instance (Unboxed.Unbox a) => Multilinear Tensor a where +instance (NFData a, Unboxed.Unbox a) => Multilinear Tensor a where -- Generic tensor constructor -- If only one upper index is given, generate a SimpleFinite tensor with upper index fromIndices [u] [] [s] [] f = @@ -546,18 +529,15 @@ {-| Transpose a tensor (switch all indices types) -} {-# INLINE transpose #-} transpose (Scalar x) = Scalar x - transpose (FiniteTensor (Finite.Covariant count name) ts) = FiniteTensor (Finite.Contravariant count name) (Multilinear.transpose <$> ts) transpose (FiniteTensor (Finite.Contravariant count name) ts) = FiniteTensor (Finite.Covariant count name) (Multilinear.transpose <$> ts) - transpose (SimpleFinite (Finite.Covariant count name) ts) = SimpleFinite (Finite.Contravariant count name) ts transpose (SimpleFinite (Finite.Contravariant count name) ts) = SimpleFinite (Finite.Covariant count name) ts - {-| Shift tensor index right -} {-| Moves given index one level deeper in recursion -} -- Scalar has no indices to shift @@ -584,10 +564,14 @@ -- there is only one index and therefore it cannot be shifted | otherwise = t1 + -- | Move contravariant indices to lower recursion level + standardize tens = foldl' (<<<|) tens $ Index.indexName <$> (Index.isContravariant `Prelude.filter` indices tens) + + -- Add scalar right {-# INLINE (.+) #-} (.+) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -596,7 +580,7 @@ -- Subtract scalar right {-# INLINE (.-) #-} (.-) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -605,7 +589,7 @@ -- Multiplicate by scalar right {-# INLINE (.*) #-} (.*) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => Tensor a -> a -> Tensor a @@ -614,7 +598,7 @@ -- Add scalar left {-# INLINE (+.) #-} (+.) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => a -> Tensor a -> Tensor a @@ -623,7 +607,7 @@ -- Subtract scalar left {-# INLINE (-.) #-} (-.) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => a -> Tensor a -> Tensor a @@ -632,20 +616,17 @@ -- Multiplicate by scalar left {-# INLINE (*.) #-} (*.) :: ( - Unboxed.Unbox a, Num a + Num a, Multilinear Tensor a ) => a -> Tensor a -> Tensor a x *. t = (x*) `Multilinear.Generic.Sequential.map` t - -{-| Simple mapping -} -{-| @map f t@ returns tensor @t2@ in which @t2[i1,i2,...] = f t[i1,i2,...]@ -} -{-# INLINE map #-} +-- | Simple mapping map :: ( - Unboxed.Unbox a, Unboxed.Unbox b - ) => (a -> b) - -> Tensor a + Multilinear Tensor a, Multilinear Tensor b + ) => (a -> b) + -> Tensor a -> Tensor b map f x = case x of -- Mapping scalar simply maps its value @@ -666,7 +647,7 @@ If for some index all elements are removed, the index itself is removed from tensor. -} {-# INLINE filter #-} filter :: ( - Unboxed.Unbox a + Multilinear Tensor a ) => (String -> Int -> Bool) -- ^ filter function -> Tensor a -- ^ tensor to filter -> Tensor a @@ -689,7 +670,7 @@ {-| Filtering one index of tensor. -} {-# INLINE filterIndex #-} filterIndex :: ( - Unboxed.Unbox a + Multilinear Tensor a ) => String -- ^ Index name to filter -> (Int -> Bool) -- ^ filter function -> Tensor a -- ^ tensor to filter @@ -699,7 +680,7 @@ {-| Zip tensors with binary combinator, assuming they have all indices the same -} {-# INLINE zipWith' #-} zipWith' :: ( - Unboxed.Unbox a, Unboxed.Unbox b, Unboxed.Unbox c + Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c ) => (a -> b -> c) -> Tensor a -> Tensor b @@ -707,9 +688,9 @@ -- Zipping two Scalars simply combines their values zipWith' f (Scalar x1) (Scalar x2) = Scalar $ f x1 x2 -- zipping complex tensor with scalar -zipWith' f t (Scalar x) = (`f` x) `_map` t +zipWith' f t (Scalar x) = (`f` x) `Multilinear.Generic.Sequential.map` t -- zipping scalar with complex tensor -zipWith' f (Scalar x) t = (x `f`) `_map` t +zipWith' f (Scalar x) t = (x `f`) `Multilinear.Generic.Sequential.map` t -- Two simple tensors case zipWith' f (SimpleFinite index1 v1) (SimpleFinite index2 v2) = if index1 == index2 then @@ -725,12 +706,12 @@ {-# INLINE zipWith #-} zipWith :: ( - Unboxed.Unbox a, Unboxed.Unbox b, Unboxed.Unbox c + Multilinear Tensor a, Multilinear Tensor b, Multilinear Tensor c ) => (a -> b -> c) -> Tensor a -> Tensor b -> Tensor c zipWith f t1 t2 = - let t1' = _standardize t1 - t2' = _standardize t2 + let t1' = standardize t1 + t2' = standardize t2 in zipWith' f t1' t2'
test/sequential/Test/QuickCheck/Multilinear/Generic/Sequential.hs view
@@ -76,6 +76,6 @@ where ts = pure (*) <*> tensors1D <*> tensors1D -- | Arbitrary random generating instance of Tensor Double --- | Simply choose a tensot from tensors list above +-- | Simply choose a tensor from tensors list above instance Arbitrary (Tensor Double) where arbitrary = elements tensors3D