Update guide

This commit is contained in:
Kiana Sheibani 2024-05-06 02:35:07 -04:00
parent 5fef91ade7
commit fd6d55f09d
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
3 changed files with 132 additions and 10 deletions

View file

@ -79,8 +79,6 @@ Vector n a = Array [n] a
A vector's type signature and stored data is effectively identical to that of the standard library type `Vect`, whose elements are confusingly also called "vectors"; we often refer to those as "vects" to differentiate.
Indices are typically written as lists of integers, but for vectors it is occasionally acceptable to write the single index number without putting it inside a list. This is mostly the case for indexing, where each indexing function has an alternate definition specifically for vectors.
### Matrices
As mentioned before, a matrix is a rank-2 array:
@ -145,7 +143,7 @@ The `TransType` value is obtained by prepending a capital T to these names. For
#### The Point Type
Transforms behave differently from regular matrices when applied to a vector. When a non-linear transform is used, the transform is first linearized, so that vectors only have linear transformations applied to them. This is not a bug.
Transforms behave differently from regular matrices when applied to a vector. When a non-linear transform is used, the transform is first linearized, so that vectors only have linear transformations applied to them. **This is not a bug!**
In order to properly apply these transforms, the `Point` type must be used, which is a wrapper around the `Vector` type that supports these transforms. This separation between points and vectors is intended to make working with affine transformations more convenient, as it mirrors the separation between points and vectors in affine algebra.
@ -153,4 +151,6 @@ In order to properly apply these transforms, the `Point` type must be used, whic
The type `Permutation n` represents a permutation of `n` elements. Permutations are mostly used internally for various algorithms, but they are also an input in various operations, such as those that permute the axes of an array.
Permutations can be composed using `(*.)`, and a permutation can be converted into a matrix using `permuteM`.
[Contents](Intro.md) | [Next](Operations.md)

View file

@ -1,5 +1,10 @@
# Basic Operations on Arrays
> [!WARNING]
> Arrays and their associated functions are not intended to be evaluated at compile-time. If you try to compute an array in the REPL, you will not get the output you expect!
>
> If you really need to use the REPL to test array code, use `:exec`.
## Constructing Arrays
The most important array constructor is `array`, which returns an array of the specified values:
@ -27,7 +32,7 @@ ones [2, 2, 3]
There are a few simple functions for accessing basic properties of arrays: `shape` and `rank`, which are self-explanatory, and `size`, which returns the total number of elements in the array.
The `shape` accessor is sufficient for most uses, but it can cause problems with the type-checker, as for an array `arr : Array s a` the type checker does not know that `shape arr` and `s` are equal. To solve this problem, a view for accessing the shape is provided:
The `shape` accessor is sufficient for most uses, but it can cause problems with the type-checker, as for an array `arr : Array s a` the type checker does not know that `shape arr` and `s` are equal. To solve this problem, there is a view:
```idris
example {s} arr with (viewShape arr)
@ -62,7 +67,7 @@ Not all combinations of these categories are defined by the library. Here are th
| **Update** | `indexUpdate` | `indexUpdateRange` | `indexUpdateNB` | | | |
| **Set** | `indexSet` | `indexSetRange` | `indexSetNB` | | | |
The accessor functions have operator forms for convenience, also specified within the table.
The accessor functions have operator forms for convenience.
### Specifying Coordinates
@ -77,7 +82,7 @@ arr !! [1, 0]
With ranged indexing, a sub-array of the original array is accessed or modified. This sub-array is given by a list of _range specifiers_, one for each axis, which can be one of the following:
- `Bounds x y` - Every index from `x` to `y`
- `Bounds x y` - Every index from `x` (inclusive) to `y` (exclusive)
- `StartBound x` - Every index from `x` to the end of the axis
- `EndBound y` - Every index from the start of the axis to `y`
- `All` - Every index in the axis
@ -117,7 +122,7 @@ When folding or traversing the elements of an array, these elements are ordered
### Concatenation and Stacking
Two arrays can be concatenated along an axis, so long as all other axes have the same dimensions. Two matrices being concatenated along the row axis requires that they must have the same number of columns.
Two arrays can be concatenated along an axis (`concat`), so long as all other axes have the same dimensions. Two matrices being concatenated along the row axis requires that they must have the same number of columns.
```idris
-- 0 is the first axis i.e. the row axis
@ -128,7 +133,7 @@ concat 0 (matrix [[1, 2], [3, 4]]) (matrix [[5, 6], [7, 8]])
[7, 8]]
```
Stacking is similar to concatenation, but slightly different. Stacking combines arrays with the exact same shape into a single array that is one rank higher. For example, vectors can be stacked along the row axis to obtain a matrix whose rows are the original vectors.
Stacking (`stack`) is similar to concatenation, but slightly different. Stacking combines arrays with the exact same shape into a single array that is one rank higher. For example, vectors can be stacked along the row axis to obtain a matrix whose rows are the original vectors.
```idris
stack 0 [vector [1, 2], vector [3, 4]]
@ -149,7 +154,7 @@ reshape [3, 2] (vector [1, 2, 3, 4, 5, 6])
[5, 6]]
```
Arrays can also be resized, which changes their shape while keeping every element at the same index. A default element must be provided to fill any indices that did not exist in the original array.
Arrays can also be resized with `resize`, which changes their shape while keeping every element at the same index. A default element must be provided to fill any indices that did not exist in the original array.
```idris
resize [2, 4] 10 (matrix [[1, 2],
@ -163,8 +168,10 @@ Instead of the `resize` function, one can also use the `resizeLTE` function, whi
### Transpose
The `transpose` function reverses the axis order of an array. For matrices, this corresponds to the usual definition of switching rows and columns. There is also a postfix form `(.T)`.
The `transpose` function reverses the axis order of an array: For `arr : Array [3,2,4] Int`, we have `transpose arr : Array [4,2,3] Int`. For matrices, this corresponds to the usual definition of switching rows and columns. There is also a postfix form `(.T)`.
For more fine-grained control when rearranging arrays, there are the `swapAxes` and `permuteAxes` functions, where the first swaps only two axes and the second takes an arbitrary [permutation](DataTypes.md#Permutations). There are also `swapInAxis` and `permuteInAxis`, which permute inside an axis, e.g. swapping rows or columns in a matrix.
Like with concatenation and stacking, the swap and permute functions have forms specific to vectors and matrices: `swapCoords` and `permuteCoords` for vectors, and `swapRows`, `permuteRows`, `swapColumns`, and `permuteColumns` for matrices.
[Previous](DataTypes.md) | [Contents](Intro.md) | [Next](VectorsMatrices.md)

View file

@ -1,4 +1,119 @@
# Working with Vectors and Matrices
As linear algebra is one of the main concerns of NumIdr, most of its provided functions are dedicated to vectors (rank-1 arrays) and matrices (rank-2 arrays).
## The Generalized Multiplication Operator
A linear algebra library wouldn't be very useful without matrix multiplication! While Idris's standard `(*)` operator would be a natural choice for this, the `Num` interface only allows for homogeneous multiplication, in which the inputs and output are all of the same type. To get around this, `(*)` is used for element-wise multiplication (a.k.a. the Hadamard product), and NumIdr defines a new interface `Mult`:
```idris
interface Mult a b c where
(*.) : a -> b -> c
-- Synonym for homogeneous cases:
Mult' : Type -> Type
Mult' a = Mult a a a
```
The generalized multiplication operator `(*.)` covers matrix multiplication, scalar-vector multiplication, and any other operation that's vaguely multiplication-like.
## Vectors
### Algebraic Operations
Vectors can be added together with `(+)`, which performs element-wise addition. Scalar-vector multiplication is done with the generalized multiplication operator `(*.)`.
```idris
2 *. (vector [1, 1] + vector [2, 3])
== vector [6, 8]
```
A few other basic linear algebra operations are available:
- `dot`, The dot product
- `cross`, The cross product
- `perp`, The perpendicular product (sometimes called the 2D cross product)
- `triple`, The scalar triple product
### Indexing
NumIdr provides special versions of `index` and `indexNB` and their infix forms `(!!)` and `(!?)` for use with vectors. These take a single numeric index instead of a list.
```idris
Vector.index 2 v == index [2] v
v !! 2 == v !! [2]
```
For convenience, when working with two- or three-dimensional vectors, there are postfix accessors `(.x)`, `(.y)`, and `(.z)`:
```idris
v = vector [5, 6, 2]
v.x == 5
v.y == 6
v.z == 2
```
### Other Operations
- `toVect` - Convert a vector into a `Vect`
- `dim` - Returns the vector's length
- `(++)` - Concatenate two vectors
## Matrices
### Arithmetic Operations
Like vectors, matrices can be added together using `(+)`. Matrix multiplication, as well as matrix-vector and matrix-scalar multiplication, are performed using `(*.)`.
For the purposes of working with matrices and matrix-like objects, the sub-interfaces `MultMonoid` and `MultGroup` are defined:
```idris
interface Mult' a => MultMonoid a where
identity : a
interface MultMonoid a => MultGroup a where
inverse : a -> a
```
The `identity` function returns an identity matrix, and `inverse` calculates a matrix's inverse. Note that `inverse` cannot tell you if an inverse of your matrix does not exist; if you want to handle that case, use `tryInverse` instead.
```idris
tryInverse : FieldCmp a => Matrix' n a -> Maybe (Matrix' n a)
```
#### LU and LUP Decomposition
The functions `decompLU` and `decompLUP` compute LU and LUP decomposition on a matrix.
```idris
decompLU : Field a => (mat : Matrix m n a) -> Maybe (DecompLU mat)
decompLUP : FieldCmp a => (mat : Matrix m n a) -> DecompLUP mat
```
`DecompLU` and `DecompLUP` are record types holding the results of the corresponding decomposition. The accessors `lower`, `upper` and `permute` can be applied to get each component of the decomposition; `lower` and `upper` return matrices, and `permute` returns a `Permutation` value.
#### Other Algebraic Operations
- `trace` - The sum of the matrix's diagonal
- `outer` - The matrix-valued outer product (or tensor product) of two vectors
- `det` - Determinant of the matrix
- `solve` - Apply an inverse matrix to a vector, useful for solving linear equations
The `det` and `solve` operations require computing an LUP decomposition, which can be expensive. To avoid duplicating work, the variants `detWithLUP` and `solveWithLUP` allow a pre-computed LUP decomposition to be passed in.
```idris
det m == detWithLUP m (decompLUP m)
```
### Indexing
Aside from the usual array indexing functions, there are a few functions specialized to matrix indexing:
- `getRow` and `getColumn` - Returns a specific row or column of the matrix
- `diagonal` - Returns the diagonal elements of the matrix as a vector
- `minor` - Removes a single row and column from the matrix
[Previous](Operations.md) | [Contents](Intro.md) | [Next](Transforms.md)