peroxide/traits/
pointer.rs

1//! Pointer toolbox
2//!
3//! # Redox
4//!
5//! ## Type
6//! ```ignore
7//! pub struct Redox<T: Vector> {
8//!     data: Box<T>
9//! }
10//! ```
11//!
12//! ## Description
13//!
14//! Operation with `Vec<_>` is too bothered. For example, next code generates error.
15//! ```compile_fail
16//! #[macro_use]
17//! extern crate peroxide;
18//! use peroxide::prelude::*;
19//!
20//! fn main() {
21//!     let a = c!(1, 2, 3);
22//!     assert_eq!(a * 2f64 - 1f64, c!(1, 3, 5));
23//! }
24//! ```
25//!
26//! Because we can't implement `Mul<Vec<f64>> for f64` and vice versa.
27//! `Redox<T: Vector>` makes the situation easy.
28//!
29//! ## Usage
30//!
31//! * `ox()`: `Vector` to `Redox<T: Vector>`
32//! * `red()`: `Redox<T: Vector>` to `T` (Ofcourse, `T` should be sized)
33//!
34//! ```
35//! #[macro_use]
36//! extern crate peroxide;
37//! use peroxide::fuga::*;
38//!
39//! fn main() {
40//!     let a = c!(1, 2, 3);
41//!     assert_eq!((a.ox() * 2f64 - 1f64).red(), c!(1, 3, 5));
42//! }
43//! ```
44//!
45//! `ox()` and `red()` come from oxidation and reduction.
46use crate::structure::ad::AD;
47use crate::structure::matrix::{Matrix, Shape};
48use crate::structure::sparse::SPMatrix;
49use crate::traits::{
50    fp::FPVector,
51    math::{LinearOp, Vector},
52    matrix::MatrixTrait,
53};
54use std::ops::{Add, Deref, Div, Mul, Sub};
55
56// =============================================================================
57// Redox Structure
58// =============================================================================
59#[derive(Debug)]
60pub struct Redox<T: Vector> {
61    data: Box<T>,
62}
63
64impl<T: Vector> Deref for Redox<T> {
65    type Target = T;
66
67    fn deref(&self) -> &Self::Target {
68        &self.data
69    }
70}
71
72pub trait RedoxCommon {
73    type ToRedox;
74    fn from_vec(vec: Self::ToRedox) -> Self;
75    fn red(self) -> Self::ToRedox;
76}
77
78impl RedoxCommon for Redox<Vec<f64>> {
79    type ToRedox = Vec<f64>;
80    fn from_vec(vec: Self::ToRedox) -> Self {
81        Self {
82            data: Box::new(vec),
83        }
84    }
85
86    fn red(self) -> Self::ToRedox {
87        (*self).to_vec()
88    }
89}
90
91impl RedoxCommon for Redox<Vec<AD>> {
92    type ToRedox = Vec<AD>;
93    fn from_vec(vec: Self::ToRedox) -> Self {
94        Self {
95            data: Box::new(vec),
96        }
97    }
98
99    fn red(self) -> Self::ToRedox {
100        (*self).to_vec()
101    }
102}
103
104// =============================================================================
105// Oxide trait
106// =============================================================================
107pub trait Oxide: Vector {
108    fn ox(self) -> Redox<Self>
109    where
110        Self: Sized;
111}
112
113// =============================================================================
114// Reference Arithmetic
115// =============================================================================
116impl<T: Vector> Add<Redox<T>> for Redox<T> {
117    type Output = Self;
118
119    fn add(self, rhs: Redox<T>) -> Self::Output {
120        Redox {
121            data: Box::new(self.add_vec(&rhs.data)),
122        }
123    }
124}
125
126impl<T: Vector + FPVector> Sub<Redox<T>> for Redox<T>
127where
128    <T as FPVector>::Scalar: Sub<Output = <T as FPVector>::Scalar>,
129{
130    type Output = Self;
131
132    fn sub(self, rhs: Redox<T>) -> Self::Output {
133        Redox {
134            data: Box::new(self.zip_with(|x, y| x - y, &rhs.data)),
135        }
136    }
137}
138
139impl<T: Vector + FPVector> Mul<Redox<T>> for Redox<T>
140where
141    <T as FPVector>::Scalar: Mul<Output = <T as FPVector>::Scalar>,
142{
143    type Output = Self;
144
145    fn mul(self, rhs: Redox<T>) -> Self::Output {
146        Redox {
147            data: Box::new(self.zip_with(|x, y| x * y, &rhs.data)),
148        }
149    }
150}
151
152impl<T: Vector + FPVector> Div<Redox<T>> for Redox<T>
153where
154    <T as FPVector>::Scalar: Div<Output = <T as FPVector>::Scalar>,
155{
156    type Output = Self;
157
158    fn div(self, rhs: Redox<T>) -> Self::Output {
159        Redox {
160            data: Box::new(self.zip_with(|x, y| x / y, &rhs.data)),
161        }
162    }
163}
164
165impl<T: Vector + FPVector> Add<f64> for Redox<T>
166where
167    <T as FPVector>::Scalar: Add<f64, Output = <T as FPVector>::Scalar>,
168{
169    type Output = Self;
170
171    fn add(self, rhs: f64) -> Self::Output {
172        Redox {
173            data: Box::new(self.fmap(|x| x + rhs)),
174        }
175    }
176}
177
178impl<T: Vector + FPVector> Sub<f64> for Redox<T>
179where
180    <T as FPVector>::Scalar: Sub<f64, Output = <T as FPVector>::Scalar>,
181{
182    type Output = Self;
183
184    fn sub(self, rhs: f64) -> Self::Output {
185        Redox {
186            data: Box::new(self.fmap(|x| x - rhs)),
187        }
188    }
189}
190
191impl<T: Vector + FPVector> Mul<f64> for Redox<T>
192where
193    <T as FPVector>::Scalar: Mul<f64, Output = <T as FPVector>::Scalar>,
194{
195    type Output = Self;
196
197    fn mul(self, rhs: f64) -> Self::Output {
198        Redox {
199            data: Box::new(self.fmap(|x| x * rhs)),
200        }
201    }
202}
203
204impl<T: Vector + FPVector> Div<f64> for Redox<T>
205where
206    <T as FPVector>::Scalar: Div<f64, Output = <T as FPVector>::Scalar>,
207{
208    type Output = Self;
209
210    fn div(self, rhs: f64) -> Self::Output {
211        Redox {
212            data: Box::new(self.fmap(|x| x / rhs)),
213        }
214    }
215}
216
217impl Mul<Redox<Vec<f64>>> for Matrix {
218    type Output = Redox<Vec<f64>>;
219
220    fn mul(self, rhs: Redox<Vec<f64>>) -> Self::Output {
221        Redox {
222            data: Box::new(self.apply(&*rhs)),
223        }
224    }
225}
226
227impl Mul<Redox<Vec<f64>>> for &Matrix {
228    type Output = Redox<Vec<f64>>;
229
230    fn mul(self, rhs: Redox<Vec<f64>>) -> Self::Output {
231        Redox {
232            data: Box::new(self.apply(&*rhs)),
233        }
234    }
235}
236
237/// Matrix multiplication with Redox
238impl Mul<Redox<Vec<f64>>> for SPMatrix {
239    type Output = Redox<Vec<f64>>;
240    fn mul(self, rhs: Redox<Vec<f64>>) -> Self::Output {
241        Redox {
242            data: Box::new(self.apply(&rhs.data)),
243        }
244    }
245}
246
247impl Mul<Redox<Vec<f64>>> for &SPMatrix {
248    type Output = Redox<Vec<f64>>;
249
250    fn mul(self, rhs: Redox<Vec<f64>>) -> Self::Output {
251        Redox {
252            data: Box::new(self.apply(&rhs.data)),
253        }
254    }
255}
256
257// =============================================================================
258// Pointer for Matrix
259// =============================================================================
260/// Pointer for col or row
261pub trait MatrixPtr {
262    unsafe fn row_ptr(&self, idx: usize) -> Vec<*const f64>;
263    unsafe fn col_ptr(&self, idx: usize) -> Vec<*const f64>;
264}
265
266impl MatrixPtr for Matrix {
267    /// Row pointer
268    ///
269    /// # Examples
270    /// ```
271    /// #[macro_use]
272    /// extern crate peroxide;
273    /// use peroxide::fuga::*;
274    ///
275    /// fn main() {
276    ///     let a = ml_matrix("1 2;3 4");
277    ///     unsafe {
278    ///         let b = a.row_ptr(1);
279    ///         let b_vec = ptr_to_vec(&b);
280    ///         assert_eq!(b_vec, vec![3f64, 4f64]);
281    ///     }
282    /// }
283    /// ```
284    unsafe fn row_ptr(&self, idx: usize) -> Vec<*const f64> {
285        assert!(idx < self.col, "Index out of range");
286        match self.shape {
287            Shape::Row => {
288                let mut v: Vec<*const f64> = vec![&0f64; self.col];
289                let start_idx = idx * self.col;
290                let p = self.ptr();
291                for (i, j) in (start_idx..start_idx + v.len()).enumerate() {
292                    v[i] = p.add(j);
293                }
294                v
295            }
296            Shape::Col => {
297                let mut v: Vec<*const f64> = vec![&0f64; self.col];
298                let p = self.ptr();
299                for (i, elem) in v.iter_mut().enumerate() {
300                    *elem = p.add(idx + i * self.row);
301                }
302                v
303            }
304        }
305    }
306
307    unsafe fn col_ptr(&self, idx: usize) -> Vec<*const f64> {
308        assert!(idx < self.col, "Index out of range");
309        match self.shape {
310            Shape::Col => {
311                let mut v: Vec<*const f64> = vec![&0f64; self.row];
312                let start_idx = idx * self.row;
313                let p = self.ptr();
314                for (i, j) in (start_idx..start_idx + v.len()).enumerate() {
315                    v[i] = p.add(j);
316                }
317                v
318            }
319            Shape::Row => {
320                let mut v: Vec<*const f64> = vec![&0f64; self.row];
321                let p = self.ptr();
322                for (i, elem) in v.iter_mut().enumerate() {
323                    *elem = p.add(idx + i * self.col);
324                }
325                v
326            }
327        }
328    }
329}