Skip to main content

rust_tensors/
matrix_address.rs

1use crate::adressable::Addressable;
2use std::ops::{Add, Neg, Sub};
3
4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
5pub struct MatrixAddress {
6    pub x: i32,
7    pub y: i32,
8}
9
10impl MatrixAddress {
11    /// Scales the position of the matrix address by the floating point scalar.
12    /// Epsilon is added to the results before truncation to avoid floating point precision issues
13    /// # Arguments
14    ///
15    /// * `scalar`: The scalar to multiply the value with.
16    ///
17    /// Returns: MatrixAddress
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use rust_tensors::matrix_address::MatrixAddress;
23    /// let address = MatrixAddress {x: 5, y: 10};
24    /// assert_eq!(address.scale(0.5), MatrixAddress {x: 2, y: 5});
25    /// ```
26    pub fn scale(self, scalar: f64) -> Self {
27        let (mut x, mut y) = (self.x as f64 * scalar, self.y as f64 * scalar);
28        if x > 0.0 {
29            x += f64::EPSILON;
30        }
31        if y > 0.0 {
32            y += f64::EPSILON;
33        }
34        MatrixAddress {
35            x: x as i32,
36            y: y as i32,
37        }
38    }
39}
40
41impl Addressable<i32, 2usize> for MatrixAddress {
42    fn get_value_at_dimension_index(&self, index: usize) -> i32 {
43        match index {
44            0 => self.x,
45            1 => self.y,
46            _ => panic!("Invalid Dimension Index"),
47        }
48    }
49}
50
51impl From<[i32; 2]> for MatrixAddress {
52    fn from(value: [i32; 2]) -> Self {
53        Self {
54            x: value[0],
55            y: value[1],
56        }
57    }
58}
59
60impl Into<[i32; 2]> for MatrixAddress {
61    fn into(self) -> [i32; 2] {
62        [self.x, self.y]
63    }
64}
65
66impl Add for MatrixAddress {
67    type Output = MatrixAddress;
68
69    fn add(self, rhs: Self) -> Self::Output {
70        MatrixAddress {
71            x: self.x + rhs.x,
72            y: self.y + rhs.y,
73        }
74    }
75}
76
77impl Sub for MatrixAddress {
78    type Output = MatrixAddress;
79
80    fn sub(self, rhs: Self) -> Self::Output {
81        MatrixAddress {
82            x: self.x - rhs.x,
83            y: self.y - rhs.y,
84        }
85    }
86}
87
88impl Neg for MatrixAddress {
89    type Output = Self;
90
91    fn neg(self) -> Self::Output {
92        MatrixAddress {
93            x: -self.x,
94            y: -self.y,
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::adressable::Addressable;
102    use crate::matrix_address::MatrixAddress;
103    use proptest::proptest;
104
105    proptest! {
106        #[test]
107        fn arithmetic_test(x1 in -100000i32..100000i32, x2 in -100000i32..100000i32, y1 in -100000i32..100000i32, y2 in -100000i32..100000i32, s in -10000i32..10000i32) {
108            let a1 = MatrixAddress{x: x1, y: y1};
109            let a2 = MatrixAddress{x: x2, y: y2};
110
111            assert_eq!(a1.get_value_at_dimension_index(0), x1);
112            assert_eq!(a1.get_value_at_dimension_index(1), y1);
113            assert_eq!(a2.get_value_at_dimension_index(0), x2);
114            assert_eq!(a2.get_value_at_dimension_index(1), y2);
115
116            assert_eq!(a1 - a2, a1 + (-a2));
117            assert_eq!(a2 - a1, a2 + (-a1));
118            assert_eq!(-(-a1), a1);
119            assert_eq!(a1 + a2 - a2, a1);
120            assert_eq!(-a1 + a2 + a1, a2);
121            assert_eq!(a1.scale(2.0), MatrixAddress{x: a1.x * 2, y: a1.y * 2});
122
123            let a1 = MatrixAddress{x: x1, y: y1};
124            assert_eq!(a1.scale(s as f64), MatrixAddress{x: a1.x * s, y: a1.y * s});
125        }
126    }
127}