#![allow(clippy::needless_lifetimes, clippy::suspicious_arithmetic_impl)]
use crate::passive::Passive;
use std::fmt;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
#[derive(Clone, Debug)]
pub struct Jet1Vec<T: Passive = f64> {
pub real: T,
pub dual: Vec<T>,
}
#[inline]
fn len_check<T: Passive>(a: &Jet1Vec<T>, b: &Jet1Vec<T>) {
debug_assert_eq!(a.dual.len(), b.dual.len(), "Jet1Vec tangent length mismatch");
}
impl<T: Passive> Jet1Vec<T> {
#[inline]
pub fn new(real: T, dual: Vec<T>) -> Self {
Jet1Vec { real, dual }
}
#[inline]
pub fn constant(real: T, n: usize) -> Self {
Jet1Vec {
real,
dual: vec![T::zero(); n],
}
}
#[inline]
pub fn variable(value: T, i: usize, n: usize) -> Self {
let mut dual = vec![T::zero(); n];
dual[i] = T::one();
Jet1Vec { real: value, dual }
}
#[inline]
pub fn real(&self) -> T {
self.real
}
#[inline]
pub fn dual(&self) -> &[T] {
&self.dual
}
#[inline]
pub fn partial(&self, i: usize) -> T {
self.dual[i]
}
#[inline]
pub fn num_vars(&self) -> usize {
self.dual.len()
}
#[inline]
fn scaled(&self, k: T) -> Vec<T> {
self.dual.iter().map(|&d| d * k).collect()
}
#[inline]
fn scaled_into(mut self, k: T) -> Vec<T> {
for d in self.dual.iter_mut() {
*d *= k;
}
self.dual
}
#[inline]
pub fn powf(&self, n: T) -> Jet1Vec<T> {
let vn = self.real.powf(n);
let gp = n * self.real.powf(n - T::one());
Jet1Vec {
real: vn,
dual: self.scaled(gp),
}
}
#[inline]
pub fn powi(&self, n: i32) -> Jet1Vec<T> {
let vn = self.real.powi(n);
let gp = T::from(n).unwrap() * self.real.powi(n - 1);
Jet1Vec {
real: vn,
dual: self.scaled(gp),
}
}
#[inline]
pub fn exp(&self) -> Jet1Vec<T> {
let e = self.real.exp();
Jet1Vec {
real: e,
dual: self.scaled(e),
}
}
#[inline]
pub fn ln(&self) -> Jet1Vec<T> {
let inv = T::one() / self.real;
Jet1Vec {
real: self.real.ln(),
dual: self.scaled(inv),
}
}
#[inline]
pub fn sqrt(&self) -> Jet1Vec<T> {
let s = self.real.sqrt();
Jet1Vec {
real: s,
dual: self.scaled(T::from(0.5).unwrap() / s),
}
}
#[inline]
pub fn sin(&self) -> Jet1Vec<T> {
Jet1Vec {
real: self.real.sin(),
dual: self.scaled(self.real.cos()),
}
}
#[inline]
pub fn cos(&self) -> Jet1Vec<T> {
Jet1Vec {
real: self.real.cos(),
dual: self.scaled(-self.real.sin()),
}
}
#[inline]
pub fn tan(&self) -> Jet1Vec<T> {
let t = self.real.tan();
let sec2 = T::one() + t * t;
Jet1Vec {
real: t,
dual: self.scaled(sec2),
}
}
#[inline]
pub fn tanh(&self) -> Jet1Vec<T> {
let t = self.real.tanh();
Jet1Vec {
real: t,
dual: self.scaled(T::one() - t * t),
}
}
#[inline]
pub fn abs(&self) -> Jet1Vec<T> {
let sign = if self.real >= T::zero() {
T::one()
} else {
-T::one()
};
Jet1Vec {
real: self.real.abs(),
dual: self.scaled(sign),
}
}
#[inline]
pub fn erf(&self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::erf::<T>(v);
let g = T::from(std::f64::consts::FRAC_2_SQRT_PI).unwrap() * (-v * v).exp();
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn norm_cdf(&self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::norm_cdf::<T>(v);
let g = crate::math::norm_pdf::<T>(v);
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn inv_norm_cdf(&self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::inv_norm_cdf::<T>(v);
let g = T::one() / crate::math::norm_pdf::<T>(r);
Jet1Vec {
real: r,
dual: self.scaled(g),
}
}
#[inline]
pub fn into_powf(self, n: T) -> Jet1Vec<T> {
let real = self.real;
let vn = real.powf(n);
let gp = n * real.powf(n - T::one());
Jet1Vec {
real: vn,
dual: self.scaled_into(gp),
}
}
#[inline]
pub fn into_powi(self, n: i32) -> Jet1Vec<T> {
let real = self.real;
let vn = real.powi(n);
let gp = T::from(n).unwrap() * real.powi(n - 1);
Jet1Vec {
real: vn,
dual: self.scaled_into(gp),
}
}
#[inline]
pub fn into_exp(self) -> Jet1Vec<T> {
let e = self.real.exp();
Jet1Vec {
real: e,
dual: self.scaled_into(e),
}
}
#[inline]
pub fn into_ln(self) -> Jet1Vec<T> {
let real = self.real;
Jet1Vec {
real: real.ln(),
dual: self.scaled_into(T::one() / real),
}
}
#[inline]
pub fn into_sqrt(self) -> Jet1Vec<T> {
let s = self.real.sqrt();
Jet1Vec {
real: s,
dual: self.scaled_into(T::from(0.5).unwrap() / s),
}
}
#[inline]
pub fn into_sin(self) -> Jet1Vec<T> {
let real = self.real;
Jet1Vec {
real: real.sin(),
dual: self.scaled_into(real.cos()),
}
}
#[inline]
pub fn into_cos(self) -> Jet1Vec<T> {
let real = self.real;
Jet1Vec {
real: real.cos(),
dual: self.scaled_into(-real.sin()),
}
}
#[inline]
pub fn into_tan(self) -> Jet1Vec<T> {
let t = self.real.tan();
let sec2 = T::one() + t * t;
Jet1Vec {
real: t,
dual: self.scaled_into(sec2),
}
}
#[inline]
pub fn into_tanh(self) -> Jet1Vec<T> {
let t = self.real.tanh();
Jet1Vec {
real: t,
dual: self.scaled_into(T::one() - t * t),
}
}
#[inline]
pub fn into_abs(self) -> Jet1Vec<T> {
let sign = if self.real >= T::zero() {
T::one()
} else {
-T::one()
};
Jet1Vec {
real: self.real.abs(),
dual: self.scaled_into(sign),
}
}
#[inline]
pub fn into_erf(self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::erf::<T>(v);
let g = T::from(std::f64::consts::FRAC_2_SQRT_PI).unwrap() * (-v * v).exp();
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
#[inline]
pub fn into_norm_cdf(self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::norm_cdf::<T>(v);
let g = crate::math::norm_pdf::<T>(v);
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
#[inline]
pub fn into_inv_norm_cdf(self) -> Jet1Vec<T> {
let v = self.real;
let r = crate::math::inv_norm_cdf::<T>(v);
let g = T::one() / crate::math::norm_pdf::<T>(r);
Jet1Vec {
real: r,
dual: self.scaled_into(g),
}
}
}
impl<'a, 'b, T: Passive> Add<&'b Jet1Vec<T>> for &'a Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(self, rhs: &'b Jet1Vec<T>) -> Jet1Vec<T> {
len_check(self, rhs);
Jet1Vec {
real: self.real + rhs.real,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(a, b)| *a + *b)
.collect(),
}
}
}
impl<T: Passive> Add for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(mut self, rhs: Jet1Vec<T>) -> Jet1Vec<T> {
self += &rhs;
self
}
}
impl<T: Passive> Add<&Jet1Vec<T>> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(mut self, rhs: &Jet1Vec<T>) -> Jet1Vec<T> {
self += rhs;
self
}
}
impl<T: Passive> Add<Jet1Vec<T>> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(self, mut rhs: Jet1Vec<T>) -> Jet1Vec<T> {
rhs += self;
rhs
}
}
impl<T: Passive> Add<T> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(self, rhs: T) -> Jet1Vec<T> {
Jet1Vec {
real: self.real + rhs,
dual: self.dual.clone(),
}
}
}
impl<T: Passive> Add<T> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn add(mut self, rhs: T) -> Jet1Vec<T> {
self.real += rhs;
self
}
}
impl<'a, 'b, T: Passive> Sub<&'b Jet1Vec<T>> for &'a Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(self, rhs: &'b Jet1Vec<T>) -> Jet1Vec<T> {
len_check(self, rhs);
Jet1Vec {
real: self.real - rhs.real,
dual: self
.dual
.iter()
.zip(&rhs.dual)
.map(|(a, b)| *a - *b)
.collect(),
}
}
}
impl<T: Passive> Sub for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(mut self, rhs: Jet1Vec<T>) -> Jet1Vec<T> {
self -= &rhs;
self
}
}
impl<T: Passive> Sub<&Jet1Vec<T>> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(mut self, rhs: &Jet1Vec<T>) -> Jet1Vec<T> {
self -= rhs;
self
}
}
impl<T: Passive> Sub<Jet1Vec<T>> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(self, mut rhs: Jet1Vec<T>) -> Jet1Vec<T> {
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<T: Passive> Sub<T> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(self, rhs: T) -> Jet1Vec<T> {
Jet1Vec {
real: self.real - rhs,
dual: self.dual.clone(),
}
}
}
impl<T: Passive> Sub<T> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn sub(mut self, rhs: T) -> Jet1Vec<T> {
self.real -= rhs;
self
}
}
impl<'a, 'b, T: Passive> Mul<&'b Jet1Vec<T>> for &'a Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(self, rhs: &'b Jet1Vec<T>) -> Jet1Vec<T> {
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<T: Passive> Mul for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(mut self, rhs: Jet1Vec<T>) -> Jet1Vec<T> {
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<T: Passive> Mul<&Jet1Vec<T>> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(mut self, rhs: &Jet1Vec<T>) -> Jet1Vec<T> {
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<T: Passive> Mul<Jet1Vec<T>> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(self, mut rhs: Jet1Vec<T>) -> Jet1Vec<T> {
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<T: Passive> Mul<T> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(self, rhs: T) -> Jet1Vec<T> {
Jet1Vec {
real: self.real * rhs,
dual: self.dual.iter().map(|&d| d * rhs).collect(),
}
}
}
impl<T: Passive> Mul<T> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn mul(mut self, rhs: T) -> Jet1Vec<T> {
self.real *= rhs;
for d in self.dual.iter_mut() {
*d *= rhs;
}
self
}
}
impl<'a, 'b, T: Passive> Div<&'b Jet1Vec<T>> for &'a Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(self, rhs: &'b Jet1Vec<T>) -> Jet1Vec<T> {
len_check(self, rhs);
let inv = T::one() / 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<T: Passive> Div for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(mut self, rhs: Jet1Vec<T>) -> Jet1Vec<T> {
len_check(&self, &rhs);
let inv = T::one() / 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<T: Passive> Div<&Jet1Vec<T>> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(mut self, rhs: &Jet1Vec<T>) -> Jet1Vec<T> {
len_check(&self, rhs);
let inv = T::one() / 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<T: Passive> Div<Jet1Vec<T>> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(self, rhs: Jet1Vec<T>) -> Jet1Vec<T> {
self / &rhs
}
}
impl<T: Passive> Div<T> for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(self, rhs: T) -> Jet1Vec<T> {
let inv = T::one() / rhs;
Jet1Vec {
real: self.real * inv,
dual: self.dual.iter().map(|&d| d * inv).collect(),
}
}
}
impl<T: Passive> Div<T> for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn div(mut self, rhs: T) -> Jet1Vec<T> {
let inv = T::one() / rhs;
self.real *= inv;
for d in self.dual.iter_mut() {
*d *= inv;
}
self
}
}
impl<T: Passive> Neg for &Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn neg(self) -> Jet1Vec<T> {
Jet1Vec {
real: -self.real,
dual: self.dual.iter().map(|&d| -d).collect(),
}
}
}
impl<T: Passive> Neg for Jet1Vec<T> {
type Output = Jet1Vec<T>;
#[inline]
fn neg(mut self) -> Jet1Vec<T> {
self.real = -self.real;
for d in self.dual.iter_mut() {
*d = -*d;
}
self
}
}
impl<T: Passive> AddAssign<&Jet1Vec<T>> for Jet1Vec<T> {
#[inline]
fn add_assign(&mut self, rhs: &Jet1Vec<T>) {
len_check(self, rhs);
self.real += rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a += b;
}
}
}
impl<T: Passive> AddAssign for Jet1Vec<T> {
#[inline]
fn add_assign(&mut self, rhs: Jet1Vec<T>) {
len_check(self, &rhs);
self.real += rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a += b;
}
}
}
impl<T: Passive> AddAssign<T> for Jet1Vec<T> {
#[inline]
fn add_assign(&mut self, rhs: T) {
self.real += rhs;
}
}
impl<T: Passive> SubAssign<&Jet1Vec<T>> for Jet1Vec<T> {
#[inline]
fn sub_assign(&mut self, rhs: &Jet1Vec<T>) {
len_check(self, rhs);
self.real -= rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a -= b;
}
}
}
impl<T: Passive> SubAssign for Jet1Vec<T> {
#[inline]
fn sub_assign(&mut self, rhs: Jet1Vec<T>) {
len_check(self, &rhs);
self.real -= rhs.real;
for (a, &b) in self.dual.iter_mut().zip(&rhs.dual) {
*a -= b;
}
}
}
impl<T: Passive> SubAssign<T> for Jet1Vec<T> {
#[inline]
fn sub_assign(&mut self, rhs: T) {
self.real -= rhs;
}
}
impl<T: Passive> MulAssign<&Jet1Vec<T>> for Jet1Vec<T> {
#[inline]
fn mul_assign(&mut self, rhs: &Jet1Vec<T>) {
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<T: Passive> MulAssign<T> for Jet1Vec<T> {
#[inline]
fn mul_assign(&mut self, rhs: T) {
self.real *= rhs;
for d in self.dual.iter_mut() {
*d *= rhs;
}
}
}
impl<T: Passive> DivAssign<&Jet1Vec<T>> for Jet1Vec<T> {
#[inline]
fn div_assign(&mut self, rhs: &Jet1Vec<T>) {
len_check(self, rhs);
let inv = T::one() / 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<T: Passive> DivAssign<T> for Jet1Vec<T> {
#[inline]
fn div_assign(&mut self, rhs: T) {
let inv = T::one() / rhs;
self.real *= inv;
for d in self.dual.iter_mut() {
*d *= inv;
}
}
}
impl<T: Passive> PartialEq for Jet1Vec<T> {
fn eq(&self, other: &Self) -> bool {
self.real == other.real
}
}
impl<T: Passive> PartialEq<T> for Jet1Vec<T> {
fn eq(&self, other: &T) -> bool {
self.real == *other
}
}
impl<T: Passive> PartialOrd for Jet1Vec<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.real.partial_cmp(&other.real)
}
}
impl<T: Passive> PartialOrd<T> for Jet1Vec<T> {
fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
self.real.partial_cmp(other)
}
}
impl<T: Passive> fmt::Display for Jet1Vec<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.real)
}
}
macro_rules! impl_scalar_lhs_jet1vec_binop {
($scalar:ty) => {
impl Add<Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn add(self, rhs: Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
rhs + self
}
}
impl Add<&Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn add(self, rhs: &Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
rhs + self
}
}
impl Sub<Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn sub(self, mut rhs: Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
rhs.real = self - rhs.real;
for d in rhs.dual.iter_mut() {
*d = -*d;
}
rhs
}
}
impl Sub<&Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn sub(self, rhs: &Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
Jet1Vec {
real: self - rhs.real,
dual: rhs.dual.iter().map(|&d| -d).collect(),
}
}
}
impl Mul<Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn mul(self, rhs: Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
rhs * self
}
}
impl Mul<&Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn mul(self, rhs: &Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
rhs * self
}
}
impl Div<Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn div(self, mut rhs: Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
let inv = 1.0 as $scalar / rhs.real;
let neg_scale = -self * inv * inv;
rhs.real = self * inv;
for d in rhs.dual.iter_mut() {
*d *= neg_scale;
}
rhs
}
}
impl Div<&Jet1Vec<$scalar>> for $scalar {
type Output = Jet1Vec<$scalar>;
#[inline]
fn div(self, rhs: &Jet1Vec<$scalar>) -> Jet1Vec<$scalar> {
let inv = 1.0 as $scalar / rhs.real;
let neg_scale = -self * inv * inv;
Jet1Vec {
real: self * inv,
dual: rhs.dual.iter().map(|&d| d * neg_scale).collect(),
}
}
}
};
}
impl_scalar_lhs_jet1vec_binop!(f64);
impl_scalar_lhs_jet1vec_binop!(f32);
#[derive(Clone, Debug)]
pub struct NamedJet1Vec<T: Passive = f64> {
pub(crate) inner: Jet1Vec<T>,
#[cfg(debug_assertions)]
pub(crate) gen_id: u64,
}
impl<T: Passive> NamedJet1Vec<T> {
#[inline]
pub(crate) fn __from_inner(inner: Jet1Vec<T>) -> Self {
Self {
inner,
#[cfg(debug_assertions)]
gen_id: crate::forward_tape::current_gen(),
}
}
#[inline]
pub fn real(&self) -> T {
self.inner.real
}
pub fn partial(&self, name: &str) -> T {
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, T)> {
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<T> {
&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: T) -> 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<T: Passive> fmt::Display for NamedJet1Vec<T> {
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<T: Passive> ::core::ops::$trait<NamedJet1Vec<T>> for NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: NamedJet1Vec<T>) -> NamedJet1Vec<T> {
#[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<T: Passive> ::core::ops::$trait<&NamedJet1Vec<T>> for &NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: &NamedJet1Vec<T>) -> NamedJet1Vec<T> {
#[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<T: Passive> ::core::ops::$trait<&NamedJet1Vec<T>> for NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: &NamedJet1Vec<T>) -> NamedJet1Vec<T> {
#[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<T: Passive> ::core::ops::$trait<NamedJet1Vec<T>> for &NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: NamedJet1Vec<T>) -> NamedJet1Vec<T> {
#[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<T: Passive> ::core::ops::$trait<T> for NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: T) -> NamedJet1Vec<T> {
NamedJet1Vec {
inner: self.inner $op rhs,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl<T: Passive> ::core::ops::$trait<T> for &NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn $method(self, rhs: T) -> NamedJet1Vec<T> {
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<T: Passive> ::core::ops::AddAssign<NamedJet1Vec<T>> for NamedJet1Vec<T> {
#[inline]
fn add_assign(&mut self, rhs: NamedJet1Vec<T>) {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
self.inner += rhs.inner;
}
}
impl<T: Passive> ::core::ops::AddAssign<&NamedJet1Vec<T>> for NamedJet1Vec<T> {
#[inline]
fn add_assign(&mut self, rhs: &NamedJet1Vec<T>) {
#[cfg(debug_assertions)]
crate::forward_tape::check_gen(self.gen_id, rhs.gen_id);
self.inner += &rhs.inner;
}
}
impl<T: Passive> ::core::ops::Neg for NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn neg(self) -> NamedJet1Vec<T> {
NamedJet1Vec {
inner: -self.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
impl<T: Passive> ::core::ops::Neg for &NamedJet1Vec<T> {
type Output = NamedJet1Vec<T>;
#[inline]
fn neg(self) -> NamedJet1Vec<T> {
NamedJet1Vec {
inner: -&self.inner,
#[cfg(debug_assertions)]
gen_id: self.gen_id,
}
}
}
macro_rules! __named_dual_scalar_lhs {
($scalar:ty) => {
impl ::core::ops::Add<NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn add(self, rhs: NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self + rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Add<&NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn add(self, rhs: &NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self + &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Sub<NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn sub(self, rhs: NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self - rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Sub<&NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn sub(self, rhs: &NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self - &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Mul<NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn mul(self, rhs: NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self * rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Mul<&NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn mul(self, rhs: &NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self * &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Div<NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn div(self, rhs: NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self / rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
impl ::core::ops::Div<&NamedJet1Vec<$scalar>> for $scalar {
type Output = NamedJet1Vec<$scalar>;
#[inline]
fn div(self, rhs: &NamedJet1Vec<$scalar>) -> NamedJet1Vec<$scalar> {
NamedJet1Vec {
inner: self / &rhs.inner,
#[cfg(debug_assertions)]
gen_id: rhs.gen_id,
}
}
}
};
}
__named_dual_scalar_lhs!(f64);
__named_dual_scalar_lhs!(f32);