{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}

-- | Experimental api following https://pechersky.github.io/haskell-numpy-docs/quickstart.basics.html
module NumHask.Array.Example
  (
    -- * The Basics
    -- $setup

    -- ** An Example
    -- $anExample

    -- ** Array Creation
    -- $arrayCreation

    -- ** Printing Arrays
    -- $printingArrays

    -- ** Universal Functions
    -- $universalFunctions

    -- ** Indexing, Slicing and Iterating
    -- $indexingSlicingIterating

    -- * Shape Manipulation
    -- $shapeManipulation

    -- * Fancy indexing and index tricks
    -- $fancyIndexing

    -- * Linear Algebra
    -- $linearAlgebra

    -- * Tricks and Tips
    -- $tricksTips
  )
where

import NumHask.Shape
import NumHask.Prelude as P

-- $setup
-- >>> :set -XDataKinds
-- >>> :set -XOverloadedLists
-- >>> :set -XNoImplicitPrelude
-- >>> :set -XFlexibleContexts
-- >>> import NumHask.Array as A
-- >>> import GHC.Exts (fromList)

-- $anExample
-- construction can be lazy; and zero pads
--
-- >>> let z = [] :: Array [] '[2] Int
-- >>> z
-- [0, 0]
-- >>> let a = [0..] :: Array [] '[3,5] Int
-- >>> a
-- [[0, 1, 2, 3, 4],
--  [5, 6, 7, 8, 9],
--  [10, 11, 12, 13, 14]]
-- >>> shape a
-- [3,5]
-- >>> length (shape a) -- dimension
-- 2
-- >>> :t a
-- a :: Array [] '[3, 5] Int
-- >>> import qualified Data.Vector as V
-- >>> let v = V.fromList [6,7,8]
-- >>> :t v
-- v :: Num a => V.Vector a
-- >>> let b = Array v
-- >>> :t b
-- b :: Num t => Array V.Vector ds t
-- >>> b :: Array V.Vector '[3] Int
-- [6, 7, 8]

-- $arrayCreation
--
-- >>> -- fixed size arrays are fully shape specified at the type level
-- >>> let a = [2, 3, 4] :: Array [] '[3] Int
-- >>> a
-- [2, 3, 4]
-- >>> [1.2, 3.5, 5.1] :: Array [] '[3] Double
-- [1.2, 3.5, 5.1]
--
-- >>> -- lists of lists is not a thing, and need to be flattened
-- >>> let ls = [[1.0,2.0,3.0],[4.0,5.0,6.0]] :: [[Double]]
-- >>> fromList (concat ls) :: Array [] '[2,3] Double
-- [[1.0, 2.0, 3.0],
--  [4.0, 5.0, 6.0]]
--
-- >>> fromList ((\x -> (fromIntegral x) :+ zero) <$> [1,2,3,4]) :: Array [] '[2,2] (Complex Double)
-- [[1.0 :+ 0.0, 2.0 :+ 0.0],
--  [3.0 :+ 0.0, 4.0 :+ 0.0]]
-- >>> let z = [] :: Array [] '[3,4] Int
-- >>> z
-- [[0, 0, 0, 0],
--  [0, 0, 0, 0],
--  [0, 0, 0, 0]]
-- >>> let o = A.singleton one :: Array [] '[2,3,4] Int
-- >>> o
-- [[[1, 1, 1, 1],
--   [1, 1, 1, 1],
--   [1, 1, 1, 1]],
--  [[1, 1, 1, 1],
--   [1, 1, 1, 1],
--   [1, 1, 1, 1]]]
-- >>> let empt = A.singleton nan :: Array [] '[2,3] Double
-- >>> empt
-- [[NaN, NaN, NaN],
--  [NaN, NaN, NaN]]
--
-- >>>  [10,15 .. 30] :: Array [] '[4] Int
-- [10, 15, 20, 25]
-- >>> [0, 0.3.. 2] :: Array [] '[7] Double
-- [0.0, 0.3, 0.6, 0.8999999999999999, 1.2, 1.5, 1.7999999999999998]
--
-- > todo: fix NumHask.Range grid
-- > fromList (grid OuterPos (Range 0 2) 8) :: Array [] '[9] Double
-- > [0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0]
-- > let x = fromList (grid OuterPos (Range 0 (2*pi)) 100) :: Array [] '[101] Double
-- > let f = fmap sin x
--

-- $printingArrays
-- >>> show ([0..] :: Array [] '[6] Int) :: Text
-- "[0, 1, 2, 3, 4, 5]"
-- >>> [0..] :: Array [] '[2,3] Int
-- [[0, 1, 2],
--  [3, 4, 5]]
-- >>> [0..] :: Array [] '[1,2,3,1] Int
-- [[[[0],
--    [1],
--    [2]],
--   [[3],
--    [4],
--    [5]]]]
--
-- > todo: implement display
-- > import Formatting
-- > display (left 7 . fixed 2) ", " (fromList $ fromIntegral <$> [0..] :: Array [] '[100,100] Double)
-- > [[   0.00,    1.00,    2.00 ..   98.00   99.00],
-- >  [ 100.00,  101.00,  102.00 ..  198.00  199.00],
-- >  [ 200.00,  201.00,  202.00 ..  298.00  299.00],
-- >  ..
-- >  [9800.00, 9801.00, 9802.00 .. 9898.00 9899.00],
-- >  [9900.00, 9901.00, 9902.00 .. 9998.00 9999.00]]
--

-- $basicOperation
--
-- >>> let a = [20,30,40,50] :: Array [] '[4] Double
-- >>> let b = [0..] :: Array [] '[4] Double
-- >>> let c = a - b
-- >>> c
-- [20.0, 29.0, 38.0, 47.0]
-- >>> -- todo: resolve potential to polymorph number literals eg b**2
-- >>> b ** (one+one)
-- [0.0, 1.0, 4.0, 9.000000000000002]
-- >>> 10 *. (sin <$> a)
-- [9.129452507276277, -9.880316240928618, 7.451131604793488, -2.6237485370392877]
-- >>> (<35) <$> a
-- [True, True, False, False]
--
-- >>> let a = [0..] :: Array [] '[2,3] Int
-- >>> let b = [0..] :: Array [] '[3,2] Int
-- >>> a .*. a
-- [[0, 1, 4],
--  [9, 16, 25]]
-- >>> -- todo: resolve NumHask.Array and NumHask.Matrix operation names
-- >>> a `NumHask.Array.mmult` b
-- [[10, 13],
--  [28, 40]]
-- >>> a .* 2
-- [[0, 2, 4],
--  [6, 8, 10]]
--
-- >>> -- random example skipped
--
-- > -- todo: awaiting grid fix
-- > let a = singleton one :: Array [] '[3] Double
-- > let b = fromList (grid OuterPos (Range 0 pi) 2) :: Array [] '[3] Double
-- > let c = a + b
-- > let d = exp . ((zero:+one) *.) $ (:+zero) <$> c
-- > d
-- [0.5403023058681398 :+ 0.8414709848078965, (-0.8414709848078965) :+ 0.5403023058681398, (-0.5403023058681399) :+ (-0.8414709848078964)]
-- > :t d
-- d :: Array [] '[3] (Complex Double)
--
-- >>> -- folding
-- >>> let a = [0..] :: Array [] '[2,5] Int
-- >>> sum a
-- 45
-- >>> minimum a
-- 0
-- >>> maximum a
-- 9
-- >>> -- todo: scanAlong
--

-- $universalFunctions
--
-- >>> let a = [0..] :: Array [] '[3] Double
-- >>> exp <$> a
-- [1.0, 2.718281828459045, 7.38905609893065]
-- >>> sqrt <$> a
-- [0.0, 1.0, 1.4142135623730951]
--

-- $indexingSlicingIterating
--
-- >>> let a = (\x -> x*x*x) <$> [0..] :: Array [] '[10] Int
-- >>> index a [2]
-- 8
-- >>> let s = (\i -> index a [i]) <$> [2..5] :: Array [] '[4] Int
-- >>> s
-- [8, 27, 64, 125]
-- >>> :t s
-- s :: Array [] '[4] Int
-- >>> -- replace every second number with -1000
-- >>> let a' = (tabulate (\[i] -> if i `mod` 2 == 0 then -1000 else (index a [i]))) :: Array [] '[10] Int
-- >>> a'
-- [-1000, 1, -1000, 27, -1000, 125, -1000, 343, -1000, 729]
--
-- > -- todo: reverse fix
-- > let a'' = (let (n:_) = shape a in tabulate (\[i] -> index a [n-i])) :: Array [] '[4] Int
-- > a''
-- > [729, -1000, 343, -1000, 125, -1000, 27, -1000, 1, -1000]
--
-- > -- todo: slicing api

-- $shapeManipulation
--
-- > -- todo:

-- $fancyIndexing
--
-- > -- todo:

-- $linearAlgebra
--
-- > -- todo:

-- $tricksTips
--
-- > -- todo: