repa-io 1.1.0.0 → 2.0.0.1
raw patch · 5 files changed
+159/−33 lines, 5 filesdep +old-timedep −dph-prim-pardep ~repadep ~repa-bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: old-time
Dependencies removed: dph-prim-par
Dependency ranges changed: repa, repa-bytestring
API changes (from Hackage documentation)
+ Data.Array.Repa.IO.BMP: readComponentsListFromBMP :: FilePath -> IO (Either Error [Array DIM2 Word8])
+ Data.Array.Repa.IO.BMP: writeComponentsListToBMP :: FilePath -> [Array DIM2 Word8] -> IO ()
+ Data.Array.Repa.IO.Timing: cpuTime :: TimeUnit -> Time -> Integer
+ Data.Array.Repa.IO.Timing: data Time
+ Data.Array.Repa.IO.Timing: milliseconds :: TimeUnit
+ Data.Array.Repa.IO.Timing: minus :: Time -> Time -> Time
+ Data.Array.Repa.IO.Timing: plus :: Time -> Time -> Time
+ Data.Array.Repa.IO.Timing: prettyTime :: Time -> String
+ Data.Array.Repa.IO.Timing: showTime :: Time -> String
+ Data.Array.Repa.IO.Timing: time :: IO a -> IO (a, Time)
+ Data.Array.Repa.IO.Timing: wallTime :: TimeUnit -> Time -> Integer
- Data.Array.Repa.IO.BMP: writeMatrixToGreyscaleBMP :: FilePath -> Array DIM2 Double -> IO ()
+ Data.Array.Repa.IO.BMP: writeMatrixToGreyscaleBMP :: (Num a, Elt a, Fractional a, RealFrac a) => FilePath -> Array DIM2 a -> IO ()
Files
- Data/Array/Repa/IO/BMP.hs +62/−18
- Data/Array/Repa/IO/Matrix.hs +3/−4
- Data/Array/Repa/IO/Timing.hs +86/−0
- Data/Array/Repa/IO/Vector.hs +2/−3
- repa-io.cabal +6/−8
Data/Array/Repa/IO/BMP.hs view
@@ -1,21 +1,29 @@-{-# LANGUAGE PackageImports #-} +{-# LANGUAGE PackageImports, PatternGuards, ExplicitForAll #-} -- | Reading and writing arrays as uncompressed 24 and 32 bit Windows BMP files. module Data.Array.Repa.IO.BMP ( readImageFromBMP , readComponentsFromBMP+ , readComponentsListFromBMP , readMatrixFromGreyscaleBMP++ -- Writing. , writeImageToBMP , writeComponentsToBMP+ , writeComponentsListToBMP , writeMatrixToGreyscaleBMP) where-import qualified Data.Array.Parallel.Unlifted as U import Data.Array.Repa as A import Data.Array.Repa.ByteString as A import Prelude as P import Codec.BMP import Data.Word +-- NOTE: We set most of these functions as NOINLINE so it's easier to understand+-- what's going on in the core programs. The top-level IO functions are+-- only called a few times each, so it doesn't matter if they're not+-- worker/wrappered etc.+ -- Read ------------------------------------------------------------------------------------------- -- | Read a matrix from a `BMP` file. -- Each pixel is converted to greyscale, normalised to [0..1] and used@@ -24,19 +32,35 @@ :: FilePath -> IO (Either Error (Array DIM2 Double)) +{-# NOINLINE readMatrixFromGreyscaleBMP #-} readMatrixFromGreyscaleBMP filePath = do eComps <- readComponentsFromBMP filePath case eComps of Left err -> return $ Left err Right (arrRed, arrGreen, arrBlue)- -> let arr = force + -> let arr = force2 $ A.fromFunction (extent arrRed)- (\ix -> sqrt ( (fromIntegral (arrRed !: ix) / 255) ^ (2 :: Int)- + (fromIntegral (arrGreen !: ix) / 255) ^ (2 :: Int)- + (fromIntegral (arrBlue !: ix) / 255) ^ (2 :: Int)))+ (\ix -> sqrt ( (fromIntegral (arrRed ! ix) / 255) ^ (2 :: Int)+ + (fromIntegral (arrGreen ! ix) / 255) ^ (2 :: Int)+ + (fromIntegral (arrBlue ! ix) / 255) ^ (2 :: Int))) in arr `deepSeqArray` return (Right arr)- ++-- | Like `readComponentsFromBMP`, but return the components as a list.+readComponentsListFromBMP+ :: FilePath+ -> IO (Either Error [Array DIM2 Word8])++readComponentsListFromBMP filePath+ = do eComps <- readComponentsFromBMP filePath+ case eComps of+ Left err+ -> return $ Left err++ Right (arrRed, arrGreen, arrBlue) + -> return $ Right [arrRed, arrGreen, arrBlue]++ -- | Read RGB components from a BMP file. -- Returns arrays of red, green and blue components, all with the same extent. -- If anything goes wrong when loading the file then then `Error`.@@ -44,7 +68,7 @@ :: FilePath -> IO (Either Error (Array DIM2 Word8, Array DIM2 Word8, Array DIM2 Word8)) -{-# INLINE readComponentsFromBMP #-}+{-# NOINLINE readComponentsFromBMP #-} readComponentsFromBMP filePath = do ebmp <- readBMP filePath case ebmp of@@ -60,18 +84,18 @@ shapeFn _ = Z :. height :. width arrRed - = traverse arr shapeFn+ = force2 $ traverse arr shapeFn (\get (sh :. x) -> get (sh :. (x * 4))) arrGreen- = traverse arr shapeFn+ = force2 $ traverse arr shapeFn (\get (sh :. x) -> get (sh :. (x * 4 + 1))) arrBlue- = traverse arr shapeFn+ = force2 $ traverse arr shapeFn (\get (sh :. x) -> get (sh :. (x * 4 + 2))) - in (arrRed, arrGreen, arrBlue)+ in [arrRed, arrGreen, arrBlue] `deepSeqArrays` (arrRed, arrGreen, arrBlue) -- | Read a RGBA image from a BMP file.@@ -83,6 +107,7 @@ :: FilePath -> IO (Either Error (Array DIM3 Word8)) +{-# NOINLINE readImageFromBMP #-} readImageFromBMP filePath = do ebmp <- readBMP filePath case ebmp of@@ -102,20 +127,37 @@ -- Negative values are discarded. Positive values are normalised to the maximum -- value in the matrix and used as greyscale pixels. writeMatrixToGreyscaleBMP - :: FilePath- -> Array DIM2 Double+ :: forall a. (Num a, Elt a, Fractional a, RealFrac a)+ => FilePath+ -> Array DIM2 a -> IO () +{-# NOINLINE writeMatrixToGreyscaleBMP #-}+{-# SPECIALISE writeMatrixToGreyscaleBMP :: FilePath -> Array DIM2 Float -> IO () #-}+{-# SPECIALISE writeMatrixToGreyscaleBMP :: FilePath -> Array DIM2 Double -> IO () #-} writeMatrixToGreyscaleBMP fileName arr = let arrNorm = normalisePositive01 arr-- scale :: Double -> Word8 scale x = fromIntegral (truncate (x * 255) :: Int)- arrWord8 = A.map scale arrNorm in writeComponentsToBMP fileName arrWord8 arrWord8 arrWord8 + +-- | Like `writeComponentsToBMP` but take the components as a list.+-- The list must have 3 arrays, for the red, green blue components+-- respectively, else `error`.+writeComponentsListToBMP+ :: FilePath + -> [Array DIM2 Word8]+ -> IO () +writeComponentsListToBMP filePath comps+ | [red, green, blue] <- comps+ = writeComponentsToBMP filePath red green blue+ + | otherwise+ = error "Data.Array.Repa.IO.BMP.writeComponentsListToBMP: wrong number of components"+ + -- | Write RGB components to a BMP file. -- All arrays must have the same extent, else `error`. writeComponentsToBMP@@ -125,6 +167,7 @@ -> Array DIM2 Word8 -> IO () +{-# NOINLINE writeComponentsToBMP #-} writeComponentsToBMP fileName arrRed arrGreen arrBlue | not $ ( extent arrRed == extent arrGreen && extent arrGreen == extent arrBlue)@@ -152,6 +195,7 @@ -> Array DIM3 Word8 -> IO () +{-# NOINLINE writeImageToBMP #-} writeImageToBMP fileName arrImage | comps /= 4 = error "Data.Array.Repa.IO.BMP: lowest order dimension must be 4"@@ -169,7 +213,7 @@ -- | Normalise a matrix to to [0 .. 1], discarding negative values. -- If the maximum value is 0 then return the array unchanged. normalisePositive01- :: (Shape sh, U.Elt a, Fractional a, Ord a)+ :: (Shape sh, Elt a, Fractional a, Ord a) => Array sh a -> Array sh a
Data/Array/Repa/IO/Matrix.hs view
@@ -19,7 +19,6 @@ import Data.List as L import Data.Array.Repa as A import Prelude as P-import qualified "dph-prim-par" Data.Array.Parallel.Unlifted as U -- | Read a matrix from a text file.@@ -27,7 +26,7 @@ -- WARNING: This doesn't do graceful error handling. If the file has the wrong format -- you'll get a confusing `error`. readMatrixFromTextFile- :: (U.Elt a, Num a, Read a)+ :: (Elt a, Num a, Read a) => FilePath -> IO (Array DIM2 a) @@ -47,7 +46,7 @@ -- | Write a matrix as a text file. writeMatrixToTextFile - :: (U.Elt a, Show a)+ :: (Elt a, Show a) => FilePath -> Array DIM2 a -> IO ()@@ -60,7 +59,7 @@ let Z :. width :. height = extent arr - hPutStrLn file $ show width ++ " " ++ show height+ hPutStrLn file $ show width P.++ " " P.++ show height hWriteValues file $ toList arr hClose file
+ Data/Array/Repa/IO/Timing.hs view
@@ -0,0 +1,86 @@+module Data.Array.Repa.IO.Timing+ ( Time+ , milliseconds, cpuTime, wallTime+ , time, minus, plus+ , showTime+ , prettyTime)+where+import GHC.Exts (traceEvent)+import System.CPUTime+import System.Time+++-- Time -----------------------------------------------------------------------+-- | Abstract representation of process time.+data Time + = Time + { cpu_time :: Integer+ , wall_time :: Integer+ }++zipT :: (Integer -> Integer -> Integer) -> Time -> Time -> Time+zipT f (Time cpu1 wall1) (Time cpu2 wall2) + = Time (f cpu1 cpu2) (f wall1 wall2)++-- | Subtract second time from the first.+minus :: Time -> Time -> Time+minus = zipT (-)+++-- | Add two times.+plus :: Time -> Time -> Time+plus = zipT (+)+++-- TimeUnit -------------------------------------------------------------------+-- | Conversion +type TimeUnit + = Integer -> Integer++milliseconds :: TimeUnit+milliseconds n = n `div` 1000000000++cpuTime :: TimeUnit -> Time -> Integer+cpuTime f = f . cpu_time++wallTime :: TimeUnit -> Time -> Integer+wallTime f = f . wall_time+++-- | Get the current time.+getTime :: IO Time+getTime =+ do+ cpu <- getCPUTime+ TOD sec pico <- getClockTime+ return $ Time cpu (pico + sec * 1000000000000)+++-- | Show a time as a string, in milliseconds.+showTime :: Time -> String+showTime t = (show $ wallTime milliseconds t)+ ++ "/"+ ++ (show $ cpuTime milliseconds t)++-- | Pretty print the times, in milliseconds.+prettyTime :: Time -> String+prettyTime t+ = unlines+ [ "elapsedTimeMS = " ++ (show $ wallTime milliseconds t)+ , "cpuTimeMS = " ++ (show $ cpuTime milliseconds t) ]++-- Timing benchmarks ----------------------------------------------------------++-- | Time some IO action.+-- Make sure to deepseq the result before returning it from the action. If you+-- don't do this then there's a good chance that you'll just pass a suspension+-- out of the action, and the computation time will be zero.+time :: IO a -> IO (a, Time)+{-# NOINLINE time #-}+time p = do+ start <- getTime+ traceEvent "Bench.Benchmark: start timing"+ x <- p+ traceEvent "Bench.Benchmark: finished timing"+ end <- getTime+ return (x, end `minus` start)
Data/Array/Repa/IO/Vector.hs view
@@ -20,14 +20,13 @@ import System.IO import Control.Monad import Data.Char-import qualified "dph-prim-par" Data.Array.Parallel.Unlifted as U -- | Read a vector from a text file. -- WARNING: This doesn't do graceful error handling. If the file has the wrong format -- you'll get a confusing `error`. readVectorFromTextFile- :: (U.Elt a, Num a, Read a)+ :: (Elt a, Num a, Read a) => FilePath -> IO (Array DIM1 a) @@ -55,7 +54,7 @@ -- | Write a vector as a text file. writeVectorToTextFile - :: (U.Elt a, Show a)+ :: (Elt a, Show a) => Array DIM1 a -> FilePath -> IO ()
repa-io.cabal view
@@ -1,5 +1,5 @@ Name: repa-io-Version: 1.1.0.0+Version: 2.0.0.1 License: BSD3 License-file: LICENSE Author: The DPH Team@@ -11,21 +11,18 @@ Homepage: http://trac.haskell.org/repa Bug-reports: http://trac.haskell.org/repa/newticket Description:- NOTE: You must use the GHC head branch > 6.13.20100309 to get decent performance. Read and write Repa arrays in various formats. Synopsis: Read and write Repa arrays in various formats. -Tested-with: GHC == 6.13.20100309, GHC == 6.12.1- Library Build-Depends: base == 4.*,- dph-prim-par == 0.4.*,- repa == 1.1.*,- repa-bytestring == 1.1.*,- bmp == 1.1.*+ repa == 2.0.*,+ repa-bytestring == 2.0.*,+ bmp == 1.1.*,+ old-time == 1.0.* ghc-options: -Odph -Wall -fno-warn-missing-signatures@@ -35,6 +32,7 @@ Data.Array.Repa.IO.BMP Data.Array.Repa.IO.Vector Data.Array.Repa.IO.Matrix+ Data.Array.Repa.IO.Timing Other-modules: Data.Array.Repa.IO.Internals.Text