aboutsummaryrefslogtreecommitdiff
path: root/vendor/smawk
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
committerValentin Popov <valentin@popov.link>2024-07-19 15:37:58 +0300
commita990de90fe41456a23e58bd087d2f107d321f3a1 (patch)
tree15afc392522a9e85dc3332235e311b7d39352ea9 /vendor/smawk
parent3d48cd3f81164bbfc1a755dc1d4a9a02f98c8ddd (diff)
downloadfparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.tar.xz
fparkan-a990de90fe41456a23e58bd087d2f107d321f3a1.zip
Deleted vendor folder
Diffstat (limited to 'vendor/smawk')
-rw-r--r--vendor/smawk/.cargo-checksum.json1
-rw-r--r--vendor/smawk/Cargo.toml53
-rw-r--r--vendor/smawk/LICENSE21
-rw-r--r--vendor/smawk/README.md151
-rw-r--r--vendor/smawk/dprint.json19
-rw-r--r--vendor/smawk/rustfmt.toml2
-rw-r--r--vendor/smawk/src/brute_force.rs150
-rw-r--r--vendor/smawk/src/lib.rs570
-rw-r--r--vendor/smawk/src/monge.rs121
-rw-r--r--vendor/smawk/src/recursive.rs191
-rw-r--r--vendor/smawk/tests/agreement.rs104
-rw-r--r--vendor/smawk/tests/complexity.rs83
-rw-r--r--vendor/smawk/tests/monge.rs83
-rw-r--r--vendor/smawk/tests/random_monge/mod.rs83
-rw-r--r--vendor/smawk/tests/version-numbers.rs9
15 files changed, 0 insertions, 1641 deletions
diff --git a/vendor/smawk/.cargo-checksum.json b/vendor/smawk/.cargo-checksum.json
deleted file mode 100644
index c553a4a..0000000
--- a/vendor/smawk/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{"Cargo.toml":"4581638d3c628d22826bde37114048c825ffb354f17f21645d8d49f9ebd64689","LICENSE":"0173035e025d60b1d19197840a93a887f6da8b075c01dd10601fcb6414a0043b","README.md":"c27297df61be8dd14e47dc30a80ae1d443f5acea82932139637543bc6d860631","dprint.json":"aacd5ec32db8741fbdea4ac916e61f0011485a51e8ec7a660f849be60cc7b512","rustfmt.toml":"6819baea67831b8a8b2a7ad33af1128dd2774a900c804635c912bb6545a4e922","src/brute_force.rs":"02edda18441ea5d6cc89d2fdfb9ab32a361e2598de74a71fb930fb630288ce35","src/lib.rs":"b312e4855945cfe27f4b1e9949b1c6ffea8f248ad80ac8fc49e72f0cc38df219","src/monge.rs":"f6c475f4d094b70b5e45d0c8a94112d42eaafa0ab41b2d3d96d06a38f1bac32d","src/recursive.rs":"e585286fe6c885dcac8001d0f484718aa8f73f3f85a452f8b4c1cb36d4fbfcf6","tests/agreement.rs":"764406a5d8c9a322bab8787764d780832cfc3962722ed01efda99684a619d543","tests/complexity.rs":"e2e850d38529f171eb6005807c2a86a3f95a907052253eaa8e24a834200cda0b","tests/monge.rs":"fe418373f89904cd40e2ed1d539bccd2d9be50c1f3f9ab2d93806ff3bce6b7ea","tests/random_monge/mod.rs":"83cf1dd0c7b0b511ad754c19857a5d830ed54e8fef3c31235cd70b709687534b","tests/version-numbers.rs":"73301b7bfe500eada5ede66f0dce89bd3e354af50a8e7a123b02931cd5eb8e16"},"package":"b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"} \ No newline at end of file
diff --git a/vendor/smawk/Cargo.toml b/vendor/smawk/Cargo.toml
deleted file mode 100644
index 44fc03d..0000000
--- a/vendor/smawk/Cargo.toml
+++ /dev/null
@@ -1,53 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2021"
-name = "smawk"
-version = "0.3.2"
-authors = ["Martin Geisler <martin@geisler.net>"]
-exclude = [
- ".github/",
- ".gitignore",
- "benches/",
- "examples/",
-]
-description = "Functions for finding row-minima in a totally monotone matrix."
-readme = "README.md"
-keywords = [
- "smawk",
- "matrix",
- "optimization",
- "dynamic-programming",
-]
-categories = [
- "algorithms",
- "mathematics",
- "science",
-]
-license = "MIT"
-repository = "https://github.com/mgeisler/smawk"
-
-[dependencies.ndarray]
-version = "0.15.4"
-optional = true
-
-[dev-dependencies.num-traits]
-version = "0.2.14"
-
-[dev-dependencies.rand]
-version = "0.8.4"
-
-[dev-dependencies.rand_chacha]
-version = "0.3.1"
-
-[dev-dependencies.version-sync]
-version = "0.9.4"
diff --git a/vendor/smawk/LICENSE b/vendor/smawk/LICENSE
deleted file mode 100644
index 124067f..0000000
--- a/vendor/smawk/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2017 Martin Geisler
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/vendor/smawk/README.md b/vendor/smawk/README.md
deleted file mode 100644
index 7d45acf..0000000
--- a/vendor/smawk/README.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# SMAWK Algorithm in Rust
-
-[![](https://github.com/mgeisler/smawk/workflows/build/badge.svg)][build-status]
-[![](https://codecov.io/gh/mgeisler/smawk/branch/master/graph/badge.svg)][codecov]
-[![](https://img.shields.io/crates/v/smawk.svg)][crates-io]
-[![](https://docs.rs/smawk/badge.svg)][api-docs]
-
-This crate contains an implementation of the [SMAWK algorithm][smawk] for
-finding the smallest element per row in a totally monotone matrix.
-
-The SMAWK algorithm allows you to lower the running time of some algorithms from
-O(_n_²) to just O(_n_). In other words, you can turn a quadratic time complexity
-(which is often too expensive) into linear time complexity.
-
-Finding optimal line breaks in a paragraph of text is an example of an algorithm
-which would normally take O(_n_²) time for _n_ words. With this crate, the
-running time becomes linear. Please see the [textwrap crate][textwrap] for an
-example of this.
-
-## Usage
-
-Add this to your `Cargo.toml`:
-
-```toml
-[dependencies]
-smawk = "0.3"
-```
-
-You can now efficiently find row and column minima. Here is an example where we
-find the column minima:
-
-```rust
-use smawk::Matrix;
-
-let matrix = vec![
- vec![3, 2, 4, 5, 6],
- vec![2, 1, 3, 3, 4],
- vec![2, 1, 3, 3, 4],
- vec![3, 2, 4, 3, 4],
- vec![4, 3, 2, 1, 1],
-];
-let minima = vec![1, 1, 4, 4, 4];
-assert_eq!(smawk::column_minima(&matrix), minima);
-```
-
-The `minima` vector gives the index of the minimum value per column, so
-`minima[0] == 1` since the minimum value in the first column is 2 (row 1). Note
-that the smallest row index is returned.
-
-### Cargo Features
-
-This crate has an optional dependency on the
-[`ndarray` crate](https://docs.rs/ndarray/), which provides an efficient matrix
-implementation. Enable the `ndarray` Cargo feature to use it.
-
-## Documentation
-
-**[API documentation][api-docs]**
-
-## Changelog
-
-### Version 0.3.2 (2023-09-17)
-
-This release adds more documentation and renames the top-level SMAWK functions.
-The old names have been kept for now to ensure backwards compatibility, but they
-will be removed in a future release.
-
-- [#65](https://github.com/mgeisler/smawk/pull/65): Forbid the use of unsafe
- code.
-- [#69](https://github.com/mgeisler/smawk/pull/69): Migrate to the Rust 2021
- edition.
-- [#73](https://github.com/mgeisler/smawk/pull/73): Add examples to all
- functions.
-- [#74](https://github.com/mgeisler/smawk/pull/74): Add “mathematics” as a crate
- category.
-- [#75](https://github.com/mgeisler/smawk/pull/75): Remove `smawk_` prefix from
- optimized functions.
-
-### Version 0.3.1 (2021-01-30)
-
-This release relaxes the bounds on the `smawk_row_minima`,
-`smawk_column_minima`, and `online_column_minima` functions so that they work on
-matrices containing floating point numbers.
-
-- [#55](https://github.com/mgeisler/smawk/pull/55): Relax bounds to `PartialOrd`
- instead of `Ord`.
-- [#56](https://github.com/mgeisler/smawk/pull/56): Update dependencies to their
- latest versions.
-- [#59](https://github.com/mgeisler/smawk/pull/59): Give an example of what
- SMAWK does in the README.
-
-### Version 0.3.0 (2020-09-02)
-
-This release slims down the crate significantly by making `ndarray` an optional
-dependency.
-
-- [#45](https://github.com/mgeisler/smawk/pull/45): Move non-SMAWK code and unit
- tests out of lib and into separate modules.
-- [#46](https://github.com/mgeisler/smawk/pull/46): Switch `smawk_row_minima`
- and `smawk_column_minima` functions to a new `Matrix` trait.
-- [#47](https://github.com/mgeisler/smawk/pull/47): Make the dependency on the
- `ndarray` crate optional.
-- [#48](https://github.com/mgeisler/smawk/pull/48): Let `is_monge` take a
- `Matrix` argument instead of `ndarray::Array2`.
-- [#50](https://github.com/mgeisler/smawk/pull/50): Remove mandatory
- dependencies on `rand` and `num-traits` crates.
-
-### Version 0.2.0 (2020-07-29)
-
-This release updates the code to Rust 2018.
-
-- [#18](https://github.com/mgeisler/smawk/pull/18): Make `online_column_minima`
- generic in matrix type.
-- [#23](https://github.com/mgeisler/smawk/pull/23): Switch to the
- [Rust 2018][rust-2018] edition. We test against the latest stable and nightly
- version of Rust.
-- [#29](https://github.com/mgeisler/smawk/pull/29): Drop strict Rust 2018
- compatibility by not testing with Rust 1.31.0.
-- [#32](https://github.com/mgeisler/smawk/pull/32): Fix crash on overflow in
- `is_monge`.
-- [#33](https://github.com/mgeisler/smawk/pull/33): Update `rand` dependency to
- latest version and get rid of `rand_derive`.
-- [#34](https://github.com/mgeisler/smawk/pull/34): Bump `num-traits` and
- `version-sync` dependencies to latest versions.
-- [#35](https://github.com/mgeisler/smawk/pull/35): Drop unnecessary Windows
- tests. The assumption is that the numeric computations we do are
- cross-platform.
-- [#36](https://github.com/mgeisler/smawk/pull/36): Update `ndarray` dependency
- to the latest version.
-- [#37](https://github.com/mgeisler/smawk/pull/37): Automate publishing new
- releases to crates.io.
-
-### Version 0.1.0 — August 7th, 2018
-
-First release with the classical offline SMAWK algorithm as well as a newer
-online version where the matrix entries can depend on previously computed column
-minima.
-
-## License
-
-SMAWK can be distributed according to the [MIT license][mit]. Contributions will
-be accepted under the same license.
-
-[build-status]: https://github.com/mgeisler/smawk/actions?query=branch%3Amaster+workflow%3Abuild
-[crates-io]: https://crates.io/crates/smawk
-[codecov]: https://codecov.io/gh/mgeisler/smawk
-[textwrap]: https://crates.io/crates/textwrap
-[smawk]: https://en.wikipedia.org/wiki/SMAWK_algorithm
-[api-docs]: https://docs.rs/smawk/
-[rust-2018]: https://doc.rust-lang.org/edition-guide/rust-2018/
-[mit]: LICENSE
diff --git a/vendor/smawk/dprint.json b/vendor/smawk/dprint.json
deleted file mode 100644
index e48af5f..0000000
--- a/vendor/smawk/dprint.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "markdown": {
- "textWrap": "always"
- },
- "exec": {
- "commands": [{
- "command": "rustfmt",
- "exts": ["rs"]
- }]
- },
- "excludes": ["target/"],
- "plugins": [
- "https://plugins.dprint.dev/json-0.17.4.wasm",
- "https://plugins.dprint.dev/markdown-0.16.1.wasm",
- "https://plugins.dprint.dev/toml-0.5.4.wasm",
- "https://plugins.dprint.dev/exec-0.4.3.json@42343548b8022c99b1d750be6b894fe6b6c7ee25f72ae9f9082226dd2e515072",
- "https://plugins.dprint.dev/prettier-0.27.0.json@3557a62b4507c55a47d8cde0683195b14d13c41dda66d0f0b0e111aed107e2fe"
- ]
-}
diff --git a/vendor/smawk/rustfmt.toml b/vendor/smawk/rustfmt.toml
deleted file mode 100644
index 24e4ea7..0000000
--- a/vendor/smawk/rustfmt.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-# Use rustfmt from the nightly channel for this:
-imports_granularity = "Module"
diff --git a/vendor/smawk/src/brute_force.rs b/vendor/smawk/src/brute_force.rs
deleted file mode 100644
index 1ec0ca3..0000000
--- a/vendor/smawk/src/brute_force.rs
+++ /dev/null
@@ -1,150 +0,0 @@
-//! Brute-force algorithm for finding column minima.
-//!
-//! The functions here are mostly meant to be used for testing
-//! correctness of the SMAWK implementation.
-//!
-//! **Note: this module is only available if you enable the `ndarray`
-//! Cargo feature.**
-
-use ndarray::{Array2, ArrayView1};
-
-/// Compute lane minimum by brute force.
-///
-/// This does a simple scan through the lane (row or column).
-#[inline]
-pub fn lane_minimum<T: Ord>(lane: ArrayView1<'_, T>) -> usize {
- lane.iter()
- .enumerate()
- .min_by_key(|&(idx, elem)| (elem, idx))
- .map(|(idx, _)| idx)
- .expect("empty lane in matrix")
-}
-
-/// Compute row minima by brute force in O(*mn*) time.
-///
-/// This function implements a simple brute-force approach where each
-/// matrix row is scanned completely. This means that the function
-/// works on all matrices, not just Monge matrices.
-///
-/// # Examples
-///
-/// ```
-/// let matrix = ndarray::arr2(&[[4, 2, 4, 3],
-/// [5, 3, 5, 3],
-/// [5, 3, 3, 1]]);
-/// assert_eq!(smawk::brute_force::row_minima(&matrix),
-/// vec![1, 1, 3]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero columns.
-pub fn row_minima<T: Ord>(matrix: &Array2<T>) -> Vec<usize> {
- matrix.rows().into_iter().map(lane_minimum).collect()
-}
-
-/// Compute column minima by brute force in O(*mn*) time.
-///
-/// This function implements a simple brute-force approach where each
-/// matrix column is scanned completely. This means that the function
-/// works on all matrices, not just Monge matrices.
-///
-/// # Examples
-///
-/// ```
-/// let matrix = ndarray::arr2(&[[4, 2, 4, 3],
-/// [5, 3, 5, 3],
-/// [5, 3, 3, 1]]);
-/// assert_eq!(smawk::brute_force::column_minima(&matrix),
-/// vec![0, 0, 2, 2]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero rows.
-pub fn column_minima<T: Ord>(matrix: &Array2<T>) -> Vec<usize> {
- matrix.columns().into_iter().map(lane_minimum).collect()
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use ndarray::arr2;
-
- #[test]
- fn brute_force_1x1() {
- let matrix = arr2(&[[2]]);
- let minima = vec![0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_2x1() {
- let matrix = arr2(&[
- [3], //
- [2],
- ]);
- let minima = vec![0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_1x2() {
- let matrix = arr2(&[[2, 1]]);
- let minima = vec![1];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_2x2() {
- let matrix = arr2(&[
- [3, 2], //
- [2, 1],
- ]);
- let minima = vec![1, 1];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_3x3() {
- let matrix = arr2(&[
- [3, 4, 4], //
- [3, 4, 4],
- [2, 3, 3],
- ]);
- let minima = vec![0, 0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_4x4() {
- let matrix = arr2(&[
- [4, 5, 5, 5], //
- [2, 3, 3, 3],
- [2, 3, 3, 3],
- [2, 2, 2, 2],
- ]);
- let minima = vec![0, 0, 0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn brute_force_5x5() {
- let matrix = arr2(&[
- [3, 2, 4, 5, 6],
- [2, 1, 3, 3, 4],
- [2, 1, 3, 3, 4],
- [3, 2, 4, 3, 4],
- [4, 3, 2, 1, 1],
- ]);
- let minima = vec![1, 1, 1, 1, 3];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-}
diff --git a/vendor/smawk/src/lib.rs b/vendor/smawk/src/lib.rs
deleted file mode 100644
index 367d033..0000000
--- a/vendor/smawk/src/lib.rs
+++ /dev/null
@@ -1,570 +0,0 @@
-//! This crate implements various functions that help speed up dynamic
-//! programming, most importantly the SMAWK algorithm for finding row
-//! or column minima in a totally monotone matrix with *m* rows and
-//! *n* columns in time O(*m* + *n*). This is much better than the
-//! brute force solution which would take O(*mn*). When *m* and *n*
-//! are of the same order, this turns a quadratic function into a
-//! linear function.
-//!
-//! # Examples
-//!
-//! Computing the column minima of an *m* ✕ *n* Monge matrix can be
-//! done efficiently with `smawk::column_minima`:
-//!
-//! ```
-//! use smawk::Matrix;
-//!
-//! let matrix = vec![
-//! vec![3, 2, 4, 5, 6],
-//! vec![2, 1, 3, 3, 4],
-//! vec![2, 1, 3, 3, 4],
-//! vec![3, 2, 4, 3, 4],
-//! vec![4, 3, 2, 1, 1],
-//! ];
-//! let minima = vec![1, 1, 4, 4, 4];
-//! assert_eq!(smawk::column_minima(&matrix), minima);
-//! ```
-//!
-//! The `minima` vector gives the index of the minimum value per
-//! column, so `minima[0] == 1` since the minimum value in the first
-//! column is 2 (row 1). Note that the smallest row index is returned.
-//!
-//! # Definitions
-//!
-//! Some of the functions in this crate only work on matrices that are
-//! *totally monotone*, which we will define below.
-//!
-//! ## Monotone Matrices
-//!
-//! We start with a helper definition. Given an *m* ✕ *n* matrix `M`,
-//! we say that `M` is *monotone* when the minimum value of row `i` is
-//! found to the left of the minimum value in row `i'` where `i < i'`.
-//!
-//! More formally, if we let `rm(i)` denote the column index of the
-//! left-most minimum value in row `i`, then we have
-//!
-//! ```text
-//! rm(0) ≤ rm(1) ≤ ... ≤ rm(m - 1)
-//! ```
-//!
-//! This means that as you go down the rows from top to bottom, the
-//! row-minima proceed from left to right.
-//!
-//! The algorithms in this crate deal with finding such row- and
-//! column-minima.
-//!
-//! ## Totally Monotone Matrices
-//!
-//! We say that a matrix `M` is *totally monotone* when every
-//! sub-matrix is monotone. A sub-matrix is formed by the intersection
-//! of any two rows `i < i'` and any two columns `j < j'`.
-//!
-//! This is often expressed as via this equivalent condition:
-//!
-//! ```text
-//! M[i, j] > M[i, j'] => M[i', j] > M[i', j']
-//! ```
-//!
-//! for all `i < i'` and `j < j'`.
-//!
-//! ## Monge Property for Matrices
-//!
-//! A matrix `M` is said to fulfill the *Monge property* if
-//!
-//! ```text
-//! M[i, j] + M[i', j'] ≤ M[i, j'] + M[i', j]
-//! ```
-//!
-//! for all `i < i'` and `j < j'`. This says that given any rectangle
-//! in the matrix, the sum of the top-left and bottom-right corners is
-//! less than or equal to the sum of the bottom-left and upper-right
-//! corners.
-//!
-//! All Monge matrices are totally monotone, so it is enough to
-//! establish that the Monge property holds in order to use a matrix
-//! with the functions in this crate. If your program is dealing with
-//! unknown inputs, it can use [`monge::is_monge`] to verify that a
-//! matrix is a Monge matrix.
-
-#![doc(html_root_url = "https://docs.rs/smawk/0.3.2")]
-// The s! macro from ndarray uses unsafe internally, so we can only
-// forbid unsafe code when building with the default features.
-#![cfg_attr(not(feature = "ndarray"), forbid(unsafe_code))]
-
-#[cfg(feature = "ndarray")]
-pub mod brute_force;
-pub mod monge;
-#[cfg(feature = "ndarray")]
-pub mod recursive;
-
-/// Minimal matrix trait for two-dimensional arrays.
-///
-/// This provides the functionality needed to represent a read-only
-/// numeric matrix. You can query the size of the matrix and access
-/// elements. Modeled after [`ndarray::Array2`] from the [ndarray
-/// crate](https://crates.io/crates/ndarray).
-///
-/// Enable the `ndarray` Cargo feature if you want to use it with
-/// `ndarray::Array2`.
-pub trait Matrix<T: Copy> {
- /// Return the number of rows.
- fn nrows(&self) -> usize;
- /// Return the number of columns.
- fn ncols(&self) -> usize;
- /// Return a matrix element.
- fn index(&self, row: usize, column: usize) -> T;
-}
-
-/// Simple and inefficient matrix representation used for doctest
-/// examples and simple unit tests.
-///
-/// You should prefer implementing it yourself, or you can enable the
-/// `ndarray` Cargo feature and use the provided implementation for
-/// [`ndarray::Array2`].
-impl<T: Copy> Matrix<T> for Vec<Vec<T>> {
- fn nrows(&self) -> usize {
- self.len()
- }
- fn ncols(&self) -> usize {
- self[0].len()
- }
- fn index(&self, row: usize, column: usize) -> T {
- self[row][column]
- }
-}
-
-/// Adapting [`ndarray::Array2`] to the `Matrix` trait.
-///
-/// **Note: this implementation is only available if you enable the
-/// `ndarray` Cargo feature.**
-#[cfg(feature = "ndarray")]
-impl<T: Copy> Matrix<T> for ndarray::Array2<T> {
- #[inline]
- fn nrows(&self) -> usize {
- self.nrows()
- }
- #[inline]
- fn ncols(&self) -> usize {
- self.ncols()
- }
- #[inline]
- fn index(&self, row: usize, column: usize) -> T {
- self[[row, column]]
- }
-}
-
-/// Compute row minima in O(*m* + *n*) time.
-///
-/// This implements the [SMAWK algorithm] for efficiently finding row
-/// minima in a totally monotone matrix.
-///
-/// The SMAWK algorithm is from Agarwal, Klawe, Moran, Shor, and
-/// Wilbur, *Geometric applications of a matrix searching algorithm*,
-/// Algorithmica 2, pp. 195-208 (1987) and the code here is a
-/// translation [David Eppstein's Python code][pads].
-///
-/// Running time on an *m* ✕ *n* matrix: O(*m* + *n*).
-///
-/// # Examples
-///
-/// ```
-/// use smawk::Matrix;
-/// let matrix = vec![vec![4, 2, 4, 3],
-/// vec![5, 3, 5, 3],
-/// vec![5, 3, 3, 1]];
-/// assert_eq!(smawk::row_minima(&matrix),
-/// vec![1, 1, 3]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero columns.
-///
-/// [pads]: https://github.com/jfinkels/PADS/blob/master/pads/smawk.py
-/// [SMAWK algorithm]: https://en.wikipedia.org/wiki/SMAWK_algorithm
-pub fn row_minima<T: PartialOrd + Copy, M: Matrix<T>>(matrix: &M) -> Vec<usize> {
- // Benchmarking shows that SMAWK performs roughly the same on row-
- // and column-major matrices.
- let mut minima = vec![0; matrix.nrows()];
- smawk_inner(
- &|j, i| matrix.index(i, j),
- &(0..matrix.ncols()).collect::<Vec<_>>(),
- &(0..matrix.nrows()).collect::<Vec<_>>(),
- &mut minima,
- );
- minima
-}
-
-#[deprecated(since = "0.3.2", note = "Please use `row_minima` instead.")]
-pub fn smawk_row_minima<T: PartialOrd + Copy, M: Matrix<T>>(matrix: &M) -> Vec<usize> {
- row_minima(matrix)
-}
-
-/// Compute column minima in O(*m* + *n*) time.
-///
-/// This implements the [SMAWK algorithm] for efficiently finding
-/// column minima in a totally monotone matrix.
-///
-/// The SMAWK algorithm is from Agarwal, Klawe, Moran, Shor, and
-/// Wilbur, *Geometric applications of a matrix searching algorithm*,
-/// Algorithmica 2, pp. 195-208 (1987) and the code here is a
-/// translation [David Eppstein's Python code][pads].
-///
-/// Running time on an *m* ✕ *n* matrix: O(*m* + *n*).
-///
-/// # Examples
-///
-/// ```
-/// use smawk::Matrix;
-/// let matrix = vec![vec![4, 2, 4, 3],
-/// vec![5, 3, 5, 3],
-/// vec![5, 3, 3, 1]];
-/// assert_eq!(smawk::column_minima(&matrix),
-/// vec![0, 0, 2, 2]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero rows.
-///
-/// [SMAWK algorithm]: https://en.wikipedia.org/wiki/SMAWK_algorithm
-/// [pads]: https://github.com/jfinkels/PADS/blob/master/pads/smawk.py
-pub fn column_minima<T: PartialOrd + Copy, M: Matrix<T>>(matrix: &M) -> Vec<usize> {
- let mut minima = vec![0; matrix.ncols()];
- smawk_inner(
- &|i, j| matrix.index(i, j),
- &(0..matrix.nrows()).collect::<Vec<_>>(),
- &(0..matrix.ncols()).collect::<Vec<_>>(),
- &mut minima,
- );
- minima
-}
-
-#[deprecated(since = "0.3.2", note = "Please use `column_minima` instead.")]
-pub fn smawk_column_minima<T: PartialOrd + Copy, M: Matrix<T>>(matrix: &M) -> Vec<usize> {
- column_minima(matrix)
-}
-
-/// Compute column minima in the given area of the matrix. The
-/// `minima` slice is updated inplace.
-fn smawk_inner<T: PartialOrd + Copy, M: Fn(usize, usize) -> T>(
- matrix: &M,
- rows: &[usize],
- cols: &[usize],
- minima: &mut [usize],
-) {
- if cols.is_empty() {
- return;
- }
-
- let mut stack = Vec::with_capacity(cols.len());
- for r in rows {
- // TODO: use stack.last() instead of stack.is_empty() etc
- while !stack.is_empty()
- && matrix(stack[stack.len() - 1], cols[stack.len() - 1])
- > matrix(*r, cols[stack.len() - 1])
- {
- stack.pop();
- }
- if stack.len() != cols.len() {
- stack.push(*r);
- }
- }
- let rows = &stack;
-
- let mut odd_cols = Vec::with_capacity(1 + cols.len() / 2);
- for (idx, c) in cols.iter().enumerate() {
- if idx % 2 == 1 {
- odd_cols.push(*c);
- }
- }
-
- smawk_inner(matrix, rows, &odd_cols, minima);
-
- let mut r = 0;
- for (c, &col) in cols.iter().enumerate().filter(|(c, _)| c % 2 == 0) {
- let mut row = rows[r];
- let last_row = if c == cols.len() - 1 {
- rows[rows.len() - 1]
- } else {
- minima[cols[c + 1]]
- };
- let mut pair = (matrix(row, col), row);
- while row != last_row {
- r += 1;
- row = rows[r];
- if (matrix(row, col), row) < pair {
- pair = (matrix(row, col), row);
- }
- }
- minima[col] = pair.1;
- }
-}
-
-/// Compute upper-right column minima in O(*m* + *n*) time.
-///
-/// The input matrix must be totally monotone.
-///
-/// The function returns a vector of `(usize, T)`. The `usize` in the
-/// tuple at index `j` tells you the row of the minimum value in
-/// column `j` and the `T` value is minimum value itself.
-///
-/// The algorithm only considers values above the main diagonal, which
-/// means that it computes values `v(j)` where:
-///
-/// ```text
-/// v(0) = initial
-/// v(j) = min { M[i, j] | i < j } for j > 0
-/// ```
-///
-/// If we let `r(j)` denote the row index of the minimum value in
-/// column `j`, the tuples in the result vector become `(r(j), M[r(j),
-/// j])`.
-///
-/// The algorithm is an *online* algorithm, in the sense that `matrix`
-/// function can refer back to previously computed column minima when
-/// determining an entry in the matrix. The guarantee is that we only
-/// call `matrix(i, j)` after having computed `v(i)`. This is
-/// reflected in the `&[(usize, T)]` argument to `matrix`, which grows
-/// as more and more values are computed.
-pub fn online_column_minima<T: Copy + PartialOrd, M: Fn(&[(usize, T)], usize, usize) -> T>(
- initial: T,
- size: usize,
- matrix: M,
-) -> Vec<(usize, T)> {
- let mut result = vec![(0, initial)];
-
- // State used by the algorithm.
- let mut finished = 0;
- let mut base = 0;
- let mut tentative = 0;
-
- // Shorthand for evaluating the matrix. We need a macro here since
- // we don't want to borrow the result vector.
- macro_rules! m {
- ($i:expr, $j:expr) => {{
- assert!($i < $j, "(i, j) not above diagonal: ({}, {})", $i, $j);
- assert!(
- $i < size && $j < size,
- "(i, j) out of bounds: ({}, {}), size: {}",
- $i,
- $j,
- size
- );
- matrix(&result[..finished + 1], $i, $j)
- }};
- }
-
- // Keep going until we have finished all size columns. Since the
- // columns are zero-indexed, we're done when finished == size - 1.
- while finished < size - 1 {
- // First case: we have already advanced past the previous
- // tentative value. We make a new tentative value by applying
- // smawk_inner to the largest square submatrix that fits under
- // the base.
- let i = finished + 1;
- if i > tentative {
- let rows = (base..finished + 1).collect::<Vec<_>>();
- tentative = std::cmp::min(finished + rows.len(), size - 1);
- let cols = (finished + 1..tentative + 1).collect::<Vec<_>>();
- let mut minima = vec![0; tentative + 1];
- smawk_inner(&|i, j| m![i, j], &rows, &cols, &mut minima);
- for col in cols {
- let row = minima[col];
- let v = m![row, col];
- if col >= result.len() {
- result.push((row, v));
- } else if v < result[col].1 {
- result[col] = (row, v);
- }
- }
- finished = i;
- continue;
- }
-
- // Second case: the new column minimum is on the diagonal. All
- // subsequent ones will be at least as low, so we can clear
- // out all our work from higher rows. As in the fourth case,
- // the loss of tentative is amortized against the increase in
- // base.
- let diag = m![i - 1, i];
- if diag < result[i].1 {
- result[i] = (i - 1, diag);
- base = i - 1;
- tentative = i;
- finished = i;
- continue;
- }
-
- // Third case: row i-1 does not supply a column minimum in any
- // column up to tentative. We simply advance finished while
- // maintaining the invariant.
- if m![i - 1, tentative] >= result[tentative].1 {
- finished = i;
- continue;
- }
-
- // Fourth and final case: a new column minimum at tentative.
- // This allows us to make progress by incorporating rows prior
- // to finished into the base. The base invariant holds because
- // these rows cannot supply any later column minima. The work
- // done when we last advanced tentative (and undone by this
- // step) can be amortized against the increase in base.
- base = i - 1;
- tentative = i;
- finished = i;
- }
-
- result
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn smawk_1x1() {
- let matrix = vec![vec![2]];
- assert_eq!(row_minima(&matrix), vec![0]);
- assert_eq!(column_minima(&matrix), vec![0]);
- }
-
- #[test]
- fn smawk_2x1() {
- let matrix = vec![
- vec![3], //
- vec![2],
- ];
- assert_eq!(row_minima(&matrix), vec![0, 0]);
- assert_eq!(column_minima(&matrix), vec![1]);
- }
-
- #[test]
- fn smawk_1x2() {
- let matrix = vec![vec![2, 1]];
- assert_eq!(row_minima(&matrix), vec![1]);
- assert_eq!(column_minima(&matrix), vec![0, 0]);
- }
-
- #[test]
- fn smawk_2x2() {
- let matrix = vec![
- vec![3, 2], //
- vec![2, 1],
- ];
- assert_eq!(row_minima(&matrix), vec![1, 1]);
- assert_eq!(column_minima(&matrix), vec![1, 1]);
- }
-
- #[test]
- fn smawk_3x3() {
- let matrix = vec![
- vec![3, 4, 4], //
- vec![3, 4, 4],
- vec![2, 3, 3],
- ];
- assert_eq!(row_minima(&matrix), vec![0, 0, 0]);
- assert_eq!(column_minima(&matrix), vec![2, 2, 2]);
- }
-
- #[test]
- fn smawk_4x4() {
- let matrix = vec![
- vec![4, 5, 5, 5], //
- vec![2, 3, 3, 3],
- vec![2, 3, 3, 3],
- vec![2, 2, 2, 2],
- ];
- assert_eq!(row_minima(&matrix), vec![0, 0, 0, 0]);
- assert_eq!(column_minima(&matrix), vec![1, 3, 3, 3]);
- }
-
- #[test]
- fn smawk_5x5() {
- let matrix = vec![
- vec![3, 2, 4, 5, 6],
- vec![2, 1, 3, 3, 4],
- vec![2, 1, 3, 3, 4],
- vec![3, 2, 4, 3, 4],
- vec![4, 3, 2, 1, 1],
- ];
- assert_eq!(row_minima(&matrix), vec![1, 1, 1, 1, 3]);
- assert_eq!(column_minima(&matrix), vec![1, 1, 4, 4, 4]);
- }
-
- #[test]
- fn online_1x1() {
- let matrix = vec![vec![0]];
- let minima = vec![(0, 0)];
- assert_eq!(online_column_minima(0, 1, |_, i, j| matrix[i][j]), minima);
- }
-
- #[test]
- fn online_2x2() {
- let matrix = vec![
- vec![0, 2], //
- vec![0, 0],
- ];
- let minima = vec![(0, 0), (0, 2)];
- assert_eq!(online_column_minima(0, 2, |_, i, j| matrix[i][j]), minima);
- }
-
- #[test]
- fn online_3x3() {
- let matrix = vec![
- vec![0, 4, 4], //
- vec![0, 0, 4],
- vec![0, 0, 0],
- ];
- let minima = vec![(0, 0), (0, 4), (0, 4)];
- assert_eq!(online_column_minima(0, 3, |_, i, j| matrix[i][j]), minima);
- }
-
- #[test]
- fn online_4x4() {
- let matrix = vec![
- vec![0, 5, 5, 5], //
- vec![0, 0, 3, 3],
- vec![0, 0, 0, 3],
- vec![0, 0, 0, 0],
- ];
- let minima = vec![(0, 0), (0, 5), (1, 3), (1, 3)];
- assert_eq!(online_column_minima(0, 4, |_, i, j| matrix[i][j]), minima);
- }
-
- #[test]
- fn online_5x5() {
- let matrix = vec![
- vec![0, 2, 4, 6, 7],
- vec![0, 0, 3, 4, 5],
- vec![0, 0, 0, 3, 4],
- vec![0, 0, 0, 0, 4],
- vec![0, 0, 0, 0, 0],
- ];
- let minima = vec![(0, 0), (0, 2), (1, 3), (2, 3), (2, 4)];
- assert_eq!(online_column_minima(0, 5, |_, i, j| matrix[i][j]), minima);
- }
-
- #[test]
- fn smawk_works_with_partial_ord() {
- let matrix = vec![
- vec![3.0, 2.0], //
- vec![2.0, 1.0],
- ];
- assert_eq!(row_minima(&matrix), vec![1, 1]);
- assert_eq!(column_minima(&matrix), vec![1, 1]);
- }
-
- #[test]
- fn online_works_with_partial_ord() {
- let matrix = vec![
- vec![0.0, 2.0], //
- vec![0.0, 0.0],
- ];
- let minima = vec![(0, 0.0), (0, 2.0)];
- assert_eq!(
- online_column_minima(0.0, 2, |_, i: usize, j: usize| matrix[i][j]),
- minima
- );
- }
-}
diff --git a/vendor/smawk/src/monge.rs b/vendor/smawk/src/monge.rs
deleted file mode 100644
index dbc80e1..0000000
--- a/vendor/smawk/src/monge.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-//! Functions for generating and checking Monge arrays.
-//!
-//! The functions here are mostly meant to be used for testing
-//! correctness of the SMAWK implementation.
-
-use crate::Matrix;
-use std::num::Wrapping;
-use std::ops::Add;
-
-/// Verify that a matrix is a Monge matrix.
-///
-/// A [Monge matrix] \(or array) is a matrix where the following
-/// inequality holds:
-///
-/// ```text
-/// M[i, j] + M[i', j'] <= M[i, j'] + M[i', j] for all i < i', j < j'
-/// ```
-///
-/// The inequality says that the sum of the main diagonal is less than
-/// the sum of the antidiagonal. Checking this condition is done by
-/// checking *n* ✕ *m* submatrices, so the running time is O(*mn*).
-///
-/// [Monge matrix]: https://en.wikipedia.org/wiki/Monge_array
-pub fn is_monge<T: Ord + Copy, M: Matrix<T>>(matrix: &M) -> bool
-where
- Wrapping<T>: Add<Output = Wrapping<T>>,
-{
- /// Returns `Ok(a + b)` if the computation can be done without
- /// overflow, otherwise `Err(a + b - T::MAX - 1)` is returned.
- fn checked_add<T: Ord + Copy>(a: Wrapping<T>, b: Wrapping<T>) -> Result<T, T>
- where
- Wrapping<T>: Add<Output = Wrapping<T>>,
- {
- let sum = a + b;
- if sum < a {
- Err(sum.0)
- } else {
- Ok(sum.0)
- }
- }
-
- (0..matrix.nrows() - 1)
- .flat_map(|row| (0..matrix.ncols() - 1).map(move |col| (row, col)))
- .all(|(row, col)| {
- let top_left = Wrapping(matrix.index(row, col));
- let top_right = Wrapping(matrix.index(row, col + 1));
- let bot_left = Wrapping(matrix.index(row + 1, col));
- let bot_right = Wrapping(matrix.index(row + 1, col + 1));
-
- match (
- checked_add(top_left, bot_right),
- checked_add(bot_left, top_right),
- ) {
- (Ok(a), Ok(b)) => a <= b, // No overflow.
- (Err(a), Err(b)) => a <= b, // Double overflow.
- (Ok(_), Err(_)) => true, // Anti-diagonal overflow.
- (Err(_), Ok(_)) => false, // Main diagonal overflow.
- }
- })
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn is_monge_handles_overflow() {
- // The x + y <= z + w computations will overflow for an u8
- // matrix unless is_monge is careful.
- let matrix: Vec<Vec<u8>> = vec![
- vec![200, 200, 200, 200],
- vec![200, 200, 200, 200],
- vec![200, 200, 200, 200],
- ];
- assert!(is_monge(&matrix));
- }
-
- #[test]
- fn monge_constant_rows() {
- let matrix = vec![
- vec![42, 42, 42, 42],
- vec![0, 0, 0, 0],
- vec![100, 100, 100, 100],
- vec![1000, 1000, 1000, 1000],
- ];
- assert!(is_monge(&matrix));
- }
-
- #[test]
- fn monge_constant_cols() {
- let matrix = vec![
- vec![42, 0, 100, 1000],
- vec![42, 0, 100, 1000],
- vec![42, 0, 100, 1000],
- vec![42, 0, 100, 1000],
- ];
- assert!(is_monge(&matrix));
- }
-
- #[test]
- fn monge_upper_right() {
- let matrix = vec![
- vec![10, 10, 42, 42, 42],
- vec![10, 10, 42, 42, 42],
- vec![10, 10, 10, 10, 10],
- vec![10, 10, 10, 10, 10],
- ];
- assert!(is_monge(&matrix));
- }
-
- #[test]
- fn monge_lower_left() {
- let matrix = vec![
- vec![10, 10, 10, 10, 10],
- vec![10, 10, 10, 10, 10],
- vec![42, 42, 42, 10, 10],
- vec![42, 42, 42, 10, 10],
- ];
- assert!(is_monge(&matrix));
- }
-}
diff --git a/vendor/smawk/src/recursive.rs b/vendor/smawk/src/recursive.rs
deleted file mode 100644
index 9df8b9c..0000000
--- a/vendor/smawk/src/recursive.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-//! Recursive algorithm for finding column minima.
-//!
-//! The functions here are mostly meant to be used for testing
-//! correctness of the SMAWK implementation.
-//!
-//! **Note: this module is only available if you enable the `ndarray`
-//! Cargo feature.**
-
-use ndarray::{s, Array2, ArrayView2, Axis};
-
-/// Compute row minima in O(*m* + *n* log *m*) time.
-///
-/// This function computes row minima in a totally monotone matrix
-/// using a recursive algorithm.
-///
-/// Running time on an *m* ✕ *n* matrix: O(*m* + *n* log *m*).
-///
-/// # Examples
-///
-/// ```
-/// let matrix = ndarray::arr2(&[[4, 2, 4, 3],
-/// [5, 3, 5, 3],
-/// [5, 3, 3, 1]]);
-/// assert_eq!(smawk::recursive::row_minima(&matrix),
-/// vec![1, 1, 3]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero columns.
-pub fn row_minima<T: Ord>(matrix: &Array2<T>) -> Vec<usize> {
- let mut minima = vec![0; matrix.nrows()];
- recursive_inner(matrix.view(), &|| Direction::Row, 0, &mut minima);
- minima
-}
-
-/// Compute column minima in O(*n* + *m* log *n*) time.
-///
-/// This function computes column minima in a totally monotone matrix
-/// using a recursive algorithm.
-///
-/// Running time on an *m* ✕ *n* matrix: O(*n* + *m* log *n*).
-///
-/// # Examples
-///
-/// ```
-/// let matrix = ndarray::arr2(&[[4, 2, 4, 3],
-/// [5, 3, 5, 3],
-/// [5, 3, 3, 1]]);
-/// assert_eq!(smawk::recursive::column_minima(&matrix),
-/// vec![0, 0, 2, 2]);
-/// ```
-///
-/// # Panics
-///
-/// It is an error to call this on a matrix with zero rows.
-pub fn column_minima<T: Ord>(matrix: &Array2<T>) -> Vec<usize> {
- let mut minima = vec![0; matrix.ncols()];
- recursive_inner(matrix.view(), &|| Direction::Column, 0, &mut minima);
- minima
-}
-
-/// The type of minima (row or column) we compute.
-enum Direction {
- Row,
- Column,
-}
-
-/// Compute the minima along the given direction (`Direction::Row` for
-/// row minima and `Direction::Column` for column minima).
-///
-/// The direction is given as a generic function argument to allow
-/// monomorphization to kick in. The function calls will be inlined
-/// and optimized away and the result is that the compiler generates
-/// differnet code for finding row and column minima.
-fn recursive_inner<T: Ord, F: Fn() -> Direction>(
- matrix: ArrayView2<'_, T>,
- dir: &F,
- offset: usize,
- minima: &mut [usize],
-) {
- if matrix.is_empty() {
- return;
- }
-
- let axis = match dir() {
- Direction::Row => Axis(0),
- Direction::Column => Axis(1),
- };
- let mid = matrix.len_of(axis) / 2;
- let min_idx = crate::brute_force::lane_minimum(matrix.index_axis(axis, mid));
- minima[mid] = offset + min_idx;
-
- if mid == 0 {
- return; // Matrix has a single row or column, so we're done.
- }
-
- let top_left = match dir() {
- Direction::Row => matrix.slice(s![..mid, ..(min_idx + 1)]),
- Direction::Column => matrix.slice(s![..(min_idx + 1), ..mid]),
- };
- let bot_right = match dir() {
- Direction::Row => matrix.slice(s![(mid + 1).., min_idx..]),
- Direction::Column => matrix.slice(s![min_idx.., (mid + 1)..]),
- };
- recursive_inner(top_left, dir, offset, &mut minima[..mid]);
- recursive_inner(bot_right, dir, offset + min_idx, &mut minima[mid + 1..]);
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use ndarray::arr2;
-
- #[test]
- fn recursive_1x1() {
- let matrix = arr2(&[[2]]);
- let minima = vec![0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_2x1() {
- let matrix = arr2(&[
- [3], //
- [2],
- ]);
- let minima = vec![0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_1x2() {
- let matrix = arr2(&[[2, 1]]);
- let minima = vec![1];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_2x2() {
- let matrix = arr2(&[
- [3, 2], //
- [2, 1],
- ]);
- let minima = vec![1, 1];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_3x3() {
- let matrix = arr2(&[
- [3, 4, 4], //
- [3, 4, 4],
- [2, 3, 3],
- ]);
- let minima = vec![0, 0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_4x4() {
- let matrix = arr2(&[
- [4, 5, 5, 5], //
- [2, 3, 3, 3],
- [2, 3, 3, 3],
- [2, 2, 2, 2],
- ]);
- let minima = vec![0, 0, 0, 0];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-
- #[test]
- fn recursive_5x5() {
- let matrix = arr2(&[
- [3, 2, 4, 5, 6],
- [2, 1, 3, 3, 4],
- [2, 1, 3, 3, 4],
- [3, 2, 4, 3, 4],
- [4, 3, 2, 1, 1],
- ]);
- let minima = vec![1, 1, 1, 1, 3];
- assert_eq!(row_minima(&matrix), minima);
- assert_eq!(column_minima(&matrix.reversed_axes()), minima);
- }
-}
diff --git a/vendor/smawk/tests/agreement.rs b/vendor/smawk/tests/agreement.rs
deleted file mode 100644
index 2e0343a..0000000
--- a/vendor/smawk/tests/agreement.rs
+++ /dev/null
@@ -1,104 +0,0 @@
-#![cfg(feature = "ndarray")]
-
-use ndarray::{s, Array2};
-use rand::SeedableRng;
-use rand_chacha::ChaCha20Rng;
-use smawk::{brute_force, online_column_minima, recursive};
-
-mod random_monge;
-use random_monge::random_monge_matrix;
-
-/// Check that the brute force, recursive, and SMAWK functions
-/// give identical results on a large number of randomly generated
-/// Monge matrices.
-#[test]
-fn column_minima_agree() {
- let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30];
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- for _ in 0..4 {
- for m in sizes.clone().iter() {
- for n in sizes.clone().iter() {
- let matrix: Array2<i32> = random_monge_matrix(*m, *n, &mut rng);
-
- // Compute and test row minima.
- let brute_force = brute_force::row_minima(&matrix);
- let recursive = recursive::row_minima(&matrix);
- let smawk = smawk::row_minima(&matrix);
- assert_eq!(
- brute_force, recursive,
- "recursive and brute force differs on:\n{:?}",
- matrix
- );
- assert_eq!(
- brute_force, smawk,
- "SMAWK and brute force differs on:\n{:?}",
- matrix
- );
-
- // Do the same for the column minima.
- let brute_force = brute_force::column_minima(&matrix);
- let recursive = recursive::column_minima(&matrix);
- let smawk = smawk::column_minima(&matrix);
- assert_eq!(
- brute_force, recursive,
- "recursive and brute force differs on:\n{:?}",
- matrix
- );
- assert_eq!(
- brute_force, smawk,
- "SMAWK and brute force differs on:\n{:?}",
- matrix
- );
- }
- }
- }
-}
-
-/// Check that the brute force and online SMAWK functions give
-/// identical results on a large number of randomly generated
-/// Monge matrices.
-#[test]
-fn online_agree() {
- let sizes = vec![1, 2, 3, 4, 5, 10, 15, 20, 30, 50];
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- for _ in 0..5 {
- for &size in &sizes {
- // Random totally monotone square matrix of the
- // desired size.
- let mut matrix: Array2<i32> = random_monge_matrix(size, size, &mut rng);
-
- // Adjust matrix so the column minima are above the
- // diagonal. The brute_force::column_minima will still
- // work just fine on such a mangled Monge matrix.
- let max = *matrix.iter().max().unwrap_or(&0);
- for idx in 0..(size as isize) {
- // Using the maximum value of the matrix instead
- // of i32::max_value() makes for prettier matrices
- // in case we want to print them.
- matrix.slice_mut(s![idx..idx + 1, ..idx + 1]).fill(max);
- }
-
- // The online algorithm always returns the initial
- // value for the left-most column -- without
- // inspecting the column at all. So we fill the
- // left-most column with this value to have the brute
- // force algorithm do the same.
- let initial = 42;
- matrix.slice_mut(s![0.., ..1]).fill(initial);
-
- // Brute-force computation of column minima, returned
- // in the same form as online_column_minima.
- let brute_force = brute_force::column_minima(&matrix)
- .iter()
- .enumerate()
- .map(|(j, &i)| (i, matrix[[i, j]]))
- .collect::<Vec<_>>();
- let online = online_column_minima(initial, size, |_, i, j| matrix[[i, j]]);
- assert_eq!(
- brute_force, online,
- "brute force and online differ on:\n{:3?}",
- matrix
- );
- }
- }
-}
diff --git a/vendor/smawk/tests/complexity.rs b/vendor/smawk/tests/complexity.rs
deleted file mode 100644
index c9881ea..0000000
--- a/vendor/smawk/tests/complexity.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-#![cfg(feature = "ndarray")]
-
-use ndarray::{Array1, Array2};
-use rand::SeedableRng;
-use rand_chacha::ChaCha20Rng;
-use smawk::online_column_minima;
-
-mod random_monge;
-use random_monge::random_monge_matrix;
-
-#[derive(Debug)]
-struct LinRegression {
- alpha: f64,
- beta: f64,
- r_squared: f64,
-}
-
-/// Square an expression. Works equally well for floats and matrices.
-macro_rules! squared {
- ($x:expr) => {
- $x * $x
- };
-}
-
-/// Compute the mean of a 1-dimensional array.
-macro_rules! mean {
- ($a:expr) => {
- $a.mean().expect("Mean of empty array")
- };
-}
-
-/// Compute a simple linear regression from the list of values.
-///
-/// See <https://en.wikipedia.org/wiki/Simple_linear_regression>.
-fn linear_regression(values: &[(usize, i32)]) -> LinRegression {
- let xs = values.iter().map(|&(x, _)| x as f64).collect::<Array1<_>>();
- let ys = values.iter().map(|&(_, y)| y as f64).collect::<Array1<_>>();
-
- let xs_mean = mean!(&xs);
- let ys_mean = mean!(&ys);
- let xs_ys_mean = mean!(&xs * &ys);
-
- let cov_xs_ys = ((&xs - xs_mean) * (&ys - ys_mean)).sum();
- let var_xs = squared!(&xs - xs_mean).sum();
-
- let beta = cov_xs_ys / var_xs;
- let alpha = ys_mean - beta * xs_mean;
- let r_squared = squared!(xs_ys_mean - xs_mean * ys_mean)
- / ((mean!(&xs * &xs) - squared!(xs_mean)) * (mean!(&ys * &ys) - squared!(ys_mean)));
-
- LinRegression {
- alpha: alpha,
- beta: beta,
- r_squared: r_squared,
- }
-}
-
-/// Check that the number of matrix accesses in `online_column_minima`
-/// grows as O(*n*) for *n* ✕ *n* matrix.
-#[test]
-fn online_linear_complexity() {
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- let mut data = vec![];
-
- for &size in &[1, 2, 3, 4, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] {
- let matrix: Array2<i32> = random_monge_matrix(size, size, &mut rng);
- let count = std::cell::RefCell::new(0);
- online_column_minima(0, size, |_, i, j| {
- *count.borrow_mut() += 1;
- matrix[[i, j]]
- });
- data.push((size, count.into_inner()));
- }
-
- let lin_reg = linear_regression(&data);
- assert!(
- lin_reg.r_squared > 0.95,
- "r² = {:.4} is lower than expected for a linear fit\nData points: {:?}\n{:?}",
- lin_reg.r_squared,
- data,
- lin_reg
- );
-}
diff --git a/vendor/smawk/tests/monge.rs b/vendor/smawk/tests/monge.rs
deleted file mode 100644
index 67058a7..0000000
--- a/vendor/smawk/tests/monge.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-#![cfg(feature = "ndarray")]
-
-use ndarray::{arr2, Array, Array2};
-use rand::SeedableRng;
-use rand_chacha::ChaCha20Rng;
-use smawk::monge::is_monge;
-
-mod random_monge;
-use random_monge::{random_monge_matrix, MongePrim};
-
-#[test]
-fn random_monge() {
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- let matrix: Array2<u8> = random_monge_matrix(5, 5, &mut rng);
-
- assert!(is_monge(&matrix));
- assert_eq!(
- matrix,
- arr2(&[
- [2, 3, 4, 4, 5],
- [5, 5, 6, 6, 7],
- [3, 3, 4, 4, 5],
- [5, 2, 3, 3, 4],
- [5, 2, 3, 3, 4]
- ])
- );
-}
-
-#[test]
-fn monge_constant_rows() {
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- let matrix: Array2<u8> = MongePrim::ConstantRows.to_matrix(5, 4, &mut rng);
- assert!(is_monge(&matrix));
- for row in matrix.rows() {
- let elem = row[0];
- assert_eq!(row, Array::from_elem(matrix.ncols(), elem));
- }
-}
-
-#[test]
-fn monge_constant_cols() {
- let mut rng = ChaCha20Rng::seed_from_u64(0);
- let matrix: Array2<u8> = MongePrim::ConstantCols.to_matrix(5, 4, &mut rng);
- assert!(is_monge(&matrix));
- for column in matrix.columns() {
- let elem = column[0];
- assert_eq!(column, Array::from_elem(matrix.nrows(), elem));
- }
-}
-
-#[test]
-fn monge_upper_right_ones() {
- let mut rng = ChaCha20Rng::seed_from_u64(1);
- let matrix: Array2<u8> = MongePrim::UpperRightOnes.to_matrix(5, 4, &mut rng);
- assert!(is_monge(&matrix));
- assert_eq!(
- matrix,
- arr2(&[
- [0, 0, 1, 1],
- [0, 0, 1, 1],
- [0, 0, 1, 1],
- [0, 0, 0, 0],
- [0, 0, 0, 0]
- ])
- );
-}
-
-#[test]
-fn monge_lower_left_ones() {
- let mut rng = ChaCha20Rng::seed_from_u64(1);
- let matrix: Array2<u8> = MongePrim::LowerLeftOnes.to_matrix(5, 4, &mut rng);
- assert!(is_monge(&matrix));
- assert_eq!(
- matrix,
- arr2(&[
- [0, 0, 0, 0],
- [0, 0, 0, 0],
- [1, 1, 0, 0],
- [1, 1, 0, 0],
- [1, 1, 0, 0]
- ])
- );
-}
diff --git a/vendor/smawk/tests/random_monge/mod.rs b/vendor/smawk/tests/random_monge/mod.rs
deleted file mode 100644
index 50a932f..0000000
--- a/vendor/smawk/tests/random_monge/mod.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-//! Test functionality for generating random Monge matrices.
-
-// The code is put here so we can reuse it in different integration
-// tests, without Cargo finding it when `cargo test` is run. See the
-// section on "Submodules in Integration Tests" in
-// https://doc.rust-lang.org/book/ch11-03-test-organization.html
-
-use ndarray::{s, Array2};
-use num_traits::PrimInt;
-use rand::distributions::{Distribution, Standard};
-use rand::Rng;
-
-/// A Monge matrix can be decomposed into one of these primitive
-/// building blocks.
-#[derive(Copy, Clone)]
-pub enum MongePrim {
- ConstantRows,
- ConstantCols,
- UpperRightOnes,
- LowerLeftOnes,
-}
-
-impl MongePrim {
- /// Generate a Monge matrix from a primitive.
- pub fn to_matrix<T: PrimInt, R: Rng>(&self, m: usize, n: usize, rng: &mut R) -> Array2<T>
- where
- Standard: Distribution<T>,
- {
- let mut matrix = Array2::from_elem((m, n), T::zero());
- // Avoid panic in UpperRightOnes and LowerLeftOnes below.
- if m == 0 || n == 0 {
- return matrix;
- }
-
- match *self {
- MongePrim::ConstantRows => {
- for mut row in matrix.rows_mut() {
- if rng.gen::<bool>() {
- row.fill(T::one())
- }
- }
- }
- MongePrim::ConstantCols => {
- for mut col in matrix.columns_mut() {
- if rng.gen::<bool>() {
- col.fill(T::one())
- }
- }
- }
- MongePrim::UpperRightOnes => {
- let i = rng.gen_range(0..(m + 1) as isize);
- let j = rng.gen_range(0..(n + 1) as isize);
- matrix.slice_mut(s![..i, -j..]).fill(T::one());
- }
- MongePrim::LowerLeftOnes => {
- let i = rng.gen_range(0..(m + 1) as isize);
- let j = rng.gen_range(0..(n + 1) as isize);
- matrix.slice_mut(s![-i.., ..j]).fill(T::one());
- }
- }
-
- matrix
- }
-}
-
-/// Generate a random Monge matrix.
-pub fn random_monge_matrix<R: Rng, T: PrimInt>(m: usize, n: usize, rng: &mut R) -> Array2<T>
-where
- Standard: Distribution<T>,
-{
- let monge_primitives = [
- MongePrim::ConstantRows,
- MongePrim::ConstantCols,
- MongePrim::LowerLeftOnes,
- MongePrim::UpperRightOnes,
- ];
- let mut matrix = Array2::from_elem((m, n), T::zero());
- for _ in 0..(m + n) {
- let monge = monge_primitives[rng.gen_range(0..monge_primitives.len())];
- matrix = matrix + monge.to_matrix(m, n, rng);
- }
- matrix
-}
diff --git a/vendor/smawk/tests/version-numbers.rs b/vendor/smawk/tests/version-numbers.rs
deleted file mode 100644
index 288592d..0000000
--- a/vendor/smawk/tests/version-numbers.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#[test]
-fn test_readme_deps() {
- version_sync::assert_markdown_deps_updated!("README.md");
-}
-
-#[test]
-fn test_html_root_url() {
- version_sync::assert_html_root_url_updated!("src/lib.rs");
-}