use crate::gto::prelude_dev::*;
use num::Zero;
pub use lightweight_simd::{f64x8, Aligned64};
#[deprecated(since = "0.4.0", note = "use `lightweight_simd::Aligned64` (or `f64x8`) directly")]
pub type FpSimd<T, const N: usize = SIMDD> = Aligned64<T, N>;
#[allow(non_camel_case_types)]
#[deprecated(since = "0.4.0", note = "use `lightweight_simd::f64x8` directly")]
pub type f64simd = f64x8;
pub trait IsGtoZero {
fn is_gto_zero(&self) -> bool;
}
impl<const N: usize> IsGtoZero for Aligned64<f64, N> {
#[inline(always)]
fn is_gto_zero(&self) -> bool {
self.as_array().iter().all(|&v| v.abs() <= GTOZERO)
}
}
#[repr(align(64))]
#[derive(Clone, Debug, Copy)]
pub struct Blk<T: Copy, const NLANE: usize>(pub [Aligned64<T, SIMDD>; NLANE]);
#[allow(non_camel_case_types)]
pub type f64blk<const NLANE: usize> = Blk<f64, NLANE>;
#[allow(non_camel_case_types)]
pub type c64blk<const NLANE: usize> = Blk<Complex<f64>, NLANE>;
impl<T: Copy, const NLANE: usize> Index<usize> for Blk<T, NLANE> {
type Output = T;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index / SIMDD][index % SIMDD]
}
}
impl<T: Copy, const NLANE: usize> IndexMut<usize> for Blk<T, NLANE> {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index / SIMDD][index % SIMDD]
}
}
impl<T: Zero + Copy, const NLANE: usize> Blk<T, NLANE> {
#[inline(always)]
#[allow(clippy::uninit_assumed_init)]
#[allow(invalid_value)]
pub unsafe fn uninit() -> Self {
Blk(MaybeUninit::uninit().assume_init())
}
#[inline(always)]
pub const fn splat(val: T) -> Self {
Blk([Aligned64::splat(val); NLANE])
}
#[inline(always)]
pub fn fill(&mut self, val: T) {
for i in 0..NLANE {
self.0[i] = Aligned64::splat(val);
}
}
#[inline(always)]
pub unsafe fn read_ensure(&mut self, src: &[T]) {
for i in 0..NLANE {
self.0[i] = Aligned64([
src[i * SIMDD],
src[i * SIMDD + 1],
src[i * SIMDD + 2],
src[i * SIMDD + 3],
src[i * SIMDD + 4],
src[i * SIMDD + 5],
src[i * SIMDD + 6],
src[i * SIMDD + 7],
]);
}
}
#[inline]
pub fn read(&mut self, src: &[T]) {
let blksize = NLANE * SIMDD;
let len_slc = if src.len() < blksize { src.len() } else { blksize };
if len_slc >= blksize {
unsafe { self.read_ensure(src) }
} else {
for i in 0..len_slc {
self[i] = src[i];
}
}
}
#[inline(always)]
pub unsafe fn write_ensure(&self, dst: &mut [T]) {
for i in 0..NLANE {
dst[i * SIMDD] = self.0[i][0];
dst[i * SIMDD + 1] = self.0[i][1];
dst[i * SIMDD + 2] = self.0[i][2];
dst[i * SIMDD + 3] = self.0[i][3];
dst[i * SIMDD + 4] = self.0[i][4];
dst[i * SIMDD + 5] = self.0[i][5];
dst[i * SIMDD + 6] = self.0[i][6];
dst[i * SIMDD + 7] = self.0[i][7];
}
}
#[inline]
pub fn write(&self, dst: &mut [T]) {
let blksize = NLANE * SIMDD;
let len_slc = if dst.len() < blksize { dst.len() } else { blksize };
if len_slc >= blksize {
unsafe { self.write_ensure(dst) }
} else {
for i in 0..len_slc {
dst[i] = self[i];
}
}
}
}
impl<T: Copy, const NLANE: usize> Blk<T, NLANE> {
#[inline(always)]
pub const fn as_simdd_slice(&self) -> &[Aligned64<T, SIMDD>; NLANE] {
&self.0
}
#[inline(always)]
pub fn as_simdd_slice_mut(&mut self) -> &mut [Aligned64<T, SIMDD>; NLANE] {
&mut self.0
}
#[inline(always)]
pub const fn get_simdd(&self, index: usize) -> Aligned64<T, SIMDD> {
let slice = self.as_simdd_slice();
slice[index]
}
#[inline(always)]
pub fn get_simdd_mut(&mut self, index: usize) -> &mut Aligned64<T, SIMDD> {
let slice = self.as_simdd_slice_mut();
&mut slice[index]
}
}
pub fn gto_l_iter(l: usize) -> Box<dyn Iterator<Item = (usize, usize, usize)>> {
match l {
0 => Box::new(std::iter::once((0, 0, 0))),
1 => Box::new([(1, 0, 0), (0, 1, 0), (0, 0, 1)].into_iter()),
2 => Box::new([(2, 0, 0), (1, 1, 0), (1, 0, 1), (0, 2, 0), (0, 1, 1), (0, 0, 2)].into_iter()),
3 => Box::new(
[(3, 0, 0), (2, 1, 0), (2, 0, 1), (1, 2, 0), (1, 1, 1), (1, 0, 2), (0, 3, 0), (0, 2, 1), (0, 1, 2), (0, 0, 3)].into_iter(),
),
4 => Box::new(
[
(4, 0, 0),
(3, 1, 0),
(3, 0, 1),
(2, 2, 0),
(2, 1, 1),
(2, 0, 2),
(1, 3, 0),
(1, 2, 1),
(1, 1, 2),
(1, 0, 3),
(0, 4, 0),
(0, 3, 1),
(0, 2, 2),
(0, 1, 3),
(0, 0, 4),
]
.into_iter(),
),
5 => Box::new(
[
(5, 0, 0),
(4, 1, 0),
(4, 0, 1),
(3, 2, 0),
(3, 1, 1),
(3, 0, 2),
(2, 3, 0),
(2, 2, 1),
(2, 1, 2),
(2, 0, 3),
(1, 4, 0),
(1, 3, 1),
(1, 2, 2),
(1, 1, 3),
(1, 0, 4),
(0, 5, 0),
(0, 4, 1),
(0, 3, 2),
(0, 2, 3),
(0, 1, 4),
(0, 0, 5),
]
.into_iter(),
),
_ => Box::new((0..=l).flat_map(move |lx| (0..=(l - lx)).map(move |ly| (lx, ly, l - lx - ly)))),
}
}
pub fn gto_nabla1_simdd(f1: &mut [[f64x8; 3]], f0: &[[f64x8; 3]], l: usize, alpha: f64) {
let a2 = f64x8::splat(-2.0 * alpha);
f1[0][X] = a2 * f0[1][X];
f1[0][Y] = a2 * f0[1][Y];
f1[0][Z] = a2 * f0[1][Z];
for i in 1..=l {
let i_f64 = f64x8::splat(i as f64);
f1[i][X] = i_f64 * f0[i - 1][X] + a2 * f0[i + 1][X];
f1[i][Y] = i_f64 * f0[i - 1][Y] + a2 * f0[i + 1][Y];
f1[i][Z] = i_f64 * f0[i - 1][Z] + a2 * f0[i + 1][Z];
}
}
pub fn gto_x1_simdd(f1: &mut [[f64x8; 3]], f0: &[[f64x8; 3]], l: usize, ri: [f64; 3]) {
let ri_x = f64x8::splat(ri[X]);
let ri_y = f64x8::splat(ri[Y]);
let ri_z = f64x8::splat(ri[Z]);
for i in 0..=l {
f1[i][X] = f0[i][X].mul_add(ri_x, f0[i + 1][X]);
f1[i][Y] = f0[i][Y].mul_add(ri_y, f0[i + 1][Y]);
f1[i][Z] = f0[i][Z].mul_add(ri_z, f0[i + 1][Z]);
}
}
pub fn gto_r_simdd(f1: &mut [[f64x8; 3]], f0: &[[f64x8; 3]], l: usize) {
for i in 0..=l {
f1[i][X] = f0[i + 1][X];
f1[i][Y] = f0[i + 1][Y];
f1[i][Z] = f0[i + 1][Z];
}
}
pub fn gto_prim_exp<const NLANE: usize>(eprim: &mut [f64blk<NLANE>], coord: &[f64blk<NLANE>; 3], alpha: &[f64], fac: f64, nprim: usize) {
let mut rr = unsafe { f64blk::<NLANE>::uninit() };
for g in 0..NLANE {
let x = coord[0].get_simdd(g);
let y = coord[1].get_simdd(g);
let z = coord[2].get_simdd(g);
*rr.get_simdd_mut(g) = x * x + y * y + z * z;
}
for p in 0..nprim {
for g in 0..NLANE {
let arr = rr.get_simdd(g) * alpha[p];
*eprim[p].get_simdd_mut(g) = (-arr).map(f64::exp) * fac;
}
}
}
#[test]
fn test_blkf64_uninit() {
#[allow(clippy::uninit_assumed_init)]
#[allow(invalid_value)]
let v: [[f64blk<48>; 10]; 10] = unsafe { [[f64blk::uninit(); 10]; 10] };
println!("{:?}", v);
}