1use crate::dual::dual::{Dual, Dual2};
2use crate::dual::enums::Number;
3use auto_ops::impl_op_ex;
4use num_traits::Pow;
5use std::sync::Arc;
6
7impl_op_ex!(/ |a: &Dual, b: &f64| -> Dual { Dual {vars: Arc::clone(&a.vars), real: a.real / b, dual: (1_f64/b) * &a.dual} });
8impl_op_ex!(/ |a: &f64, b: &Dual| -> Dual { a * b.clone().pow(-1.0) });
9impl_op_ex!(/ |a: &Dual2, b: &f64| -> Dual2 {
10 Dual2 {vars: Arc::clone(&a.vars), real: a.real / b, dual: (1_f64/b) * &a.dual, dual2: (1_f64/b) * &a.dual2}
11});
12impl_op_ex!(/ |a: &f64, b: &Dual2| -> Dual2 { a * b.clone().pow(-1.0) });
13
14impl_op_ex!(/ |a: &Dual, b: &Dual| -> Dual {
16 let b_ = Dual {real: 1.0 / b.real, vars: Arc::clone(&b.vars), dual: -1.0 / (b.real * b.real) * &b.dual};
17 a * b_
18});
19
20impl_op_ex!(/ |a: &Dual2, b: &Dual2| -> Dual2 { a * b.clone().pow(-1.0) });
22
23impl_op_ex!(/ |a: &Number, b: &Number| -> Number {
25 match (a,b) {
26 (Number::F64(f), Number::F64(f2)) => Number::F64(f / f2),
27 (Number::F64(f), Number::Dual(d2)) => Number::Dual(f / d2),
28 (Number::F64(f), Number::Dual2(d2)) => Number::Dual2(f / d2),
29 (Number::Dual(d), Number::F64(f2)) => Number::Dual(d / f2),
30 (Number::Dual(d), Number::Dual(d2)) => Number::Dual(d / d2),
31 (Number::Dual(_), Number::Dual2(_)) => panic!("Cannot mix dual types: Dual / Dual2"),
32 (Number::Dual2(d), Number::F64(f2)) => Number::Dual2(d / f2),
33 (Number::Dual2(_), Number::Dual(_)) => panic!("Cannot mix dual types: Dual2 / Dual"),
34 (Number::Dual2(d), Number::Dual2(d2)) => Number::Dual2(d / d2),
35 }
36});
37
38impl_op_ex!(/ |a: &Number, b: &f64| -> Number {
40 match a {
41 Number::F64(f) => Number::F64(f / b),
42 Number::Dual(d) => Number::Dual(d / b),
43 Number::Dual2(d) => Number::Dual2(d / b),
44 }
45});
46
47impl_op_ex!(/ |a: &f64, b: &Number| -> Number {
49 match b {
50 Number::F64(f) => Number::F64(a / f),
51 Number::Dual(d) => Number::Dual(a / d),
52 Number::Dual2(d) => Number::Dual2(a / d),
53 }
54});
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn div_f64() {
62 let d1 = Dual::try_new(
63 1.0,
64 vec!["v0".to_string(), "v1".to_string()],
65 vec![1.0, 2.0],
66 )
67 .unwrap();
68 let result = d1 / 2.0;
69 let expected = Dual::try_new(
70 0.5,
71 vec!["v0".to_string(), "v1".to_string()],
72 vec![0.5, 1.0],
73 )
74 .unwrap();
75 assert_eq!(result, expected)
76 }
77
78 #[test]
79 fn f64_div() {
80 let d1 = Dual::try_new(
81 1.0,
82 vec!["v0".to_string(), "v1".to_string()],
83 vec![1.0, 2.0],
84 )
85 .unwrap();
86 let result = 2.0 / d1.clone();
87 let expected = Dual::new(2.0, vec![]) / d1;
88 assert_eq!(result, expected)
89 }
90
91 #[test]
92 fn div() {
93 let d1 = Dual::try_new(
94 1.0,
95 vec!["v0".to_string(), "v1".to_string()],
96 vec![1.0, 2.0],
97 )
98 .unwrap();
99 let d2 = Dual::try_new(
100 2.0,
101 vec!["v0".to_string(), "v2".to_string()],
102 vec![0.0, 3.0],
103 )
104 .unwrap();
105 let expected = Dual::try_new(
106 0.5,
107 vec!["v0".to_string(), "v1".to_string(), "v2".to_string()],
108 vec![0.5, 1.0, -0.75],
109 )
110 .unwrap();
111 let result = d1 / d2;
112 assert_eq!(result, expected)
113 }
114
115 #[test]
116 fn div_f64_2() {
117 let d1 = Dual2::try_new(
118 1.0,
119 vec!["v0".to_string(), "v1".to_string()],
120 vec![1.0, 2.0],
121 Vec::new(),
122 )
123 .unwrap();
124 let result = d1 / 2.0;
125 let expected = Dual2::try_new(
126 0.5,
127 vec!["v0".to_string(), "v1".to_string()],
128 vec![0.5, 1.0],
129 Vec::new(),
130 )
131 .unwrap();
132 assert_eq!(result, expected)
133 }
134
135 #[test]
136 fn f64_div2() {
137 let d1 = Dual2::try_new(
138 1.0,
139 vec!["v0".to_string(), "v1".to_string()],
140 vec![1.0, 2.0],
141 Vec::new(),
142 )
143 .unwrap();
144 let result = 2.0 / d1.clone();
145 let expected = Dual2::new(2.0, vec![]) / d1;
146 assert_eq!(result, expected)
147 }
148
149 #[test]
150 fn div2() {
151 let d1 = Dual2::try_new(
152 1.0,
153 vec!["v0".to_string(), "v1".to_string()],
154 vec![1.0, 2.0],
155 Vec::new(),
156 )
157 .unwrap();
158 let d2 = Dual2::try_new(
159 2.0,
160 vec!["v0".to_string(), "v2".to_string()],
161 vec![0.0, 3.0],
162 Vec::new(),
163 )
164 .unwrap();
165 let expected = Dual2::try_new(
166 0.5,
167 vec!["v0".to_string(), "v1".to_string(), "v2".to_string()],
168 vec![0.5, 1.0, -0.75],
169 vec![0., 0., -0.375, 0., 0., -0.75, -0.375, -0.75, 1.125],
170 )
171 .unwrap();
172 let result = d1 / d2;
173 assert_eq!(result, expected)
174 }
175
176 #[test]
177 fn test_enum() {
178 let f = Number::F64(2.0);
179 let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
180 assert_eq!(
181 &f / &d,
182 Number::Dual(
183 Dual::try_new(2.0 / 3.0, vec!["x".to_string()], vec![-2.0 / 9.0]).unwrap()
184 )
185 );
186
187 assert_eq!(
188 &d / &d,
189 Number::Dual(Dual::try_new(1.0, vec!["x".to_string()], vec![0.0]).unwrap())
190 );
191 }
192
193 #[test]
194 #[should_panic]
195 fn test_enum_panic() {
196 let d = Number::Dual2(Dual2::new(2.0, vec!["y".to_string()]));
197 let d2 = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
198 let _ = d / d2;
199 }
200
201 #[test]
202 fn test_enum_f64() {
203 let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
204 let res = 2.0_f64 / d;
205 assert_eq!(
206 res,
207 Number::Dual(2.0 / Dual::new(3.0, vec!["x".to_string()]))
208 );
209
210 let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
211 let res = d / 2.0_f64;
212 assert_eq!(
213 res,
214 Number::Dual(Dual::new(3.0, vec!["x".to_string()]) / 2.0)
215 );
216 }
217}