///|
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: T::zero() }
}
///|
pub fn[T : One] Dual::variable(value : T) -> Dual[T] {
{ value, tangent: T::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(T::zero())
}
///|
pub impl[T : One + Zero] One for Dual[T] with fn one() -> Dual[T] {
Dual::constant(T::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]
///|
pub impl[T : NatHomomorphism + Zero] NatHomomorphism for Dual[T] with fn[
S : Nat,
] from_nat(value : S) -> Dual[T] {
Dual::constant(T::from_nat(value))
}
///|
pub impl[T : IntegralHomomorphism + Zero] IntegralHomomorphism for Dual[T] with fn[
S : Integral,
] from_integral(value : S) -> Dual[T] {
Dual::constant(T::from_integral(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 + IntegralHomomorphism + 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 = T::from_integral(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 + IntegralHomomorphism + Mul + Div] Dual::sqrt(
self : Dual[T],
) -> Dual[T] {
let root = Sqrt::sqrt(self.value)
let two : T = T::from_integral(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 + IntegralHomomorphism + Mul] Dual::exp2(
self : Dual[T],
) -> Dual[T] {
let value = Exponential::exp2(self.value)
let two : T = T::from_integral(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 + IntegralHomomorphism + Mul + Div] Dual::log2(
self : Dual[T],
) -> Dual[T] {
let two : T = T::from_integral(2)
Dual::new(
Logarithmic::log2(self.value),
self.tangent / (self.value * Logarithmic::ln(two)),
)
}
///|
pub fn[T : Logarithmic + IntegralHomomorphism + Mul + Div] Dual::log10(
self : Dual[T],
) -> Dual[T] {
let ten : T = T::from_integral(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 + IntegralHomomorphism + Mul + Div] Sqrt for Dual[T] with fn sqrt(
self,
) {
self.sqrt()
}
///|
pub impl[T : SqrtChecked + DivChecked + IntegralHomomorphism + Mul] SqrtChecked for Dual[
T,
] with fn sqrt_checked(self, ctx) {
self.sqrt_checked(ctx)
}
///|
pub impl[T : Exponential + Logarithmic + IntegralHomomorphism + Mul] Exponential for Dual[
T,
] with fn exp(self) {
self.exp()
}
///|
pub impl[T : Exponential + Logarithmic + IntegralHomomorphism + Mul] Exponential for Dual[
T,
] with fn exp2(self) {
self.exp2()
}
///|
pub impl[T : Logarithmic + IntegralHomomorphism + Mul + Div] Logarithmic for Dual[
T,
] with fn ln(self) {
self.ln()
}
///|
pub impl[T : Logarithmic + IntegralHomomorphism + Mul + Div] Logarithmic for Dual[
T,
] with fn log2(self) {
self.log2()
}
///|
pub impl[T : Logarithmic + IntegralHomomorphism + 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())
}