1use std::ops::{Add, Mul};
2
3use mdarray::{Array, Dim, Layout, Shape, Slice};
4use mdarray_linalg::{
5 matvec::{Argmax, MatVec, MatVecBuilder, Outer, OuterBuilder, VecOps},
6 utils::unravel_index,
7};
8use num_complex::ComplexFloat;
9use num_traits::Zero;
10
11use super::{
12 scalar::BlasScalar,
13 simple::{amax, asum, axpy, dotc, dotu, gemv, ger, nrm2},
14};
15use crate::Blas;
16
17struct BlasMatVecBuilder<'a, T, D0, D1, La, Lx>
18where
19 D0: Dim,
20 D1: Dim,
21 La: Layout,
22 Lx: Layout,
23{
24 alpha: T,
25 a: &'a Slice<T, (D0, D1), La>,
26 x: &'a Slice<T, (D1,), Lx>,
27}
28
29impl<'a, T, La, Lx, D0: Dim, D1: Dim> MatVecBuilder<'a, T, La, Lx, D0, D1>
30 for BlasMatVecBuilder<'a, T, D0, D1, La, Lx>
31where
32 La: Layout,
33 Lx: Layout,
34 T: BlasScalar + ComplexFloat,
35 T::Real: Into<T>,
36 D0: Dim,
37 D1: Dim,
38{
39 fn scale(mut self, alpha: T) -> Self {
40 self.alpha = alpha * self.alpha;
41 self
42 }
43
44 fn eval(self) -> Array<T, (D0,)> {
45 let mut y = Array::<T, (D0,)>::from_elem(
46 <(D0,) as Shape>::from_dims(&[self.a.shape().dim(0)]),
47 T::zero(),
48 );
49 gemv(self.alpha, self.a, self.x, T::zero(), &mut y);
50 y
51 }
52
53 fn write<Ly: Layout>(self, y: &mut Slice<T, (D0,), Ly>) {
54 gemv(self.alpha, self.a, self.x, T::zero(), y);
55 }
56
57 fn add_to_vec<Ly: Layout>(self, y: &mut Slice<T, (D0,), Ly>) {
58 gemv(self.alpha, self.a, self.x, T::one(), y);
59 }
60
61 fn add_to_scaled_vec<Ly: Layout>(self, y: &mut Slice<T, (D0,), Ly>, beta: T) {
62 gemv(self.alpha, self.a, self.x, beta, y);
63 }
64}
65
66impl<T, D0: Dim, D1: Dim> MatVec<T, D0, D1> for Blas
67where
68 T: BlasScalar + ComplexFloat,
69 T::Real: Into<T>,
70{
71 fn matvec<'a, La, Lx>(
72 &self,
73 a: &'a Slice<T, (D0, D1), La>,
74 x: &'a Slice<T, (D1,), Lx>,
75 ) -> impl MatVecBuilder<'a, T, La, Lx, D0, D1>
76 where
77 La: Layout,
78 Lx: Layout,
79 {
80 BlasMatVecBuilder {
81 alpha: T::one(),
82 a,
83 x,
84 }
85 }
86}
87
88impl<T: ComplexFloat + BlasScalar + Add<Output = T> + Mul<Output = T> + Zero + Copy, D1: Dim>
89 VecOps<T, D1> for Blas
90{
91 type Real = T::Real;
92
93 fn add_to_scaled<Lx: Layout, Ly: Layout>(
94 &self,
95 alpha: T,
96 x: &Slice<T, (D1,), Lx>,
97 y: &mut Slice<T, (D1,), Ly>,
98 ) {
99 axpy(alpha, x, y);
100 }
101
102 fn dot<Lx: Layout, Ly: Layout>(&self, x: &Slice<T, (D1,), Lx>, y: &Slice<T, (D1,), Ly>) -> T {
103 dotu(x, y)
104 }
105
106 fn dotc<Lx: Layout, Ly: Layout>(&self, x: &Slice<T, (D1,), Lx>, y: &Slice<T, (D1,), Ly>) -> T {
107 dotc(x, y)
108 }
109
110 fn norm2<Lx: Layout>(&self, x: &Slice<T, (D1,), Lx>) -> Self::Real {
111 nrm2(x)
112 }
113
114 fn norm1<Lx: Layout>(&self, x: &Slice<T, (D1,), Lx>) -> Self::Real {
115 asum(x)
116 }
117
118 fn rot<Lx: Layout, Ly: Layout>(
119 &self,
120 _x: &mut Slice<T, (D1,), Lx>,
121 _y: &mut Slice<T, (D1,), Ly>,
122 _c: Self::Real,
123 _s: T,
124 ) {
125 todo!()
126 }
127}
128
129impl<
130 T: ComplexFloat
131 + std::cmp::PartialOrd
132 + BlasScalar
133 + Add<Output = T>
134 + Mul<Output = T>
135 + Zero
136 + Copy,
137> Argmax<T> for Blas
138where
139 T::Real: PartialOrd,
140{
141 fn argmax_write<Lx: Layout, S: Shape>(
142 &self,
143 _x: &Slice<T, S, Lx>,
144 _output: &mut Vec<usize>,
145 ) -> bool {
146 unimplemented!();
147 }
148
149 fn argmax<Lx: Layout, S: Shape>(&self, _x: &Slice<T, S, Lx>) -> Option<Vec<usize>> {
150 unimplemented!();
151 }
152
153 fn argmax_abs_write<Lx: Layout, S: Shape>(
154 &self,
155 x: &Slice<T, S, Lx>,
156 output: &mut Vec<usize>,
157 ) -> bool {
158 output.clear();
159 if x.is_empty() {
160 return false;
161 }
162 if x.rank() == 0 {
163 return true;
164 }
165 let max_flat_idx = amax(x);
166 let indices = unravel_index(x, max_flat_idx);
167 output.extend_from_slice(&indices);
168 true
169 }
170
171 fn argmax_abs<Lx: Layout, S: Shape>(&self, x: &Slice<T, S, Lx>) -> Option<Vec<usize>> {
172 let mut result = Vec::new();
173 if self.argmax_abs_write(x, &mut result) {
174 Some(result)
175 } else {
176 None
177 }
178 }
179}
180
181struct BlasOuterBuilder<'a, T, Dx, Dy, Lx, Ly>
182where
183 Lx: Layout,
184 Ly: Layout,
185 Dx: Dim,
186 Dy: Dim,
187{
188 alpha: T,
189 x: &'a Slice<T, (Dx,), Lx>,
190 y: &'a Slice<T, (Dy,), Ly>,
191}
192
193impl<'a, T, Dx, Dy, Lx, Ly> OuterBuilder<'a, T, Lx, Ly, Dx, Dy>
194 for BlasOuterBuilder<'a, T, Dx, Dy, Lx, Ly>
195where
196 Lx: Layout,
197 Ly: Layout,
198 T: BlasScalar + ComplexFloat,
199 T::Real: Into<T>,
200 Dx: Dim,
201 Dy: Dim,
202{
203 fn scale(mut self, alpha: T) -> Self {
204 self.alpha = alpha * self.alpha;
205 self
206 }
207
208 fn eval(self) -> Array<T, (Dx, Dy)> {
209 let shape = <(Dx, Dy) as Shape>::from_dims(&[self.x.len(), self.y.len()]);
210 let mut a = Array::<T, (Dx, Dy)>::from_elem(shape, T::zero());
211 ger(self.alpha, self.x, self.y, &mut a);
212 a
213 }
214
215 fn write<La: Layout>(self, a: &mut Slice<T, (Dx, Dy), La>) {
216 let zero = T::zero();
217 a.fill(zero);
218 ger(self.alpha, self.x, self.y, a);
219 }
220
221 fn add_to<La: Layout>(self, a: &mut Slice<T, (Dx, Dy), La>) {
222 ger(self.alpha, self.x, self.y, a);
223 }
224
225}
226
227impl<T, Dx, Dy> Outer<T, Dx, Dy> for Blas
228where
229 T: BlasScalar + ComplexFloat,
230 T::Real: Into<T>,
231 Dx: Dim,
232 Dy: Dim,
233{
234 fn outer<'a, Lx, Ly>(
235 &self,
236 x: &'a Slice<T, (Dx,), Lx>,
237 y: &'a Slice<T, (Dy,), Ly>,
238 ) -> impl OuterBuilder<'a, T, Lx, Ly, Dx, Dy>
239 where
240 Lx: Layout,
241 Ly: Layout,
242 {
243 BlasOuterBuilder {
244 alpha: T::one(),
245 x,
246 y,
247 }
248 }
249}