bigoish 0.1.0

Test the computational complexity (big-O) of Rust algorithms
Documentation
# Bigoish: Test the empirical computational complexity of Rust algorithms

Your functions or datastructure methods implement an algorithm; how do you know if they're scaling as expected?
For example, imagine you've implemented a new sorting algorithm.
Decent sorting is typically O(nlogn), but how about _your_ implementation?
Maybe there's a bug somewhere that makes it worse.

With `bigoish`, pronounced "big-o-ish", you can write tests that assert that a particular function has a particular empirical computational complexity.
More accurately, you can assert that an expected complexity model you provide is empirically the best fit for measured runtime, when compared to the fits of a specific set of common complexity models.
Real big-O, in contrast, is a mathematically-proven upper bound.

Here's an example, asserting that Rust's built-in `sort()` fits `n*log(n)` best:

```rust
use bigoish::{N, Log, assert_best_fit, growing_inputs};

// The function whose complexity we want to assert.
fn sort(mut v: Vec<i64>) -> Vec<i64> {
    v.sort();
    v
}

// Creates a test input of a particular size for `sort()`.
fn make_vec(n: usize) -> Vec<i64> {
    // Random number generation library:
    use fastrand;
    std::iter::repeat_with(|| fastrand::i64(..)).take(n).collect()
}

// Assert that that n*log(n) is the complexity model that fits `sort()` best.
assert_best_fit(
    // The expected best-fitting computational complexity model:
    N * Log(N),
    // The function being tested:
    sort,
    // Pairs of (input length, input); the inputs will be passed to `sort()`.
    [
        (10, make_vec(10)), (100, make_vec(100)), (1000, make_vec(1000)),
        (10_000, make_vec(10_000)), (100_000, make_vec(100_000))
    ]
);

// You can use `growing_inputs()` to generate input pairs more easily.
assert_best_fit(
    N * Log(N),
    sort,
    // Starting with input size 10, generate 25 increasingly larger inputs using
    // `make_vec()`.
    growing_inputs(10, make_vec, 25),
);
```

If you were to erroneously assert that `sort()` uses model `N`:

```ignore
assert_best_fit(N, sort, growing_inputs(10, make_vec, 25));
```

You would then get a panic that looks like this:

![Plot of real (input size, runtime dots) vs the best fit n*log(n), and an error indicating that the wrong model was found. Note that when screen readers are used you can disable the plots, see the accessibility section of the docs]( data:image/png;base64,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)

## Improving your chances of a correct fit

Sometimes [`assert_best_fit`] will misidentify your function's likely complexity, claiming that, for example, `n*log(n)` is the best fit for your function despite it clearly being linear.
Or, it may fail intermittently.
To reduce the chances of this happening, you should:

* Use a sufficient number of inputs.
  Using 20 inputs is better than using 4 inputs.
* Make sure your inputs span a number of orders of magnitude.
  For example, if your function takes a `Vec`, testing with vectors of length 10, 100, 1000, and 10_000 is better than lengths of 10, 11, 12, and 13.
  The [`growing_inputs()`] function is a useful way to generate a sequence of increasingly bigger inputs.
* Make sure the minimal size of your inputs is large enough.
  Tiny inputs may have too much noise when the function's runtime is measured.

## Differences between `release` and `test` profiles

Typically `cargo test` runs with the ["test" profile](https://doc.rust-lang.org/cargo/reference/profiles.html), whereas released code runs with the "release" profile.
The latter drops debug assertions, and compiles with optimizations.
As a result, if you're using [`assert_best_fit`] in a `#[test]`, by default when you run `cargo test` you'll be asserting on code that is compiled differently than in released code.

Most of the time, this doesn't matter; the "test" profile will result in _slower_ code, but not in a different computational complexity.
Sometimes, however, "release" profile will allow the compiler to optimize your code into something much more scalable; perhaps a loop can be optimized into a constant-time operation.
In that case, you'll want to run [`assert_best_fit`] under the "release" profile in order to assert the correct complexity model.

You can make your test only run if debug assertions are disabled:

```no_run
#[cfg(not(debug_assertions))]
#[test]
fn complexity_of_sort() {
    assert_best_fit(
        N * Log(N),
        sort,
        [
            (1000, make_vec(1000)),
            (10_000, make_vec(10_000)),
            (100_000, make_vec(100_000))
        ]
    )
}
```

And then run tests with the "release" profile:

```bash
cargo test --release
```

## How it works

[`assert_best_fit`] takes an expected complexity model, a single-threaded function, and inputs (or rather, input sizes plus values).
[`assert_best_fit`] then tries to fit pairs of `(input size, measured runtime of function(input))` to the given model, as well as to additional models: constant, n, n², n³, √n, log(n), nlog(n), log(log(n)).

If the best-fitting model is the one you asserted, all is well; if not, [`assert_best_fit`] panics.

You can construct new models from the existing implementations of [`Model`], or create your own.

How runtime is measured depends on your operating system and environment:

* On Windows and macOS, the measurement uses CPU usage time on the current thread.
* On Linux, an attempt will be made to use the CPU instruction count for the current thread.
  However, this doesn't work in all environments, for example it doesn't work on GitHub Actions.
  If CPU instruction counts are unavailable, CPU usage time will be used instead.
* If you set an environment variable `BIGOISH_TIME_ONLY=1`, CPU usage time will be used regardless.

Notice that in all cases time spent sleeping or otherwise waiting shouldn't be counted, though you probably shouldn't do that in your code in the first place.

## Accessibility

If [`assert_best_fit`] panics and you're using a terminal, it will generate a graph showing how well the best fitting model matches your inputs and their measured runtime.
That way you can visually see if the proposed alternative model makes sense or not.

If you're using a screen reader, you can disable this behavior by setting either `NO_COLORS` or `TERM=dumb` environment variables.
Both, especially the latter, will likely impact the behavior of other programs.

## Credits

This crate is inspired by the Python library [bigO](https://github.com/plasma-umass/bigO/), which in turn is based on [_Measuring Empirical Computational Complexity_](https://theory.stanford.edu/~aiken/publications/papers/fse07.pdf) by Goldsmith et al.