Fix various guide issues

This commit is contained in:
Kiana Sheibani 2024-05-06 04:55:50 -04:00
parent d8c22d7ed6
commit 8903575d8b
Signed by: toki
GPG key ID: 6CB106C25E86A9F7
6 changed files with 30 additions and 34 deletions

View file

@ -28,7 +28,7 @@ combine the most useful features of each library.
## Documentation
Most of the exported utility functions have docstrings. There is also
a (currently unfinished) guide on how to use NumIdr [here](docs/Intro.md).
a (currently unfinished) guide on how to use NumIdr [here](docs/Contents.md).
## Usage

View file

@ -49,9 +49,6 @@ When determining the index of a value inside the array, the order of the indices
> (as in "multi-dimensional array" in the previous section), or to the lengths of its
> axes. Conventionally, NumIdr reserves "dimension" for the second meaning, and uses
> "rank" for the first meaning.
>
> This guide has ignored this convention until now to be more understandable to newcomers,
> but will follow it from this point onward.
## Types of Arrays
@ -133,4 +130,4 @@ The type `Permutation n` represents a permutation of `n` elements. Permutations
Permutations can be composed using `(*.)`, and a permutation can be converted into a matrix using `permuteM`.
[Contents](Intro.md) | [Next](Operations.md)
[Contents](Contents.md) | [Next](Operations.md)

View file

@ -1,6 +1,6 @@
# Basic Operations on Arrays
> [!WARNING]
> [!CAUTION]
> 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`.
@ -13,7 +13,7 @@ The most important array constructor is `array`, which returns an array of the s
array [[1, 2, 3], [4, 5, 6]]
```
Scalars, vectors and matrices have their own constructors, used in exactly the same way (`scalar`, `vector`, and `matrix`). These should be used instead of `array` whereever possible, as they provide more information to the type-checker.
Scalars, vectors and matrices have their own constructors, used in exactly the same way (`scalar`, `vector`, and `matrix`). These should be used instead of `array` wherever possible, as they provide more information to the type-checker.
There are also a few other, more basic constructors for convenience.
@ -32,14 +32,13 @@ 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, there is a view:
```idris
example {s} arr with (viewShape arr)
_ | Shape s = ...
```
This will fully placate the type-checker, as the `s` returned by the view is proven to be equal to the shape of the array.
> [!TIP]
> 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, you can use the `ShapeView`:
>
> ```idris
> example {s} arr with (viewShape arr)
> _ | Shape s = ...
> ```
## Indexing Arrays
@ -114,8 +113,8 @@ matrix [[1, 1], [2, 5]] + matrix [[2, 3], [-1, 3]]
This elementwise behavior holds for `(+)`, `(*)`, `(-)`, `(/)`, and `(<+>)`. **`(*)` is not matrix multiplication!** For the generalized multiplication operator, which includes matrix multiplication, see [the next chapter](VectorsMatrices.md).
> [!NOTE]
> Due to unfortunate restrictions in Idris's standard `Num` interface, the addition and multiplication operations can only be used when the array's shape is available at run-time. If this is not the case, you must use `zipwith (+)` or `zipWith (*)` instead.
> [!WARNING]
> Due to unfortunate restrictions in Idris's standard `Num` interface, `(+)` and `(*)` can only be used when the array's shape is available at run-time. If this is not the case, you must use `zipwith (+)` or `zipWith (*)` instead.
### `Foldable` and `Traversable`
@ -177,4 +176,4 @@ For more fine-grained control when rearranging arrays, there are the `swapAxes`
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)
[Previous](DataTypes.md) | [Contents](Contents.md) | [Next](VectorsMatrices.md)

View file

@ -1,6 +1,6 @@
# Transforms
In code that works with linear algebra, it is common to use matrices as _transformations_, i.e. functions that take in a vector and output a new vector. These matrices can often be divided into categories based on the operations they perform, such as a rotation matrix or an affine transformation matrix.
In code that works with linear algebra, it is common to use matrices as _transformations_, functions that take in a vector and output a new vector. These matrices can often be divided into categories based on the operations they perform, such as a rotation matrix or an affine transformation matrix.
The `Transform` wrapper exists to encode these differing properties on the type level, as well as to provide extra utilities for working with matrices in this fashion.
@ -26,7 +26,7 @@ A `Transform ty n a` is a wrapper over an `HMatrix' n a`. The `ty` parameter is
- `TRotation`
- `TTrivial` (always the `identity`)
The capital T at the beginning of each of these names identifies it as a `TransType` value. To make working with transforms smoother, NumIdr provides synonyms for transforms of each type. For example, `Isometry n a` is a synonym for `Transform TIsometry n a`.
The capital T at the beginning of each of these names identifies it as a `TransType` value. To make working with transforms smoother, NumIdr provides synonyms for transforms of each type: for example, `Isometry n a` is a synonym for `Transform TIsometry n a`.
### Linear and Affine
@ -50,9 +50,9 @@ For simplicity, both categories of transform are wrappers over homogeneous matri
Some transform types can be cast into other types. For example, a `Rotation` can be cast into an `Orthonormal`, as all rotation matrices are orthonormal.
```idris
rot : Rotation 3 Double
rt : Rotation 3 Double
cast rot : Orthonormal 3 Double
cast rt : Orthonormal 3 Double
```
In the diagram from the previous section, lower types can be cast into types higher up. Each linear type (on the left) can also be cast into the corresponding affine type (on the right).
@ -63,8 +63,8 @@ There are multiple ways to construct transforms, either by wrapping a matrix or
For each transform type, `fromHMatrix` can be used to test if a homogeneous matrix satisfies the right properties, and converts it into a transform if it does. The `Rotation`, `Orthonormal` and `Linear` types also have `fromMatrix` for non-homogeneous matrices.
> [!NOTE]
> The `fromHMatrix` and `fromMatrix` constructors use exact equality comparisons when testing matrices, which can be an issue if your element type is `Double` or a similar inexact number type. To remedy this, NumIdr provides a `WithEpsilon` named implementation that defines equality approximately.
> [!WARNING]
> The `fromHMatrix` and `fromMatrix` constructors use exact equality comparisons when testing matrices, which can be a problem if your element type is `Double` or a similar inexact number type. To fix this issue, NumIdr provides a `WithEpsilon` named implementation that defines equality approximately and allows you to specify an epsilon value.
>
> ```idris
> fromHMatrix @{WithEpsilon 1.0e-6} mat
@ -74,7 +74,10 @@ There are also direct constructors for transforms, which are often more convenie
## Multiplication with Transforms
Like most objects in NumIdr, transforms multiply with the generalized multiplication operator `(*.)`, and `identity` and `inverse` can also be used with transforms. There is no `tryInverse` function, as all transforms are required to be invertible.
Like most objects in NumIdr, transforms multiply with the generalized multiplication operator `(*.)`, and `identity` and `inverse` can also be used with transforms.
> [!IMPORTANT]
> There is no `tryInverse` function for transforms. This is because all transforms are required to be invertible, so there isn't any need for it; you can safely use `inverse` in all circumstances.
Transforms of any types can be multiplied. When two transforms of different types are multiplied, the resulting transform type is determined by taking the most specific type that both original types can be cast to. For example, an `Orthonormal` transform multiplied by a `Translation` returns an `Isometry`.
@ -102,4 +105,4 @@ To remember the distinction between the two addition operators, the dot is alway
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. These may feel like arbitrary restrictions, but you might be surprised by how convenient they are to work with!
[Previous](VectorsMatrices.md) | [Contents](Intro.md)
[Previous](VectorsMatrices.md) | [Contents](Contents.md)

View file

@ -4,7 +4,7 @@ As linear algebra is one of the main concerns of NumIdr, most of its provided fu
## 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`:
A linear algebra library wouldn't be very useful without matrix multiplication! Since `(*)` is already used for element-wise multiplication, NumIdr defines a new interface `Mult`:
```idris
interface Mult a b c where
@ -21,7 +21,7 @@ The generalized multiplication operator `(*.)` covers matrix multiplication, sca
### Algebraic Operations
Vectors can be added together with `(+)`, which performs element-wise addition. Scalar-vector multiplication is done with the generalized multiplication operator `(*.)`.
Vectors can be added together with element-wise addition `(+)`. Scalar-vector multiplication is done with the generalized multiplication operator `(*.)`.
```idris
2 *. (vector [1, 1] + vector [2, 3])
@ -104,11 +104,8 @@ decompLUP : FieldCmp a => (mat : Matrix m n a) -> DecompLUP mat
- `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)
```
> [!TIP]
> The `det` and `solve` operations require computing an LUP decomposition, which can be expensive. The variants `detWithLUP` and `solveWithLUP` allow an existing LUP decomposition to be passed in, which can make your code more efficient.
### Indexing
@ -118,4 +115,4 @@ Aside from the usual array indexing functions, there are a few functions special
- `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)
[Previous](Operations.md) | [Contents](Contents.md) | [Next](Transforms.md)