{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeApplications #-} module Main ( main ) where import Criterion.Main import Data.List.NonEmpty (NonEmpty(..)) import Data.Massiv.Array as A hiding (zipWith) import Data.Monoid ((<>)) import qualified Data.Vector as V import qualified Data.Vector.Unboxed as U import Geography.MapAlgebra import GHC.TypeLits import Graphics.ColorSpace import qualified Numeric.LinearAlgebra as LA import Prelude hiding (zipWith) --- main :: IO () main = do img <- fileY "data/gray512.tif" imgF <- fileY "data/gray512.tif" rgba <- fileRGB "data/512x512.tif" a512 <- fileRGB "data/512x512.tif" -- a1024 <- fileRGB "data/1024x1024.tif" -- a2048 <- fileRGB "data/2048x2048.tif" -- a4096 <- fileRGB "data/4096x4096.tif" -- let aHuge :: Raster S u 46500 46500 Word8 -- aHuge = fromFunction S Par (\(r :. c) -> fromIntegral $ r * c) defaultMain [ creation , io , colouring img , massivOps img , localOps rgba a512 img , hmatrix , conversions img , focalOps img imgF , compositeOps a512 -- a1024 a2048 a4096 , histograms img ] creation :: Benchmark creation = bgroup "Raster Creation" [ bench "constant 256x256" $ nf (_array . constantB) 5 , bench "constant 512x512" $ nf (_array . constantB') 5 , bench "fromFunction 256x256" $ nf (_array . functionB) (\(r :. c) -> r * c) , bench "fromFunction 512x512" $ nf (_array . functionB') (\(r :. c) -> r * c) , bench "fromVector Unboxed Int - 256x256" $ nf (_array . vectorB) uv , bench "fromVector Boxed Int - 256x256" $ nf (_array . vectorB') bv ] where uv = U.fromList ([1..65536] :: [Int]) bv = V.fromList ([1..65536] :: [Int]) io :: Benchmark io = bgroup "IO" [ bench "fromRGBA 512x512" $ nfIO (_array . _red <$> fileRGB @Word8 @512 @512 "data/512x512.tif") , bench "fromRGBA (Word8 -> Double) 512x512" $ nfIO (_array . _red <$> fileRGB @Double @512 @512 "data/512x512.tif") , bench "fromGray Multiband 512x512" $ nfIO (_array <$> fileY @Word8 @512 @512 "data/512x512.tif") , bench "fromGray Singleband 512x512" $ nfIO (_array <$> gray "data/gray512.tif") ] colouring :: Raster S p 512 512 Word8 -> Benchmark colouring img = bgroup "Colouring" [ bench "classify 512x512" $ nf (_array . strict S . classify invisible cr . lazy) img , bench "grayscale 512x512" $ nf (_array . strict S . grayscale . lazy) img ] where cr = greenRed [25, 50, 75, 100, 125, 150, 175, 200, 225, 255] massivOps :: Raster S p 512 512 Word8 -> Benchmark massivOps img = bgroup "Massiv Operations" [ bench "strict S . lazy" $ nf (_array . strict S . lazy) img , bench "strict U . lazy" $ nf (_array . strict U . lazy) img , bench "strict P . lazy" $ nf (_array . strict P . lazy) img ] localOps :: RGBARaster p 512 512 Word8 -> RGBARaster p 512 512 Double -> Raster S p 512 512 Word8 -> Benchmark localOps (RGBARaster r g b _) (RGBARaster rF gF bF _) img = bgroup "Local Operations" [ bench "fmap (+ 17) . lazy" $ nf (_array . strict S . fmap (+ 17) . lazy) img , bench "zipWith (+)" $ nf (_array . strict S . zipWith (+) r) g , bench "zipWith (/)" $ nf (_array . strict S . zipWith (/) rF) gF , bench "(+)" $ nf (_array . strict S . (+ lazy r)) (lazy g) , bench "(/)" $ nf (_array . strict S . (/ lazy rF)) (lazy gF) , bench "(.+)" $ nf (\g' -> computeAs S $ _array r .+ g') (_array g) , bench "(./)" $ nf (\g' -> computeAs S $ _array rF ./ g') (_array gF) , bench "lmax" $ nf (_array . strict S . lmax img) img , bench "lmin" $ nf (_array . strict S . lmin img) img , bench "lmean (Word8)" $ nf (_array . strict S . lmean @Word8 @Double) rs , bench "lmean (Double)" $ nf (_array . strict S . lmean @Double @Double) rsF , bench "lvariety" $ nf (_array . strict S . lvariety) rs , bench "lmajority" $ nf (_array . strict S . lmajority) rs , bench "lminority" $ nf (_array . strict S . lminority) rs , bench "lvariance (Word8)" $ nf (fmap (_array . strict S) . lvariance) rs , bench "lvariance (Double)" $ nf (fmap (_array . strict S) . lvariance) rsF ] where rs = lazy r :| [lazy g, lazy b] rsF = lazy rF :| [lazy gF, lazy bF] hmatrix :: Benchmark hmatrix = bgroup "HMatrix" [ bench "linearSolveLS" $ nf (LA.linearSolveLS zing) (LA.col [8,8,8,8,8,8,8,8,8]) , bench "manual - MxM" $ nf (leftPseudo <>) (LA.col [8,8,8,8,8,8,8,8,8]) , bench "manual - MxV" $ nf (leftPseudo LA.#>) (LA.vector [8,8,8,8,8,8,8,8,8]) ] conversions :: Raster S p 512 512 Word8 -> Benchmark conversions img = bgroup "Numeric Conversion" [ bench "Double -> Double via id" $ nf id tau , bench "Double -> Double via realToFrac" $ nf (realToFrac @Double @Double) tau , bench "Word -> Double via realToFrac" $ nf (realToFrac @Word8 @Double) 5 , bench "realToFrac on Raster" $ nf (_array . strict S . fmap (realToFrac @Word8 @Double) . lazy) img ] focalOps :: Raster S p 512 512 Word8 -> Raster S p 512 512 Double -> Benchmark focalOps img imgF = bgroup "Focal Operations" [ bgroup "fsum" [ bench "512" $ nf (_array . strict S . fsum) img -- , bench "46500" $ nf (_array . strict S . fsum) huge -- , bench "maybing" $ nf (_array . strict B . fmap Just . lazy) img -- , bench "nodata" $ nf (_array . strict S . nodatafsum) img ] , bgroup "fmean" [ bench "Word8" $ nf (_array . strict S . fmean @Word8 @Double) img , bench "Double" $ nf (_array . strict S . fmean @Double @Double) imgF ] , bench "fmax" $ nf (_array . strict S . fmax) img , bench "fmin" $ nf (_array . strict S . fmin) img , bench "fmajority" $ nf (_array . strict S . fmajority) img , bench "fminority" $ nf (_array . strict S . fminority) img , bench "fvariety" $ nf (_array . strict S . fvariety) img , bench "fpercentage" $ nf (_array . strict S . fpercentage) img , bench "fpercentile" $ nf (_array . strict S . fpercentile) img , bench "flinkage" $ nf (_array . strict S . flinkage) img , bench "flength" $ nf (_array . strict S . flength . flinkage) img , bench "fpartition" $ nf (_array . strict B . fpartition) img , bench "fshape" $ nf (_array . strict B . fshape) img , bench "ffrontage" $ nf (_array . strict S . ffrontage . fshape) img , bench "farea" $ nf (_array . strict S . farea . fshape) img , bgroup "fvolume" [ bench "Word8 -> Double" $ nf (_array . strict S . fvolume . strict S . fmap (realToFrac @Word8 @Double) . lazy) img , bench "Double" $ nf (_array . strict S . fvolume) imgF ] , bgroup "fgradient" [ bench "Word8" $ nf (_array . strict S . fgradient . strict S . fmap wtod . lazy) img , bench "Double" $ nf (_array . strict S . fgradient) imgF ] , bgroup "faspect" [ bench "Unsafe (Word8)" $ nf (_array . strict S . faspect' . strict S . fmap wtod . lazy) img , bench "Unsafe (Double)" $ nf (_array .strict S . faspect') imgF , bench "Safe (Word8)" $ nf (_array . strict B . faspect . strict S . fmap wtod . lazy) img , bench "Safe (Double)" $ nf (_array . strict B . faspect) imgF ] , bgroup "fdownstream" [ bench "Word8" $ nf (_array . strict S . fdownstream . strict S . fmap wtod . lazy) img , bench "Double" $ nf (_array. strict S . fdownstream) imgF ] , bgroup "fupstream" [ bench "Word8" $ nf (_array . strict S . fupstream . strict S . fdownstream . strict S . fmap wtod . lazy) img , bench "Double" $ nf (_array . strict S . fupstream . strict S . fdownstream) imgF ] ] wtod :: Word8 -> Double wtod = realToFrac compositeOps :: RGBARaster p 512 512 Double -- -> RGBARaster p 1024 1024 Double -- -> RGBARaster p 2048 2048 Double -- -> RGBARaster p 4096 4096 Double -> Benchmark compositeOps i@(RGBARaster r g _ _) = bgroup "Composite Operations" [ bench "NDVI" $ nf (_array . strict S . ndvi (lazy g)) (lazy r) , bench "EVI (512)" $ nf (_array . strict S . evi) i -- , bench "EVI (1024)" $ nf (_array . strict S . evi) a1024 -- , bench "EVI (2048)" $ nf (_array . strict S . evi) a2048 -- , bench "EVI (4096)" $ nf (_array . strict S . evi) a4096 , bench "EVI + Colour" $ nf (_array . strict S . classify invisible cr . evi) i , bench "EVI + Colour + PNG (D)" $ nf (png . classify invisible cr . evi) i , bench "EVI + Colour + PNG (S)" $ nf (png . strict S . classify invisible cr . evi) i ] where cr = greenRed $ fmap (10 ^) ([1..10] :: [Int]) fromRight :: Either a b -> b fromRight (Right b) = b fromRight _ = error "Was Left" constantB :: Int -> Raster S p 256 256 Int constantB = constant S Par constantB' :: Int -> Raster S p 512 512 Int constantB' = constant S Par functionB :: (Ix2 -> Int) -> Raster S p 256 256 Int functionB = fromFunction S Par functionB' :: (Ix2 -> Int) -> Raster S p 512 512 Int functionB' = fromFunction S Par vectorB :: U.Vector Int -> Raster U p 256 256 Int vectorB = fromRight . fromVector Par vectorB' :: V.Vector Int -> Raster B p 256 256 Int vectorB' = fromRight . fromVector Par -- doubles :: Raster U p 512 512 Double -- doubles = fromRight . fromVector Par $ U.fromList ([1..262144] :: [Double]) zing :: LA.Matrix Double zing = LA.matrix 3 [ -0.5, -0.5, 1 , -0.5, 0, 1 , -0.5, 0.5, 1 , 0, -0.5, 1 , 0, 0, 1 , 0, 0.5, 1 , 0.5, -0.5, 1 , 0.5, 0, 1 , 0.5, 0.5, 1 ] gray :: FilePath -> IO (Raster S p 512 512 Word8) gray fp = do i <- fromGray fp case i of Left err -> error err Right img -> pure img fileY :: (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (Raster S p r c a) fileY fp = do i <- fromGray fp case i of Left err -> error err Right img -> pure img {-# INLINE fileY #-} fileRGB :: (Elevator a, KnownNat r, KnownNat c) => FilePath -> IO (RGBARaster p r c a) fileRGB fp = do i <- fromRGBA fp case i of Left err -> error err Right img -> pure img {-# INLINE fileRGB #-} -- | See: https://en.wikipedia.org/wiki/Normalized_difference_vegetation_index ndvi :: (KnownNat r, KnownNat c) => Raster D p r c Double -> Raster D p r c Double -> Raster D p r c Double ndvi nir red = (nir - red) / (nir + red) {-# INLINE ndvi #-} -- | See: https://en.wikipedia.org/wiki/Enhanced_vegetation_index evi :: (Fractional a, Storable a, KnownNat r, KnownNat c) => RGBARaster p r c a -> Raster D p r c a evi (RGBARaster r g b _) = 2.5 * (numer / denom) where nir = lazy g -- fudging it. numer = nir - lazy r denom = nir + (6 * lazy r) - (7.5 * lazy b) + 1 {-# INLINE evi #-} -- nodatafsum :: Raster S p 1753 1760 Double -> Raster DW p 1753 1760 Double -- nodatafsum = fmap (maybe 0 ((/9) . getSum)) . fmonoid . strict B . fmap check . lazy -- where check 0 = Nothing -- check n = Just $ Sum n -- {-# INLINE nodatafsum #-} histograms :: Raster S p 512 512 Word8 -> Benchmark histograms r = bgroup "Histogram Algorithms" [ bench "Storable Super Mutable" $ nf (_histogram . histogram) r ]