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 Dual2Vec<T: Scalar, D: Dim>
14where
15 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
16{
17 pub re: T,
19 pub v1: Derivative<T, U1, D>,
21 pub v2: Derivative<T, D, D>,
23}
24
25impl<T: Scalar + Copy, const N: usize> Copy for Dual2Vec<T, Const<N>> {}
26
27#[cfg(feature = "ndarray")]
28impl<T: DualNum, D: Dim> ndarray::ScalarOperand for Dual2Vec<T, D> where
29 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>
30{
31}
32
33pub type Dual2SVec<T, const N: usize> = Dual2Vec<T, Const<N>>;
34pub type Dual2DVec<T> = Dual2Vec<T, Dyn>;
35pub type Dual2Vec32<D> = Dual2Vec<f32, D>;
36pub type Dual2Vec64<D> = Dual2Vec<f64, D>;
37pub type Dual2SVec32<const N: usize> = Dual2Vec<f32, Const<N>>;
38pub type Dual2SVec64<const N: usize> = Dual2Vec<f64, Const<N>>;
39pub type Dual2DVec32 = Dual2Vec<f32, Dyn>;
40pub type Dual2DVec64 = Dual2Vec<f64, Dyn>;
41
42impl<T: DualNum, D: Dim> Dual2Vec<T, D>
43where
44 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
45{
46 #[inline]
48 pub fn new(re: T, v1: Derivative<T, U1, D>, v2: Derivative<T, D, D>) -> Self {
49 Self { re, v1, v2 }
50 }
51}
52
53impl<T: DualNum, const N: usize> Dual2SVec<T, N> {
54 #[inline]
70 pub fn derivative(mut self, index: usize) -> Self {
71 self.v1 = Derivative::derivative_generic(U1, Const::<N>, index);
72 self
73 }
74}
75
76impl<T: DualNum> Dual2DVec<T> {
77 #[inline]
93 pub fn derivative(mut self, variables: usize, index: usize) -> Self {
94 self.v1 = Derivative::derivative_generic(U1, Dyn(variables), index);
95 self
96 }
97}
98
99impl<T: DualNum, D: Dim> Dual2Vec<T, D>
100where
101 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
102{
103 #[inline]
105 pub fn from_re(re: T) -> Self {
106 Self::new(re, Derivative::none(), Derivative::none())
107 }
108}
109
110impl<T: DualNum, D: Dim> Dual2Vec<T, D>
112where
113 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
114{
115 #[inline]
116 fn chain_rule(&self, f0: T, f1: T, f2: T) -> Self {
117 Self::new(
118 f0,
119 &self.v1 * f1.clone(),
120 &self.v2 * f1 + self.v1.tr_mul(&self.v1) * f2,
121 )
122 }
123}
124
125impl<T: DualNum, D: Dim> Mul<&Dual2Vec<T, D>> for &Dual2Vec<T, D>
127where
128 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
129{
130 type Output = Dual2Vec<T, D>;
131 #[inline]
132 fn mul(self, other: &Dual2Vec<T, D>) -> Dual2Vec<T, D> {
133 Dual2Vec::new(
134 self.re.clone() * other.re.clone(),
135 &other.v1 * self.re.clone() + &self.v1 * other.re.clone(),
136 &other.v2 * self.re.clone()
137 + self.v1.tr_mul(&other.v1)
138 + other.v1.tr_mul(&self.v1)
139 + &self.v2 * other.re.clone(),
140 )
141 }
142}
143
144impl<T: DualNum, D: Dim> Div<&Dual2Vec<T, D>> for &Dual2Vec<T, D>
146where
147 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
148{
149 type Output = Dual2Vec<T, D>;
150 #[inline]
151 fn div(self, other: &Dual2Vec<T, D>) -> Dual2Vec<T, D> {
152 let inv = other.re.recip();
153 let inv2 = inv.clone() * inv.clone();
154 Dual2Vec::new(
155 self.re.clone() * inv.clone(),
156 (&self.v1 * other.re.clone() - &other.v1 * self.re.clone()) * inv2.clone(),
157 &self.v2 * inv.clone()
158 - (&other.v2 * self.re.clone()
159 + self.v1.tr_mul(&other.v1)
160 + other.v1.tr_mul(&self.v1))
161 * inv2.clone()
162 + other.v1.tr_mul(&other.v1)
163 * ((T::one() + T::one()) * self.re.clone() * inv2 * inv),
164 )
165 }
166}
167
168impl<T: DualNum, D: Dim> fmt::Display for Dual2Vec<T, D>
170where
171 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
172{
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 write!(f, "{}", self.re)?;
175 self.v1.fmt(f, "ε1")?;
176 self.v2.fmt(f, "ε1²")
177 }
178}
179
180impl_second_derivatives!(Dual2Vec, [v1, v2], [D], [U1, D], [D, D]);
181impl_dual!(Dual2Vec, [v1, v2], [D], [U1, D], [D, D]);
182impl_nalgebra!(Dual2Vec, [v1, v2], [D], [U1, D], [D, D]);