packages feed

easytensor-0.3.1.0: bench/misc.hs

{-# LANGUAGE DataKinds        #-}
{-# LANGUAGE GADTs            #-}
{-# LANGUAGE KindSignatures   #-}
{-# 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
-- import qualified Numeric.Dimensions.Traverse.ST as ST



main :: IO ()
main = do
    putStrLn "Hello world!"
    print (Dn @3 :* Dn @2 :* (D :: Dim ('[] :: [Nat])))

    print (fromList [vec2 1 0, vec2 2 3, vec2 3 4, vec2 5 6] :: DataFrame Int '[N 2, XN 2])
    print (fromList [vec4 1 0 2 11, vec4 2 22 3 0, vec4 3 4 0 0] :: DataFrame Double '[N 4, XN 2])
    print (fromList [vec2 0 0, vec2 2 22, vec2 2 22] :: DataFrame Float '[N 2, XN 2])
    print (fromList [0, 1, 3, 5, 7] :: DataFrame Float '[XN 2])
    print (fromList [9, 13, 2] :: DataFrame Float '[N 5, N 2, XN 2])
    print $ vec2 1 1 %* mat22 (vec2 1 1) (vec2 2 (3 :: Float))
    print (toList (42 :: DataFrame Int '[4,3,2]))
    -- 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 '[N 4, N 2, XN 2] of
                    -- Amazing inference!
                    -- m :: KnownNat k => DataFrame '[4,2,k]
        SomeDataFrame m -> print $ vec4 1 2.25 3 0.162 %* m
    putStrLn "Constructing larger matrices"
    let x :: DataFrame Double '[2,5,4]
        x =   transpose ( (56707.4   <::> 73558.41  <+:> 47950.074  <+:> 83394.61  <+:> 25611.629 )
                     <::> (53704.516 <::> -3277.478 <+:> 99479.92   <+:> 18915.17  <+:> 59666.938 ) )
         <::> transpose ( (-3035.543 <::> 15831.447 <+:> 73256.625  <+:> 80709.38  <+:> 72695.04  )
                     <::> (50932.49  <::> 7865.496  <+:> -4050.5957 <+:> 99839.41  <+:> 10834.297 ) )
         <+:> transpose ( (21961.227 <::> 29640.914 <+:> 39657.19   <+:> 81469.64  <+:> 17815.506 )
                     <::> (-8484.239 <::> 16877.531 <+:> 65145.742  <+:> 80219.67  <+:> 81508.87  ) )
         <+:> transpose ( (53105.71  <::> 16255.646 <+:> 23324.957  <+:> -4438.164 <+:> 35369.824 )
                     <::> (67930.45  <::> 8950.834  <+:> 64451.71   <+:> 76685.57  <+:> 6728.465  ) )
        y :: DataFrame Double '[3,7]
        y = transpose $
               (70096.85  <::> 34332.492 <+:> 3642.8867 <+:> 25242.25  <+:> 59776.234 <+:> 12092.57 <+:> 10708.498)
          <::> (46447.965 <::> 37145.668 <+:> 56899.656 <+:> 85367.56  <+:> 15872.262 <+:> 87466.24 <+:> 82506.76 )
          <+:> (50458.848 <::> 31650.453 <+:> 71432.78  <+:> 53073.203 <+:> 59267.883 <+:> 82369.89 <+:> 78171.56 )
        z = ewgen x :: DataFrame Double '[2,5,4,3,7]
    print $ ewfoldl @_ @'[2] (+) 10 z
    print $ ewfoldr @_ @'[2,5] (+) 0 z + 10
    print $ ewfoldl (+) 10 z - ewfoldr @_ @'[2,5,4] (+) 0 z - 10

    -- We can map arbitrary prefix dimension over the dataframe,
    -- indexing by suffix dimensions.
    -- At the same time, we can transform underlying element type
    --  or prefix dimensionality.
    -- For example, we can do tensor produt of every sub-tensor.
    putStrLn "\nConversions between element types and frame sizes."
    print $ iwmap @Int @'[2,2] @'[7] @_
                  (\(i:!Z) v -> fromScalar . (scalar 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:!Z) (scalar 777) rVec
    print $ update (2:!3:!Z) (vec2 999 999) x

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

    -- Working with mutable frames
    print $ ST.runST $ do
      sdf <- ST.thawDataFrame matY
      ST.writeDataFrame sdf (1:!1:!Z) 900101
      ST.writeDataFrame sdf (3:!3:!Z) 900303
      ST.writeDataFrame sdf (5:!3:!Z) 900503
      ST.unsafeFreezeDataFrame sdf