From d7c291151f22d9684ffe6d52563adf6a068d3443 Mon Sep 17 00:00:00 2001 From: Dan Wilhelm Date: Mon, 16 Dec 2019 18:13:33 -0800 Subject: [PATCH] Update to ndarray 0.13 (#560) --- Cargo.toml | 2 +- src/science/mathematics/linear_algebra.md | 4 +- .../linear_algebra/add-matrices.md | 12 ++++- .../multiply-scalar-vector-matrix.md | 20 +++++--- .../linear_algebra/vector-comparison.md | 50 ++++++++++++++++++ .../mathematics/linear_algebra/vector-norm.md | 30 ++++++----- .../mathematics/linear_algebra/vector-sum.md | 51 ------------------- 7 files changed, 92 insertions(+), 77 deletions(-) create mode 100644 src/science/mathematics/linear_algebra/vector-comparison.md delete mode 100644 src/science/mathematics/linear_algebra/vector-sum.md diff --git a/Cargo.toml b/Cargo.toml index a6ba7fe..9f33df9 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ log4rs = "0.8" memmap = "0.7" mime = "0.3" nalgebra = "0.16.12" -ndarray = "0.12" +ndarray = { version = "0.13", features = ["approx"] } num = "0.2" num_cpus = "1.8" percent-encoding = "2.1" diff --git a/src/science/mathematics/linear_algebra.md b/src/science/mathematics/linear_algebra.md index f6e4644..bc339c0 100644 --- a/src/science/mathematics/linear_algebra.md +++ b/src/science/mathematics/linear_algebra.md @@ -1,10 +1,10 @@ # Linear Algebra -{{#include linear_algebra/vector-sum.md}} -{{#include linear_algebra/vector-norm.md}} {{#include linear_algebra/add-matrices.md}} {{#include linear_algebra/multiply-matrices.md}} {{#include linear_algebra/multiply-scalar-vector-matrix.md}} +{{#include linear_algebra/vector-comparison.md}} +{{#include linear_algebra/vector-norm.md}} {{#include linear_algebra/invert-matrix.md}} {{#include ../../links.md}} diff --git a/src/science/mathematics/linear_algebra/add-matrices.md b/src/science/mathematics/linear_algebra/add-matrices.md index 18b505b..f223b68 100644 --- a/src/science/mathematics/linear_algebra/add-matrices.md +++ b/src/science/mathematics/linear_algebra/add-matrices.md @@ -1,7 +1,9 @@ ## Adding matrices [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] -Creates two matrices with [`ndarray::arr2`] and adds them together. +Creates two 2-D matrices with [`ndarray::arr2`] and sums them element-wise. + +Note the sum is computed as `let sum = &a + &b`. The `&` operator is used to avoid consuming `a` and `b`, making them available later for display. A new array is created containing their sum. ```rust extern crate ndarray; @@ -15,7 +17,13 @@ fn main() { let b = arr2(&[[6, 5, 4], [3, 2, 1]]); - println!("Sum: {}", a + b); + let sum = &a + &b; + + println!("{}", a); + println!("+"); + println!("{}", b); + println!("="); + println!("{}", sum); } ``` diff --git a/src/science/mathematics/linear_algebra/multiply-scalar-vector-matrix.md b/src/science/mathematics/linear_algebra/multiply-scalar-vector-matrix.md index c7bbda2..2beed7c 100644 --- a/src/science/mathematics/linear_algebra/multiply-scalar-vector-matrix.md +++ b/src/science/mathematics/linear_algebra/multiply-scalar-vector-matrix.md @@ -2,14 +2,18 @@ [![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science] Creates a 1-D array (vector) with [`ndarray::arr1`] and a 2-D array (matrix) -with [`ndarray::arr2`]. First, a scalar is multiplied by the vector to get +with [`ndarray::arr2`]. + +First, a scalar is multiplied by the vector to get another vector. Then, the matrix is multiplied by the new vector with -[`ndarray::Array2::dot`]. (`dot` performs matrix multiplication, while the `*` -operator performs element-wise multiplication.) In `ndarray`, 1-D arrays can be -interpreted as either row or column vectors depending on context. If -representing the orientation of a vector is important, a 2-D array with one row -or one column must be used instead. In this example, the vector is a 1-D array -on the right-hand side, so `dot` handles it as a column vector. +[`ndarray::Array2::dot`]. (Matrix multiplication is performed using `dot`, while +the `*` operator performs element-wise multiplication.) + +In `ndarray`, 1-D arrays can be interpreted as either row or column vectors +depending on context. If representing the orientation of a vector is important, +a 2-D array with one row or one column must be used instead. In this example, +the vector is a 1-D array on the right-hand side, so `dot` handles it as a column +vector. ```rust extern crate ndarray; @@ -32,6 +36,6 @@ fn main() { } ``` -[`ndarray::Array2::dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1 [`ndarray::arr1`]: https://docs.rs/ndarray/*/ndarray/fn.arr1.html [`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.html +[`ndarray::Array2::dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot-1 \ No newline at end of file diff --git a/src/science/mathematics/linear_algebra/vector-comparison.md b/src/science/mathematics/linear_algebra/vector-comparison.md new file mode 100644 index 0000000..0078731 --- /dev/null +++ b/src/science/mathematics/linear_algebra/vector-comparison.md @@ -0,0 +1,50 @@ +## Vector comparison +[![ndarray-badge]][ndarray] + +The [ndarray] crate supports a number of ways to create arrays -- this recipe creates +[`ndarray::Array`]s from `std::Vec` using `from`. Then, it sums the arrays element-wise. + +This recipe contains an example of comparing two floating-point vectors element-wise. +Floating-point numbers are often stored inexactly, making exact comparisons difficult. +However, the [`assert_abs_diff_eq!`] macro from the [`approx`] crate allows for convenient +element-wise comparisons. To use the `approx` crate with `ndarray`, the `approx` +feature must be added to the `ndarray` dependency in `Cargo.toml`. For example, +`ndarray = { version = "0.13", features = ["approx"] }`. + +This recipe also contains additional ownership examples. Here, `let z = a + b` consumes +`a` and `b`, updates `a` with the result, then moves ownership to `z`. Alternatively, +`let w = &c + &d` creates a new vector without consuming `c` or `d`, allowing +their modification later. See [Binary Operators With Two Arrays] for additional detail. + +```rust +#[macro_use(assert_abs_diff_eq)] +extern crate approx; +extern crate ndarray; + +use ndarray::Array; + +fn main() { + let a = Array::from(vec![1., 2., 3., 4., 5.]); + let b = Array::from(vec![5., 4., 3., 2., 1.]); + let mut c = Array::from(vec![1., 2., 3., 4., 5.]); + let mut d = Array::from(vec![5., 4., 3., 2., 1.]); + + let z = a + b; + let w = &c + &d; + + assert_abs_diff_eq!(z, Array::from(vec![6., 6., 6., 6., 6.])); + + println!("c = {}", c); + c[0] = 10.; + d[1] = 10.; + + assert_abs_diff_eq!(w, Array::from(vec![6., 6., 6., 6., 6.])); + +} +``` + +[`approx`]: https://docs.rs/approx/*/approx/index.html +[`assert_abs_diff_eq!`]: https://docs.rs/approx/*/approx/macro.assert_abs_diff_eq.html +[Binary Operators With Two Arrays]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#binary-operators-with-two-arrays +[ndarray]: https://docs.rs/crate/ndarray/* +[`ndarray::Array`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html diff --git a/src/science/mathematics/linear_algebra/vector-norm.md b/src/science/mathematics/linear_algebra/vector-norm.md index a997c1c..b1988fc 100644 --- a/src/science/mathematics/linear_algebra/vector-norm.md +++ b/src/science/mathematics/linear_algebra/vector-norm.md @@ -1,26 +1,30 @@ -## Vector Norm +## Vector norm [![ndarray-badge]][ndarray] This recipe demonstrates use of the [`Array1`] type, [`ArrayView1`] type, [`fold`] method, and [`dot`] method in computing the [l1] and [l2] norms of a -given vector. The l2 norm calculation is the simpler of the two, as it is the -square root of the dot product of a vector with itself, shown in the function -`l2_norm`. The l1 norm, shown in the function `l1_norm`, is computed by a `fold` +given vector. ++ The `l2_norm` function is the simpler of the two, as it computes the +square root of the dot product of a vector with itself. ++ The `l1_norm` function is computed by a `fold` operation that sums the absolute values of the elements. (This could also be performed with `x.mapv(f64::abs).scalar_sum()`, but that would allocate a new array for the result of the `mapv`.) Note that both `l1_norm` and `l2_norm` take the [`ArrayView1`] type. This recipe -considers vector norms, so the norm functions only need to accept one -dimensional views (hence [`ArrayView1`]). While the functions could take a +considers vector norms, so the norm functions only need to accept one-dimensional +views (hence [`ArrayView1`]). While the functions could take a parameter of type `&Array1` instead, that would require the caller to have a reference to an owned array, which is more restrictive than just having access to a view (since a view can be created from any array or view, not just an owned -array). The most convenient argument type for the caller would be -`&ArrayBase where S: Data`, because then the caller could use `&array` -or `&view` instead of `x.view()`. If the function is part of your public API, -that may be a better choice for the benefit of your users, but for internal -functions, the more concise `ArrayView1` may be preferable. +array). + +`Array` and `ArrayView` are both type aliases for `ArrayBase`. So, the most +general argument type for the caller would be `&ArrayBase where S: Data`, +because then the caller could use `&array` or `&view` instead of `x.view()`. +If the function is part of a public API, that may be a better choice for the +benefit of users. For internal functions, the more concise `ArrayView1` +may be preferable. ```rust #[macro_use(array)] @@ -50,9 +54,9 @@ fn main() { } ``` -[l1]: http://mathworld.wolfram.com/L1-Norm.html -[l2]: http://mathworld.wolfram.com/L2-Norm.html [`Array1`]: https://docs.rs/ndarray/*/ndarray/type.Array1.html [`ArrayView1`]: https://docs.rs/ndarray/*/ndarray/type.ArrayView1.html [`dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot [`fold`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.fold +[l1]: http://mathworld.wolfram.com/L1-Norm.html +[l2]: http://mathworld.wolfram.com/L2-Norm.html \ No newline at end of file diff --git a/src/science/mathematics/linear_algebra/vector-sum.md b/src/science/mathematics/linear_algebra/vector-sum.md deleted file mode 100644 index eaffdb4..0000000 --- a/src/science/mathematics/linear_algebra/vector-sum.md +++ /dev/null @@ -1,51 +0,0 @@ -## Vector Sum -[![ndarray-badge]][ndarray] - -The [ndarray] crate supports a number of ways to create arrays -- this recipe -focuses on creating [`ndarray::Array`]s from `std::Vec` via [`from_vec`]. Adding two -arrays together is no different than adding two numbers together. Using the `&` -operand on the arrays within an arithmetic operation prevents the operation from -consuming the arrays. Without `&`, the arrays are consumed. - -In the first example, arrays `a` and `b` are moved in the let-statement `z = a + -b`. In the second example, the arrays `c` and `d` are not moved and instead, a -new array is created for `w`. Updating either of `c` or `d` after the vector sum -has no effect the value of `w`. Additionally, while printing `c` works as -expected, it would be an error to print `b` due to the move. See [Binary -Operators With Two Arrays] for additional detail. - -```rust -extern crate ndarray; -use ndarray::Array; - -fn main() { - let a = Array::from_vec(vec![1., 2., 3., 4., 5.]); - let b = Array::from_vec(vec![5., 4., 3., 2., 1.]); - let mut c = Array::from_vec(vec![1., 2., 3., 4., 5.]); - let mut d = Array::from_vec(vec![5., 4., 3., 2., 1.]); - - let z = a + b; - let w = &c + &d; - - let epsilon = 1e-8; - for elem in z.iter() { - let diff: f32 = *elem - 6.; - assert!(diff.abs() < epsilon); - } - - println!("c = {}", c); - c[0] = 10.; - d[1] = 10.; - - for elem in w.iter() { - let diff: f32 = *elem - 6.; - assert!(diff.abs() < epsilon); - } - -} -``` - -[Binary Operators With Two Arrays]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#binary-operators-with-two-arrays -[`from_vec`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.from_vec -[ndarray]: https://docs.rs/crate/ndarray/* -[`ndarray::Array`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html