packages feed

easytensor-2.0.0.0: bench/misc.hs

{-# LANGUAGE DataKinds        #-}
{-# LANGUAGE GADTs            #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators    #-}

module Main (main) where

import Numeric.DataFrame
import Numeric.Dimensions

import qualified Control.Monad.ST     as ST
import qualified Numeric.DataFrame.ST as ST



main :: IO ()
main = do
    putStrLn "Hello world!"
    print (D3 :* D2 :* U)

    print (fromList [vec2 1 0, vec2 2 3, vec2 3 4, vec2 5 6]
             :: DataFrame Int '[XN 0, N 2])
    print (fromList [vec4 1 0 2 11, vec4 2 22 3 0, vec4 3 4 0 0]
             :: DataFrame Double '[XN 0, N 4])
    print (fromList [vec2 0 0, vec2 2 22, vec2 2 22]
             :: DataFrame Float '[XN 0, N 2])
    print $ fromList [0 :: Scf, 1, 3, 5, 7]
    print ( fromList [9, 13, 2]
             :: DataFrame Float '[XN 0, N 5, N 2])
    print $ vec2 1 1 %* mat22 1 (vec2 2 (3 :: Float))

    -- Seems like I have to specify known dimension explicitly,
    -- because the inference process within the pattern match
    -- cannot escape the case expression.
    -- On the other hand, if I type wrong dimension it will throw a nice type-level error.
    () <- case (fromList [10, 100, 1000] :: DataFrame Double '[XN 0, N 2, N 4]) of
        XFrame m
          | KnownDims <- dims `inSpaceOf` m
              -- Amazing inference!
              -- m :: KnownNat k => DataFrame '[k,2,4]
            -> print $ m %* vec4 1 2.25 3 0.162
        _ -> print "Failed to construct a DataFrame!"
    putStrLn "Constructing larger matrices"
    let x :: DataFrame Double '[4,5,2]
        x =  DF4 (transpose $ DF2
                    (DF5  56707.4     73558.41    47950.074  83394.61    25611.629)
                    (DF5  53704.516  (-3277.478)  99479.92   18915.17    59666.938))
                 (transpose $ DF2
                    (DF5 (-3035.543)  15831.447   73256.625   80709.38   72695.04)
                    (DF5  50932.49    7865.496   (-4050.5957) 99839.41   10834.297))
                 (transpose $ DF2
                    (DF5  21961.227   29640.914   39657.19    81469.64   17815.506 )
                    (DF5 (-8484.239)  16877.531  65145.742    80219.67   81508.87  ))
                 (transpose $ DF2
                    (DF5  53105.71    16255.646   23324.957  (-4438.164) 35369.824 )
                    (DF5  67930.45    8950.834    64451.71    76685.57   6728.465  ))
        y :: DataFrame Double '[7,3]
        y = transpose $ DF3
          (DF7 70096.85  34332.492 3642.8867 25242.25  59776.234 12092.57 10708.498)
          (DF7 46447.965 37145.668 56899.656 85367.56  15872.262 87466.24 82506.76 )
          (DF7 50458.848 31650.453 71432.78  53073.203 59267.883 82369.89 78171.56 )
        z = ewgen x :: DataFrame Double '[7,3,4,5,2]
    print $ ewfoldl @_ @_ @'[2] (+) 10 z
    print $ ewfoldr @_ @_ @'[5,2] (+) 0 z + 10
    print $ ewfoldl (+) 10 z - ewfoldr @_ @_ @'[4,5,2] (+) 0 z - 10

    -- We can map arbitrary suffix dimension over the dataframe,
    -- indexing by prefix dimensions.
    -- At the same time, we can transform underlying element type
    --  or suffix dimensionality.
    -- For example, we can do tensor produt of every sub-tensor.
    putStrLn "\nConversions between element types and frame sizes."
    print $ iwmap @Int @'[7] @'[2,2] @_
                  (\(i:*U) v -> fromScalar . (scalar (fromIntegral i) +) . round
                                     $ vec3 0.02 (-0.01) 0.001 %* v
                  ) y

    -- Using elementWise function we can apply arbitrary applicative functors
    -- over subtensors.
    -- This means we can even do arbitrary IO for each subtensor
    -- indexed by suffix dimensions.
    putStrLn "\nWelement-wise IO!"
    rVec <- elementWise @Double @'[4] @_  @_
              (\v -> print v >> return (sqrt . trace $ v %* transpose v)) x
    putStrLn "\nTraces for each matrix element:"
    print rVec

    -- Updating existing frames
    print $ update (2:*U) (scalar 777) rVec
    print $ update (1:*3:*U) (vec2 999 555) x

    let matX = iwgen (scalar . fromEnum) :: DataFrame Int '[2,6,4]
        matY = iwgen (scalar . fromEnum) :: DataFrame Int '[5,4]
    putStrLn "Check carefully that this returns no garbage"
    print matX
    print (ewmap @_ @'[2,6] (`snocDF` scalar 111) matX :: DataFrame Int '[2,6,5])
    print matY
    print (ewmap fromScalar matY :: DataFrame Int '[5,4,3])

    -- Working with mutable frames
    print $ ST.runST $ do
      sdf <- ST.thawDataFrame matY
      ST.writeDataFrame sdf (0:*0:*U) 900101
      ST.writeDataFrame sdf (2:*2:*U) 900303
      ST.writeDataFrame sdf (4:*2:*U) 900503
      ST.unsafeFreezeDataFrame sdf