module Multilinear.Generic.MultiCore.Serialize (
toBinary, toBinaryFile,
fromBinary, fromBinaryFile,
Multilinear.Generic.MultiCore.Serialize.toJSON,
Multilinear.Generic.MultiCore.Serialize.toJSONFile,
Multilinear.Generic.MultiCore.Serialize.fromJSON,
Multilinear.Generic.MultiCore.Serialize.fromJSONFile,
fromCSVFile, toCSVFile
) where
import Codec.Compression.GZip
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.MultiCore
import qualified Multilinear.Index.Finite as Finite
import Multilinear.Index.Finite.Serialize ()
instance (Serialize a, Unboxed.Unbox a) => Serialize (Tensor a)
instance (ToJSON a, Unboxed.Unbox a) => ToJSON (Tensor a)
instance (FromJSON a, Unboxed.Unbox a) => FromJSON (Tensor a)
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, Unboxed.Unbox a) => FromRecord (Tensor a) where
parseRecord v =
if Boxed.length v == 1 then
Scalar <$> v .! 0
else
error "non-scalar"
toBinary :: (
Serialize a, Unboxed.Unbox a
) => Tensor a
-> ByteString.ByteString
toBinary = compress . Data.Serialize.encodeLazy
toBinaryFile :: (
Serialize a, Unboxed.Unbox a
) => Tensor a
-> String
-> IO ()
toBinaryFile t fileName = do
let bs = toBinary t
runConduitRes $
sourceLazy bs .| sinkFile fileName
fromBinary :: (
Serialize a, Unboxed.Unbox a
) => ByteString.ByteString
-> Either String (Tensor a)
fromBinary = Data.Serialize.decodeLazy . decompress
fromBinaryFile :: (
Serialize a, Unboxed.Unbox a
) => String
-> ExceptT String IO (Tensor a)
fromBinaryFile fileName = do
contents <- lift $ runConduitRes $
sourceFile fileName .| sinkLazy
ExceptT $ return $ fromBinary contents
toJSON :: (
ToJSON a, Unboxed.Unbox a
) => Tensor a
-> ByteString.ByteString
toJSON = Data.Aeson.encode
toJSONFile :: (
ToJSON a, Unboxed.Unbox a
) => Tensor a
-> String
-> IO ()
toJSONFile t fileName = do
let bs = Multilinear.Generic.MultiCore.Serialize.toJSON t
runConduitRes $
sourceLazy bs .| sinkFile fileName
fromJSON :: (
FromJSON a, Unboxed.Unbox a
) => ByteString.ByteString
-> Maybe (Tensor a)
fromJSON = Data.Aeson.decode
fromJSONFile :: (
FromJSON a, Unboxed.Unbox a
) => String
-> MaybeT IO (Tensor a)
fromJSONFile fileName = do
contents <- lift $ runConduitRes $
sourceFile fileName .| sinkLazy
MaybeT $ return $ Multilinear.Generic.MultiCore.Serialize.fromJSON contents
toCSVFile :: (
ToField a, Unboxed.Unbox a
) => Tensor a
-> String
-> IO ()
toCSVFile s@(Scalar _) fileName = do
let bs = Data.Csv.encode [s]
runConduitRes $
sourceLazy bs .| sinkFile fileName
toCSVFile (SimpleFinite _ vs) fileName = do
let rows = [vs]
let bs = Data.Csv.encode rows
runConduitRes $
sourceLazy bs .| sinkFile fileName
toCSVFile (FiniteTensor _ vrows) fileName = do
let rows = Boxed.toList vrows
let bs = Data.Csv.encode rows
runConduitRes $
sourceLazy bs .| sinkFile fileName
fromCSVFile :: (
FromField a, Unboxed.Unbox a
) => String
-> Char
-> String
-> ExceptT String IO (Tensor a)
fromCSVFile fileName separator [conI,covI] = do
contents <- lift $ runConduitRes $
sourceFile fileName .| sinkLazy
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 (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!"