rateslib/dual/dual_ops/
neg.rs

1use crate::dual::dual::{Dual, Dual2};
2use crate::dual::enums::Number;
3use auto_ops::impl_op;
4use std::sync::Arc;
5
6impl_op!(-|a: Dual| -> Dual {
7    Dual {
8        vars: a.vars,
9        real: -a.real,
10        dual: -a.dual,
11    }
12});
13impl_op!(-|a: &Dual| -> Dual {
14    Dual {
15        vars: Arc::clone(&a.vars),
16        real: -a.real,
17        dual: &a.dual * -1.0,
18    }
19});
20
21impl_op!(-|a: Dual2| -> Dual2 {
22    Dual2 {
23        vars: a.vars,
24        real: -a.real,
25        dual: -a.dual,
26        dual2: -a.dual2,
27    }
28});
29
30impl_op!(-|a: &Dual2| -> Dual2 {
31    Dual2 {
32        vars: Arc::clone(&a.vars),
33        real: -a.real,
34        dual: &a.dual * -1.0,
35        dual2: &a.dual2 * -1.0,
36    }
37});
38
39// Neg for Number
40impl_op!(-|a: &Number| -> Number {
41    match a {
42        Number::F64(f) => Number::F64(-f),
43        Number::Dual(d) => Number::Dual(-d),
44        Number::Dual2(d) => Number::Dual2(-d),
45    }
46});
47
48// Neg for Number
49impl_op!(-|a: Number| -> Number {
50    match a {
51        Number::F64(f) => Number::F64(-f),
52        Number::Dual(d) => Number::Dual(-d),
53        Number::Dual2(d) => Number::Dual2(-d),
54    }
55});
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use ndarray::Array1;
61
62    #[test]
63    fn negate() {
64        let d = Dual::try_new(
65            2.3,
66            Vec::from([String::from("a"), String::from("b")]),
67            Vec::from([2., -1.4]),
68        )
69        .unwrap();
70        let d2 = -d.clone();
71        assert!(d2.real == -2.3);
72        assert!(Arc::ptr_eq(&d.vars, &d2.vars));
73        assert!(d2.dual[0] == -2.0);
74        assert!(d2.dual[1] == 1.4);
75    }
76
77    #[test]
78    fn neg_ref() {
79        let d1 =
80            Dual::try_new(2.5, vec!["x".to_string(), "y".to_string()], vec![1.1, 2.2]).unwrap();
81        let d2 = -&d1;
82        assert_eq!(d2.real, -2.5);
83        assert_eq!(d2.dual, Array1::from_vec(vec![-1.1, -2.2]));
84    }
85
86    #[test]
87    fn negate2() {
88        let d = Dual2::try_new(
89            2.3,
90            Vec::from([String::from("a"), String::from("b")]),
91            Vec::from([2., -1.4]),
92            Vec::from([1.0, -1.0, -1.0, 2.0]),
93        )
94        .unwrap();
95        let d2 = -d.clone();
96        assert!(d2.real == -2.3);
97        assert!(Arc::ptr_eq(&d.vars, &d2.vars));
98        assert!(d2.dual[0] == -2.0);
99        assert!(d2.dual[1] == 1.4);
100        assert!(d2.dual2[[1, 0]] == 1.0);
101    }
102
103    #[test]
104    fn negate_ref2() {
105        let d = Dual2::try_new(
106            2.3,
107            Vec::from([String::from("a"), String::from("b")]),
108            Vec::from([2., -1.4]),
109            Vec::from([1.0, -1.0, -1.0, 2.0]),
110        )
111        .unwrap();
112        let d2 = -&d;
113        assert!(d2.real == -2.3);
114        assert!(Arc::ptr_eq(&d.vars, &d2.vars));
115        assert!(d2.dual[0] == -2.0);
116        assert!(d2.dual[1] == 1.4);
117        assert!(d2.dual2[[1, 0]] == 1.0);
118    }
119
120    #[test]
121    fn test_enum() {
122        let f = Number::F64(2.0);
123        let d = Number::Dual(Dual::new(3.0, vec!["x".to_string()]));
124        assert_eq!(-f, Number::F64(-2.0));
125        assert_eq!(
126            -d,
127            Number::Dual(Dual::try_new(-3.0, vec!["x".to_string()], vec![-1.0]).unwrap())
128        );
129    }
130}