harpie
Safe HaskellNone
LanguageGHC2024

Harpie.Fixed.Generic

Description

Arrays with shape information and computations at a type-level.

Synopsis

Usage

>>> :set -XDataKinds

Several names used in harpie conflict with Prelude:

>>> import Prelude hiding (cycle, repeat, take, drop, zipWith, length)

In general, Array functionality is contained in Harpie.Fixed and shape functionality is contained in Harpie.Shape. These two modules also have name clashes and at least one needs to be qualified:

>>> import Harpie.Fixed.Generic as F
>>> import Harpie.Shape qualified as S

prettyprinter is used to prettily render arrays to better visualise shape.

>>> import Prettyprinter hiding (dot,fill)

The Representable class from adjunctions is used heavily by the module.

>>> import Data.Functor.Rep hiding (index, tabulate)

An important base accounting of Array shape is the singleton types SNat (a type-level Natural or Nat) from GHC.TypeNats in base.

>>> import GHC.TypeNats

The first-class-families library was used to code most of type-level constraint logic.

>>> import Fcf qualified

Examples of arrays:

An array with no dimensions (a scalar).

>>> s = array @Vec.Vector @'[] @Int [1]
>>> s
[1]
>>> shape s
[]
>>> pretty s
1

A single-dimension array (a vector).

>>> let v = range @Vec.Vector @'[3]
>>> pretty v
[0,1,2]

A two-dimensional array (a matrix).

>>> let m = range @Vec.Vector @[2,3]
>>> pretty m
[[0,1,2],
 [3,4,5]]

An n-dimensional array (n should be finite).

>>> a = range @Vec.Vector @[2,3,4]
>>> a
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]
>>> pretty a
[[[0,1,2,3],
  [4,5,6,7],
  [8,9,10,11]],
 [[12,13,14,15],
  [16,17,18,19],
  [20,21,22,23]]]

Conversion to a dynamic, value-level shaped Array

>>> toDynamic a
UnsafeArray [2,3,4] [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]

Fixed Arrays

newtype Array (v :: k -> Type) (s :: [Nat]) (a :: k) Source #

A hyperrectangular (or multidimensional) array with a type-level shape.

>>> array @Vec.Vector @[2,3,4] @Int [1..24]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
>>> array [1..24] :: Array Vec.Vector '[2,3,4] Int
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
>>> pretty (array @Vec.Vector @[2,3,4] @Int [1..24])
[[[1,2,3,4],
  [5,6,7,8],
  [9,10,11,12]],
 [[13,14,15,16],
  [17,18,19,20],
  [21,22,23,24]]]
>>> array [1,2,3] :: Array Vec.Vector '[2,2] Int
*** Exception: Shape Mismatch
...

In many situations, the use of TypeApplication can lead to a clean coding style.

>>> array @Vec.Vector @[2,3] @Int [1..6]
[1,2,3,4,5,6]

The main computational entry and exit points are often via index and tabulate with arrays indexed by Fins:

>>> index a (S.UnsafeFins [1,2,3])
23
>>> :t tabulate id :: Array Vec.Vector [2,3] (Fins [2,3])
tabulate id :: Array Vec.Vector [2,3] (Fins [2,3])
  :: Array Vec.Vector [2, 3] (Fins [2, 3])
>>> pretty (tabulate id :: Array Vec.Vector [2,3] (Fins [2,3]))
[[[0,0],[0,1],[0,2]],
 [[1,0],[1,1],[1,2]]]

Constructors

Array (v a) 

Instances

Instances details
(Storable a, KnownNats s) => FromVector (Array s a) a Source # 
Instance details

Defined in Harpie.Fixed.Storable

Methods

asVector :: Array s a -> Vector a Source #

vectorAs :: Vector a -> Array s a Source #

(Unbox a, KnownNats s) => FromVector (Array s a) a Source # 
Instance details

Defined in Harpie.Fixed.Unboxed

Methods

asVector :: Array s a -> Vector a Source #

vectorAs :: Vector a -> Array s a Source #

Functor v => Functor (Array v s) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

fmap :: (a -> b) -> Array v s a -> Array v s b #

(<$) :: a -> Array v s b -> Array v s a #

Foldable v => Foldable (Array v s) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

fold :: Monoid m => Array v s m -> m #

foldMap :: Monoid m => (a -> m) -> Array v s a -> m #

foldMap' :: Monoid m => (a -> m) -> Array v s a -> m #

foldr :: (a -> b -> b) -> b -> Array v s a -> b #

foldr' :: (a -> b -> b) -> b -> Array v s a -> b #

foldl :: (b -> a -> b) -> b -> Array v s a -> b #

foldl' :: (b -> a -> b) -> b -> Array v s a -> b #

foldr1 :: (a -> a -> a) -> Array v s a -> a #

foldl1 :: (a -> a -> a) -> Array v s a -> a #

toList :: Array v s a -> [a] #

null :: Array v s a -> Bool #

length :: Array v s a -> Int #

elem :: Eq a => a -> Array v s a -> Bool #

maximum :: Ord a => Array v s a -> a #

minimum :: Ord a => Array v s a -> a #

sum :: Num a => Array v s a -> a #

product :: Num a => Array v s a -> a #

Traversable v => Traversable (Array v s) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

traverse :: Applicative f => (a -> f b) -> Array v s a -> f (Array v s b) #

sequenceA :: Applicative f => Array v s (f a) -> f (Array v s a) #

mapM :: Monad m => (a -> m b) -> Array v s a -> m (Array v s b) #

sequence :: Monad m => Array v s (m a) -> m (Array v s a) #

Eq (v a) => Eq (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(==) :: Array v s a -> Array v s a -> Bool #

(/=) :: Array v s a -> Array v s a -> Bool #

Ord (v a) => Ord (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

compare :: Array v s a -> Array v s a -> Ordering #

(<) :: Array v s a -> Array v s a -> Bool #

(<=) :: Array v s a -> Array v s a -> Bool #

(>) :: Array v s a -> Array v s a -> Bool #

(>=) :: Array v s a -> Array v s a -> Bool #

max :: Array v s a -> Array v s a -> Array v s a #

min :: Array v s a -> Array v s a -> Array v s a #

Generic (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Associated Types

type Rep (Array v s a) 
Instance details

Defined in Harpie.Fixed.Generic

type Rep (Array v s a) = D1 ('MetaData "Array" "Harpie.Fixed.Generic" "harpie-0.3.0.0-inplace" 'True) (C1 ('MetaCons "Array" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (v a))))

Methods

from :: Array v s a -> Rep (Array v s a) x #

to :: Rep (Array v s a) x -> Array v s a #

Show (v a) => Show (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

showsPrec :: Int -> Array v s a -> ShowS #

show :: Array v s a -> String #

showList :: [Array v s a] -> ShowS #

(Additive a, KnownNats s, Vector v a) => AdditiveAction (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Associated Types

type AdditiveScalar (Array v s a) 
Instance details

Defined in Harpie.Fixed.Generic

type AdditiveScalar (Array v s a) = a

Methods

(|+) :: Array v s a -> AdditiveScalar (Array v s a) -> Array v s a #

(Divisive a, KnownNats s, Vector v a) => DivisiveAction (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(|/) :: Array v s a -> Scalar (Array v s a) -> Array v s a #

(Multiplicative a, KnownNats s, Vector v a) => MultiplicativeAction (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Associated Types

type Scalar (Array v s a) 
Instance details

Defined in Harpie.Fixed.Generic

type Scalar (Array v s a) = a

Methods

(|*) :: Array v s a -> Scalar (Array v s a) -> Array v s a #

(Subtractive a, KnownNats s, Vector v a) => SubtractiveAction (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(|-) :: Array v s a -> AdditiveScalar (Array v s a) -> Array v s a #

(Additive a, KnownNats s, Vector v a) => Additive (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(+) :: Array v s a -> Array v s a -> Array v s a #

zero :: Array v s a #

(Subtractive a, KnownNats s, Vector v a) => Subtractive (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

negate :: Array v s a -> Array v s a #

(-) :: Array v s a -> Array v s a -> Array v s a #

(KnownNats s, JoinSemiLattice a, Vector v a, Eq (v a)) => JoinSemiLattice (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(\/) :: Array v s a -> Array v s a -> Array v s a #

(KnownNats s, MeetSemiLattice a, Vector v a, Eq (v a)) => MeetSemiLattice (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

(/\) :: Array v s a -> Array v s a -> Array v s a #

(KnownNats s, Subtractive a, Epsilon a, Vector v a, Eq (v a)) => Epsilon (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

epsilon :: Array v s a #

(FromInteger a, Vector v a) => FromInteger (Array v ('[] :: [Nat]) a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

fromInteger :: Integer -> Array v ('[] :: [Nat]) a #

(FromRational a, Vector v a) => FromRational (Array v ('[] :: [Nat]) a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

fromRational :: Rational -> Array v ('[] :: [Nat]) a #

(KnownNats s, Show a, Show (v a), Vector v a, Vector v (Array v a)) => Pretty (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

pretty :: Array v s a -> Doc ann #

prettyList :: [Array v s a] -> Doc ann #

Vector v a => FromVector (Array v s a) v a Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

asVector :: Array v s a -> v a Source #

vectorAs :: v a -> Array v s a Source #

type Rep (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

type Rep (Array v s a) = D1 ('MetaData "Array" "Harpie.Fixed.Generic" "harpie-0.3.0.0-inplace" 'True) (C1 ('MetaCons "Array" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (v a))))
type AdditiveScalar (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

type AdditiveScalar (Array v s a) = a
type Scalar (Array v s a) Source # 
Instance details

Defined in Harpie.Fixed.Generic

type Scalar (Array v s a) = a

unsafeArray :: forall (s :: [Nat]) t (v :: Type -> Type) a. (KnownNats s, FromVector t v a, Vector v a) => t -> Array v s a Source #

Construct an array without shape validation.

>>> unsafeArray [0..4] :: Array Vec.Vector [2,3] Int
[0,1,2,3,4]

validate :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> Bool Source #

Validate the size and shape of an array.

>>> validate (unsafeArray [0..4] :: Array Vec.Vector [2,3] Int)
False

safeArray :: forall (s :: [Nat]) t (v :: Type -> Type) a. (KnownNats s, FromVector t v a, Vector v a) => t -> Maybe (Array v s a) Source #

Construct an Array, checking shape.

>>> (safeArray [0..23] :: Maybe (Array Vec.Vector [2,3,4] Int)) == Just a
True

array :: forall (v :: Type -> Type) (s :: [Nat]) a t. (KnownNats s, FromVector t v a, Vector v a) => t -> Array v s a Source #

Construct an Array, throwing an exception on a bad shape.

>>> array [0..22] :: Array Vec.Vector [2,3,4] Int
*** Exception: Shape Mismatch
...

unsafeModifyShape :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', Vector v a) => Array v s a -> Array v s' a Source #

Unsafely modify an array shape.

>>> pretty (unsafeModifyShape @Vec.Vector @[3,2] (array @Vec.Vector @[2,3] @Int [0..5]))
[[0,1],
 [2,3],
 [4,5]]

unsafeModifyVector :: forall v (s :: [Nat]) a b. (KnownNats s, Vector v a, Vector v b) => (v a -> v b) -> Array v s a -> Array v s b Source #

Unsafely modify an array vector.

pretty (unsafeModifyVector (Vec.map (+1)) (array [0..5] :: Array Vec.Vector [2,3] Int))
[1,2,3
,
4,5,6
]

Dimensions

type Dim = SNat Source #

Representation of an index into a shape (a type-level [Nat]). 'Dim @0' is commonly thought of as the row of an array.

pattern Dim :: () => KnownNat n => SNat n Source #

Pattern synonym for a Dim

type Dims = SNats Source #

Representation of indexes into a shape (a type-level [Nat]). The indexes are dimensions of the shape.

pattern Dims :: () => KnownNats ns => SNats ns Source #

Pattern synonym for a Dims

Conversion

class Vector v a => FromVector t (v :: Type -> Type) a | t -> a where Source #

Conversion to and from a Vector

Note that conversion of an Array to a vector drops shape information, so that:

vectorAs . asVector == id
asVector . vectorAs == 'flat'
>>> asVector (range @Vec.Vector @[2,3]) :: Vec.Vector Int
[0,1,2,3,4,5]
vectorAs (VG.fromList [0..5]) :: Array Vec.Vector [2,3] Int
0,1,2,3,4,5

Methods

asVector :: t -> v a Source #

vectorAs :: v a -> t Source #

Instances

Instances details
Vector v a => FromVector [a] v a Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

asVector :: [a] -> v a Source #

vectorAs :: v a -> [a] Source #

Vector v a => FromVector (v a) v a Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

asVector :: v a -> v a Source #

vectorAs :: v a -> v a Source #

Vector v a => FromVector (Array v s a) v a Source # 
Instance details

Defined in Harpie.Fixed.Generic

Methods

asVector :: Array v s a -> v a Source #

vectorAs :: v a -> Array v s a Source #

toDynamic :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> Array v a Source #

Convert to a dynamic array with shape at the value level.

>>> toDynamic a
UnsafeArray [2,3,4] [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]

with :: forall (v :: Type -> Type) a r. Vector v a => Array v a -> (forall (s :: [Nat]). KnownNats s => Array v s a -> r) -> r Source #

Use a dynamic array in a fixed context.

>>> import Harpie.Array.Generic qualified as A
>>> with (A.range @Vec.Vector [2,3,4]) show
"[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]"

This doesn't work for anything more complex where KnownNats need to be type computed:

:t with (A.range [2,3,4]) (pretty . F.takes (Dims @'[0]) (S.SNats @'[1]))

... • Could not deduce ‘S.KnownNats (Fcf.Data.List.Drop_ 1 s)’ ...

Shape Access

shape :: forall (v :: Type -> Type) a (s :: [Nat]). (KnownNats s, Vector v a) => Array v s a -> Vector Int Source #

Get shape of an Array as a value.

>>> shape a
[2,3,4]

rank :: forall (v :: Type -> Type) a (s :: [Nat]). (KnownNats s, Vector v a) => Array v s a -> Int Source #

Get rank of an Array as a value.

>>> rank a
3

size :: forall (v :: Type -> Type) a (s :: [Nat]). (KnownNats s, Vector v a) => Array v s a -> Int Source #

Get size of an Array as a value.

>>> size a
24

length :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> Int Source #

Number of rows (first dimension size) in an Array. As a convention, a scalar value is still a single row.

>>> length a
2
>>> length (toScalar @Vec.Vector 0)
1

isNull :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> Bool Source #

Is the Array empty (has zero number of elements).

>>> isNull (array [] :: Array Vec.Vector [2,0] ())
True
>>> isNull (array [4] :: Array Vec.Vector '[] Int)
False

Indexing

index :: forall (v :: Type -> Type) (s :: [Nat]) a. (KnownNats s, Vector v a) => Array v s a -> Fins s -> a Source #

Index into an array using Fins.

unsafeIndex :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> [Int] -> a Source #

Extract an element at an index, unsafely.

>>> unsafeIndex a [1,2,3]
23

(!) :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> [Int] -> a infixl 9 Source #

Extract an element at an index, unsafely.

>>> a ! [1,2,3]
23

(!?) :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> [Int] -> Maybe a infixl 9 Source #

Extract an element at an index, safely.

>>> a !? [1,2,3]
Just 23
>>> a !? [2,3,1]
Nothing

tabulate :: forall (v :: Type -> Type) (s :: [Nat]) a. (KnownNats s, Vector v a) => (Fins s -> a) -> Array v s a Source #

Tabulate an array from a function on Fins.

unsafeTabulate :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => ([Int] -> a) -> Array v s a Source #

Tabulate unsafely.

>>> :t tabulate @Vec.Vector @[2,3] id
tabulate @Vec.Vector @[2,3] id
  :: Array Vec.Vector [2, 3] (Fins [2, 3])
>>> :t unsafeTabulate @[2,3] id :: Array Vec.Vector [2,3] [Int]
unsafeTabulate @[2,3] id :: Array Vec.Vector [2,3] [Int]
  :: Array Vec.Vector [2, 3] [Int]
>>> pretty (unsafeTabulate @[2,3] id :: Array Vec.Vector [2,3] [Int])
[[[0,0],[0,1],[0,2]],
 [[1,0],[1,1],[1,2]]]

backpermute :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', Vector v a) => (Fins s' -> Fins s) -> Array v s a -> Array v s' a Source #

backpermute is a tabulation where the contents of an array do not need to be accessed, and is thus a fulcrum for leveraging laziness and fusion via the rule:

backpermute f (backpermute f' a) == backpermute (f . f') a

Many functions in this module are examples of backpermute usage.

>>> pretty $ backpermute @Vec.Vector @[4,3,2] (UnsafeFins . List.reverse . fromFins) a
[[[0,12],
  [4,16],
  [8,20]],
 [[1,13],
  [5,17],
  [9,21]],
 [[2,14],
  [6,18],
  [10,22]],
 [[3,15],
  [7,19],
  [11,23]]]

unsafeBackpermute :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', Vector v a) => ([Int] -> [Int]) -> Array v s a -> Array v s' a Source #

Unsafe backpermute

>>> pretty $ unsafeBackpermute @Vec.Vector @[4,3,2] List.reverse a
[[[0,12],
  [4,16],
  [8,20]],
 [[1,13],
  [5,17],
  [9,21]],
 [[2,14],
  [6,18],
  [10,22]],
 [[3,15],
  [7,19],
  [11,23]]]

Scalars

fromScalar :: forall (v :: Type -> Type) a. Vector v a => Array v ('[] :: [Nat]) a -> a Source #

Unwrap a scalar.

>>> s = array @Vec.Vector @'[] @Int [3]
>>> :t fromScalar s
fromScalar s :: Int

toScalar :: forall (v :: Type -> Type) a. Vector v a => a -> Array v ('[] :: [Nat]) a Source #

Wrap a scalar.

>>> :t toScalar @Vec.Vector @Int 2
toScalar @Vec.Vector @Int 2 :: Array Vec.Vector '[] Int

isScalar :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Array v s a -> Bool Source #

Is an array a scalar?

>>> isScalar (toScalar @Vec.Vector (2::Int))
True

asSingleton :: forall (s :: [Nat]) (s' :: [Nat]) (v :: Type -> Type) a. (KnownNats s, KnownNats s', s' ~ Eval (AsSingleton s), Vector v a) => Array v s a -> Array v s' a Source #

Convert a scalar to being a dimensioned array. Do nothing if not a scalar.

>>> asSingleton (toScalar @Vec.Vector 4)
[4]

asScalar :: forall (s :: [Nat]) (s' :: [Nat]) (v :: Type -> Type) a. (KnownNats s, KnownNats s', s' ~ Eval (AsScalar s), Vector v a) => Array v s a -> Array v s' a Source #

Convert an array with shape [1] to being a scalar (Do nothing if not a shape [1] array).

>>> pretty (asScalar (singleton @Vec.Vector 3))
3

Array Creation

empty :: forall (v :: Type -> Type) a. Vector v a => Array v '[0] a Source #

An array with no elements.

>>> toDynamic (empty @Vec.Vector @Int)
UnsafeArray [0] []

range :: forall (v :: Type -> Type) (s :: [Nat]). (KnownNats s, Vector v Int) => Array v s Int Source #

An enumeration of row-major or lexicographic order.

>>> pretty (range :: Array Vec.Vector [2,3] Int)
[[0,1,2],
 [3,4,5]]

corange :: forall (v :: Type -> Type) (s :: [Nat]). (KnownNats s, Vector v Int) => Array v s Int Source #

An enumeration of col-major or colexicographic order.

>>> pretty (corange @Vec.Vector @[2,3,4])
[[[0,6,12,18],
  [2,8,14,20],
  [4,10,16,22]],
 [[1,7,13,19],
  [3,9,15,21],
  [5,11,17,23]]]

indices :: forall (s :: [Nat]) (v :: Type -> Type). (KnownNats s, Vector v [Int]) => Array v s [Int] Source #

Indices of an array shape.

>>> pretty (indices @[3,3] :: Array Vec.Vector [3,3] [Int])
[[[0,0],[0,1],[0,2]],
 [[1,0],[1,1],[1,2]],
 [[2,0],[2,1],[2,2]]]

ident :: forall (s :: [Nat]) a (v :: Type -> Type). (KnownNats s, Additive a, Multiplicative a, Vector v a) => Array v s a Source #

The identity array.

>>> pretty (ident @[3,3] :: Array Vec.Vector [3,3] Int)
[[1,0,0],
 [0,1,0],
 [0,0,1]]

konst :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => a -> Array v s a Source #

Create an array composed of a single value.

>>> pretty (konst @[3,2] 1 :: Array Vec.Vector [3,2] Int)
[[1,1],
 [1,1],
 [1,1]]

singleton :: forall (v :: Type -> Type) a. Vector v a => a -> Array v '[1] a Source #

Create an array of shape [1].

>>> pretty $ singleton @Vec.Vector 1
[1]

diag :: forall (v :: Type -> Type) (s' :: [Nat]) a (s :: [Nat]). (KnownNats s, KnownNats s', s' ~ Eval (MinDim s), Vector v a) => Array v s a -> Array v s' a Source #

Extract the diagonal of an array.

>>> pretty $ diag (ident @[3,3] :: Array Vec.Vector [3,3] Int)
[1,1,1]

undiag :: forall (v :: Type -> Type) (s' :: [Nat]) a (s :: [Nat]). (KnownNats s, KnownNats s', s' ~ Eval (s ++ s), Additive a, Vector v a) => Array v s a -> Array v s' a Source #

Expand an array to form a diagonal array

>>> pretty $ undiag (range @Vec.Vector @'[3])
[[0,0,0],
 [0,1,0],
 [0,0,2]]

Vector-level helpers

fmapA :: forall (v :: Type -> Type) (s :: [Nat]) a b. (KnownNats s, Vector v a, Vector v b) => (a -> b) -> Array v s a -> Array v s b Source #

sumA :: forall (v :: Type -> Type) (s :: [Nat]) a. (Additive a, Vector v a) => Array v s a -> a Source #

traverseA :: forall f (v :: Type -> Type) (s :: [Nat]) a b. (Applicative f, KnownNats s, Vector v a, Vector v b, Vector v (f b)) => (a -> f b) -> Array v s a -> f (Array v s b) Source #

Element-level functions

zipWith :: forall (s :: [Nat]) (v :: Type -> Type) a b c. (KnownNats s, Vector v a, Vector v b, Vector v c) => (a -> b -> c) -> Array v s a -> Array v s b -> Array v s c Source #

Zip two arrays at an element level.

>>> zipWith (-) v v
[0,0,0]

modify :: forall (s :: [Nat]) (v :: Type -> Type) a. (KnownNats s, Vector v a) => Fins s -> (a -> a) -> Array v s a -> Array v s a Source #

Modify a single value at an index.

>>> pretty $ modify (S.UnsafeFins [0,0]) (const 100) (range @Vec.Vector @[3,2])
[[100,1],
 [2,3],
 [4,5]]

imap :: forall (s :: [Nat]) (v :: Type -> Type) a b. (KnownNats s, Vector v a, Vector v b, Vector v [Int]) => ([Int] -> a -> b) -> Array v s a -> Array v s b Source #

Maps an index function at element-level.

>>> pretty $ imap (\xs x -> x - sum xs) a
[[[0,0,0,0],
  [3,3,3,3],
  [6,6,6,6]],
 [[11,11,11,11],
  [14,14,14,14],
  [17,17,17,17]]]

Function generalisers

rowWise :: forall (v :: Type -> Type) a (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) (xs :: [Nat]) proxy. (KnownNats s, KnownNats ds, ds ~ Eval (DimsOf xs), Vector v a) => (Dims ds -> proxy xs -> Array v s a -> Array v s' a) -> proxy xs -> Array v s a -> Array v s' a Source #

With a function that takes dimensions and (type-level) parameters, apply the parameters to the initial dimensions. ie

rowWise f xs = f [0..rank xs - 1] xs
>>> toDynamic $ rowWise indexesT (S.SNats @[1,0]) a
UnsafeArray [4] [12,13,14,15]

colWise :: forall (v :: Type -> Type) a (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) (xs :: [Nat]) proxy. (KnownNats s, KnownNats ds, ds ~ Eval (EndDimsOf xs s), Vector v a) => (Dims ds -> proxy xs -> Array v s a -> Array v s' a) -> proxy xs -> Array v s a -> Array v s' a Source #

With a function that takes dimensions and (type-level) parameters, apply the parameters to the the last dimensions. ie

colWise f xs = f (List.reverse [0 .. (rank a - 1)]) xs
>>> toDynamic $ colWise indexesT (S.SNats @[1,0]) a
UnsafeArray [2] [1,13]

Single-dimension functions

take :: forall (v :: Type -> Type) (d :: Nat) (t :: Nat) (s :: [Nat]) (s' :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (TakeDim d t s), Vector v a) => Dim d -> SNat t -> Array v s a -> Array v s' a Source #

Take the top-most elements across the specified dimension.

>>> pretty $ take (Dim @2) (SNat @1) a
[[[0],
  [4],
  [8]],
 [[12],
  [16],
  [20]]]

takeB :: forall (v :: Type -> Type) (s :: [Nat]) (s' :: [Nat]) a (d :: Nat) (t :: Nat). (KnownNats s, KnownNats s', s' ~ Eval (TakeDim d t s), Vector v a) => Dim d -> SNat t -> Array v s a -> Array v s' a Source #

Take the bottom-most elements across the specified dimension.

>>> pretty $ takeB (Dim @2) (SNat @1) a
[[[3],
  [7],
  [11]],
 [[15],
  [19],
  [23]]]

drop :: forall (v :: Type -> Type) (s :: [Nat]) (s' :: [Nat]) a (d :: Nat) (t :: Nat). (KnownNats s, KnownNats s', Eval (DropDim d t s) ~ s', Vector v a) => Dim d -> SNat t -> Array v s a -> Array v s' a Source #

Drop the top-most elements across the specified dimension.

>>> pretty $ drop (Dim @2) (SNat @1) a
[[[1,2,3],
  [5,6,7],
  [9,10,11]],
 [[13,14,15],
  [17,18,19],
  [21,22,23]]]

dropB :: forall (v :: Type -> Type) (s :: [Nat]) (s' :: [Nat]) a (d :: Nat) (t :: Nat). (KnownNats s, KnownNats s', Eval (DropDim d t s) ~ s', Vector v a) => Dim d -> SNat t -> Array v s a -> Array v s' a Source #

Drop the bottom-most elements across the specified dimension.

>>> pretty $ dropB (Dim @2) (SNat @1) a
[[[0,1,2],
  [4,5,6],
  [8,9,10]],
 [[12,13,14],
  [16,17,18],
  [20,21,22]]]

select :: forall (v :: Type -> Type) (d :: Nat) a (p :: Nat) (s :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats s', s' ~ Eval (DeleteDim d s), p ~ Eval (GetDim d s), Vector v a) => Dim d -> Fin p -> Array v s a -> Array v s' a Source #

Select an index along a dimension.

>>> let s = select (Dim @2) (S.fin @4 3) a
>>> pretty s
[[3,7,11],
 [15,19,23]]

insert :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (si :: [Nat]) (d :: Nat) (p :: Nat) a. (KnownNats s, KnownNats si, KnownNats s', s' ~ Eval (IncAt d s), p ~ Eval (GetDim d s), 'True ~ Eval (InsertOk d s si), Vector v a) => Dim d -> Fin p -> Array v s a -> Array v si a -> Array v s' a Source #

Insert along a dimension at a position.

>>> pretty $ insert (Dim @2) (UnsafeFin 0) a (konst @[2,3] 0 :: Array Vec.Vector [2,3] Int)
[[[0,0,1,2,3],
  [0,4,5,6,7],
  [0,8,9,10,11]],
 [[0,12,13,14,15],
  [0,16,17,18,19],
  [0,20,21,22,23]]]
>>> toDynamic $ insert (Dim @0) (UnsafeFin 0) (toScalar @Vec.Vector 1) (toScalar @Vec.Vector 2)
UnsafeArray [2] [2,1]

delete :: forall (v :: Type -> Type) (d :: Nat) (s :: [Nat]) (s' :: [Nat]) (p :: Natural) a. (KnownNats s, KnownNats s', s' ~ Eval (DecAt d s), p ~ (1 + Eval (GetDim d s)), Vector v a) => Dim d -> Fin p -> Array v s a -> Array v s' a Source #

Delete along a dimension at a position.

>>> pretty $ delete (Dim @2) (UnsafeFin 3) a
[[[0,1,2],
  [4,5,6],
  [8,9,10]],
 [[12,13,14],
  [16,17,18],
  [20,21,22]]]

append :: forall (v :: Type -> Type) a (d :: Nat) (s :: [Nat]) (si :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats si, KnownNats s', s' ~ Eval (IncAt d s), 'True ~ Eval (InsertOk d s si), Vector v a) => Dim d -> Array v s a -> Array v si a -> Array v s' a Source #

Insert along a dimension at the end.

>>> pretty $ append (Dim @2) a (konst @[2,3] 0 :: Array Vec.Vector [2,3] Int)
[[[0,1,2,3,0],
  [4,5,6,7,0],
  [8,9,10,11,0]],
 [[12,13,14,15,0],
  [16,17,18,19,0],
  [20,21,22,23,0]]]

prepend :: forall (v :: Type -> Type) a (d :: Nat) (s :: [Nat]) (si :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats si, KnownNats s', s' ~ Eval (IncAt d s), 'True ~ Eval (InsertOk d s si), Vector v a) => Dim d -> Array v si a -> Array v s a -> Array v s' a Source #

Insert along a dimension at the beginning.

>>> pretty $ prepend (Dim @2) (konst @[2,3] 0 :: Array Vec.Vector [2,3] Int) a
[[[0,0,1,2,3],
  [0,4,5,6,7],
  [0,8,9,10,11]],
 [[0,12,13,14,15],
  [0,16,17,18,19],
  [0,20,21,22,23]]]

concatenate :: forall (v :: Type -> Type) a (s0 :: [Nat]) (s1 :: [Nat]) (d :: Nat) (s :: [Nat]). (KnownNats s0, KnownNats s1, KnownNats s, Eval (Concatenate d s0 s1) ~ s, Vector v a) => Dim d -> Array v s0 a -> Array v s1 a -> Array v s a Source #

Concatenate along a dimension.

>>> shape $ concatenate (Dim @1) a a
[2,6,4]
>>> toDynamic $ concatenate (Dim @0) (toScalar @Vec.Vector 1) (toScalar @Vec.Vector 2)
UnsafeArray [2] [1,2]
>>> toDynamic $ concatenate (Dim @0) (array @Vec.Vector @'[1] [0]) (array @Vec.Vector @'[3] [1..3])
UnsafeArray [4] [0,1,2,3]

couple :: forall (v :: Type -> Type) (d :: Nat) a (s :: [Nat]) (s' :: [Nat]) (se :: [Nat]). (KnownNat d, KnownNats s, KnownNats s', KnownNats se, s' ~ Eval (Concatenate d se se), se ~ Eval (InsertDim d 1 s), Vector v a) => Dim d -> Array v s a -> Array v s a -> Array v s' a Source #

Combine two arrays as a new dimension of a new array.

>>> pretty $ couple (Dim @0) (array @Vec.Vector @'[3] [1,2,3]) (array @Vec.Vector @'[3] @Int [4,5,6])
[[1,2,3],
 [4,5,6]]
>>> couple (Dim @0) (toScalar @Vec.Vector @Int 0) (toScalar @Vec.Vector 1)
[0,1]

slice :: forall (v :: Type -> Type) a (d :: Nat) (off :: Nat) (l :: Nat) (s :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats s', s' ~ Eval (SetDim d l s), Eval (SliceOk d off l s) ~ 'True, Vector v a) => Dim d -> SNat off -> SNat l -> Array v s a -> Array v s' a Source #

Slice along a dimension with the supplied offset & length.

>>> pretty $ slice (Dim @2) (SNat @1) (SNat @2) a
[[[1,2],
  [5,6],
  [9,10]],
 [[13,14],
  [17,18],
  [21,22]]]

rotate :: forall (v :: Type -> Type) (d :: Nat) (s :: [Nat]) a. (KnownNats s, Vector v a) => Dim d -> Int -> Array v s a -> Array v s a Source #

Rotate an array along a dimension.

>>> pretty $ rotate (Dim @1) 2 a
[[[8,9,10,11],
  [0,1,2,3],
  [4,5,6,7]],
 [[20,21,22,23],
  [12,13,14,15],
  [16,17,18,19]]]

Multi-dimension functions

takes :: forall (v :: Type -> Type) (ds :: [Nat]) (xs :: [Nat]) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (SetDims ds xs s), Vector v a) => Dims ds -> SNats xs -> Array v s a -> Array v s' a Source #

Across the specified dimensions, takes the top-most elements.

>>> pretty $ takes (Dims @[0,1]) (S.SNats @[1,2]) a
[[[0,1,2,3],
  [4,5,6,7]]]

takeBs :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a (ds :: [Nat]) (xs :: [Nat]). (KnownNats s, KnownNats s', KnownNats ds, KnownNats xs, s' ~ Eval (SetDims ds xs s), Vector v a) => Dims ds -> SNats xs -> Array v s a -> Array v s' a Source #

Across the specified dimensions, takes the bottom-most elements.

>>> pretty (takeBs (Dims @[0,1]) (S.SNats @[1,2]) a)
[[[16,17,18,19],
  [20,21,22,23]]]

drops :: forall (v :: Type -> Type) (ds :: [Nat]) (xs :: [Nat]) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', KnownNats ds, KnownNats xs, s' ~ Eval (DropDims ds xs s), Vector v a) => Dims ds -> SNats xs -> Array v s a -> Array v s' a Source #

Across the specified dimensions, drops the top-most elements.

>>> pretty $ drops (Dims @[0,2]) (S.SNats @[1,3]) a
[[[15],
  [19],
  [23]]]

dropBs :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (ds :: [Nat]) (xs :: [Nat]) a. (KnownNats s, KnownNats s', KnownNats ds, KnownNats xs, s' ~ Eval (DropDims ds xs s), Vector v a) => Dims ds -> SNats xs -> Array v s a -> Array v s' a Source #

Across the specified dimensions, drops the bottom-most elements.

>>> pretty $ dropBs (Dims @[0,2]) (S.SNats @[1,3]) a
[[[0],
  [4],
  [8]]]

indexes :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (ds :: [Nat]) (xs :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (DeleteDims ds s), xs ~ Eval (GetDims ds s), Vector v a) => Dims ds -> Fins xs -> Array v s a -> Array v s' a Source #

Select by dimensions and indexes.

>>> pretty $ indexes (Dims @[0,1]) (S.UnsafeFins [1,1]) a
[16,17,18,19]
>>> pretty $ indexes (Dims @'[1]) (S.fins @'[3] [1]) (range @Vec.Vector @[2,3])
[1,4]

indexesT :: forall (v :: Type -> Type) (ds :: [Nat]) (xs :: [Nat]) (s :: [Nat]) (s' :: [Nat]) a. (KnownNats s, KnownNats ds, KnownNats xs, KnownNats s', s' ~ Eval (DeleteDims ds s), 'True ~ Eval (IsFins xs =<< GetDims ds s), Vector v a) => Dims ds -> SNats xs -> Array v s a -> Array v s' a Source #

Select by dimensions and indexes, supplying indexes as a type.

>>> pretty $ indexesT (Dims @[0,1]) (S.SNats @[1,1]) a
[16,17,18,19]

slices :: forall (v :: Type -> Type) a (ds :: [Nat]) (ls :: [Nat]) (offs :: [Nat]) (s :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats s', KnownNats ds, KnownNats ls, KnownNats offs, Eval (SlicesOk ds offs ls s) ~ 'True, Eval (SetDims ds ls s) ~ s', Vector v a) => Dims ds -> SNats offs -> SNats ls -> Array v s a -> Array v s' a Source #

Slice along dimensions with the supplied offsets and lengths.

>>> pretty $ slices (Dims @'[2]) (S.SNats @'[1]) (S.SNats @'[2]) a
[[[1,2],
  [5,6],
  [9,10]],
 [[13,14],
  [17,18],
  [21,22]]]

heads :: forall (v :: Type -> Type) a (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats s', KnownNats ds, s' ~ Eval (DeleteDims ds s), Vector v a) => Dims ds -> Array v s a -> Array v s' a Source #

Select the first element along the supplied dimensions.

>>> pretty $ heads (Dims @[0,2]) a
[0,4,8]

lasts :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) a. (KnownNats s, KnownNats ds, KnownNats s', s' ~ Eval (DeleteDims ds s), Vector v a) => Dims ds -> Array v s a -> Array v s' a Source #

Select the last element along the supplied dimensions.

>>> pretty $ lasts (Dims @[0,2]) a
[15,19,23]

tails :: forall (v :: Type -> Type) (ds :: [Nat]) (os :: [Nat]) (s :: [Nat]) (s' :: [Nat]) a (ls :: [Nat]). (KnownNats s, KnownNats ds, KnownNats s', KnownNats ls, KnownNats os, Eval (SlicesOk ds os ls s) ~ 'True, os ~ Eval (Replicate (Eval (Rank ds)) 1), ls ~ Eval (GetLastPositions ds s), s' ~ Eval (SetDims ds ls s), Vector v a) => Dims ds -> Array v s a -> Array v s' a Source #

Select the tail elements along the supplied dimensions.

>>> pretty $ tails (Dims @[0,2]) a
[[[13,14,15],
  [17,18,19],
  [21,22,23]]]

inits :: forall (v :: Type -> Type) (ds :: [Nat]) (os :: [Nat]) (s :: [Nat]) (s' :: [Nat]) a (ls :: [Nat]). (KnownNats s, KnownNats ds, KnownNats s', KnownNats ls, KnownNats os, Eval (SlicesOk ds os ls s) ~ 'True, os ~ Eval (Replicate (Eval (Rank ds)) 0), ls ~ Eval (GetLastPositions ds s), s' ~ Eval (SetDims ds ls s), Vector v a) => Dims ds -> Array v s a -> Array v s' a Source #

Select the init elements along the supplied dimensions.

>>> pretty $ inits (Dims @[0,2]) a
[[[0,1,2],
  [4,5,6],
  [8,9,10]]]

Function application

extracts :: forall (v :: Type -> Type) (ds :: [Nat]) (st :: [Nat]) (si :: [Nat]) (so :: [Nat]) a. (KnownNats st, KnownNats ds, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds st), so ~ Eval (GetDims ds st), Vector v a, Vector v (Array v si a)) => Dims ds -> Array v st a -> Array v so (Array v si a) Source #

Extracts specified dimensions to an outer layer.

>>> :t extracts (Dims @'[0]) (range @Vec.Vector @[2,3,4])
extracts (Dims @'[0]) (range @Vec.Vector @[2,3,4])
  :: Array Vec.Vector '[2] (Array Vec.Vector [3, 4] Int)

reduces :: forall (v :: Type -> Type) (ds :: [Nat]) (st :: [Nat]) (si :: [Nat]) (so :: [Nat]) a b. (KnownNats st, KnownNats ds, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds st), so ~ Eval (GetDims ds st), Vector v a, Vector v b, Vector v (Array v si a)) => Dims ds -> (Array v si a -> b) -> Array v st a -> Array v so b Source #

Reduce along specified dimensions, using the supplied fold.

>>> pretty $ reduces (Dims @'[0]) sum a
[66,210]
>>> pretty $ reduces (Dims @[0,2]) sum a
[[12,15,18,21],
 [48,51,54,57]]

joins :: forall (v :: Type -> Type) a (ds :: [Nat]) (si :: [Nat]) (so :: [Nat]) (st :: [Nat]). (KnownNats ds, KnownNats st, KnownNats si, KnownNats so, Eval (InsertDims ds so si) ~ st, Vector v (Array v si a), Vector v a) => Dims ds -> Array v so (Array v si a) -> Array v st a Source #

Join inner and outer dimension layers by supplied dimensions.

>>> let e = extracts (Dims @[1,0]) a
>>> let j = joins (Dims @[1,0]) e
>>> a == j
True

join :: forall (v :: Type -> Type) a (si :: [Nat]) (so :: [Nat]) (st :: [Nat]) (ds :: [Nat]). (KnownNats st, KnownNats si, KnownNats so, KnownNats ds, ds ~ Eval (DimsOf so), st ~ Eval (InsertDims ds so si), Vector v (Array v si a), Vector v a) => Array v so (Array v si a) -> Array v st a Source #

Join inner and outer dimension layers in outer dimension order.

>>> a == join (extracts (Dims @[0,1]) a)
True

traverses :: forall f (s :: [Nat]) (si :: [Nat]) (so :: [Nat]) (ds :: [Nat]) (v :: Type -> Type) a b. (Applicative f, KnownNats s, KnownNats si, KnownNats so, si ~ Eval (GetDims ds s), so ~ Eval (DeleteDims ds s), s ~ Eval (InsertDims ds si so), Vector v a, Vector v b, Vector v (Array v so a), Vector v (Array v so b), Vector v (f b), Vector v (f (Array v so b))) => Dims ds -> (a -> f b) -> Array v s a -> f (Array v s b) Source #

Traverse along specified dimensions.

>>> traverses (Dims @'[1]) print (range @Vec.Vector @[2,3])
0
3
1
4
2
5
[(),(),(),(),(),()]

maps :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) (si :: [Nat]) (si' :: [Nat]) (so :: [Nat]) a b. (KnownNats s, KnownNats s', KnownNats si, KnownNats si', KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s' ~ Eval (InsertDims ds so si'), s ~ Eval (InsertDims ds so si), Vector v a, Vector v b, Vector v (Array v si a), Vector v (Array v si' b)) => Dims ds -> (Array v si a -> Array v si' b) -> Array v s a -> Array v s' b Source #

Maps a function along specified dimensions.

>>> pretty $ maps (Dims @'[1]) transpose a
[[[0,12],
  [4,16],
  [8,20]],
 [[1,13],
  [5,17],
  [9,21]],
 [[2,14],
  [6,18],
  [10,22]],
 [[3,15],
  [7,19],
  [11,23]]]

filters :: forall (v :: Type -> Type) (ds :: [Nat]) (si :: [Nat]) (so :: [Nat]) a. (KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds so), KnownNats (Eval (GetDims ds so)), Vector v a, Vector v (Array v si a)) => Dims ds -> (Array v si a -> Bool) -> Array v so a -> Array v (Array v si a) Source #

Filters along specified dimensions (which are flattened as a dynamic array).

>>> pretty $ filters (Dims @[0,1]) (any ((==0) . (`mod` 7))) a
[[0,1,2,3],[4,5,6,7],[12,13,14,15],[20,21,22,23]]

zips :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) (si :: [Nat]) (si' :: [Nat]) (so :: [Nat]) a b c. (KnownNats s, KnownNats s', KnownNats si, KnownNats si', KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s' ~ Eval (InsertDims ds so si'), s ~ Eval (InsertDims ds so si), Vector v a, Vector v b, Vector v c, Vector v (Array v si a), Vector v (Array v si b), Vector v (Array v si' c)) => Dims ds -> (Array v si a -> Array v si b -> Array v si' c) -> Array v s a -> Array v s b -> Array v s' c Source #

Zips two arrays with a function along specified dimensions.

>>> pretty $ zips (Dims @[0,1]) (zipWith (,)) a (reverses (Dims @'[0]) a)
[[[(0,12),(1,13),(2,14),(3,15)],
  [(4,16),(5,17),(6,18),(7,19)],
  [(8,20),(9,21),(10,22),(11,23)]],
 [[(12,0),(13,1),(14,2),(15,3)],
  [(16,4),(17,5),(18,6),(19,7)],
  [(20,8),(21,9),(22,10),(23,11)]]]

modifies :: forall (v :: Type -> Type) a (si :: [Nat]) (s :: [Nat]) (ds :: [Nat]) (so :: [Nat]). (KnownNats s, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s ~ Eval (InsertDims ds so si), Vector v a, Vector v (Array v si a)) => (Array v si a -> Array v si a) -> Dims ds -> Fins so -> Array v s a -> Array v s a Source #

Modify using the supplied function along dimensions and positions.

>>> pretty $ modifies (fmap (100+)) (Dims @'[2]) (S.UnsafeFins [0]) a
[[[100,1,2,3],
  [104,5,6,7],
  [108,9,10,11]],
 [[112,13,14,15],
  [116,17,18,19],
  [120,21,22,23]]]

diffs :: forall (v :: Type -> Type) a b (ds :: [Nat]) (ls :: [Nat]) (si :: [Nat]) (si' :: [Nat]) (st :: [Nat]) (st' :: [Nat]) (so :: [Nat]) (postDrop :: [Nat]). (KnownNats ls, KnownNats si, KnownNats si', KnownNats st, KnownNats st', KnownNats so, KnownNats postDrop, si ~ Eval (DeleteDims ds postDrop), so ~ Eval (GetDims ds postDrop), st' ~ Eval (InsertDims ds so si'), postDrop ~ Eval (InsertDims ds so si), postDrop ~ Eval (DropDims ds ls st), Vector v a, Vector v b, Vector v (Array v si a), Vector v (Array v si' b)) => Dims ds -> SNats ls -> (Array v si a -> Array v si a -> Array v si' b) -> Array v st a -> Array v st' b Source #

Apply a binary function between successive slices, across dimensions and lags.

>>> pretty $ diffs (Dims @'[1]) (S.SNats @'[1]) (zipWith (-)) a
[[[4,4,4,4],
  [4,4,4,4]],
 [[4,4,4,4],
  [4,4,4,4]]]

Array expansion & contraction

expand :: forall (v :: Type -> Type) (sc :: [Nat]) (sa :: [Nat]) (sb :: [Nat]) a b c. (KnownNats sa, KnownNats sb, KnownNats sc, sc ~ Eval (sa ++ sb), Vector v a, Vector v b, Vector v c) => (a -> b -> c) -> Array v sa a -> Array v sb b -> Array v sc c Source #

Product two arrays using the supplied binary function.

For context, if the function is multiply, and the arrays are tensors, then this can be interpreted as a tensor product. The concept of a tensor product is a dense crossroad, and a complete treatment is elsewhere. To quote the wiki article:

... the tensor product can be extended to other categories of mathematical objects in addition to vector spaces, such as to matrices, tensors, algebras, topological vector spaces, and modules. In each such case the tensor product is characterized by a similar universal property: it is the freest bilinear operation. The general concept of a "tensor product" is captured by monoidal categories; that is, the class of all things that have a tensor product is a monoidal category.

>>> x = array [1,2,3] :: Array Vec.Vector '[3] Int
>>> pretty $ expand (*) x x
[[1,2,3],
 [2,4,6],
 [3,6,9]]

Alternatively, expand can be understood as representing the permutation of element pairs of two arrays, so like the Applicative List instance.

>>> i2 = indices @[2,2] :: Array Vec.Vector [2,2] [Int]
>>> pretty $ expand (,) i2 i2
[[[[([0,0],[0,0]),([0,0],[0,1])],
   [([0,0],[1,0]),([0,0],[1,1])]],
  [[([0,1],[0,0]),([0,1],[0,1])],
   [([0,1],[1,0]),([0,1],[1,1])]]],
 [[[([1,0],[0,0]),([1,0],[0,1])],
   [([1,0],[1,0]),([1,0],[1,1])]],
  [[([1,1],[0,0]),([1,1],[0,1])],
   [([1,1],[1,0]),([1,1],[1,1])]]]]

coexpand :: forall (v :: Type -> Type) (sc :: [Nat]) (sa :: [Nat]) (sb :: [Nat]) a b c. (KnownNats sa, KnownNats sb, KnownNats sc, sc ~ Eval (sb ++ sa), Vector v a, Vector v b, Vector v c) => (a -> b -> c) -> Array v sa a -> Array v sb b -> Array v sc c Source #

Like expand, but permutes the first array first, rather than the second.

>>> pretty $ expand (,) v (fmap (+3) v)
[[(0,3),(0,4),(0,5)],
 [(1,3),(1,4),(1,5)],
 [(2,3),(2,4),(2,5)]]
>>> pretty $ coexpand (,) v (fmap (+3) v)
[[(0,3),(1,3),(2,3)],
 [(0,4),(1,4),(2,4)],
 [(0,5),(1,5),(2,5)]]

contract :: forall (v :: Type -> Type) a b (s :: [Nat]) (ss :: [Nat]) (se :: [Nat]) (s' :: [Nat]) (ds :: [Nat]) (ds' :: [Nat]). (KnownNats se, se ~ Eval (DeleteDims ds' s), KnownNats ds', KnownNats s, KnownNats ss, KnownNats s', s' ~ Eval (GetDims ds' s), ss ~ Eval (MinDim se), ds' ~ Eval (ExceptDims ds s), Vector v a, Vector v b, Vector v (Array v se a)) => Dims ds -> (Array v ss a -> b) -> Array v s a -> Array v s' b Source #

Contract an array by applying the supplied (folding) function on diagonal elements of the dimensions.

This generalises a tensor contraction by allowing the number of contracting diagonals to be other than 2.

>>> pretty $ contract (Dims @[1,2]) sum (expand (*) m (transpose m))
[[5,14],
 [14,50]]

prod :: forall (v :: Type -> Type) a b c d (s0 :: [Nat]) (s1 :: [Nat]) (so0 :: [Nat]) (so1 :: [Nat]) (si :: [Nat]) (st :: [Nat]) (ds0 :: [Nat]) (ds1 :: [Nat]). (KnownNats so0, KnownNats so1, KnownNats si, KnownNats s0, KnownNats s1, KnownNats st, KnownNats ds0, KnownNats ds1, so0 ~ Eval (DeleteDims ds0 s0), so1 ~ Eval (DeleteDims ds1 s1), si ~ Eval (GetDims ds0 s0), si ~ Eval (GetDims ds1 s1), st ~ Eval (so0 ++ so1), Vector v c, Vector v a, Vector v b, Vector v d) => Dims ds0 -> Dims ds1 -> (Array v si c -> d) -> (a -> b -> c) -> Array v s0 a -> Array v s1 b -> Array v st d Source #

Expand two arrays and then contract the result using the supplied matching dimensions.

>>> pretty $ prod (Dims @'[1]) (Dims @'[0]) sum (*) (range @Vec.Vector @[2,3]) (range @Vec.Vector @[3,2])
[[10,13],
 [28,40]]

With full laziness, this computation would be equivalent to:

f . diag <$> extracts (Dims @ds') (expand g a b)

dot :: forall (v :: Type -> Type) a b c d (ds0 :: [Nat]) (ds1 :: [Nat]) (s0 :: [Nat]) (s1 :: [Nat]) (so0 :: [Nat]) (so1 :: [Nat]) (st :: [Nat]) (si :: [Nat]). (KnownNats s0, KnownNats s1, KnownNats ds0, KnownNats ds1, KnownNats so0, KnownNats so1, KnownNats st, KnownNats si, so0 ~ Eval (DeleteDims ds0 s0), so1 ~ Eval (DeleteDims ds1 s1), si ~ Eval (GetDims ds0 s0), si ~ Eval (GetDims ds1 s1), st ~ Eval (so0 ++ so1), ds0 ~ '[Eval (Eval (Rank s0) - 1)], ds1 ~ '[0], Vector v c, Vector v a, Vector v b, Vector v d) => (Array v si c -> d) -> (a -> b -> c) -> Array v s0 a -> Array v s1 b -> Array v st d Source #

A generalisation of a dot operation, which is a multiplicative expansion of two arrays and sum contraction along the middle two dimensions.

matrix multiplication

>>> pretty $ dot sum (*) m (transpose m)
[[5,14],
 [14,50]]

inner product

>>> pretty $ dot sum (*) v v
5

matrix-vector multiplication Note that an Array with shape [3] is neither a row vector nor column vector.

>>> pretty $ dot sum (*) v (transpose m)
[5,14]
>>> pretty $ dot sum (*) m v
[5,14]

mult :: forall (v :: Type -> Type) a (ds0 :: [Nat]) (ds1 :: [Nat]) (s0 :: [Nat]) (s1 :: [Nat]) (so0 :: [Nat]) (so1 :: [Nat]) (st :: [Nat]) (si :: [Nat]). (Additive a, Multiplicative a, KnownNats s0, KnownNats s1, KnownNats ds0, KnownNats ds1, KnownNats so0, KnownNats so1, KnownNats st, KnownNats si, so0 ~ Eval (DeleteDims ds0 s0), so1 ~ Eval (DeleteDims ds1 s1), si ~ Eval (GetDims ds0 s0), si ~ Eval (GetDims ds1 s1), st ~ Eval (so0 ++ so1), ds0 ~ '[Eval (Eval (Rank s0) - 1)], ds1 ~ '[0], Vector v a) => Array v s0 a -> Array v s1 a -> Array v st a Source #

Array multiplication.

matrix multiplication

>>> pretty $ mult m (transpose m)
[[5,14],
 [14,50]]

inner product

>>> pretty $ mult v v
5

matrix-vector multiplication

>>> pretty $ mult v (transpose m)
[5,14]
>>> pretty $ mult m v
[5,14]

windows :: forall (v :: Type -> Type) (w :: [Nat]) (s :: [Nat]) (ws :: [Nat]) a. (KnownNats s, KnownNats ws, ws ~ Eval (ExpandWindows w s), Vector v a) => SNats w -> Array v s a -> Array v ws a Source #

windows xs are xs-sized windows of an array

>>> shape $ windows (Dims @[2,2]) (range @Vec.Vector @[4,3,2])
[3,2,2,2,2]

Search

find :: forall (v :: Type -> Type) (s' :: [Nat]) (si :: [Nat]) (s :: [Nat]) a (r :: Nat) (i' :: [Nat]) (re :: [Nat]) (ws :: [Nat]). (Eq a, KnownNats si, KnownNats s, KnownNats s', KnownNats re, KnownNats i', KnownNat r, KnownNats ws, ws ~ Eval (ExpandWindows i' s), r ~ Eval (Rank s), i' ~ Eval (Rerank r si), re ~ Eval (DimWindows ws s), i' ~ Eval (DeleteDims re ws), s' ~ Eval (GetDims re ws), Vector v a, Vector v Bool, Eq (v a), Vector v (Array v i' a)) => Array v si a -> Array v s a -> Array v s' Bool Source #

Find the starting positions of occurences of one array in another.

>>> a = cycle @Vec.Vector @[4,4] (range @Vec.Vector @'[3])
>>> i = array @Vec.Vector @[2,2] [1,2,2,0]
>>> pretty $ find i a
[[False,True,False],
 [True,False,False],
 [False,False,True]]

findNoOverlap :: forall (v :: Type -> Type) (s' :: [Nat]) (si :: [Nat]) (s :: [Nat]) a (r :: Nat) (i' :: [Nat]) (re :: [Nat]) (ws :: [Nat]). (Eq a, KnownNats si, KnownNats s, KnownNats s', KnownNats re, KnownNats i', KnownNat r, KnownNats ws, ws ~ Eval (ExpandWindows i' s), r ~ Eval (Rank s), i' ~ Eval (Rerank r si), re ~ Eval (DimWindows ws s), i' ~ Eval (DeleteDims re ws), s' ~ Eval (GetDims re ws), Vector v a, Vector v Bool, Eq (v a), Vector v (Array v i' a), Vector v [Int]) => Array v si a -> Array v s a -> Array v s' Bool Source #

Find the ending positions of one array in another except where the array overlaps with another copy.

>>> a = konst @[5,5] 1 :: Array Vec.Vector [5,5] Int
>>> i = konst @[2,2] 1 :: Array Vec.Vector [2,2] Int
>>> pretty $ findNoOverlap i a
[[True,False,True,False],
 [False,False,False,False],
 [True,False,True,False],
 [False,False,False,False]]

isPrefixOf :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (r :: Nat) a. (Eq a, KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), 'True ~ Eval (IsSubset s' s), r ~ Eval (Rank s'), Vector v a, Eq (v a)) => Array v s' a -> Array v s a -> Bool Source #

Check if the first array is a prefix of the second.

>>> isPrefixOf (array @Vec.Vector @[2,2] [0,1,4,5]) a
True

isSuffixOf :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (r :: Nat) a. (Eq a, KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), r ~ Eval (Rank s'), 'True ~ Eval (IsSubset s' s), Vector v a, Eq (v a)) => Array v s' a -> Array v s a -> Bool Source #

Check if the first array is a suffix of the second.

>>> isSuffixOf (array @Vec.Vector @[2,2] [18,19,22,23]) a
True

isInfixOf :: forall (v :: Type -> Type) (s' :: [Nat]) (si :: [Nat]) (s :: [Nat]) a (r :: Nat) (i' :: [Nat]) (re :: [Nat]) (ws :: [Nat]). (Eq a, KnownNats si, KnownNats s, KnownNats s', KnownNats re, KnownNats i', KnownNat r, KnownNats ws, ws ~ Eval (ExpandWindows i' s), r ~ Eval (Rank s), i' ~ Eval (Rerank r si), re ~ Eval (DimWindows ws s), i' ~ Eval (DeleteDims re ws), s' ~ Eval (GetDims re ws), Vector v a, Vector v Bool, Eq (v a), Vector v (Array v i' a)) => Array v si a -> Array v s a -> Bool Source #

Check if the first array is an infix of the second.

>>> isInfixOf (array @Vec.Vector @[2,2] [18,19,22,23]) a
True

Shape manipulations

fill :: forall (v :: Type -> Type) (s' :: [Nat]) a (s :: [Nat]). (KnownNats s, KnownNats s', Vector v a, Semigroup (v a)) => a -> Array v s a -> Array v s' a Source #

Fill an array with the supplied value without regard to the original shape or cut the array values to match array size.

validate (def x a) == True
>>> pretty $ fill @Vec.Vector @'[3] 0 (array @Vec.Vector @'[0] [])
[0,0,0]
>>> pretty $ fill @Vec.Vector @'[3] 0 (array @Vec.Vector @'[4] [1..4])
[1,2,3]

cut :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (r :: Nat) a. (KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), 'True ~ Eval (IsSubset s' s), r ~ Eval (Rank s'), Vector v a) => Array v s a -> Array v s' a Source #

Cut an array to form a new (smaller) shape. Errors if the new shape is larger. The old array is reranked to the rank of the new shape first.

>>> toDynamic $ cut @Vec.Vector @'[2] (array @Vec.Vector @'[4] @Int [0..3])
UnsafeArray [2] [0,1]

cutSuffix :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a (r :: Nat). (KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), r ~ Eval (Rank s'), 'True ~ Eval (IsSubset s' s), Vector v a) => Array v s a -> Array v s' a Source #

Cut an array to form a new (smaller) shape, using suffix elements. Errors if the new shape is larger. The old array is reranked to the rank of the new shape first.

>>> toDynamic $ cutSuffix @Vec.Vector @[2,2] a
UnsafeArray [2,2] [18,19,22,23]

pad :: forall (v :: Type -> Type) (s' :: [Nat]) a (s :: [Nat]) (r :: Nat). (KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), r ~ Eval (Rank s'), Vector v a) => a -> Array v s a -> Array v s' a Source #

Pad an array to form a new shape, supplying a default value for elements outside the shape of the old array. The old array is reranked to the rank of the new shape first.

>>> toDynamic $ pad @Vec.Vector @'[5] 0 (array @Vec.Vector @'[4] @Int [0..3])
UnsafeArray [5] [0,1,2,3,0]

lpad :: forall (v :: Type -> Type) (s' :: [Nat]) a (s :: [Nat]) (r :: Nat). (KnownNats s, KnownNats s', KnownNat r, KnownNats (Eval (Rerank r s)), r ~ Eval (Rank s'), Vector v a) => a -> Array v s a -> Array v s' a Source #

Left pad an array to form a new shape, supplying a default value for elements outside the shape of the old array.

>>> toDynamic $ lpad @Vec.Vector @'[5] 0 (array @Vec.Vector @'[4] [0..3])
UnsafeArray [5] [0,0,1,2,3]
>>> pretty $ lpad @Vec.Vector @[3,3] 0 (range @Vec.Vector @[2,2])
[[0,0,0],
 [0,0,1],
 [0,2,3]]

reshape :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (Eval (Size s) ~ Eval (Size s'), KnownNats s, KnownNats s', Vector v a) => Array v s a -> Array v s' a Source #

Reshape an array (with the same number of elements).

>>> pretty $ reshape @Vec.Vector @[4,3,2] a
[[[0,1],
  [2,3],
  [4,5]],
 [[6,7],
  [8,9],
  [10,11]],
 [[12,13],
  [14,15],
  [16,17]],
 [[18,19],
  [20,21],
  [22,23]]]

flat :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ '[Eval (Size s)], Vector v a) => Array v s a -> Array v s' a Source #

Make an Array single dimensional.

>>> pretty $ flat (range @Vec.Vector @[2,2])
[0,1,2,3]
>>> pretty (flat $ toScalar @Vec.Vector 0)
[0]

repeat :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', Eval (IsPrefixOf s s') ~ 'True, Vector v a) => Array v s a -> Array v s' a Source #

Reshape an array, repeating the original array. The shape of the array should be a suffix of the new shape.

>>> pretty $ repeat @Vec.Vector @[2,2,2] (array @Vec.Vector @'[2] [1,2])
[[[1,2],
  [1,2]],
 [[1,2],
  [1,2]]]
repeat ds (toScalar @Vec.Vector x) == konst ds x

cycle :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) a. (KnownNats s, KnownNats s', Vector v a) => Array v s a -> Array v s' a Source #

Reshape an array, cycling through the elements without regard to the original shape.

>>> pretty $ cycle @Vec.Vector @[2,2,2] (array @Vec.Vector @'[3] [1,2,3])
[[[1,2],
  [3,1]],
 [[2,3],
  [1,2]]]

rerank :: forall (v :: Type -> Type) (r :: Nat) (s :: [Nat]) (s' :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (Rerank r s), Vector v a) => SNat r -> Array v s a -> Array v s' a Source #

Change rank by adding new dimensions at the front, if the new rank is greater, or combining dimensions (from left to right) into rows, if the new rank is lower.

>>> shape (rerank (SNat @4) a)
[1,2,3,4]
>>> shape (rerank (SNat @2) a)
[6,4]
flat == rerank 1

reorder :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) (s' :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (Reorder s ds), Vector v a) => SNats ds -> Array v s a -> Array v s' a Source #

Change the order of dimensions.

>>> pretty $ reorder (Dims @[2,0,1]) a
[[[0,4,8],
  [12,16,20]],
 [[1,5,9],
  [13,17,21]],
 [[2,6,10],
  [14,18,22]],
 [[3,7,11],
  [15,19,23]]]

squeeze :: forall (v :: Type -> Type) (s :: [Nat]) (t :: [Nat]) a. (KnownNats s, KnownNats t, t ~ Eval (Squeeze s), Vector v a) => Array v s a -> Array v t a Source #

Remove single dimensions.

>>> let sq = array [1..24] :: Array Vec.Vector '[2,1,3,4,1] Int
>>> shape $ squeeze sq
[2,3,4]
>>> shape $ squeeze (singleton @Vec.Vector 0)
[]

elongate :: forall (s :: [Nat]) (s' :: [Nat]) (d :: Nat) (v :: Type -> Type) a. (KnownNats s, KnownNats s', s' ~ Eval (InsertDim d 1 s), Vector v a) => Dim d -> Array v s a -> Array v s' a Source #

Insert a single dimension at the supplied position.

>>> shape $ elongate (SNat @1) a
[2,1,3,4]
>>> toDynamic $ elongate (SNat @0) (toScalar @Vec.Vector 1)
UnsafeArray [1] [1]

transpose :: forall (v :: Type -> Type) a (s :: [Nat]) (s' :: [Nat]). (KnownNats s, KnownNats s', s' ~ Eval (Reverse s), Vector v a) => Array v s a -> Array v s' a Source #

Reverse indices eg transposes the element Aijk to Akji.

>>> (transpose a) ! [1,0,0] == a ! [0,0,1]
True
>>> pretty $ transpose (array @Vec.Vector @[2,2,2] [1..8])
[[[1,5],
  [3,7]],
 [[2,6],
  [4,8]]]

inflate :: forall (v :: Type -> Type) (s' :: [Nat]) (s :: [Nat]) (d :: Nat) (x :: Nat) a. (KnownNats s, KnownNats s', s' ~ Eval (InsertDim d x s), Vector v a) => Dim d -> SNat x -> Array v s a -> Array v s' a Source #

Inflate (or replicate) an array by inserting a new dimension given a supplied dimension and size.

>>> pretty $ inflate (SNat @0) (SNat @2) (array @Vec.Vector @'[3] [0,1,2])
[[0,1,2],
 [0,1,2]]

intercalate :: forall (v :: Type -> Type) (d :: Nat) (ds :: [Nat]) (n :: Nat) (n' :: Nat) (s :: [Nat]) (si :: [Nat]) (st :: [Nat]) a. (KnownNats s, KnownNats si, KnownNats st, KnownNats ds, KnownNat n, KnownNat n', ds ~ '[d], si ~ Eval (DeleteDim d s), n ~ Eval (GetDim d s), n' ~ Eval (Eval (n + n) - 1), st ~ Eval (InsertDim d n' si), Vector v a, Vector v (Array v si a)) => Dim d -> Array v si a -> Array v s a -> Array v st a Source #

Intercalate an array along dimensions.

>>> pretty $ intercalate (SNat @2) (konst @[2,3] 0 :: Array Vec.Vector [2,3] Int) a
[[[0,0,1,0,2,0,3],
  [4,0,5,0,6,0,7],
  [8,0,9,0,10,0,11]],
 [[12,0,13,0,14,0,15],
  [16,0,17,0,18,0,19],
  [20,0,21,0,22,0,23]]]

intersperse :: forall (v :: Type -> Type) (d :: Nat) (ds :: [Nat]) (n :: Nat) (n' :: Nat) (s :: [Nat]) (si :: [Nat]) (st :: [Nat]) a. (KnownNats s, KnownNats si, KnownNats st, KnownNats ds, KnownNat n, KnownNat n', ds ~ '[d], si ~ Eval (DeleteDim d s), n ~ Eval (GetDim d s), n' ~ ((n + n) - 1), st ~ Eval (InsertDim d n' si), Vector v a, Vector v (Array v si a)) => Dim d -> a -> Array v s a -> Array v st a Source #

Intersperse an element along dimensions.

>>> pretty $ intersperse (SNat @2) 0 a
[[[0,0,1,0,2,0,3],
  [4,0,5,0,6,0,7],
  [8,0,9,0,10,0,11]],
 [[12,0,13,0,14,0,15],
  [16,0,17,0,18,0,19],
  [20,0,21,0,22,0,23]]]

concats :: forall (v :: Type -> Type) (s :: [Nat]) (s' :: [Nat]) (newd :: Nat) (ds :: [Nat]) a. (KnownNats s, KnownNats s', s' ~ Eval (ConcatDims ds newd s), Vector v a) => Dims ds -> SNat newd -> Array v s a -> Array v s' a Source #

Concatenate dimensions, creating a new dimension at the supplied postion.

>>> pretty $ concats (Dims @[0,1]) (SNat @1) a
[[0,4,8,12,16,20],
 [1,5,9,13,17,21],
 [2,6,10,14,18,22],
 [3,7,11,15,19,23]]

reverses :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) a. (KnownNats s, Vector v a) => Dims ds -> Array v s a -> Array v s a Source #

Reverses element order along specified dimensions.

>>> pretty $ reverses (Dims @[0,1]) a
[[[20,21,22,23],
  [16,17,18,19],
  [12,13,14,15]],
 [[8,9,10,11],
  [4,5,6,7],
  [0,1,2,3]]]

rotates :: forall (v :: Type -> Type) a (ds :: [Nat]) (s :: [Nat]). (KnownNats s, 'True ~ Eval (IsDims ds s), Vector v a) => Dims ds -> [Int] -> Array v s a -> Array v s a Source #

Rotate an array by/along dimensions & offsets.

>>> pretty $ rotates (Dims @'[1]) [2] a
[[[8,9,10,11],
  [0,1,2,3],
  [4,5,6,7]],
 [[20,21,22,23],
  [12,13,14,15],
  [16,17,18,19]]]

Sorting

sorts :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) a (si :: [Nat]) (so :: [Nat]). (Ord a, KnownNats s, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s ~ Eval (InsertDims ds so si), Vector v a, Ord (v a), Vector v (Array v si a)) => Dims ds -> Array v s a -> Array v s a Source #

Sort an array along the supplied dimensions.

>>> pretty $ sorts (Dims @'[0]) (array @Vec.Vector @[2,2] [2,3,1,4])
[[1,4],
 [2,3]]
>>> pretty $ sorts (Dims @'[1]) (array @Vec.Vector @[2,2] [2,3,1,4])
[[2,3],
 [1,4]]
>>> pretty $ sorts (Dims @[0,1]) (array @Vec.Vector @[2,2] [2,3,1,4])
[[1,2],
 [3,4]]

sortsBy :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) a b (si :: [Nat]) (so :: [Nat]). (Ord b, KnownNats s, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s ~ Eval (InsertDims ds so si), Vector v a, Vector v (Array v si a), Ord (v b)) => Dims ds -> (Array v si a -> Array v si b) -> Array v s a -> Array v s a Source #

The indices into the array if it were sorted by a comparison function along the dimensions supplied.

>>> import Data.Ord (Down (..))
>>> toDynamic $ sortsBy (Dims @'[0]) (fmap Down) (array @Vec.Vector @[2,2] [2,3,1,4])
UnsafeArray [2,2] [2,3,1,4]

orders :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) a (si :: [Nat]) (so :: [Nat]). (Ord a, KnownNats s, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s ~ Eval (InsertDims ds so si), Vector v a, Vector v Int, Ord (v a), Vector v (Array v si a)) => Dims ds -> Array v s a -> Array v so Int Source #

The indices into the array if it were sorted along the dimensions supplied.

>>> orders (Dims @'[0]) (array @Vec.Vector @[2,2] [2,3,1,4])
[1,0]

ordersBy :: forall (v :: Type -> Type) (ds :: [Nat]) (s :: [Nat]) a b (si :: [Nat]) (so :: [Nat]). (Ord b, KnownNats s, KnownNats si, KnownNats so, si ~ Eval (DeleteDims ds s), so ~ Eval (GetDims ds s), s ~ Eval (InsertDims ds so si), Vector v a, Vector v Int, Vector v (Array v si a), Ord (v b)) => Dims ds -> (Array v si a -> Array v si b) -> Array v s a -> Array v so Int Source #

The indices into the array if it were sorted by a comparison function along the dimensions supplied.

>>> import Data.Ord (Down (..))
>>> ordersBy (Dims @'[0]) (fmap Down) (array @Vec.Vector @[2,2] [2,3,1,4])
[0,1]

Transmission

telecasts :: forall (v :: Type -> Type) (sa :: [Nat]) (sb :: [Nat]) (sc :: [Nat]) (sia :: [Nat]) (sib :: [Nat]) (sic :: [Nat]) (ma :: [Nat]) (mb :: [Nat]) a b c (soa :: [Nat]) (sob :: [Nat]) (ds :: [Nat]). (KnownNats sa, KnownNats sb, KnownNats sc, KnownNats sia, KnownNats sib, KnownNats sic, KnownNats soa, KnownNats sob, KnownNats ds, ds ~ Eval (DimsOf soa), sia ~ Eval (DeleteDims ma sa), sib ~ Eval (DeleteDims mb sb), soa ~ Eval (GetDims ma sa), sob ~ Eval (GetDims mb sb), soa ~ sob, sc ~ Eval (InsertDims ds soa sic), Vector v a, Vector v b, Vector v c, Vector v (Array v sia a), Vector v (Array v sib b), Vector v (Array v sic c)) => SNats ma -> SNats mb -> (Array v sia a -> Array v sib b -> Array v sic c) -> Array v sa a -> Array v sb b -> Array v sc c Source #

Apply a binary array function to two arrays with matching shapes across the supplied (matching) dimensions.

>>> a = array @Vec.Vector @[2,3] [0..5]
>>> b = array @Vec.Vector @'[3] [6..8]
>>> pretty $ telecasts (Dims @'[1]) (Dims @'[0]) (concatenate (SNat @0)) a b
[[0,3,6],
 [1,4,7],
 [2,5,8]]

transmit :: forall (v :: Type -> Type) (sa :: [Nat]) (sb :: [Nat]) (sc :: [Nat]) a b c (ds :: [Nat]) (sib :: [Nat]) (sic :: [Nat]) (sob :: [Nat]). (KnownNats sa, KnownNats sb, KnownNats sc, KnownNats ds, KnownNats sib, KnownNats sic, KnownNats sob, ds ~ Eval (EnumFromTo (Eval (Rank sa)) (Eval (Rank sb) - 1)), sib ~ Eval (DeleteDims ds sb), sob ~ Eval (GetDims ds sb), sb ~ Eval (InsertDims ds sob sib), sc ~ Eval (InsertDims ds sob sic), 'True ~ Eval (IsPrefixOf sa sb), Vector v a, Vector v b, Vector v c, Vector v (Array v sib b), Vector v (Array v sic c)) => (Array v sa a -> Array v sib b -> Array v sic c) -> Array v sa a -> Array v sb b -> Array v sc c Source #

Apply a binary array function to two arrays where the shape of the first array is a prefix of the second array.

>>> a = array @Vec.Vector @[2,3] [0..5]
>>> pretty $ transmit (zipWith (+)) (toScalar @Vec.Vector 1) a
[[1,2,3],
 [4,5,6]]

Row specializations

pattern (:<) :: forall v s sh st a (os :: [Nat]) (ls :: [Nat]) (ds :: [Natural]). (KnownNats s, KnownNats sh, KnownNats st, 'True ~ Eval (InsertOk 0 st sh), s ~ Eval (IncAt 0 st), ds ~ '[0], sh ~ Eval (DeleteDims ds s), KnownNats ls, KnownNats os, Eval (SlicesOk ds os ls s) ~ 'True, os ~ Eval (Replicate (Eval (Rank ds)) 1), ls ~ Eval (GetLastPositions ds s), st ~ Eval (SetDims ds ls s), Vector v a) => Array v sh a -> Array v st a -> Array v s a infix 5 Source #

Convenience pattern for row extraction and consolidation at the beginning of an Array.

>>> (x:<xs) = array @Vec.Vector @'[4] [0..3]
>>> toDynamic x
UnsafeArray [] [0]
>>> toDynamic xs
UnsafeArray [3] [1,2,3]
>>> toDynamic (x:<xs)
UnsafeArray [4] [0,1,2,3]

cons :: forall (v :: Type -> Type) (st :: [Nat]) (s :: [Nat]) (sh :: [Nat]) a. (KnownNats st, KnownNats s, KnownNats sh, 'True ~ Eval (InsertOk 0 st sh), s ~ Eval (IncAt 0 st), sh ~ Eval (DeleteDim 0 st), Vector v a) => Array v sh a -> Array v st a -> Array v s a Source #

Add a new row

>>> pretty $ cons (array @Vec.Vector @'[2] [0,1]) (array @Vec.Vector @[2,2] [2,3,4,5])
[[0,1],
 [2,3],
 [4,5]]

uncons :: forall (v :: Type -> Type) a (s :: [Nat]) (sh :: [Nat]) (st :: [Nat]) (ls :: [Nat]) (os :: [Nat]) (ds :: [Natural]). (KnownNats s, KnownNats sh, KnownNats st, ds ~ '[0], sh ~ Eval (DeleteDims ds s), KnownNats ls, KnownNats os, os ~ Eval (Replicate (Eval (Rank ds)) 1), ls ~ Eval (GetLastPositions ds s), Eval (SlicesOk ds os ls s) ~ 'True, st ~ Eval (SetDims ds ls s), Vector v a) => Array v s a -> (Array v sh a, Array v st a) Source #

split an array into the first row and the remaining rows.

>>> import Data.Bifunctor (bimap)
>>> bimap toDynamic toDynamic $ uncons (array @Vec.Vector @[3,2] [0..5])
(UnsafeArray [2] [0,1],UnsafeArray [2,2] [2,3,4,5])

pattern (:>) :: forall v si sl s a (ds :: [Nat]) (ls :: [Nat]) (os :: [Nat]). (KnownNats si, KnownNats sl, KnownNats s, 'True ~ Eval (InsertOk 0 si sl), s ~ Eval (IncAt 0 si), KnownNats ds, KnownNats ls, KnownNats os, sl ~ Eval (DeleteDim 0 si), ds ~ '[0], Eval (SlicesOk ds os ls s) ~ 'True, os ~ Eval (Replicate (Eval (Rank ds)) 0), ls ~ Eval (GetLastPositions ds s), si ~ Eval (SetDims ds ls s), sl ~ Eval (DeleteDims ds s), Vector v a) => Array v si a -> Array v sl a -> Array v s a infix 5 Source #

Convenience pattern for row extraction and consolidation at the end of an Array.

>>> (xs:>x) = array @Vec.Vector @'[4] [0..3]
>>> toDynamic x
UnsafeArray [] [3]
>>> toDynamic xs
UnsafeArray [3] [0,1,2]
>>> toDynamic (xs:>x)
UnsafeArray [4] [0,1,2,3]

snoc :: forall (v :: Type -> Type) (si :: [Nat]) (s :: [Nat]) (sl :: [Nat]) a. (KnownNats si, KnownNats s, KnownNats sl, 'True ~ Eval (InsertOk 0 si sl), s ~ Eval (IncAt 0 si), sl ~ Eval (DeleteDim 0 si), Vector v a) => Array v si a -> Array v sl a -> Array v s a Source #

Add a new row at the end

>>> pretty $ snoc (array @Vec.Vector @[2,2] [0,1,2,3]) (array @Vec.Vector @'[2] [4,5])
[[0,1],
 [2,3],
 [4,5]]

unsnoc :: forall (v :: Type -> Type) (ds :: [Nat]) (os :: [Nat]) (s :: [Nat]) a (ls :: [Nat]) (si :: [Nat]) (sl :: [Nat]). (KnownNats s, KnownNats ds, KnownNats si, KnownNats ls, KnownNats os, KnownNats sl, ds ~ '[0], Eval (SlicesOk ds os ls s) ~ 'True, os ~ Eval (Replicate (Eval (Rank ds)) 0), ls ~ Eval (GetLastPositions ds s), si ~ Eval (SetDims ds ls s), sl ~ Eval (DeleteDims ds s), Vector v a) => Array v s a -> (Array v si a, Array v sl a) Source #

split an array into the initial rows and the last row.

>>> import Data.Bifunctor (bimap)
>>> bimap toDynamic toDynamic $ unsnoc (array @Vec.Vector @[3,2] [0..5])
(UnsafeArray [2,2] [0,1,2,3],UnsafeArray [2] [4,5])

Shape specializations

type Vector (v :: k -> Type) (s :: Nat) (a :: k) = Array v '[s] a Source #

A one-dimensional array.

vector :: forall (v :: Type -> Type) (n :: Nat) a t. (FromVector t v a, KnownNat n, Vector v a) => t -> Array v '[n] a Source #

Create a one-dimensional array.

>>> pretty $ vector @Vec.Vector @3 @Int [2,3,4]
[2,3,4]

vector' :: forall (v :: Type -> Type) a (n :: Nat) t. (FromVector t v a, Vector v a) => SNat n -> t -> Array v '[n] a Source #

vector with an explicit SNat rather than a KnownNat constraint.

>>> pretty $ vector' @Vec.Vector @Int (SNat @3) [2,3,4]
[2,3,4]

iota :: forall (v :: Type -> Type) (n :: Nat). (KnownNat n, Vector v Int) => Vector v n Int Source #

Vector specialisation of range

>>> toDynamic $ iota @Vec.Vector @5
UnsafeArray [5] [0,1,2,3,4]

type Matrix (v :: k -> Type) (m :: Nat) (n :: Nat) (a :: k) = Array v '[m, n] a Source #

A two-dimensional array.

Math

uniform :: forall (v :: Type -> Type) (s :: [Nat]) a g m. (StatefulGen g m, UniformRange a, KnownNats s, Vector v a) => g -> (a, a) -> m (Array v s a) Source #

Generate an array of uniform random variates between a range.

>>> import System.Random.Stateful hiding (uniform)
>>> g <- newIOGenM (mkStdGen 42)
>>> u <- uniform @Vec.Vector @[2,3,4] @Int g (0,9)
>>> pretty u
[[[0,7,0,2],
  [1,7,4,2],
  [5,9,8,2]],
 [[9,8,1,0],
  [2,2,8,2],
  [2,8,0,6]]]