A flexible, stateless implementation of the bisection method

Overview

Bisector

Overview

A flexible, stateless implementation of the bisection method.

Flexibility is achieved by giving the user of this crate control over the input and output types. That is, this implementation is not limited to numeric types. In addition, the implementation is stateless. The Bisector struct on which the bisect methods are implemented does not hold internal mutable state of the last step. This gives the user the option to re-execute a step, or really perform any step in the order the user desires (although incremental steps may be most logical still 😅 ).

The lack of internal mutable state also allows the implementation to take a shared reference (&self), instead of an exclusive reference (&mut self), which is convenient when dealing with ownership in many cases, and was the original reason behind this crate.

Install

Cargo

  1. Last published version on crates.io (recommended):

Add the bisector crate to list of dependencies in your Cargo manifest (Cargo.toml):

[dependencies]
bisector = "*" # replace `*` with latest version
  1. Last development version on GitHub:

Add the bisector crate to list of dependencies in your Cargo manifest (Cargo.toml):

[dependencies]
bisector = { git = "https://github.com/foresterre/bisector.git" }

MSRV

The Minimal Supported Rust Version was determined with cargo-msrv, and is verified on the during CI runs. The table below lists the MSRV for the current and historical versions of bisector.

bisector version MSRV
0.1.0 N/A
0.2.0 N/A
0.3.0 1.37

Examples

Example 1

fn main() {
    let values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let bisector = Bisector::new(&values);

    let start_from = Indices::from_bisector(&bisector);

    // In this example, we'll manually step through the bisection (i.e. without a loop).

    // (1) We use the default starting indices (i.e. left = 0, right = |values| - 1 = 9);
    let step: Step<u32, u32> = bisector.bisect(|&value| ConvergeTo::Left(value), start_from);

    // We converge to the left, so our view of values will be halved to the left half.
    assert_eq!(step.indices, Indices::new(0, 4));
    assert_eq!(step.result.unwrap().try_into_left().unwrap(), 5);

    // (2) Now we use the next indices produced by step, to progress our bisection: step.indices
    //      Because we zig-zag, we'll now converge to the right
    let step: Step<u32, u32> = bisector.bisect(|&value| ConvergeTo::Right(value), step.indices);

    // We converge to the right, so our view of values will be halved to the right half of our previous
    // view.
    assert_eq!(step.indices, Indices::new(3, 4));
    assert_eq!(step.result.unwrap().try_into_right().unwrap(), 3);

    // (3) Step further: zig-zag left
    let final_step: Step<u32, u32> =
        bisector.bisect(|&value| ConvergeTo::Left(value), step.indices);

    assert_eq!(final_step.indices, Indices::new(3, 3));
    assert_eq!(final_step.result.unwrap().try_into_left().unwrap(), 4);

    // (4a) Step a one more time to check we are at the end: left
    let step: Step<u32, u32> =
        bisector.bisect(|&value| ConvergeTo::Left(value), final_step.indices);

    assert_eq!(step.indices, Indices::new(3, 3));
    assert!(step.result.is_none());

    // (4b) Step a one more time to check we are at the end: right
    let step: Step<u32, u32> =
        bisector.bisect(|&value| ConvergeTo::Right(value), final_step.indices);

    assert_eq!(step.indices, Indices::new(3, 3));
    assert!(step.result.is_none());
}

Example 2

// NB: output held by ConvergeTo does *not* need to be of the same type as
// the value. In this example, it just happens to be the case.
fn f(value: u32) -> ConvergeTo<u32, u32> {
    if value >= 5 && value <= 6 {
        ConvergeTo::Right(value)
    } else {
        ConvergeTo::Left(value)
    }
}

fn main() {
    let values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    let bisector = Bisector::new(&values);
    let mut elements_seen = vec![];
    let mut value = None;

    let mut i = Indices::from_bisector(&bisector);
    while let Step {
        indices,
        result: Some(t),
    } = bisector.bisect(|&v| f(v), i)
    {
        i = indices;

        let val = match t {
            ConvergeTo::Left(l) => l,
            ConvergeTo::Right(r) => r,
        };

        elements_seen.push(val);
        value = Some(val);
    }

    println!("{:?}", elements_seen);
    println!("Final converged to '{}'", value.unwrap());
}

Example: bisect in cargo msrv

A more contrived example can be found in cargo msrv.

NB: Linked revision was implemented before Bisector::try_bisect was added. To cover a fallible case in the convergence function, you may want to use Bisector::try_bisect over Bisector::bisect.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

You might also like...
ESP32 implementation of RustZX Spectrum emulator for ESP32-USB-OTG

RustZX for ESP32 - experimental version Goal of the project: Run ZX Spectrum on ESP32 HW: ESP32 OTG USB with ST7789 display References Rust code for E

An implementation of Olm and Megolm in pure Rust.

A Rust implementation of Olm and Megolm vodozemac is a Rust implementation of libolm, a cryptographic library used for end-to-end encryption in Matrix

Pure Rust Implementation of secp256k1.

SECP256K1 implementation in pure Rust Cargo Documentation SECP256K1 implementation with no_std support. Currently we have implementation for: Convert

A Rust implementation of generic prefix tree (trie) map with wildcard capture support

prefix_tree_map A Rust implementation of generic prefix tree (trie) map with wildcard capture support. Design Trie is a good data structure for storin

fast rust implementation of online nonnegative matrix factorization as laid out in the paper "detect and track latent factors with online nonnegative matrix factorization"

ONMF status: early work in progress. still figuring this out. code still somewhat messy. api still in flux. fast rust implementation of online nonnega

An implementation of a predicative polymorphic language with bidirectional type inference and algebraic data types

Vinilla Lang Vanilla is a pure functional programming language based on System F, a classic but powerful type system. Merits Simple as it is, Vanilla

An implementation of Ngo et al's GenericJoin in timely dataflow.

dataflow-join A streaming implementation of Ngo et al's GenericJoin in timely dataflow. Ngo et al presented a very cool join algorithm, some details o

A modular implementation of timely dataflow in Rust

Timely Dataflow Timely dataflow is a low-latency cyclic dataflow computational model, introduced in the paper Naiad: a timely dataflow system. This pr

A radix tree implementation for router, and provides CRUD operations.

radixtree A radix tree implementation for router, and provides CRUD operations. Radixtree is part of treemux, on top of which updates and removes are

Comments
Releases(v0.4.0)
  • v0.4.0(May 25, 2022)

    What's Changed

    • Bump actions/checkout from 2.4.0 to 3 by @dependabot in https://github.com/foresterre/bisector/pull/4
    • Add fallible Indices constructor by @foresterre in https://github.com/foresterre/bisector/pull/5

    Full Changelog: https://github.com/foresterre/bisector/compare/v0.3.0...v0.4.0

    Source code(tar.gz)
    Source code(zip)
Owner
Martijn Gribnau
Martijn Gribnau
The utility is designed to check the availability of peers and automatically update them in the Yggdrasil configuration file, as well as using the admin API - addPeer method.

Yggrasil network peers checker / updater The utility is designed to check the availability of peers and automatically update them in the Yggdrasil con

null 6 Dec 25, 2022
Rust-idiomatic, compliant, flexible and performant BIP21 crate

Rust implementation of BIP21 Rust-idiomatic, compliant, flexible and performant BIP21 crate. About Important: while lot of work went into polishing th

Martin Habovštiak 6 Dec 15, 2022
Stack heap flexible string designed to improve performance for Rust

flexible-string A stack heap flexible string designed to improve performance. FlexibleString was first implemented in spdlog-rs crate, which improved

Sprite 6 Feb 9, 2022
🤩 Flexible interpreted programming language

Jel Flexible, memory-safe, easy-to-use, interpreted programming language. work in progress Example Hello World: print(Hello World!) # this is valid pr

0x707 4 Sep 18, 2022
A backend framework for building fast and flexible APIs rapidly.

Andromeda Andromeda is a backend framework for Rust, to simplify the development of the kinds of basic API services that we developers have to build s

Framesurge 7 Dec 28, 2022
A fast and flexible LRU map.

A fast and flexible LRU map This repository contains a fast and flexible LRU map. Blazingly fast. Up to twice as fast as the lru crate, and with less

Koute 67 Jan 1, 2023
A typesafe, flexible, simple, and user-friendly unit system library for Rust that has good error messages.

uy A typesafe, flexible, simple, and user-friendly unit system library for Rust that has good error messages. Usage uy not only stores the unit of a v

Lachlan Sneff 19 Aug 8, 2023
Experimental Quantum Computer Simulator + Quantum Chess Implementation

Quantum Chess A somewhat hacky implementation of this paper (made in a week over a holiday). It's not heavily tested and probably has some bugs still

null 19 Jan 21, 2022
Ray Tracing: The Next Week implementation in Rust

rttnw Ray Tracing: The Next Week implementation in Rust How to run Install Rust: Link here. Run project git clone https://github.com/luliic2/rttnw cd

null 20 Apr 26, 2022
Rust implementation of µKanren, a featherweight relational programming language.

µKanren-rs This is a Rust implementation of µKanren, a featherweight relational programming language. See the original Scheme implementation here for

Eric Zhang 99 Dec 8, 2022