rateslib/dual/dual_ops/
div.rs

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
14// impl Div for Dual
15impl_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
20// impl Div for Dual2
21impl_op_ex!(/ |a: &Dual2, b: &Dual2| -> Dual2 { a * b.clone().pow(-1.0) });
22
23// Div for Number
24impl_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
38// Div for Number
39impl_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
47// Div for Number
48impl_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}