-- | Module    :  Debug.SimpleExpr.Utils.Algebra
-- Copyright   :  (C) 2025 Alexey Tochin
-- License     :  BSD3 (see the file LICENSE)
-- Maintainer  :  Alexey Tochin <Alexey.Tochin@gmail.com>
--
-- Inegral power type class and instances.
module Debug.SimpleExpr.Utils.Algebra
  ( MultiplicativeAction,
    (*|),
    Convolution,
    (|*|),
    AlgebraicPower,
    IntPower,
    IntegerPower,
    NaturalPower,
    FloatPower,
    DoublePower,
    (^^),
    (^),
    square,
    qube,
    splitIntoN,
    splitInto4,
  )
where

import Combinatorics (binomialSeq)
import Data.Functor (Functor (fmap))
import Data.Functor.Identity (Identity (Identity))
import Data.Int (Int, Int16, Int32, Int64, Int8)
import qualified Data.List as DL
import qualified Data.Stream as DS
import qualified Data.Vector as DV
import qualified Data.Vector.Generic as DVG
import qualified Data.Vector.Generic.Sized as DVGS
import qualified Data.Vector.Unboxed as DVU
import Data.Word (Word, Word16, Word32, Word64, Word8)
import Debug.SimpleExpr (SimpleExpr)
import GHC.Base (Double, Eq ((==)), Float, Maybe, otherwise, ($), (.), (>=))
import GHC.Integer (Integer)
import GHC.Natural (naturalFromInteger)
import qualified GHC.Num as GHCN
import GHC.Real (Integral, Real, fromIntegral, mod, realToFrac, toInteger)
import qualified GHC.Real
import GHC.TypeLits (Natural)
import NumHask
  ( Complex (Complex),
    Field,
    Multiplicative,
    Ring,
    Subtractive,
    negate,
    recip,
    (*),
    (-),
  )
import qualified NumHask as NH

-- | Type class for multiplicative actions.
-- This class defines a method for multiplying a value of type @b@
-- by a value of type @a@ producing a value of type @b@.
--
-- ==== __Examples__
--
-- >>> (2 :: Int) *| (3 :: Float) :: Float
-- 6.0
--
-- >>> (2 :: Int) *| (3 :: Float, 4 :: Double) :: (Float, Double)
-- (6.0,8.0)
--
-- >>> (2 :: Natural) *| [3, 4, 5] :: [Int]
-- [6,8,10]
--
-- >>> (2 :: Natural) *| Data.Vector.fromList [3, 4, 5] :: Data.Vector.Vector Int
-- [6,8,10]
--
-- >>> (2 :: Natural) *| [(3, 4), (5, 6), (7, 8)] :: [(Int, Int)]
-- [(6,8),(10,12),(14,16)]
--
-- >>> (2 :: Natural) *| Data.Vector.fromList [[3, 4], [], [5]] :: Data.Vector.Vector [Int]
-- [[6,8],[],[10]]
class MultiplicativeAction a b where
  -- | Left multiplicative action operator that preserve
  -- the type on the right hand side.
  (*|) :: a -> b -> b

-- | `Int` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Int
  where
  *| :: a -> Int -> Int
(*|) a
c = (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Int -> Int -> Int
forall a. Multiplicative a => a -> a -> a
*)

-- | `Int8` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Int8
  where
  *| :: a -> Int8 -> Int8
(*|) a
c = (a -> Int8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Int8 -> Int8 -> Int8
forall a. Multiplicative a => a -> a -> a
*)

-- | `Int16` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Int16
  where
  *| :: a -> Int16 -> Int16
(*|) a
c = (a -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Int16 -> Int16 -> Int16
forall a. Multiplicative a => a -> a -> a
*)

-- | `Int32` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Int32
  where
  *| :: a -> Int32 -> Int32
(*|) a
c = (a -> Int32
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Int32 -> Int32 -> Int32
forall a. Multiplicative a => a -> a -> a
*)

-- | `Int64` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Int64
  where
  *| :: a -> Int64 -> Int64
(*|) a
c = (a -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Int64 -> Int64 -> Int64
forall a. Multiplicative a => a -> a -> a
*)

-- | `Word` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Word
  where
  *| :: a -> Word -> Word
(*|) a
c = (a -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Word -> Word -> Word
forall a. Multiplicative a => a -> a -> a
*)

-- | `Word8` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Word8
  where
  *| :: a -> Word8 -> Word8
(*|) a
c = (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Word8 -> Word8 -> Word8
forall a. Multiplicative a => a -> a -> a
*)

-- | `Word16` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Word16
  where
  *| :: a -> Word16 -> Word16
(*|) a
c = (a -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Word16 -> Word16 -> Word16
forall a. Multiplicative a => a -> a -> a
*)

-- | `Word32` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Word32
  where
  *| :: a -> Word32 -> Word32
(*|) a
c = (a -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Word32 -> Word32 -> Word32
forall a. Multiplicative a => a -> a -> a
*)

-- | `Word64` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Word64
  where
  *| :: a -> Word64 -> Word64
(*|) a
c = (a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Word64 -> Word64 -> Word64
forall a. Multiplicative a => a -> a -> a
*)

-- | `Integer` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Integer
  where
  *| :: a -> Integer -> Integer
(*|) a
c = (a -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Integer -> Integer -> Integer
forall a. Multiplicative a => a -> a -> a
*)

-- | `Natural` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a Natural
  where
  *| :: a -> Natural -> Natural
(*|) a
c = (a -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
c Natural -> Natural -> Natural
forall a. Multiplicative a => a -> a -> a
*)

-- | `Float` instance of `MultiplicativeAction`@ a@.
instance
  (Real a) =>
  MultiplicativeAction a Float
  where
  *| :: a -> Float -> Float
(*|) a
c = (a -> Float
forall a b. (Real a, Fractional b) => a -> b
realToFrac a
c Float -> Float -> Float
forall a. Multiplicative a => a -> a -> a
*)

-- | `Double` instance of `MultiplicativeAction`@ a@.
instance
  (Real a) =>
  MultiplicativeAction a Double
  where
  *| :: a -> Double -> Double
(*|) a
c = (a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac a
c Double -> Double -> Double
forall a. Multiplicative a => a -> a -> a
*)

-- | `SimpleExpr` instance of `MultiplicativeAction`@ a@.
instance
  (Integral a) =>
  MultiplicativeAction a SimpleExpr
  where
  *| :: a -> SimpleExpr -> SimpleExpr
(*|) a
c = SimpleExpr -> SimpleExpr -> SimpleExpr
forall a. Multiplicative a => a -> a -> a
(*) (Integer -> SimpleExpr
forall a. FromInteger a => Integer -> a
NH.fromInteger (Integer -> SimpleExpr) -> Integer -> SimpleExpr
forall a b. (a -> b) -> a -> b
$ a -> Integer
forall a. Integral a => a -> Integer
toInteger a
c)

-- | Tuple instance of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b0, MultiplicativeAction a b1) =>
  MultiplicativeAction a (b0, b1)
  where
  *| :: a -> (b0, b1) -> (b0, b1)
(*|) a
c (b0
x0, b1
x1) = (a
c a -> b0 -> b0
forall a b. MultiplicativeAction a b => a -> b -> b
*| b0
x0, a
c a -> b1 -> b1
forall a b. MultiplicativeAction a b => a -> b -> b
*| b1
x1)

-- | Triple instance of `MultiplicativeAction`@ a@.
instance
  ( MultiplicativeAction a b0,
    MultiplicativeAction a b1,
    MultiplicativeAction a b2
  ) =>
  MultiplicativeAction a (b0, b1, b2)
  where
  *| :: a -> (b0, b1, b2) -> (b0, b1, b2)
(*|) a
c (b0
x0, b1
x1, b2
x2) = (a
c a -> b0 -> b0
forall a b. MultiplicativeAction a b => a -> b -> b
*| b0
x0, a
c a -> b1 -> b1
forall a b. MultiplicativeAction a b => a -> b -> b
*| b1
x1, a
c a -> b2 -> b2
forall a b. MultiplicativeAction a b => a -> b -> b
*| b2
x2)

-- | `Data.Functor.Identity` instance of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a (Identity b)
  where
  *| :: a -> Identity b -> Identity b
(*|) = (b -> b) -> Identity b -> Identity b
forall a b. (a -> b) -> Identity a -> Identity b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((b -> b) -> Identity b -> Identity b)
-> (a -> b -> b) -> a -> Identity b -> Identity b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | List `[]` instance of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a [b]
  where
  *| :: a -> [b] -> [b]
(*|) = (b -> b) -> [b] -> [b]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((b -> b) -> [b] -> [b]) -> (a -> b -> b) -> a -> [b] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | Boxed vector `Data.Vector.Vector` instance of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a (DV.Vector b)
  where
  *| :: a -> Vector b -> Vector b
(*|) = (b -> b) -> Vector b -> Vector b
forall a b. (a -> b) -> Vector a -> Vector b
DV.map ((b -> b) -> Vector b -> Vector b)
-> (a -> b -> b) -> a -> Vector b -> Vector b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | Unboxed vector `Data.Vector.Unboxed.Vector` instance
-- of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a (DVGS.Vector DV.Vector n b)
  where
  *| :: a -> Vector Vector n b -> Vector Vector n b
(*|) = (b -> b) -> Vector Vector n b -> Vector Vector n b
forall (v :: * -> *) a b (n :: Natural).
(Vector v a, Vector v b) =>
(a -> b) -> Vector v n a -> Vector v n b
DVGS.map ((b -> b) -> Vector Vector n b -> Vector Vector n b)
-> (a -> b -> b) -> a -> Vector Vector n b -> Vector Vector n b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | `Data.Stream.Stream` instance of `MultiplicativeAction`@ a@.
instance
  (MultiplicativeAction a b) =>
  MultiplicativeAction a (DS.Stream b)
  where
  *| :: a -> Stream b -> Stream b
(*|) = (b -> b) -> Stream b -> Stream b
forall a b. (a -> b) -> Stream a -> Stream b
DS.map ((b -> b) -> Stream b -> Stream b)
-> (a -> b -> b) -> a -> Stream b -> Stream b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b -> b
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)

-- | Type class for convolution operations that support nested structures.
--
-- ==== __Examples__
--
-- >>> [1,1,1] |*| [1,2,0] :: Int
-- 3
--
-- >>> ([1,1,1], Data.Vector.fromList [1, 2]) |*| ([1,2,0], Data.Vector.fromList [0, 2]) :: Int
-- 7
class Convolution a b c where
  -- | The convolution operator that combines values of type @a@ and @b@.
  (|*|) :: a -> b -> c

-- | `Int` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Int Int a
  where
  Int
x |*| :: Int -> Int -> a
|*| Int
y = Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Int -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
y

-- | `Int8` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Int8 Int8 a
  where
  Int8
x |*| :: Int8 -> Int8 -> a
|*| Int8
y = Int8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int8
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Int8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int8
y

-- | `Int16` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Int16 Int16 a
  where
  Int16
x |*| :: Int16 -> Int16 -> a
|*| Int16
y = Int16 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int16
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Int16 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int16
y

-- | `Int32` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Int32 Int32 a
  where
  Int32
x |*| :: Int32 -> Int32 -> a
|*| Int32
y = Int32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Int32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
y

-- | `Int64` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Int64 Int64 a
  where
  Int64
x |*| :: Int64 -> Int64 -> a
|*| Int64
y = Int64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Int64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
y

-- | `Word` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Word Word a
  where
  Word
x |*| :: Word -> Word -> a
|*| Word
y = Word -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Word -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
y

-- | `Word8` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Word8 Word8 a
  where
  Word8
x |*| :: Word8 -> Word8 -> a
|*| Word8
y = Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Word8 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
y

-- | `Word16` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Word16 Word16 a
  where
  Word16
x |*| :: Word16 -> Word16 -> a
|*| Word16
y = Word16 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Word16 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
y

-- | `Word32` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Word32 Word32 a
  where
  Word32
x |*| :: Word32 -> Word32 -> a
|*| Word32
y = Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Word32 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
y

-- | `Word64` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Word64 Word64 a
  where
  Word64
x |*| :: Word64 -> Word64 -> a
|*| Word64
y = Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
y

-- | `Integer` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Integer Integer a
  where
  Integer
x |*| :: Integer -> Integer -> a
|*| Integer
y = Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Integer -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
y

-- | `Natural` instance of `Convolution`.
instance
  (GHCN.Num a) =>
  Convolution Natural Natural a
  where
  Natural
x |*| :: Natural -> Natural -> a
|*| Natural
y = Natural -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Natural -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
y

-- | `Float` instance of `Convolution`.
instance
  (GHC.Real.Fractional a) =>
  Convolution Float Float a
  where
  Float
x |*| :: Float -> Float -> a
|*| Float
y = Float -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac Float
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Float -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac Float
y

-- | `Double` instance of `Convolution`.
instance
  (GHC.Real.Fractional a) =>
  Convolution Double Double a
  where
  Double
x |*| :: Double -> Double -> a
|*| Double
y = Double -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
x a -> a -> a
forall a. Num a => a -> a -> a
GHCN.* Double -> a
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
y

-- | Tuple instance of `Convolution`.
instance
  (Convolution a0 b0 c, Convolution a1 b1 c, NH.Additive c) =>
  Convolution (a0, a1) (b0, b1) c
  where
  (a0
x0, a1
x1) |*| :: (a0, a1) -> (b0, b1) -> c
|*| (b0
y0, b1
y1) = a0
x0 a0 -> b0 -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b0
y0 c -> c -> c
forall a. Additive a => a -> a -> a
NH.+ a1
x1 a1 -> b1 -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b1
y1

-- | Triple instance of `Convolution`.
instance
  (Convolution a0 b0 c, Convolution a1 b1 c, Convolution a2 b2 c, NH.Additive c) =>
  Convolution (a0, a1, a2) (b0, b1, b2) c
  where
  (a0
x0, a1
x1, a2
x2) |*| :: (a0, a1, a2) -> (b0, b1, b2) -> c
|*| (b0
y0, b1
y1, b2
y2) = a0
x0 a0 -> b0 -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b0
y0 c -> c -> c
forall a. Additive a => a -> a -> a
NH.+ a1
x1 a1 -> b1 -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b1
y1 c -> c -> c
forall a. Additive a => a -> a -> a
NH.+ a2
x2 a2 -> b2 -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b2
y2

-- | `Data.Functor.Identity` instance of `Convolution`.
instance
  (Convolution a b c) =>
  Convolution (Identity a) (Identity b) c
  where
  (Identity a
x) |*| :: Identity a -> Identity b -> c
|*| (Identity b
y) = a
x a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
|*| b
y

-- | List `[]` instance of `Convolution`.
-- Shorter list is efficently treated as padded with zeros.
instance
  (Convolution a b c, NH.Additive c) =>
  Convolution [a] [b] c
  where
  [a]
lx |*| :: [a] -> [b] -> c
|*| [b]
ly = (c -> c -> c) -> c -> [c] -> c
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
DL.foldl' c -> c -> c
forall a. Additive a => a -> a -> a
(NH.+) c
forall a. Additive a => a
NH.zero ([c] -> c) -> [c] -> c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> [a] -> [b] -> [c]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
DL.zipWith a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
(|*|) [a]
lx [b]
ly

-- | Boxed vector `Data.Vector.Vector` instance of `Convolution`.
-- Smaller vector is efficently treated as padded with zeros.
instance
  (Convolution a b c, NH.Additive c) =>
  Convolution (DV.Vector a) (DV.Vector b) c
  where
  Vector a
vx |*| :: Vector a -> Vector b -> c
|*| Vector b
vy = (c -> c -> c) -> c -> Vector c -> c
forall a b. (a -> b -> a) -> a -> Vector b -> a
DV.foldl' c -> c -> c
forall a. Additive a => a -> a -> a
(NH.+) c
forall a. Additive a => a
NH.zero (Vector c -> c) -> Vector c -> c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c) -> Vector a -> Vector b -> Vector c
forall a b c. (a -> b -> c) -> Vector a -> Vector b -> Vector c
DV.zipWith a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
(|*|) Vector a
vx Vector b
vy

-- | Unboxed vector `Data.Vector.Unboxed.Vector` instance of `Convolution`.
-- Smaller vector is efficently treated as padded with zeros.
instance
  (Convolution a b c, NH.Additive c) =>
  Convolution (DVGS.Vector DV.Vector n a) (DVGS.Vector DV.Vector n b) c
  where
  Vector Vector n a
vx |*| :: Vector Vector n a -> Vector Vector n b -> c
|*| Vector Vector n b
vy = (c -> c -> c) -> c -> Vector Vector n c -> c
forall (v :: * -> *) b a (n :: Natural).
Vector v b =>
(a -> b -> a) -> a -> Vector v n b -> a
DVGS.foldl' c -> c -> c
forall a. Additive a => a -> a -> a
(NH.+) c
forall a. Additive a => a
NH.zero (Vector Vector n c -> c) -> Vector Vector n c -> c
forall a b. (a -> b) -> a -> b
$ (a -> b -> c)
-> Vector Vector n a -> Vector Vector n b -> Vector Vector n c
forall (v :: * -> *) a b c (n :: Natural).
(Vector v a, Vector v b, Vector v c) =>
(a -> b -> c) -> Vector v n a -> Vector v n b -> Vector v n c
DVGS.zipWith a -> b -> c
forall a b c. Convolution a b c => a -> b -> c
(|*|) Vector Vector n a
vx Vector Vector n b
vy

-- instance
--   MultiplicativeAction a b c =>
--   MultiplicativeAction (FiniteSupportStream a) (DS.Stream b) c
--   where
--   vx |*| vy = undefined --   foldl' zero (+) $ DVGS.zipwith (|*|) lx ly
--   -- (*|) = DS.map . (*|)

-- instance
--   MultiplicativeAction a b c =>
--   MultiplicativeAction (DS.Stream a) (FiniteSupportStream b) c
--   where
--   vx |*| vy = undefined --   foldl' zero (+) $ DVGS.zipwith (|*|) lx ly

-- instance
--   MultiplicativeAction a b c =>
--   MultiplicativeAction (FiniteSupportStream a) (FiniteSupportStream b) c
--   where
--   vx |*| vy = undefined --   foldl' zero (+) $ DVGS.zipwith (|*|) lx ly

-- | Type class for power operations.
-- This class defines a method for raising a value of type @a@ to a power
-- of type @b@.
-- It is usefull to deistinguish, for example,
-- the integral power defined as a repetative multiplication
-- `(^^)` or `(^)` from the general power operation.
--
-- ==== __Examples__
--
-- >>> import Debug.SimpleExpr (variable, SE, simplify)
-- >>> import GHC.Base (($))
-- >>> import GHC.Real (Rational)
-- >>> import qualified NumHask
--
-- >>> x = variable "x"
--
-- >>> (^^ 2) x
-- x^2
--
-- >>> (NumHask.^^ 2) (x)
-- x*x
--
-- >>> (^^ 2) (3 :: Float)
-- 9.0
--
-- >>> (2.0 :: Double) ^^ (3.5 :: Float)
-- 11.313708498984761
--
-- For lists, vectors and other containers, the power operation is applied element-wise:
-- >>> (^^ 2) [0, 1, 2, 3] :: [Int]
-- [0,1,4,9]
class AlgebraicPower a b where
  (^^) :: b -> a -> b

-- | `Int` type alias for `AlgebraicPower`.
type IntPower a = AlgebraicPower Int a

-- | `Integer` type alias for `AlgebraicPower`.
type IntegerPower a = AlgebraicPower Integer a

-- | `Natural` type alias for `AlgebraicPower`.
type NaturalPower a = AlgebraicPower Natural a

-- | `Float` type alias for `AlgebraicPower`.
type FloatPower a = AlgebraicPower Float a

-- | `Double` type alias for `AlgebraicPower`.
type DoublePower a = AlgebraicPower Double a

-- | Infix synonym for `(^^)`.
(^) :: (AlgebraicPower Integer a) => a -> Integer -> a
^ :: forall a. AlgebraicPower Integer a => a -> Integer -> a
(^) = a -> Integer -> a
forall a b. AlgebraicPower a b => b -> a -> b
(^^)

-- | Square a value.
square :: (AlgebraicPower Integer a) => a -> a
square :: forall a. AlgebraicPower Integer a => a -> a
square a
x = a
x a -> Integer -> a
forall a. AlgebraicPower Integer a => a -> Integer -> a
^ Integer
2

-- | Qube a value.
qube :: (AlgebraicPower Integer a) => a -> a
qube :: forall a. AlgebraicPower Integer a => a -> a
qube a
x = a
x a -> Integer -> a
forall a. AlgebraicPower Integer a => a -> Integer -> a
^ Integer
2

-- | `Int` instance of `AlgebraicPower` typeclass.
instance
  (Integral a) =>
  AlgebraicPower a Int
  where
  Int
x ^^ :: Int -> a -> Int
^^ a
n = Int
x Int -> a -> Int
forall a b. (Num a, Integral b) => a -> b -> a
GHC.Real.^ a
n

-- | `Int8` instance of `AlgebraicPower` typeclass.
instance
  (Integral a) =>
  AlgebraicPower a Int8
  where
  Int8
x ^^ :: Int8 -> a -> Int8
^^ a
n = Int8
x Int8 -> a -> Int8
forall a b. (Num a, Integral b) => a -> b -> a
GHC.Real.^ a
n

-- | `Integer` instance of `AlgebraicPower` typeclass.
instance
  (Integral a) =>
  AlgebraicPower a Integer
  where
  Integer
x ^^ :: Integer -> a -> Integer
^^ a
n = Integer
x Integer -> a -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
GHC.Real.^ a
n

-- | `Float` instace of `AlgebraicPower` typeclass.
instance
  (Real a) =>
  AlgebraicPower a Float
  where
  Float
x ^^ :: Float -> a -> Float
^^ a
n = Float
x Float -> Float -> Float
forall a. ExpField a => a -> a -> a
NH.** a -> Float
forall a b. (Real a, Fractional b) => a -> b
realToFrac a
n

-- | `Double` instance of `AlgebraicPower` typeclass
-- for raising `Double` values to `Real` exponents.
instance
  (Real a) =>
  AlgebraicPower a Double
  where
  Double
x ^^ :: Double -> a -> Double
^^ a
n = Double
x Double -> Double -> Double
forall a. ExpField a => a -> a -> a
NH.** a -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac a
n

-- | `AlgebraicPower` instance for raising `SimpleExpr` values to `Integer` exponents.
instance AlgebraicPower Integer SimpleExpr where
  SimpleExpr
x ^^ :: SimpleExpr -> Integer -> SimpleExpr
^^ Integer
n = SimpleExpr
x SimpleExpr -> SimpleExpr -> SimpleExpr
forall a. ExpField a => a -> a -> a
NH.** Integer -> SimpleExpr
forall a. FromInteger a => Integer -> a
NH.fromInteger Integer
n

-- | `Data.Functor.Identity` instance of `AlgebraicPower` typeclass.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b (Identity a)
  where
  (Identity a
x0) ^^ :: Identity a -> b -> Identity a
^^ b
n = a -> Identity a
forall a. a -> Identity a
Identity (a -> Identity a) -> a -> Identity a
forall a b. (a -> b) -> a -> b
$ a
x0 a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n

-- | `Maybe` instance of `AlgebraicPower` typeclass.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b (Maybe a)
  where
  Maybe a
x ^^ :: Maybe a -> b -> Maybe a
^^ b
n = (a -> a) -> Maybe a -> Maybe a
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) Maybe a
x

-- | Generate the list of terms of the binomial expansion of
-- \( (x + y)^n \).
--
-- ==== __Examples__
--
-- >>> import Debug.SimpleExpr (variable, simplify)
--
-- >>> simplify $ biniminalList 3 (variable "x") (variable "y")
-- [y^3,3*(x*(y^2)),3*((x^2)*y),x^3]
biniminalList ::
  ( Multiplicative a,
    AlgebraicPower b a,
    MultiplicativeAction b a,
    Subtractive b,
    Integral b
  ) =>
  b ->
  a ->
  a ->
  [a]
biniminalList :: forall a b.
(Multiplicative a, AlgebraicPower b a, MultiplicativeAction b a,
 Subtractive b, Integral b) =>
b -> a -> a -> [a]
biniminalList b
n a
x a
y =
  (b -> a -> a) -> [b] -> [a] -> [a]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
DL.zipWith
    b -> a -> a
forall a b. MultiplicativeAction a b => a -> b -> b
(*|)
    (b -> [b]
forall a. Integral a => a -> [a]
binomialSeq b
n)
    ([a
x a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
i a -> a -> a
forall a. Multiplicative a => a -> a -> a
* a
y a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ (b
n b -> b -> b
forall a. Subtractive a => a -> a -> a
- b
i) | b
i <- [b
0 ..]])

-- | Interleave two lists.
--
-- ==== __Examples__
--
-- >>> interleave [1,3,5] [2,4,6]
-- [1,2,3,4,5,6]
interleave :: [a] -> [a] -> [a]
interleave :: forall a. [a] -> [a] -> [a]
interleave [] [a]
ys = [a]
ys
interleave [a]
xs [] = [a]
xs
interleave (a
x : [a]
xs) (a
y : [a]
ys) = a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: a
y a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
interleave [a]
xs [a]
ys

-- | Take every n-th element from a list starting from a given index.
--
-- ==== __Examples__
--
-- >>> takeEveryNth 3 0 [0..11]
-- [0,3,6,9]
takeEveryNth :: Int -> Int -> [a1] -> [a1]
takeEveryNth :: forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
n Int
start [a1]
ys = [a1
y | (a1
y, Int
j) <- [a1] -> [Int] -> [(a1, Int)]
forall a b. [a] -> [b] -> [(a, b)]
DL.zip [a1]
ys [Int
0 ..], Int
j Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
start]

-- | Split a list into n lists by taking every n-th element.
--
-- ==== __Examples__
--
-- >>> splitIntoN 3 [0..11]
-- [[0,3,6,9],[1,4,7,10],[2,5,8,11]]
splitIntoN :: Int -> [a] -> [[a]]
splitIntoN :: forall a. Int -> [a] -> [[a]]
splitIntoN Int
n [a]
xs = [Int -> Int -> [a] -> [a]
forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
n Int
i [a]
xs | Int
i <- [Int
0 .. Int
n Int -> Int -> Int
forall a. Subtractive a => a -> a -> a
- Int
1]]

-- | Split a list into n lists by taking every n-th element.
--
-- ==== __Examples__
--
-- >>> splitInto4 [0..11]
-- ([0,4,8],[1,5,9],[2,6,10],[3,7,11])
splitInto4 :: [a] -> ([a], [a], [a], [a])
splitInto4 :: forall a. [a] -> ([a], [a], [a], [a])
splitInto4 [a]
xs = (Int -> Int -> [a] -> [a]
forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
4 Int
0 [a]
xs, Int -> Int -> [a] -> [a]
forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
4 Int
1 [a]
xs, Int -> Int -> [a] -> [a]
forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
4 Int
2 [a]
xs, Int -> Int -> [a] -> [a]
forall a1. Int -> Int -> [a1] -> [a1]
takeEveryNth Int
4 Int
3 [a]
xs)

-- | Complex number `NumHask.Complex` instance of `AlgebraicPower`
-- for raising to `Natural` exponents.
instance
  (Ring a, AlgebraicPower Natural a, MultiplicativeAction Natural a) =>
  AlgebraicPower Natural (Complex a)
  where
  (Complex (a
x, a
y)) ^^ :: Complex a -> Natural -> Complex a
^^ Natural
n = (a, a) -> Complex a
forall a. (a, a) -> Complex a
Complex (a
r, a
i)
    where
      r :: a
r = [a] -> a
forall a (f :: * -> *). (Additive a, Foldable f) => f a -> a
NH.sum ([a] -> a) -> [a] -> a
forall a b. (a -> b) -> a -> b
$ [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
interleave [a]
split0 ((a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Subtractive a => a -> a
negate [a]
split2)
      i :: a
i = [a] -> a
forall a (f :: * -> *). (Additive a, Foldable f) => f a -> a
NH.sum ([a] -> a) -> [a] -> a
forall a b. (a -> b) -> a -> b
$ [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
interleave [a]
split1 ((a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> a
forall a. Subtractive a => a -> a
negate [a]
split3)
      ([a]
split0, [a]
split1, [a]
split2, [a]
split3) = [a] -> ([a], [a], [a], [a])
forall a. [a] -> ([a], [a], [a], [a])
splitInto4 (Natural -> a -> a -> [a]
forall a b.
(Multiplicative a, AlgebraicPower b a, MultiplicativeAction b a,
 Subtractive b, Integral b) =>
b -> a -> a -> [a]
biniminalList Natural
n a
x a
y)

-- | Complex number `NumHask.Complex` instance of `AlgebraicPower`
-- for raising to `Integer` exponents.
instance
  (Field a, AlgebraicPower Natural a, MultiplicativeAction Natural a) =>
  AlgebraicPower Integer (Complex a)
  where
  Complex a
x ^^ :: Complex a -> Integer -> Complex a
^^ Integer
n
    | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
0 = Complex a
x Complex a -> Natural -> Complex a
forall a b. AlgebraicPower a b => b -> a -> b
^^ Integer -> Natural
naturalFromInteger Integer
n
    | Bool
otherwise = Complex a -> Complex a
forall a. Divisive a => a -> a
recip (Complex a -> Complex a) -> Complex a -> Complex a
forall a b. (a -> b) -> a -> b
$ Complex a
x Complex a -> Natural -> Complex a
forall a b. AlgebraicPower a b => b -> a -> b
^^ Integer -> Natural
naturalFromInteger (-Integer
n)

-- | `AlgebraicPower` instance for raising tuples to powers.
instance
  (AlgebraicPower b a0, AlgebraicPower b a1) =>
  AlgebraicPower b (a0, a1)
  where
  (a0
x0, a1
x1) ^^ :: (a0, a1) -> b -> (a0, a1)
^^ b
n = (a0
x0 a0 -> b -> a0
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n, a1
x1 a1 -> b -> a1
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n)

-- | `AlgebraicPower` instance for raising triples to powers.
instance
  (AlgebraicPower b a0, AlgebraicPower b a1, AlgebraicPower b a2) =>
  AlgebraicPower b (a0, a1, a2)
  where
  (a0
x0, a1
x1, a2
x2) ^^ :: (a0, a1, a2) -> b -> (a0, a1, a2)
^^ b
n = (a0
x0 a0 -> b -> a0
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n, a1
x1 a1 -> b -> a1
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n, a2
x2 a2 -> b -> a2
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n)

-- | `AlgebraicPower` instance for raising lists to powers.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b [a]
  where
  [a]
x ^^ :: [a] -> b -> [a]
^^ b
n = (a -> a) -> [a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) [a]
x

-- | `AlgebraicPower` instance for raising boxed vectors to powers.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b (DV.Vector a)
  where
  Vector a
x ^^ :: Vector a -> b -> Vector a
^^ b
n = (a -> a) -> Vector a -> Vector a
forall a b. (a -> b) -> Vector a -> Vector b
DV.map (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) Vector a
x

-- | `AlgebraicPower` instance for raising unboxed vectors to powers.
instance
  (AlgebraicPower b a, DVU.Unbox a) =>
  AlgebraicPower b (DVU.Vector a)
  where
  Vector a
x ^^ :: Vector a -> b -> Vector a
^^ b
n = (a -> a) -> Vector a -> Vector a
forall a b. (Unbox a, Unbox b) => (a -> b) -> Vector a -> Vector b
DVU.map (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) Vector a
x

-- | `AlgebraicPower` instance for raising sized vectors to powers.
instance
  (AlgebraicPower b a, DVG.Vector v a) =>
  AlgebraicPower b (DVGS.Vector v n a)
  where
  Vector v n a
x ^^ :: Vector v n a -> b -> Vector v n a
^^ b
n = (a -> a) -> Vector v n a -> Vector v n a
forall (v :: * -> *) a b (n :: Natural).
(Vector v a, Vector v b) =>
(a -> b) -> Vector v n a -> Vector v n b
DVGS.map (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) Vector v n a
x

-- | `AlgebraicPower` instance for raising streams to powers.
instance
  (AlgebraicPower b a) =>
  AlgebraicPower b (DS.Stream a)
  where
  Stream a
x ^^ :: Stream a -> b -> Stream a
^^ b
n = (a -> a) -> Stream a -> Stream a
forall a b. (a -> b) -> Stream a -> Stream b
DS.map (a -> b -> a
forall a b. AlgebraicPower a b => b -> a -> b
^^ b
n) Stream a
x