1use crate::ffi::c_char;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4pub enum BLASLayout {
5 #[default]
6 Undefined = -1,
7 RowMajor = 101,
8 ColMajor = 102,
9 Sequential = 103,
11 NonContiguous = 104,
12}
13
14pub type BALSOrder = BLASLayout;
15pub use BLASLayout::{ColMajor as BLASColMajor, RowMajor as BLASRowMajor};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
18pub enum BLASTranspose {
19 #[default]
20 Undefined = -1,
21 NoTrans = 111,
22 Trans = 112,
23 ConjTrans = 113,
24 ConjNoTrans = 114,
25}
26
27pub use BLASTranspose::{ConjTrans as BLASConjTrans, NoTrans as BLASNoTrans, Trans as BLASTrans};
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum BLASUpLo {
31 #[default]
32 Undefined = -1,
33 Upper = 121,
34 Lower = 122,
35}
36
37pub use BLASUpLo::{Lower as BLASLower, Upper as BLASUpper};
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
40pub enum BLASDiag {
41 #[default]
42 Undefined = -1,
43 NonUnit = 131,
44 Unit = 132,
45}
46
47pub use BLASDiag::{NonUnit as BLASNonUnit, Unit as BLASUnit};
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
50pub enum BLASSide {
51 #[default]
52 Undefined = -1,
53 Left = 141,
54 Right = 142,
55}
56
57pub use BLASSide::{Left as BLASLeft, Right as BLASRight};
58
59use super::{blas_invalid, BLASError};
60
61impl From<char> for BLASLayout {
62 #[inline]
63 fn from(c: char) -> Self {
64 match c.to_ascii_uppercase() {
65 'R' => BLASRowMajor,
66 'C' => BLASColMajor,
67 _ => Self::Undefined,
68 }
69 }
70}
71
72impl TryFrom<BLASLayout> for char {
73 type Error = BLASError;
74 #[inline]
75 fn try_from(layout: BLASLayout) -> Result<Self, BLASError> {
76 match layout {
77 BLASRowMajor => Ok('R'),
78 BLASColMajor => Ok('C'),
79 _ => blas_invalid!(layout),
80 }
81 }
82}
83
84impl TryFrom<BLASLayout> for c_char {
85 type Error = BLASError;
86 #[inline]
87 fn try_from(layout: BLASLayout) -> Result<Self, BLASError> {
88 match layout {
89 BLASRowMajor => Ok('R' as c_char),
90 BLASColMajor => Ok('C' as c_char),
91 _ => blas_invalid!(layout),
92 }
93 }
94}
95
96impl From<char> for BLASTranspose {
97 #[inline]
98 fn from(c: char) -> Self {
99 match c.to_ascii_uppercase() {
100 'N' => BLASNoTrans,
101 'T' => BLASTrans,
102 'C' => BLASConjTrans,
103 _ => Self::Undefined,
104 }
105 }
106}
107
108impl TryFrom<BLASTranspose> for char {
109 type Error = BLASError;
110 #[inline]
111 fn try_from(trans: BLASTranspose) -> Result<Self, Self::Error> {
112 match trans {
113 BLASNoTrans => Ok('N'),
114 BLASTrans => Ok('T'),
115 BLASConjTrans => Ok('C'),
116 _ => blas_invalid!(trans),
117 }
118 }
119}
120
121impl TryFrom<BLASTranspose> for c_char {
122 type Error = BLASError;
123 #[inline]
124 fn try_from(trans: BLASTranspose) -> Result<Self, Self::Error> {
125 match trans {
126 BLASNoTrans => Ok('N' as c_char),
127 BLASTrans => Ok('T' as c_char),
128 BLASConjTrans => Ok('C' as c_char),
129 _ => blas_invalid!(trans),
130 }
131 }
132}
133
134impl From<char> for BLASUpLo {
135 #[inline]
136 fn from(c: char) -> Self {
137 match c.to_ascii_uppercase() {
138 'U' => BLASUpper,
139 'L' => BLASLower,
140 _ => Self::Undefined,
141 }
142 }
143}
144
145impl TryFrom<BLASUpLo> for char {
146 type Error = BLASError;
147 #[inline]
148 fn try_from(uplo: BLASUpLo) -> Result<Self, BLASError> {
149 match uplo {
150 BLASUpper => Ok('U'),
151 BLASLower => Ok('L'),
152 _ => blas_invalid!(uplo),
153 }
154 }
155}
156
157impl TryFrom<BLASUpLo> for c_char {
158 type Error = BLASError;
159 #[inline]
160 fn try_from(uplo: BLASUpLo) -> Result<Self, Self::Error> {
161 match uplo {
162 BLASUpper => Ok('U' as c_char),
163 BLASLower => Ok('L' as c_char),
164 _ => blas_invalid!(uplo),
165 }
166 }
167}
168
169impl From<char> for BLASDiag {
170 #[inline]
171 fn from(c: char) -> Self {
172 match c.to_ascii_uppercase() {
173 'N' => BLASNonUnit,
174 'U' => BLASUnit,
175 _ => Self::Undefined,
176 }
177 }
178}
179
180impl TryFrom<BLASDiag> for char {
181 type Error = BLASError;
182 #[inline]
183 fn try_from(diag: BLASDiag) -> Result<Self, Self::Error> {
184 match diag {
185 BLASNonUnit => Ok('N'),
186 BLASUnit => Ok('U'),
187 _ => blas_invalid!(diag),
188 }
189 }
190}
191
192impl TryFrom<BLASDiag> for c_char {
193 type Error = BLASError;
194 #[inline]
195 fn try_from(diag: BLASDiag) -> Result<Self, Self::Error> {
196 match diag {
197 BLASNonUnit => Ok('N' as c_char),
198 BLASUnit => Ok('U' as c_char),
199 _ => blas_invalid!(diag),
200 }
201 }
202}
203
204impl From<char> for BLASSide {
205 #[inline]
206 fn from(c: char) -> Self {
207 match c.to_ascii_uppercase() {
208 'L' => BLASLeft,
209 'R' => BLASRight,
210 _ => Self::Undefined,
211 }
212 }
213}
214
215impl TryFrom<BLASSide> for char {
216 type Error = BLASError;
217 #[inline]
218 fn try_from(side: BLASSide) -> Result<Self, Self::Error> {
219 match side {
220 BLASLeft => Ok('L'),
221 BLASRight => Ok('R'),
222 _ => blas_invalid!(side),
223 }
224 }
225}
226
227impl TryFrom<BLASSide> for c_char {
228 type Error = BLASError;
229 #[inline]
230 fn try_from(side: BLASSide) -> Result<Self, Self::Error> {
231 match side {
232 BLASLeft => Ok('L' as c_char),
233 BLASRight => Ok('R' as c_char),
234 _ => blas_invalid!(side),
235 }
236 }
237}
238
239impl BLASLayout {
240 #[inline]
241 pub fn flip(&self) -> Result<Self, BLASError> {
242 match self {
243 BLASRowMajor => Ok(BLASColMajor),
244 BLASColMajor => Ok(BLASRowMajor),
245 _ => blas_invalid!(self),
246 }
247 }
248}
249
250impl BLASUpLo {
251 #[inline]
252 pub fn flip(&self) -> Result<Self, BLASError> {
253 match self {
254 BLASUpper => Ok(BLASLower),
255 BLASLower => Ok(BLASUpper),
256 _ => blas_invalid!(self),
257 }
258 }
259}
260
261impl BLASSide {
262 #[inline]
263 pub fn flip(&self) -> Result<Self, BLASError> {
264 match self {
265 BLASLeft => Ok(BLASRight),
266 BLASRight => Ok(BLASLeft),
267 _ => blas_invalid!(self),
268 }
269 }
270}
271
272impl BLASTranspose {
273 #[inline]
274 pub fn flip(&self, hermi: bool) -> Result<Self, BLASError> {
275 match self {
276 BLASNoTrans => match hermi {
277 false => Ok(BLASTrans),
278 true => Ok(BLASConjTrans),
279 },
280 BLASTrans => Ok(BLASNoTrans),
281 BLASConjTrans => Ok(BLASNoTrans),
282 _ => blas_invalid!(self),
283 }
284 }
285}
286
287unsafe impl Send for BLASLayout {}
288unsafe impl Send for BLASTranspose {}
289unsafe impl Send for BLASUpLo {}
290unsafe impl Send for BLASDiag {}
291unsafe impl Send for BLASSide {}
292
293unsafe impl Sync for BLASLayout {}
294unsafe impl Sync for BLASTranspose {}
295unsafe impl Sync for BLASUpLo {}
296unsafe impl Sync for BLASDiag {}
297unsafe impl Sync for BLASSide {}
298
299impl BLASLayout {
300 #[inline]
301 pub fn is_cpref(&self) -> bool {
302 match self {
303 BLASRowMajor => true,
304 BLASLayout::Sequential => true,
305 _ => false,
306 }
307 }
308
309 #[inline]
310 pub fn is_fpref(&self) -> bool {
311 match self {
312 BLASColMajor => true,
313 BLASLayout::Sequential => true,
314 _ => false,
315 }
316 }
317}
318
319pub(crate) fn get_layout_row_preferred(by_first: &[Option<BLASLayout>], by_all: &[BLASLayout]) -> BLASLayout {
320 for x in by_first {
321 if let Some(x) = x {
322 if x.is_cpref() {
323 return BLASRowMajor;
324 } else if x.is_fpref() {
325 return BLASColMajor;
326 }
327 }
328 }
329
330 if by_all.iter().all(|f| f.is_cpref()) {
331 return BLASRowMajor;
332 } else if by_all.iter().all(|f| f.is_fpref()) {
333 return BLASColMajor;
334 } else {
335 return BLASRowMajor;
336 }
337}
338
339#[cfg(test)]
341mod tests {
342 use super::*;
343
344 #[test]
345 fn test_blaslayout_from_char() {
346 assert_eq!(BLASLayout::from('R'), BLASRowMajor);
347 assert_eq!(BLASLayout::from('r'), BLASRowMajor);
348 assert_eq!(BLASLayout::from('C'), BLASColMajor);
349 assert_eq!(BLASLayout::from('c'), BLASColMajor);
350 assert_eq!(BLASLayout::from('X'), BLASLayout::Undefined);
351 }
352
353 #[test]
354 fn test_blaslayout_try_from_blaslayout_for_char() {
355 assert_eq!(char::try_from(BLASRowMajor), Ok('R'));
356 assert_eq!(char::try_from(BLASColMajor), Ok('C'));
357 assert!(char::try_from(BLASLayout::Undefined).is_err());
358 }
359
360 #[test]
361 fn test_blaslayout_try_from_blaslayout_for_c_char() {
362 assert_eq!(c_char::try_from(BLASRowMajor), Ok('R' as c_char));
363 assert_eq!(c_char::try_from(BLASColMajor), Ok('C' as c_char));
364 assert!(c_char::try_from(BLASLayout::Undefined).is_err());
365 }
366
367 #[test]
368 fn test_blastranspose_from_char() {
369 assert_eq!(BLASTranspose::from('N'), BLASNoTrans);
370 assert_eq!(BLASTranspose::from('n'), BLASNoTrans);
371 assert_eq!(BLASTranspose::from('T'), BLASTrans);
372 assert_eq!(BLASTranspose::from('t'), BLASTrans);
373 assert_eq!(BLASTranspose::from('C'), BLASConjTrans);
374 assert_eq!(BLASTranspose::from('c'), BLASConjTrans);
375 assert_eq!(BLASTranspose::from('X'), BLASTranspose::Undefined);
376 }
377
378 #[test]
379 fn test_blastranspose_try_from_blastranspose_for_char() {
380 assert_eq!(char::try_from(BLASNoTrans), Ok('N'));
381 assert_eq!(char::try_from(BLASTrans), Ok('T'));
382 assert_eq!(char::try_from(BLASConjTrans), Ok('C'));
383 assert!(char::try_from(BLASTranspose::Undefined).is_err());
384 }
385
386 #[test]
387 fn test_blastranspose_try_from_blastranspose_for_c_char() {
388 assert_eq!(c_char::try_from(BLASNoTrans), Ok('N' as c_char));
389 assert_eq!(c_char::try_from(BLASTrans), Ok('T' as c_char));
390 assert_eq!(c_char::try_from(BLASConjTrans), Ok('C' as c_char));
391 assert!(c_char::try_from(BLASTranspose::Undefined).is_err());
392 }
393
394 #[test]
395 fn test_blasuplo_from_char() {
396 assert_eq!(BLASUpLo::from('U'), BLASUpper);
397 assert_eq!(BLASUpLo::from('u'), BLASUpper);
398 assert_eq!(BLASUpLo::from('L'), BLASLower);
399 assert_eq!(BLASUpLo::from('l'), BLASLower);
400 assert_eq!(BLASUpLo::from('X'), BLASUpLo::Undefined);
401 }
402
403 #[test]
404 fn test_blasuplo_try_from_blasuplo_for_char() {
405 assert_eq!(char::try_from(BLASUpper), Ok('U'));
406 assert_eq!(char::try_from(BLASLower), Ok('L'));
407 assert!(char::try_from(BLASUpLo::Undefined).is_err());
408 }
409
410 #[test]
411 fn test_blasuplo_try_from_blasuplo_for_c_char() {
412 assert_eq!(c_char::try_from(BLASUpper), Ok('U' as c_char));
413 assert_eq!(c_char::try_from(BLASLower), Ok('L' as c_char));
414 assert!(c_char::try_from(BLASUpLo::Undefined).is_err());
415 }
416
417 #[test]
418 fn test_blasdiag_from_char() {
419 assert_eq!(BLASDiag::from('N'), BLASNonUnit);
420 assert_eq!(BLASDiag::from('n'), BLASNonUnit);
421 assert_eq!(BLASDiag::from('U'), BLASUnit);
422 assert_eq!(BLASDiag::from('u'), BLASUnit);
423 assert_eq!(BLASDiag::from('X'), BLASDiag::Undefined);
424 }
425
426 #[test]
427 fn test_blasdiag_try_from_blasdiag_for_char() {
428 assert_eq!(char::try_from(BLASNonUnit), Ok('N'));
429 assert_eq!(char::try_from(BLASUnit), Ok('U'));
430 assert!(char::try_from(BLASDiag::Undefined).is_err());
431 }
432
433 #[test]
434 fn test_blasdiag_try_from_blasdiag_for_c_char() {
435 assert_eq!(c_char::try_from(BLASNonUnit), Ok('N' as c_char));
436 assert_eq!(c_char::try_from(BLASUnit), Ok('U' as c_char));
437 assert!(c_char::try_from(BLASDiag::Undefined).is_err());
438 }
439
440 #[test]
441 fn test_blasside_from_char() {
442 assert_eq!(BLASSide::from('L'), BLASLeft);
443 assert_eq!(BLASSide::from('l'), BLASLeft);
444 assert_eq!(BLASSide::from('R'), BLASRight);
445 assert_eq!(BLASSide::from('r'), BLASRight);
446 assert_eq!(BLASSide::from('X'), BLASSide::Undefined);
447 }
448
449 #[test]
450 fn test_blasside_try_from_blasside_for_char() {
451 assert_eq!(char::try_from(BLASLeft), Ok('L'));
452 assert_eq!(char::try_from(BLASRight), Ok('R'));
453 assert!(char::try_from(BLASSide::Undefined).is_err());
454 }
455
456 #[test]
457 fn test_blasside_try_from_blasside_for_c_char() {
458 assert_eq!(c_char::try_from(BLASLeft), Ok('L' as c_char));
459 assert_eq!(c_char::try_from(BLASRight), Ok('R' as c_char));
460 assert!(c_char::try_from(BLASSide::Undefined).is_err());
461 }
462
463 #[test]
464 fn test_blaslayout_flip() {
465 assert_eq!(BLASRowMajor.flip(), Ok(BLASColMajor));
466 assert_eq!(BLASColMajor.flip(), Ok(BLASRowMajor));
467 assert!(BLASLayout::Undefined.flip().is_err());
468 }
469
470 #[test]
471 fn test_blasuplo_flip() {
472 assert_eq!(BLASUpper.flip(), Ok(BLASLower));
473 assert_eq!(BLASLower.flip(), Ok(BLASUpper));
474 assert!(BLASUpLo::Undefined.flip().is_err());
475 }
476
477 #[test]
478 fn test_blasside_flip() {
479 assert_eq!(BLASLeft.flip(), Ok(BLASRight));
480 assert_eq!(BLASRight.flip(), Ok(BLASLeft));
481 assert!(BLASSide::Undefined.flip().is_err());
482 }
483
484 #[test]
485 fn test_blastranspose_flip() {
486 assert_eq!(BLASNoTrans.flip(false), Ok(BLASTrans));
487 assert_eq!(BLASNoTrans.flip(true), Ok(BLASConjTrans));
488 assert_eq!(BLASTrans.flip(false), Ok(BLASNoTrans));
489 assert_eq!(BLASTrans.flip(true), Ok(BLASNoTrans));
490 assert_eq!(BLASConjTrans.flip(false), Ok(BLASNoTrans));
491 assert_eq!(BLASConjTrans.flip(true), Ok(BLASNoTrans));
492 assert!(BLASTranspose::Undefined.flip(false).is_err());
493 }
494
495 #[test]
496 fn test_blaslayout_is_cpref() {
497 assert!(BLASRowMajor.is_cpref());
498 assert!(!BLASColMajor.is_cpref());
499 assert!(BLASLayout::Sequential.is_cpref());
500 assert!(!BLASLayout::Undefined.is_cpref());
501 }
502
503 #[test]
504 fn test_blaslayout_is_fpref() {
505 assert!(!BLASRowMajor.is_fpref());
506 assert!(BLASColMajor.is_fpref());
507 assert!(BLASLayout::Sequential.is_fpref());
508 assert!(!BLASLayout::Undefined.is_fpref());
509 }
510
511 #[test]
512 fn test_get_layout_row_preferred() {
513 let by_first = [Some(BLASRowMajor), Some(BLASColMajor), None];
514 let by_all = [BLASRowMajor, BLASColMajor, BLASLayout::Sequential];
515
516 assert_eq!(get_layout_row_preferred(&by_first, &by_all), BLASRowMajor);
517
518 let by_first = [None, None, None];
519 let by_all = [BLASRowMajor, BLASRowMajor, BLASRowMajor];
520
521 assert_eq!(get_layout_row_preferred(&by_first, &by_all), BLASRowMajor);
522
523 let by_first = [None, None, None];
524 let by_all = [BLASColMajor, BLASColMajor, BLASColMajor];
525
526 assert_eq!(get_layout_row_preferred(&by_first, &by_all), BLASColMajor);
527
528 let by_first = [None, None, None];
529 let by_all = [BLASRowMajor, BLASColMajor, BLASLayout::Sequential];
530
531 assert_eq!(get_layout_row_preferred(&by_first, &by_all), BLASRowMajor);
532 }
533}