#![allow(clippy::needless_lifetimes, clippy::suspicious_arithmetic_impl)]
use std::fmt;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Clone, Debug)]
pub struct Jet1Vec {
pub real: f64,
pub dual: Vec<f64>,
}
#[inline]
fn len_check(a: &Jet1Vec, b: &Jet1Vec) {
debug_assert_eq!(a.dual.len(), b.dual.len(), "Jet1Vec tangent length mismatch");
}
impl Jet1Vec {
#[inline]
pub fn new(real: f64, dual: Vec<f64>) -> Self {
Jet1Vec { real, dual }
}
#[inline]
pub fn constant(real: f64, n: usize) -> Self {
Jet1Vec {
real,
dual: vec![0.0; n],
}
}
#[inline]
pub fn variable(value: f64, i: usize, n: usize) -> Self {
let mut dual = vec![0.0; n];
dual[i] = 1.0;
Jet1Vec { real: value, dual }
}
#[inline]
pub fn real(&self) -> f64 {
self.real
}
#[inline]
pub fn dual(&self) -> &[f64] {
&self.dual
}
#[inline]
pub fn partial(&self, i: usize) -> f64 {
self.dual[i]
}
#[inline]
pub fn num_vars(&self) -> usize {
self.dual.len()
}
#[inline]
fn scaled(&self, k: f64) -> Vec<f64> {
self.dual.iter().map(|&d| d * k).collect()
}
#[inline]
fn scaled_into(mut self, k: f64) -> Vec<f64> {
for d in self.dual.iter_mut() {
*d *= k;
}
self.dual
}
#[inline]
pub fn powf(&self, n: f64) -> Jet1Vec {
let vn = self.real.powf(n);
let gp = n * self.real.powf(n - 1.0);
Jet1Vec {
real: vn,
dual: self.scaled(gp),
}
}
#[inline]
pub fn powi(&self, n: i32) -> Jet1Vec {
let vn = self.real.powi(n);
let gp = (n as f64) * self.real.powi(n - 1);
Jet1Vec {
real: vn,
dual: self.scaled(gp),
}
}
#[inline]
pub fn exp(&self) -> Jet1Vec {
let e = self.real.exp();
Jet1Vec {
real: e,
dual: self.scaled(e),
}
}
#[inline]
pub fn ln(&self) -> Jet1Vec {
let inv = 1.0 / self.real;
Jet1Vec {
real: self.real.ln(),
dual: self.scaled(inv),
}
}
#[inline]
pub fn sqrt(&self) -> Jet1Vec {
let s = self.real.sqrt();
Jet1Vec {
real: s,
dual: self.scaled(0.5 / s),
}
}
#[inline]
pub fn sin(&self) -> Jet1Vec {
Jet1Vec {
real: self.real.sin(),
dual: self.scaled(self.real.cos()),
}
}
#[inline]
pub fn cos(&self) -> Jet1Vec {
Jet1Vec {
real: self.real.cos(),
dual: self.scaled(-self.real.sin()),
}
}
#[inline]
pub fn tan(&self) -> Jet1Vec {
let t = self.real.tan();
let sec2 = 1.0 + t * t;
Jet1Vec {
real: t,
dual: self.scaled(sec2),
}
}
#[inline]
pub fn tanh(&self) -> Jet1Vec {
let t = self.real.tanh();
Jet1Vec {
real: t,
dual: self.scaled(1.0 - t * t),
}
}
#[inline]
pub fn abs(&self) -> Jet1Vec {
let sign = if self.real >= 0.0 { 1.0 } else { -1.0 };
Jet1Vec {
real: self.real.abs(),
dual: self.scaled(sign),
}
}
#[inline]
pub fn erf(&self) -> Jet1Vec {
let v = self.real;
let r = crate::math::erf(v);
let g = std::f64::consts::FRAC_2_SQRT_PI * (-v * v).exp();
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn norm_cdf(&self) -> Jet1Vec {
let v = self.real;
let r = crate::math::norm_cdf(v);
let g = crate::math::norm_pdf(v);
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn inv_norm_cdf(&self) -> Jet1Vec {
let v = self.real;
let r = crate::math::inv_norm_cdf(v);
let g = 1.0 / crate::math::norm_pdf(r);
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn into_powf(self, n: f64) -> Jet1Vec {
let real = self.real;
let vn = real.powf(n);
let gp = n * real.powf(n - 1.0);
Jet1Vec {
real: vn,
dual: self.scaled_into(gp),
}
}
#[inline]
pub fn into_powi(self, n: i32) -> Jet1Vec {
let real = self.real;
let vn = real.powi(n);
let gp = (n as f64) * real.powi(n - 1);
Jet1Vec {
real: vn,
dual: self.scaled_into(gp),
}
}
#[inline]
pub fn into_exp(self) -> Jet1Vec {
let e = self.real.exp();
Jet1Vec {
real: e,
dual: self.scaled_into(e),
}
}
#[inline]
pub fn into_ln(self) -> Jet1Vec {
let real = self.real;
Jet1Vec {
real: real.ln(),
dual: self.scaled_into(1.0 / real),
}
}
#[inline]
pub fn into_sqrt(self) -> Jet1Vec {
let s = self.real.sqrt();
Jet1Vec {
real: s,
dual: self.scaled_into(0.5 / s),
}
}
#[inline]
pub fn into_sin(self) -> Jet1Vec {
let real = self.real;
Jet1Vec {
real: real.sin(),
dual: self.scaled_into(real.cos()),
}
}
#[inline]
pub fn into_cos(self) -> Jet1Vec {
let real = self.real;
Jet1Vec {
real: real.cos(),
dual: self.scaled_into(-real.sin()),
}
}
#[inline]
pub fn into_tan(self) -> Jet1Vec {
let t = self.real.tan();
let sec2 = 1.0 + t * t;
Jet1Vec {
real: t,
dual: self.scaled_into(sec2),
}
}
#[inline]
pub fn into_tanh(self) -> Jet1Vec {
let t = self.real.tanh();
Jet1Vec {
real: t,
dual: self.scaled_into(1.0 - t * t),
}
}
#[inline]
pub fn into_abs(self) -> Jet1Vec {
let sign = if self.real >= 0.0 { 1.0 } else { -1.0 };
Jet1Vec {
real: self.real.abs(),
dual: self.scaled_into(sign),
}
}
#[inline]
pub fn into_erf(self) -> Jet1Vec {
let v = self.real;
let r = crate::math::erf(v);
let g = std::f64::consts::FRAC_2_SQRT_PI * (-v * v).exp();
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
#[inline]
pub fn into_norm_cdf(self) -> Jet1Vec {
let v = self.real;
let r = crate::math::norm_cdf(v);
let g = crate::math::norm_pdf(v);
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
#[inline]
pub fn into_inv_norm_cdf(self) -> Jet1Vec {
let v = self.real;
let r = crate::math::inv_norm_cdf(v);
let g = 1.0 / crate::math::norm_pdf(r);
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
}
impl<'a, 'b> Add<&'b Jet1Vec> for &'a Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(self, rhs: &'b Jet1Vec) -> Jet1Vec {
len_check(self, rhs);
Jet1Vec {
real: self.real + rhs.real,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(a, b)| a + b)
.collect(),
}
}
}
impl Add for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(mut self, rhs: Jet1Vec) -> Jet1Vec {
self += &rhs;
self
}
}
impl Add<&Jet1Vec> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(mut self, rhs: &Jet1Vec) -> Jet1Vec {
self += rhs;
self
}
}
impl Add<Jet1Vec> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(self, mut rhs: Jet1Vec) -> Jet1Vec {
rhs += self;
rhs
}
}
impl Add<f64> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(self, rhs: f64) -> Jet1Vec {
Jet1Vec {
real: self.real + rhs,
dual: self.dual.clone(),
}
}
}
impl Add<f64> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn add(mut self, rhs: f64) -> Jet1Vec {
self.real += rhs;
self
}
}
impl Add<&Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn add(self, rhs: &Jet1Vec) -> Jet1Vec {
rhs + self
}
}
impl Add<Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn add(self, rhs: Jet1Vec) -> Jet1Vec {
rhs + self
}
}
impl<'a, 'b> Sub<&'b Jet1Vec> for &'a Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(self, rhs: &'b Jet1Vec) -> Jet1Vec {
len_check(self, rhs);
Jet1Vec {
real: self.real - rhs.real,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(a, b)| a - b)
.collect(),
}
}
}
impl Sub for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(mut self, rhs: Jet1Vec) -> Jet1Vec {
self -= &rhs;
self
}
}
impl Sub<&Jet1Vec> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(mut self, rhs: &Jet1Vec) -> Jet1Vec {
self -= rhs;
self
}
}
impl Sub<Jet1Vec> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(self, mut rhs: Jet1Vec) -> Jet1Vec {
len_check(self, &rhs);
rhs.real = self.real - rhs.real;
for (b, &a) in rhs.dual.iter_mut().zip(&self.dual) {
*b = a - *b;
}
rhs
}
}
impl Sub<f64> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(self, rhs: f64) -> Jet1Vec {
Jet1Vec {
real: self.real - rhs,
dual: self.dual.clone(),
}
}
}
impl Sub<f64> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn sub(mut self, rhs: f64) -> Jet1Vec {
self.real -= rhs;
self
}
}
impl Sub<&Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn sub(self, rhs: &Jet1Vec) -> Jet1Vec {
Jet1Vec {
real: self - rhs.real,
dual: rhs.dual.iter().map(|&d| -d).collect(),
}
}
}
impl Sub<Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn sub(self, mut rhs: Jet1Vec) -> Jet1Vec {
rhs.real = self - rhs.real;
for d in rhs.dual.iter_mut() {
*d = -*d;
}
rhs
}
}
impl<'a, 'b> Mul<&'b Jet1Vec> for &'a Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(self, rhs: &'b Jet1Vec) -> Jet1Vec {
len_check(self, rhs);
let a = self.real;
let b = rhs.real;
Jet1Vec {
real: a * b,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(&da, &db)| da * b + db * a)
.collect(),
}
}
}
impl Mul for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(mut self, rhs: Jet1Vec) -> Jet1Vec {
len_check(&self, &rhs);
let a = self.real;
let b = rhs.real;
self.real = a * b;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * b + db * a;
}
self
}
}
impl Mul<&Jet1Vec> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(mut self, rhs: &Jet1Vec) -> Jet1Vec {
len_check(&self, rhs);
let a = self.real;
let b = rhs.real;
self.real = a * b;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * b + db * a;
}
self
}
}
impl Mul<Jet1Vec> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(self, mut rhs: Jet1Vec) -> Jet1Vec {
len_check(self, &rhs);
let a = self.real;
let b = rhs.real;
rhs.real = a * b;
for (db, &da) in rhs.dual.iter_mut().zip(&self.dual) {
*db = da * b + *db * a;
}
rhs
}
}
impl Mul<f64> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(self, rhs: f64) -> Jet1Vec {
Jet1Vec {
real: self.real * rhs,
dual: self.dual.iter().map(|&d| d * rhs).collect(),
}
}
}
impl Mul<f64> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn mul(mut self, rhs: f64) -> Jet1Vec {
self.real *= rhs;
for d in self.dual.iter_mut() {
*d *= rhs;
}
self
}
}
impl Mul<&Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn mul(self, rhs: &Jet1Vec) -> Jet1Vec {
rhs * self
}
}
impl Mul<Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn mul(self, rhs: Jet1Vec) -> Jet1Vec {
rhs * self
}
}
impl<'a, 'b> Div<&'b Jet1Vec> for &'a Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(self, rhs: &'b Jet1Vec) -> Jet1Vec {
len_check(self, rhs);
let inv = 1.0 / rhs.real;
let inv2 = inv * inv;
let a_inv2 = self.real * inv2;
Jet1Vec {
real: self.real * inv,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(&da, &db)| da * inv - db * a_inv2)
.collect(),
}
}
}
impl Div for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(mut self, rhs: Jet1Vec) -> Jet1Vec {
len_check(&self, &rhs);
let inv = 1.0 / rhs.real;
let inv2 = inv * inv;
let a_inv2 = self.real * inv2;
self.real *= inv;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * inv - db * a_inv2;
}
self
}
}
impl Div<&Jet1Vec> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(mut self, rhs: &Jet1Vec) -> Jet1Vec {
len_check(&self, rhs);
let inv = 1.0 / rhs.real;
let inv2 = inv * inv;
let a_inv2 = self.real * inv2;
self.real *= inv;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * inv - db * a_inv2;
}
self
}
}
impl Div<Jet1Vec> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(self, rhs: Jet1Vec) -> Jet1Vec {
self / &rhs
}
}
impl Div<f64> for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(self, rhs: f64) -> Jet1Vec {
let inv = 1.0 / rhs;
Jet1Vec {
real: self.real * inv,
dual: self.dual.iter().map(|&d| d * inv).collect(),
}
}
}
impl Div<f64> for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn div(mut self, rhs: f64) -> Jet1Vec {
let inv = 1.0 / rhs;
self.real *= inv;
for d in self.dual.iter_mut() {
*d *= inv;
}
self
}
}
impl Div<&Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn div(self, rhs: &Jet1Vec) -> Jet1Vec {
let inv = 1.0 / rhs.real;
let neg_scale = -self * inv * inv;
Jet1Vec {
real: self * inv,
dual: rhs.dual.iter().map(|&d| d * neg_scale).collect(),
}
}
}
impl Div<Jet1Vec> for f64 {
type Output = Jet1Vec;
#[inline]
fn div(self, mut rhs: Jet1Vec) -> Jet1Vec {
let inv = 1.0 / rhs.real;
let neg_scale = -self * inv * inv;
rhs.real = self * inv;
for d in rhs.dual.iter_mut() {
*d *= neg_scale;
}
rhs
}
}
impl Neg for &Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn neg(self) -> Jet1Vec {
Jet1Vec {
real: -self.real,
dual: self.dual.iter().map(|&d| -d).collect(),
}
}
}
impl Neg for Jet1Vec {
type Output = Jet1Vec;
#[inline]
fn neg(mut self) -> Jet1Vec {
self.real = -self.real;
for d in self.dual.iter_mut() {
*d = -*d;
}
self
}
}
impl AddAssign<&Jet1Vec> for Jet1Vec {
#[inline]
fn add_assign(&mut self, rhs: &Jet1Vec) {
len_check(self, rhs);
self.real += rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a += b;
}
}
}
impl AddAssign for Jet1Vec {
#[inline]
fn add_assign(&mut self, rhs: Jet1Vec) {
len_check(self, &rhs);
self.real += rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a += b;
}
}
}
impl AddAssign<f64> for Jet1Vec {
#[inline]
fn add_assign(&mut self, rhs: f64) {
self.real += rhs;
}
}
impl SubAssign<&Jet1Vec> for Jet1Vec {
#[inline]
fn sub_assign(&mut self, rhs: &Jet1Vec) {
len_check(self, rhs);
self.real -= rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a -= b;
}
}
}
impl SubAssign for Jet1Vec {
#[inline]
fn sub_assign(&mut self, rhs: Jet1Vec) {
len_check(self, &rhs);
self.real -= rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a -= b;
}
}
}
impl SubAssign<f64> for Jet1Vec {
#[inline]
fn sub_assign(&mut self, rhs: f64) {
self.real -= rhs;
}
}
impl MulAssign<&Jet1Vec> for Jet1Vec {
#[inline]
fn mul_assign(&mut self, rhs: &Jet1Vec) {
len_check(self, rhs);
let a = self.real;
let b = rhs.real;
self.real = a * b;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * b + db * a;
}
}
}
impl MulAssign<f64> for Jet1Vec {
#[inline]
fn mul_assign(&mut self, rhs: f64) {
self.real *= rhs;
for d in self.dual.iter_mut() {
*d *= rhs;
}
}
}
impl DivAssign<&Jet1Vec> for Jet1Vec {
#[inline]
fn div_assign(&mut self, rhs: &Jet1Vec) {
len_check(self, rhs);
let inv = 1.0 / rhs.real;
let inv2 = inv * inv;
let a_inv2 = self.real * inv2;
self.real *= inv;
for (da, &db) in self.dual.iter_mut().zip(&rhs.dual) {
*da = *da * inv - db * a_inv2;
}
}
}
impl DivAssign<f64> for Jet1Vec {
#[inline]
fn div_assign(&mut self, rhs: f64) {
let inv = 1.0 / rhs;
self.real *= inv;
for d in self.dual.iter_mut() {
*d *= inv;
}
}
}
impl PartialEq for Jet1Vec {
fn eq(&self, other: &Self) -> bool {
self.real == other.real
}
}
impl PartialEq<f64> for Jet1Vec {
fn eq(&self, other: &f64) -> bool {
self.real == *other
}
}
impl PartialOrd for Jet1Vec {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.real.partial_cmp(&other.real)
}
}
impl PartialOrd<f64> for Jet1Vec {
fn partial_cmp(&self, other: &f64) -> Option<std::cmp::Ordering> {
self.real.partial_cmp(other)
}
}
impl fmt::Display for Jet1Vec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.real)
}
}
#[derive(Clone, Debug)]
pub struct NamedJet1Vec {
pub(crate) inner: Jet1Vec,
#[cfg(debug_assertions)]
pub(crate) gen_id: u64,
}
impl NamedJet1Vec {
#[inline]
pub(crate) fn __from_inner(inner: Jet1Vec) -> Self {
Self {
inner,
#[cfg(debug_assertions)]
gen_id: crate::forward_tape::current_gen(),
}
}
#[inline]
pub fn real(&self) -> f64 {
self.inner.real
}
pub fn partial(&self, name: &str) -> f64 {
let idx = crate::forward_tape::with_active_registry(|r| {
let r =
r.expect("NamedJet1Vec::partial called outside a frozen NamedForwardTape scope");
r.index_of(name).unwrap_or_else(|| {
panic!(
"NamedJet1Vec::partial: name {:?} not present in registry",
name
)
})
});
self.inner.partial(idx)
}
pub fn gradient(&self) -> Vec<(String, f64)> {
crate::forward_tape::with_active_registry(|r| {
let r =
r.expect("NamedJet1Vec::gradient called outside a frozen NamedForwardTape scope");
let n = r.len();
let mut out = Vec::with_capacity(n);
for (i, name) in r.iter().enumerate() {
out.push((name.to_string(), self.inner.partial(i)));
}
out
})
}
#[inline]
pub fn inner(&self) -> &Jet1Vec {
&self.inner
}
#[inline]
pub fn exp(&self) -> Self {
Self {
inner: self.inner.exp(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn ln(&self) -> Self {
Self {
inner: self.inner.ln(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn sqrt(&self) -> Self {
Self {
inner: self.inner.sqrt(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn sin(&self) -> Self {
Self {
inner: self.inner.sin(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn cos(&self) -> Self {
Self {
inner: self.inner.cos(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn tan(&self) -> Self {
Self {
inner: self.inner.tan(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn norm_cdf(&self) -> Self {
Self {
inner: self.inner.norm_cdf(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn inv_norm_cdf(&self) -> Self {
Self {
inner: self.inner.inv_norm_cdf(),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn powf(&self, n: f64) -> Self {
Self {
inner: self.inner.powf(n),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
#[inline]
pub fn powi(&self, n: i32) -> Self {
Self {
inner: self.inner.powi(n),
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl fmt::Display for NamedJet1Vec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NamedJet1Vec({})", self.inner.real)
}
}
macro_rules! __named_dual_binop {
($trait:ident, $method:ident, $op:tt) => {
impl ::core::ops::$trait<NamedJet1Vec> for NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
NamedJet1Vec {
inner: self.inner $op rhs.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::$trait<&NamedJet1Vec> for &NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
NamedJet1Vec {
inner: &self.inner $op &rhs.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::$trait<&NamedJet1Vec> for NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
NamedJet1Vec {
inner: self.inner $op &rhs.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::$trait<NamedJet1Vec> for &NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
NamedJet1Vec {
inner: &self.inner $op rhs.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::$trait<f64> for NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: f64) -> NamedJet1Vec {
NamedJet1Vec {
inner: self.inner $op rhs,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::$trait<f64> for &NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn $method(self, rhs: f64) -> NamedJet1Vec {
NamedJet1Vec {
inner: &self.inner $op rhs,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
};
}
__named_dual_binop!(Add, add, +);
__named_dual_binop!(Sub, sub, -);
__named_dual_binop!(Mul, mul, *);
__named_dual_binop!(Div, div, /);
impl ::core::ops::AddAssign<NamedJet1Vec> for NamedJet1Vec {
#[inline]
fn add_assign(&mut self, rhs: NamedJet1Vec) {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
self.inner += rhs.inner;
}
}
impl ::core::ops::AddAssign<&NamedJet1Vec> for NamedJet1Vec {
#[inline]
fn add_assign(&mut self, rhs: &NamedJet1Vec) {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
self.inner += &rhs.inner;
}
}
impl ::core::ops::Neg for NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn neg(self) -> NamedJet1Vec {
NamedJet1Vec {
inner: -self.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::Neg for &NamedJet1Vec {
type Output = NamedJet1Vec;
#[inline]
fn neg(self) -> NamedJet1Vec {
NamedJet1Vec {
inner: -&self.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl ::core::ops::Add<NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn add(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self + rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Add<&NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn add(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self + &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Sub<NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn sub(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self - rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Sub<&NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn sub(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self - &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Mul<NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn mul(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self * rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Mul<&NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn mul(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self * &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Div<NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn div(self, rhs: NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self / rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Div<&NamedJet1Vec> for f64 {
type Output = NamedJet1Vec;
#[inline]
fn div(self, rhs: &NamedJet1Vec) -> NamedJet1Vec {
NamedJet1Vec {
inner: self / &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}