Skip to content

Commit

Permalink
Merge branch 'rust-ndarray:master' into zip_any
Browse files Browse the repository at this point in the history
  • Loading branch information
Nil Goyette committed Jul 8, 2023
2 parents 5e8ebc2 + 9447328 commit 43fe8dc
Show file tree
Hide file tree
Showing 21 changed files with 269 additions and 117 deletions.
31 changes: 11 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ jobs:
- 1.51.0 # MSRV

steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- uses: Swatinem/rust-cache@v2
- name: Install openblas
run: sudo apt-get install libopenblas-dev gfortran
- run: ./scripts/all-tests.sh "$FEATURES" ${{ matrix.rust }}
Expand All @@ -45,20 +44,14 @@ jobs:
target: i686-unknown-linux-gnu

steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.rust }}
target: ${{ matrix.target }}
override: true
- name: Cache cargo plugins
uses: actions/cache@v1
with:
path: ~/.cargo/bin/
key: ${{ runner.os }}-cargo-plugins
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- name: Install cross
run: cargo install cross || true
run: cargo install cross
- run: ./scripts/cross-tests.sh "docs" ${{ matrix.rust }} ${{ matrix.target }}

clippy:
Expand All @@ -68,12 +61,10 @@ jobs:
rust:
- beta
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
components: clippy
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --features docs

8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ rayon = ["rayon_", "std"]

matrixmultiply-threading = ["matrixmultiply/threading"]

[profile.release]
[profile.bench]
debug = true
[profile.dev.package.numeric-tests]
opt-level = 2
[profile.test.package.numeric-tests]
opt-level = 2

[workspace]
members = ["ndarray-rand", "xtest-serialization", "xtest-blas"]
exclude = ["xtest-numeric"]
members = ["ndarray-rand", "xtest-serialization", "xtest-blas", "xtest-numeric"]

[package.metadata.release]
no-dev-version = true
Expand Down
63 changes: 25 additions & 38 deletions README-quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ You can use [play.integer32.com](https://play.integer32.com/) to immediately try

## The Basics

Just create your first 2x3 floating-point ndarray
You can create your first 2x3 floating-point ndarray as such:
```rust
use ndarray::prelude::*;

Expand All @@ -24,7 +24,7 @@ fn main() {
println!("{:?}", a);
}
```
This code will create a simple array and output to stdout:
This code will create a simple array, then print it to stdout as such:
```
[[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]], shape=[2, 3], strides=[3, 1], layout=C (0x1), const ndim=2
Expand All @@ -34,8 +34,7 @@ This code will create a simple array and output to stdout:

### Element type and dimensionality

Now let's create more arrays. How about try make a zero array with dimension of (3, 2, 4)?

Now let's create more arrays. A common operation on matrices is to create a matrix full of 0's of certain dimensions. Let's try to do that with dimensions (3, 2, 4) using the `Array::zeros` function:
```rust
use ndarray::prelude::*;
use ndarray::Array;
Expand All @@ -44,13 +43,13 @@ fn main() {
println!("{:?}", a);
}
```
gives
Unfortunately, this code does not compile.
```
| let a = Array::zeros((3, 2, 4).f());
| - ^^^^^^^^^^^^ cannot infer type for type parameter `A`
```
Note that the compiler needs to infer the element type and dimensionality from context. In this
case the compiler failed to do that. Now we give it the type and let it infer dimensionality
Indeed, note that the compiler needs to infer the element type and dimensionality from context only. In this
case the compiler does not have enough information. To fix the code, we can explicitly give the element type through turbofish syntax, and let it infer the dimensionality type:

```rust
use ndarray::prelude::*;
Expand All @@ -60,7 +59,7 @@ fn main() {
println!("{:?}", a);
}
```
and now it works:
This code now compiles to what we wanted:
```
[[[0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0]],
Expand All @@ -72,24 +71,11 @@ and now it works:
[0.0, 0.0, 0.0, 0.0]]], shape=[3, 2, 4], strides=[1, 3, 6], layout=F (0x2), const ndim=3
```

We can also specify its dimensionality
We could also specify its dimensionality explicitly `Array::<f64, Ix3>::zeros(...)`, with`Ix3` standing for 3D array type. Phew! We achieved type safety. If you tried changing the code above to `Array::<f64, Ix3>::zeros((3, 2, 4, 5).f());`, which is not of dimension 3 anymore, Rust's type system would gracefully prevent you from compiling the code.

```rust
use ndarray::prelude::*;
use ndarray::{Array, Ix3};
fn main() {
let a = Array::<f64, Ix3>::zeros((3, 2, 4).f());
println!("{:?}", a);
}
```
`Ix3` stands for 3D array.

And now we are type checked. Try change the code above to `Array::<f64, Ix3>::zeros((3, 2, 4, 5).f());`
and compile, see what happens.

### How about create array of different type and having different initial values?
### Creating arrays with different initial values and/or different types

The [`from_elem`](http://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.from_elem) method can be handy here:
The [`from_elem`](http://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.from_elem) method allows initializing an array of given dimension to a specific value of any type:

```rust
use ndarray::{Array, Ix3};
Expand All @@ -99,7 +85,7 @@ fn main() {
}
```

### Some common create helper functions
### Some common array initializing helper functions
`linspace` - Create a 1-D array with 11 elements with values 0., …, 5.
```rust
use ndarray::prelude::*;
Expand All @@ -114,10 +100,11 @@ The output is:
[0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], shape=[11], strides=[1], layout=C | F (0x3), const ndim=1
```

And there are also `range`, `logspace`, `ones`, `eye` and so on you can choose to use.
Common array initializing methods include [`range`](https://docs.rs/ndarray/0.13.0/ndarray/struct.ArrayBase.html#method.range), [`logspace`](https://docs.rs/ndarray/0.13.0/ndarray/struct.ArrayBase.html#method.logspace), [`eye`](https://docs.rs/ndarray/0.13.0/ndarray/struct.ArrayBase.html#method.eye), [`ones`](https://docs.rs/ndarray/0.13.0/ndarray/struct.ArrayBase.html#method.ones)...

## Basic operations

Basic operations on arrays are all element-wise; you need to use specific methods for operations such as matrix multiplication (see later section).
```rust
use ndarray::prelude::*;
use ndarray::Array;
Expand All @@ -136,16 +123,19 @@ fn main() {
}
```

Try remove all the `&` sign in front of `a` and `b`, does it still compile? Why?

Note that
Note that (for any binary operator `@`):
* `&A @ &A` produces a new `Array`
* `B @ A` consumes `B`, updates it with the result, and returns it
* `B @ &A` consumes `B`, updates it with the result, and returns it
* `C @= &A` performs an arithmetic operation in place

Try removing all the `&` sign in front of `a` and `b` in the last example: it will not compile anymore because of those rules.

For more info checkout https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#arithmetic-operations



Some operations have `_axis` appended to the function name: they generally take in a parameter of type `Axis` as one of their inputs,
such as `sum_axis`:

Expand Down Expand Up @@ -237,7 +227,7 @@ The output is:

For more info about iteration see [Loops, Producers, and Iterators](https://docs.rs/ndarray/0.13.0/ndarray/struct.ArrayBase.html#loops-producers-and-iterators)

Let's try a 3D array with elements of type `isize`. This is how you index it:
Let's try a iterating over a 3D array with elements of type `isize`. This is how you index it:
```rust
use ndarray::prelude::*;

Expand All @@ -250,8 +240,8 @@ fn main() {
[110,112,113]]
];

let a = a.mapv(|a: isize| a.pow(1)); // numpy equivlant of `a ** 1`;
// This line does nothing but illustrate mapv with isize type
let a = a.mapv(|a: isize| a.pow(1)); // numpy equivalent of `a ** 1`;
// This line does nothing except illustrating mapv with isize type
println!("a -> \n{}\n", a);

println!("`a.slice(s![1, .., ..])` -> \n{}\n", a.slice(s![1, .., ..]));
Expand Down Expand Up @@ -461,11 +451,8 @@ s2 =

## Copies and Views
### View, Ref or Shallow Copy
As in Rust we have owner ship, so we cannot simply
update an element of an array while we have a
shared view of it. This will help us write more
robust code.

Rust has ownership, so we cannot simply update an element of an array while we have a shared view of it. This brings guarantees & helps having more robust code.
```rust
use ndarray::prelude::*;
use ndarray::{Array, Axis};
Expand Down Expand Up @@ -566,9 +553,9 @@ b clone of a =
[2, 3]]
```

Noticing that using `clone()` (or cloning) an `Array` type also copies the array's elements. It creates an independently owned array of the same type.
Notice that using `clone()` (or cloning) an `Array` type also copies the array's elements. It creates an independently owned array of the same type.

Cloning an `ArrayView` does not clone or copy the underlying elements - it just clones the view reference (as it happens in Rust when cloning a `&` reference).
Cloning an `ArrayView` does not clone or copy the underlying elements - it only clones the view reference (as it happens in Rust when cloning a `&` reference).

## Broadcasting

Expand Down Expand Up @@ -600,7 +587,7 @@ fn main() {

See [.broadcast()](https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.broadcast) for a more detailed description.

And there is a short example of it:
And here is a short example of it:
```rust
use ndarray::prelude::*;

Expand Down
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ your `Cargo.toml`.
- Enables parallel iterators, parallelized methods and ``par_azip!``.
- Implies std

- ``approx``

- Implementations of traits from version 0.4 of the [`approx`] crate.

- ``approx-0_5``

- Implementations of traits from version 0.5 of the [`approx`] crate.

- ``blas``

- Enable transparent BLAS support for matrix multiplication.
Expand Down
14 changes: 12 additions & 2 deletions scripts/all-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ set -e
FEATURES=$1
CHANNEL=$2

if [ "$CHANNEL" = "1.51.0" ]; then
cargo update --package rayon --precise 1.5.3
cargo update --package rayon-core --precise 1.9.3
cargo update --package serde --precise 1.0.156
cargo update --package thiserror --precise 1.0.39
cargo update --package once_cell --precise 1.14.0
cargo update --package openblas-src --precise 0.10.5
cargo update --package openblas-build --precise 0.10.5
fi

cargo build --verbose --no-default-features
# Testing both dev and release profiles helps find bugs, especially in low level code
cargo test --verbose --no-default-features
Expand All @@ -17,6 +27,6 @@ cargo test --manifest-path=ndarray-rand/Cargo.toml --features quickcheck --verbo
cargo test --manifest-path=xtest-serialization/Cargo.toml --verbose
cargo test --manifest-path=xtest-blas/Cargo.toml --verbose --features openblas-system
cargo test --examples
CARGO_TARGET_DIR=target/ cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose
CARGO_TARGET_DIR=target/ cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose --features test_blas
cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose
cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose --features test_blas
([ "$CHANNEL" != "nightly" ] || cargo bench --no-run --verbose --features "$FEATURES")
2 changes: 1 addition & 1 deletion scripts/cross-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ cross build -v --features="$FEATURES" --target=$TARGET
cross test -v --no-fail-fast --features="$FEATURES" --target=$TARGET
cross test -v --no-fail-fast --target=$TARGET --manifest-path=ndarray-rand/Cargo.toml --features quickcheck
cross test -v --no-fail-fast --target=$TARGET --manifest-path=xtest-serialization/Cargo.toml --verbose
CARGO_TARGET_DIR=target/ cross test -v --no-fail-fast --target=$TARGET --manifest-path=xtest-numeric/Cargo.toml
cross test -v --no-fail-fast --target=$TARGET --manifest-path=xtest-numeric/Cargo.toml
2 changes: 1 addition & 1 deletion src/arraytraits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ where
{
}

#[cfg(any(feature = "serde"))]
#[cfg(feature = "serde")]
// Use version number so we can add a packed format later.
pub const ARRAY_FORMAT_VERSION: u8 = 1u8;

Expand Down
6 changes: 3 additions & 3 deletions src/dimension/dimension_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub trait Dimension:

/// Compute the size of the dimension (number of elements)
fn size(&self) -> usize {
self.slice().iter().fold(1, |s, &a| s * a as usize)
self.slice().iter().product()
}

/// Compute the size while checking for overflow.
Expand Down Expand Up @@ -603,7 +603,7 @@ impl Dimension for Dim<[Ix; 2]> {
fn size_checked(&self) -> Option<usize> {
let m = get!(self, 0);
let n = get!(self, 1);
(m as usize).checked_mul(n as usize)
m.checked_mul(n)
}

#[inline]
Expand Down Expand Up @@ -728,7 +728,7 @@ impl Dimension for Dim<[Ix; 3]> {
let m = get!(self, 0);
let n = get!(self, 1);
let o = get!(self, 2);
m as usize * n as usize * o as usize
m * n * o
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/dimension/dynindeximpl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ impl<T: PartialEq> PartialEq for IxDynRepr<T> {
match (self, rhs) {
(&IxDynRepr::Inline(slen, ref sarr), &IxDynRepr::Inline(rlen, ref rarr)) => {
slen == rlen
&& (0..CAP as usize)
&& (0..CAP)
.filter(|&i| i < slen as usize)
.all(|i| sarr[i] == rarr[i])
}
Expand Down
2 changes: 1 addition & 1 deletion src/dimension/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ mod sequence;
/// Calculate offset from `Ix` stride converting sign properly
#[inline(always)]
pub fn stride_offset(n: Ix, stride: Ix) -> isize {
(n as isize) * ((stride as Ixs) as isize)
(n as isize) * (stride as Ixs)
}

/// Check whether the given `dim` and `stride` lead to overlapping indices
Expand Down
3 changes: 3 additions & 0 deletions src/doc/ndarray_for_numpy_users/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@
//! `a[-5:]` or `a[-5:, :]` | [`a.slice(s![-5.., ..])`][.slice()] or [`a.slice_axis(Axis(0), Slice::from(-5..))`][.slice_axis()] | get the last 5 rows of a 2-D array
//! `a[:3, 4:9]` | [`a.slice(s![..3, 4..9])`][.slice()] | columns 4, 5, 6, 7, and 8 of the first 3 rows
//! `a[1:4:2, ::-1]` | [`a.slice(s![1..4;2, ..;-1])`][.slice()] | rows 1 and 3 with the columns in reverse order
//! `a.take([4, 2])` | `a.select(Axis(0), &[4, 2])` | rows 4 and 2 of the array
//!
//! ## Shape and strides
//!
Expand Down Expand Up @@ -531,6 +532,8 @@
//! ------|-----------|------
//! `a[:] = 3.` | [`a.fill(3.)`][.fill()] | set all array elements to the same scalar value
//! `a[:] = b` | [`a.assign(&b)`][.assign()] | copy the data from array `b` into array `a`
//! `a[:5, 2] = 3.` | [`a.slice_mut(s![..5, 2]).fill(3.)`][.fill()] | set a portion of the array to the same scalar value
//! `a[:5, 2] = b` | [`a.slice_mut(s![..5, 2]).assign(&b)`][.assign()] | copy the data from array `b` into part of array `a`
//! `np.concatenate((a,b), axis=1)` | [`concatenate![Axis(1), a, b]`][concatenate!] or [`concatenate(Axis(1), &[a.view(), b.view()])`][concatenate()] | concatenate arrays `a` and `b` along axis 1
//! `np.stack((a,b), axis=1)` | [`stack![Axis(1), a, b]`][stack!] or [`stack(Axis(1), vec![a.view(), b.view()])`][stack()] | stack arrays `a` and `b` along axis 1
//! `a[:,np.newaxis]` or `np.expand_dims(a, axis=1)` | [`a.slice(s![.., NewAxis])`][.slice()] or [`a.insert_axis(Axis(1))`][.insert_axis()] | create an view of 1-D array `a`, inserting a new axis 1
Expand Down

0 comments on commit 43fe8dc

Please sign in to comment.