pub struct Scalar {
pub lo: f64,
pub hi: f64,
}Expand description
A number as the kernel computes with it: an interval [lo, hi] of
f64 with outward-rounded arithmetic. The default is zero, [0, 0].
A plain value, borrowing nothing: what is worked out in one can be kept
as any other value — a drawing’s views, in the session editing it.
Fields§
§lo: f64§hi: f64Implementations§
Source§impl Scalar
impl Scalar
pub const ZERO: Self
pub const ONE: Self
pub const TWO: Self
pub const PI: Self
Sourcepub const ENTIRE: Self
pub const ENTIRE: Self
The “entire” interval (-inf, inf) — the top element of the interval
lattice. could_be_equal/could_be_greater/could_be_less against
it are always true, and it never satisfies definitely_*. Used to
represent a value or a whole curve/surface whose position is not yet
known — an unsharp placeholder that automatically passes any
overlap/equality check made against it.
Sourcepub fn degenerate(v: f64) -> Self
pub fn degenerate(v: f64) -> Self
Degenerate (point) interval.
pub fn from_i64(v: i64) -> Self
pub fn from_f64(v: f64) -> Self
pub fn from_ratio(num: i64, den: i64) -> GeopResult<Self>
Sourcepub fn to_f64(self) -> f64
pub fn to_f64(self) -> f64
Approximate f64 midpoint, (lo + hi) / 2. Used only for
rendering/debugging.
pub fn add(self, other: Self) -> Self
pub fn sub(self, other: Self) -> Self
pub fn mul(self, other: Self) -> Self
pub fn neg(self) -> Self
Sourcepub fn div(self, other: Self) -> GeopResult<Self>
pub fn div(self, other: Self) -> GeopResult<Self>
Fails where the divisor could be zero.
pub fn abs(self) -> Self
pub fn sqrt(self) -> GeopResult<Self>
Sourcepub fn sin(self) -> Self
pub fn sin(self) -> Self
Outward-rounded enclosure of sin over the whole interval
(radians). Total — never fails, even for Scalar::ENTIRE or an
Scalar::INFINITY-adjacent value, which just widen to [-1, 1].
Sourcepub fn cos(self) -> Self
pub fn cos(self) -> Self
Outward-rounded enclosure of cos (see Scalar::sin).
Sourcepub fn acos(self) -> GeopResult<Self>
pub fn acos(self) -> GeopResult<Self>
Outward-rounded enclosure of acos over the interval, in [0, π]:
the angle whose cosine it is. The part of the interval beyond
[-1, 1] is left out; an interval with nothing in [-1, 1] fails.
Sourcepub fn degrees_to_radians(self) -> GeopResult<Self>
pub fn degrees_to_radians(self) -> GeopResult<Self>
The angle self, given in degrees, in radians.
Sourcepub fn atan2(self, x: Self) -> Self
pub fn atan2(self, x: Self) -> Self
An enclosure of the angle of the point (x, self) from the x axis,
in radians, in (-pi, pi]: of atan2(y, x) for every y in self
and x in x. All of [-pi, pi] where that is not one range of
angles: the box (x, self) holds the origin, or reaches across the
negative x axis, where the angle jumps.
Over a box clear of the origin the angle is least and greatest at
corners. Those are taken in f64 — free choices of where to put the
bounds — and then each is proven, not trusted: a bound b holds when
every point of the box lies on the far side of the ray at angle b,
cos(b) y - sin(b) x definitely of the right sign, evaluated in the
scalar’s own outward-rounded arithmetic. Where rounding leaves that
undecided the bound moves outward, by steps that double, until it
holds.
pub fn could_be_equal(self, other: Self) -> bool
pub fn definitely_not_equal(self, other: Self) -> bool
pub fn could_be_greater(self, other: Self) -> bool
pub fn definitely_greater(self, other: Self) -> bool
pub fn could_be_less(self, other: Self) -> bool
pub fn definitely_less(self, other: Self) -> bool
Sourcepub fn is_zero(self) -> bool
pub fn is_zero(self) -> bool
Whether it is definitely zero — no value it could be is less or more than zero: an exact zero, such as the entry of a column a row has nothing in.
Sourcepub fn definite_sign(self) -> Option<bool>
pub fn definite_sign(self) -> Option<bool>
The sign it definitely has: Some(true) if it is definitely
positive, Some(false) if definitely negative, None where it could
be zero.
pub fn is_infinite(self) -> bool
pub fn is_finite(self) -> bool
pub fn midpoint(self) -> Self
Sourcepub fn is_sharp(self) -> bool
pub fn is_sharp(self) -> bool
True iff this value carries no width — it’s a single, exactly-known point, not a genuine range of possibility.
Sourcepub fn width(self) -> Self
pub fn width(self) -> Self
How much possibility this enclosure carries: hi - lo, as a sharp,
non-negative value. Zero exactly when Scalar::is_sharp.
This is how much a computed quantity is not known. Being sharp
itself is what makes it usable as a threshold — comparing an uncertain
width against an uncertain bound could never be decided three-valuedly
(see validation::numerical_accuracy).
Sourcepub fn lower(self) -> Self
pub fn lower(self) -> Self
The sharp lower endpoint of this enclosure. Every value self could
be is >= lower() and <= upper(), so these are the outer bounds
to cut at when a search restricts a domain to an enclosure of its
answer: a cut there never loses a solution (unlike
Scalar::sharpen, which would cut through the enclosure).
Sourcepub fn upper(self) -> Self
pub fn upper(self) -> Self
The sharp upper endpoint (see Scalar::lower).
Sourcepub fn sharpen(self) -> Self
pub fn sharpen(self) -> Self
Collapse to a single representative point (currently the midpoint,
like Scalar::midpoint, but named for its distinct purpose: use
this only when you are free to pick any value within self and
don’t need to preserve which one — e.g. choosing where to place a
new knot when subdividing a curve at an arbitrary interior point.
Never use this to compress a value that represents a genuinely
uncertain physical quantity (a search’s converged bound, a measured
position) — that would silently discard real uncertainty rather than
making an arbitrary, harmless choice.
Exists to break a specific class of interval blowup: repeatedly
re-deriving a split point as (t0 + t1) / 2 from an already-widened
domain propagates and compounds that width forever, even though nothing
downstream actually cares which interior point was chosen — only
that some valid one was. Sharpening throws that unneeded width away
at the source instead of letting every later alpha = (t - e) / (s - e)
division amplify it further.
Sourcepub fn fraction(lo: Self, hi: Self, f: Self) -> Self
pub fn fraction(lo: Self, hi: Self, f: Self) -> Self
The point a fraction f of the way from lo to hi, sharp: a
sample position, a free choice (see Scalar::sharpen) — not an
enclosure of the point there, which Scalar::interpolate is.
Sourcepub fn interpolate(a: Self, b: Self, alpha: Self) -> Self
pub fn interpolate(a: Self, b: Self, alpha: Self) -> Self
Point a fraction alpha of the way from a to b: a at
alpha=0, b at alpha=1.
Deliberately a.add(alpha.mul(b.sub(a))), not the equally-valid
a.mul(Scalar::ONE.sub(alpha)).add(b.mul(alpha)) — both give the
same exact real result, but the latter computes alpha and
1-alpha as two decorrelated intervals before ever relating a
and b, so interval arithmetic can’t recognize when they cancel.
This form computes b.sub(a) first: when a and b are honestly
the same value (e.g. a weight that should stay exactly 1.0 across
many subdivisions), that subtraction is exactly 0 regardless of
alpha’s own width, and the whole expression collapses to exactly
a instead of needlessly widening with every call.
Sourcepub fn intersect(self, other: Self) -> Self
pub fn intersect(self, other: Self) -> Self
The largest value contained in both self and other — the dual
of Scalar::union. Callers must only intersect two enclosures of
the same underlying exact value (as Scalar::interpolate does);
given that, the result is still an honest enclosure, just a tighter
one. Returns the narrower input if the two somehow don’t overlap,
rather than fabricating an empty/inverted interval.
Sourcepub fn union(self, other: Self) -> Self
pub fn union(self, other: Self) -> Self
The smallest value definitely containing both self and other —
the scalar-level analog of Set::union.
Sourcepub fn is_subset_of(self, other: Self) -> bool
pub fn is_subset_of(self, other: Self) -> bool
True iff self is contained in other as sets: other.lo <= self.lo
and self.hi <= other.hi. This is the rigorous existence/uniqueness
test a Krawczyk-style contraction relies on (K(X) ⊆ X) — distinct
from Scalar::could_be_equal, which only asks whether the two
enclosures overlap.
Sourcepub fn is_exactly(self, other: Self) -> bool
pub fn is_exactly(self, other: Self) -> bool
Whether it is exactly other, as a set: both the same single value,
or both the same range. A weight that is exactly one is skipped
rather than multiplied by, since the product would only be widened
by rounding.
Sourcepub fn max(self, other: Self) -> Self
pub fn max(self, other: Self) -> Self
The larger of the two: an enclosure of max(a, b) for every a and
b the two could be — sharp where both are.
Sourcepub fn min(self, other: Self) -> Self
pub fn min(self, other: Self) -> Self
The smaller of the two (see Scalar::max).
Trait Implementations§
Source§impl Bisect for Scalar
Sharp: which point is asked is the search’s own free choice, and a
sharp middle keeps the bracket from widening as it shrinks.
impl Bisect for Scalar
Sharp: which point is asked is the search’s own free choice, and a sharp middle keeps the bracket from widening as it shrinks.
Source§fn strictly_between(lo: Self, mid: Self, hi: Self) -> bool
fn strictly_between(lo: Self, mid: Self, hi: Self) -> bool
For lo below hi.
Source§fn middle(lo: Self, hi: Self) -> GeopResult<Self>
fn middle(lo: Self, hi: Self) -> GeopResult<Self>
lo and hi: where the next side is asked.impl Copy for Scalar
Source§impl Exact for Scalar
A sharp scalar as its number, any other as [lo, hi]. Sharp to the
bit: [-0, 0] is not sharp, and is written as both.
impl Exact for Scalar
A sharp scalar as its number, any other as [lo, hi]. Sharp to the
bit: [-0, 0] is not sharp, and is written as both.
Source§impl Newton1d for Scalar
Sharpened before clamping: clamped’s comparisons are exact on a
sharp value, so the seed stays in the domain.
impl Newton1d for Scalar
Sharpened before clamping: clamped’s comparisons are exact on a
sharp value, so the seed stays in the domain.
Source§fn could_be_zero(self) -> bool
fn could_be_zero(self) -> bool
self, a function’s value, could be zero.Source§fn step(value: Self, slope: Self) -> GeopResult<(Self, f64)>
fn step(value: Self, slope: Self) -> GeopResult<(Self, f64)>
value / slope and its size, or why there is none.Source§impl Number for Scalar
impl Number for Scalar
const ZERO: Self = Scalar::ZERO
const ONE: Self = Scalar::ONE
const TWO: Self = Scalar::TWO
const PI: Self = Scalar::PI
fn from_i64(v: i64) -> Self
fn from_f64(v: f64) -> Self
Source§fn from_scalar(s: Scalar) -> Self
fn from_scalar(s: Scalar) -> Self
s as a constant: depending on no variable.fn from_ratio(num: i64, den: i64) -> GeopResult<Self>
fn add(self, other: Self) -> Self
fn sub(self, other: Self) -> Self
fn mul(self, other: Self) -> Self
fn neg(self) -> Self
Source§fn div(self, other: Self) -> GeopResult<Self>
fn div(self, other: Self) -> GeopResult<Self>
fn abs(self) -> Self
fn sqrt(self) -> GeopResult<Self>
fn sin(self) -> Self
fn cos(self) -> Self
fn acos(self) -> GeopResult<Self>
Source§fn degrees_to_radians(self) -> GeopResult<Self>
fn degrees_to_radians(self) -> GeopResult<Self>
self, given in degrees, in radians.fn could_be_equal(self, other: Self) -> bool
fn definitely_not_equal(self, other: Self) -> bool
fn could_be_greater(self, other: Self) -> bool
fn definitely_greater(self, other: Self) -> bool
fn could_be_less(self, other: Self) -> bool
fn definitely_less(self, other: Self) -> bool
Source§fn is_sharp(self) -> bool
fn is_sharp(self) -> bool
Source§fn is_exactly(self, other: Self) -> bool
fn is_exactly(self, other: Self) -> bool
other’s, as a set (see
Scalar::is_exactly).Source§fn union(self, other: Self) -> Self
fn union(self, other: Self) -> Self
Scalar::union).impl StructuralPartialEq for Scalar
Source§impl Variable for Scalar
A number steps by what is added to it.
impl Variable for Scalar
A number steps by what is added to it.
Source§fn dimension(&self) -> usize
fn dimension(&self) -> usize
Source§fn retract(&self, step: &[Scalar]) -> GeopResult<Scalar>
fn retract(&self, step: &[Scalar]) -> GeopResult<Scalar>
step — Variable::dimension numbers — takes it: the value
a solver tries next, a free choice, so sharp.Source§fn retract_over(&self, step: &[Scalar]) -> GeopResult<Scalar>
fn retract_over(&self, step: &[Scalar]) -> GeopResult<Scalar>
step takes it to: an enclosure,
nothing sharpened — of the value it stands for, which a sharp value
may only approximate (a rotation’s unit quaternion).Source§fn differential(&self, step: &[Scalar]) -> GeopResult<Option<Vec<Vec<Scalar>>>>
fn differential(&self, step: &[Scalar]) -> GeopResult<Option<Vec<Vec<Scalar>>>>
step: the matrix
D, one row per number of a step, such that for every δ in the box
a step dδ further, retract(δ + dδ), is to first order the step
D dδ from retract(δ) — an enclosure for every δ in the box.
None for the identity: a step that adds to the value.Source§fn stay(&self, at: &Scalar, _: Scalar) -> GeopResult<Rows>
fn stay(&self, at: &Scalar, _: Scalar) -> GeopResult<Rows>
at where nothing else decides where it goes:
residuals that vanish there, each a length — a turn measured where
it moves a point scale from its axis — and their derivatives by
its step.