From 8903575d8b3a2fa1acc1bc62d6762397cedb0345 Mon Sep 17 00:00:00 2001 From: Kiana Sheibani Date: Mon, 6 May 2024 04:55:50 -0400 Subject: [PATCH] Fix various guide issues --- README.md | 2 +- docs/{Main.md => Contents.md} | 0 docs/DataTypes.md | 5 +---- docs/Operations.md | 25 ++++++++++++------------- docs/Transforms.md | 19 +++++++++++-------- docs/VectorsMatrices.md | 13 +++++-------- 6 files changed, 30 insertions(+), 34 deletions(-) rename docs/{Main.md => Contents.md} (100%) diff --git a/README.md b/README.md index 02d4de3..9e77ec6 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/Main.md b/docs/Contents.md similarity index 100% rename from docs/Main.md rename to docs/Contents.md diff --git a/docs/DataTypes.md b/docs/DataTypes.md index 749aeea..58adf25 100644 --- a/docs/DataTypes.md +++ b/docs/DataTypes.md @@ -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) diff --git a/docs/Operations.md b/docs/Operations.md index a2e6af8..bb25582 100644 --- a/docs/Operations.md +++ b/docs/Operations.md @@ -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) diff --git a/docs/Transforms.md b/docs/Transforms.md index 0f36860..1b3271c 100644 --- a/docs/Transforms.md +++ b/docs/Transforms.md @@ -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) diff --git a/docs/VectorsMatrices.md b/docs/VectorsMatrices.md index fec2e3f..8073d94 100644 --- a/docs/VectorsMatrices.md +++ b/docs/VectorsMatrices.md @@ -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)