frustool/functions/
vector.rs

1/*
2 * operations.rs - Vector math operations for libfrustool.
3 *
4 * Copyright 2020-2021 Naman Bishnoi
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17*/
18
19//! Vector coupling math operations
20//!
21//! Calculates two vector operations fast and effortlessly.
22
23use crate::errors::Error;
24use cpython::{exc, PyErr, PyResult, Python};
25
26pub struct Vectors {
27    input_vector1: Vec<f64>,
28    input_vector2: Vec<f64>,
29}
30
31impl Vectors {
32    pub fn new(input_vector1: Vec<f64>, input_vector2: Vec<f64>) -> Result<Self, Error> {
33        if input_vector1.len() != input_vector2.len() {
34            return Err(Error::InvalidParams(String::from(
35                "Vectors length mismatch",
36            )));
37        }
38        Ok(Self {
39            input_vector1,
40            input_vector2,
41        })
42    }
43
44    /// Add - Vector arithmetic addition
45    pub fn add(&self) -> Vec<f64> {
46        let mut output_vector = Vec::new();
47        for idx in 0..self.input_vector1.len() {
48            output_vector.push(self.input_vector1[idx] + self.input_vector2[idx])
49        }
50        output_vector
51    }
52
53    /// Subtraction - Vector arithmetic subtraction
54    pub fn sub(&self) -> Vec<f64> {
55        let mut output_vector = Vec::new();
56        for idx in 0..self.input_vector1.len() {
57            output_vector.push(self.input_vector1[idx] - self.input_vector2[idx])
58        }
59        output_vector
60    }
61    /// Divide - Vector arithmetic division
62    pub fn div(&self) -> Vec<f64> {
63        let mut output_vector = Vec::new();
64        for idx in 0..self.input_vector1.len() {
65            output_vector.push(self.input_vector1[idx] / self.input_vector2[idx])
66        }
67        output_vector
68    }
69    /// Muliplication - Vector arithmetic multiplication
70    pub fn mul(&self) -> Vec<f64> {
71        let mut output_vector = Vec::new();
72        for idx in 0..self.input_vector1.len() {
73            output_vector.push(self.input_vector1[idx] * self.input_vector2[idx])
74        }
75        output_vector
76    }
77}
78
79pub fn add_py(py: Python, vector1: Vec<f64>, vector2: Vec<f64>) -> PyResult<Vec<f64>> {
80    let vec_zip = Vectors::new(vector1, vector2);
81    let vectors = match vec_zip {
82        Ok(x) => x,
83        Err(err_typ) => match err_typ {
84            Error::InvalidParams(msg) => return Err(PyErr::new::<exc::IndexError, _>(py, msg)),
85        },
86    };
87    let out_vec = vectors.add();
88    Ok(out_vec)
89}
90
91pub fn sub_py(py: Python, vector1: Vec<f64>, vector2: Vec<f64>) -> PyResult<Vec<f64>> {
92    let vec_zip = Vectors::new(vector1, vector2);
93    let vectors = match vec_zip {
94        Ok(x) => x,
95        Err(err_typ) => match err_typ {
96            Error::InvalidParams(msg) => return Err(PyErr::new::<exc::IndexError, _>(py, msg)),
97        },
98    };
99    let out_vec = vectors.sub();
100    Ok(out_vec)
101}
102
103pub fn mul_py(py: Python, vector1: Vec<f64>, vector2: Vec<f64>) -> PyResult<Vec<f64>> {
104    let vec_zip = Vectors::new(vector1, vector2);
105    let vectors = match vec_zip {
106        Ok(x) => x,
107        Err(err_typ) => match err_typ {
108            Error::InvalidParams(msg) => return Err(PyErr::new::<exc::IndexError, _>(py, msg)),
109        },
110    };
111    let out_vec = vectors.mul();
112    Ok(out_vec)
113}
114
115pub fn div_py(py: Python, vector1: Vec<f64>, vector2: Vec<f64>) -> PyResult<Vec<f64>> {
116    let vec_zip = Vectors::new(vector1, vector2);
117    let vectors = match vec_zip {
118        Ok(x) => x,
119        Err(err_typ) => match err_typ {
120            Error::InvalidParams(msg) => return Err(PyErr::new::<exc::IndexError, _>(py, msg)),
121        },
122    };
123    let out_vec = vectors.div();
124    Ok(out_vec)
125}
126
127/**
128 *
129 * Ahoy mate! Unit tests ahead, if you want to test every
130 * functionality of the library/program then feel free to do so;
131 *
132 */
133
134#[cfg(test)]
135mod test {
136    use super::*;
137
138    #[test]
139    fn test_vect_mul() {
140        let vec1 = vec![1.0, 2.0, 3.0, 4.0];
141        let vec2 = vec![1.0, 2.0, 3.0, 4.0];
142        let vectors = Vectors::new(vec1, vec2).unwrap();
143        let vec_mul = vectors.mul();
144
145        assert_eq!(vec_mul, vec![1.0, 4.0, 9.0, 16.0])
146    }
147    #[test]
148    fn test_vect_add() {
149        let vec1 = vec![1.0, 2.0, 3.0, 4.0];
150        let vec2 = vec![1.0, 2.0, 3.0, 4.0];
151
152        let vectors = Vectors::new(vec1, vec2).unwrap();
153        let vec_add = vectors.add();
154
155        assert_eq!(vec_add, vec![2.0, 4.0, 6.0, 8.0])
156    }
157    #[test]
158    fn test_vect_div() {
159        let vec1 = vec![1.0, 2.0, 3.0, 4.0];
160        let vec2 = vec![1.0, 2.0, 3.0, 4.0];
161
162        let vectors = Vectors::new(vec1, vec2).unwrap();
163        let vec_div = vectors.div();
164
165        assert_eq!(vec_div, vec![1.0, 1.0, 1.0, 1.0])
166    }
167    #[test]
168    fn test_vect_sub() {
169        let vec1 = vec![1.0, 2.0, 3.0, 4.0];
170        let vec2 = vec![1.0, 2.0, 3.0, 4.0];
171
172        let vectors = Vectors::new(vec1, vec2).unwrap();
173        let vec_sub = vectors.sub();
174
175        assert_eq!(vec_sub, vec![0.0, 0.0, 0.0, 0.0])
176    }
177}