use super::blas::{Op, gemm};
use crate::math::complex::{Complex, Float};
use crate::math::numbers::Number;
use core::fmt;
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
pub(crate) mod sealed {
use super::*;
pub trait Element: Clone + PartialEq + fmt::Debug {
fn zero() -> Self;
fn one() -> Self;
fn is_zero(&self) -> bool;
fn conj(&self) -> Self;
fn add(a: &Self, b: &Self) -> Self;
fn sub(a: &Self, b: &Self) -> Self;
fn mul(a: &Self, b: &Self) -> Self;
fn neg(a: &Self) -> Self;
fn add_assign(a: &mut Self, b: &Self);
fn sub_assign(a: &mut Self, b: &Self);
fn mul_assign(a: &mut Self, b: &Self);
fn mul_add(c: &mut Self, a: &Self, b: &Self);
fn product(c: &mut [Self], a: &[Self], b: &[Self], m: usize, k: usize, n: usize) {
for j in 0..n {
let c = &mut c[j * m..(j + 1) * m];
for p in 0..k {
let x = &b[p + j * k];
if x.is_zero() {
continue;
}
for (c, a) in c.iter_mut().zip(&a[p * m..(p + 1) * m]) {
Self::mul_add(c, a, x);
}
}
}
}
}
pub trait Scalar:
Element
+ Copy
+ Default
+ Add<Output = Self>
+ Sub<Output = Self>
+ Mul<Output = Self>
+ Div<Output = Self>
+ Neg<Output = Self>
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ Send
+ Sync
+ 'static
{
type R: Float;
type C: super::Scalar<Real = Self::R>;
type Re: super::Scalar<Real = Self::R>;
const IS_COMPLEX: bool;
fn re(self) -> Self::R;
fn im(self) -> Self::R;
fn from_real(re: Self::R) -> Self;
fn from_parts(re: Self::R, im: Self::R) -> Self;
fn abs(self) -> Self::R;
fn abs2(self) -> Self::R;
fn abs1(self) -> Self::R;
fn scale(self, r: Self::R) -> Self;
fn mul_sub(self, a: Self, b: Self) -> Self;
fn sqrt(self) -> Self;
fn to_complex(self) -> Complex<Self::R>;
fn to_c(self) -> Self::C;
fn from_c(c: Self::C) -> Self;
fn is_finite(self) -> bool;
#[allow(clippy::too_many_arguments)]
fn gemm_real(
m: usize,
n: usize,
k: usize,
alpha: Self::R,
a: &[Self::R],
lda: usize,
b: &[Self::R],
ldb: usize,
beta: Self::R,
c: &mut [Self::R],
ldc: usize,
);
#[allow(clippy::too_many_arguments)]
fn gemm(
m: usize,
n: usize,
k: usize,
alpha: Self,
a: &[Self],
lda: usize,
opa: Op,
b: &[Self],
ldb: usize,
opb: Op,
beta: Self,
c: &mut [Self],
ldc: usize,
);
}
}
pub trait Element: sealed::Element {}
pub trait Scalar: Element + sealed::Scalar<R = <Self as Scalar>::Real> {
type Real: Float;
}
impl Element for Number {}
impl sealed::Element for Number {
#[inline]
fn zero() -> Self {
Number::default()
}
#[inline]
fn one() -> Self {
Number::from(1u8)
}
#[inline]
fn is_zero(&self) -> bool {
Number::is_zero(self)
}
#[inline]
fn conj(&self) -> Self {
self.clone()
}
#[inline]
fn add(a: &Self, b: &Self) -> Self {
a + b
}
#[inline]
fn sub(a: &Self, b: &Self) -> Self {
a - b
}
#[inline]
fn mul(a: &Self, b: &Self) -> Self {
a * b
}
#[inline]
fn neg(a: &Self) -> Self {
-a
}
#[inline]
fn add_assign(a: &mut Self, b: &Self) {
*a += b;
}
#[inline]
fn sub_assign(a: &mut Self, b: &Self) {
*a -= b;
}
#[inline]
fn mul_assign(a: &mut Self, b: &Self) {
*a *= b;
}
#[inline]
fn mul_add(c: &mut Self, a: &Self, b: &Self) {
if !a.is_zero() {
*c += a * b;
}
}
}
macro_rules! gemm {
($f:ident) => {
#[inline]
#[track_caller]
fn gemm(
m: usize,
n: usize,
k: usize,
alpha: Self,
a: &[Self],
lda: usize,
opa: Op,
b: &[Self],
ldb: usize,
opb: Op,
beta: Self,
c: &mut [Self],
ldc: usize,
) {
super::gemm::$f(m, n, k, alpha, a, lda, opa, b, ldb, opb, beta, c, ldc);
}
};
}
macro_rules! copy_element {
($zero:expr, $one:expr, $conj:expr) => {
#[inline]
fn zero() -> Self {
$zero
}
#[inline]
fn one() -> Self {
$one
}
#[inline]
fn is_zero(&self) -> bool {
*self == $zero
}
#[inline]
fn conj(&self) -> Self {
$conj(*self)
}
#[inline]
fn add(a: &Self, b: &Self) -> Self {
*a + *b
}
#[inline]
fn sub(a: &Self, b: &Self) -> Self {
*a - *b
}
#[inline]
fn mul(a: &Self, b: &Self) -> Self {
*a * *b
}
#[inline]
fn neg(a: &Self) -> Self {
-*a
}
#[inline]
fn add_assign(a: &mut Self, b: &Self) {
*a += *b;
}
#[inline]
fn sub_assign(a: &mut Self, b: &Self) {
*a -= *b;
}
#[inline]
fn mul_assign(a: &mut Self, b: &Self) {
*a *= *b;
}
#[inline]
fn mul_add(c: &mut Self, a: &Self, b: &Self) {
*c += *a * *b;
}
fn product(c: &mut [Self], a: &[Self], b: &[Self], m: usize, k: usize, n: usize) {
gemm(m, n, k, $one, a, m, Op::N, b, k, Op::N, $zero, c, m);
}
};
}
macro_rules! real {
($t:ident) => {
impl Element for $t {}
impl Scalar for $t {
type Real = $t;
}
impl sealed::Element for $t {
copy_element!(0.0, 1.0, core::convert::identity);
}
impl sealed::Scalar for $t {
type R = $t;
type C = Complex<$t>;
type Re = $t;
const IS_COMPLEX: bool = false;
#[inline]
fn re(self) -> $t {
self
}
#[inline]
fn im(self) -> $t {
0.0
}
#[inline]
fn from_real(re: $t) -> Self {
re
}
#[inline]
fn from_parts(re: $t, _: $t) -> Self {
re
}
#[inline]
fn abs(self) -> $t {
$t::abs(self)
}
#[inline]
fn abs2(self) -> $t {
self * self
}
#[inline]
fn abs1(self) -> $t {
$t::abs(self)
}
#[inline]
fn scale(self, r: $t) -> Self {
self * r
}
#[inline(always)]
fn mul_sub(self, a: Self, b: Self) -> Self {
$t::mul_add(-a, b, self)
}
#[inline]
fn sqrt(self) -> Self {
$t::sqrt(self)
}
#[inline]
fn to_complex(self) -> Complex<$t> {
Complex::new(self, 0.0)
}
#[inline]
fn to_c(self) -> Complex<$t> {
Complex::new(self, 0.0)
}
#[inline]
fn from_c(c: Complex<$t>) -> Self {
c.re
}
#[inline]
fn is_finite(self) -> bool {
$t::is_finite(self)
}
#[inline]
fn gemm_real(
m: usize,
n: usize,
k: usize,
alpha: $t,
a: &[$t],
lda: usize,
b: &[$t],
ldb: usize,
beta: $t,
c: &mut [$t],
ldc: usize,
) {
gemm(m, n, k, alpha, a, lda, Op::N, b, ldb, Op::N, beta, c, ldc);
}
gemm!(real);
}
impl Element for Complex<$t> {}
impl Scalar for Complex<$t> {
type Real = $t;
}
impl sealed::Element for Complex<$t> {
copy_element!(Complex::<$t>::ZERO, Complex::<$t>::ONE, Complex::conj);
}
impl sealed::Scalar for Complex<$t> {
type R = $t;
type C = Self;
type Re = $t;
const IS_COMPLEX: bool = true;
#[inline]
fn re(self) -> $t {
self.re
}
#[inline]
fn im(self) -> $t {
self.im
}
#[inline]
fn from_real(re: $t) -> Self {
Complex::new(re, 0.0)
}
#[inline]
fn from_parts(re: $t, im: $t) -> Self {
Complex::new(re, im)
}
#[inline]
fn abs(self) -> $t {
Complex::abs(self)
}
#[inline]
fn abs2(self) -> $t {
self.norm_sqr()
}
#[inline]
fn abs1(self) -> $t {
self.re.abs() + self.im.abs()
}
#[inline]
fn scale(self, r: $t) -> Self {
self * r
}
#[inline(always)]
fn mul_sub(self, a: Self, b: Self) -> Self {
let re = $t::mul_add(a.im, b.im, $t::mul_add(-a.re, b.re, self.re));
let im = $t::mul_add(-a.im, b.re, $t::mul_add(-a.re, b.im, self.im));
Complex::new(re, im)
}
#[inline]
fn sqrt(self) -> Self {
Complex::sqrt(self)
}
#[inline]
fn to_complex(self) -> Complex<$t> {
self
}
#[inline]
fn to_c(self) -> Self {
self
}
#[inline]
fn from_c(c: Self) -> Self {
c
}
#[inline]
fn is_finite(self) -> bool {
Complex::is_finite(self)
}
#[inline]
fn gemm_real(
m: usize,
n: usize,
k: usize,
alpha: $t,
a: &[$t],
lda: usize,
b: &[$t],
ldb: usize,
beta: $t,
c: &mut [$t],
ldc: usize,
) {
gemm(m, n, k, alpha, a, lda, Op::N, b, ldb, Op::N, beta, c, ldc);
}
gemm!(complex);
}
};
}
real!(f32);
real!(f64);