diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index a8194f8ee..13fb9d0d6 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -1,22 +1,41 @@
on:
pull_request:
+ paths-ignore:
+ - '.github/workflows/latest-deps.yaml'
merge_group:
+ push:
+ branches:
+ - master
name: Continuous integration
env:
CARGO_TERM_COLOR: always
HOST: x86_64-unknown-linux-gnu
- FEATURES: "test docs"
+ FEATURES: "approx,serde,rayon"
RUSTFLAGS: "-D warnings"
+ MSRV: 1.64.0
+ BLAS_MSRV: 1.71.1
jobs:
+ pass-msrv:
+ runs-on: ubuntu-latest
+ name: Pass MSRV values to other jobs
+ outputs:
+ MSRV: ${{ env.MSRV }}
+ BLAS_MSRV: ${{ env.BLAS_MSRV }}
+ steps:
+ - name: Pass MSRV
+ run: |
+ echo "MSRV=${{ env.MSRV }}" >> $GITHUB_OUTPUT
+ echo "BLAS_MSRV=${{ env.BLAS_MSRV }}" >> $GITHUB_OUTPUT
+
clippy:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- - beta
+ - stable
name: clippy/${{ matrix.rust }}
steps:
- uses: actions/checkout@v4
@@ -25,7 +44,7 @@ jobs:
toolchain: ${{ matrix.rust }}
components: clippy
- uses: Swatinem/rust-cache@v2
- - run: cargo clippy --features docs
+ - run: cargo clippy --features approx,serde,rayon
format:
runs-on: ubuntu-latest
@@ -42,15 +61,37 @@ jobs:
components: rustfmt
- run: cargo fmt --all --check
+ nostd:
+ runs-on: ubuntu-latest
+ continue-on-error: ${{ matrix.experimental }}
+ strategy:
+ matrix:
+ include:
+ - rust: stable
+ experimental: false
+ target: thumbv6m-none-eabi
+
+ name: nostd/${{ matrix.target }}/${{ matrix.rust }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
+ with:
+ toolchain: ${{ matrix.rust }}
+ targets: ${{ matrix.target }}
+ - name: Tests
+ run: |
+ cargo rustc "--target=${{ matrix.target }}" --no-default-features --features portable-atomic-critical-section
+
tests:
runs-on: ubuntu-latest
+ needs: pass-msrv
strategy:
matrix:
rust:
- stable
- beta
- nightly
- - 1.57.0 # MSRV
+ - ${{ needs.pass-msrv.outputs.MSRV }}
name: tests/${{ matrix.rust }}
steps:
@@ -63,9 +104,37 @@ jobs:
- name: Install openblas
run: sudo apt-get install libopenblas-dev gfortran
- run: ./scripts/all-tests.sh "$FEATURES" ${{ matrix.rust }}
+
+ blas-msrv:
+ runs-on: ubuntu-latest
+ name: blas-msrv
+ needs: pass-msrv
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{ needs.pass-msrv.outputs.BLAS_MSRV }}
+ - uses: rui314/setup-mold@v1
+ - uses: Swatinem/rust-cache@v2
+ - name: Install openblas
+ run: sudo apt-get install libopenblas-dev gfortran
+ - run: cargo tree -p blas-tests -i openblas-src -F blas-tests/openblas-system
+ - run: cargo tree -p blas-tests -i openblas-build -F blas-tests/openblas-system
+ - run: ./scripts/blas-integ-tests.sh $BLAS_MSRV
+
+ miri:
+ runs-on: ubuntu-latest
+ name: miri
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@nightly
+ with:
+ components: miri
+ - uses: Swatinem/rust-cache@v2
+ - run: ./scripts/miri-tests.sh
cross_test:
- if: ${{ github.event_name == 'merge_group' }}
+ #if: ${{ github.event_name == 'merge_group' }}
runs-on: ubuntu-latest
strategy:
matrix:
@@ -86,10 +155,10 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Install cross
run: cargo install cross
- - run: ./scripts/cross-tests.sh "docs" ${{ matrix.rust }} ${{ matrix.target }}
+ - run: ./scripts/cross-tests.sh "approx,serde,rayon" ${{ matrix.rust }} ${{ matrix.target }}
cargo-careful:
- if: ${{ github.event_name == 'merge_group' }}
+ #if: ${{ github.event_name == 'merge_group' }}
runs-on: ubuntu-latest
name: cargo-careful
steps:
@@ -101,28 +170,31 @@ jobs:
- name: Install cargo-careful
run: cargo install cargo-careful
- run: cargo careful test -Zcareful-sanitizer --features="$FEATURES"
- - run: cargo careful test -Zcareful-sanitizer -p ndarray-rand
docs:
- if: ${{ github.event_name == 'merge_group' }}
+ #if: ${{ github.event_name == 'merge_group' }}
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- - stable
+ - nightly # This is what docs.rs runs on, and is needed for the feature flags
name: docs/${{ matrix.rust }}
+ env:
+ RUSTDOCFLAGS: "-Dwarnings --cfg docsrs"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- - run: cargo doc
+ - run: cargo doc --no-deps --all-features
conclusion:
needs:
- clippy
- # - format # should format be required?
+ - format # should format be required?
+ - nostd
- tests
+ - miri
- cross_test
- cargo-careful
- docs
diff --git a/.github/workflows/latest-deps.yaml b/.github/workflows/latest-deps.yaml
new file mode 100644
index 000000000..3b28169ec
--- /dev/null
+++ b/.github/workflows/latest-deps.yaml
@@ -0,0 +1,69 @@
+name: Check Latest Dependencies
+on:
+ schedule:
+ # Chosen so that it runs right before the international date line experiences the weekend.
+ # Since we're open source, that means globally we should be aware of it right when we have the most
+ # time to fix it.
+ #
+ # Sorry if this ruins your weekend, future maintainer...
+ - cron: '0 12 * * FRI'
+ workflow_dispatch: # For running manually
+ pull_request:
+ paths:
+ - '.github/workflows/latest-deps.yaml'
+
+env:
+ CARGO_TERM_COLOR: always
+ HOST: x86_64-unknown-linux-gnu
+ FEATURES: "approx,serde,rayon"
+ RUSTFLAGS: "-D warnings"
+ MSRV: 1.64.0
+ BLAS_MSRV: 1.71.0
+
+jobs:
+ latest_deps_stable:
+ runs-on: ubuntu-latest
+ name: Check Latest Dependencies on Stable
+ steps:
+ - name: Check Out Repo
+ uses: actions/checkout@v4
+ - name: Install Rust
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable
+ - name: Setup Mold Linker
+ uses: rui314/setup-mold@v1
+ - name: Setup Rust Cache
+ uses: Swatinem/rust-cache@v2
+ - name: Install openblas
+ run: sudo apt-get install libopenblas-dev gfortran
+ - name: Ensure latest dependencies
+ run: cargo update
+ - name: Run Tests
+ run: ./scripts/all-tests.sh "$FEATURES" stable
+
+ latest_deps_msrv:
+ runs-on: ubuntu-latest
+ name: Check Latest Dependencies on MSRV
+ steps:
+ - name: Check Out Repo
+ uses: actions/checkout@v4
+ - name: Install Stable Rust for Update
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable
+ - name: Setup Mold Linker
+ uses: rui314/setup-mold@v1
+ - name: Setup Rust Cache
+ uses: Swatinem/rust-cache@v2
+ - name: Install openblas
+ run: sudo apt-get install libopenblas-dev gfortran
+ - name: Ensure latest dependencies
+ # The difference is here between this and `latest_deps_stable`
+ run: CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS="fallback" cargo update
+ - name: Install MSRV Rust for Test
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: ${{ env.MSRV }}
+ - name: Run Tests
+ run: ./scripts/all-tests.sh "$FEATURES" $MSRV
diff --git a/.gitignore b/.gitignore
index 1e7caa9ea..c1885550c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,9 @@
-Cargo.lock
+# Rust items
target/
+
+# Editor settings
+.vscode
+.idea
+
+# Apple details
+**/.DS_Store
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 000000000..057a36d03
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1367 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "accelerate-src"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "415ed64958754dbe991900f3940677e6a7eefb4d7367afd70d642677b0c7d19d"
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "approx"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "blas-mock-tests"
+version = "0.1.0"
+dependencies = [
+ "cblas-sys",
+ "itertools",
+ "ndarray",
+ "ndarray-gen",
+]
+
+[[package]]
+name = "blas-src"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b95e83dc868db96e69795c0213143095f03de9dd3252f205d4ac716e4076a7e0"
+dependencies = [
+ "accelerate-src",
+ "blis-src",
+ "netlib-src",
+ "openblas-src",
+]
+
+[[package]]
+name = "blas-tests"
+version = "0.1.0"
+dependencies = [
+ "approx",
+ "blas-src",
+ "blis-src",
+ "defmac",
+ "itertools",
+ "ndarray",
+ "ndarray-gen",
+ "netlib-src",
+ "num-complex",
+ "num-traits",
+ "openblas-src",
+]
+
+[[package]]
+name = "blis-src"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc119b6761ce8b063102502af49043051f81a9bdf242ae06d12e9ea0d92b727a"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cblas-sys"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6feecd82cce51b0204cf063f0041d69f24ce83f680d87514b004248e7b0fa65"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cmake"
+version = "0.1.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "critical-section"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "defmac"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5592fca31e96d8a748d03080b58be78c5383617aa4bd89e69f30607d8769891"
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "errno"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "filetime"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "279259b0ac81c89d11c290495fdcfa96ea3643b7df311c138b6fe8ca5237f0f8"
+dependencies = [
+ "idna_mapping",
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "idna_mapping"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11c13906586a4b339310541a274dd927aff6fcbb5b8e3af90634c4b31681c792"
+dependencies = [
+ "unicode-joining-type",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "libm"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags",
+ "libc",
+ "redox_syscall",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "matrixmultiply"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
+dependencies = [
+ "autocfg",
+ "num_cpus",
+ "once_cell",
+ "rawpointer",
+ "thread-tree",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "ndarray"
+version = "0.16.1"
+dependencies = [
+ "approx",
+ "cblas-sys",
+ "defmac",
+ "itertools",
+ "libc",
+ "matrixmultiply",
+ "ndarray-gen",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "portable-atomic",
+ "portable-atomic-util",
+ "quickcheck",
+ "rawpointer",
+ "rayon",
+ "serde",
+]
+
+[[package]]
+name = "ndarray-gen"
+version = "0.1.0"
+dependencies = [
+ "ndarray",
+ "num-traits",
+]
+
+[[package]]
+name = "ndarray-rand"
+version = "0.15.0"
+dependencies = [
+ "ndarray",
+ "quickcheck",
+ "rand 0.9.1",
+ "rand_distr",
+ "rand_isaac",
+]
+
+[[package]]
+name = "netlib-src"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39f41f36bb4d46906d5a72da5b73a804d9de1a7282eb7c89617201acda7b8212"
+dependencies = [
+ "cmake",
+]
+
+[[package]]
+name = "num-complex"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "numeric-tests"
+version = "0.1.0"
+dependencies = [
+ "approx",
+ "blas-src",
+ "ndarray",
+ "ndarray-rand",
+ "num-complex",
+ "num-traits",
+ "openblas-src",
+ "rand 0.9.1",
+ "rand_distr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
+
+[[package]]
+name = "openblas-build"
+version = "0.10.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ca8f8c64eb5b43f5538059ccbc71391420bba14d987d7e8ab99ed62ed33e26b"
+dependencies = [
+ "anyhow",
+ "cc",
+ "flate2",
+ "native-tls",
+ "tar",
+ "thiserror 2.0.12",
+ "ureq",
+]
+
+[[package]]
+name = "openblas-src"
+version = "0.10.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "252f22774417be65f908a20f7721a97e33a253acad4f28370408b7f1baea0629"
+dependencies = [
+ "dirs",
+ "openblas-build",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "openssl"
+version = "0.10.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+dependencies = [
+ "critical-section",
+]
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quickcheck"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6"
+dependencies = [
+ "rand 0.8.5",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.3",
+]
+
+[[package]]
+name = "rand_distr"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463"
+dependencies = [
+ "num-traits",
+ "rand 0.9.1",
+]
+
+[[package]]
+name = "rand_isaac"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3382fc9f0aad4f2e2a56b53d9133c8c810b4dbf21e7e370e24346161a5b2c7bd"
+dependencies = [
+ "rand_core 0.9.3",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "rmp"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bddb316f4b9cae1a3e89c02f1926d557d1142d0d2e684b038c11c1b77705229a"
+dependencies = [
+ "byteorder",
+ "num-traits",
+ "paste",
+]
+
+[[package]]
+name = "rmp-serde"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "938a142ab806f18b88a97b0dea523d39e0fd730a064b035726adcfc58a8a5188"
+dependencies = [
+ "byteorder",
+ "rmp",
+ "serde",
+]
+
+[[package]]
+name = "ron"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
+dependencies = [
+ "base64 0.21.7",
+ "bitflags",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "rustix"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5"
+dependencies = [
+ "openssl-probe",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+dependencies = [
+ "zeroize",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "schannel"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serialization-tests"
+version = "0.1.0"
+dependencies = [
+ "ndarray",
+ "rmp",
+ "rmp-serde",
+ "ron",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "smallvec"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tar"
+version = "0.4.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
+dependencies = [
+ "filetime",
+ "libc",
+ "xattr",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl 2.0.12",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread-tree"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630"
+dependencies = [
+ "crossbeam-channel",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unicode-joining-type"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8d00a78170970967fdb83f9d49b92f959ab2bb829186b113e4f4604ad98e180"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "ureq"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
+dependencies = [
+ "base64 0.22.1",
+ "flate2",
+ "log",
+ "native-tls",
+ "once_cell",
+ "rustls-native-certs",
+ "url",
+]
+
+[[package]]
+name = "url"
+version = "2.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "xattr"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e"
+dependencies = [
+ "libc",
+ "rustix",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
diff --git a/Cargo.toml b/Cargo.toml
index 945dc6aa8..14226986e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "ndarray"
-version = "0.15.6"
-edition = "2018"
-rust-version = "1.57"
+version = "0.16.1"
+edition = "2021"
+rust-version = "1.64"
authors = [
"Ulrik Sverdrup \"bluss\"",
"Jim Turner"
@@ -20,6 +20,7 @@ keywords = ["array", "data-structure", "multidimensional", "matrix", "blas"]
categories = ["data-structures", "science"]
exclude = ["docgen/images/*"]
+resolver = "2"
[lib]
name = "ndarray"
@@ -27,17 +28,15 @@ bench = false
test = true
[dependencies]
-num-integer = { version = "0.1.39", default-features = false }
-num-traits = { version = "0.2", default-features = false }
-num-complex = { version = "0.4", default-features = false }
-
-# Use via the `rayon` crate feature!
-rayon_ = { version = "1.0.3", optional = true, package = "rayon" }
+num-integer = { workspace = true }
+num-traits = { workspace = true }
+num-complex = { workspace = true }
-approx = { version = "0.5", optional = true , default-features = false }
+approx = { workspace = true, optional = true }
+rayon = { version = "1.10.0", optional = true }
-# Use via the `blas` crate feature!
-cblas-sys = { version = "0.1.4", optional = true, default-features = false }
+# Use via the `blas` crate feature
+cblas-sys = { workspace = true, optional = true }
libc = { version = "0.2.82", optional = true }
matrixmultiply = { version = "0.3.2", default-features = false, features=["cgemm"] }
@@ -47,44 +46,75 @@ rawpointer = { version = "0.2" }
[dev-dependencies]
defmac = "0.2"
-quickcheck = { version = "1.0", default-features = false }
-approx = "0.5"
-itertools = { version = "0.10.0", default-features = false, features = ["use_std"] }
+quickcheck = { workspace = true }
+approx = { workspace = true, default-features = true }
+itertools = { workspace = true }
+ndarray-gen = { workspace = true }
[features]
default = ["std"]
# Enable blas usage
# See README for more instructions
-blas = ["cblas-sys", "libc"]
-
-# Old name for the serde feature
-serde-1 = ["serde"]
-
-# These features are used for testing
-test = []
+blas = ["dep:cblas-sys", "dep:libc"]
-# This feature is used for docs
-docs = ["approx", "serde", "rayon"]
+serde = ["dep:serde"]
std = ["num-traits/std", "matrixmultiply/std"]
-rayon = ["rayon_", "std"]
+rayon = ["dep:rayon", "std"]
matrixmultiply-threading = ["matrixmultiply/threading"]
+portable-atomic-critical-section = ["portable-atomic/critical-section"]
+
+
+[target.'cfg(not(target_has_atomic = "ptr"))'.dependencies]
+portable-atomic = { version = "1.6.0" }
+portable-atomic-util = { version = "0.2.0", features = [ "alloc" ] }
+
+[workspace]
+members = [
+ "ndarray-rand",
+ "crates/*",
+]
+default-members = [
+ ".",
+ "ndarray-rand",
+ "crates/ndarray-gen",
+ "crates/numeric-tests",
+ "crates/serialization-tests",
+ # exclude blas-tests and blas-mock-tests that activate "blas" feature
+]
+
+[workspace.dependencies]
+ndarray = { version = "0.16", path = ".", default-features = false }
+ndarray-rand = { path = "ndarray-rand" }
+ndarray-gen = { path = "crates/ndarray-gen" }
+
+num-integer = { version = "0.1.39", default-features = false }
+num-traits = { version = "0.2", default-features = false }
+num-complex = { version = "0.4", default-features = false }
+approx = { version = "0.5", default-features = false }
+quickcheck = { version = "1.0", default-features = false }
+rand = { version = "0.9.0", features = ["small_rng"] }
+rand_distr = { version = "0.5.0" }
+itertools = { version = "0.13.0", default-features = false, features = ["use_std"] }
+cblas-sys = { version = "0.1.4", default-features = false }
+
[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", "xtest-numeric"]
+[profile.test.package.blas-tests]
+opt-level = 2
[package.metadata.release]
no-dev-version = true
tag-name = "{{version}}"
+# Config specific to docs.rs
[package.metadata.docs.rs]
-features = ["docs"]
+features = ["approx", "serde", "rayon"]
+# Define the configuration attribute `docsrs`
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/README.rst b/README.rst
index 4e33d12c4..49558b1c1 100644
--- a/README.rst
+++ b/README.rst
@@ -97,16 +97,20 @@ your `Cargo.toml`.
- Enable the ``threading`` feature in the matrixmultiply package
+- ``portable-atomic-critical-section``
+
+ - Whether ``portable-atomic`` should use ``critical-section``
+
How to use with cargo
---------------------
::
[dependencies]
- ndarray = "0.15.0"
+ ndarray = "0.16.0"
-How to enable blas integration
------------------------------
+How to enable BLAS integration
+------------------------------
Blas integration is an optional add-on. Without BLAS, ndarray uses the
``matrixmultiply`` crate for matrix multiplication for ``f64`` and ``f32``
@@ -123,16 +127,16 @@ An example configuration using system openblas is shown below. Note that only
end-user projects (not libraries) should select provider::
[dependencies]
- ndarray = { version = "0.15.0", features = ["blas"] }
- blas-src = { version = "0.8", features = ["openblas"] }
+ ndarray = { version = "0.16.0", features = ["blas"] }
+ blas-src = { version = "0.10", features = ["openblas"] }
openblas-src = { version = "0.10", features = ["cblas", "system"] }
Using system-installed dependencies can save a long time building dependencies.
An example configuration using (compiled) netlib is shown below anyway::
[dependencies]
- ndarray = { version = "0.15.0", features = ["blas"] }
- blas-src = { version = "0.8.0", default-features = false, features = ["netlib"] }
+ ndarray = { version = "0.16.0", features = ["blas"] }
+ blas-src = { version = "0.10.0", default-features = false, features = ["netlib"] }
When this is done, your program must also link to ``blas_src`` by using it or
explicitly including it in your code::
@@ -145,12 +149,21 @@ there is no tight coupling to the ``blas-src`` version, so version selection is
=========== ============ ================ ==============
``ndarray`` ``blas-src`` ``openblas-src`` ``netlib-src``
=========== ============ ================ ==============
+0.16 0.10 0.10 0.8
0.15 0.8 0.10 0.8
0.15 0.7 0.9 0.8
0.14 0.6.1 0.9.0
0.13 0.2.0 0.6.0
=========== ============ ================ ==============
+------------
+BLAS on MSRV
+------------
+
+Although ``ndarray`` currently maintains an MSRV of 1.64.0, this is separate from the MSRV (either stated or real) of the various BLAS providers.
+As of the time of writing, ``openblas`` currently supports MSRV of 1.71.1.
+So, while ``ndarray`` and ``openblas-src`` are compatible, they can only work together with toolchains 1.71.1 or above.
+
Recent Changes
--------------
diff --git a/RELEASES.md b/RELEASES.md
index 364166718..8b4786666 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,98 @@
+Version 0.16.1 (2024-08-14)
+===========================
+
+- Refactor and simplify BLAS gemm call further by [@bluss](https://github.com/bluss) [#1421](https://github.com/rust-ndarray/ndarray/pull/1421)
+- Fix infinite recursion and off-by-one error in triu/tril by [@akern40](https://github.com/akern40) [#1418](https://github.com/rust-ndarray/ndarray/pull/1418)
+- Fix using BLAS for all compatible cases of memory layout by [@bluss](https://github.com/bluss) [#1419](https://github.com/rust-ndarray/ndarray/pull/1419)
+- Use PR check instead of Merge Queue, and check rustdoc by [@bluss](https://github.com/bluss) [#1420](https://github.com/rust-ndarray/ndarray/pull/1420)
+- Make iterators covariant in element type by [@bluss](https://github.com/bluss) [#1417](https://github.com/rust-ndarray/ndarray/pull/1417)
+
+Version 0.16.0 (2024-08-03)
+===========================
+
+Featured Changes
+----------------
+
+- Better shape: Deprecate reshape, into_shape by [@bluss](https://github.com/bluss) [#1310](https://github.com/rust-ndarray/ndarray/pull/1310)
+ `.into_shape()` **is now deprecated**.
+ Use `.into_shape_with_order()` or `.to_shape()` instead, which don't have `into_shape`'s drawbacks.
+
+New Features and Improvements
+-----------------------------
+
+- Check for aliasing in `RawViewMut::from_shape_ptr` with a debug assertion by [@bluss](https://github.com/bluss) [#1413](https://github.com/rust-ndarray/ndarray/pull/1413)
+- Allow aliasing in ArrayView::from_shape by [@bluss](https://github.com/bluss) [#1410](https://github.com/rust-ndarray/ndarray/pull/1410)
+- Remove deprecations from 0.15.x by [@bluss](https://github.com/bluss) [#1409](https://github.com/rust-ndarray/ndarray/pull/1409)
+- Make `CowArray` an owned storage array, require Clone bound for `into_shared` by [@jturner314](https://github.com/jturner314) [#1028](https://github.com/rust-ndarray/ndarray/pull/1028)
+- Change `NdProducer::Dim` of `axis_windows()` to `Ix1` by [@jonasBoss](https://github.com/jonasBoss) [#1305](https://github.com/rust-ndarray/ndarray/pull/1305)
+- Add `squeeze()` to dynamic dimension arrays by [@barakugav](https://github.com/barakugav) [#1396](https://github.com/rust-ndarray/ndarray/pull/1396)
+- Add `flatten`, `flatten_with_order` and `into_flat` to arrays by [@barakugav](https://github.com/barakugav) [#1397](https://github.com/rust-ndarray/ndarray/pull/1397)
+- Make compatible with thumbv6m-none-eabi by [@BjornTheProgrammer](https://github.com/BjornTheProgrammer) [#1384](https://github.com/rust-ndarray/ndarray/pull/1384)
+- `is_unique` for `ArcArray` by [@daniellga](https://github.com/daniellga) [#1399](https://github.com/rust-ndarray/ndarray/pull/1399)
+- Add `triu` and `tril` methods directly to ArrayBase by [@akern40](https://github.com/akern40) [#1386](https://github.com/rust-ndarray/ndarray/pull/1386)
+- Fix styling of the BLAS integration heading. by [@adamreichold](https://github.com/adamreichold) [#1390](https://github.com/rust-ndarray/ndarray/pull/1390)
+- Implement `product_axis` by [@akern40](https://github.com/akern40) [#1387](https://github.com/rust-ndarray/ndarray/pull/1387)
+- Add reserve method for owned arrays by [@ssande7](https://github.com/ssande7) [#1268](https://github.com/rust-ndarray/ndarray/pull/1268)
+- Use inline on spit_at and smaller methods by [@bluss](https://github.com/bluss) [#1381](https://github.com/rust-ndarray/ndarray/pull/1381)
+- Update to Approx 0.5 by [@bluss](https://github.com/bluss) [#1380](https://github.com/rust-ndarray/ndarray/pull/1380)
+- Add .into_raw_vec_with_offset() and deprecate .into_raw_vec() by [@bluss](https://github.com/bluss) [#1379](https://github.com/rust-ndarray/ndarray/pull/1379)
+- Add additional array -> array view conversions by [@bluss](https://github.com/bluss) [#1130](https://github.com/rust-ndarray/ndarray/pull/1130)
+- implement DoubleEndedIterator for 1d `LanesIter` by [@Muthsera](https://github.com/Muthsera) [#1237](https://github.com/rust-ndarray/ndarray/pull/1237)
+- Add Zip::any by [@nilgoyette](https://github.com/nilgoyette) [#1228](https://github.com/rust-ndarray/ndarray/pull/1228)
+- Make the aview0, aview1, and aview2 free functions be const fns by [@jturner314](https://github.com/jturner314) [#1132](https://github.com/rust-ndarray/ndarray/pull/1132)
+- Add missing safety checks to `From<&[[A; N]]> for ArrayView` and `From<&mut [[A; N]]> for ArrayViewMut` by [@jturner314](https://github.com/jturner314) [#1131](https://github.com/rust-ndarray/ndarray/pull/1131)
+- derived Debug for Iter and IterMut by [@biskwikman](https://github.com/biskwikman) [#1353](https://github.com/rust-ndarray/ndarray/pull/1353)
+- Fix Miri errors for WindowsIter and ExactChunksIter/Mut by [@jturner314](https://github.com/jturner314) [#1142](https://github.com/rust-ndarray/ndarray/pull/1142)
+- Fix Miri failure with -Zmiri-tag-raw-pointers by [@jturner314](https://github.com/jturner314) [#1138](https://github.com/rust-ndarray/ndarray/pull/1138)
+- Track-caller panics by [@xd009642](https://github.com/xd009642) [#975](https://github.com/rust-ndarray/ndarray/pull/975)
+- Add slice_axis_move method by [@jturner314](https://github.com/jturner314) [#1211](https://github.com/rust-ndarray/ndarray/pull/1211)
+- iterators: Re-export IntoIter by [@bluss](https://github.com/bluss) [#1370](https://github.com/rust-ndarray/ndarray/pull/1370)
+- Fix unsafe blocks in `s![]` macro by [@jturner314](https://github.com/jturner314) [#1196](https://github.com/rust-ndarray/ndarray/pull/1196)
+- Fix comparison with NumPy of slicing with negative step by [@venkat0791](https://github.com/venkat0791) [#1319](https://github.com/rust-ndarray/ndarray/pull/1319)
+- Updated Windows `base` Computations to be Safer by [@LazaroHurtado](https://github.com/LazaroHurtado) [#1297](https://github.com/rust-ndarray/ndarray/pull/1297)
+- Update README-quick-start.md by [@fumseckk](https://github.com/fumseckk) [#1246](https://github.com/rust-ndarray/ndarray/pull/1246)
+- Added stride support to `Windows` by [@LazaroHurtado](https://github.com/LazaroHurtado) [#1249](https://github.com/rust-ndarray/ndarray/pull/1249)
+- Added select example to numpy user docs by [@WillAyd](https://github.com/WillAyd) [#1294](https://github.com/rust-ndarray/ndarray/pull/1294)
+- Add both approx features to the readme by [@nilgoyette](https://github.com/nilgoyette) [#1289](https://github.com/rust-ndarray/ndarray/pull/1289)
+- Add NumPy examples combining slicing and assignment by [@jturner314](https://github.com/jturner314) [#1210](https://github.com/rust-ndarray/ndarray/pull/1210)
+- Fix contig check for single element arrays by [@bluss](https://github.com/bluss) [#1362](https://github.com/rust-ndarray/ndarray/pull/1362)
+- Export Linspace and Logspace iterators by [@johann-cm](https://github.com/johann-cm) [#1348](https://github.com/rust-ndarray/ndarray/pull/1348)
+- Use `clone_from()` in two places by [@ChayimFriedman2](https://github.com/ChayimFriedman2) [#1347](https://github.com/rust-ndarray/ndarray/pull/1347)
+- Update README-quick-start.md by [@joelchen](https://github.com/joelchen) [#1344](https://github.com/rust-ndarray/ndarray/pull/1344)
+- Provide element-wise math functions for floats by [@KmolYuan](https://github.com/KmolYuan) [#1042](https://github.com/rust-ndarray/ndarray/pull/1042)
+- Improve example in doc for columns method by [@gkobeaga](https://github.com/gkobeaga) [#1221](https://github.com/rust-ndarray/ndarray/pull/1221)
+- Fix description of stack! in quick start by [@jturner314](https://github.com/jturner314) [#1156](https://github.com/rust-ndarray/ndarray/pull/1156)
+
+Tests, CI and Maintainer tasks
+------------------------------
+
+- CI: require rustfmt, nostd by [@bluss](https://github.com/bluss) [#1411](https://github.com/rust-ndarray/ndarray/pull/1411)
+- Prepare changelog for 0.16.0 by [@bluss](https://github.com/bluss) [#1401](https://github.com/rust-ndarray/ndarray/pull/1401)
+- Organize dependencies with workspace = true (cont.) by [@bluss](https://github.com/bluss) [#1407](https://github.com/rust-ndarray/ndarray/pull/1407)
+- Update to use dep: for features by [@bluss](https://github.com/bluss) [#1406](https://github.com/rust-ndarray/ndarray/pull/1406)
+- Organize the workspace of test crates a bit better by [@bluss](https://github.com/bluss) [#1405](https://github.com/rust-ndarray/ndarray/pull/1405)
+- Add rustfmt commit to ignored revisions for git blame by [@lucascolley](https://github.com/lucascolley) [#1376](https://github.com/rust-ndarray/ndarray/pull/1376)
+- The minimum amount of work required to fix our CI by [@adamreichold](https://github.com/adamreichold) [#1388](https://github.com/rust-ndarray/ndarray/pull/1388)
+- Fixed broke continuous integration badge by [@juhotuho10](https://github.com/juhotuho10) [#1382](https://github.com/rust-ndarray/ndarray/pull/1382)
+- Use mold linker to speed up ci by [@bluss](https://github.com/bluss) [#1378](https://github.com/rust-ndarray/ndarray/pull/1378)
+- Add rustformat config and CI by [@bluss](https://github.com/bluss) [#1375](https://github.com/rust-ndarray/ndarray/pull/1375)
+- Add docs to CI by [@jturner314](https://github.com/jturner314) [#925](https://github.com/rust-ndarray/ndarray/pull/925)
+- Test using cargo-careful by [@bluss](https://github.com/bluss) [#1371](https://github.com/rust-ndarray/ndarray/pull/1371)
+- Further ci updates - numeric tests, and run all tests on PRs by [@bluss](https://github.com/bluss) [#1369](https://github.com/rust-ndarray/ndarray/pull/1369)
+- Setup ci so that most checks run in merge queue only by [@bluss](https://github.com/bluss) [#1368](https://github.com/rust-ndarray/ndarray/pull/1368)
+- Use merge queue by [@bluss](https://github.com/bluss) [#1367](https://github.com/rust-ndarray/ndarray/pull/1367)
+- Try to make the master branch shipshape by [@adamreichold](https://github.com/adamreichold) [#1286](https://github.com/rust-ndarray/ndarray/pull/1286)
+- Update ci - run cross tests only on master by [@bluss](https://github.com/bluss) [#1366](https://github.com/rust-ndarray/ndarray/pull/1366)
+- ndarray_for_numpy_users some example to code not pointed out to clippy by [@higumachan](https://github.com/higumachan) [#1360](https://github.com/rust-ndarray/ndarray/pull/1360)
+- Fix minimum rust version mismatch in lib.rs by [@HoKim98](https://github.com/HoKim98) [#1352](https://github.com/rust-ndarray/ndarray/pull/1352)
+- Fix MSRV build by pinning crossbeam crates. by [@adamreichold](https://github.com/adamreichold) [#1345](https://github.com/rust-ndarray/ndarray/pull/1345)
+- Fix new rustc lints to make the CI pass. by [@adamreichold](https://github.com/adamreichold) [#1337](https://github.com/rust-ndarray/ndarray/pull/1337)
+- Make Clippy happy and fix MSRV build by [@adamreichold](https://github.com/adamreichold) [#1320](https://github.com/rust-ndarray/ndarray/pull/1320)
+- small formatting fix in README.rst by [@podusowski](https://github.com/podusowski) [#1199](https://github.com/rust-ndarray/ndarray/pull/1199)
+- Fix CI failures (mostly linting with clippy) by [@aganders3](https://github.com/aganders3) [#1171](https://github.com/rust-ndarray/ndarray/pull/1171)
+- Remove doc(hidden) attr from items in trait impls by [@jturner314](https://github.com/jturner314) [#1165](https://github.com/rust-ndarray/ndarray/pull/1165)
+
+
Version 0.15.6 (2022-07-30)
===========================
diff --git a/benches/bench1.rs b/benches/bench1.rs
index 33185844a..c07b8e3d9 100644
--- a/benches/bench1.rs
+++ b/benches/bench1.rs
@@ -982,6 +982,7 @@ fn dot_extended(bench: &mut test::Bencher)
const MEAN_SUM_N: usize = 127;
+#[cfg(feature = "std")]
fn range_mat(m: Ix, n: Ix) -> Array2
{
assert!(m * n != 0);
@@ -990,6 +991,7 @@ fn range_mat(m: Ix, n: Ix) -> Array2
.unwrap()
}
+#[cfg(feature = "std")]
#[bench]
fn mean_axis0(bench: &mut test::Bencher)
{
@@ -997,6 +999,7 @@ fn mean_axis0(bench: &mut test::Bencher)
bench.iter(|| a.mean_axis(Axis(0)));
}
+#[cfg(feature = "std")]
#[bench]
fn mean_axis1(bench: &mut test::Bencher)
{
@@ -1004,6 +1007,7 @@ fn mean_axis1(bench: &mut test::Bencher)
bench.iter(|| a.mean_axis(Axis(1)));
}
+#[cfg(feature = "std")]
#[bench]
fn sum_axis0(bench: &mut test::Bencher)
{
@@ -1011,6 +1015,7 @@ fn sum_axis0(bench: &mut test::Bencher)
bench.iter(|| a.sum_axis(Axis(0)));
}
+#[cfg(feature = "std")]
#[bench]
fn sum_axis1(bench: &mut test::Bencher)
{
diff --git a/benches/construct.rs b/benches/construct.rs
index 278174388..380d87799 100644
--- a/benches/construct.rs
+++ b/benches/construct.rs
@@ -19,6 +19,7 @@ fn zeros_f64(bench: &mut Bencher)
bench.iter(|| Array::::zeros((128, 128)))
}
+#[cfg(feature = "std")]
#[bench]
fn map_regular(bench: &mut test::Bencher)
{
@@ -28,6 +29,7 @@ fn map_regular(bench: &mut test::Bencher)
bench.iter(|| a.map(|&x| 2. * x));
}
+#[cfg(feature = "std")]
#[bench]
fn map_stride(bench: &mut test::Bencher)
{
diff --git a/benches/higher-order.rs b/benches/higher-order.rs
index 9cc3bd961..1b4e8340c 100644
--- a/benches/higher-order.rs
+++ b/benches/higher-order.rs
@@ -12,6 +12,7 @@ const N: usize = 1024;
const X: usize = 64;
const Y: usize = 16;
+#[cfg(feature = "std")]
#[bench]
fn map_regular(bench: &mut Bencher)
{
@@ -26,6 +27,7 @@ pub fn double_array(mut a: ArrayViewMut2<'_, f64>)
a *= 2.0;
}
+#[cfg(feature = "std")]
#[bench]
fn map_stride_double_f64(bench: &mut Bencher)
{
@@ -38,6 +40,7 @@ fn map_stride_double_f64(bench: &mut Bencher)
});
}
+#[cfg(feature = "std")]
#[bench]
fn map_stride_f64(bench: &mut Bencher)
{
@@ -48,6 +51,7 @@ fn map_stride_f64(bench: &mut Bencher)
bench.iter(|| av.map(|&x| 2. * x));
}
+#[cfg(feature = "std")]
#[bench]
fn map_stride_u32(bench: &mut Bencher)
{
@@ -59,6 +63,7 @@ fn map_stride_u32(bench: &mut Bencher)
bench.iter(|| av.map(|&x| 2 * x));
}
+#[cfg(feature = "std")]
#[bench]
fn fold_axis(bench: &mut Bencher)
{
diff --git a/benches/iter.rs b/benches/iter.rs
index 77f511745..154ee4eaf 100644
--- a/benches/iter.rs
+++ b/benches/iter.rs
@@ -45,6 +45,7 @@ fn iter_sum_2d_transpose(bench: &mut Bencher)
bench.iter(|| a.iter().sum::());
}
+#[cfg(feature = "std")]
#[bench]
fn iter_filter_sum_2d_u32(bench: &mut Bencher)
{
@@ -55,6 +56,7 @@ fn iter_filter_sum_2d_u32(bench: &mut Bencher)
bench.iter(|| b.iter().filter(|&&x| x < 75).sum::());
}
+#[cfg(feature = "std")]
#[bench]
fn iter_filter_sum_2d_f32(bench: &mut Bencher)
{
@@ -65,6 +67,7 @@ fn iter_filter_sum_2d_f32(bench: &mut Bencher)
bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::());
}
+#[cfg(feature = "std")]
#[bench]
fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher)
{
@@ -76,6 +79,7 @@ fn iter_filter_sum_2d_stride_u32(bench: &mut Bencher)
bench.iter(|| b.iter().filter(|&&x| x < 75).sum::());
}
+#[cfg(feature = "std")]
#[bench]
fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher)
{
@@ -87,6 +91,7 @@ fn iter_filter_sum_2d_stride_f32(bench: &mut Bencher)
bench.iter(|| b.iter().filter(|&&x| x < 75.).sum::());
}
+#[cfg(feature = "std")]
#[bench]
fn iter_rev_step_by_contiguous(bench: &mut Bencher)
{
@@ -98,6 +103,7 @@ fn iter_rev_step_by_contiguous(bench: &mut Bencher)
});
}
+#[cfg(feature = "std")]
#[bench]
fn iter_rev_step_by_discontiguous(bench: &mut Bencher)
{
diff --git a/benches/numeric.rs b/benches/numeric.rs
index e2ffa1b84..ceb57fbd7 100644
--- a/benches/numeric.rs
+++ b/benches/numeric.rs
@@ -9,6 +9,7 @@ const N: usize = 1024;
const X: usize = 64;
const Y: usize = 16;
+#[cfg(feature = "std")]
#[bench]
fn clip(bench: &mut Bencher)
{
diff --git a/crates/blas-mock-tests/Cargo.toml b/crates/blas-mock-tests/Cargo.toml
new file mode 100644
index 000000000..39ef9cf99
--- /dev/null
+++ b/crates/blas-mock-tests/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "blas-mock-tests"
+version = "0.1.0"
+edition = "2018"
+publish = false
+
+[lib]
+test = false
+doc = false
+doctest = false
+
+[dependencies]
+cblas-sys = { workspace = true }
+
+[dev-dependencies]
+ndarray = { workspace = true, features = ["approx", "blas"] }
+ndarray-gen = { workspace = true }
+itertools = { workspace = true }
diff --git a/crates/blas-mock-tests/src/lib.rs b/crates/blas-mock-tests/src/lib.rs
new file mode 100644
index 000000000..11fc5975e
--- /dev/null
+++ b/crates/blas-mock-tests/src/lib.rs
@@ -0,0 +1,100 @@
+//! Mock interfaces to BLAS
+
+use core::cell::RefCell;
+use core::ffi::{c_double, c_float, c_int};
+use std::thread_local;
+
+use cblas_sys::{c_double_complex, c_float_complex, CBLAS_LAYOUT, CBLAS_TRANSPOSE};
+
+thread_local! {
+ /// This counter is incremented every time a gemm function is called
+ pub static CALL_COUNT: RefCell = RefCell::new(0);
+}
+
+#[rustfmt::skip]
+#[no_mangle]
+#[allow(unused)]
+pub unsafe extern "C" fn cblas_sgemm(
+ layout: CBLAS_LAYOUT,
+ transa: CBLAS_TRANSPOSE,
+ transb: CBLAS_TRANSPOSE,
+ m: c_int,
+ n: c_int,
+ k: c_int,
+ alpha: c_float,
+ a: *const c_float,
+ lda: c_int,
+ b: *const c_float,
+ ldb: c_int,
+ beta: c_float,
+ c: *mut c_float,
+ ldc: c_int
+) {
+ CALL_COUNT.with(|ctx| *ctx.borrow_mut() += 1);
+}
+
+#[rustfmt::skip]
+#[no_mangle]
+#[allow(unused)]
+pub unsafe extern "C" fn cblas_dgemm(
+ layout: CBLAS_LAYOUT,
+ transa: CBLAS_TRANSPOSE,
+ transb: CBLAS_TRANSPOSE,
+ m: c_int,
+ n: c_int,
+ k: c_int,
+ alpha: c_double,
+ a: *const c_double,
+ lda: c_int,
+ b: *const c_double,
+ ldb: c_int,
+ beta: c_double,
+ c: *mut c_double,
+ ldc: c_int
+) {
+ CALL_COUNT.with(|ctx| *ctx.borrow_mut() += 1);
+}
+
+#[rustfmt::skip]
+#[no_mangle]
+#[allow(unused)]
+pub unsafe extern "C" fn cblas_cgemm(
+ layout: CBLAS_LAYOUT,
+ transa: CBLAS_TRANSPOSE,
+ transb: CBLAS_TRANSPOSE,
+ m: c_int,
+ n: c_int,
+ k: c_int,
+ alpha: *const c_float_complex,
+ a: *const c_float_complex,
+ lda: c_int,
+ b: *const c_float_complex,
+ ldb: c_int,
+ beta: *const c_float_complex,
+ c: *mut c_float_complex,
+ ldc: c_int
+) {
+ CALL_COUNT.with(|ctx| *ctx.borrow_mut() += 1);
+}
+
+#[rustfmt::skip]
+#[no_mangle]
+#[allow(unused)]
+pub unsafe extern "C" fn cblas_zgemm(
+ layout: CBLAS_LAYOUT,
+ transa: CBLAS_TRANSPOSE,
+ transb: CBLAS_TRANSPOSE,
+ m: c_int,
+ n: c_int,
+ k: c_int,
+ alpha: *const c_double_complex,
+ a: *const c_double_complex,
+ lda: c_int,
+ b: *const c_double_complex,
+ ldb: c_int,
+ beta: *const c_double_complex,
+ c: *mut c_double_complex,
+ ldc: c_int
+) {
+ CALL_COUNT.with(|ctx| *ctx.borrow_mut() += 1);
+}
diff --git a/crates/blas-mock-tests/tests/use-blas.rs b/crates/blas-mock-tests/tests/use-blas.rs
new file mode 100644
index 000000000..217508af6
--- /dev/null
+++ b/crates/blas-mock-tests/tests/use-blas.rs
@@ -0,0 +1,88 @@
+extern crate ndarray;
+
+use ndarray::prelude::*;
+
+use blas_mock_tests::CALL_COUNT;
+use ndarray::linalg::general_mat_mul;
+use ndarray::Order;
+use ndarray_gen::array_builder::ArrayBuilder;
+
+use itertools::iproduct;
+
+#[test]
+fn test_gen_mat_mul_uses_blas()
+{
+ let alpha = 1.0;
+ let beta = 0.0;
+
+ let sizes = vec![
+ (8, 8, 8),
+ (10, 10, 10),
+ (8, 8, 1),
+ (1, 10, 10),
+ (10, 1, 10),
+ (10, 10, 1),
+ (1, 10, 1),
+ (10, 1, 1),
+ (1, 1, 10),
+ (4, 17, 3),
+ (17, 3, 22),
+ (19, 18, 2),
+ (16, 17, 15),
+ (15, 16, 17),
+ (67, 63, 62),
+ ];
+ let strides = &[1, 2, -1, -2];
+ let cf_order = [Order::C, Order::F];
+
+ // test different strides and memory orders
+ for &(m, k, n) in &sizes {
+ for (&s1, &s2) in iproduct!(strides, strides) {
+ for (ord1, ord2, ord3) in iproduct!(cf_order, cf_order, cf_order) {
+ println!("Case s1={}, s2={}, orders={:?}, {:?}, {:?}", s1, s2, ord1, ord2, ord3);
+
+ let a = ArrayBuilder::new((m, k)).memory_order(ord1).build();
+ let b = ArrayBuilder::new((k, n)).memory_order(ord2).build();
+ let mut c = ArrayBuilder::new((m, n)).memory_order(ord3).build();
+
+ {
+ let av;
+ let bv;
+ let mut cv;
+
+ if s1 != 1 || s2 != 1 {
+ av = a.slice(s![..;s1, ..;s2]);
+ bv = b.slice(s![..;s2, ..;s2]);
+ cv = c.slice_mut(s![..;s1, ..;s2]);
+ } else {
+ // different stride cases for slicing versus not sliced (for axes of
+ // len=1); so test not sliced here.
+ av = a.view();
+ bv = b.view();
+ cv = c.view_mut();
+ }
+
+ let pre_count = CALL_COUNT.with(|ctx| *ctx.borrow());
+ general_mat_mul(alpha, &av, &bv, beta, &mut cv);
+ let after_count = CALL_COUNT.with(|ctx| *ctx.borrow());
+ let ncalls = after_count - pre_count;
+ debug_assert!(ncalls <= 1);
+
+ let always_uses_blas = s1 == 1 && s2 == 1;
+
+ if always_uses_blas {
+ assert_eq!(ncalls, 1, "Contiguous arrays should use blas, orders={:?}", (ord1, ord2, ord3));
+ }
+
+ let should_use_blas = av.strides().iter().all(|&s| s > 0)
+ && bv.strides().iter().all(|&s| s > 0)
+ && cv.strides().iter().all(|&s| s > 0)
+ && av.strides().iter().any(|&s| s == 1)
+ && bv.strides().iter().any(|&s| s == 1)
+ && cv.strides().iter().any(|&s| s == 1);
+ assert_eq!(should_use_blas, ncalls > 0);
+ }
+ }
+ }
+ }
+}
diff --git a/xtest-blas/Cargo.toml b/crates/blas-tests/Cargo.toml
similarity index 62%
rename from xtest-blas/Cargo.toml
rename to crates/blas-tests/Cargo.toml
index 3724caf14..08acc7fa5 100644
--- a/xtest-blas/Cargo.toml
+++ b/crates/blas-tests/Cargo.toml
@@ -3,25 +3,29 @@ name = "blas-tests"
version = "0.1.0"
authors = ["bluss"]
publish = false
+edition = "2018"
[lib]
test = false
-
-[dev-dependencies]
-approx = "0.5"
-defmac = "0.2"
-num-traits = "0.2"
-num-complex = { version = "0.4", default-features = false }
+doc = false
+doctest = false
[dependencies]
-ndarray = { path = "..", features = ["approx", "blas"] }
-
-blas-src = { version = "0.8", optional = true }
+ndarray = { workspace = true, features = ["approx", "blas"] }
+ndarray-gen = { workspace = true }
-openblas-src = { version = "0.10", optional = true }
+blas-src = { version = "0.10", optional = true }
+openblas-src = { version = ">=0.10.11", optional = true }
netlib-src = { version = "0.8", optional = true }
blis-src = { version = "0.2", features = ["system"], optional = true }
+[dev-dependencies]
+defmac = "0.2"
+approx = { workspace = true }
+num-traits = { workspace = true }
+num-complex = { workspace = true }
+itertools = { workspace = true }
+
[features]
# Just for making an example and to help testing, , multiple different possible
# configurations are selectable here.
@@ -30,3 +34,4 @@ openblas-cache = ["blas-src", "blas-src/openblas", "openblas-src/cache"]
netlib = ["blas-src", "blas-src/netlib"]
netlib-system = ["blas-src", "blas-src/netlib", "netlib-src/system"]
blis-system = ["blas-src", "blas-src/blis", "blis-src/system"]
+accelerate = ["blas-src", "blas-src/accelerate"]
diff --git a/xtest-blas/src/lib.rs b/crates/blas-tests/src/lib.rs
similarity index 100%
rename from xtest-blas/src/lib.rs
rename to crates/blas-tests/src/lib.rs
diff --git a/crates/blas-tests/tests/dyn.rs b/crates/blas-tests/tests/dyn.rs
new file mode 100644
index 000000000..6c0fd975e
--- /dev/null
+++ b/crates/blas-tests/tests/dyn.rs
@@ -0,0 +1,80 @@
+extern crate blas_src;
+use ndarray::{linalg::Dot, Array1, Array2, ArrayD, Ix1, Ix2};
+
+#[test]
+fn test_arrayd_dot_2d()
+{
+ let mat1 = ArrayD::from_shape_vec(vec![3, 2], vec![3.0; 6]).unwrap();
+ let mat2 = ArrayD::from_shape_vec(vec![2, 3], vec![1.0; 6]).unwrap();
+
+ let result = mat1.dot(&mat2);
+
+ // Verify the result is correct
+ assert_eq!(result.ndim(), 2);
+ assert_eq!(result.shape(), &[3, 3]);
+
+ // Compare with Array2 implementation
+ let mat1_2d = Array2::from_shape_vec((3, 2), vec![3.0; 6]).unwrap();
+ let mat2_2d = Array2::from_shape_vec((2, 3), vec![1.0; 6]).unwrap();
+ let expected = mat1_2d.dot(&mat2_2d);
+
+ assert_eq!(result.into_dimensionality::().unwrap(), expected);
+}
+
+#[test]
+fn test_arrayd_dot_1d()
+{
+ // Test 1D array dot product
+ let vec1 = ArrayD::from_shape_vec(vec![3], vec![1.0, 2.0, 3.0]).unwrap();
+ let vec2 = ArrayD::from_shape_vec(vec![3], vec![4.0, 5.0, 6.0]).unwrap();
+
+ let result = vec1.dot(&vec2);
+
+ // Verify scalar result
+ assert_eq!(result.ndim(), 0);
+ assert_eq!(result.shape(), &[]);
+ assert_eq!(result[[]], 32.0); // 1*4 + 2*5 + 3*6
+}
+
+#[test]
+#[should_panic(expected = "Dot product for ArrayD is only supported for 1D and 2D arrays")]
+fn test_arrayd_dot_3d()
+{
+ // Test that 3D arrays are not supported
+ let arr1 = ArrayD::from_shape_vec(vec![2, 2, 2], vec![1.0; 8]).unwrap();
+ let arr2 = ArrayD::from_shape_vec(vec![2, 2, 2], vec![1.0; 8]).unwrap();
+
+ let _result = arr1.dot(&arr2); // Should panic
+}
+
+#[test]
+#[should_panic(expected = "ndarray: inputs 2 × 3 and 4 × 5 are not compatible for matrix multiplication")]
+fn test_arrayd_dot_incompatible_dims()
+{
+ // Test arrays with incompatible dimensions
+ let arr1 = ArrayD::from_shape_vec(vec![2, 3], vec![1.0; 6]).unwrap();
+ let arr2 = ArrayD::from_shape_vec(vec![4, 5], vec![1.0; 20]).unwrap();
+
+ let _result = arr1.dot(&arr2); // Should panic
+}
+
+#[test]
+fn test_arrayd_dot_matrix_vector()
+{
+ // Test matrix-vector multiplication
+ let mat = ArrayD::from_shape_vec(vec![3, 2], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
+ let vec = ArrayD::from_shape_vec(vec![2], vec![1.0, 2.0]).unwrap();
+
+ let result = mat.dot(&vec);
+
+ // Verify result
+ assert_eq!(result.ndim(), 1);
+ assert_eq!(result.shape(), &[3]);
+
+ // Compare with Array2 implementation
+ let mat_2d = Array2::from_shape_vec((3, 2), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).unwrap();
+ let vec_1d = Array1::from_vec(vec![1.0, 2.0]);
+ let expected = mat_2d.dot(&vec_1d);
+
+ assert_eq!(result.into_dimensionality::().unwrap(), expected);
+}
diff --git a/xtest-blas/tests/oper.rs b/crates/blas-tests/tests/oper.rs
similarity index 76%
rename from xtest-blas/tests/oper.rs
rename to crates/blas-tests/tests/oper.rs
index 3ed81915e..f604ae091 100644
--- a/xtest-blas/tests/oper.rs
+++ b/crates/blas-tests/tests/oper.rs
@@ -9,12 +9,17 @@ use ndarray::prelude::*;
use ndarray::linalg::general_mat_mul;
use ndarray::linalg::general_mat_vec_mul;
+use ndarray::Order;
use ndarray::{Data, Ix, LinalgScalar};
+use ndarray_gen::array_builder::ArrayBuilder;
+use ndarray_gen::array_builder::ElementGenerator;
use approx::assert_relative_eq;
use defmac::defmac;
+use itertools::iproduct;
use num_complex::Complex32;
use num_complex::Complex64;
+use num_traits::Num;
#[test]
fn mat_vec_product_1d()
@@ -46,46 +51,29 @@ fn mat_vec_product_1d_inverted_axis()
assert_eq!(a.t().dot(&b), ans);
}
-fn range_mat(m: Ix, n: Ix) -> Array2
+fn range_mat(m: Ix, n: Ix) -> Array2
{
- Array::linspace(0., (m * n) as f32 - 1., m * n)
- .into_shape_with_order((m, n))
- .unwrap()
-}
-
-fn range_mat64(m: Ix, n: Ix) -> Array2
-{
- Array::linspace(0., (m * n) as f64 - 1., m * n)
- .into_shape_with_order((m, n))
- .unwrap()
+ ArrayBuilder::new((m, n)).build()
}
fn range_mat_complex(m: Ix, n: Ix) -> Array2
{
- Array::linspace(0., (m * n) as f32 - 1., m * n)
- .into_shape_with_order((m, n))
- .unwrap()
- .map(|&f| Complex32::new(f, 0.))
+ ArrayBuilder::new((m, n)).build()
}
fn range_mat_complex64(m: Ix, n: Ix) -> Array2
{
- Array::linspace(0., (m * n) as f64 - 1., m * n)
- .into_shape_with_order((m, n))
- .unwrap()
- .map(|&f| Complex64::new(f, 0.))
+ ArrayBuilder::new((m, n)).build()
}
fn range1_mat64(m: Ix) -> Array1
{
- Array::linspace(0., m as f64 - 1., m)
+ ArrayBuilder::new(m).build()
}
fn range_i32(m: Ix, n: Ix) -> Array2
{
- Array::from_iter(0..(m * n) as i32)
- .into_shape_with_order((m, n))
- .unwrap()
+ ArrayBuilder::new((m, n)).build()
}
// simple, slow, correct (hopefully) mat mul
@@ -160,8 +148,8 @@ where
fn mat_mul_order()
{
let (m, n, k) = (50, 50, 50);
- let a = range_mat(m, n);
- let b = range_mat(n, k);
+ let a = range_mat::(m, n);
+ let b = range_mat::(n, k);
let mut af = Array::zeros(a.dim().f());
let mut bf = Array::zeros(b.dim().f());
af.assign(&a);
@@ -180,7 +168,7 @@ fn mat_mul_order()
fn mat_mul_broadcast()
{
let (m, n, k) = (16, 16, 16);
- let a = range_mat(m, n);
+ let a = range_mat::(m, n);
let x1 = 1.;
let x = Array::from(vec![x1]);
let b0 = x.broadcast((n, k)).unwrap();
@@ -200,8 +188,8 @@ fn mat_mul_broadcast()
fn mat_mul_rev()
{
let (m, n, k) = (16, 16, 16);
- let a = range_mat(m, n);
- let b = range_mat(n, k);
+ let a = range_mat::(m, n);
+ let b = range_mat::(n, k);
let mut rev = Array::zeros(b.dim());
let mut rev = rev.slice_mut(s![..;-1, ..]);
rev.assign(&b);
@@ -230,8 +218,8 @@ fn mat_mut_zero_len()
}
}
});
- mat_mul_zero_len!(range_mat);
- mat_mul_zero_len!(range_mat64);
+ mat_mul_zero_len!(range_mat::);
+ mat_mul_zero_len!(range_mat::);
mat_mul_zero_len!(range_i32);
}
@@ -243,32 +231,59 @@ fn gen_mat_mul()
let sizes = vec![
(4, 4, 4),
(8, 8, 8),
- (17, 15, 16),
+ (8, 8, 1),
+ (1, 10, 10),
+ (10, 1, 10),
+ (10, 10, 1),
+ (1, 10, 1),
+ (10, 1, 1),
+ (1, 1, 10),
(4, 17, 3),
(17, 3, 22),
(19, 18, 2),
- (16, 17, 15),
(15, 16, 17),
- (67, 63, 62),
+ (67, 50, 62),
];
- // test different strides
- for &s1 in &[1, 2, -1, -2] {
- for &s2 in &[1, 2, -1, -2] {
- for &(m, k, n) in &sizes {
- let a = range_mat64(m, k);
- let b = range_mat64(k, n);
- let mut c = range_mat64(m, n);
+ let strides = &[1, 2, -1, -2];
+ let cf_order = [Order::C, Order::F];
+ let generator = [ElementGenerator::Sequential, ElementGenerator::Checkerboard];
+
+ // test different strides and memory orders
+ for (&s1, &s2, &gen) in iproduct!(strides, strides, &generator) {
+ for &(m, k, n) in &sizes {
+ for (ord1, ord2, ord3) in iproduct!(cf_order, cf_order, cf_order) {
+ println!("Case s1={}, s2={}, gen={:?}, orders={:?}, {:?}, {:?}", s1, s2, gen, ord1, ord2, ord3);
+ let a = ArrayBuilder::new((m, k))
+ .memory_order(ord1)
+ .generator(gen)
+ .build()
+ * 0.5;
+ let b = ArrayBuilder::new((k, n)).memory_order(ord2).build();
+ let mut c = ArrayBuilder::new((m, n)).memory_order(ord3).build();
+
let mut answer = c.clone();
{
- let a = a.slice(s![..;s1, ..;s2]);
- let b = b.slice(s![..;s2, ..;s2]);
- let mut cv = c.slice_mut(s![..;s1, ..;s2]);
+ let av;
+ let bv;
+ let mut cv;
+
+ if s1 != 1 || s2 != 1 {
+ av = a.slice(s![..;s1, ..;s2]);
+ bv = b.slice(s![..;s2, ..;s2]);
+ cv = c.slice_mut(s![..;s1, ..;s2]);
+ } else {
+ // different stride cases for slicing versus not sliced (for axes of
+ // len=1); so test not sliced here.
+ av = a.view();
+ bv = b.view();
+ cv = c.view_mut();
+ }
- let answer_part = alpha * reference_mat_mul(&a, &b) + beta * &cv;
+ let answer_part: Array = alpha * reference_mat_mul(&av, &bv) + beta * &cv;
answer.slice_mut(s![..;s1, ..;s2]).assign(&answer_part);
- general_mat_mul(alpha, &a, &b, beta, &mut cv);
+ general_mat_mul(alpha, &av, &bv, beta, &mut cv);
}
assert_relative_eq!(c, answer, epsilon = 1e-12, max_relative = 1e-7);
}
@@ -280,11 +295,11 @@ fn gen_mat_mul()
#[test]
fn gemm_64_1_f()
{
- let a = range_mat64(64, 64).reversed_axes();
+ let a = range_mat::(64, 64).reversed_axes();
let (m, n) = a.dim();
// m x n times n x 1 == m x 1
- let x = range_mat64(n, 1);
- let mut y = range_mat64(m, 1);
+ let x = range_mat::(n, 1);
+ let mut y = range_mat::(m, 1);
let answer = reference_mat_mul(&a, &x) + &y;
general_mat_mul(1.0, &a, &x, 1.0, &mut y);
assert_relative_eq!(y, answer, epsilon = 1e-12, max_relative = 1e-7);
@@ -366,11 +381,8 @@ fn gen_mat_vec_mul()
for &s1 in &[1, 2, -1, -2] {
for &s2 in &[1, 2, -1, -2] {
for &(m, k) in &sizes {
- for &rev in &[false, true] {
- let mut a = range_mat64(m, k);
- if rev {
- a = a.reversed_axes();
- }
+ for order in [Order::C, Order::F] {
+ let a = ArrayBuilder::new((m, k)).memory_order(order).build();
let (m, k) = a.dim();
let b = range1_mat64(k);
let mut c = range1_mat64(m);
@@ -411,11 +423,8 @@ fn vec_mat_mul()
for &s1 in &[1, 2, -1, -2] {
for &s2 in &[1, 2, -1, -2] {
for &(m, n) in &sizes {
- for &rev in &[false, true] {
- let mut b = range_mat64(m, n);
- if rev {
- b = b.reversed_axes();
- }
+ for order in [Order::C, Order::F] {
+ let b = ArrayBuilder::new((m, n)).memory_order(order).build();
let (m, n) = b.dim();
let a = range1_mat64(m);
let mut c = range1_mat64(n);
diff --git a/crates/ndarray-gen/Cargo.toml b/crates/ndarray-gen/Cargo.toml
new file mode 100644
index 000000000..6818e4b65
--- /dev/null
+++ b/crates/ndarray-gen/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "ndarray-gen"
+version = "0.1.0"
+edition = "2018"
+publish = false
+
+[dependencies]
+ndarray = { workspace = true, default-features = false }
+num-traits = { workspace = true }
diff --git a/crates/ndarray-gen/README.md b/crates/ndarray-gen/README.md
new file mode 100644
index 000000000..7dd02320c
--- /dev/null
+++ b/crates/ndarray-gen/README.md
@@ -0,0 +1,4 @@
+
+## ndarray-gen
+
+Array generation functions, used for testing.
diff --git a/crates/ndarray-gen/src/array_builder.rs b/crates/ndarray-gen/src/array_builder.rs
new file mode 100644
index 000000000..9351aadc5
--- /dev/null
+++ b/crates/ndarray-gen/src/array_builder.rs
@@ -0,0 +1,96 @@
+// Copyright 2024 bluss and ndarray developers.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ndarray::Array;
+use ndarray::Dimension;
+use ndarray::IntoDimension;
+use ndarray::Order;
+
+use num_traits::Num;
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub struct ArrayBuilder
+{
+ dim: D,
+ memory_order: Order,
+ generator: ElementGenerator,
+}
+
+/// How to generate elements
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum ElementGenerator
+{
+ Sequential,
+ Checkerboard,
+ Zero,
+}
+
+impl Default for ArrayBuilder
+{
+ fn default() -> Self
+ {
+ Self::new(D::zeros(D::NDIM.unwrap_or(1)))
+ }
+}
+
+impl ArrayBuilder
+where D: Dimension
+{
+ pub fn new(dim: impl IntoDimension) -> Self
+ {
+ ArrayBuilder {
+ dim: dim.into_dimension(),
+ memory_order: Order::C,
+ generator: ElementGenerator::Sequential,
+ }
+ }
+
+ pub fn memory_order(mut self, order: Order) -> Self
+ {
+ self.memory_order = order;
+ self
+ }
+
+ pub fn generator(mut self, generator: ElementGenerator) -> Self
+ {
+ self.generator = generator;
+ self
+ }
+
+ pub fn build(self) -> Array
+ where T: Num + Clone
+ {
+ let zero = T::zero();
+ let size = self.dim.size();
+ (match self.generator {
+ ElementGenerator::Sequential =>
+ Array::from_iter(core::iter::successors(Some(zero), |elt| Some(elt.clone() + T::one())).take(size)),
+ ElementGenerator::Checkerboard => Array::from_iter([T::one(), zero].iter().cycle().take(size).cloned()),
+ ElementGenerator::Zero => Array::zeros(size),
+ })
+ .into_shape_with_order((self.dim, self.memory_order))
+ .unwrap()
+ }
+}
+
+#[test]
+fn test_order()
+{
+ let (m, n) = (12, 13);
+ let c = ArrayBuilder::new((m, n))
+ .memory_order(Order::C)
+ .build::();
+ let f = ArrayBuilder::new((m, n))
+ .memory_order(Order::F)
+ .build::();
+
+ assert_eq!(c.shape(), &[m, n]);
+ assert_eq!(f.shape(), &[m, n]);
+ assert_eq!(c.strides(), &[n as isize, 1]);
+ assert_eq!(f.strides(), &[1, m as isize]);
+}
diff --git a/crates/ndarray-gen/src/lib.rs b/crates/ndarray-gen/src/lib.rs
new file mode 100644
index 000000000..09440e68d
--- /dev/null
+++ b/crates/ndarray-gen/src/lib.rs
@@ -0,0 +1,11 @@
+#![no_std]
+// Copyright 2024 bluss and ndarray developers.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// Build ndarray arrays for test purposes
+pub mod array_builder;
diff --git a/crates/numeric-tests/Cargo.toml b/crates/numeric-tests/Cargo.toml
new file mode 100644
index 000000000..93a182e66
--- /dev/null
+++ b/crates/numeric-tests/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "numeric-tests"
+version = "0.1.0"
+authors = ["bluss"]
+publish = false
+edition = "2018"
+
+[lib]
+test = false
+doc = false
+doctest = false
+
+[dependencies]
+ndarray = { workspace = true, features = ["approx"] }
+ndarray-rand = { workspace = true }
+
+approx = { workspace = true }
+rand = { workspace = true }
+rand_distr = { workspace = true }
+
+blas-src = { optional = true, version = "0.10", default-features = false, features = ["openblas"] }
+openblas-src = { optional = true, version = ">=0.10.11", default-features = false, features = ["cblas", "system"] }
+
+[dev-dependencies]
+num-traits = { workspace = true }
+num-complex = { workspace = true }
+
+[features]
+test_blas = ["ndarray/blas", "blas-src", "openblas-src"]
diff --git a/xtest-numeric/src/lib.rs b/crates/numeric-tests/src/lib.rs
similarity index 100%
rename from xtest-numeric/src/lib.rs
rename to crates/numeric-tests/src/lib.rs
diff --git a/xtest-numeric/tests/accuracy.rs b/crates/numeric-tests/tests/accuracy.rs
similarity index 93%
rename from xtest-numeric/tests/accuracy.rs
rename to crates/numeric-tests/tests/accuracy.rs
index e98fb3c4d..db10d57cd 100644
--- a/xtest-numeric/tests/accuracy.rs
+++ b/crates/numeric-tests/tests/accuracy.rs
@@ -86,7 +86,7 @@ where
#[test]
fn accurate_eye_f32()
{
- let rng = &mut SmallRng::from_entropy();
+ let rng = &mut SmallRng::from_os_rng();
for i in 0..20 {
let eye = Array::eye(i);
for j in 0..20 {
@@ -99,8 +99,8 @@ fn accurate_eye_f32()
}
// pick a few random sizes
for _ in 0..10 {
- let i = rng.gen_range(15..512);
- let j = rng.gen_range(15..512);
+ let i = rng.random_range(15..512);
+ let j = rng.random_range(15..512);
println!("Testing size {} by {}", i, j);
let a = gen::(Ix2(i, j), rng);
let eye = Array::eye(i);
@@ -114,7 +114,7 @@ fn accurate_eye_f32()
#[test]
fn accurate_eye_f64()
{
- let rng = &mut SmallRng::from_entropy();
+ let rng = &mut SmallRng::from_os_rng();
let abs_tol = 1e-15;
for i in 0..20 {
let eye = Array::eye(i);
@@ -128,8 +128,8 @@ fn accurate_eye_f64()
}
// pick a few random sizes
for _ in 0..10 {
- let i = rng.gen_range(15..512);
- let j = rng.gen_range(15..512);
+ let i = rng.random_range(15..512);
+ let j = rng.random_range(15..512);
println!("Testing size {} by {}", i, j);
let a = gen::(Ix2(i, j), rng);
let eye = Array::eye(i);
@@ -172,9 +172,9 @@ fn random_matrix_mul(
) -> (Array2, Array2)
where A: LinalgScalar
{
- let m = rng.gen_range(15..512);
- let k = rng.gen_range(15..512);
- let n = rng.gen_range(15..1560);
+ let m = rng.random_range(15..128);
+ let k = rng.random_range(15..128);
+ let n = rng.random_range(15..512);
let a = generator(Ix2(m, k), rng);
let b = generator(Ix2(n, k), rng);
let c = if use_general {
@@ -209,7 +209,7 @@ where
A: fmt::Debug,
{
// pick a few random sizes
- let mut rng = SmallRng::from_entropy();
+ let mut rng = SmallRng::from_os_rng();
for i in 0..20 {
let (c, reference) = random_matrix_mul(&mut rng, i > 10, use_general, gen::);
@@ -241,7 +241,7 @@ where
A: fmt::Debug,
{
// pick a few random sizes
- let mut rng = SmallRng::from_entropy();
+ let mut rng = SmallRng::from_os_rng();
for i in 0..20 {
let (c, reference) = random_matrix_mul(&mut rng, i > 10, true, gen_complex::);
@@ -259,10 +259,10 @@ where
fn accurate_mul_with_column_f64()
{
// pick a few random sizes
- let rng = &mut SmallRng::from_entropy();
+ let rng = &mut SmallRng::from_os_rng();
for i in 0..10 {
- let m = rng.gen_range(1..350);
- let k = rng.gen_range(1..350);
+ let m = rng.random_range(1..128);
+ let k = rng.random_range(1..350);
let a = gen::(Ix2(m, k), rng);
let b_owner = gen::(Ix2(k, k), rng);
let b_row_col;
diff --git a/crates/serialization-tests/Cargo.toml b/crates/serialization-tests/Cargo.toml
new file mode 100644
index 000000000..4ad165f39
--- /dev/null
+++ b/crates/serialization-tests/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "serialization-tests"
+version = "0.1.0"
+authors = ["bluss"]
+publish = false
+edition = "2018"
+
+[lib]
+test = false
+doc = false
+doctest = false
+
+[dependencies]
+ndarray = { workspace = true, features = ["serde"] }
+
+serde = { version = "1.0.100", default-features = false }
+ron = { version = "0.8.1" }
+
+[dev-dependencies]
+serde_json = { version = "1.0.40" }
+# >=0.8.11 to avoid rmp-serde security vulnerability
+# <0.8.14 to allows MSRV 1.64.0
+rmp = { version = ">=0.8.11,<0.8.14" }
+# Old version to work with Rust 1.64+
+rmp-serde = { version = ">=1.1.1" }
diff --git a/xtest-serialization/src/lib.rs b/crates/serialization-tests/src/lib.rs
similarity index 100%
rename from xtest-serialization/src/lib.rs
rename to crates/serialization-tests/src/lib.rs
diff --git a/xtest-serialization/tests/serialize.rs b/crates/serialization-tests/tests/serialize.rs
similarity index 93%
rename from xtest-serialization/tests/serialize.rs
rename to crates/serialization-tests/tests/serialize.rs
index 95e93e4fb..478eb20ef 100644
--- a/xtest-serialization/tests/serialize.rs
+++ b/crates/serialization-tests/tests/serialize.rs
@@ -6,7 +6,6 @@ extern crate serde_json;
extern crate rmp_serde;
-#[cfg(feature = "ron")]
extern crate ron;
use ndarray::{arr0, arr1, arr2, s, ArcArray, ArcArray2, ArrayD, IxDyn};
@@ -46,13 +45,13 @@ fn serial_many_dim_serde()
{
// Test a sliced array.
- let mut a = ArcArray::linspace(0., 31., 32)
+ let mut a = ArcArray::from_iter(0..32)
.into_shape_with_order((2, 2, 2, 4))
.unwrap();
a.slice_collapse(s![..;-1, .., .., ..2]);
let serial = serde_json::to_string(&a).unwrap();
println!("Encode {:?} => {:?}", a, serial);
- let res = serde_json::from_str::>(&serial);
+ let res = serde_json::from_str::>(&serial);
println!("{:?}", res);
assert_eq!(a, res.unwrap());
}
@@ -161,7 +160,7 @@ fn serial_many_dim_serde_msgpack()
{
// Test a sliced array.
- let mut a = ArcArray::linspace(0., 31., 32)
+ let mut a = ArcArray::from_iter(0..32)
.into_shape_with_order((2, 2, 2, 4))
.unwrap();
a.slice_collapse(s![..;-1, .., .., ..2]);
@@ -172,14 +171,13 @@ fn serial_many_dim_serde_msgpack()
.unwrap();
let mut deserializer = rmp_serde::Deserializer::new(&buf[..]);
- let a_de: ArcArray = serde::Deserialize::deserialize(&mut deserializer).unwrap();
+ let a_de: ArcArray = serde::Deserialize::deserialize(&mut deserializer).unwrap();
assert_eq!(a, a_de);
}
}
#[test]
-#[cfg(feature = "ron")]
fn serial_many_dim_ron()
{
use ron::de::from_str as ron_deserialize;
@@ -217,14 +215,14 @@ fn serial_many_dim_ron()
{
// Test a sliced array.
- let mut a = ArcArray::linspace(0., 31., 32)
+ let mut a = ArcArray::from_iter(0..32)
.into_shape_with_order((2, 2, 2, 4))
.unwrap();
a.slice_collapse(s![..;-1, .., .., ..2]);
let a_s = ron_serialize(&a).unwrap();
- let a_de: ArcArray = ron_deserialize(&a_s).unwrap();
+ let a_de: ArcArray = ron_deserialize(&a_s).unwrap();
assert_eq!(a, a_de);
}
diff --git a/examples/axis_ops.rs b/examples/axis_ops.rs
index 3a54a52fb..7f80a637f 100644
--- a/examples/axis_ops.rs
+++ b/examples/axis_ops.rs
@@ -13,7 +13,7 @@ use ndarray::prelude::*;
/// it corresponds to their order in memory.
///
/// Errors if array has a 0-stride axis
-fn regularize(a: &mut Array) -> Result<(), &'static str>
+fn regularize(a: &mut ArrayRef) -> Result<(), &'static str>
where
D: Dimension,
A: ::std::fmt::Debug,
diff --git a/examples/bounds_check_elim.rs b/examples/bounds_check_elim.rs
index e6b57c719..f1a91cca0 100644
--- a/examples/bounds_check_elim.rs
+++ b/examples/bounds_check_elim.rs
@@ -57,7 +57,7 @@ pub fn test1d_single_mut(a: &mut Array1, i: usize) -> f64
#[no_mangle]
pub fn test1d_len_of(a: &Array1) -> f64
{
- let a = &*a;
+ let a = a;
let mut sum = 0.;
for i in 0..a.len_of(Axis(0)) {
sum += a[i];
diff --git a/examples/convo.rs b/examples/convo.rs
index a59795e12..79e8ab6b6 100644
--- a/examples/convo.rs
+++ b/examples/convo.rs
@@ -14,7 +14,7 @@ type Kernel3x3 = [[A; 3]; 3];
#[inline(never)]
#[cfg(feature = "std")]
-fn conv_3x3(a: &ArrayView2<'_, F>, out: &mut ArrayViewMut2<'_, F>, kernel: &Kernel3x3)
+fn conv_3x3(a: &ArrayRef2, out: &mut ArrayRef2, kernel: &Kernel3x3)
where F: Float
{
let (n, m) = a.dim();
diff --git a/examples/functions_and_traits.rs b/examples/functions_and_traits.rs
new file mode 100644
index 000000000..dc8f73da4
--- /dev/null
+++ b/examples/functions_and_traits.rs
@@ -0,0 +1,178 @@
+//! Examples of how to write functions and traits that operate on `ndarray` types.
+//!
+//! `ndarray` has four kinds of array types that users may interact with:
+//! 1. [`ArrayBase`], the owner of the layout that describes an array in memory;
+//! this includes [`ndarray::Array`], [`ndarray::ArcArray`], [`ndarray::ArrayView`],
+//! [`ndarray::RawArrayView`], and other variants.
+//! 2. [`ArrayRef`], which represents a read-safe, uniquely-owned look at an array.
+//! 3. [`RawRef`], which represents a read-unsafe, possibly-shared look at an array.
+//! 4. [`LayoutRef`], which represents a look at an array's underlying structure,
+//! but does not allow data reading of any kind.
+//!
+//! Below, we illustrate how to write functions and traits for most variants of these types.
+
+use ndarray::{ArrayBase, ArrayRef, Data, DataMut, Dimension, LayoutRef, RawData, RawDataMut, RawRef};
+
+/// Take an array with the most basic requirements.
+///
+/// This function takes its data as owning. It is very rare that a user will need to specifically
+/// take a reference to an `ArrayBase`, rather than to one of the other four types.
+#[rustfmt::skip]
+fn takes_base_raw(arr: ArrayBase) -> ArrayBase
+{
+ // These skip from a possibly-raw array to `RawRef` and `LayoutRef`, and so must go through `AsRef`
+ takes_rawref(arr.as_ref()); // Caller uses `.as_ref`
+ takes_rawref_asref(&arr); // Implementor uses `.as_ref`
+ takes_layout(arr.as_ref()); // Caller uses `.as_ref`
+ takes_layout_asref(&arr); // Implementor uses `.as_ref`
+
+ arr
+}
+
+/// Similar to above, but allow us to read the underlying data.
+#[rustfmt::skip]
+fn takes_base_raw_mut(mut arr: ArrayBase) -> ArrayBase
+{
+ // These skip from a possibly-raw array to `RawRef` and `LayoutRef`, and so must go through `AsMut`
+ takes_rawref_mut(arr.as_mut()); // Caller uses `.as_mut`
+ takes_rawref_asmut(&mut arr); // Implementor uses `.as_mut`
+ takes_layout_mut(arr.as_mut()); // Caller uses `.as_mut`
+ takes_layout_asmut(&mut arr); // Implementor uses `.as_mut`
+
+ arr
+}
+
+/// Now take an array whose data is safe to read.
+#[allow(dead_code)]
+fn takes_base(mut arr: ArrayBase) -> ArrayBase
+{
+ // Raw call
+ arr = takes_base_raw(arr);
+
+ // No need for AsRef, since data is safe
+ takes_arrref(&arr);
+ takes_rawref(&arr);
+ takes_rawref_asref(&arr);
+ takes_layout(&arr);
+ takes_layout_asref(&arr);
+
+ arr
+}
+
+/// Now, an array whose data is safe to read and that we can mutate.
+///
+/// Notice that we include now a trait bound on `D: Dimension`; this is necessary in order
+/// for the `ArrayBase` to dereference to an `ArrayRef` (or to any of the other types).
+#[allow(dead_code)]
+fn takes_base_mut(mut arr: ArrayBase) -> ArrayBase
+{
+ // Raw call
+ arr = takes_base_raw_mut(arr);
+
+ // No need for AsMut, since data is safe
+ takes_arrref_mut(&mut arr);
+ takes_rawref_mut(&mut arr);
+ takes_rawref_asmut(&mut arr);
+ takes_layout_mut(&mut arr);
+ takes_layout_asmut(&mut arr);
+
+ arr
+}
+
+/// Now for new stuff: we want to read (but not alter) any array whose data is safe to read.
+///
+/// This is probably the most common functionality that one would want to write.
+/// As we'll see below, calling this function is very simple for `ArrayBase`.
+fn takes_arrref(arr: &ArrayRef)
+{
+ // No need for AsRef, since data is safe
+ takes_rawref(arr);
+ takes_rawref_asref(arr);
+ takes_layout(arr);
+ takes_layout_asref(arr);
+}
+
+/// Now we want any array whose data is safe to mutate.
+///
+/// **Importantly**, any array passed to this function is guaranteed to uniquely point to its data.
+/// As a result, passing a shared array to this function will **silently** un-share the array.
+#[allow(dead_code)]
+fn takes_arrref_mut(arr: &mut ArrayRef)
+{
+ // Immutable call
+ takes_arrref(arr);
+
+ // No need for AsMut, since data is safe
+ takes_rawref_mut(arr);
+ takes_rawref_asmut(arr);
+ takes_layout_mut(arr);
+ takes_rawref_asmut(arr);
+}
+
+/// Now, we no longer care about whether we can safely read data.
+///
+/// This is probably the rarest type to deal with, since `LayoutRef` can access and modify an array's
+/// shape and strides, and even do in-place slicing. As a result, `RawRef` is only for functionality
+/// that requires unsafe data access, something that `LayoutRef` can't do.
+///
+/// Writing functions and traits that deal with `RawRef`s and `LayoutRef`s can be done two ways:
+/// 1. Directly on the types; calling these functions on arrays whose data are not known to be safe
+/// to dereference (i.e., raw array views or `ArrayBase`) must explicitly call `.as_ref()`.
+/// 2. Via a generic with `: AsRef>`; doing this will allow direct calling for all `ArrayBase` and
+/// `ArrayRef` instances.
+/// We'll demonstrate #1 here for both immutable and mutable references, then #2 directly below.
+#[allow(dead_code)]
+fn takes_rawref(arr: &RawRef)
+{
+ takes_layout(arr);
+ takes_layout_asref(arr);
+}
+
+/// Mutable, directly take `RawRef`
+#[allow(dead_code)]
+fn takes_rawref_mut(arr: &mut RawRef)
+{
+ takes_layout(arr);
+ takes_layout_asmut(arr);
+}
+
+/// Immutable, take a generic that implements `AsRef` to `RawRef`
+#[allow(dead_code)]
+fn takes_rawref_asref(_arr: &T)
+where T: AsRef>
+{
+ takes_layout(_arr.as_ref());
+ takes_layout_asref(_arr.as_ref());
+}
+
+/// Mutable, take a generic that implements `AsMut` to `RawRef`
+#[allow(dead_code)]
+fn takes_rawref_asmut(_arr: &mut T)
+where T: AsMut>
+{
+ takes_layout_mut(_arr.as_mut());
+ takes_layout_asmut(_arr.as_mut());
+}
+
+/// Finally, there's `LayoutRef`: this type provides read and write access to an array's *structure*, but not its *data*.
+///
+/// Practically, this means that functions that only read/modify an array's shape or strides,
+/// such as checking dimensionality or slicing, should take `LayoutRef`.
+///
+/// Like `RawRef`, functions can be written either directly on `LayoutRef` or as generics with `: AsRef>>`.
+#[allow(dead_code)]
+fn takes_layout(_arr: &LayoutRef) {}
+
+/// Mutable, directly take `LayoutRef`
+#[allow(dead_code)]
+fn takes_layout_mut(_arr: &mut LayoutRef) {}
+
+/// Immutable, take a generic that implements `AsRef` to `LayoutRef`
+#[allow(dead_code)]
+fn takes_layout_asref>, A, D>(_arr: &T) {}
+
+/// Mutable, take a generic that implements `AsMut` to `LayoutRef`
+#[allow(dead_code)]
+fn takes_layout_asmut>, A, D>(_arr: &mut T) {}
+
+fn main() {}
diff --git a/ndarray-rand/Cargo.toml b/ndarray-rand/Cargo.toml
index 4e9bf265f..72b959020 100644
--- a/ndarray-rand/Cargo.toml
+++ b/ndarray-rand/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "ndarray-rand"
-version = "0.14.0"
+version = "0.15.0"
edition = "2018"
authors = ["bluss"]
license = "MIT OR Apache-2.0"
@@ -14,17 +14,15 @@ description = "Constructors for randomized arrays. `rand` integration for `ndarr
keywords = ["multidimensional", "matrix", "rand", "ndarray"]
[dependencies]
-ndarray = { version = "0.15", path = ".." }
-rand_distr = "0.4.0"
-quickcheck = { version = "1.0", default-features = false, optional = true }
+ndarray = { workspace = true }
-[dependencies.rand]
-version = "0.8.0"
-features = ["small_rng"]
+rand = { workspace = true }
+rand_distr = { workspace = true }
+quickcheck = { workspace = true, optional = true }
[dev-dependencies]
-rand_isaac = "0.3.0"
-quickcheck = { version = "1.0", default-features = false }
+rand_isaac = "0.4.0"
+quickcheck = { workspace = true }
[package.metadata.release]
no-dev-version = true
diff --git a/ndarray-rand/RELEASES.md b/ndarray-rand/RELEASES.md
index 8d7586fbe..cff9acd96 100644
--- a/ndarray-rand/RELEASES.md
+++ b/ndarray-rand/RELEASES.md
@@ -1,6 +1,11 @@
Recent Changes
--------------
+- 0.15.0
+
+ - Require ndarray 0.16
+ - Remove deprecated F32 by [@bluss](https://github.com/bluss) [#1409](https://github.com/rust-ndarray/ndarray/pull/1409)
+
- 0.14.0
- Require ndarray 0.15
diff --git a/ndarray-rand/benches/bench.rs b/ndarray-rand/benches/bench.rs
index 0e5eb2ff7..364eca9f4 100644
--- a/ndarray-rand/benches/bench.rs
+++ b/ndarray-rand/benches/bench.rs
@@ -13,7 +13,7 @@ use test::Bencher;
fn uniform_f32(b: &mut Bencher)
{
let m = 100;
- b.iter(|| Array::random((m, m), Uniform::new(-1f32, 1.)));
+ b.iter(|| Array::random((m, m), Uniform::new(-1f32, 1.).unwrap()));
}
#[bench]
diff --git a/ndarray-rand/src/lib.rs b/ndarray-rand/src/lib.rs
index 027198538..795e246d4 100644
--- a/ndarray-rand/src/lib.rs
+++ b/ndarray-rand/src/lib.rs
@@ -29,10 +29,10 @@
//! that the items are not compatible (e.g. that a type doesn't implement a
//! necessary trait).
-use crate::rand::distributions::{Distribution, Uniform};
+use crate::rand::distr::{Distribution, Uniform};
use crate::rand::rngs::SmallRng;
use crate::rand::seq::index;
-use crate::rand::{thread_rng, Rng, SeedableRng};
+use crate::rand::{rng, Rng, SeedableRng};
use ndarray::{Array, Axis, RemoveAxis, ShapeBuilder};
use ndarray::{ArrayBase, Data, DataOwned, Dimension, RawData};
@@ -71,8 +71,8 @@ where
/// Create an array with shape `dim` with elements drawn from
/// `distribution` using the default RNG.
///
- /// ***Panics*** if creation of the RNG fails or if the number of elements
- /// overflows usize.
+ /// ***Panics*** if creation of the RNG fails, the number of elements
+ /// overflows usize, or the axis has zero length.
///
/// ```
/// use ndarray::Array;
@@ -80,7 +80,7 @@ where
/// use ndarray_rand::rand_distr::Uniform;
///
/// # fn main() {
- /// let a = Array::random((2, 5), Uniform::new(0., 10.));
+ /// let a = Array::random((2, 5), Uniform::new(0., 10.).unwrap());
/// println!("{:8.4}", a);
/// // Example Output:
/// // [[ 8.6900, 6.9824, 3.8922, 6.5861, 2.4890],
@@ -95,7 +95,8 @@ where
/// Create an array with shape `dim` with elements drawn from
/// `distribution`, using a specific Rng `rng`.
///
- /// ***Panics*** if the number of elements overflows usize.
+ /// ***Panics*** if the number of elements overflows usize
+ /// or the axis has zero length.
///
/// ```
/// use ndarray::Array;
@@ -110,7 +111,7 @@ where
/// let mut rng = Isaac64Rng::seed_from_u64(seed);
///
/// // Generate a random array using `rng`
- /// let a = Array::random_using((2, 5), Uniform::new(0., 10.), &mut rng);
+ /// let a = Array::random_using((2, 5), Uniform::new(0., 10.).unwrap(), &mut rng);
/// println!("{:8.4}", a);
/// // Example Output:
/// // [[ 8.6900, 6.9824, 3.8922, 6.5861, 2.4890],
@@ -270,7 +271,7 @@ where
{
let indices: Vec<_> = match strategy {
SamplingStrategy::WithReplacement => {
- let distribution = Uniform::from(0..self.len_of(axis));
+ let distribution = Uniform::new(0, self.len_of(axis)).unwrap();
(0..n_samples).map(|_| distribution.sample(rng)).collect()
}
SamplingStrategy::WithoutReplacement => index::sample(rng, self.len_of(axis), n_samples).into_vec(),
@@ -308,34 +309,5 @@ impl Arbitrary for SamplingStrategy
fn get_rng() -> SmallRng
{
- SmallRng::from_rng(thread_rng()).expect("create SmallRng from thread_rng failed")
-}
-
-/// A wrapper type that allows casting f64 distributions to f32
-///
-/// ```
-/// use ndarray::Array;
-/// use ndarray_rand::{RandomExt, F32};
-/// use ndarray_rand::rand_distr::Normal;
-///
-/// # fn main() {
-/// let distribution_f64 = Normal::new(0., 1.).expect("Failed to create normal distribution");
-/// let a = Array::random((2, 5), F32(distribution_f64));
-/// println!("{:8.4}", a);
-/// // Example Output:
-/// // [[ -0.6910, 1.1730, 1.0902, -0.4092, -1.7340],
-/// // [ -0.6810, 0.1678, -0.9487, 0.3150, 1.2981]]
-/// # }
-#[derive(Copy, Clone, Debug)]
-#[deprecated(since = "0.14.0", note = "Redundant with rand 0.8")]
-pub struct F32(pub S);
-
-#[allow(deprecated)]
-impl Distribution for F32
-where S: Distribution
-{
- fn sample(&self, rng: &mut R) -> f32
- {
- self.0.sample(rng) as f32
- }
+ SmallRng::from_rng(&mut rng())
}
diff --git a/ndarray-rand/tests/tests.rs b/ndarray-rand/tests/tests.rs
index 2db040310..5d322551a 100644
--- a/ndarray-rand/tests/tests.rs
+++ b/ndarray-rand/tests/tests.rs
@@ -1,6 +1,6 @@
use ndarray::{Array, Array2, ArrayView1, Axis};
#[cfg(feature = "quickcheck")]
-use ndarray_rand::rand::{distributions::Distribution, thread_rng};
+use ndarray_rand::rand::{distr::Distribution, rng};
use ndarray::ShapeBuilder;
use ndarray_rand::rand_distr::Uniform;
@@ -13,7 +13,7 @@ fn test_dim()
let (mm, nn) = (5, 5);
for m in 0..mm {
for n in 0..nn {
- let a = Array::random((m, n), Uniform::new(0., 2.));
+ let a = Array::random((m, n), Uniform::new(0., 2.).unwrap());
assert_eq!(a.shape(), &[m, n]);
assert!(a.iter().all(|x| *x < 2.));
assert!(a.iter().all(|x| *x >= 0.));
@@ -28,7 +28,7 @@ fn test_dim_f()
let (mm, nn) = (5, 5);
for m in 0..mm {
for n in 0..nn {
- let a = Array::random((m, n).f(), Uniform::new(0., 2.));
+ let a = Array::random((m, n).f(), Uniform::new(0., 2.).unwrap());
assert_eq!(a.shape(), &[m, n]);
assert!(a.iter().all(|x| *x < 2.));
assert!(a.iter().all(|x| *x >= 0.));
@@ -41,7 +41,7 @@ fn test_dim_f()
fn sample_axis_on_view()
{
let m = 5;
- let a = Array::random((m, 4), Uniform::new(0., 2.));
+ let a = Array::random((m, 4), Uniform::new(0., 2.).unwrap());
let _samples = a
.view()
.sample_axis(Axis(0), m, SamplingStrategy::WithoutReplacement);
@@ -52,14 +52,15 @@ fn sample_axis_on_view()
fn oversampling_without_replacement_should_panic()
{
let m = 5;
- let a = Array::random((m, 4), Uniform::new(0., 2.));
+ let a = Array::random((m, 4), Uniform::new(0., 2.).unwrap());
let _samples = a.sample_axis(Axis(0), m + 1, SamplingStrategy::WithoutReplacement);
}
quickcheck! {
+ #[cfg_attr(miri, ignore)] // Takes an insufferably long time
fn oversampling_with_replacement_is_fine(m: u8, n: u8) -> TestResult {
let (m, n) = (m as usize, n as usize);
- let a = Array::random((m, n), Uniform::new(0., 2.));
+ let a = Array::random((m, n), Uniform::new(0., 2.).unwrap());
// Higher than the length of both axes
let n_samples = m + n + 1;
@@ -86,14 +87,15 @@ quickcheck! {
#[cfg(feature = "quickcheck")]
quickcheck! {
+ #[cfg_attr(miri, ignore)] // This takes *forever* with Miri
fn sampling_behaves_as_expected(m: u8, n: u8, strategy: SamplingStrategy) -> TestResult {
let (m, n) = (m as usize, n as usize);
- let a = Array::random((m, n), Uniform::new(0., 2.));
- let mut rng = &mut thread_rng();
+ let a = Array::random((m, n), Uniform::new(0., 2.).unwrap());
+ let mut rng = &mut rng();
// We don't want to deal with sampling from 0-length axes in this test
if m != 0 {
- let n_row_samples = Uniform::from(1..m+1).sample(&mut rng);
+ let n_row_samples = Uniform::new(1, m+1).unwrap().sample(&mut rng);
if !sampling_works(&a, strategy.clone(), Axis(0), n_row_samples) {
return TestResult::failed();
}
@@ -103,7 +105,7 @@ quickcheck! {
// We don't want to deal with sampling from 0-length axes in this test
if n != 0 {
- let n_col_samples = Uniform::from(1..n+1).sample(&mut rng);
+ let n_col_samples = Uniform::new(1, n+1).unwrap().sample(&mut rng);
if !sampling_works(&a, strategy, Axis(1), n_col_samples) {
return TestResult::failed();
}
@@ -120,7 +122,7 @@ fn sampling_works(a: &Array2, strategy: SamplingStrategy, axis: Axis, n_sam
let samples = a.sample_axis(axis, n_samples, strategy);
samples
.axis_iter(axis)
- .all(|lane| is_subset(&a, &lane, axis))
+ .all(|lane| is_subset(a, &lane, axis))
}
// Check if, when sliced along `axis`, there is at least one lane in `a` equal to `b`
@@ -134,7 +136,7 @@ fn is_subset(a: &Array2, b: &ArrayView1, axis: Axis) -> bool
fn sampling_without_replacement_from_a_zero_length_axis_should_panic()
{
let n = 5;
- let a = Array::random((0, n), Uniform::new(0., 2.));
+ let a = Array::random((0, n), Uniform::new(0., 2.).unwrap());
let _samples = a.sample_axis(Axis(0), 1, SamplingStrategy::WithoutReplacement);
}
@@ -143,6 +145,6 @@ fn sampling_without_replacement_from_a_zero_length_axis_should_panic()
fn sampling_with_replacement_from_a_zero_length_axis_should_panic()
{
let n = 5;
- let a = Array::random((0, n), Uniform::new(0., 2.));
+ let a = Array::random((0, n), Uniform::new(0., 2.).unwrap());
let _samples = a.sample_axis(Axis(0), 1, SamplingStrategy::WithReplacement);
}
diff --git a/scripts/all-tests.sh b/scripts/all-tests.sh
index cbea6dba7..612a7d758 100755
--- a/scripts/all-tests.sh
+++ b/scripts/all-tests.sh
@@ -6,36 +6,29 @@ set -e
FEATURES=$1
CHANNEL=$2
-if [ "$CHANNEL" = "1.57.0" ]; then
- cargo update --package openblas-src --precise 0.10.5
- cargo update --package openblas-build --precise 0.10.5
- cargo update --package once_cell --precise 1.14.0
- cargo update --package byteorder --precise 1.4.3
- cargo update --package rayon --precise 1.5.3
- cargo update --package rayon-core --precise 1.9.3
- cargo update --package crossbeam-channel --precise 0.5.8
- cargo update --package crossbeam-deque --precise 0.8.3
- cargo update --package crossbeam-epoch --precise 0.9.15
- cargo update --package crossbeam-utils --precise 0.8.16
- cargo update --package rmp --precise 0.8.11
- cargo update --package serde_json --precise 1.0.99
- cargo update --package serde --precise 1.0.156
- cargo update --package thiserror --precise 1.0.39
- cargo update --package quote --precise 1.0.30
- cargo update --package proc-macro2 --precise 1.0.65
+QC_FEAT=--features=ndarray-rand/quickcheck
+
+# build check with no features
+cargo build -v --no-default-features
+
+# ndarray with no features
+cargo test -p ndarray -v --no-default-features
+# ndarray with no_std-compatible features
+cargo test -p ndarray -v --no-default-features --features approx
+# all with features
+cargo test -v --features "$FEATURES" $QC_FEAT
+# all with features and release (ignore test crates which is already optimized)
+cargo test -v -p ndarray -p ndarray-rand --release --features "$FEATURES" $QC_FEAT --lib --tests
+
+# BLAS tests
+cargo test -p ndarray --lib -v --features blas
+cargo test -p blas-mock-tests -v
+if [[ -z "${MSRV}" ]] && [ "$CHANNEL" != "$MSRV" ]; then
+ ./scripts/blas-integ-tests.sh "$FEATURES" $CHANNEL
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
-cargo test --release --verbose --no-default-features
-cargo build --verbose --features "$FEATURES"
-cargo test --verbose --features "$FEATURES"
-cargo test --manifest-path=ndarray-rand/Cargo.toml --no-default-features --verbose
-cargo test --manifest-path=ndarray-rand/Cargo.toml --features quickcheck --verbose
-cargo test --manifest-path=xtest-serialization/Cargo.toml --verbose
-cargo test --manifest-path=xtest-blas/Cargo.toml --verbose --features openblas-system
+# Examples
cargo test --examples
-cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose
-cargo test --manifest-path=xtest-numeric/Cargo.toml --verbose --features test_blas
+
+# Benchmarks
([ "$CHANNEL" != "nightly" ] || cargo bench --no-run --verbose --features "$FEATURES")
diff --git a/scripts/blas-integ-tests.sh b/scripts/blas-integ-tests.sh
new file mode 100755
index 000000000..3d769e0af
--- /dev/null
+++ b/scripts/blas-integ-tests.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -x
+set -e
+
+# BLAS tests
+cargo test -p blas-tests -v --features blas-tests/openblas-system
+cargo test -p numeric-tests -v --features numeric-tests/test_blas
diff --git a/scripts/cross-tests.sh b/scripts/cross-tests.sh
index dc27058f8..80b37c339 100755
--- a/scripts/cross-tests.sh
+++ b/scripts/cross-tests.sh
@@ -7,8 +7,8 @@ FEATURES=$1
CHANNEL=$2
TARGET=$3
-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
-cross test -v --no-fail-fast --target=$TARGET --manifest-path=xtest-numeric/Cargo.toml --release
+QC_FEAT=--features=ndarray-rand/quickcheck
+
+cross build -v --features="$FEATURES" $QC_FEAT --target=$TARGET
+cross test -v --no-fail-fast --features="$FEATURES" $QC_FEAT --target=$TARGET
+cross test -v -p blas-mock-tests
diff --git a/scripts/makechangelog.sh b/scripts/makechangelog.sh
new file mode 100755
index 000000000..535280804
--- /dev/null
+++ b/scripts/makechangelog.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Usage: makechangelog
+#
+# This script depends on and uses the github `gh` binary
+# which needs to be authenticated to use.
+#
+# Will produce some duplicates for PRs integrated using rebase,
+# but those will not occur with current merge queue.
+
+git log --first-parent --pretty="tformat:%H" "$@" | while IFS= read -r commit_sha
+do
+ gh api "/repos/:owner/:repo/commits/${commit_sha}/pulls" \
+ -q ".[] | \"- \(.title) by [@\(.user.login)](\(.user.html_url)) [#\(.number)](\(.html_url))\""
+done | uniq
+
diff --git a/scripts/miri-tests.sh b/scripts/miri-tests.sh
new file mode 100755
index 000000000..0100f3e6a
--- /dev/null
+++ b/scripts/miri-tests.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -x
+set -e
+
+# We rely on layout-dependent casts, which should be covered with #[repr(transparent)]
+# This should catch if we missed that
+RUSTFLAGS="-Zrandomize-layout"
+
+# Miri reports a stacked borrow violation deep within rayon, in a crate called crossbeam-epoch
+# The crate has a PR to fix this: https://github.com/crossbeam-rs/crossbeam/pull/871
+# but using Miri's tree borrow mode may resolve it for now.
+# Disabled until we can figure out a different rayon issue: https://github.com/rust-lang/miri/issues/1371
+# MIRIFLAGS="-Zmiri-tree-borrows"
+
+# General tests
+# Note that we exclude blas feature because Miri can't do cblas_gemm
+cargo miri test -v -p ndarray -p ndarray-rand --features approx,serde
diff --git a/src/alias_asref.rs b/src/alias_asref.rs
new file mode 100644
index 000000000..ab78af605
--- /dev/null
+++ b/src/alias_asref.rs
@@ -0,0 +1,359 @@
+use crate::{
+ iter::Axes,
+ ArrayBase,
+ Axis,
+ AxisDescription,
+ Dimension,
+ NdIndex,
+ RawArrayView,
+ RawData,
+ RawDataMut,
+ Slice,
+ SliceArg,
+};
+
+/// Functions coming from RawRef
+impl, D: Dimension> ArrayBase
+{
+ /// Return a raw pointer to the element at `index`, or return `None`
+ /// if the index is out of bounds.
+ ///
+ /// ```
+ /// use ndarray::arr2;
+ ///
+ /// let a = arr2(&[[1., 2.], [3., 4.]]);
+ ///
+ /// let v = a.raw_view();
+ /// let p = a.get_ptr((0, 1)).unwrap();
+ ///
+ /// assert_eq!(unsafe { *p }, 2.);
+ /// ```
+ pub fn get_ptr(&self, index: I) -> Option<*const A>
+ where I: NdIndex
+ {
+ self.as_raw_ref().get_ptr(index)
+ }
+
+ /// Return a raw pointer to the element at `index`, or return `None`
+ /// if the index is out of bounds.
+ ///
+ /// ```
+ /// use ndarray::arr2;
+ ///
+ /// let mut a = arr2(&[[1., 2.], [3., 4.]]);
+ ///
+ /// let v = a.raw_view_mut();
+ /// let p = a.get_mut_ptr((0, 1)).unwrap();
+ ///
+ /// unsafe {
+ /// *p = 5.;
+ /// }
+ ///
+ /// assert_eq!(a.get((0, 1)), Some(&5.));
+ /// ```
+ pub fn get_mut_ptr(&mut self, index: I) -> Option<*mut A>
+ where
+ S: RawDataMut,
+ I: NdIndex,
+ {
+ self.as_raw_ref_mut().get_mut_ptr(index)
+ }
+
+ /// Return a pointer to the first element in the array.
+ ///
+ /// Raw access to array elements needs to follow the strided indexing
+ /// scheme: an element at multi-index *I* in an array with strides *S* is
+ /// located at offset
+ ///
+ /// *Σ0 ≤ k < d Ik × Sk*
+ ///
+ /// where *d* is `self.ndim()`.
+ #[inline(always)]
+ pub fn as_ptr(&self) -> *const A
+ {
+ self.as_raw_ref().as_ptr()
+ }
+
+ /// Return a raw view of the array.
+ #[inline]
+ pub fn raw_view(&self) -> RawArrayView
+ {
+ self.as_raw_ref().raw_view()
+ }
+}
+
+/// Functions coming from LayoutRef
+impl ArrayBase
+{
+ /// Slice the array in place without changing the number of dimensions.
+ ///
+ /// In particular, if an axis is sliced with an index, the axis is
+ /// collapsed, as in [`.collapse_axis()`], rather than removed, as in
+ /// [`.slice_move()`] or [`.index_axis_move()`].
+ ///
+ /// [`.collapse_axis()`]: Self::collapse_axis
+ /// [`.slice_move()`]: Self::slice_move
+ /// [`.index_axis_move()`]: Self::index_axis_move
+ ///
+ /// See [*Slicing*](#slicing) for full documentation.
+ /// See also [`s!`], [`SliceArg`], and [`SliceInfo`](crate::SliceInfo).
+ ///
+ /// **Panics** in the following cases:
+ ///
+ /// - if an index is out of bounds
+ /// - if a step size is zero
+ /// - if [`NewAxis`](`crate::SliceInfoElem::NewAxis`) is in `info`, e.g. if `NewAxis` was
+ /// used in the [`s!`] macro
+ /// - if `D` is `IxDyn` and `info` does not match the number of array axes
+ #[track_caller]
+ pub fn slice_collapse(&mut self, info: I)
+ where I: SliceArg
+ {
+ self.as_layout_ref_mut().slice_collapse(info);
+ }
+
+ /// Slice the array in place along the specified axis.
+ ///
+ /// **Panics** if an index is out of bounds or step size is zero.
+ /// **Panics** if `axis` is out of bounds.
+ #[track_caller]
+ pub fn slice_axis_inplace(&mut self, axis: Axis, indices: Slice)
+ {
+ self.as_layout_ref_mut().slice_axis_inplace(axis, indices);
+ }
+
+ /// Slice the array in place, with a closure specifying the slice for each
+ /// axis.
+ ///
+ /// This is especially useful for code which is generic over the
+ /// dimensionality of the array.
+ ///
+ /// **Panics** if an index is out of bounds or step size is zero.
+ #[track_caller]
+ pub fn slice_each_axis_inplace(&mut self, f: F)
+ where F: FnMut(AxisDescription) -> Slice
+ {
+ self.as_layout_ref_mut().slice_each_axis_inplace(f);
+ }
+
+ /// Selects `index` along the axis, collapsing the axis into length one.
+ ///
+ /// **Panics** if `axis` or `index` is out of bounds.
+ #[track_caller]
+ pub fn collapse_axis(&mut self, axis: Axis, index: usize)
+ {
+ self.as_layout_ref_mut().collapse_axis(axis, index);
+ }
+
+ /// Return `true` if the array data is laid out in contiguous “C order” in
+ /// memory (where the last index is the most rapidly varying).
+ ///
+ /// Return `false` otherwise, i.e. the array is possibly not
+ /// contiguous in memory, it has custom strides, etc.
+ pub fn is_standard_layout(&self) -> bool
+ {
+ self.as_layout_ref().is_standard_layout()
+ }
+
+ /// Return true if the array is known to be contiguous.
+ pub(crate) fn is_contiguous(&self) -> bool
+ {
+ self.as_layout_ref().is_contiguous()
+ }
+
+ /// Return an iterator over the length and stride of each axis.
+ pub fn axes(&self) -> Axes<'_, D>
+ {
+ self.as_layout_ref().axes()
+ }
+
+ /*
+ /// Return the axis with the least stride (by absolute value)
+ pub fn min_stride_axis(&self) -> Axis {
+ self.dim.min_stride_axis(&self.strides)
+ }
+ */
+
+ /// Return the axis with the greatest stride (by absolute value),
+ /// preferring axes with len > 1.
+ pub fn max_stride_axis(&self) -> Axis
+ {
+ self.as_layout_ref().max_stride_axis()
+ }
+
+ /// Reverse the stride of `axis`.
+ ///
+ /// ***Panics*** if the axis is out of bounds.
+ #[track_caller]
+ pub fn invert_axis(&mut self, axis: Axis)
+ {
+ self.as_layout_ref_mut().invert_axis(axis);
+ }
+
+ /// Swap axes `ax` and `bx`.
+ ///
+ /// This does not move any data, it just adjusts the array’s dimensions
+ /// and strides.
+ ///
+ /// **Panics** if the axes are out of bounds.
+ ///
+ /// ```
+ /// use ndarray::arr2;
+ ///
+ /// let mut a = arr2(&[[1., 2., 3.]]);
+ /// a.swap_axes(0, 1);
+ /// assert!(
+ /// a == arr2(&[[1.], [2.], [3.]])
+ /// );
+ /// ```
+ #[track_caller]
+ pub fn swap_axes(&mut self, ax: usize, bx: usize)
+ {
+ self.as_layout_ref_mut().swap_axes(ax, bx);
+ }
+
+ /// If possible, merge in the axis `take` to `into`.
+ ///
+ /// Returns `true` iff the axes are now merged.
+ ///
+ /// This method merges the axes if movement along the two original axes
+ /// (moving fastest along the `into` axis) can be equivalently represented
+ /// as movement along one (merged) axis. Merging the axes preserves this
+ /// order in the merged axis. If `take` and `into` are the same axis, then
+ /// the axis is "merged" if its length is ≤ 1.
+ ///
+ /// If the return value is `true`, then the following hold:
+ ///
+ /// * The new length of the `into` axis is the product of the original
+ /// lengths of the two axes.
+ ///
+ /// * The new length of the `take` axis is 0 if the product of the original
+ /// lengths of the two axes is 0, and 1 otherwise.
+ ///
+ /// If the return value is `false`, then merging is not possible, and the
+ /// original shape and strides have been preserved.
+ ///
+ /// Note that the ordering constraint means that if it's possible to merge
+ /// `take` into `into`, it's usually not possible to merge `into` into
+ /// `take`, and vice versa.
+ ///
+ /// ```
+ /// use ndarray::Array3;
+ /// use ndarray::Axis;
+ ///
+ /// let mut a = Array3::::zeros((2, 3, 4));
+ /// assert!(a.merge_axes(Axis(1), Axis(2)));
+ /// assert_eq!(a.shape(), &[2, 1, 12]);
+ /// ```
+ ///
+ /// ***Panics*** if an axis is out of bounds.
+ #[track_caller]
+ pub fn merge_axes(&mut self, take: Axis, into: Axis) -> bool
+ {
+ self.as_layout_ref_mut().merge_axes(take, into)
+ }
+
+ /// Return the total number of elements in the array.
+ pub fn len(&self) -> usize
+ {
+ self.as_layout_ref().len()
+ }
+
+ /// Return the length of `axis`.
+ ///
+ /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
+ /// number of dimensions (axes) of the array.
+ ///
+ /// ***Panics*** if the axis is out of bounds.
+ #[track_caller]
+ pub fn len_of(&self, axis: Axis) -> usize
+ {
+ self.as_layout_ref().len_of(axis)
+ }
+
+ /// Return whether the array has any elements
+ pub fn is_empty(&self) -> bool
+ {
+ self.as_layout_ref().is_empty()
+ }
+
+ /// Return the number of dimensions (axes) in the array
+ pub fn ndim(&self) -> usize
+ {
+ self.as_layout_ref().ndim()
+ }
+
+ /// Return the shape of the array in its “pattern” form,
+ /// an integer in the one-dimensional case, tuple in the n-dimensional cases
+ /// and so on.
+ pub fn dim(&self) -> D::Pattern
+ {
+ self.as_layout_ref().dim()
+ }
+
+ /// Return the shape of the array as it's stored in the array.
+ ///
+ /// This is primarily useful for passing to other `ArrayBase`
+ /// functions, such as when creating another array of the same
+ /// shape and dimensionality.
+ ///
+ /// ```
+ /// use ndarray::Array;
+ ///
+ /// let a = Array::from_elem((2, 3), 5.);
+ ///
+ /// // Create an array of zeros that's the same shape and dimensionality as `a`.
+ /// let b = Array::::zeros(a.raw_dim());
+ /// ```
+ pub fn raw_dim(&self) -> D
+ {
+ self.as_layout_ref().raw_dim()
+ }
+
+ /// Return the shape of the array as a slice.
+ ///
+ /// Note that you probably don't want to use this to create an array of the
+ /// same shape as another array because creating an array with e.g.
+ /// [`Array::zeros()`](ArrayBase::zeros) using a shape of type `&[usize]`
+ /// results in a dynamic-dimensional array. If you want to create an array
+ /// that has the same shape and dimensionality as another array, use
+ /// [`.raw_dim()`](ArrayBase::raw_dim) instead:
+ ///
+ /// ```rust
+ /// use ndarray::{Array, Array2};
+ ///
+ /// let a = Array2::::zeros((3, 4));
+ /// let shape = a.shape();
+ /// assert_eq!(shape, &[3, 4]);
+ ///
+ /// // Since `a.shape()` returned `&[usize]`, we get an `ArrayD` instance:
+ /// let b = Array::zeros(shape);
+ /// assert_eq!(a.clone().into_dyn(), b);
+ ///
+ /// // To get the same dimension type, use `.raw_dim()` instead:
+ /// let c = Array::zeros(a.raw_dim());
+ /// assert_eq!(a, c);
+ /// ```
+ pub fn shape(&self) -> &[usize]
+ {
+ self.as_layout_ref().shape()
+ }
+
+ /// Return the strides of the array as a slice.
+ pub fn strides(&self) -> &[isize]
+ {
+ self.as_layout_ref().strides()
+ }
+
+ /// Return the stride of `axis`.
+ ///
+ /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
+ /// number of dimensions (axes) of the array.
+ ///
+ /// ***Panics*** if the axis is out of bounds.
+ #[track_caller]
+ pub fn stride_of(&self, axis: Axis) -> isize
+ {
+ self.as_layout_ref().stride_of(axis)
+ }
+}
diff --git a/src/aliases.rs b/src/aliases.rs
index 5df0c95ec..7f897304b 100644
--- a/src/aliases.rs
+++ b/src/aliases.rs
@@ -2,7 +2,7 @@
//!
use crate::dimension::Dim;
-use crate::{ArcArray, Array, ArrayView, ArrayViewMut, Ix, IxDynImpl};
+use crate::{ArcArray, Array, ArrayRef, ArrayView, ArrayViewMut, Ix, IxDynImpl, LayoutRef};
/// Create a zero-dimensional index
#[allow(non_snake_case)]
@@ -123,6 +123,40 @@ pub type Array6 = Array;
/// dynamic-dimensional array
pub type ArrayD = Array;
+/// zero-dimensional array reference
+pub type ArrayRef0 = ArrayRef;
+/// one-dimensional array reference
+pub type ArrayRef1 = ArrayRef;
+/// two-dimensional array reference
+pub type ArrayRef2 = ArrayRef;
+/// three-dimensional array reference
+pub type ArrayRef3 = ArrayRef;
+/// four-dimensional array reference
+pub type ArrayRef4 = ArrayRef;
+/// five-dimensional array reference
+pub type ArrayRef5 = ArrayRef;
+/// six-dimensional array reference
+pub type ArrayRef6 = ArrayRef;
+/// dynamic-dimensional array reference
+pub type ArrayRefD = ArrayRef;
+
+/// zero-dimensional layout reference
+pub type LayoutRef0 = LayoutRef;
+/// one-dimensional layout reference
+pub type LayoutRef1 = LayoutRef;
+/// two-dimensional layout reference
+pub type LayoutRef2 = LayoutRef;
+/// three-dimensional layout reference
+pub type LayoutRef3 = LayoutRef;
+/// four-dimensional layout reference
+pub type LayoutRef4 = LayoutRef;
+/// five-dimensional layout reference
+pub type LayoutRef5 = LayoutRef;
+/// six-dimensional layout reference
+pub type LayoutRef6 = LayoutRef;
+/// dynamic-dimensional layout reference
+pub type LayoutRefD = LayoutRef;
+
/// zero-dimensional array view
pub type ArrayView0<'a, A> = ArrayView<'a, A, Ix0>;
/// one-dimensional array view
diff --git a/src/argument_traits.rs b/src/argument_traits.rs
index de8ac7f99..c4e85186a 100644
--- a/src/argument_traits.rs
+++ b/src/argument_traits.rs
@@ -11,7 +11,7 @@ pub trait AssignElem
}
/// Assignable element, simply `*self = input`.
-impl<'a, T> AssignElem for &'a mut T
+impl AssignElem for &mut T
{
fn assign_elem(self, input: T)
{
@@ -20,7 +20,7 @@ impl<'a, T> AssignElem for &'a mut T
}
/// Assignable element, simply `self.set(input)`.
-impl<'a, T> AssignElem for &'a Cell
+impl AssignElem for &Cell
{
fn assign_elem(self, input: T)
{
@@ -29,7 +29,7 @@ impl<'a, T> AssignElem for &'a Cell
}
/// Assignable element, simply `self.set(input)`.
-impl<'a, T> AssignElem for &'a MathCell
+impl AssignElem for &MathCell
{
fn assign_elem(self, input: T)
{
@@ -39,7 +39,7 @@ impl<'a, T> AssignElem for &'a MathCell
/// Assignable element, the item in the MaybeUninit is overwritten (prior value, if any, is not
/// read or dropped).
-impl<'a, T> AssignElem for &'a mut MaybeUninit
+impl AssignElem for &mut MaybeUninit
{
fn assign_elem(self, input: T)
{
diff --git a/src/array_approx.rs b/src/array_approx.rs
index 493864c7e..958f6f6ba 100644
--- a/src/array_approx.rs
+++ b/src/array_approx.rs
@@ -1,35 +1,27 @@
#[cfg(feature = "approx")]
+#[cfg_attr(docsrs, doc(cfg(feature = "approx")))]
mod approx_methods
{
use crate::imp_prelude::*;
- impl ArrayBase
- where
- S: Data,
- D: Dimension,
+ impl ArrayRef
{
/// A test for equality that uses the elementwise absolute difference to compute the
/// approximate equality of two arrays.
- ///
- /// **Requires crate feature `"approx"`**
- pub fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool
+ pub fn abs_diff_eq(&self, other: &ArrayRef, epsilon: A::Epsilon) -> bool
where
- A: ::approx::AbsDiffEq,
+ A: ::approx::AbsDiffEq,
A::Epsilon: Clone,
- S2: Data,
{
>::abs_diff_eq(self, other, epsilon)
}
/// A test for equality that uses an elementwise relative comparison if the values are far
/// apart; and the absolute difference otherwise.
- ///
- /// **Requires crate feature `"approx"`**
- pub fn relative_eq(&self, other: &ArrayBase, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool
+ pub fn relative_eq(&self, other: &ArrayRef, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool
where
- A: ::approx::RelativeEq,
+ A: ::approx::RelativeEq,
A::Epsilon: Clone,
- S2: Data,
{
>::relative_eq(self, other, epsilon, max_relative)
}
@@ -44,12 +36,10 @@ macro_rules! impl_approx_traits {
use $approx::{AbsDiffEq, RelativeEq, UlpsEq};
#[doc = $doc]
- impl AbsDiffEq> for ArrayBase
+ impl AbsDiffEq> for ArrayRef
where
A: AbsDiffEq,
A::Epsilon: Clone,
- S: Data,
- S2: Data,
D: Dimension,
{
type Epsilon = A::Epsilon;
@@ -58,7 +48,7 @@ macro_rules! impl_approx_traits {
A::default_epsilon()
}
- fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool {
+ fn abs_diff_eq(&self, other: &ArrayRef, epsilon: A::Epsilon) -> bool {
if self.shape() != other.shape() {
return false;
}
@@ -70,13 +60,31 @@ macro_rules! impl_approx_traits {
}
#[doc = $doc]
- impl RelativeEq> for ArrayBase
+ impl AbsDiffEq> for ArrayBase
where
- A: RelativeEq,
+ A: AbsDiffEq,
A::Epsilon: Clone,
S: Data,
S2: Data,
D: Dimension,
+ {
+ type Epsilon = A::Epsilon;
+
+ fn default_epsilon() -> A::Epsilon {
+ A::default_epsilon()
+ }
+
+ fn abs_diff_eq(&self, other: &ArrayBase, epsilon: A::Epsilon) -> bool {
+ (**self).abs_diff_eq(other, epsilon)
+ }
+ }
+
+ #[doc = $doc]
+ impl RelativeEq> for ArrayRef
+ where
+ A: RelativeEq,
+ A::Epsilon: Clone,
+ D: Dimension,
{
fn default_max_relative() -> A::Epsilon {
A::default_max_relative()
@@ -84,7 +92,7 @@ macro_rules! impl_approx_traits {
fn relative_eq(
&self,
- other: &ArrayBase,
+ other: &ArrayRef,
epsilon: A::Epsilon,
max_relative: A::Epsilon,
) -> bool {
@@ -99,13 +107,34 @@ macro_rules! impl_approx_traits {
}
#[doc = $doc]
- impl UlpsEq> for ArrayBase
+ impl RelativeEq> for ArrayBase
where
- A: UlpsEq,
+ A: RelativeEq,
A::Epsilon: Clone,
S: Data,
S2: Data,
D: Dimension,
+ {
+ fn default_max_relative() -> A::Epsilon {
+ A::default_max_relative()
+ }
+
+ fn relative_eq(
+ &self,
+ other: &ArrayBase,
+ epsilon: A::Epsilon,
+ max_relative: A::Epsilon,
+ ) -> bool {
+ (**self).relative_eq(other, epsilon, max_relative)
+ }
+ }
+
+ #[doc = $doc]
+ impl UlpsEq> for ArrayRef
+ where
+ A: UlpsEq,
+ A::Epsilon: Clone,
+ D: Dimension,
{
fn default_max_ulps() -> u32 {
A::default_max_ulps()
@@ -113,7 +142,7 @@ macro_rules! impl_approx_traits {
fn ulps_eq(
&self,
- other: &ArrayBase,
+ other: &ArrayRef,
epsilon: A::Epsilon,
max_ulps: u32,
) -> bool {
@@ -127,6 +156,29 @@ macro_rules! impl_approx_traits {
}
}
+ #[doc = $doc]
+ impl UlpsEq> for ArrayBase
+ where
+ A: UlpsEq,
+ A::Epsilon: Clone,
+ S: Data,
+ S2: Data,
+ D: Dimension,
+ {
+ fn default_max_ulps() -> u32 {
+ A::default_max_ulps()
+ }
+
+ fn ulps_eq(
+ &self,
+ other: &ArrayBase,
+ epsilon: A::Epsilon,
+ max_ulps: u32,
+ ) -> bool {
+ (**self).ulps_eq(other, epsilon, max_ulps)
+ }
+ }
+
#[cfg(test)]
mod tests {
use crate::prelude::*;
@@ -192,4 +244,5 @@ macro_rules! impl_approx_traits {
}
#[cfg(feature = "approx")]
+#[cfg_attr(docsrs, doc(cfg(feature = "approx")))]
impl_approx_traits!(approx, "**Requires crate feature `\"approx\"`.**");
diff --git a/src/array_serde.rs b/src/array_serde.rs
index 31b613d4c..5d51a8011 100644
--- a/src/array_serde.rs
+++ b/src/array_serde.rs
@@ -18,7 +18,7 @@ use std::marker::PhantomData;
use crate::imp_prelude::*;
use super::arraytraits::ARRAY_FORMAT_VERSION;
-use super::Iter;
+use crate::iterators::Iter;
use crate::IntoDimension;
/// Verifies that the version of the deserialized array matches the current
@@ -98,7 +98,7 @@ where
// private iterator wrapper
struct Sequence<'a, A, D>(Iter<'a, A, D>);
-impl<'a, A, D> Serialize for Sequence<'a, A, D>
+impl Serialize for Sequence<'_, A, D>
where
A: Serialize,
D: Dimension + Serialize,
@@ -162,7 +162,7 @@ impl<'de> Deserialize<'de> for ArrayField
{
struct ArrayFieldVisitor;
- impl<'de> Visitor<'de> for ArrayFieldVisitor
+ impl Visitor<'_> for ArrayFieldVisitor
{
type Value = ArrayField;
diff --git a/src/arrayformat.rs b/src/arrayformat.rs
index 202805604..7e5e1b1c9 100644
--- a/src/arrayformat.rs
+++ b/src/arrayformat.rs
@@ -6,7 +6,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::{ArrayBase, ArrayView, Axis, Data, Dimension, NdProducer};
-use crate::aliases::{Ix1, IxDyn};
+use crate::{
+ aliases::{Ix1, IxDyn},
+ ArrayRef,
+};
use alloc::format;
use std::fmt;
@@ -51,9 +54,9 @@ impl FormatOptions
fn set_no_limit(mut self, no_limit: bool) -> Self
{
if no_limit {
- self.axis_collapse_limit = std::usize::MAX;
- self.axis_collapse_limit_next_last = std::usize::MAX;
- self.axis_collapse_limit_last = std::usize::MAX;
+ self.axis_collapse_limit = usize::MAX;
+ self.axis_collapse_limit_next_last = usize::MAX;
+ self.axis_collapse_limit_last = usize::MAX;
}
self
}
@@ -112,13 +115,12 @@ fn format_with_overflow(
Ok(())
}
-fn format_array(
- array: &ArrayBase, f: &mut fmt::Formatter<'_>, format: F, fmt_opt: &FormatOptions,
+fn format_array(
+ array: &ArrayRef, f: &mut fmt::Formatter<'_>, format: F, fmt_opt: &FormatOptions,
) -> fmt::Result
where
F: FnMut(&A, &mut fmt::Formatter<'_>) -> fmt::Result + Clone,
D: Dimension,
- S: Data,
{
// Cast into a dynamically dimensioned view
// This is required to be able to use `index_axis` for the recursive case
@@ -174,6 +176,18 @@ where
/// The array is shown in multiline style.
impl fmt::Display for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array reference using `Display` and apply the formatting parameters
+/// used to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::Display for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@@ -188,6 +202,18 @@ where S: Data
/// The array is shown in multiline style.
impl fmt::Debug for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array reference using `Debug` and apply the formatting parameters used
+/// to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::Debug for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@@ -216,6 +242,18 @@ where S: Data
/// The array is shown in multiline style.
impl fmt::LowerExp for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array reference using `LowerExp` and apply the formatting parameters used
+/// to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::LowerExp for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@@ -230,6 +268,18 @@ where S: Data
/// The array is shown in multiline style.
impl fmt::UpperExp for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array using `UpperExp` and apply the formatting parameters used
+/// to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::UpperExp for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@@ -237,12 +287,25 @@ where S: Data
format_array(self, f, <_>::fmt, &fmt_opt)
}
}
+
/// Format the array using `LowerHex` and apply the formatting parameters used
/// to each element.
///
/// The array is shown in multiline style.
impl fmt::LowerHex for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array using `LowerHex` and apply the formatting parameters used
+/// to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::LowerHex for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
@@ -257,6 +320,18 @@ where S: Data
/// The array is shown in multiline style.
impl fmt::Binary for ArrayBase
where S: Data
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
+ {
+ (**self).fmt(f)
+ }
+}
+
+/// Format the array using `Binary` and apply the formatting parameters used
+/// to each element.
+///
+/// The array is shown in multiline style.
+impl fmt::Binary for ArrayRef
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
diff --git a/src/arraytraits.rs b/src/arraytraits.rs
index ea0b380ed..a34b1985e 100644
--- a/src/arraytraits.rs
+++ b/src/arraytraits.rs
@@ -10,18 +10,23 @@
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
+use std::hash;
use std::mem;
+use std::mem::size_of;
use std::ops::{Index, IndexMut};
-use std::{hash, mem::size_of};
use std::{iter::FromIterator, slice};
use crate::imp_prelude::*;
+use crate::Arc;
+
+use crate::LayoutRef;
use crate::{
dimension,
iter::{Iter, IterMut},
numeric_util,
FoldWhile,
NdIndex,
+ OwnedArcRepr,
Zip,
};
@@ -33,11 +38,10 @@ pub(crate) fn array_out_of_bounds() -> !
}
#[inline(always)]
-pub fn debug_bounds_check(_a: &ArrayBase, _index: &I)
+pub fn debug_bounds_check(_a: &LayoutRef, _index: &I)
where
D: Dimension,
I: NdIndex,
- S: Data,
{
debug_bounds_check!(_a, *_index);
}
@@ -45,15 +49,15 @@ where
/// Access the element at **index**.
///
/// **Panics** if index is out of bounds.
-impl