Skip to main content

aocl_types/
lib.rs

1//! Shared types used by AOCL safe wrappers.
2//!
3//! Pull-out crate for the matrix-orientation / triangular-storage enums
4//! that recur across BLAS, LAPACK, sparse-BLAS, and data-analytics calls.
5//! Each safe `aocl-*` crate accepts these types and converts them to the
6//! corresponding native FFI representation at its boundary.
7
8#![warn(missing_debug_implementations, missing_docs)]
9#![cfg_attr(docsrs, feature(doc_cfg))]
10
11/// Storage order of a 2-D matrix.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum Layout {
14    /// Rows are stored contiguously (C-style).
15    RowMajor,
16    /// Columns are stored contiguously (Fortran-style).
17    ColMajor,
18}
19
20/// How to interpret a matrix operand: as-is, transposed, or
21/// conjugate-transposed.
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum Trans {
24    /// Use the matrix as stored.
25    No,
26    /// Use the transpose `Aᵀ`.
27    T,
28    /// Use the conjugate transpose `Aᴴ`. Equivalent to `T` for real matrices.
29    C,
30}
31
32/// Triangular fill mode for a matrix.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub enum Uplo {
35    /// Upper triangle is referenced; lower is implied.
36    Upper,
37    /// Lower triangle is referenced; upper is implied.
38    Lower,
39}
40
41/// Diagonal interpretation for a triangular matrix.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub enum Diag {
44    /// Diagonal entries are explicit.
45    NonUnit,
46    /// Diagonal entries are implicitly `1` (unit-triangular).
47    Unit,
48}
49
50/// On which side of an operand a matrix is applied.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum Side {
53    /// `A` is applied on the left of `B` (`op(A) · B`).
54    Left,
55    /// `A` is applied on the right of `B` (`B · op(A)`).
56    Right,
57}
58
59/// Single-precision complex number, ABI-compatible with the C struct
60/// `{ float real; float imag; }` used by BLIS's `scomplex`, LAPACK's
61/// `lapack_complex_float`, and FFTW's `fftwf_complex`.
62#[repr(C)]
63#[derive(Debug, Clone, Copy, PartialEq)]
64pub struct Complex32 {
65    /// Real part.
66    pub re: f32,
67    /// Imaginary part.
68    pub im: f32,
69}
70
71impl Complex32 {
72    /// Create a complex number `re + im·i`.
73    #[inline]
74    pub const fn new(re: f32, im: f32) -> Self {
75        Self { re, im }
76    }
77
78    /// `0 + 0i`.
79    pub const ZERO: Self = Self::new(0.0, 0.0);
80    /// `1 + 0i`.
81    pub const ONE: Self = Self::new(1.0, 0.0);
82    /// `0 + 1i`.
83    pub const I: Self = Self::new(0.0, 1.0);
84
85    /// Modulus squared `re² + im²` (avoids the square root of `abs`).
86    #[inline]
87    pub fn norm_sqr(&self) -> f32 {
88        self.re * self.re + self.im * self.im
89    }
90
91    /// Modulus `√(re² + im²)`.
92    #[inline]
93    pub fn abs(&self) -> f32 {
94        self.norm_sqr().sqrt()
95    }
96
97    /// Complex conjugate.
98    #[inline]
99    pub fn conj(&self) -> Self {
100        Self::new(self.re, -self.im)
101    }
102}
103
104impl From<(f32, f32)> for Complex32 {
105    #[inline]
106    fn from((re, im): (f32, f32)) -> Self {
107        Self::new(re, im)
108    }
109}
110
111impl From<[f32; 2]> for Complex32 {
112    #[inline]
113    fn from(a: [f32; 2]) -> Self {
114        Self::new(a[0], a[1])
115    }
116}
117
118impl From<Complex32> for [f32; 2] {
119    #[inline]
120    fn from(c: Complex32) -> Self {
121        [c.re, c.im]
122    }
123}
124
125impl From<f32> for Complex32 {
126    #[inline]
127    fn from(re: f32) -> Self {
128        Self::new(re, 0.0)
129    }
130}
131
132/// Double-precision complex number, ABI-compatible with the C struct
133/// `{ double real; double imag; }` used by BLIS's `dcomplex`, LAPACK's
134/// `lapack_complex_double`, and FFTW's `fftw_complex`.
135#[repr(C)]
136#[derive(Debug, Clone, Copy, PartialEq)]
137pub struct Complex64 {
138    /// Real part.
139    pub re: f64,
140    /// Imaginary part.
141    pub im: f64,
142}
143
144impl Complex64 {
145    /// Create a complex number `re + im·i`.
146    #[inline]
147    pub const fn new(re: f64, im: f64) -> Self {
148        Self { re, im }
149    }
150
151    /// `0 + 0i`.
152    pub const ZERO: Self = Self::new(0.0, 0.0);
153    /// `1 + 0i`.
154    pub const ONE: Self = Self::new(1.0, 0.0);
155    /// `0 + 1i`.
156    pub const I: Self = Self::new(0.0, 1.0);
157
158    /// Modulus squared `re² + im²`.
159    #[inline]
160    pub fn norm_sqr(&self) -> f64 {
161        self.re * self.re + self.im * self.im
162    }
163
164    /// Modulus `√(re² + im²)`.
165    #[inline]
166    pub fn abs(&self) -> f64 {
167        self.norm_sqr().sqrt()
168    }
169
170    /// Complex conjugate.
171    #[inline]
172    pub fn conj(&self) -> Self {
173        Self::new(self.re, -self.im)
174    }
175}
176
177impl From<(f64, f64)> for Complex64 {
178    #[inline]
179    fn from((re, im): (f64, f64)) -> Self {
180        Self::new(re, im)
181    }
182}
183
184impl From<[f64; 2]> for Complex64 {
185    #[inline]
186    fn from(a: [f64; 2]) -> Self {
187        Self::new(a[0], a[1])
188    }
189}
190
191impl From<Complex64> for [f64; 2] {
192    #[inline]
193    fn from(c: Complex64) -> Self {
194        [c.re, c.im]
195    }
196}
197
198impl From<f64> for Complex64 {
199    #[inline]
200    fn from(re: f64) -> Self {
201        Self::new(re, 0.0)
202    }
203}
204
205/// Module containing a sealed marker trait for use as a bound on public
206/// traits whose set of implementing types should not grow outside this
207/// project.
208///
209/// Each safe `aocl-*` crate's `Scalar` trait extends `Sealed` so users
210/// cannot add their own scalar types.
211pub mod sealed {
212    use super::{Complex32, Complex64};
213
214    /// Sealed marker. Implemented for `f32`, `f64`, and the complex
215    /// precisions `Complex32` / `Complex64`.
216    pub trait Sealed {}
217
218    impl Sealed for f32 {}
219    impl Sealed for f64 {}
220    impl Sealed for Complex32 {}
221    impl Sealed for Complex64 {}
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn complex32_layout_matches_array() {
230        // Repr-C struct of two f32s must be exactly 8 bytes laid out
231        // [re, im], matching [f32; 2] for FFI cast safety.
232        assert_eq!(std::mem::size_of::<Complex32>(), 8);
233        assert_eq!(
234            std::mem::align_of::<Complex32>(),
235            std::mem::align_of::<f32>()
236        );
237        let c = Complex32::new(1.5, -2.0);
238        let arr: [f32; 2] = c.into();
239        assert_eq!(arr, [1.5, -2.0]);
240    }
241
242    #[test]
243    fn complex64_layout_matches_array() {
244        assert_eq!(std::mem::size_of::<Complex64>(), 16);
245        assert_eq!(
246            std::mem::align_of::<Complex64>(),
247            std::mem::align_of::<f64>()
248        );
249        let c = Complex64::new(3.0, 4.0);
250        assert_eq!(c.abs(), 5.0);
251        assert_eq!(c.norm_sqr(), 25.0);
252        assert_eq!(c.conj(), Complex64::new(3.0, -4.0));
253    }
254
255    #[test]
256    fn complex_constants() {
257        assert_eq!(Complex32::ZERO, Complex32::new(0.0, 0.0));
258        assert_eq!(Complex32::ONE, Complex32::new(1.0, 0.0));
259        assert_eq!(Complex32::I, Complex32::new(0.0, 1.0));
260        assert_eq!(Complex64::ZERO, Complex64::new(0.0, 0.0));
261    }
262}