///|
pub struct Dual[T] {
value : T
tangent : T
} derive(Eq, Debug)
///|
pub fn[T] Dual::new(value : T, tangent : T) -> Dual[T] {
{ value, tangent, }
}
///|
pub fn[T : Zero] Dual::constant(value : T) -> Dual[T] {
{ value, tangent: Zero::zero(), }
}
///|
pub fn[T : One] Dual::variable(value : T) -> Dual[T] {
{ value, tangent: One::one(), }
}
///|
pub fn[T] Dual::value(self : Dual[T]) -> T {
self.value
}
///|
pub fn[T] Dual::tangent(self : Dual[T]) -> T {
self.tangent
}
///|
pub impl[T : Zero] Zero for Dual[T] with fn zero() -> Dual[T] {
Dual::constant(Zero::zero())
}
///|
pub impl[T : One + Zero] One for Dual[T] with fn one() -> Dual[T] {
Dual::constant(One::one())
}
///|
pub impl[T : Add] Add for Dual[T] with fn add(self, other) {
Dual::new(self.value + other.value, self.tangent + other.tangent)
}
///|
pub impl[T : Sub] Sub for Dual[T] with fn sub(self, other) {
Dual::new(self.value - other.value, self.tangent - other.tangent)
}
///|
pub impl[T : Neg] Neg for Dual[T] with fn neg(self) {
Dual::new(-self.value, -self.tangent)
}
///|
pub impl[T : Add + Mul] Mul for Dual[T] with fn mul(self, other) {
Dual::new(
self.value * other.value,
self.value * other.tangent + other.value * self.tangent,
)
}
///|
pub impl[T : Div + Sub + Mul] Div for Dual[T] with fn div(self, other) {
let denominator = other.value * other.value
Dual::new(
self.value / other.value,
(self.tangent * other.value - self.value * other.tangent) / denominator,
)
}
///|
pub impl[T : AddMonoid] AddMonoid for Dual[T]
///|
pub impl[T : Semiring] MulMonoid for Dual[T]
///|
pub impl[T : AddGroup] AddGroup for Dual[T]
///|
pub impl[T : Semiring] Semiring for Dual[T]
///|
pub impl[T : Ring] Ring for Dual[T]
///|
/// The canonical map ℕ -> `Dual[T]`: a constant, so the tangent is zero.
pub impl[T : FromNat + Zero] FromNat for Dual[T] with fn from_natural(value) {
Dual::constant(FromNat::from_natural(value))
}
///|
/// The canonical map ℤ -> `Dual[T]`: a constant, so the tangent is zero.
pub impl[T : FromInteger + Zero] FromInteger for Dual[T] with fn from_integer(
value,
) {
Dual::constant(FromInteger::from_integer(value))
}
///|
pub impl[T : DivChecked + Sub + Mul] DivChecked for Dual[T] with fn div_checked(
self,
other,
ctx,
) -> Result[Dual[T], ArithmeticError] {
match DivChecked::div_checked(self.value, other.value, ctx) {
Err(err) => Err(err)
Ok(value) =>
match
DivChecked::div_checked(
self.tangent * other.value - self.value * other.tangent,
other.value * other.value,
ctx,
) {
Err(err) => Err(err)
Ok(tangent) => Ok(Dual::new(value, tangent))
}
}
}
///|
pub fn[T : SqrtChecked + DivChecked + FromInteger + Mul] Dual::sqrt_checked(
self : Dual[T],
ctx : ArithmeticContext,
) -> Result[Dual[T], ArithmeticError] {
match SqrtChecked::sqrt_checked(self.value, ctx) {
Err(err) => Err(err)
Ok(root) => {
let two : T = lift_to(2)
match DivChecked::div_checked(self.tangent, two * root, ctx) {
Err(err) => Err(err)
Ok(tangent) => Ok(Dual::new(root, tangent))
}
}
}
}
///|
pub fn[T : Sqrt + FromInteger + Mul + Div] Dual::sqrt(
self : Dual[T],
) -> Dual[T] {
let root = Sqrt::sqrt(self.value)
let two : T = lift_to(2)
Dual::new(root, self.tangent / (two * root))
}
///|
pub fn[T : Exponential + Mul] Dual::exp(self : Dual[T]) -> Dual[T] {
let value = Exponential::exp(self.value)
Dual::new(value, self.tangent * value)
}
///|
pub fn[T : Exponential + Logarithmic + FromInteger + Mul] Dual::exp2(
self : Dual[T],
) -> Dual[T] {
let value = Exponential::exp2(self.value)
let two : T = lift_to(2)
Dual::new(value, self.tangent * value * Logarithmic::ln(two))
}
///|
pub fn[T : Logarithmic + Div] Dual::ln(self : Dual[T]) -> Dual[T] {
Dual::new(Logarithmic::ln(self.value), self.tangent / self.value)
}
///|
pub fn[T : Logarithmic + FromInteger + Mul + Div] Dual::log2(
self : Dual[T],
) -> Dual[T] {
let two : T = lift_to(2)
Dual::new(
Logarithmic::log2(self.value),
self.tangent / (self.value * Logarithmic::ln(two)),
)
}
///|
pub fn[T : Logarithmic + FromInteger + Mul + Div] Dual::log10(
self : Dual[T],
) -> Dual[T] {
let ten : T = lift_to(10)
Dual::new(
Logarithmic::log10(self.value),
self.tangent / (self.value * Logarithmic::ln(ten)),
)
}
///|
pub fn[T : Trigonometric + Mul] Dual::sin(self : Dual[T]) -> Dual[T] {
Dual::new(
Trigonometric::sin(self.value),
self.tangent * Trigonometric::cos(self.value),
)
}
///|
pub fn[T : Trigonometric + Mul + Neg] Dual::cos(self : Dual[T]) -> Dual[T] {
Dual::new(
Trigonometric::cos(self.value),
-(self.tangent * Trigonometric::sin(self.value)),
)
}
///|
pub fn[T : Trigonometric + Mul + Div] Dual::tan(self : Dual[T]) -> Dual[T] {
let c = Trigonometric::cos(self.value)
Dual::new(Trigonometric::tan(self.value), self.tangent / (c * c))
}
///|
pub impl[T : Sqrt + FromInteger + Mul + Div] Sqrt for Dual[T] with fn sqrt(self) {
self.sqrt()
}
///|
pub impl[T : SqrtChecked + DivChecked + FromInteger + Mul] SqrtChecked for Dual[
T,
] with fn sqrt_checked(self, ctx) {
self.sqrt_checked(ctx)
}
///|
pub impl[T : Exponential + Logarithmic + FromInteger + Mul] Exponential for Dual[
T,
] with fn exp(self) {
self.exp()
}
///|
pub impl[T : Exponential + Logarithmic + FromInteger + Mul] Exponential for Dual[
T,
] with fn exp2(self) {
self.exp2()
}
///|
pub impl[T : Logarithmic + FromInteger + Mul + Div] Logarithmic for Dual[T] with fn ln(
self,
) {
self.ln()
}
///|
pub impl[T : Logarithmic + FromInteger + Mul + Div] Logarithmic for Dual[T] with fn log2(
self,
) {
self.log2()
}
///|
pub impl[T : Logarithmic + FromInteger + Mul + Div] Logarithmic for Dual[T] with fn log10(
self,
) {
self.log10()
}
///|
pub impl[T : Trigonometric + Mul + Neg + Div] Trigonometric for Dual[T] with fn sin(
self,
) {
self.sin()
}
///|
pub impl[T : Trigonometric + Mul + Neg + Div] Trigonometric for Dual[T] with fn cos(
self,
) {
self.cos()
}
///|
pub impl[T : Trigonometric + Mul + Neg + Div] Trigonometric for Dual[T] with fn tan(
self,
) {
self.tan()
}
///|
pub impl[T : Constants + Zero] Constants for Dual[T] with fn pi() {
Dual::constant(Constants::pi())
}
///|
pub impl[T : Constants + Zero] Constants for Dual[T] with fn tau() {
Dual::constant(Constants::tau())
}
///|
pub impl[T : Constants + Zero] Constants for Dual[T] with fn e() {
Dual::constant(Constants::e())
}