mirror of
https://github.com/rust-lang-nursery/rust-cookbook
synced 2024-11-25 04:50:21 +00:00
Update to ndarray 0.13 (#560)
This commit is contained in:
parent
3fcb08bee2
commit
d7c291151f
7 changed files with 92 additions and 77 deletions
|
@ -29,7 +29,7 @@ log4rs = "0.8"
|
||||||
memmap = "0.7"
|
memmap = "0.7"
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
nalgebra = "0.16.12"
|
nalgebra = "0.16.12"
|
||||||
ndarray = "0.12"
|
ndarray = { version = "0.13", features = ["approx"] }
|
||||||
num = "0.2"
|
num = "0.2"
|
||||||
num_cpus = "1.8"
|
num_cpus = "1.8"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
# Linear Algebra
|
# Linear Algebra
|
||||||
|
|
||||||
{{#include linear_algebra/vector-sum.md}}
|
|
||||||
{{#include linear_algebra/vector-norm.md}}
|
|
||||||
{{#include linear_algebra/add-matrices.md}}
|
{{#include linear_algebra/add-matrices.md}}
|
||||||
{{#include linear_algebra/multiply-matrices.md}}
|
{{#include linear_algebra/multiply-matrices.md}}
|
||||||
{{#include linear_algebra/multiply-scalar-vector-matrix.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 linear_algebra/invert-matrix.md}}
|
||||||
|
|
||||||
{{#include ../../links.md}}
|
{{#include ../../links.md}}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
## Adding matrices
|
## Adding matrices
|
||||||
[![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science]
|
[![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
|
```rust
|
||||||
extern crate ndarray;
|
extern crate ndarray;
|
||||||
|
@ -15,7 +17,13 @@ fn main() {
|
||||||
let b = arr2(&[[6, 5, 4],
|
let b = arr2(&[[6, 5, 4],
|
||||||
[3, 2, 1]]);
|
[3, 2, 1]]);
|
||||||
|
|
||||||
println!("Sum: {}", a + b);
|
let sum = &a + &b;
|
||||||
|
|
||||||
|
println!("{}", a);
|
||||||
|
println!("+");
|
||||||
|
println!("{}", b);
|
||||||
|
println!("=");
|
||||||
|
println!("{}", sum);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,18 @@
|
||||||
[![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science]
|
[![ndarray-badge]][ndarray] [![cat-science-badge]][cat-science]
|
||||||
|
|
||||||
Creates a 1-D array (vector) with [`ndarray::arr1`] and a 2-D array (matrix)
|
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
|
another vector. Then, the matrix is multiplied by the new vector with
|
||||||
[`ndarray::Array2::dot`]. (`dot` performs matrix multiplication, while the `*`
|
[`ndarray::Array2::dot`]. (Matrix multiplication is performed using `dot`, while
|
||||||
operator performs element-wise multiplication.) In `ndarray`, 1-D arrays can be
|
the `*` operator performs element-wise multiplication.)
|
||||||
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
|
In `ndarray`, 1-D arrays can be interpreted as either row or column vectors
|
||||||
or one column must be used instead. In this example, the vector is a 1-D array
|
depending on context. If representing the orientation of a vector is important,
|
||||||
on the right-hand side, so `dot` handles it as a column vector.
|
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
|
```rust
|
||||||
extern crate ndarray;
|
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::arr1`]: https://docs.rs/ndarray/*/ndarray/fn.arr1.html
|
||||||
[`ndarray::arr2`]: https://docs.rs/ndarray/*/ndarray/fn.arr2.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
|
50
src/science/mathematics/linear_algebra/vector-comparison.md
Normal file
50
src/science/mathematics/linear_algebra/vector-comparison.md
Normal file
|
@ -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
|
|
@ -1,26 +1,30 @@
|
||||||
## Vector Norm
|
## Vector norm
|
||||||
[![ndarray-badge]][ndarray]
|
[![ndarray-badge]][ndarray]
|
||||||
|
|
||||||
This recipe demonstrates use of the [`Array1`] type, [`ArrayView1`] type,
|
This recipe demonstrates use of the [`Array1`] type, [`ArrayView1`] type,
|
||||||
[`fold`] method, and [`dot`] method in computing the [l1] and [l2] norms of a
|
[`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
|
given vector.
|
||||||
square root of the dot product of a vector with itself, shown in the function
|
+ The `l2_norm` function is the simpler of the two, as it computes the
|
||||||
`l2_norm`. The l1 norm, shown in the function `l1_norm`, is computed by a `fold`
|
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
|
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
|
performed with `x.mapv(f64::abs).scalar_sum()`, but that would allocate a new
|
||||||
array for the result of the `mapv`.)
|
array for the result of the `mapv`.)
|
||||||
|
|
||||||
Note that both `l1_norm` and `l2_norm` take the [`ArrayView1`] type. This recipe
|
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
|
considers vector norms, so the norm functions only need to accept one-dimensional
|
||||||
dimensional views (hence [`ArrayView1`]). While the functions could take a
|
views (hence [`ArrayView1`]). While the functions could take a
|
||||||
parameter of type `&Array1<f64>` instead, that would require the caller to have
|
parameter of type `&Array1<f64>` instead, that would require the caller to have
|
||||||
a reference to an owned array, which is more restrictive than just having access
|
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
|
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
|
array).
|
||||||
`&ArrayBase<S, Ix1> 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,
|
`Array` and `ArrayView` are both type aliases for `ArrayBase`. So, the most
|
||||||
that may be a better choice for the benefit of your users, but for internal
|
general argument type for the caller would be `&ArrayBase<S, Ix1> where S: Data`,
|
||||||
functions, the more concise `ArrayView1<f64>` may be preferable.
|
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<f64>`
|
||||||
|
may be preferable.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use(array)]
|
#[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
|
[`Array1`]: https://docs.rs/ndarray/*/ndarray/type.Array1.html
|
||||||
[`ArrayView1`]: https://docs.rs/ndarray/*/ndarray/type.ArrayView1.html
|
[`ArrayView1`]: https://docs.rs/ndarray/*/ndarray/type.ArrayView1.html
|
||||||
[`dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot
|
[`dot`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.dot
|
||||||
[`fold`]: https://docs.rs/ndarray/*/ndarray/struct.ArrayBase.html#method.fold
|
[`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
|
|
@ -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
|
|
Loading…
Reference in a new issue