1use crate::{Derivative, DualNum, DualNumFloat, DualStruct};
2use nalgebra::allocator::Allocator;
3use nalgebra::*;
4use num_traits::{FloatConst, FromPrimitive, Inv, Num, One, Signed, Zero};
5use std::fmt;
6use std::iter::{Product, Sum};
7use std::ops::{
8 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
9};
10
11#[derive(Clone, Debug)]
13pub struct DualVec<T: Scalar, D: Dim>
14where
15 DefaultAllocator: Allocator<D>,
16{
17 pub re: T,
19 pub eps: Derivative<T, D, U1>,
21}
22
23#[cfg(feature = "ndarray")]
24impl<T: Scalar, D: Dim> ndarray::ScalarOperand for DualVec<T, D> where DefaultAllocator: Allocator<D>
25{}
26
27impl<T: Scalar + Copy, const N: usize> Copy for DualVec<T, Const<N>> {}
28
29pub type DualSVec<D, const N: usize> = DualVec<D, Const<N>>;
30pub type DualDVec<D> = DualVec<D, Dyn>;
31pub type DualVec32<D> = DualVec<f32, D>;
32pub type DualVec64<D> = DualVec<f64, D>;
33pub type DualSVec32<const N: usize> = DualVec<f32, Const<N>>;
34pub type DualSVec64<const N: usize> = DualVec<f64, Const<N>>;
35pub type DualDVec32 = DualVec<f32, Dyn>;
36pub type DualDVec64 = DualVec<f64, Dyn>;
37
38impl<T: DualNum, D: Dim> DualVec<T, D>
39where
40 DefaultAllocator: Allocator<D>,
41{
42 #[inline]
44 pub fn new(re: T, eps: Derivative<T, D, U1>) -> Self {
45 Self { re, eps }
46 }
47}
48
49impl<T: DualNum, const N: usize> DualSVec<T, N> {
50 #[inline]
65 pub fn derivative(mut self, index: usize) -> Self {
66 self.eps = Derivative::derivative_generic(Const::<N>, U1, index);
67 self
68 }
69}
70
71impl<T: DualNum> DualDVec<T> {
72 #[inline]
87 pub fn derivative(mut self, variables: usize, index: usize) -> Self {
88 self.eps = Derivative::derivative_generic(Dyn(variables), U1, index);
89 self
90 }
91}
92
93impl<T: DualNum, D: Dim> DualVec<T, D>
94where
95 DefaultAllocator: Allocator<D>,
96{
97 #[inline]
99 pub fn from_re(re: T) -> Self {
100 Self::new(re, Derivative::none())
101 }
102}
103
104impl<T: DualNum, D: Dim> DualVec<T, D>
106where
107 DefaultAllocator: Allocator<D>,
108{
109 #[inline]
110 fn chain_rule(&self, f0: T, f1: T) -> Self {
111 Self::new(f0, &self.eps * f1)
112 }
113}
114
115impl<T: DualNum, D: Dim> Mul<&DualVec<T, D>> for &DualVec<T, D>
117where
118 DefaultAllocator: Allocator<D>,
119{
120 type Output = DualVec<T, D>;
121 #[inline]
122 fn mul(self, other: &DualVec<T, D>) -> Self::Output {
123 DualVec::new(
124 self.re.clone() * other.re.clone(),
125 &self.eps * other.re.clone() + &other.eps * self.re.clone(),
126 )
127 }
128}
129
130impl<T: DualNum, D: Dim> Div<&DualVec<T, D>> for &DualVec<T, D>
132where
133 DefaultAllocator: Allocator<D>,
134{
135 type Output = DualVec<T, D>;
136 #[inline]
137 fn div(self, other: &DualVec<T, D>) -> DualVec<T, D> {
138 let inv = other.re.recip();
139 DualVec::new(
140 self.re.clone() * inv.clone(),
141 (&self.eps * other.re.clone() - &other.eps * self.re.clone()) * inv.clone() * inv,
142 )
143 }
144}
145
146impl<T: DualNum, D: Dim> fmt::Display for DualVec<T, D>
148where
149 DefaultAllocator: Allocator<D>,
150{
151 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152 write!(f, "{}", self.re)?;
153 self.eps.fmt(f, "ε")
154 }
155}
156
157impl_first_derivatives!(DualVec, [eps], [D], [D]);
158impl_dual!(DualVec, [eps], [D], [D]);
159impl_nalgebra!(DualVec, [eps], [D], [D]);