custos_math/
matrix.rs

1use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Sub, SubAssign};
2
3use crate::{AdditionalOps, AssignOps, BaseOps};
4
5#[cfg(feature = "opencl")]
6use custos::{
7    opencl::api::{enqueue_write_buffer, wait_for_event},
8    OpenCL,
9};
10use custos::{
11    Alloc, Buffer, CloneBuf, Device, IsShapeIndep, MainMemory, Read, ShallowCopy, Shape, ToDim, CPU,
12};
13
14#[cfg(feature = "cuda")]
15use custos::{cuda::api::cu_write, CUDA};
16
17mod impl_with_shape;
18
19/// A matrix using [Buffer] described with rows and columns
20/// # Example
21/// The following example creates a zeroed (or values set to default) Matrix with the given dimensions.
22#[cfg_attr(feature = "cpu", doc = "```")]
23#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
24/// use custos::CPU;
25/// use custos_math::Matrix;
26///
27/// let device = CPU::new();
28/// let m = Matrix::<i32>::new(&device, (5, 8));
29///
30/// assert_eq!(m.rows(), 5);
31/// assert_eq!(m.cols(), 8);
32/// assert_eq!(m.size(), 5*8);
33/// assert_eq!(m.read(), vec![0; 5*8])
34/// ```
35pub struct Matrix<'a, T = f32, D: Device = CPU, S: Shape = ()> {
36    pub data: Buffer<'a, T, D, S>,
37    pub dims: (usize, usize),
38}
39
40impl<'a, T, D: Device, S: Shape> Matrix<'a, T, D, S> {
41    /// Returns an empty matrix with the specified dimensions (rows, cols).
42    /// # Example
43    #[cfg_attr(feature = "cpu", doc = "```")]
44    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
45    /// use custos::CPU;
46    /// use custos_math::Matrix;
47    ///
48    /// let device = CPU::new();
49    /// let m = Matrix::<f64>::new(&device, (20, 10));
50    ///
51    /// assert_eq!(m.size(), 20*10);
52    /// assert_eq!(m.read(), vec![0.0; 20*10])
53    /// ```
54    #[inline]
55    pub fn new(device: &'a D, dims: (usize, usize)) -> Matrix<'a, T, D, S>
56    where
57        D: Alloc<'a, T, S>,
58    {
59        Matrix {
60            data: Buffer::new(device, dims.0 * dims.1),
61            dims,
62        }
63    }
64
65    #[inline]
66    pub fn device(&self) -> &'a D {
67        self.data.device()
68    }
69
70    // TODO: mind ptrs_Mut
71    //#[inline]
72    //pub fn ptr(&self) -> (*mut T, *mut c_void, u64)
73    //where D::Ptr<T, ()>: CommonPtrs<T>
74    //{
75    //    self.data.ptrs_mut()
76    //}
77
78    /// Returns a reference to the underlying buffer.
79    /// # Example
80    #[cfg_attr(feature = "cpu", doc = "```")]
81    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
82    /// use custos::{CPU, Read};
83    /// use custos_math::Matrix;
84    ///
85    /// let device = CPU::new();
86    /// let a = Matrix::from((&device, (2, 3), [1., 2., 3., 3., 2., 1.,]));
87    /// let read = a.read();
88    /// assert_eq!(vec![1., 2., 3., 3., 2., 1.,], read);
89    /// ```
90    #[inline]
91    pub fn as_buf(&self) -> &Buffer<'a, T, D, S> {
92        &self.data
93    }
94
95    #[inline]
96    pub fn to_buf(self) -> Buffer<'a, T, D, S> {
97        self.data
98    }
99
100    /// Returns a mutable reference to the underlying buffer.
101    #[inline]
102    pub fn as_buf_mut(&mut self) -> &mut Buffer<'a, T, D, S> {
103        &mut self.data
104    }
105
106    #[inline]
107    pub fn dims(&self) -> (usize, usize) {
108        self.dims
109    }
110
111    #[inline]
112    pub fn reshape(&mut self, dims: (usize, usize)) {
113        self.dims = dims;
114    }
115
116    /// Returns the row count of the matrix.
117    ///
118    /// # Example
119    #[cfg_attr(feature = "cpu", doc = "```")]
120    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
121    /// use custos::CPU;
122    /// use custos_math::Matrix;
123    ///
124    /// let device = CPU::new();
125    /// let matrix = Matrix::<i32>::new(&device, (2, 5));
126    /// assert_eq!(matrix.rows(), 2)
127    /// ```
128    #[inline]
129    pub fn rows(&self) -> usize {
130        self.dims.0
131    }
132
133    /// Returns the column count of the matrix.
134    ///
135    /// # Example
136    #[cfg_attr(feature = "cpu", doc = "```")]
137    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
138    /// use custos::CPU;
139    /// use custos_math::Matrix;
140    ///
141    /// let device = CPU::new();
142    /// let matrix = Matrix::<i32>::new(&device, (2, 5));
143    /// assert_eq!(matrix.cols(), 5)
144    /// ```
145    #[inline]
146    pub fn cols(&self) -> usize {
147        self.dims.1
148    }
149
150    /// Returns the number of elements in the matrix: rows * cols
151    ///
152    /// # Example
153    #[cfg_attr(feature = "cpu", doc = "```")]
154    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
155    /// use custos::CPU;
156    /// use custos_math::Matrix;
157    ///
158    /// let device = CPU::new();
159    /// let matrix = Matrix::<u16>::new(&device, (4, 12));
160    /// assert_eq!(matrix.size(), 48)
161    /// ```
162    #[inline]
163    pub fn size(&self) -> usize {
164        self.dims.0 * self.dims.1
165    }
166
167    #[inline]
168    pub fn as_slice(&self) -> &[T]
169    where
170        D: MainMemory,
171    {
172        self.data.as_slice()
173    }
174
175    #[inline]
176    pub fn as_mut_slice(&mut self) -> &mut [T]
177    where
178        D: MainMemory,
179    {
180        self.as_buf_mut().as_mut_slice()
181    }
182
183    /*
184    /// Sets all elements to zero.
185    /// # Example
186    /// ```
187    /// use custos::{CPU, AsDev, Matrix};
188    ///
189    /// let device = CPU::new().select();
190    /// let mut matrix = Matrix::from((&device, 3, 2, [4, 3, 2, 6, 9, 2,]));
191    /// assert_eq!(matrix.read(), vec![4, 3, 2, 6, 9, 2]);
192    ///
193    /// matrix.clear();
194    /// assert_eq!(matrix.read(), vec![0; 6]);
195    /// ```
196    pub fn clear(&mut self)
197    where T: CDatatype
198    {
199        let device = get_device!(BaseOps, T).unwrap();
200        device.clear(self)
201    }*/
202
203    /// Uses VecRead and current global device to read Matrix
204    ///
205    /// # Example
206    #[cfg_attr(feature = "cpu", doc = "```")]
207    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
208    /// use custos::CPU;
209    /// use custos_math::Matrix;
210    ///
211    /// let device = CPU::new();
212    ///
213    /// let a = Matrix::from((&device, (2, 2), [5, 7, 2, 10,]));
214    /// assert_eq!(a.read(), vec![5, 7, 2, 10])
215    /// ```
216    pub fn read(&'a self) -> D::Read<'a>
217    where
218        T: Default + Copy,
219        D: Read<T, D, S>,
220    {
221        self.device().read(self.as_buf())
222    }
223
224    /// Uses VecRead and current global device to read Matrix
225    ///
226    /// # Example
227    #[cfg_attr(feature = "cpu", doc = "```")]
228    #[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
229    /// use custos::CPU;
230    /// use custos_math::Matrix;
231    ///
232    /// let device = CPU::new();
233    ///
234    /// let a = Matrix::from((&device, (2, 2), [5, 7, 2, 10,]));
235    /// assert_eq!(a.read(), vec![5, 7, 2, 10])
236    /// ```
237    #[cfg(not(feature = "no-std"))]
238    pub fn read_to_vec(&self) -> Vec<T>
239    where
240        T: Default + Copy,
241        D: Read<T, D, S>,
242    {
243        self.device().read_to_vec(self.as_buf())
244    }
245
246    /// Creates a shallow copy of &self.
247    pub fn shallow(&self) -> Matrix<'a, T, D, S>
248    where
249        D::Ptr<T, S>: ShallowCopy,
250    {
251        unsafe {
252            Self {
253                data: self.data.shallow(),
254                dims: self.dims,
255            }
256        }
257    }
258
259    /// Creates a shallow copy or a deep copy of &self, depening on whether the `realloc` feature is activated.
260    pub fn shallow_or_clone(&self) -> Matrix<'a, T, D, S>
261    where
262        T: Clone,
263        D::Ptr<T, S>: ShallowCopy,
264        D: CloneBuf<'a, T, S>,
265    {
266        unsafe {
267            Self {
268                data: self.data.shallow_or_clone(),
269                dims: self.dims,
270            }
271        }
272    }
273}
274
275impl<T, D: Device> Default for Matrix<'_, T, D>
276where
277    D::Ptr<T, ()>: Default,
278{
279    fn default() -> Self {
280        Self {
281            data: Default::default(),
282            dims: Default::default(),
283        }
284    }
285}
286
287impl<'a, T, D: Device, S: Shape> Matrix<'a, T, D, S> {
288    /// Converts a (non stack allocated) `Buffer` with no shape to a `Buffer` with shape `O`.
289    #[inline]
290    pub fn to_dims<O: Shape>(self) -> Matrix<'a, T, D, O>
291    where
292        D: ToDim<T, S, O>,
293    {
294        let data = self.data.to_dims();
295
296        Matrix {
297            data,
298            dims: self.dims,
299        }
300    }
301}
302
303impl<T, D: IsShapeIndep, S: Shape> Matrix<'_, T, D, S> {
304    #[inline]
305    pub fn as_dims<'b, O: Shape>(&self) -> &Matrix<'b, T, D, O> {
306        unsafe { &*(self as *const Self).cast() }
307    }
308
309    #[inline]
310    pub fn as_dims_mut<'b, O: Shape>(&mut self) -> &mut Matrix<'b, T, D, O> {
311        unsafe { &mut *(self as *mut Self).cast() }
312    }
313}
314
315impl<'a, T, D: Device, S: Shape> core::ops::Deref for Matrix<'a, T, D, S> {
316    type Target = Buffer<'a, T, D, S>;
317
318    #[inline]
319    fn deref(&self) -> &Self::Target {
320        self.as_buf()
321    }
322}
323
324impl<'a, T, D: Device, S: Shape> core::ops::DerefMut for Matrix<'a, T, D, S> {
325    #[inline]
326    fn deref_mut(&mut self) -> &mut Self::Target {
327        self.as_buf_mut()
328    }
329}
330
331impl<'a, T, S, D> Clone for Matrix<'a, T, D, S>
332where
333    T: Clone,
334    S: Shape,
335    D: CloneBuf<'a, T, S>,
336{
337    fn clone(&self) -> Self {
338        Self {
339            data: self.data.clone(),
340            dims: self.dims.clone(),
341        }
342    }
343}
344
345// From conversions
346
347impl<'a, T, D: Device, S: Shape> From<(Buffer<'a, T, D, S>, (usize, usize))>
348    for Matrix<'a, T, D, S>
349{
350    #[inline]
351    fn from((data, dims): (Buffer<'a, T, D, S>, (usize, usize))) -> Self {
352        Matrix { data, dims }
353    }
354}
355
356// no tuple for dims
357impl<'a, T, D: Device, S: Shape> From<(Buffer<'a, T, D, S>, usize, usize)> for Matrix<'a, T, D, S> {
358    #[inline]
359    fn from((data, rows, cols): (Buffer<'a, T, D, S>, usize, usize)) -> Self {
360        Matrix {
361            data,
362            dims: (rows, cols),
363        }
364    }
365}
366
367// TODO: unsafe from raw parts?
368#[cfg(feature = "cpu")]
369impl<'a, T> From<(*mut T, (usize, usize))> for Matrix<'a, T> {
370    #[inline]
371    fn from((ptr, dims): (*mut T, (usize, usize))) -> Self {
372        unsafe {
373            Matrix {
374                data: Buffer::from_raw_host(ptr, dims.0 * dims.1),
375                dims,
376            }
377        }
378    }
379}
380
381// TODO: unsafe from raw parts?
382#[cfg(feature = "cpu")]
383impl<'a, T> From<(&'a CPU, *mut T, (usize, usize))> for Matrix<'a, T> {
384    #[inline]
385    fn from((cpu, ptr, dims): (&'a CPU, *mut T, (usize, usize))) -> Self {
386        unsafe {
387            Matrix {
388                data: Buffer::from_raw_host_device(cpu, ptr, dims.0 * dims.1),
389                dims,
390            }
391        }
392    }
393}
394
395/*
396// TODO: unsafe from raw parts?
397// is wrapper flag ok?
398#[cfg(not(feature = "safe"))]
399impl<T, D: Device> From<(*mut T, usize, usize)> for Matrix<'_, T, D> {
400    #[inline]
401    fn from(ptr_dims: (*mut T, usize, usize)) -> Self {
402        Matrix {
403            data: Buffer {
404                ptr: (ptr_dims.0, std::ptr::null_mut(), 0),
405                len: ptr_dims.1 * ptr_dims.2,
406                device: Device::default(),
407                flag: BufFlag::Wrapper,
408                node: Node::default(),
409            },
410            dims: (ptr_dims.1, ptr_dims.2),
411        }
412    }
413}*/
414
415/*
416impl<T: Copy + Default, const N: usize> From<((usize, usize), &[T; N])> for Matrix<'_, T> {
417    fn from(dims_slice: ((usize, usize), &[T; N])) -> Self {
418        let device = get_device!(Device<T>).unwrap();
419
420        let buffer = Buffer::from((&device, dims_slice.1));
421        Matrix {
422            data: buffer,
423            dims: dims_slice.0,
424        }
425    }
426}*/
427
428/*
429impl<T: Copy + Default> From<(usize, usize)> for Matrix<'_, T> {
430    fn from(dims: (usize, usize)) -> Self {
431        let device = get_device!(Device<T>).unwrap();
432        let buffer = Buffer::<T>::from((&device, dims.0 * dims.1));
433
434        Matrix { data: buffer, dims }
435    }
436}
437
438impl<T: Copy + Default> From<(usize, usize, Vec<T>)> for Matrix<'_, T> {
439    fn from(dims_data: (usize, usize, Vec<T>)) -> Self {
440        let device = get_device!(Device<T>).unwrap();
441        let buffer = Buffer::<T>::from((device, dims_data.2));
442
443        Matrix {
444            data: buffer,
445            dims: (dims_data.0, dims_data.1),
446        }
447    }
448}*/
449
450#[cfg(feature = "opencl")]
451impl<'a, 'b, T> From<(&'a OpenCL, Matrix<'b, T>)> for Matrix<'a, T, OpenCL> {
452    fn from((device, matrix): (&'a OpenCL, Matrix<'b, T>)) -> Self {
453        //assert!(CPU_CACHE.with(|cache| !cache.borrow().nodes.is_empty()), "no allocations");
454        let out = device.retrieve(matrix.size(), ());
455
456        let event =
457            unsafe { enqueue_write_buffer(&device.queue(), out.ptr.ptr, &matrix, true).unwrap() };
458        wait_for_event(event).unwrap();
459        Matrix::from((out, matrix.dims()))
460    }
461}
462
463#[cfg(feature = "static-api")]
464impl<'a, T: Clone> From<(usize, usize, &[T])> for Matrix<'a, T> {
465    #[inline]
466    fn from((rows, cols, slice): (usize, usize, &[T])) -> Self {
467        Matrix::from((Buffer::from(slice), rows, cols))
468    }
469}
470
471#[cfg(feature = "static-api")]
472impl<'a, T: Clone, const N: usize> From<(usize, usize, [T; N])> for Matrix<'a, T> {
473    #[inline]
474    fn from((rows, cols, slice): (usize, usize, [T; N])) -> Self {
475        Matrix::from((Buffer::from(slice), rows, cols))
476    }
477}
478
479#[cfg(feature = "cuda")]
480impl<'a, 'b, T> From<(&'a CUDA, Matrix<'b, T>)> for Matrix<'a, T, CUDA> {
481    fn from(device_matrix: (&'a CUDA, Matrix<'b, T>)) -> Self {
482        let dst = device_matrix.0.retrieve(device_matrix.1.size(), ());
483        cu_write(dst.ptr.ptr, &device_matrix.1).unwrap();
484        Matrix::from((dst, device_matrix.1.dims()))
485    }
486}
487
488impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep, const N: usize>
489    From<(&'a D, (usize, usize), [T; N])> for Matrix<'a, T, D>
490{
491    fn from((device, dims, slice): (&'a D, (usize, usize), [T; N])) -> Self {
492        let data = Buffer::from((device, slice));
493        Matrix { data, dims }
494    }
495}
496
497// no tuple for dims
498impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep, const N: usize>
499    From<(&'a D, usize, usize, [T; N])> for Matrix<'a, T, D>
500{
501    fn from(dims_slice: (&'a D, usize, usize, [T; N])) -> Self {
502        let data = Buffer::from((dims_slice.0, dims_slice.3));
503        Matrix {
504            data,
505            dims: (dims_slice.1, dims_slice.2),
506        }
507    }
508}
509
510impl<'a, T: Copy, D: Alloc<'a, T>> From<(&'a D, usize, usize)> for Matrix<'a, T, D> {
511    fn from((device, rows, cols): (&'a D, usize, usize)) -> Self {
512        let data = Buffer::new(device, rows * cols);
513        Matrix {
514            data,
515            dims: (rows, cols),
516        }
517    }
518}
519
520impl<'a, T: Copy, D: Alloc<'a, T>> From<(&'a D, (usize, usize))> for Matrix<'a, T, D> {
521    fn from((device, dims): (&'a D, (usize, usize))) -> Self {
522        let data = Buffer::new(device, dims.0 * dims.1);
523        Matrix { data, dims }
524    }
525}
526
527// FIXME: In this case, GraphReturn acts as an "IsDynamic" trait, as GraphReturn is not implemented for Stack
528#[cfg(not(feature = "no-std"))]
529impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep> From<(&'a D, (usize, usize), Vec<T>)>
530    for Matrix<'a, T, D>
531{
532    fn from(dims_slice: (&'a D, (usize, usize), Vec<T>)) -> Self {
533        let data = Buffer::from((dims_slice.0, dims_slice.2));
534        Matrix {
535            data,
536            dims: dims_slice.1,
537        }
538    }
539}
540
541// no tuple for dims
542#[cfg(not(feature = "no-std"))]
543// FIXME: In this case, GraphReturn acts as an "IsDynamic" trait, as GraphReturn is not implemented for Stack
544impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep> From<(&'a D, usize, usize, Vec<T>)>
545    for Matrix<'a, T, D>
546{
547    fn from(dims_slice: (&'a D, usize, usize, Vec<T>)) -> Self {
548        let data = Buffer::from((dims_slice.0, dims_slice.3));
549        Matrix {
550            data,
551            dims: (dims_slice.1, dims_slice.2),
552        }
553    }
554}
555
556// FIXME: In this case, GraphReturn acts as an "IsDynamic" trait, as GraphReturn is not implemented for Stack
557impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep> From<(&'a D, (usize, usize), &[T])>
558    for Matrix<'a, T, D>
559{
560    fn from(dims_slice: (&'a D, (usize, usize), &[T])) -> Self {
561        let data = Buffer::from((dims_slice.0, dims_slice.2));
562        Matrix {
563            data,
564            dims: dims_slice.1,
565        }
566    }
567}
568
569// no tuple for dims
570// FIXME: In this case, GraphReturn acts as an "IsDynamic" trait, as GraphReturn is not implemented for Stack
571impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep> From<(&'a D, usize, usize, &[T])>
572    for Matrix<'a, T, D>
573{
574    fn from(dims_slice: (&'a D, usize, usize, &[T])) -> Self {
575        let data = Buffer::from((dims_slice.0, dims_slice.3));
576        Matrix {
577            data,
578            dims: (dims_slice.1, dims_slice.2),
579        }
580    }
581}
582
583#[cfg(not(feature = "no-std"))]
584impl<'a, T: Copy, D: Alloc<'a, T> + IsShapeIndep> From<(&'a D, (usize, usize), &Vec<T>)>
585    for Matrix<'a, T, D>
586{
587    fn from(dims_slice: (&'a D, (usize, usize), &Vec<T>)) -> Self {
588        let data = Buffer::from((dims_slice.0, dims_slice.2));
589        Matrix {
590            data,
591            dims: dims_slice.1,
592        }
593    }
594}
595
596//-------------Add-------------
597
598impl<'a, T, D, S: Shape> Add<Self> for &Matrix<'a, T, D, S>
599where
600    D: BaseOps<T, S>,
601{
602    type Output = Matrix<'a, T, D, S>;
603
604    fn add(self, rhs: Self) -> Self::Output {
605        self.device().add(self, rhs)
606    }
607}
608
609impl<'a, T, D, S: Shape> Add<Self> for Matrix<'a, T, D, S>
610where
611    D: BaseOps<T, S>,
612{
613    type Output = Matrix<'a, T, D, S>;
614
615    fn add(self, rhs: Self) -> Self::Output {
616        self.device().add(&self, &rhs)
617    }
618}
619
620impl<'a, T, D, S: Shape> Add<&Self> for Matrix<'a, T, D, S>
621where
622    D: BaseOps<T, S>,
623{
624    type Output = Matrix<'a, T, D, S>;
625
626    fn add(self, rhs: &Self) -> Self::Output {
627        self.device().add(&self, rhs)
628    }
629}
630
631impl<'a, T, D, S: Shape> Add<Matrix<'a, T, D, S>> for &Matrix<'a, T, D, S>
632where
633    D: BaseOps<T, S>,
634{
635    type Output = Matrix<'a, T, D, S>;
636
637    fn add(self, rhs: Matrix<T, D, S>) -> Self::Output {
638        self.device().add(self, &rhs)
639    }
640}
641
642impl<'a, T, D, S: Shape> Add<T> for &Matrix<'a, T, D, S>
643where
644    D: AdditionalOps<T, S>,
645{
646    type Output = Matrix<'a, T, D, S>;
647
648    fn add(self, rhs: T) -> Self::Output {
649        self.adds(rhs)
650    }
651}
652
653impl<'a, T, D> Add<T> for Matrix<'a, T, D>
654where
655    D: AdditionalOps<T>,
656{
657    type Output = Matrix<'a, T, D>;
658
659    fn add(self, rhs: T) -> Self::Output {
660        self.adds(rhs)
661    }
662}
663
664//-------------Sub-------------
665
666impl<'a, T, D, S> Sub<Self> for &Matrix<'a, T, D, S>
667where
668    D: BaseOps<T, S>,
669    S: Shape,
670{
671    type Output = Matrix<'a, T, D, S>;
672
673    fn sub(self, rhs: Self) -> Self::Output {
674        self.device().sub(self, rhs)
675    }
676}
677
678impl<'a, T, D, S> Sub<Self> for Matrix<'a, T, D, S>
679where
680    D: BaseOps<T, S>,
681    S: Shape,
682{
683    type Output = Matrix<'a, T, D, S>;
684
685    fn sub(self, rhs: Self) -> Self::Output {
686        self.device().sub(&self, &rhs)
687    }
688}
689
690impl<'a, T, D, S> Sub<&Self> for Matrix<'a, T, D, S>
691where
692    D: BaseOps<T, S>,
693    S: Shape,
694{
695    type Output = Matrix<'a, T, D, S>;
696
697    fn sub(self, rhs: &Self) -> Self::Output {
698        self.device().sub(&self, rhs)
699    }
700}
701
702impl<'a, T, D, S> Sub<Matrix<'a, T, D, S>> for &Matrix<'a, T, D, S>
703where
704    D: BaseOps<T, S>,
705    S: Shape,
706{
707    type Output = Matrix<'a, T, D, S>;
708
709    fn sub(self, rhs: Matrix<T, D, S>) -> Self::Output {
710        self.device().sub(self, &rhs)
711    }
712}
713
714impl<'a, T, D, S> Sub<T> for &Matrix<'a, T, D, S>
715where
716    S: Shape,
717    D: AdditionalOps<T, S>,
718{
719    type Output = Matrix<'a, T, D, S>;
720
721    fn sub(self, rhs: T) -> Self::Output {
722        self.subs(rhs);
723        todo!()
724        //self.subs
725    }
726}
727
728impl<'a, T> Sub<T> for Matrix<'a, T> {
729    type Output = Matrix<'a, T>;
730
731    fn sub(self, _rhs: T) -> Self::Output {
732        todo!()
733        //self.subs(rhs)
734    }
735}
736
737//-------------Mul-------------
738
739impl<'a, T, D, S: Shape> Mul<Self> for &Matrix<'a, T, D, S>
740where
741    D: BaseOps<T, S>,
742{
743    type Output = Matrix<'a, T, D, S>;
744
745    fn mul(self, rhs: Self) -> Self::Output {
746        self.device().mul(self, rhs)
747    }
748}
749
750impl<'a, T, D, S: Shape> Mul<Self> for Matrix<'a, T, D, S>
751where
752    D: BaseOps<T, S>,
753{
754    type Output = Matrix<'a, T, D, S>;
755
756    fn mul(self, rhs: Self) -> Self::Output {
757        self.device().mul(&self, &rhs)
758    }
759}
760
761impl<'a, T, D, S: Shape> Mul<&Self> for Matrix<'a, T, D, S>
762where
763    D: BaseOps<T, S>,
764{
765    type Output = Matrix<'a, T, D, S>;
766
767    fn mul(self, rhs: &Self) -> Self::Output {
768        self.device().mul(&self, rhs)
769    }
770}
771
772impl<'a, T, S: Shape, D: AdditionalOps<T, S>> Mul<T> for Matrix<'a, T, D, S> {
773    type Output = Matrix<'a, T, D, S>;
774
775    fn mul(self, rhs: T) -> Self::Output {
776        self.muls(rhs)
777    }
778}
779
780impl<'a, T: Copy, S: Shape, D: AdditionalOps<T, S>> Mul<&T> for Matrix<'a, T, D, S> {
781    type Output = Matrix<'a, T, D, S>;
782
783    fn mul(self, rhs: &T) -> Self::Output {
784        self.muls(*rhs)
785    }
786}
787
788impl<'a, T, S: Shape, D: AdditionalOps<T, S>> Mul<T> for &Matrix<'a, T, D, S> {
789    type Output = Matrix<'a, T, D, S>;
790
791    fn mul(self, rhs: T) -> Self::Output {
792        self.muls(rhs)
793    }
794}
795
796// div
797
798impl<'a, T, S: Shape, D: BaseOps<T, S>> Div<Self> for &Matrix<'a, T, D, S> {
799    type Output = Matrix<'a, T, D, S>;
800
801    fn div(self, rhs: Self) -> Self::Output {
802        self.device().div(self, rhs)
803    }
804}
805
806impl<'a, T, S: Shape, D: AdditionalOps<T, S>> Div<T> for Matrix<'a, T, D, S> {
807    type Output = Matrix<'a, T, D, S>;
808
809    fn div(self, rhs: T) -> Self::Output {
810        self.divs(rhs)
811    }
812}
813
814impl<'a, T, S: Shape, D: AdditionalOps<T, S>> Div<T> for &Matrix<'a, T, D, S> {
815    type Output = Matrix<'a, T, D, S>;
816
817    fn div(self, rhs: T) -> Self::Output {
818        self.divs(rhs)
819    }
820}
821
822impl<T, D, S: Shape> AddAssign<&Self> for Matrix<'_, T, D, S>
823where
824    D: AssignOps<T, S, D>,
825{
826    fn add_assign(&mut self, rhs: &Self) {
827        rhs.device().add_assign(self, rhs)
828    }
829}
830
831impl<T, D, S: Shape> AddAssign<Self> for Matrix<'_, T, D, S>
832where
833    D: AssignOps<T, S, D>,
834{
835    fn add_assign(&mut self, rhs: Self) {
836        rhs.device().add_assign(self, &rhs)
837    }
838}
839
840impl<T, D, S: Shape> MulAssign<&Self> for Matrix<'_, T, D, S>
841where
842    D: AssignOps<T, S, D>,
843{
844    fn mul_assign(&mut self, rhs: &Self) {
845        rhs.device().mul_assign(self, rhs)
846    }
847}
848
849impl<T, D, S: Shape> MulAssign<Self> for Matrix<'_, T, D, S>
850where
851    D: AssignOps<T, S, D>,
852{
853    fn mul_assign(&mut self, rhs: Self) {
854        rhs.device().mul_assign(self, &rhs)
855    }
856}
857
858impl<T, D, S: Shape> SubAssign<&Matrix<'_, T, D, S>> for &mut Matrix<'_, T, D, S>
859where
860    D: AssignOps<T, S, D>,
861{
862    fn sub_assign(&mut self, rhs: &Matrix<T, D, S>) {
863        rhs.device().sub_assign(self, rhs)
864    }
865}
866
867impl<T, D, S: Shape> SubAssign<Matrix<'_, T, D, S>> for &mut Matrix<'_, T, D, S>
868where
869    D: AssignOps<T, S, D>,
870{
871    fn sub_assign(&mut self, rhs: Matrix<T, D, S>) {
872        rhs.device().sub_assign(self, &rhs)
873    }
874}
875
876impl<T, D, S: Shape> SubAssign<&Self> for Matrix<'_, T, D, S>
877where
878    D: AssignOps<T, S, D>,
879{
880    fn sub_assign(&mut self, rhs: &Self) {
881        rhs.device().sub_assign(self, rhs)
882    }
883}
884
885impl<T, D, S: Shape> SubAssign<Self> for Matrix<'_, T, D, S>
886where
887    D: AssignOps<T, S, D>,
888{
889    fn sub_assign(&mut self, rhs: Self) {
890        rhs.device().sub_assign(self, &rhs)
891    }
892}
893
894#[cfg(not(feature = "no-std"))]
895impl<'a, T: Default + Copy + core::fmt::Debug, D: Read<T, D>> core::fmt::Debug for Matrix<'a, T, D>
896where
897    D: Read<T, D> + 'a,
898    //for<'b> <D as Read<T, D>>::Read<'b>: Iterator,
899{
900    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
901        let data = self.read_to_vec();
902
903        writeln!(f, "dims={:?}", self.dims)?;
904        write!(f, "[")?;
905
906        let max = self.dims.0 * self.dims.1;
907        for (count, value) in data.iter().enumerate() {
908            write!(f, "{:?}, ", value)?;
909
910            if (count + 1) % self.dims.1 == 0 && count + 1 != max {
911                writeln!(f)?;
912            }
913        }
914        write!(f, ":datatype={}]", core::any::type_name::<T>())
915    }
916}
917
918#[cfg(feature = "stack")]
919impl<'a, T, const N: usize> From<(&custos::Stack, usize, usize, [T; N])>
920    for Matrix<'a, T, custos::Stack, custos::Dim1<N>>
921{
922    fn from((_, rows, cols, array): (&custos::Stack, usize, usize, [T; N])) -> Self {
923        let data = Buffer::from((&custos::Stack, array));
924        Matrix {
925            data,
926            dims: (rows, cols),
927        }
928    }
929}
930
931#[cfg(feature = "stack")]
932impl<'a, T: Copy + Default, const A: usize, const B: usize, const N: usize>
933    From<(&custos::Stack, usize, usize, [T; N])>
934    for Matrix<'a, T, custos::Stack, custos::Dim2<A, B>>
935{
936    fn from((_, rows, cols, array): (&custos::Stack, usize, usize, [T; N])) -> Self {
937        let data = Buffer::from((&custos::Stack, array));
938        Matrix {
939            data,
940            dims: (rows, cols),
941        }
942    }
943}
944
945/*impl<'a, T, D: IsShapeIndep, S: Shape> From<(&D, usize, usize, [T; N])> Matrix<T, D, S> {
946
947}*/
948
949#[cfg(test)]
950mod tests {
951    use crate::Matrix;
952
953    #[cfg(feature = "stack")]
954    #[cfg(not(feature = "no-std"))]
955    #[test]
956    fn test_run() {
957        let device = custos::CPU::new();
958
959        let a = Matrix::from((&device, 1, 1000, [1; 1000]));
960        let b = Matrix::from((&device, 1, 1000, [7; 1000]));
961
962        loop {
963            let out = &a + &b;
964            assert_eq!(out.as_slice(), &[8; 1000]);
965        }
966    }
967
968    #[cfg(feature = "cpu")]
969    #[test]
970    fn test_to_dims() {
971        use custos::{Dim1, ToDim, CPU};
972
973        let device = CPU::new();
974        let a = Matrix::from((&device, 1, 1000, [1; 1000]));
975        ToDim::<i32, (), Dim1<1000>>::to_dim(&device, a.data.ptr);
976        //let b: custos::cpu::CPUPtr<i32> = a.device().to_dim(a.ptr);
977    }
978}