multilinear-io 0.2.3 → 0.3.0.0
raw patch · 8 files changed
+60/−49 lines, 8 filesdep ~multilinearsetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: multilinear
API changes (from Hackage documentation)
- Multilinear.Generic.Serialize: instance Data.Aeson.Types.FromJSON.FromJSON a => Data.Aeson.Types.FromJSON.FromJSON (Multilinear.Generic.Tensor a)
- Multilinear.Generic.Serialize: instance Data.Aeson.Types.ToJSON.ToJSON a => Data.Aeson.Types.ToJSON.ToJSON (Multilinear.Generic.Tensor a)
- Multilinear.Generic.Serialize: instance Data.Csv.Conversion.FromField a => Data.Csv.Conversion.FromRecord (Multilinear.Generic.Tensor a)
- Multilinear.Generic.Serialize: instance Data.Csv.Conversion.ToField a => Data.Csv.Conversion.ToRecord (Multilinear.Generic.Tensor a)
- Multilinear.Generic.Serialize: instance Data.Serialize.Serialize a => Data.Serialize.Serialize (Multilinear.Generic.Tensor a)
+ Multilinear.Generic.Serialize: instance (Data.Aeson.Types.FromJSON.FromJSON a, Data.Vector.Unboxed.Base.Unbox a) => Data.Aeson.Types.FromJSON.FromJSON (Multilinear.Generic.Tensor a)
+ Multilinear.Generic.Serialize: instance (Data.Aeson.Types.ToJSON.ToJSON a, Data.Vector.Unboxed.Base.Unbox a) => Data.Aeson.Types.ToJSON.ToJSON (Multilinear.Generic.Tensor a)
+ Multilinear.Generic.Serialize: instance (Data.Csv.Conversion.FromField a, Data.Vector.Unboxed.Base.Unbox a) => Data.Csv.Conversion.FromRecord (Multilinear.Generic.Tensor a)
+ Multilinear.Generic.Serialize: instance (Data.Csv.Conversion.ToField a, Data.Vector.Unboxed.Base.Unbox a) => Data.Csv.Conversion.ToRecord (Multilinear.Generic.Tensor a)
+ Multilinear.Generic.Serialize: instance (Data.Serialize.Serialize a, Data.Vector.Unboxed.Base.Unbox a) => Data.Serialize.Serialize (Multilinear.Generic.Tensor a)
- Multilinear.Generic.Serialize: fromBinary :: Serialize a => ByteString -> Either String (Tensor a)
+ Multilinear.Generic.Serialize: fromBinary :: (Serialize a, Unbox a) => ByteString -> Either String (Tensor a)
- Multilinear.Generic.Serialize: fromBinaryFile :: Serialize a => String -> ExceptT String IO (Tensor a)
+ Multilinear.Generic.Serialize: fromBinaryFile :: (Serialize a, Unbox a) => String -> ExceptT String IO (Tensor a)
- Multilinear.Generic.Serialize: fromCSVFile :: FromField a => String -> Char -> String -> ExceptT String IO (Tensor a)
+ Multilinear.Generic.Serialize: fromCSVFile :: (FromField a, Unbox a) => String -> Char -> String -> ExceptT String IO (Tensor a)
- Multilinear.Generic.Serialize: fromJSON :: FromJSON a => ByteString -> Maybe (Tensor a)
+ Multilinear.Generic.Serialize: fromJSON :: (FromJSON a, Unbox a) => ByteString -> Maybe (Tensor a)
- Multilinear.Generic.Serialize: fromJSONFile :: FromJSON a => String -> MaybeT IO (Tensor a)
+ Multilinear.Generic.Serialize: fromJSONFile :: (FromJSON a, Unbox a) => String -> MaybeT IO (Tensor a)
- Multilinear.Generic.Serialize: toBinary :: Serialize a => Tensor a -> ByteString
+ Multilinear.Generic.Serialize: toBinary :: (Serialize a, Unbox a) => Tensor a -> ByteString
- Multilinear.Generic.Serialize: toBinaryFile :: Serialize a => Tensor a -> String -> IO ()
+ Multilinear.Generic.Serialize: toBinaryFile :: (Serialize a, Unbox a) => Tensor a -> String -> IO ()
- Multilinear.Generic.Serialize: toCSVFile :: ToField a => Tensor a -> String -> IO ()
+ Multilinear.Generic.Serialize: toCSVFile :: (ToField a, Unbox a) => Tensor a -> String -> IO ()
- Multilinear.Generic.Serialize: toJSON :: ToJSON a => Tensor a -> ByteString
+ Multilinear.Generic.Serialize: toJSON :: (ToJSON a, Unbox a) => Tensor a -> ByteString
- Multilinear.Generic.Serialize: toJSONFile :: ToJSON a => Tensor a -> String -> IO ()
+ Multilinear.Generic.Serialize: toJSONFile :: (ToJSON a, Unbox a) => Tensor a -> String -> IO ()
Files
- ChangeLog.md +3/−0
- README.md +3/−3
- Setup.hs +2/−2
- multilinear-io.cabal +15/−16
- src/Multilinear/Generic/Serialize.hs +34/−25
- test/binary/Spec.hs +1/−1
- test/csv/Spec.hs +1/−1
- test/json/Spec.hs +1/−1
ChangeLog.md view
@@ -1,3 +1,6 @@+# 0.3.0.0, 2018-11-14 +- ported to multilinear-0.3.0.0 + # 0.2.3, 2018-11-02 - IO ported to Conduit based - support for CSV with cassava
README.md view
@@ -1,9 +1,9 @@ # README ## Build status -- Travis (Linux, macOS): [](https://travis-ci.org/ArturB/multilinear) -- AppVeyor (Windows): [](https://ci.appveyor.com/api/projects/status/github/ArturB/multilinear) +- Travis (Linux, macOS): [](https://travis-ci.org/ArturB/multilinear-io) +- AppVeyor (Windows): [](https://ci.appveyor.com/api/projects/status/github/ArturB/multilinear-io) ## Summary This package provides conduit-based input/output capability for [Multilinear](https://github.com/ArturB/multilinear) package, in various formats:
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple -main = defaultMain +import Distribution.Simple+main = defaultMain
multilinear-io.cabal view
@@ -1,13 +1,11 @@-cabal-version: 1.12 ---- This file has been generated from package.yaml by hpack version 0.31.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: f722f54ad6081f3a4e98e1615679d778fd0ba99c89c3d5db3165762ff54a5bd3+-- hash: 86b14a55f0044713d22b5d0d065b6241e7d37686463ad116dde83c012791e38b name: multilinear-io-version: 0.2.3+version: 0.3.0.0 synopsis: Input/output capability for multilinear package. description: Input & output capability for multilinear package <https://hackage.haskell.org/package/multilinear>. Supports various file formats: binary, CSV, JSON. More information available on GitHub: <https://github.com/ArturB/multilinear-io#readme> category: Machine learning@@ -19,9 +17,10 @@ license: BSD3 license-file: LICENSE build-type: Simple+cabal-version: >= 1.10 extra-source-files:- README.md ChangeLog.md+ README.md source-repository head type: git@@ -37,7 +36,7 @@ hs-source-dirs: src default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances MultiParamTypeClasses ScopedTypeVariables- ghc-options: -O2 -Wall+ ghc-options: -O2 -W build-depends: aeson , base >=4.7 && <5@@ -47,7 +46,7 @@ , cereal-vector , conduit , either- , multilinear >=0.2.0 && <0.3+ , multilinear , transformers , vector , zlib@@ -61,12 +60,12 @@ hs-source-dirs: test/binary default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances MultiParamTypeClasses ScopedTypeVariables- ghc-options: -O2 -Wall -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5 , directory , either- , multilinear >=0.2.0 && <0.3+ , multilinear , multilinear-io , transformers default-language: Haskell2010@@ -79,12 +78,12 @@ hs-source-dirs: test/csv default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances MultiParamTypeClasses ScopedTypeVariables- ghc-options: -O2 -Wall -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5 , directory , either- , multilinear >=0.2.0 && <0.3+ , multilinear , multilinear-io , transformers default-language: Haskell2010@@ -97,12 +96,12 @@ hs-source-dirs: test/json default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances MultiParamTypeClasses ScopedTypeVariables- ghc-options: -O2 -Wall -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5 , directory , either- , multilinear >=0.2.0 && <0.3+ , multilinear , multilinear-io , transformers default-language: Haskell2010@@ -115,14 +114,14 @@ hs-source-dirs: benchmark default-extensions: DeriveGeneric FlexibleContexts FlexibleInstances MultiParamTypeClasses ScopedTypeVariables- ghc-options: -O2 -Wall -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -O2 -W -threaded -rtsopts -with-rtsopts=-N build-depends: base >=4.7 && <5 , criterion , deepseq , directory , either- , multilinear >=0.2.0 && <0.3+ , multilinear , multilinear-io , transformers default-language: Haskell2010
src/Multilinear/Generic/Serialize.hs view
@@ -20,55 +20,54 @@ ) where import Codec.Compression.GZip -import Data.Conduit -import Data.Conduit.Combinators import Control.Monad.Trans.Class import Control.Monad.Trans.Except import Control.Monad.Trans.Maybe import Data.Aeson import qualified Data.ByteString.Internal as BS import qualified Data.ByteString.Lazy as ByteString +import Data.Conduit +import Data.Conduit.Combinators import Data.Csv import Data.Either import Data.Serialize import qualified Data.Vector as Boxed import Data.Vector.Serialize () +import qualified Data.Vector.Unboxed as Unboxed import Multilinear.Generic import qualified Multilinear.Index.Finite as Finite import Multilinear.Index.Finite.Serialize () import Multilinear.Index.Infinite.Serialize () -- Binary serialization instance -instance Serialize a => Serialize (Tensor a) +instance (Serialize a, Unboxed.Unbox a) => Serialize (Tensor a) -- JSON serialization instance -instance ToJSON a => ToJSON (Tensor a) +instance (ToJSON a, Unboxed.Unbox a) => ToJSON (Tensor a) -- JSON deserialization instance -instance FromJSON a => FromJSON (Tensor a) +instance (FromJSON a, Unboxed.Unbox a) => FromJSON (Tensor a) -- CSV serialization instance -instance ToField a => ToRecord (Tensor a) where +instance (ToField a, Unboxed.Unbox a) => ToRecord (Tensor a) where toRecord (Scalar x) = record [toField x] toRecord (SimpleFinite _ scalars) = toRecord scalars toRecord _ = error "Only 1-order tensor may be converted to record!" -instance FromField a => FromRecord (Tensor a) where +instance (FromField a, Unboxed.Unbox a) => FromRecord (Tensor a) where parseRecord v = if Boxed.length v == 1 then Scalar <$> v .! 0 else - --FiniteTensor (Finite.Covariant (Boxed.length v) "i") <$> v error "non-scalar" - {-| Serialize tensor to zlib compressed binary string -} toBinary :: ( - Serialize a + Serialize a, Unboxed.Unbox a ) => Tensor a -- ^ Tensor to serialize -> ByteString.ByteString -- ^ Tensor serialized to lazy ByteString toBinary = compress . Data.Serialize.encodeLazy {-| Write tensor to binary file. Uses compression with gzip -} toBinaryFile :: ( - Serialize a + Serialize a, Unboxed.Unbox a ) => Tensor a -- ^ Tensor to serialize -> String -- ^ File name -> IO () @@ -79,14 +78,14 @@ {-| Deserialize tensor from zlib compressed binary string -} fromBinary :: ( - Serialize a + Serialize a, Unboxed.Unbox a ) => ByteString.ByteString -- ^ ByteString to deserialize -> Either String (Tensor a) -- ^ Deserialized tensor or an error message. fromBinary = Data.Serialize.decodeLazy . decompress {-| Read tensor from binary file -} fromBinaryFile :: ( - Serialize a + Serialize a, Unboxed.Unbox a ) => String -- ^ File path. -> ExceptT String IO (Tensor a) -- ^ Deserialized tensor or an error message fromBinaryFile fileName = do @@ -96,14 +95,14 @@ {-| Serialize tensor to JSON string -} toJSON :: ( - ToJSON a + ToJSON a, Unboxed.Unbox a ) => Tensor a -- ^ Tensor to serialize. -> ByteString.ByteString -- ^ Tensor serialized to lazy ByteString. toJSON = Data.Aeson.encode {-| Write tensor to JSON file -} toJSONFile :: ( - ToJSON a + ToJSON a, Unboxed.Unbox a ) => Tensor a -- ^ Tensor to serialize -> String -- ^ File path. -> IO () @@ -114,14 +113,14 @@ {-| Deserialize tensor from JSON string -} fromJSON :: ( - FromJSON a + FromJSON a, Unboxed.Unbox a ) => ByteString.ByteString -- ^ ByteString to deserialize -> Maybe (Tensor a) -- ^ Deserialized tensor or Nothing, if deserialization error occured. fromJSON = Data.Aeson.decode {-| Read tensor from JSON file -} fromJSONFile :: ( - FromJSON a + FromJSON a, Unboxed.Unbox a ) => String -- ^ File path. -> MaybeT IO (Tensor a) -- ^ Deserialized tensor or Nothing, if error occured. fromJSONFile fileName = do @@ -131,25 +130,35 @@ {-| Write tensor to CSV file -} toCSVFile :: ( - ToField a + ToField a, Unboxed.Unbox a ) => Tensor a -- ^ Tensor to serialize -> String -- ^ File path -> IO () -toCSVFile (FiniteTensor _ vrows) fileName = do - let rows = Boxed.toList vrows - let bs = Data.Csv.encode rows + +-- Encoding Scalar value +toCSVFile s@(Scalar _) fileName = do + let bs = Data.Csv.encode [s] runConduitRes $ sourceLazy bs .| sinkFile fileName + +-- Encoding SimpleFinite (1D) tensor toCSVFile (SimpleFinite _ vs) fileName = do let rows = [vs] let bs = Data.Csv.encode rows runConduitRes $ sourceLazy bs .| sinkFile fileName +-- Encoding FiniteTensor (many dimensions) +toCSVFile (FiniteTensor _ vrows) fileName = do + let rows = Boxed.toList vrows + let bs = Data.Csv.encode rows + runConduitRes $ + sourceLazy bs .| sinkFile fileName + {-| Read tensor from CSV -} fromCSVFile :: ( - FromField a + FromField a, Unboxed.Unbox a ) => String -- ^ File path. -> Char -- ^ CSV separator -> String -- ^ Matrix indices names @@ -158,13 +167,13 @@ --let csvSettings = CSVSettings separator Nothing contents <- lift $ runConduitRes $ sourceFile fileName .| sinkLazy - let decodedData = Data.Csv.decodeWith (DecodeOptions (BS.c2w separator)) NoHeader contents :: FromField a => Either String (Boxed.Vector (Boxed.Vector a)) + let decodedData = Data.Csv.decodeWith (DecodeOptions (BS.c2w separator)) NoHeader contents :: (FromField a, Unboxed.Unbox a) => Either String (Boxed.Vector (Unboxed.Vector a)) if isLeft decodedData then do let msg = fromLeft "" decodedData ExceptT $ return $ Left msg else do - let components = fromRight (Boxed.empty) decodedData - let rows = (\r -> SimpleFinite (Finite.Covariant (Boxed.length r) [covI]) r) <$> components + let components = fromRight Boxed.empty decodedData + let rows = (\r -> SimpleFinite (Finite.Covariant (Unboxed.length r) [covI]) r) <$> components ExceptT $ return $ Right $ FiniteTensor (Finite.Contravariant (Boxed.length rows) [conI]) rows fromCSVFile _ _ _ = error "You must provide exactly two indices names!"
test/binary/Spec.hs view
@@ -16,7 +16,7 @@ fileName1 = "test/m1" m1 :: Tensor Double -m1 = Matrix.fromIndices "ij" 500 500 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) +m1 = Matrix.fromIndices "ij" 50 50 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) writeMatrixBinary :: Tensor Double -> String -> IO () writeMatrixBinary m fileName = do
test/csv/Spec.hs view
@@ -16,7 +16,7 @@ fileName1 = "test/m1" m1 :: Tensor Double -m1 = Matrix.fromIndices "ij" 500 500 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) +m1 = Matrix.fromIndices "ij" 50 50 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) writeMatrixCSV :: Tensor Double -> String -> IO () writeMatrixCSV m fileName = do
test/json/Spec.hs view
@@ -16,7 +16,7 @@ fileName1 = "test/m1" m1 :: Tensor Double -m1 = Matrix.fromIndices "ij" 500 500 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) +m1 = Matrix.fromIndices "ij" 50 50 $ \i j -> cos (fromIntegral i) + sin (fromIntegral j) writeMatrixJSON :: Tensor Double -> String -> IO () writeMatrixJSON m fileName = do