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

-- | NumHask usage examples
module NumHask.Examples
  (
    -- ** Imports and Pragmas
    -- $imports

    -- $setup
    -- ** Basic Arithmetic
    -- $basic

    -- ** Complex numbers
    -- $complex

    -- ** Vectors
    -- $vector

    -- ** Matrices
    -- $matrices
  ) where

import Data.Functor.Rep
import NumHask.Matrix
import NumHask.Prelude
import NumHask.Vector

-- $imports
-- NumHask.Prelude is a replacement for the standard prelude with the 'NoImplicitPrelude' extension explicitly required.
--
-- $setup
-- >>> :set -XNoImplicitPrelude
-- >>> import NumHask.Prelude
--
-- $basic
-- 'Int', 'Integer', 'Double' and 'Float' are from base.  NumHask takes these classes and redefines the basic arithmetic operators.
--
-- >>> 1 + 1
-- 2
-- >>> 1 - 1
-- 0
-- >>> 1 * 1
-- 1
-- >>> 1 / 1
-- 1.0
--
-- Note that the literal numbers in the divide above defaulted to Float rather than Int.
--
-- >>> 1 / (1::Int)
-- ...
-- ... No instance for (MultiplicativeGroup Int)
-- ...
--
-- >>> 1 / fromIntegral (1::Int)
-- 1.0
--
-- 'Float' and 'Double' are 'NumHask.Algebra.Fields.Field' instances.
--
-- >>> zero == 0.0
-- True
-- >>> one == 1.0
-- True
-- >>> 1.0 + 1.0
-- 2.0
-- >>> 1.0 - 1.0
-- 0.0
-- >>> 1.0 * 1.0
-- 1.0
-- >>> 1.0 / 1.0
-- 1.0
--
-- 'QuotientField'
--
-- >>> 1 `div` 2
-- 0
-- >>> 3 `mod` 2
-- 1
--
-- 'BoundedField'
--
-- >>> one/zero
-- Infinity
-- >>> -one/zero
-- -Infinity
-- >>> zero/zero+one
-- NaN
--
-- 'ExpField'
--
-- >>> logBase 2 4
-- 2.0
-- >>> 2 ** 2
-- 4.0
-- >>> sqrt 4
-- 2.0
-- >>> exp 2
-- 7.38905609893065
-- >>> log 2
-- 0.6931471805599453
--
-- $complex
--
-- >>> let a = 1 :+ 2
-- >>> a
-- 1 :+ 2
-- >>> zero - a
-- (-1) :+ (-2)
-- >>> (1 :+ (-2)) * ((-2) :+ 4)
-- 6 :+ 8
-- >>> (1 :+ (-1)) / (2 :+ 2)
-- 0.0 :+ (-0.5)
-- $vector
-- A 'Vector' is a 'Representable' 'Functor' where the representation is an 'Int'.
--
-- >>> import NumHask.Vector
-- >>> :set -XDataKinds
-- >>> :set -XOverloadedLists
-- >>> [] :: Vector 3 Int
-- [0,0,0]
-- >>> let a = [1..] :: Vector 3 Int
-- >>> a
-- [1,2,3]
-- >>> let b = [3,2] :: Vector 3 Int
-- >>> b
-- [3,2,0]
-- >>> a+zero==a
-- True
-- >>> zero+a==a
-- True
-- >>> a+b
-- [4,4,3]
-- >>> a-a == zero
-- True
-- >>> a * b
-- [3,4,0]
-- >>> let a' = unsafeToVector . someVector $ a :: Vector 2 Int
-- >>> let b' = unsafeToVector . someVector $ b :: Vector 2 Int
-- >>> a' `divMod` b'
-- ([0,1],[1,0])
-- >>> let c = [1.0,2.0] :: Vector 3 Float
-- >>> let d = [3.0,2.0] :: Vector 3 Float
-- >>> c / d
-- [0.33333334,1.0,NaN]
-- >>> size c :: Float
-- 2.236068
-- >>> distance c d :: Float
-- 2.0
-- >>> c <.> d :: Float
-- 7.0
--
-- The type of an outer product of two vectors is a Vector m (Vector n), and is a perfectly formed Matrix representation.
--
-- >>> a >< b
-- [[3,2,0],[6,4,0],[9,6,0]]
--
-- >>> (a >< b) >< (b >< a)
-- [[[9,12,0],[6,8,0],[0,0,0]],[[18,24,0],[12,16,0],[0,0,0]],[[27,36,0],[18,24,0],[0,0,0]]]
-- $matrices
-- A 'Matrix' is a 'Representable' 'Functor' where the representation is an (Int,Int).
--
-- >>> import NumHask.Matrix
-- >>> :set -XDataKinds
-- >>> :set -XOverloadedLists
-- >>> [] :: Matrix 2 1 Int
-- [[0]
--  [0]]
-- >>> let a = [1..] :: Matrix 2 3 Int
-- >>> let b = trans a
-- >>> a
-- [[1,2,3]
--  [4,5,6]]
-- >>> b
-- [[1,4]
--  [2,5]
--  [3,6]]
-- >>> mmult a b
-- [[14,32]
--  [32,77]]
-- >>> getDiag one == (one :: Vector 6 Int)
-- True
-- >>> diagonal one == (one :: Matrix 4 4 Int)
-- True
-- >>> let a = [1..] :: Matrix 3 3 Int
-- >>> a <.> a
-- 285
-- >>> toVV a <.> toVV a
-- [66,93,126]