Skip to main content

Absorb

Trait Absorb 

Source
pub trait Absorb<N>: Sized {
    // Required methods
    fn from_narrow(narrow: &N) -> Self;
    fn add_narrow(&mut self, narrow: &N);
    fn sub_narrow(&mut self, narrow: &N);
    fn mul_narrow(&self, narrow: &N) -> Self;
    fn add_mul_narrow(&mut self, narrow: &N, other: &Self);
}
Expand description

What a wide accumulator does with a narrow value.

The wide type is Self, so every implementation sees both types concretely and can be written in terms of the operators that exist for the pair.

§No defaults

Every method has to be written out. A default body would have to be phrased in terms of from_narrow, which is the slow path: it materialises a wide value and hands it to the general routine, so a forgotten override would cost orders of magnitude at the larger widths and cost nothing at the smallest, which is where it would be tested. Requiring each body makes leaving one out a compile error rather than a benchmark result.

Two macros write the bodies, so the burden is one line per pair in practice: absorb_by_ops! for a pair that has operators, absorb_by_widening! for one that does not.

§Extending it

A crate downstream can implement this for its own narrow type against a wide type from here: impl<const S: usize> Absorb<MyCoefficient> for Big<S> is a foreign trait for a foreign Self with a local type parameter, which the orphan rule permits. Such an implementation sees Big concretely and can be as fast as one written here.

A crate that brings its own wide type implements this for it against the narrow types it wants to read, which is always allowed because Self is then local.

§Agreement

The four operating methods have to agree with from_narrow: w.add_narrow(n) equals w += W::from_narrow(n), w.sub_narrow(n) equals w -= W::from_narrow(n), w.mul_narrow(n) equals w * W::from_narrow(n), and w.add_mul_narrow(n, v) equals w += v * W::from_narrow(n). The tests in this crate check every implementation against those four statements.

§Example

use relp_num::fixed::One;
use relp_num::{Absorb, RationalBig, RB};

let mut accumulator = RB!(1, 2);
// No `RationalBig` is materialised, and no gcd is taken: the denominator is added into the
// numerator where it stands.
accumulator.add_narrow(&One);
assert_eq!(accumulator, RB!(3, 2));

assert_eq!(RB!(7, 2).mul_narrow(&One), RB!(7, 2));
assert_eq!(<RationalBig as Absorb<One>>::from_narrow(&One), RB!(1));

Required Methods§

Source

fn from_narrow(narrow: &N) -> Self

The narrow value in the wide type.

Source

fn add_narrow(&mut self, narrow: &N)

Add a narrow value to this one.

Source

fn sub_narrow(&mut self, narrow: &N)

Subtract a narrow value from this one.

Source

fn mul_narrow(&self, narrow: &N) -> Self

Multiply this value by a narrow one.

Source

fn add_mul_narrow(&mut self, narrow: &N, other: &Self)

Add the product of a narrow value and a wide one to this value.

This is the operation an inner product is made of, and the reason it is a method of its own rather than a multiplication followed by an addition: for a narrow value that is one, the multiplication is not a cheap multiplication but no multiplication, and the intermediate it would have produced is not a cheap allocation but no allocation.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl Absorb<Binary> for Rational8

Source§

impl Absorb<Binary> for Rational16

Source§

impl Absorb<Binary> for Rational32

Source§

impl Absorb<Binary> for Rational64

Source§

impl Absorb<Binary> for Rational128

Source§

impl Absorb<One> for Rational8

Source§

impl Absorb<One> for Rational16

Source§

impl Absorb<One> for Rational32

Source§

impl Absorb<One> for Rational64

Source§

impl Absorb<One> for Rational128

Source§

impl Absorb<One> for RationalUsize

Source§

impl Absorb<SignedOne> for Rational8

Source§

impl Absorb<SignedOne> for Rational16

Source§

impl Absorb<SignedOne> for Rational32

Source§

impl Absorb<SignedOne> for Rational64

Source§

impl Absorb<SignedOne> for Rational128

Source§

impl Absorb<Zero> for Rational8

Source§

impl Absorb<Zero> for Rational16

Source§

impl Absorb<Zero> for Rational32

Source§

impl Absorb<Zero> for Rational64

Source§

impl Absorb<Zero> for Rational128

Source§

impl Absorb<Zero> for RationalUsize

Source§

impl Absorb<i8> for Rational8

Source§

impl Absorb<i8> for Rational16

Source§

impl Absorb<i8> for Rational32

Source§

impl Absorb<i8> for Rational64

Source§

impl Absorb<i8> for Rational128

Source§

impl Absorb<i16> for Rational16

Source§

impl Absorb<i16> for Rational32

Source§

impl Absorb<i16> for Rational64

Source§

impl Absorb<i16> for Rational128

Source§

impl Absorb<i32> for Rational32

Source§

impl Absorb<i32> for Rational64

Source§

impl Absorb<i32> for Rational128

Source§

impl Absorb<i64> for Rational64

Source§

impl Absorb<i64> for Rational128

Source§

impl Absorb<i128> for Rational128

Source§

impl Absorb<u8> for Rational8

Source§

impl Absorb<u8> for Rational16

Source§

impl Absorb<u8> for Rational32

Source§

impl Absorb<u8> for Rational64

Source§

impl Absorb<u8> for Rational128

Source§

impl Absorb<u16> for Rational16

Source§

impl Absorb<u16> for Rational32

Source§

impl Absorb<u16> for Rational64

Source§

impl Absorb<u16> for Rational128

Source§

impl Absorb<u32> for Rational32

Source§

impl Absorb<u32> for Rational64

Source§

impl Absorb<u32> for Rational128

Source§

impl Absorb<u64> for Rational64

Source§

impl Absorb<u64> for Rational128

Source§

impl Absorb<u128> for Rational128

Source§

impl<N> Absorb<&N> for Rational8
where Rational8: Absorb<N>,

A provider that hands out references to what it stores is read through them.

Source§

impl<N> Absorb<&N> for Rational16
where Rational16: Absorb<N>,

A provider that hands out references to what it stores is read through them.

Source§

impl<N> Absorb<&N> for Rational32
where Rational32: Absorb<N>,

A provider that hands out references to what it stores is read through them.

Source§

impl<N> Absorb<&N> for Rational64
where Rational64: Absorb<N>,

A provider that hands out references to what it stores is read through them.

Source§

impl<N> Absorb<&N> for Rational128
where Rational128: Absorb<N>,

A provider that hands out references to what it stores is read through them.

Source§

impl<N> Absorb<&N> for RationalUsize

Source§

impl<N> Absorb<Option<N>> for Rational8
where Rational8: Absorb<N>,

An absent value is zero, so it contributes nothing.

Source§

impl<N> Absorb<Option<N>> for Rational16
where Rational16: Absorb<N>,

An absent value is zero, so it contributes nothing.

Source§

impl<N> Absorb<Option<N>> for Rational32
where Rational32: Absorb<N>,

An absent value is zero, so it contributes nothing.

Source§

impl<N> Absorb<Option<N>> for Rational64
where Rational64: Absorb<N>,

An absent value is zero, so it contributes nothing.

Source§

impl<N> Absorb<Option<N>> for Rational128
where Rational128: Absorb<N>,

An absent value is zero, so it contributes nothing.

Source§

impl<N> Absorb<Option<N>> for RationalUsize

Source§

impl<const S: usize, N> Absorb<&N> for Big<S>
where Big<S>: Absorb<N>,

A matrix provider that hands out references to what it stores is read through them.

Source§

impl<const S: usize, N> Absorb<Option<N>> for Big<S>
where Big<S>: Absorb<N>,

An absent value is zero, so it contributes nothing.

Sparse rows are stored as Options to keep the zeros out. This lift is written for the wide type rather than once for every wide type at once, because Self has to be local to the crate that writes the implementation; a crate defining its own accumulator writes its own.

Source§

impl<const S: usize> Absorb<Binary> for Big<S>

Source§

impl<const S: usize> Absorb<One> for Big<S>

Source§

impl<const S: usize> Absorb<SignedOne> for Big<S>

Source§

impl<const S: usize> Absorb<Zero> for Big<S>

Source§

impl<const S: usize> Absorb<i8> for Big<S>

Source§

impl<const S: usize> Absorb<i16> for Big<S>

Source§

impl<const S: usize> Absorb<i32> for Big<S>

Source§

impl<const S: usize> Absorb<i64> for Big<S>

Source§

impl<const S: usize> Absorb<isize> for Big<S>

Source§

impl<const S: usize> Absorb<u8> for Big<S>

Source§

impl<const S: usize> Absorb<u16> for Big<S>

Source§

impl<const S: usize> Absorb<u32> for Big<S>

Source§

impl<const S: usize> Absorb<u64> for Big<S>

Source§

impl<const S: usize> Absorb<usize> for Big<S>