Skip to main content

Scratch

Struct Scratch 

Source
pub struct Scratch<'a> { /* private fields */ }
Expand description

A bump arena of f64 components for expansion arithmetic. See the module documentation for the model.

Implementations§

Source§

impl Scratch<'static>

Source

pub fn growable(initial: usize) -> Scratch<'static>

Creates an empty arena that owns its memory, with room for initial components (at most u32::MAX, the most an arena uses).

When an operation needs more room the arena grows on the heap to at least double its capacity, or to what the operation needs if that is more, keeping its contents. Spans are indices, so they stay valid after the buffer moves. The arena fails with ScratchExhausted only when an operation needs more than u32::MAX components, and then it is unchanged.

Running out of memory aborts, as for any alloc collection; ScratchExhausted is returned only when the arena would exceed u32::MAX components.

Available only with the alloc cargo feature.

§Examples
use implicit_predicates_core::Scratch;

let mut scratch = Scratch::growable(1);
let a = scratch.push(&[1e-20, 1.0])?; // grows
assert!(scratch.capacity() >= 2);
assert_eq!(scratch.get(a), &[1e-20, 1.0]);
Source§

impl Scratch<'_>

Source

pub fn product(&mut self, a: Span, b: Span) -> Result<Span, ScratchExhausted>

Writes the expansion of a * b and returns its span.

The product is the sum, over the components c of the shorter operand, of the longer operand scaled by c (expansion::scale), accumulated with expansion::sum. It is exact, and the result is a valid expansion of at most 2 * a.len() * b.len() components.

Requirement, as for scale: every component of a and of b lies in the product domain (see eft::in_product_domain), since every product of a component of a by one of b is computed exactly with eft::two_product; debug builds panic if one does not. The components of the result can lie outside that domain, so a product of products needs the caller to bound the magnitudes involved.

Needs 4 * a.len() * b.len() + 2 * max(a.len(), b.len()) free components while it works, or none if either operand is empty. The result ends up just above the previous top, like that of every other operation, and the working space beyond it is released.

§Errors

ScratchExhausted if that space is not free; the arena is unchanged.

§Examples
use implicit_predicates_core::Scratch;

let tiny = 2f64.powi(-60);
let mut buf = [0.0; 32];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[tiny, 1.0])?; // 1 + 2^-60
let b = scratch.push(&[-tiny, 1.0])?; // 1 - 2^-60
let p = scratch.product(a, b)?;
assert_eq!(scratch.get(p), &[-tiny * tiny, 1.0]); // 1 - 2^-120
assert_eq!(scratch.used(), 4 + p.len());
assert_eq!(scratch.high_water(), 4 + 4 * 2 * 2 + 2 * 2);
Source§

impl<'a> Scratch<'a>

Source

pub fn borrowed(buf: &'a mut [f64]) -> Scratch<'a>

Creates an empty arena over buf, of which it uses at most u32::MAX components. The initial contents of buf do not matter.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 64];
let scratch = Scratch::borrowed(&mut buf);
assert_eq!(scratch.capacity(), 64);
assert_eq!(scratch.used(), 0);
Source

pub fn mark(&self) -> Mark

Returns a mark of the current top, to return to with reset.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 4];
let mut scratch = Scratch::borrowed(&mut buf);
scratch.push(&[1.0])?;
let mark = scratch.mark();
scratch.push(&[2.0])?;
scratch.reset(mark);
assert_eq!(scratch.used(), 1);
Source

pub fn reset(&mut self, m: Mark)

Lowers the top to the mark m, releasing every span created since m was taken. high_water is unchanged.

m must not be above the current top, which happens when a reset to an earlier mark came in between. That is a logic error: debug builds panic, release builds leave the top unchanged.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 4];
let mut scratch = Scratch::borrowed(&mut buf);
let mark = scratch.mark();
scratch.push(&[1e-20, 1.0])?;
scratch.reset(mark);
assert_eq!(scratch.used(), 0);
assert_eq!(scratch.high_water(), 2);
Source

pub fn get(&self, s: Span) -> &[f64]

Returns the components of the expansion at s.

Debug builds panic if s reaches past the top; see the module documentation for spans that are no longer valid.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 4];
let mut scratch = Scratch::borrowed(&mut buf);
let s = scratch.push(&[1e-20, 1.0])?;
assert_eq!(scratch.get(s), &[1e-20, 1.0]);
Source

pub fn used(&self) -> usize

Returns the number of components in use, below the top.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 4];
let mut scratch = Scratch::borrowed(&mut buf);
scratch.push(&[1e-20, 1.0])?;
assert_eq!(scratch.used(), 2);
Source

pub fn capacity(&self) -> usize

Returns the number of components the arena can hold: the length of its buffer, or u32::MAX if the buffer is longer.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 8];
assert_eq!(Scratch::borrowed(&mut buf).capacity(), 8);
Source

pub fn high_water(&self) -> usize

Returns the highest used ever reached, counting the space each successful operation reserves while it works, even when its result turns out shorter. A buffer this long is enough to repeat the same computation. Failed operations reserve nothing.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 8];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[1e-20, 1.0])?;
let zero = scratch.diff(a, a)?; // reserves 4 components, keeps none
assert!(zero.is_empty());
assert_eq!(scratch.used(), 2);
assert_eq!(scratch.high_water(), 6);
Source

pub fn push(&mut self, e: &[f64]) -> Result<Span, ScratchExhausted>

Copies the expansion e into the arena and returns its span.

Needs e.len() free components; an empty e always succeeds, giving an empty span. Requirement: e is a valid expansion (see expansion); it is copied as is, and debug builds panic if it is not valid.

§Errors

ScratchExhausted if e does not fit; the arena is unchanged.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 2];
let mut scratch = Scratch::borrowed(&mut buf);
let s = scratch.push(&[1e-20, 1.0])?;
assert_eq!(scratch.get(s), &[1e-20, 1.0]);
Source

pub fn sum(&mut self, a: Span, b: Span) -> Result<Span, ScratchExhausted>

Writes the expansion of a + b and returns its span, as expansion::sum does.

Needs a.len() + b.len() free components while it works.

§Errors

ScratchExhausted if that space is not free; the arena is unchanged.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 8];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[1e-20, 1.0])?;
let b = scratch.push(&[-1e-20, 2.0])?;
let s = scratch.sum(a, b)?;
assert_eq!(scratch.get(s), &[3.0]);
Source

pub fn diff(&mut self, a: Span, b: Span) -> Result<Span, ScratchExhausted>

Writes the expansion of a - b and returns its span, as expansion::diff does.

Needs a.len() + b.len() free components while it works.

§Errors

ScratchExhausted if that space is not free; the arena is unchanged.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 8];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[1e-20, 1.0])?;
let b = scratch.push(&[1e-20, 2.0])?;
let d = scratch.diff(a, b)?;
assert_eq!(scratch.get(d), &[-1.0]);
Source

pub fn scale(&mut self, a: Span, b: f64) -> Result<Span, ScratchExhausted>

Writes the expansion of a * b and returns its span, as expansion::scale does, with the same requirements on the magnitudes.

Needs 2 * a.len() free components while it works.

§Errors

ScratchExhausted if that space is not free; the arena is unchanged.

§Examples
use implicit_predicates_core::Scratch;

let mut buf = [0.0; 8];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[0.25, 4.0])?;
let s = scratch.scale(a, 3.0)?;
assert_eq!(scratch.get(s), &[12.75]);
Source

pub fn sign(&self, a: Span) -> Sign

Returns the exact sign of the expansion at a, as expansion::sign does.

§Examples
use implicit_predicates_core::{Scratch, Sign};

let mut buf = [0.0; 2];
let mut scratch = Scratch::borrowed(&mut buf);
let a = scratch.push(&[1e-20, -1.0])?;
assert_eq!(scratch.sign(a), Sign::Negative);

Trait Implementations§

Source§

impl Debug for Scratch<'_>

Shows the accounting of the arena, not its contents.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> !UnwindSafe for Scratch<'a>

§

impl<'a> Forget for Scratch<'a>

§

impl<'a> Freeze for Scratch<'a>

§

impl<'a> Move for Scratch<'a>

§

impl<'a> RefUnwindSafe for Scratch<'a>

§

impl<'a> Send for Scratch<'a>

§

impl<'a> Sync for Scratch<'a>

§

impl<'a> Unpin for Scratch<'a>

§

impl<'a> UnsafeUnpin for Scratch<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.