pub type Ex = Expr<Numeric>;Expand description
A numeric expression — the primary type for symbolic math.
Aliased Type§
pub struct Ex { /* private fields */ }Implementations§
Source§impl Ex
impl Ex
Sourcepub fn as_rational(&self) -> Option<Ratio<BigInt>>
pub fn as_rational(&self) -> Option<Ratio<BigInt>>
The exact value if this expression is a numeric literal.
Returns None for anything that is not a plain number node (symbols,
pi, sqrt(2), unevaluated sums, …) — call
eval first if you want constant folding.
use symplex::prelude::*;
use num_bigint::BigInt;
use num_rational::Ratio;
let ctx = Context::new();
let r = ctx.rational(6, 4).as_rational().unwrap();
assert_eq!(r, Ratio::new(BigInt::from(3), BigInt::from(2)));
assert!(ctx.pi().as_rational().is_none());
assert!((&ctx.int(2).sqrt() * &ctx.int(2).sqrt()).eval().as_rational().is_some());Sourcepub fn as_ratio_parts(&self) -> Option<(BigInt, BigInt)>
pub fn as_ratio_parts(&self) -> Option<(BigInt, BigInt)>
Numerator and denominator (lowest terms, denominator positive) if this
expression is a rational literal — SymPy’s Rational.p / .q.
Unlike as_numer_denom, which decomposes
any expression symbolically, this returns plain integers and only
for numbers. Call eval first to fold constant
arithmetic such as 1/3 + 1/6.
use symplex::prelude::*;
use symplex::num_bigint::BigInt;
let ctx = Context::new();
let (p, q) = ctx.rational(6, -4).as_ratio_parts().unwrap();
assert_eq!((p, q), (BigInt::from(-3), BigInt::from(2)));
assert_eq!(ctx.int(7).as_ratio_parts(), Some((BigInt::from(7), BigInt::from(1))));
assert!(ctx.symbol("x").as_ratio_parts().is_none());Sourcepub fn as_ratio_i128(&self) -> Option<(i128, i128)>
pub fn as_ratio_i128(&self) -> Option<(i128, i128)>
Numerator and denominator as machine integers, if this expression is a
rational literal whose parts fit in i128.
The convenient form for comparing with literals or feeding other
exact-arithmetic code without touching BigInt:
use symplex::prelude::*;
let ctx = Context::new();
assert_eq!(ctx.rational(3, 31).as_ratio_i128(), Some((3, 31)));
assert_eq!((ctx.rational(1, 3) + ctx.rational(1, 6)).as_ratio_i128(), Some((1, 2)));
assert_eq!(ctx.int(-4).as_ratio_i128(), Some((-4, 1)));
// Too large for i128 → None (use `as_ratio_parts`).
assert!(ctx.from_bigint(symplex::num_bigint::BigInt::from(2).pow(200)).as_ratio_i128().is_none());Sourcepub fn as_bigint(&self) -> Option<BigInt>
pub fn as_bigint(&self) -> Option<BigInt>
The exact value if this expression is an integer literal.
use symplex::prelude::*;
use num_bigint::BigInt;
let ctx = Context::new();
assert_eq!(ctx.int(-7).as_bigint(), Some(BigInt::from(-7)));
assert_eq!(ctx.rational(1, 2).as_bigint(), None);Sourcepub fn as_i64(&self) -> Option<i64>
pub fn as_i64(&self) -> Option<i64>
The value if this expression is an integer literal that fits in i64.
use symplex::prelude::*;
let ctx = Context::new();
assert_eq!(ctx.int(42).as_i64(), Some(42));
assert_eq!(ctx.from_u64(u64::MAX).as_i64(), None);
assert_eq!(ctx.symbol("n").as_i64(), None);Sourcepub fn compare_numeric(&self, other: &Ex) -> Option<Ordering>
pub fn compare_numeric(&self, other: &Ex) -> Option<Ordering>
Three-valued numeric comparison of self and other.
Decision procedure, in order:
- Both are numeric literals → exact rational comparison.
d = (self − other).eval()is a literal → exact sign ofd; ifdisoo/-oo→Greater/Less.- The assumption system knows the sign of
d(e.g.a − bwithapositive andbnegative;x² + 1for realx). - Both are constants (no free symbols) → 16-digit numeric
evaluation; decided only if the values differ by more than
1e-9relative and both are real. - Otherwise
None.
§Examples
use std::cmp::Ordering;
use symplex::prelude::*;
let ctx = Context::new();
assert_eq!(ctx.rational(1, 3).compare_numeric(&ctx.rational(1, 2)), Some(Ordering::Less));
assert_eq!(ctx.pi().compare_numeric(&ctx.int(3)), Some(Ordering::Greater));
assert_eq!(ctx.int(2).sqrt().compare_numeric(&ctx.rational(3, 2)), Some(Ordering::Less));
let x = ctx.symbol("x");
assert_eq!((&x + 1).compare_numeric(&x), Some(Ordering::Greater));
assert_eq!(x.compare_numeric(&ctx.int(0)), None);
let p = ctx.symbol_with("p", &[Assumption::Positive]);
assert_eq!(p.compare_numeric(&ctx.int(0)), Some(Ordering::Greater));Sourcepub fn is_less_than(&self, other: &Ex) -> Option<bool>
pub fn is_less_than(&self, other: &Ex) -> Option<bool>
Is self < other? Three-valued; see
compare_numeric for the decision procedure.
use symplex::prelude::*;
let ctx = Context::new();
assert_eq!(ctx.int(1).is_less_than(&ctx.int(2)), Some(true));
assert_eq!(ctx.pi().is_less_than(&ctx.int(3)), Some(false));
let x = ctx.symbol("x");
assert_eq!(x.is_less_than(&ctx.int(3)), None);
// Assumptions help: x² ≥ 0 for real x, so x² < -1 is false.
let r = ctx.symbol_with("r", &[Assumption::Real]);
assert_eq!(r.powi(2).is_less_than(&ctx.int(-1)), Some(false));Sourcepub fn is_greater_than(&self, other: &Ex) -> Option<bool>
pub fn is_greater_than(&self, other: &Ex) -> Option<bool>
Is self > other? Three-valued; see
compare_numeric.
use symplex::prelude::*;
let ctx = Context::new();
assert_eq!(ctx.e().is_greater_than(&ctx.int(2)), Some(true));
assert_eq!(ctx.int(2).is_greater_than(&ctx.int(2)), Some(false));
assert_eq!(ctx.symbol("x").is_greater_than(&ctx.int(0)), None);Sourcepub fn probably_equal(&self, other: &Ex, samples: usize) -> Option<bool>
pub fn probably_equal(&self, other: &Ex, samples: usize) -> Option<bool>
Randomized equality test: evaluate both sides at samples random
rational points and compare.
Some(false)— a concrete point was found where the two sides differ. When both sides fold to exact rationals at that point this is a proof; when transcendental functions force floating-point evaluation the sides differ by more than1e-9relative.Some(true)—equalsproved it symbolically, or every sample agreed. The latter is probabilistic: for polynomial and rational identities the chance of a false positive is negligible after a few samples, but no proof is produced.None— no sample point could be evaluated (domain errors at every point) and the symbolic test was inconclusive.
Sample points are drawn from a fixed-seed generator keyed on the two
expressions, so results are reproducible. samples == 0 is treated
as 1.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
let lhs = (&x + 1).powi(3);
let rhs = &x.powi(3) + &x.powi(2) * 3 + &x * 3 + 1;
assert_eq!(lhs.probably_equal(&rhs, 5), Some(true));
assert_eq!(x.probably_equal(&ctx.symbol("y"), 5), Some(false));
assert_eq!(x.sin().probably_equal(&x.cos(), 5), Some(false));Sourcepub fn eval_at(&self, pairs: &[(&Ex, &Ex)]) -> Ex
pub fn eval_at(&self, pairs: &[(&Ex, &Ex)]) -> Ex
Substitute (symbol, value) pairs simultaneously and evaluate.
Shorthand for self.subs_map(pairs).eval(). The result is exact
and may still be symbolic if not every symbol was bound.
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let f = &x.powi(2) + &y;
assert_eq!(format!("{}", f.eval_at(&[(&x, &ctx.int(3)), (&y, &ctx.rational(1, 2))])), "19/2");
assert_eq!(format!("{}", f.eval_at(&[(&x, &ctx.pi())])), "y + pi^2");Source§impl Ex
impl Ex
Sourcepub fn solve_general(&self, var: &Ex) -> Result<GeneralSolution, SymplexError>
pub fn solve_general(&self, var: &Ex) -> Result<GeneralSolution, SymplexError>
Solve self = 0 for var, returning general solution families.
Unlike solve, which returns only principal branches,
this expresses periodic solutions with a fresh integer parameter
(n, or n1, n2, … if n is already in use), exposed through
GeneralSolution::parameters:
sin(x) = c→asin(c) + 2πn,π − asin(c) + 2πncos(x) = c→±acos(c) + 2πntan(x) = c→atan(c) + πn
Linear arguments (sin(a·x + b) = c) and change-of-variable forms
(sin²x − sin x = 0) are supported. Non-periodic equations return
the same solutions as solve with an empty parameter list.
§Errors
Same as solve: InfiniteSolutions for identities,
NoSolution for contradictions, ComputationFailed when nothing
applies.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
let eq = &x.sin() - &ctx.rational(1, 2);
let fam = eq.solve_general(&x).unwrap();
assert_eq!(fam.solutions.len(), 2);
assert_eq!(fam.parameters.len(), 1);
// Every member of every family satisfies the equation.
for k in -2..=2 {
for s in fam.instance(k) {
let residual = eq.subs(&x, &s).eval_f64().unwrap();
assert!(residual.abs() < 1e-12);
}
}Source§impl Ex
impl Ex
Sourcepub fn solve_ode_ivp(
&self,
func: &Ex,
var: &Ex,
ics: &[(usize, Ex, Ex)],
) -> Result<Ex, SymplexError>
pub fn solve_ode_ivp( &self, func: &Ex, var: &Ex, ics: &[(usize, Ex, Ex)], ) -> Result<Ex, SymplexError>
Solve the ODE self = 0 for func(var) subject to initial
conditions.
Each initial condition is (k, x0, value) meaning
d^k func / d var^k (x0) = value (k = 0 is func(x0) = value).
The general solution is found with solve_ode,
then the integration constants C1, C2, … are determined by
substituting the conditions and solving the resulting (usually
linear) system with linsolve; nonlinear constant equations are
handled one at a time with solve. Constants not
pinned down by the conditions remain in the result.
§Errors
SymplexError::ComputationFailedif the ODE cannot be solved or the constants cannot be determined.SymplexError::NoSolutionif the initial conditions are contradictory.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
// y'' + y = 0, y(0) = 0, y'(0) = 1 → y = sin(x)
let ode = &y.formal_diff(&x).formal_diff(&x) + &y;
let sol = ode
.solve_ode_ivp(&y, &x, &[(0, ctx.int(0), ctx.int(0)), (1, ctx.int(0), ctx.int(1))])
.unwrap();
assert_eq!(format!("{}", sol.simplify()), "sin(x)");Source§impl Ex
impl Ex
Sourcepub fn solve_riccati(
&self,
func: &Ex,
var: &Ex,
particular: &Ex,
) -> Result<Ex, SymplexError>
pub fn solve_riccati( &self, func: &Ex, var: &Ex, particular: &Ex, ) -> Result<Ex, SymplexError>
Solve the Riccati equation self = 0, i.e.
y' = q₀(x) + q₁(x)·y + q₂(x)·y², given a known particular
solution particular.
The substitution y = y_p + 1/v reduces the equation to the linear
ODE v' + (q₁ + 2·q₂·y_p)·v = −q₂; the result is y_p + 1/v with the
integration constant C1.
§Errors
SymplexError::InvalidArgumentifselfis not a Riccati equation infuncorparticulardoes not satisfy it.SymplexError::ComputationFailedif the linear equation forvcannot be solved in closed form.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
// y' = y² - 2/x² has the particular solution y = 1/x
let ode = &y.formal_diff(&x) - &y.powi(2) + &(&ctx.int(2) / &x.powi(2));
let sol = ode.solve_riccati(&y, &x, &(&ctx.int(1) / &x)).unwrap();
assert!(sol.contains(&ctx.symbol("C1")));
assert!(ode.check_ode_solution(&sol, &y, &x));Source§impl Ex
impl Ex
Sourcepub fn as_poly(&self, gens: &[&Ex]) -> Option<Poly>
pub fn as_poly(&self, gens: &[&Ex]) -> Option<Poly>
View this expression as a Poly in gens; see Poly::new.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let (x, a) = (ctx.symbol("x"), ctx.symbol("a"));
let p = (&a * &x.powi(2) + 1).as_poly(&[&x]).unwrap();
assert_eq!(p.degree_in(&x), Some(2));
assert_eq!(p.leading_coeff(), a);
assert!(x.sin().as_poly(&[&x]).is_none());Source§impl Ex
impl Ex
Sourcepub fn z_transform(&self, n: &Ex, z: &Ex) -> Result<Ex, SymplexError>
pub fn z_transform(&self, n: &Ex, z: &Ex) -> Result<Ex, SymplexError>
Unilateral Z-transform X(z) = Σ_{n≥0} x[n] z^{−n} of this sequence
(a function of the integer index n).
Table: constants, aⁿ, nᵏ aⁿ (via Z{n x[n]} = −z X′(z)),
sin(ωn), cos(ωn), aⁿ sin(ωn), aⁿ cos(ωn), H(n − k),
δ[n − k], C(n, k), 1/n!; rules: linearity, scaling
aⁿ x[n] → X(z/a), delay x[n − k] H(n − k) → z^{−k} X(z).
§Errors
ComputationFailed if n/z are not symbols or no rule applies.
There is no unevaluated Z-transform node, so this API is
Result-only.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let n = ctx.symbol("n");
let z = ctx.symbol("z");
let half = ctx.rational(1, 2);
// Z{(1/2)^n} = z/(z − 1/2)
let result = half.pow(&n).z_transform(&n, &z).unwrap();
assert_eq!(result, &z / (&z - half));
// n² → z(z + 1)/(z − 1)³
let x = n.powi(2).z_transform(&n, &z).unwrap();
let expected = &z * (&z + 1) / (&z - 1).powi(3);
assert!((&x - &expected).simplify().is_zero_structural(), "{x}");
// δ[n − 3] → z⁻³
assert_eq!((&n - 3).dirac_delta().z_transform(&n, &z).unwrap(), z.powi(-3));Sourcepub fn inverse_z_transform(&self, z: &Ex, n: &Ex) -> Result<Ex, SymplexError>
pub fn inverse_z_transform(&self, z: &Ex, n: &Ex) -> Result<Ex, SymplexError>
Inverse (unilateral) Z-transform of this expression (a function of
z) as a sequence in n.
Rational X(z) is handled through partial fractions in z
(z/(z − a)ᵐ → C(n, m−1) a^{n−m+1}, 1/(z − a)ᵐ through the delay
rule), together with constants (δ[n]), z^{−k} (δ[n − k]),
z^{−k} X(z) (x[n−k] H(n−k)), e^{1/z} (1/n!) and the
trigonometric forms.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let n = ctx.symbol("n");
let z = ctx.symbol("z");
// Z⁻¹{z/(z−2)} = 2ⁿ
let xz = &z / &(&z - 2);
assert_eq!(format!("{}", xz.inverse_z_transform(&z, &n).unwrap()), "2^n");
// Z⁻¹{z⁻²} = δ[n − 2]
let d = (1 / z.powi(2)).inverse_z_transform(&z, &n).unwrap();
assert_eq!(format!("{d}"), "KroneckerDelta(2, n)");Source§impl Ex
impl Ex
Sourcepub fn prove_nonnegative_on_box(
&self,
bounds: &[(Ex, Ex, Ex)],
degree: u32,
) -> Result<BoxOutcome, SymplexError>
pub fn prove_nonnegative_on_box( &self, bounds: &[(Ex, Ex, Ex)], degree: u32, ) -> Result<BoxOutcome, SymplexError>
prove_nonnegative_on_box as a method.
Source§impl Ex
impl Ex
Sourcepub fn find_root_bracket(
&self,
var: &Ex,
a: f64,
b: f64,
) -> Result<f64, SymplexError>
pub fn find_root_bracket( &self, var: &Ex, a: f64, b: f64, ) -> Result<f64, SymplexError>
Numerically find a root of this expression in var inside the
bracket [a, b] by brent_root with default RootOpts.
The expression is compiled with compile first, so
evaluation is fast and the usual compile-time checks apply.
§Errors
SymplexError::InvalidArgumentifvaris not a symbol, or the bracket is invalid (non-finite, or no sign change).SymplexError::FreeSymbolif the expression contains a symbol other thanvar.SymplexError::NotImplementedif the expression cannot be compiled tof64arithmetic.SymplexError::ComputationFailedif the iteration does not converge or meets a non-finite value.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
let r = (&x.powi(2) - 2).find_root_bracket(&x, 0.0, 2.0).unwrap();
assert!((r - 2f64.sqrt()).abs() < 1e-12);
// A transcendental equation: cos x = x.
let r = (x.cos() - &x).find_root_bracket(&x, 0.0, 1.0).unwrap();
assert!((r - 0.739_085_133_215_160_6).abs() < 1e-12);
// Another free symbol → FreeSymbol, not a silent NaN.
let a = ctx.symbol("a");
assert!(matches!(
(&x.powi(2) - &a).find_root_bracket(&x, 0.0, 2.0),
Err(SymplexError::FreeSymbol { .. })
));Sourcepub fn find_root_bracket_with(
&self,
var: &Ex,
a: f64,
b: f64,
opts: &RootOpts,
) -> Result<f64, SymplexError>
pub fn find_root_bracket_with( &self, var: &Ex, a: f64, b: f64, opts: &RootOpts, ) -> Result<f64, SymplexError>
find_root_bracket with explicit
RootOpts.
§Examples
use symplex::optimize::RootOpts;
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
let opts = RootOpts { xtol: 1e-6, ..RootOpts::default() };
let r = (x.exp() - 3).find_root_bracket_with(&x, 0.0, 2.0, &opts).unwrap();
assert!((r - 3f64.ln()).abs() < 1e-6);Sourcepub fn minimize_numeric(
&self,
vars: &[&Ex],
x0: &[f64],
) -> Result<MinimizeResult, SymplexError>
pub fn minimize_numeric( &self, vars: &[&Ex], x0: &[f64], ) -> Result<MinimizeResult, SymplexError>
Minimise this expression numerically over vars from the starting
point x0 by nelder_mead with default MinimizeOpts.
x0[i] is the initial value of vars[i].
§Errors
SymplexError::InvalidArgumentifvarsis empty, a variable is not a symbol, orx0.len() != vars.len().SymplexError::FreeSymbolif the expression contains a symbol not listed invars.SymplexError::NotImplementedif the expression cannot be compiled tof64arithmetic.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let bowl = (&x - 1).powi(2) + (&y + 2).powi(2);
let r = bowl.minimize_numeric(&[&x, &y], &[0.0, 0.0]).unwrap();
assert!(r.converged);
assert!((r.x[0] - 1.0).abs() < 1e-6 && (r.x[1] + 2.0).abs() < 1e-6);
assert!(r.fun < 1e-12);Sourcepub fn minimize_numeric_with(
&self,
vars: &[&Ex],
x0: &[f64],
opts: &MinimizeOpts,
) -> Result<MinimizeResult, SymplexError>
pub fn minimize_numeric_with( &self, vars: &[&Ex], x0: &[f64], opts: &MinimizeOpts, ) -> Result<MinimizeResult, SymplexError>
minimize_numeric with explicit
MinimizeOpts.
§Examples
use symplex::optimize::MinimizeOpts;
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let rosen = (1 - &x).powi(2) + 100 * (&y - &x.powi(2)).powi(2);
let opts = MinimizeOpts { max_iter: 2000, ..MinimizeOpts::default() };
let r = rosen.minimize_numeric_with(&[&x, &y], &[-1.2, 1.0], &opts).unwrap();
assert!((r.x[0] - 1.0).abs() < 1e-4 && (r.x[1] - 1.0).abs() < 1e-4);Sourcepub fn minimize_scalar_numeric(
&self,
var: &Ex,
a: f64,
b: f64,
) -> Result<(f64, f64), SymplexError>
pub fn minimize_scalar_numeric( &self, var: &Ex, a: f64, b: f64, ) -> Result<(f64, f64), SymplexError>
Minimise this expression in the single variable var over [a, b]
by Brent’s method (minimize_scalar) with default
MinimizeOpts. Returns (x_min, f_min).
§Errors
As for find_root_bracket plus the
interval rules of minimize_scalar.
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
// x·ln x has its minimum −1/e at x = 1/e.
let (xm, fm) = (&x * x.ln()).minimize_scalar_numeric(&x, 0.1, 2.0).unwrap();
assert!((xm - (-1.0f64).exp()).abs() < 1e-6);
assert!((fm + (-1.0f64).exp()).abs() < 1e-12);Sourcepub fn minimize_global_numeric(
&self,
vars: &[&Ex],
bounds: &[(f64, f64)],
opts: &DeOpts,
) -> Result<MinimizeResult, SymplexError>
pub fn minimize_global_numeric( &self, vars: &[&Ex], bounds: &[(f64, f64)], opts: &DeOpts, ) -> Result<MinimizeResult, SymplexError>
Globally minimise this expression over the box bounds (one
(lo, hi) pair per entry of vars) by
differential_evolution.
§Errors
As for minimize_numeric, with
bounds.len() playing the role of x0.len(), plus the option and
bound rules of differential_evolution.
§Examples
use symplex::optimize::DeOpts;
use symplex::prelude::*;
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
// Himmelblau's function has four global minima with f = 0.
let h = (&x.powi(2) + &y - 11).powi(2) + (&x + &y.powi(2) - 7).powi(2);
let r = h.minimize_global_numeric(&[&x, &y], &[(-5.0, 5.0), (-5.0, 5.0)], &DeOpts::default()).unwrap();
assert!(r.fun < 1e-8, "f = {}", r.fun);Sourcepub fn poly_fit_points(
ctx: &Context,
points: &[(Ex, Ex)],
var: &Ex,
degree: usize,
) -> Result<Ex, SymplexError>
pub fn poly_fit_points( ctx: &Context, points: &[(Ex, Ex)], var: &Ex, degree: usize, ) -> Result<Ex, SymplexError>
Exact least-squares polynomial of degree degree in var through
the rational points (x, y).
Each coordinate is constant-folded with eval and
must then be a rational literal (ctx.int, ctx.rational,
sqrt(4), …). The fit is computed by poly_fit_exact, so the
result is the exact least-squares polynomial — the interpolating
polynomial when degree + 1 == points.len() or the data are
consistent.
§Errors
SymplexError::InvalidArgumentif a coordinate is not a rational literal after evaluation, ordegree >= points.len().SymplexError::ComputationFailedif the normal equations are singular (fewer thandegree + 1distinct abscissae).
§Panics
Panics if var or a point belongs to a different context than
ctx (the standard cross-context guard).
§Examples
use symplex::prelude::*;
let ctx = Context::new();
let x = ctx.symbol("x");
// Five samples of x²/3 − x/2 + 1/7.
let pts = [
(ctx.int(0), ctx.rational(1, 7)),
(ctx.int(1), ctx.rational(-1, 42)),
(ctx.int(2), ctx.rational(10, 21)),
(ctx.int(3), ctx.rational(23, 14)),
(ctx.int(4), ctx.rational(73, 21)),
];
let p = Ex::poly_fit_points(&ctx, &pts, &x, 2).unwrap();
let expected = &x.powi(2) * ctx.rational(1, 3) - &x * ctx.rational(1, 2) + ctx.rational(1, 7);
assert!((&p - &expected).expand().is_zero_structural(), "{p}");
// A symbolic coordinate is rejected.
let a = ctx.symbol("a");
assert!(Ex::poly_fit_points(&ctx, &[(ctx.int(0), a), (ctx.int(1), ctx.int(1))], &x, 1).is_err());Trait Implementations§
Source§impl AddAssign for Ex
impl AddAssign for Ex
Source§fn add_assign(&mut self, rhs: Ex)
fn add_assign(&mut self, rhs: Ex)
+= operation. Read moreSource§impl AddAssign<&Expr<Numeric>> for Ex
impl AddAssign<&Expr<Numeric>> for Ex
Source§fn add_assign(&mut self, rhs: &Ex)
fn add_assign(&mut self, rhs: &Ex)
+= operation. Read moreSource§impl<T: Scalar> AddAssign<T> for Ex
impl<T: Scalar> AddAssign<T> for Ex
Source§fn add_assign(&mut self, rhs: T)
fn add_assign(&mut self, rhs: T)
+= operation. Read moreSource§impl DivAssign for Ex
impl DivAssign for Ex
Source§fn div_assign(&mut self, rhs: Ex)
fn div_assign(&mut self, rhs: Ex)
/= operation. Read moreSource§impl DivAssign<&Expr<Numeric>> for Ex
impl DivAssign<&Expr<Numeric>> for Ex
Source§fn div_assign(&mut self, rhs: &Ex)
fn div_assign(&mut self, rhs: &Ex)
/= operation. Read moreSource§impl<T: Scalar> DivAssign<T> for Ex
impl<T: Scalar> DivAssign<T> for Ex
Source§fn div_assign(&mut self, rhs: T)
fn div_assign(&mut self, rhs: T)
/= operation. Read moreSource§impl Mul<&Quaternion> for &Ex
impl Mul<&Quaternion> for &Ex
Source§type Output = Quaternion
type Output = Quaternion
* operator.Source§fn mul(self, rhs: &Quaternion) -> Quaternion
fn mul(self, rhs: &Quaternion) -> Quaternion
* operation. Read moreSource§impl Mul<&Quaternion> for Ex
impl Mul<&Quaternion> for Ex
Source§type Output = Quaternion
type Output = Quaternion
* operator.Source§fn mul(self, rhs: &Quaternion) -> Quaternion
fn mul(self, rhs: &Quaternion) -> Quaternion
* operation. Read moreSource§impl Mul<Acceleration> for &Ex
impl Mul<Acceleration> for &Ex
Source§type Output = Acceleration
type Output = Acceleration
* operator.Source§fn mul(self, rhs: Acceleration) -> Acceleration
fn mul(self, rhs: Acceleration) -> Acceleration
* operation. Read moreSource§impl Mul<AngularAcceleration> for &Ex
impl Mul<AngularAcceleration> for &Ex
Source§type Output = AngularAcceleration
type Output = AngularAcceleration
* operator.Source§fn mul(self, rhs: AngularAcceleration) -> AngularAcceleration
fn mul(self, rhs: AngularAcceleration) -> AngularAcceleration
* operation. Read moreSource§impl Mul<AngularMomentum> for &Ex
impl Mul<AngularMomentum> for &Ex
Source§type Output = AngularMomentum
type Output = AngularMomentum
* operator.Source§fn mul(self, rhs: AngularMomentum) -> AngularMomentum
fn mul(self, rhs: AngularMomentum) -> AngularMomentum
* operation. Read moreSource§impl Mul<AngularVelocity> for &Ex
impl Mul<AngularVelocity> for &Ex
Source§type Output = AngularVelocity
type Output = AngularVelocity
* operator.Source§fn mul(self, rhs: AngularVelocity) -> AngularVelocity
fn mul(self, rhs: AngularVelocity) -> AngularVelocity
* operation. Read moreSource§impl Mul<Capacitance> for &Ex
impl Mul<Capacitance> for &Ex
Source§type Output = Capacitance
type Output = Capacitance
* operator.Source§fn mul(self, rhs: Capacitance) -> Capacitance
fn mul(self, rhs: Capacitance) -> Capacitance
* operation. Read moreSource§impl Mul<Dimensionless> for &Ex
impl Mul<Dimensionless> for &Ex
Source§type Output = Dimensionless
type Output = Dimensionless
* operator.Source§fn mul(self, rhs: Dimensionless) -> Dimensionless
fn mul(self, rhs: Dimensionless) -> Dimensionless
* operation. Read moreSource§impl Mul<Inductance> for &Ex
impl Mul<Inductance> for &Ex
Source§type Output = Inductance
type Output = Inductance
* operator.Source§fn mul(self, rhs: Inductance) -> Inductance
fn mul(self, rhs: Inductance) -> Inductance
* operation. Read moreSource§impl Mul<MagneticFlux> for &Ex
impl Mul<MagneticFlux> for &Ex
Source§type Output = MagneticFlux
type Output = MagneticFlux
* operator.Source§fn mul(self, rhs: MagneticFlux) -> MagneticFlux
fn mul(self, rhs: MagneticFlux) -> MagneticFlux
* operation. Read moreSource§impl Mul<MomentOfInertia> for &Ex
impl Mul<MomentOfInertia> for &Ex
Source§type Output = MomentOfInertia
type Output = MomentOfInertia
* operator.Source§fn mul(self, rhs: MomentOfInertia) -> MomentOfInertia
fn mul(self, rhs: MomentOfInertia) -> MomentOfInertia
* operation. Read moreSource§impl Mul<Quaternion> for &Ex
impl Mul<Quaternion> for &Ex
Source§type Output = Quaternion
type Output = Quaternion
* operator.Source§fn mul(self, rhs: Quaternion) -> Quaternion
fn mul(self, rhs: Quaternion) -> Quaternion
* operation. Read moreSource§impl Mul<Quaternion> for Ex
impl Mul<Quaternion> for Ex
Source§type Output = Quaternion
type Output = Quaternion
* operator.Source§fn mul(self, rhs: Quaternion) -> Quaternion
fn mul(self, rhs: Quaternion) -> Quaternion
* operation. Read moreSource§impl Mul<Resistance> for &Ex
impl Mul<Resistance> for &Ex
Source§type Output = Resistance
type Output = Resistance
* operator.Source§fn mul(self, rhs: Resistance) -> Resistance
fn mul(self, rhs: Resistance) -> Resistance
* operation. Read moreSource§impl Mul<Temperature> for &Ex
impl Mul<Temperature> for &Ex
Source§type Output = Temperature
type Output = Temperature
* operator.Source§fn mul(self, rhs: Temperature) -> Temperature
fn mul(self, rhs: Temperature) -> Temperature
* operation. Read moreSource§impl MulAssign for Ex
impl MulAssign for Ex
Source§fn mul_assign(&mut self, rhs: Ex)
fn mul_assign(&mut self, rhs: Ex)
*= operation. Read moreSource§impl MulAssign<&Expr<Numeric>> for Ex
impl MulAssign<&Expr<Numeric>> for Ex
Source§fn mul_assign(&mut self, rhs: &Ex)
fn mul_assign(&mut self, rhs: &Ex)
*= operation. Read moreSource§impl<T: Scalar> MulAssign<T> for Ex
impl<T: Scalar> MulAssign<T> for Ex
Source§fn mul_assign(&mut self, rhs: T)
fn mul_assign(&mut self, rhs: T)
*= operation. Read moreSource§impl Product for Ex
Multiply an iterator of expressions.
impl Product for Ex
Multiply an iterator of expressions.
§Panics
Panics on an empty iterator (no context to build 1 in) — see
Context::product and the Option<Ex> implementation — and on
mixed-context input.
Source§impl SubAssign for Ex
impl SubAssign for Ex
Source§fn sub_assign(&mut self, rhs: Ex)
fn sub_assign(&mut self, rhs: Ex)
-= operation. Read moreSource§impl SubAssign<&Expr<Numeric>> for Ex
impl SubAssign<&Expr<Numeric>> for Ex
Source§fn sub_assign(&mut self, rhs: &Ex)
fn sub_assign(&mut self, rhs: &Ex)
-= operation. Read moreSource§impl<T: Scalar> SubAssign<T> for Ex
impl<T: Scalar> SubAssign<T> for Ex
Source§fn sub_assign(&mut self, rhs: T)
fn sub_assign(&mut self, rhs: T)
-= operation. Read moreSource§impl Sum for Ex
Sum an iterator of expressions.
impl Sum for Ex
Sum an iterator of expressions.
§Panics
Panics on an empty iterator: there is no context in which to build
0. Use Context::sum (yields 0 on empty) or collect into
Option<Ex> (yields None on empty) when the iterator may be empty.
Also panics if the expressions come from different contexts.
use symplex::prelude::*;
let ctx = Context::new();
let total: Ex = (1..=4).map(|n| ctx.int(n)).sum();
assert_eq!(format!("{total}"), "10");
let none: Option<Ex> = std::iter::empty::<Ex>().sum();
assert!(none.is_none());