blas_array2/util/
blas_flags.rs

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    // extension of current crate
10    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// Following test is generated by DeepSeek
340#[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}