Safe Haskell | None |
---|---|
Language | Haskell2010 |
Arrays with a fixed shape.
Synopsis
- newtype Array s a = Array {}
- with :: forall a r s. HasShape s => Array a -> (Array s a -> r) -> r
- shape :: forall a s. HasShape s => Array s a -> [Int]
- toDynamic :: HasShape s => Array s a -> Array a
- reshape :: forall a s s'. (Size s ~ Size s', HasShape s, HasShape s') => Array s a -> Array s' a
- transpose :: forall a s. (HasShape s, HasShape (Reverse s)) => Array s a -> Array (Reverse s) a
- diag :: forall a s. (HasShape s, HasShape '[Minimum s]) => Array s a -> Array '[Minimum s] a
- selects :: forall ds s s' a. (HasShape s, HasShape ds, HasShape s', s' ~ DropIndexes s ds) => Proxy ds -> [Int] -> Array s a -> Array s' a
- selectsExcept :: forall ds s s' a. (HasShape s, HasShape ds, HasShape s', s' ~ TakeIndexes s ds) => Proxy ds -> [Int] -> Array s a -> Array s' a
- folds :: forall ds st si so a b. (HasShape st, HasShape ds, HasShape si, HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds) => (Array si a -> b) -> Proxy ds -> Array st a -> Array so b
- extracts :: forall ds st si so a. (HasShape st, HasShape ds, HasShape si, HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds) => Proxy ds -> Array st a -> Array so (Array si a)
- joins :: forall ds si st so a. (HasShape st, HasShape ds, st ~ AddIndexes si ds so, HasShape si, HasShape so) => Proxy ds -> Array so (Array si a) -> Array st a
- maps :: forall ds st st' si si' so a b. (HasShape st, HasShape st', HasShape ds, HasShape si, HasShape si', HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds, st' ~ AddIndexes si' ds so, st ~ AddIndexes si ds so) => (Array si a -> Array si' b) -> Proxy ds -> Array st a -> Array st' b
- concatenate :: forall a s0 s1 d s. (CheckConcatenate d s0 s1 s, Concatenate d s0 s1 ~ s, HasShape s0, HasShape s1, HasShape s, KnownNat d) => Proxy d -> Array s0 a -> Array s1 a -> Array s a
- insert :: forall a s s' d i. (DropIndex s d ~ s', CheckInsert d i s, KnownNat i, KnownNat d, HasShape s, HasShape s', HasShape (Insert d s)) => Proxy d -> Proxy i -> Array s a -> Array s' a -> Array (Insert d s) a
- append :: forall a d s s'. (DropIndex s d ~ s', CheckInsert d (Dimension s d - 1) s, KnownNat (Dimension s d - 1), KnownNat d, HasShape s, HasShape s', HasShape (Insert d s)) => Proxy d -> Array s a -> Array s' a -> Array (Insert d s) a
- reorder :: forall a ds s. (HasShape ds, HasShape s, HasShape (Reorder s ds), CheckReorder ds s) => Proxy ds -> Array s a -> Array (Reorder s ds) a
- expand :: forall s s' a b c. (HasShape s, HasShape s', HasShape ((++) s s')) => (a -> b -> c) -> Array s a -> Array s' b -> Array ((++) s s') c
- contract :: forall a b s ss s' ds. (KnownNat (Minimum (TakeIndexes s ds)), HasShape (TakeIndexes s ds), HasShape s, HasShape ds, HasShape ss, HasShape s', s' ~ DropIndexes s ds, ss ~ '[Minimum (TakeIndexes s ds)]) => (Array ss a -> b) -> Proxy ds -> Array s a -> Array s' b
- dot :: forall a b c d sa sb s' ss se. (HasShape sa, HasShape sb, HasShape (sa ++ sb), se ~ TakeIndexes (sa ++ sb) '[Rank sa - 1, Rank sa], HasShape se, KnownNat (Minimum se), KnownNat (Rank sa - 1), KnownNat (Rank sa), ss ~ '[Minimum se], HasShape ss, s' ~ DropIndexes (sa ++ sb) '[Rank sa - 1, Rank sa], HasShape s') => (Array ss c -> d) -> (a -> b -> c) -> Array sa a -> Array sb b -> Array s' d
- slice :: forall (pss :: [[Nat]]) s s' a. (HasShape s, HasShape s', KnownNatss pss, KnownNat (Rank pss), s' ~ Ranks pss) => Proxy pss -> Array s a -> Array s' a
- squeeze :: forall s t a. t ~ Squeeze s => Array s a -> Array t a
- ident :: forall a s. (HasShape s, Additive a, Multiplicative a) => Array s a
- singleton :: HasShape s => a -> Array s a
- type Scalar a = Array ('[] :: [Nat]) a
- fromScalar :: HasShape ('[] :: [Nat]) => Array ('[] :: [Nat]) a -> a
- toScalar :: HasShape ('[] :: [Nat]) => a -> Array ('[] :: [Nat]) a
- type Vector s a = Array '[s] a
- type Matrix m n a = Array '[m, n] a
- col :: forall m n a. (KnownNat m, KnownNat n, HasShape '[m, n]) => Int -> Matrix m n a -> Vector n a
- row :: forall m n a. (KnownNat m, KnownNat n, HasShape '[m, n]) => Int -> Matrix m n a -> Vector n a
- safeCol :: forall m n a j. (True ~ CheckIndex j n, KnownNat j, KnownNat m, KnownNat n, HasShape '[m, n]) => Proxy j -> Matrix m n a -> Vector n a
- safeRow :: forall m n a j. (True ~ CheckIndex j m, KnownNat j, KnownNat m, KnownNat n, HasShape '[m, n]) => Proxy j -> Matrix m n a -> Vector n a
- mmult :: forall m n k a. (KnownNat k, KnownNat m, KnownNat n, HasShape [m, n], Ring a) => Array [m, k] a -> Array [k, n] a -> Array [m, n] a
Fixed-sixed arrays
a multidimensional array with a type-level shape
>>>
a
[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]>>>
[1,2,3] :: Array '[2,2] Int
[[*** Exception: NumHaskException {errorMessage = "shape mismatch"}
Instances
with :: forall a r s. HasShape s => Array a -> (Array s a -> r) -> r Source #
use a dynamic array in a fixed context
>>>
with (D.fromFlatList [2,3,4] [1..24]) (selects (Proxy :: Proxy '[0,1]) [1,1] :: Array '[2,3,4] Int -> Array '[4] Int)
[17, 18, 19, 20]
shape :: forall a s. HasShape s => Array s a -> [Int] Source #
get shape of an Array as a value
>>>
shape a
[2,3,4]
toDynamic :: HasShape s => Array s a -> Array a Source #
convert to a dynamic array with shape at the value level.
Operators
reshape :: forall a s s'. (Size s ~ Size s', HasShape s, HasShape s') => Array s a -> Array s' a Source #
reshape an array (with the same number of elements)
>>>
reshape a :: Array '[4,3,2] 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]]]
transpose :: forall a s. (HasShape s, HasShape (Reverse s)) => Array s a -> Array (Reverse s) a Source #
reverse indices eg transposes the element Aijk to Akji
>>>
index (transpose a) [1,0,0] == index a [0,0,1]
True
diag :: forall a s. (HasShape s, HasShape '[Minimum s]) => Array s a -> Array '[Minimum s] a Source #
>>>
diag (ident :: Array '[3,2] Int)
[1, 1]
selects :: forall ds s s' a. (HasShape s, HasShape ds, HasShape s', s' ~ DropIndexes s ds) => Proxy ds -> [Int] -> Array s a -> Array s' a Source #
selects ds ps a select from a elements ds dimensions at positions ps
>>>
let s = selects (Proxy :: Proxy '[0,1]) [1,1] a
>>>
:t s
s :: Array '[4] Int
>>>
s
[17, 18, 19, 20]
selectsExcept :: forall ds s s' a. (HasShape s, HasShape ds, HasShape s', s' ~ TakeIndexes s ds) => Proxy ds -> [Int] -> Array s a -> Array s' a Source #
select an index except along dimensions
>>>
let s = selectsExcept (Proxy :: Proxy '[2]) [1,1] a
>>>
:t s
s :: Array '[4] Int
>>>
s
[17, 18, 19, 20]
folds :: forall ds st si so a b. (HasShape st, HasShape ds, HasShape si, HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds) => (Array si a -> b) -> Proxy ds -> Array st a -> Array so b Source #
fold along specified dimensions
>>>
folds sum (Proxy :: Proxy '[1]) a
[68, 100, 132]
extracts :: forall ds st si so a. (HasShape st, HasShape ds, HasShape si, HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds) => Proxy ds -> Array st a -> Array so (Array si a) Source #
extracts dimensions to an outer layer
>>>
let e = extracts (Proxy :: Proxy '[1,2]) a
>>>
:t e
e :: Array '[3, 4] (Array '[2] Int)
joins :: forall ds si st so a. (HasShape st, HasShape ds, st ~ AddIndexes si ds so, HasShape si, HasShape so) => Proxy ds -> Array so (Array si a) -> Array st a Source #
join inner and outer dimension layers
>>>
let e = extracts (Proxy :: Proxy '[1,0]) a
>>>
:t e
e :: Array '[3, 2] (Array '[4] Int)
>>>
let j = joins (Proxy :: Proxy '[1,0]) e
>>>
:t j
j :: Array '[2, 3, 4] Int
>>>
a == j
True
maps :: forall ds st st' si si' so a b. (HasShape st, HasShape st', HasShape ds, HasShape si, HasShape si', HasShape so, si ~ DropIndexes st ds, so ~ TakeIndexes st ds, st' ~ AddIndexes si' ds so, st ~ AddIndexes si ds so) => (Array si a -> Array si' b) -> Proxy ds -> Array st a -> Array st' b Source #
maps along specified dimensions
>>>
:t maps (transpose) (Proxy :: Proxy '[1]) a
maps (transpose) (Proxy :: Proxy '[1]) a :: Array '[4, 3, 2] Int
concatenate :: forall a s0 s1 d s. (CheckConcatenate d s0 s1 s, Concatenate d s0 s1 ~ s, HasShape s0, HasShape s1, HasShape s, KnownNat d) => Proxy d -> Array s0 a -> Array s1 a -> Array s a Source #
concatenate along a dimension
>>>
:t concatenate (Proxy :: Proxy 1) a a
concatenate (Proxy :: Proxy 1) a a :: Array '[2, 6, 4] Int
insert :: forall a s s' d i. (DropIndex s d ~ s', CheckInsert d i s, KnownNat i, KnownNat d, HasShape s, HasShape s', HasShape (Insert d s)) => Proxy d -> Proxy i -> Array s a -> Array s' a -> Array (Insert d s) a Source #
insert (Proxy :: Proxy d) (Proxy :: Proxy i) insert along the dimension d at position i
>>>
insert (Proxy :: Proxy 2) (Proxy :: Proxy 0) a ([100..105])
[[[100, 1, 2, 3, 4], [101, 5, 6, 7, 8], [102, 9, 10, 11, 12]], [[103, 13, 14, 15, 16], [104, 17, 18, 19, 20], [105, 21, 22, 23, 24]]]
append :: forall a d s s'. (DropIndex s d ~ s', CheckInsert d (Dimension s d - 1) s, KnownNat (Dimension s d - 1), KnownNat d, HasShape s, HasShape s', HasShape (Insert d s)) => Proxy d -> Array s a -> Array s' a -> Array (Insert d s) a Source #
insert along a dimension at the end
>>>
:t append (Proxy :: Proxy 0) a
append (Proxy :: Proxy 0) a :: Array '[3, 4] Int -> Array '[3, 3, 4] Int
reorder :: forall a ds s. (HasShape ds, HasShape s, HasShape (Reorder s ds), CheckReorder ds s) => Proxy ds -> Array s a -> Array (Reorder s ds) a Source #
change the order of dimensions
>>>
let r = reorder (Proxy :: Proxy '[2,0,1]) a
>>>
:t r
r :: Array '[4, 2, 3] Int
expand :: forall s s' a b c. (HasShape s, HasShape s', HasShape ((++) s s')) => (a -> b -> c) -> Array s a -> Array s' b -> Array ((++) s s') c Source #
product two arrays using the supplied binary function If the function is multiply, and the arrays are tensors, then this can be interpreted as a tensor product.
https://en.wikipedia.org/wiki/Tensor_product
The concept of a tensor product is a dense crossroad, and a complete treatment is elsewhere. To quote: ... 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.
>>>
expand (*) v v
[[1, 2, 3], [2, 4, 6], [3, 6, 9]]
contract :: forall a b s ss s' ds. (KnownNat (Minimum (TakeIndexes s ds)), HasShape (TakeIndexes s ds), HasShape s, HasShape ds, HasShape ss, HasShape s', s' ~ DropIndexes s ds, ss ~ '[Minimum (TakeIndexes s ds)]) => (Array ss a -> b) -> Proxy ds -> Array s a -> Array 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, and allowing another binary other than addition
>>>
let b = [1..6] :: Array '[2,3] Int
>>>
contract sum (Proxy :: Proxy '[1,2]) (expand (*) b (transpose b))
[[14, 32], [32, 77]]
dot :: forall a b c d sa sb s' ss se. (HasShape sa, HasShape sb, HasShape (sa ++ sb), se ~ TakeIndexes (sa ++ sb) '[Rank sa - 1, Rank sa], HasShape se, KnownNat (Minimum se), KnownNat (Rank sa - 1), KnownNat (Rank sa), ss ~ '[Minimum se], HasShape ss, s' ~ DropIndexes (sa ++ sb) '[Rank sa - 1, Rank sa], HasShape s') => (Array ss c -> d) -> (a -> b -> c) -> Array sa a -> Array sb b -> Array s' d Source #
a generalisation of a dot operation, which is a multiplicative expansion of two arrays and sum contraction along the middle two dimensions.
dot sum (*) on two matrices is known as matrix multiplication
>>>
let b = [1..6] :: Array '[2,3] Int
>>>
dot sum (*) b (transpose b)
[[14, 32], [32, 77]]
dot sum (*) on two vectors is known as the inner product
>>>
let v = [1..3] :: Array '[3] Int
>>>
:t dot sum (*) v v
dot sum (*) v v :: Array '[] Int
>>>
dot sum (*) v v
14
dot sum (*) m v on a matrix and a vector is matrix-vector multiplication
Note that an `Array '[3] Int` is neither a row vector nor column vector. dot
is not turning the vector into a matrix and then using matrix multiplication.
>>>
dot sum (*) v b
[9, 12, 15]
>>>
dot sum (*) b v
[14, 32]
slice :: forall (pss :: [[Nat]]) s s' a. (HasShape s, HasShape s', KnownNatss pss, KnownNat (Rank pss), s' ~ Ranks pss) => Proxy pss -> Array s a -> Array s' a Source #
select elements along every dimension
>>>
let s = slice (Proxy :: Proxy '[[0,1],[0,2],[1,2]]) a
>>>
:t s
s :: Array '[2, 2, 2] Int
>>>
s
[[[2, 3], [10, 11]], [[14, 15], [22, 23]]]
>>>
let s = squeeze $ slice (Proxy :: Proxy '[ '[0], '[0], '[0]]) a
>>>
:t s
s :: Array '[] Int
>>>
s
1
squeeze :: forall s t a. t ~ Squeeze s => Array s a -> Array t a Source #
remove singleton dimensions
>>>
let a = [1..24] :: Array '[2,1,3,4,1] Int
>>>
a
[[[[[1], [2], [3], [4]], [[5], [6], [7], [8]], [[9], [10], [11], [12]]]], [[[[13], [14], [15], [16]], [[17], [18], [19], [20]], [[21], [22], [23], [24]]]]]>>>
squeeze a
[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]
>>>
squeeze ([1] :: Array '[1,1] Double)
1.0
ident :: forall a s. (HasShape s, Additive a, Multiplicative a) => Array s a Source #
>>>
ident :: Array '[3,2] Int
[[1, 0], [0, 1], [0, 0]]
singleton :: HasShape s => a -> Array s a Source #
>>>
singleton one :: Array '[3,2] Int
[[1, 1], [1, 1], [1, 1]]
Scalar
Scalar specialisations
type Scalar a = Array ('[] :: [Nat]) a Source #
An Array '[] a despite being a Scalar is never-the-less a one-element vector under the hood. Unification of representation is unexplored.
fromScalar :: HasShape ('[] :: [Nat]) => Array ('[] :: [Nat]) a -> a Source #
unwrapping scalars is probably a performance bottleneck
>>>
let s = [3] :: Array ('[] :: [Nat]) Int
>>>
fromScalar s
3
toScalar :: HasShape ('[] :: [Nat]) => a -> Array ('[] :: [Nat]) a Source #
convert a number to a scalar
>>>
:t toScalar 2
toScalar 2 :: Num a => Array '[] a
Vector
Scalar specialisations
Matrix
Matrix specialisations
col :: forall m n a. (KnownNat m, KnownNat n, HasShape '[m, n]) => Int -> Matrix m n a -> Vector n a Source #
extract specialised to a matrix
>>>
col 1 m
[1, 5, 9]
row :: forall m n a. (KnownNat m, KnownNat n, HasShape '[m, n]) => Int -> Matrix m n a -> Vector n a Source #
extract specialised to a matrix
>>>
row 1 m
[4, 5, 6, 7]
safeCol :: forall m n a j. (True ~ CheckIndex j n, KnownNat j, KnownNat m, KnownNat n, HasShape '[m, n]) => Proxy j -> Matrix m n a -> Vector n a Source #
column extraction checked at type level
>>>
safeCol (Proxy :: Proxy 1) m
[1, 5, 9]
>>>
safeCol (Proxy :: Proxy 4) m
... ... index outside range ...
safeRow :: forall m n a j. (True ~ CheckIndex j m, KnownNat j, KnownNat m, KnownNat n, HasShape '[m, n]) => Proxy j -> Matrix m n a -> Vector n a Source #
row extraction checked at type level
>>>
safeRow (Proxy :: Proxy 1) m
[4, 5, 6, 7]
>>>
safeRow (Proxy :: Proxy 3) m
... ... index outside range ...
mmult :: forall m n k a. (KnownNat k, KnownNat m, KnownNat n, HasShape [m, n], Ring a) => Array [m, k] a -> Array [k, n] a -> Array [m, n] a Source #
matrix multiplication
This is dot sum (*) specialised to matrices
>>>
let a = [1, 2, 3, 4] :: Array '[2, 2] Int
>>>
let b = [5, 6, 7, 8] :: Array '[2, 2] Int
>>>
a
[[1, 2], [3, 4]]
>>>
b
[[5, 6], [7, 8]]
>>>
mmult a b
[[19, 22], [43, 50]]