1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::missing_safety_doc)]
3#![allow(clippy::type_complexity)]
4#![allow(clippy::too_many_arguments)]
5#![forbid(elided_lifetimes_in_paths)]
6#![allow(non_snake_case)]
7
8use bytemuck::Pod;
9use dyn_stack::{PodStack, SizeOverflow, StackReq};
10use faer_core::{
11 group_helpers::*,
12 permutation::PermutationRef,
13 sparse::{windows2, *},
14 Entity, Side,
15};
16
17const CHOLESKY_SUPERNODAL_RATIO_FACTOR: f64 = 40.0;
18const QR_SUPERNODAL_RATIO_FACTOR: f64 = 40.0;
19const LU_SUPERNODAL_RATIO_FACTOR: f64 = 40.0;
20
21#[derive(Copy, Clone, Debug)]
22pub struct SymbolicSupernodalParams<'a> {
23 pub relax: Option<&'a [(usize, f64)]>,
24}
25
26impl Default for SymbolicSupernodalParams<'_> {
27 #[inline]
28 fn default() -> Self {
29 Self {
30 relax: Some(&[(4, 1.0), (16, 0.8), (48, 0.1), (usize::MAX, 0.05)]),
31 }
32 }
33}
34
35#[derive(Copy, Clone, Debug, PartialEq)]
36pub struct SupernodalThreshold(pub f64);
37
38impl Default for SupernodalThreshold {
39 #[inline]
40 fn default() -> Self {
41 Self(1.0)
42 }
43}
44
45impl SupernodalThreshold {
46 pub const FORCE_SIMPLICIAL: Self = Self(f64::INFINITY);
47 pub const FORCE_SUPERNODAL: Self = Self(0.0);
48 pub const AUTO: Self = Self(1.0);
49}
50
51use faer_core::sparse::util::{
52 ghost_adjoint_symbolic, ghost_permute_hermitian_unsorted,
53 ghost_permute_hermitian_unsorted_symbolic, transpose,
54};
55
56pub use faer_core::{
57 permutation::{Index, SignedIndex},
58 FaerError,
59};
60
61#[allow(unused_macros)]
62macro_rules! shadow {
63 ($id: ident) => {
64 let $id = {
65 struct Shadowed;
66 impl ::core::ops::Drop for Shadowed {
67 fn drop(&mut self) {}
68 }
69 Shadowed
70 };
71 ::core::mem::drop($id);
72 };
73}
74
75macro_rules! impl_copy {
76 (< $($lt_param: lifetime),* >< $($ty_param: ident $(: $tt: tt)?),* > <$ty: ty>) => {
77 impl<$($lt_param,)* $($ty_param $(: $tt)?,)*> Copy for $ty {}
78 impl<$($lt_param,)* $($ty_param $(: $tt)?,)*> Clone for $ty {
79 #[inline(always)]
80 fn clone(&self) -> Self {
81 *self
82 }
83 }
84 };
85}
86
87#[inline]
88#[track_caller]
89fn try_zeroed<I: Pod>(n: usize) -> Result<alloc::vec::Vec<I>, FaerError> {
90 let mut v = alloc::vec::Vec::new();
91 v.try_reserve_exact(n).map_err(nomem)?;
92 unsafe {
93 core::ptr::write_bytes::<I>(v.as_mut_ptr(), 0u8, n);
94 v.set_len(n);
95 }
96 Ok(v)
97}
98
99#[inline]
100#[track_caller]
101fn try_collect<I: IntoIterator>(iter: I) -> Result<alloc::vec::Vec<I::Item>, FaerError> {
102 let iter = iter.into_iter();
103 let mut v = alloc::vec::Vec::new();
104 v.try_reserve_exact(iter.size_hint().0).map_err(nomem)?;
105 v.extend(iter);
106 Ok(v)
107}
108
109#[inline]
110fn nomem<T>(_: T) -> FaerError {
111 FaerError::OutOfMemory
112}
113
114fn make_raw_req<E: Entity>(size: usize) -> Result<StackReq, SizeOverflow> {
115 let req = Ok(StackReq::empty());
116 let additional = StackReq::try_new::<E::Unit>(size)?;
117 let (req, _) = E::faer_map_with_context(req, E::UNIT, &mut {
118 #[inline(always)]
119 |req, ()| {
120 let req = match req {
121 Ok(req) => req.try_and(additional),
122 _ => Err(SizeOverflow),
123 };
124 (req, ())
125 }
126 });
127 req
128}
129
130fn make_raw<E: Entity>(size: usize, stack: PodStack<'_>) -> (SliceGroupMut<'_, E>, PodStack<'_>) {
131 let (stack, array) = E::faer_map_with_context(stack, E::UNIT, &mut {
132 #[inline(always)]
133 |stack, ()| {
134 let (alloc, stack) = stack.make_raw::<E::Unit>(size);
135 (stack, alloc)
136 }
137 });
138 (SliceGroupMut::new(array), stack)
139}
140
141#[cfg(test)]
142macro_rules! monomorphize_test {
143 ($name: ident) => {
144 monomorphize_test!($name, u32);
145 monomorphize_test!($name, u64);
146 };
147
148 ($name: ident, $ty: ident) => {
149 paste::paste! {
150 #[test]
151 fn [<$name _ $ty>]() {
152 $name::<$ty>();
153 }
154 }
155 };
156}
157
158extern crate alloc;
159
160pub mod triangular_solve;
161
162pub mod amd;
163pub mod colamd;
164
165pub mod cholesky;
166
167#[doc(hidden)]
168pub mod lu;
169#[doc(hidden)]
170pub mod qr;
171
172#[doc(hidden)]
173pub mod superlu;
174
175mod ghost;
176
177mod mem;
178
179#[cfg(test)]
180pub(crate) mod qd {
181 use bytemuck::{Pod, Zeroable};
185 use faer_entity::*;
186 use pulp::{Scalar, Simd};
187
188 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
191 #[repr(C)]
192 pub struct Double<T>(pub T, pub T);
193
194 unsafe impl<T: Zeroable> Zeroable for Double<T> {}
195 unsafe impl<T: Pod> Pod for Double<T> {}
196
197 impl<I: Iterator> Iterator for Double<I> {
198 type Item = Double<I::Item>;
199
200 #[inline(always)]
201 fn next(&mut self) -> Option<Self::Item> {
202 let x0 = self.0.next()?;
203 let x1 = self.1.next()?;
204 Some(Double(x0, x1))
205 }
206 }
207
208 #[inline(always)]
209 fn quick_two_sum<S: Simd>(simd: S, a: S::f64s, b: S::f64s) -> (S::f64s, S::f64s) {
210 let s = simd.f64s_add(a, b);
211 let err = simd.f64s_sub(b, simd.f64s_sub(s, a));
212 (s, err)
213 }
214
215 #[inline(always)]
216 fn two_sum<S: Simd>(simd: S, a: S::f64s, b: S::f64s) -> (S::f64s, S::f64s) {
217 let s = simd.f64s_add(a, b);
218 let bb = simd.f64s_sub(s, a);
219
220 let err = simd.f64s_add(simd.f64s_sub(a, simd.f64s_sub(s, bb)), simd.f64s_sub(b, bb));
222 (s, err)
223 }
224
225 #[inline(always)]
226 #[allow(dead_code)]
227 fn quick_two_diff<S: Simd>(simd: S, a: S::f64s, b: S::f64s) -> (S::f64s, S::f64s) {
228 let s = simd.f64s_sub(a, b);
229 let err = simd.f64s_sub(simd.f64s_sub(a, s), b);
230 (s, err)
231 }
232
233 #[inline(always)]
234 fn two_diff<S: Simd>(simd: S, a: S::f64s, b: S::f64s) -> (S::f64s, S::f64s) {
235 let s = simd.f64s_sub(a, b);
236 let bb = simd.f64s_sub(s, a);
237
238 let err = simd.f64s_sub(simd.f64s_sub(a, simd.f64s_sub(s, bb)), simd.f64s_add(b, bb));
240 (s, err)
241 }
242
243 #[inline(always)]
244 fn two_prod<S: Simd>(simd: S, a: S::f64s, b: S::f64s) -> (S::f64s, S::f64s) {
245 let p = simd.f64s_mul(a, b);
246 let err = simd.f64s_mul_add(a, b, simd.f64s_neg(p));
247
248 (p, err)
249 }
250
251 pub mod double {
252 use super::*;
253
254 #[inline(always)]
255 pub fn simd_add<S: Simd>(
256 simd: S,
257 a: Double<S::f64s>,
258 b: Double<S::f64s>,
259 ) -> Double<S::f64s> {
260 let (s, e) = two_sum(simd, a.0, b.0);
261 let e = simd.f64s_add(e, simd.f64s_add(a.1, b.1));
262 let (s, e) = quick_two_sum(simd, s, e);
263 Double(s, e)
264 }
265
266 #[inline(always)]
267 pub fn simd_sub<S: Simd>(
268 simd: S,
269 a: Double<S::f64s>,
270 b: Double<S::f64s>,
271 ) -> Double<S::f64s> {
272 let (s, e) = two_diff(simd, a.0, b.0);
273 let e = simd.f64s_add(e, a.1);
274 let e = simd.f64s_sub(e, b.1);
275 let (s, e) = quick_two_sum(simd, s, e);
276 Double(s, e)
277 }
278
279 #[inline(always)]
280 pub fn simd_neg<S: Simd>(simd: S, a: Double<S::f64s>) -> Double<S::f64s> {
281 Double(simd.f64s_neg(a.0), simd.f64s_neg(a.1))
282 }
283
284 #[inline(always)]
285 pub fn simd_mul<S: Simd>(
286 simd: S,
287 a: Double<S::f64s>,
288 b: Double<S::f64s>,
289 ) -> Double<S::f64s> {
290 let (p1, p2) = two_prod(simd, a.0, b.0);
291 let p2 = simd.f64s_add(
292 p2,
293 simd.f64s_add(simd.f64s_mul(a.0, b.1), simd.f64s_mul(a.1, b.0)),
294 );
295 let (p1, p2) = quick_two_sum(simd, p1, p2);
296 Double(p1, p2)
297 }
298
299 #[inline(always)]
300 fn simd_mul_f64<S: Simd>(simd: S, a: Double<S::f64s>, b: S::f64s) -> Double<S::f64s> {
301 let (p1, p2) = two_prod(simd, a.0, b);
302 let p2 = simd.f64s_add(p2, simd.f64s_mul(a.1, b));
303 let (p1, p2) = quick_two_sum(simd, p1, p2);
304 Double(p1, p2)
305 }
306
307 pub fn simd_select<S: Simd>(
308 simd: S,
309 mask: S::m64s,
310 if_true: Double<S::f64s>,
311 if_false: Double<S::f64s>,
312 ) -> Double<S::f64s> {
313 Double(
314 simd.m64s_select_f64s(mask, if_true.0, if_false.0),
315 simd.m64s_select_f64s(mask, if_true.1, if_false.1),
316 )
317 }
318
319 #[inline]
320 pub fn simd_div<S: Simd>(
321 simd: S,
322 a: Double<S::f64s>,
323 b: Double<S::f64s>,
324 ) -> Double<S::f64s> {
325 simd.vectorize(
326 #[inline(always)]
327 || {
328 let pos_zero = simd.f64s_splat(0.0);
329 let pos_infty = simd.f64s_splat(f64::INFINITY);
330 let sign_bit = simd.f64s_splat(-0.0);
331
332 let a_sign = simd.f64s_and(a.0, sign_bit);
333 let b_sign = simd.f64s_and(b.0, sign_bit);
334
335 let combined_sign = simd.f64s_xor(a_sign, b_sign);
336
337 let a_is_zero = simd_eq(simd, a, Double(pos_zero, pos_zero));
338 let b_is_zero = simd_eq(simd, b, Double(pos_zero, pos_zero));
339 let a_is_infty = simd_eq(
340 simd,
341 Double(simd.f64s_abs(a.0), simd.f64s_abs(a.1)),
342 Double(pos_infty, pos_infty),
343 );
344 let b_is_infty = simd_eq(
345 simd,
346 Double(simd.f64s_abs(b.0), simd.f64s_abs(b.1)),
347 Double(pos_infty, pos_infty),
348 );
349
350 let q1 = simd.f64s_div(a.0, b.0);
351 let r = simd_mul_f64(simd, b, q1);
352
353 let (s1, s2) = two_diff(simd, a.0, r.0);
354 let s2 = simd.f64s_sub(s2, r.1);
355 let s2 = simd.f64s_add(s2, a.1);
356
357 let q2 = simd.f64s_div(simd.f64s_add(s1, s2), b.0);
358 let (q0, q1) = quick_two_sum(simd, q1, q2);
359
360 simd_select(
361 simd,
362 simd.m64s_and(b_is_zero, simd.m64s_not(a_is_zero)),
363 Double(
364 simd.f64s_or(combined_sign, pos_infty),
365 simd.f64s_or(combined_sign, pos_infty),
366 ),
367 simd_select(
368 simd,
369 simd.m64s_and(b_is_infty, simd.m64s_not(a_is_infty)),
370 Double(
371 simd.f64s_or(combined_sign, pos_zero),
372 simd.f64s_or(combined_sign, pos_zero),
373 ),
374 Double(q0, q1),
375 ),
376 )
377 },
378 )
379 }
380
381 #[inline(always)]
382 pub fn simd_abs<S: Simd>(simd: S, a: Double<S::f64s>) -> Double<S::f64s> {
383 let is_negative = simd.f64s_less_than(a.0, simd.f64s_splat(0.0));
384 Double(
385 simd.m64s_select_f64s(is_negative, simd.f64s_neg(a.0), a.0),
386 simd.m64s_select_f64s(is_negative, simd.f64s_neg(a.1), a.1),
387 )
388 }
389
390 #[inline(always)]
391 pub fn simd_less_than<S: Simd>(simd: S, a: Double<S::f64s>, b: Double<S::f64s>) -> S::m64s {
392 let lt0 = simd.f64s_less_than(a.0, b.0);
393 let eq0 = simd.f64s_equal(a.0, b.0);
394 let lt1 = simd.f64s_less_than(a.1, b.1);
395 simd.m64s_or(lt0, simd.m64s_and(eq0, lt1))
396 }
397
398 #[inline(always)]
399 pub fn simd_less_than_or_equal<S: Simd>(
400 simd: S,
401 a: Double<S::f64s>,
402 b: Double<S::f64s>,
403 ) -> S::m64s {
404 let lt0 = simd.f64s_less_than(a.0, b.0);
405 let eq0 = simd.f64s_equal(a.0, b.0);
406 let lt1 = simd.f64s_less_than_or_equal(a.1, b.1);
407 simd.m64s_or(lt0, simd.m64s_and(eq0, lt1))
408 }
409
410 #[inline(always)]
411 pub fn simd_greater_than<S: Simd>(
412 simd: S,
413 a: Double<S::f64s>,
414 b: Double<S::f64s>,
415 ) -> S::m64s {
416 let lt0 = simd.f64s_greater_than(a.0, b.0);
417 let eq0 = simd.f64s_equal(a.0, b.0);
418 let lt1 = simd.f64s_greater_than(a.1, b.1);
419 simd.m64s_or(lt0, simd.m64s_and(eq0, lt1))
420 }
421
422 #[inline(always)]
423 pub fn simd_greater_than_or_equal<S: Simd>(
424 simd: S,
425 a: Double<S::f64s>,
426 b: Double<S::f64s>,
427 ) -> S::m64s {
428 let lt0 = simd.f64s_greater_than(a.0, b.0);
429 let eq0 = simd.f64s_equal(a.0, b.0);
430 let lt1 = simd.f64s_greater_than_or_equal(a.1, b.1);
431 simd.m64s_or(lt0, simd.m64s_and(eq0, lt1))
432 }
433
434 #[inline(always)]
435 pub fn simd_eq<S: Simd>(simd: S, a: Double<S::f64s>, b: Double<S::f64s>) -> S::m64s {
436 let eq0 = simd.f64s_equal(a.0, b.0);
437 let eq1 = simd.f64s_equal(a.1, b.1);
438 simd.m64s_and(eq0, eq1)
439 }
440 }
441
442 impl core::ops::Add for Double<f64> {
443 type Output = Self;
444
445 #[inline(always)]
446 fn add(self, rhs: Self) -> Self::Output {
447 double::simd_add(Scalar::new(), self, rhs)
448 }
449 }
450
451 impl core::ops::Sub for Double<f64> {
452 type Output = Self;
453
454 #[inline(always)]
455 fn sub(self, rhs: Self) -> Self::Output {
456 double::simd_sub(Scalar::new(), self, rhs)
457 }
458 }
459
460 impl core::ops::Mul for Double<f64> {
461 type Output = Self;
462
463 #[inline(always)]
464 fn mul(self, rhs: Self) -> Self::Output {
465 double::simd_mul(Scalar::new(), self, rhs)
466 }
467 }
468
469 impl core::ops::Div for Double<f64> {
470 type Output = Self;
471
472 #[inline(always)]
473 fn div(self, rhs: Self) -> Self::Output {
474 double::simd_div(Scalar::new(), self, rhs)
475 }
476 }
477
478 impl core::ops::AddAssign for Double<f64> {
479 #[inline(always)]
480 fn add_assign(&mut self, rhs: Self) {
481 *self = *self + rhs;
482 }
483 }
484
485 impl core::ops::SubAssign for Double<f64> {
486 #[inline(always)]
487 fn sub_assign(&mut self, rhs: Self) {
488 *self = *self - rhs;
489 }
490 }
491
492 impl core::ops::MulAssign for Double<f64> {
493 #[inline(always)]
494 fn mul_assign(&mut self, rhs: Self) {
495 *self = *self * rhs;
496 }
497 }
498
499 impl core::ops::DivAssign for Double<f64> {
500 #[inline(always)]
501 fn div_assign(&mut self, rhs: Self) {
502 *self = *self / rhs;
503 }
504 }
505
506 impl core::ops::Neg for Double<f64> {
507 type Output = Self;
508
509 #[inline(always)]
510 fn neg(self) -> Self::Output {
511 Self(-self.0, -self.1)
512 }
513 }
514
515 impl Double<f64> {
516 pub const EPSILON: Self = Self(7.888609052210118e-31, 0.0);
518 pub const MIN_POSITIVE: Self = Self(1.0020841800044864e-292, 0.0);
520
521 pub const ZERO: Self = Self(0.0, 0.0);
522 pub const NAN: Self = Self(f64::NAN, f64::NAN);
523 pub const INFINITY: Self = Self(f64::INFINITY, f64::INFINITY);
524
525 #[inline(always)]
526 pub fn abs(self) -> Self {
527 double::simd_abs(Scalar::new(), self)
528 }
529
530 #[inline(always)]
531 pub fn recip(self) -> Self {
532 double::simd_div(Scalar::new(), Self(1.0, 0.0), self)
533 }
534
535 #[inline]
536 pub fn sqrt(self) -> Self {
537 if self == Self::ZERO {
538 Self::ZERO
539 } else if self < Self::ZERO {
540 Self::NAN
541 } else if self == Self::INFINITY {
542 Self::INFINITY
543 } else {
544 let a = self;
545 let x = a.0.sqrt().recip();
546 let ax = Self(a.0 * x, 0.0);
547
548 ax + (a - ax * ax) * Double(x * 0.5, 0.0)
549 }
550 }
551 }
552
553 pub struct DoubleGroup {
554 __private: (),
555 }
556
557 impl ForType for DoubleGroup {
558 type FaerOf<T> = Double<T>;
559 }
560 impl ForCopyType for DoubleGroup {
561 type FaerOfCopy<T: Copy> = Double<T>;
562 }
563 impl ForDebugType for DoubleGroup {
564 type FaerOfDebug<T: core::fmt::Debug> = Double<T>;
565 }
566
567 mod faer_impl {
568 use super::*;
569 use faer_core::{ComplexField, Conjugate, Entity, RealField};
570
571 unsafe impl Entity for Double<f64> {
572 type Unit = f64;
573 type Index = u64;
574
575 type SimdUnit<S: Simd> = S::f64s;
576 type SimdMask<S: Simd> = S::m64s;
577 type SimdIndex<S: Simd> = S::u64s;
578
579 type Group = DoubleGroup;
580 type Iter<I: Iterator> = Double<I>;
581
582 type PrefixUnit<'a, S: Simd> = pulp::Prefix<'a, f64, S, S::m64s>;
583 type SuffixUnit<'a, S: Simd> = pulp::Suffix<'a, f64, S, S::m64s>;
584 type PrefixMutUnit<'a, S: Simd> = pulp::PrefixMut<'a, f64, S, S::m64s>;
585 type SuffixMutUnit<'a, S: Simd> = pulp::SuffixMut<'a, f64, S, S::m64s>;
586
587 const N_COMPONENTS: usize = 2;
588 const UNIT: GroupCopyFor<Self, ()> = Double((), ());
589
590 #[inline(always)]
591 fn faer_first<T>(group: GroupFor<Self, T>) -> T {
592 group.0
593 }
594
595 #[inline(always)]
596 fn faer_from_units(group: GroupFor<Self, Self::Unit>) -> Self {
597 group
598 }
599
600 #[inline(always)]
601 fn faer_into_units(self) -> GroupFor<Self, Self::Unit> {
602 self
603 }
604
605 #[inline(always)]
606 fn faer_as_ref<T>(group: &GroupFor<Self, T>) -> GroupFor<Self, &T> {
607 Double(&group.0, &group.1)
608 }
609
610 #[inline(always)]
611 fn faer_as_mut<T>(group: &mut GroupFor<Self, T>) -> GroupFor<Self, &mut T> {
612 Double(&mut group.0, &mut group.1)
613 }
614
615 #[inline(always)]
616 fn faer_as_ptr<T>(group: *mut GroupFor<Self, T>) -> GroupFor<Self, *mut T> {
617 unsafe {
618 Double(
619 core::ptr::addr_of_mut!((*group).0),
620 core::ptr::addr_of_mut!((*group).1),
621 )
622 }
623 }
624
625 #[inline(always)]
626 fn faer_map_impl<T, U>(
627 group: GroupFor<Self, T>,
628 f: &mut impl FnMut(T) -> U,
629 ) -> GroupFor<Self, U> {
630 Double((*f)(group.0), (*f)(group.1))
631 }
632
633 #[inline(always)]
634 fn faer_zip<T, U>(
635 first: GroupFor<Self, T>,
636 second: GroupFor<Self, U>,
637 ) -> GroupFor<Self, (T, U)> {
638 Double((first.0, second.0), (first.1, second.1))
639 }
640
641 #[inline(always)]
642 fn faer_unzip<T, U>(
643 zipped: GroupFor<Self, (T, U)>,
644 ) -> (GroupFor<Self, T>, GroupFor<Self, U>) {
645 (
646 Double(zipped.0 .0, zipped.1 .0),
647 Double(zipped.0 .1, zipped.1 .1),
648 )
649 }
650
651 #[inline(always)]
652 fn faer_map_with_context<Ctx, T, U>(
653 ctx: Ctx,
654 group: GroupFor<Self, T>,
655 f: &mut impl FnMut(Ctx, T) -> (Ctx, U),
656 ) -> (Ctx, GroupFor<Self, U>) {
657 let (ctx, x0) = (*f)(ctx, group.0);
658 let (ctx, x1) = (*f)(ctx, group.1);
659 (ctx, Double(x0, x1))
660 }
661
662 #[inline(always)]
663 fn faer_into_iter<I: IntoIterator>(iter: GroupFor<Self, I>) -> Self::Iter<I::IntoIter> {
664 Double(iter.0.into_iter(), iter.1.into_iter())
665 }
666 }
667
668 unsafe impl Conjugate for Double<f64> {
669 type Conj = Double<f64>;
670 type Canonical = Double<f64>;
671 #[inline(always)]
672 fn canonicalize(self) -> Self::Canonical {
673 self
674 }
675 }
676
677 impl RealField for Double<f64> {
678 #[inline(always)]
679 fn faer_epsilon() -> Option<Self> {
680 Some(Self::EPSILON)
681 }
682 #[inline(always)]
683 fn faer_zero_threshold() -> Option<Self> {
684 Some(Self::MIN_POSITIVE)
685 }
686
687 #[inline(always)]
688 fn faer_div(self, rhs: Self) -> Self {
689 self / rhs
690 }
691
692 #[inline(always)]
693 fn faer_usize_to_index(a: usize) -> Self::Index {
694 a as _
695 }
696
697 #[inline(always)]
698 fn faer_index_to_usize(a: Self::Index) -> usize {
699 a as _
700 }
701
702 #[inline(always)]
703 fn faer_max_index() -> Self::Index {
704 Self::Index::MAX
705 }
706
707 #[inline(always)]
708 fn faer_simd_less_than<S: Simd>(
709 simd: S,
710 a: SimdGroupFor<Self, S>,
711 b: SimdGroupFor<Self, S>,
712 ) -> Self::SimdMask<S> {
713 double::simd_less_than(simd, a, b)
714 }
715
716 #[inline(always)]
717 fn faer_simd_less_than_or_equal<S: Simd>(
718 simd: S,
719 a: SimdGroupFor<Self, S>,
720 b: SimdGroupFor<Self, S>,
721 ) -> Self::SimdMask<S> {
722 double::simd_less_than_or_equal(simd, a, b)
723 }
724
725 #[inline(always)]
726 fn faer_simd_greater_than<S: Simd>(
727 simd: S,
728 a: SimdGroupFor<Self, S>,
729 b: SimdGroupFor<Self, S>,
730 ) -> Self::SimdMask<S> {
731 double::simd_greater_than(simd, a, b)
732 }
733
734 #[inline(always)]
735 fn faer_simd_greater_than_or_equal<S: Simd>(
736 simd: S,
737 a: SimdGroupFor<Self, S>,
738 b: SimdGroupFor<Self, S>,
739 ) -> Self::SimdMask<S> {
740 double::simd_greater_than_or_equal(simd, a, b)
741 }
742
743 #[inline(always)]
744 fn faer_simd_select<S: Simd>(
745 simd: S,
746 mask: Self::SimdMask<S>,
747 if_true: SimdGroupFor<Self, S>,
748 if_false: SimdGroupFor<Self, S>,
749 ) -> SimdGroupFor<Self, S> {
750 double::simd_select(simd, mask, if_true, if_false)
751 }
752
753 #[inline(always)]
754 fn faer_simd_index_select<S: Simd>(
755 simd: S,
756 mask: Self::SimdMask<S>,
757 if_true: Self::SimdIndex<S>,
758 if_false: Self::SimdIndex<S>,
759 ) -> Self::SimdIndex<S> {
760 simd.m64s_select_u64s(mask, if_true, if_false)
761 }
762
763 #[inline(always)]
764 fn faer_simd_index_seq<S: Simd>(simd: S) -> Self::SimdIndex<S> {
765 let _ = simd;
766 pulp::cast_lossy([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15_u64])
767 }
768
769 #[inline(always)]
770 fn faer_simd_index_splat<S: Simd>(simd: S, value: Self::Index) -> Self::SimdIndex<S> {
771 simd.u64s_splat(value)
772 }
773
774 #[inline(always)]
775 fn faer_simd_index_add<S: Simd>(
776 simd: S,
777 a: Self::SimdIndex<S>,
778 b: Self::SimdIndex<S>,
779 ) -> Self::SimdIndex<S> {
780 simd.u64s_add(a, b)
781 }
782
783 #[inline(always)]
784 fn faer_min_positive() -> Self {
785 Self::MIN_POSITIVE
786 }
787
788 #[inline(always)]
789 fn faer_min_positive_inv() -> Self {
790 Self::MIN_POSITIVE.recip()
791 }
792
793 #[inline(always)]
794 fn faer_min_positive_sqrt() -> Self {
795 Self::MIN_POSITIVE.sqrt()
796 }
797
798 #[inline(always)]
799 fn faer_min_positive_sqrt_inv() -> Self {
800 Self::MIN_POSITIVE.sqrt().recip()
801 }
802
803 #[inline(always)]
804 fn faer_simd_index_rotate_left<S: Simd>(
805 simd: S,
806 values: SimdIndexFor<Self, S>,
807 amount: usize,
808 ) -> SimdIndexFor<Self, S> {
809 simd.u64s_rotate_left(values, amount)
810 }
811
812 #[inline(always)]
813 fn faer_simd_abs<S: Simd>(
814 simd: S,
815 values: SimdGroupFor<Self, S>,
816 ) -> SimdGroupFor<Self, S> {
817 double::simd_abs(simd, values)
818 }
819 }
820
821 impl ComplexField for Double<f64> {
822 type Real = Double<f64>;
823 type Simd = pulp::Arch;
824 type ScalarSimd = pulp::Arch;
825 type PortableSimd = pulp::Arch;
826
827 #[inline(always)]
828 fn faer_sqrt(self) -> Self {
829 self.sqrt()
830 }
831
832 #[inline(always)]
833 fn faer_from_f64(value: f64) -> Self {
834 Self(value, 0.0)
835 }
836
837 #[inline(always)]
838 fn faer_add(self, rhs: Self) -> Self {
839 self + rhs
840 }
841
842 #[inline(always)]
843 fn faer_sub(self, rhs: Self) -> Self {
844 self - rhs
845 }
846
847 #[inline(always)]
848 fn faer_mul(self, rhs: Self) -> Self {
849 self * rhs
850 }
851
852 #[inline(always)]
853 fn faer_neg(self) -> Self {
854 -self
855 }
856
857 #[inline(always)]
858 fn faer_inv(self) -> Self {
859 self.recip()
860 }
861
862 #[inline(always)]
863 fn faer_conj(self) -> Self {
864 self
865 }
866
867 #[inline(always)]
868 fn faer_scale_real(self, rhs: Self::Real) -> Self {
869 self * rhs
870 }
871
872 #[inline(always)]
873 fn faer_scale_power_of_two(self, rhs: Self::Real) -> Self {
874 Self(self.0 * rhs.0, self.1 * rhs.0)
875 }
876
877 #[inline(always)]
878 fn faer_score(self) -> Self::Real {
879 self.abs()
880 }
881
882 #[inline(always)]
883 fn faer_abs(self) -> Self::Real {
884 self.abs()
885 }
886
887 #[inline(always)]
888 fn faer_abs2(self) -> Self::Real {
889 self * self
890 }
891
892 #[inline(always)]
893 fn faer_nan() -> Self {
894 Self::NAN
895 }
896
897 #[inline(always)]
898 fn faer_from_real(real: Self::Real) -> Self {
899 real
900 }
901
902 #[inline(always)]
903 fn faer_real(self) -> Self::Real {
904 self
905 }
906
907 #[inline(always)]
908 fn faer_imag(self) -> Self::Real {
909 Self::ZERO
910 }
911
912 #[inline(always)]
913 fn faer_zero() -> Self {
914 Self::ZERO
915 }
916
917 #[inline(always)]
918 fn faer_one() -> Self {
919 Self(1.0, 0.0)
920 }
921
922 #[inline(always)]
923 fn faer_slice_as_simd<S: Simd>(
924 slice: &[Self::Unit],
925 ) -> (&[Self::SimdUnit<S>], &[Self::Unit]) {
926 S::f64s_as_simd(slice)
927 }
928
929 #[inline(always)]
930 fn faer_slice_as_simd_mut<S: Simd>(
931 slice: &mut [Self::Unit],
932 ) -> (&mut [Self::SimdUnit<S>], &mut [Self::Unit]) {
933 S::f64s_as_mut_simd(slice)
934 }
935
936 #[inline(always)]
937 fn faer_partial_load_unit<S: Simd>(simd: S, slice: &[Self::Unit]) -> Self::SimdUnit<S> {
938 simd.f64s_partial_load(slice)
939 }
940
941 #[inline(always)]
942 fn faer_partial_store_unit<S: Simd>(
943 simd: S,
944 slice: &mut [Self::Unit],
945 values: Self::SimdUnit<S>,
946 ) {
947 simd.f64s_partial_store(slice, values)
948 }
949
950 #[inline(always)]
951 fn faer_partial_load_last_unit<S: Simd>(
952 simd: S,
953 slice: &[Self::Unit],
954 ) -> Self::SimdUnit<S> {
955 simd.f64s_partial_load_last(slice)
956 }
957
958 #[inline(always)]
959 fn faer_partial_store_last_unit<S: Simd>(
960 simd: S,
961 slice: &mut [Self::Unit],
962 values: Self::SimdUnit<S>,
963 ) {
964 simd.f64s_partial_store_last(slice, values)
965 }
966
967 #[inline(always)]
968 fn faer_simd_splat_unit<S: Simd>(simd: S, unit: Self::Unit) -> Self::SimdUnit<S> {
969 simd.f64s_splat(unit)
970 }
971
972 #[inline(always)]
973 fn faer_simd_neg<S: Simd>(
974 simd: S,
975 values: SimdGroupFor<Self, S>,
976 ) -> SimdGroupFor<Self, S> {
977 double::simd_neg(simd, values)
978 }
979
980 #[inline(always)]
981 fn faer_simd_conj<S: Simd>(
982 simd: S,
983 values: SimdGroupFor<Self, S>,
984 ) -> SimdGroupFor<Self, S> {
985 let _ = simd;
986 values
987 }
988
989 #[inline(always)]
990 fn faer_simd_add<S: Simd>(
991 simd: S,
992 lhs: SimdGroupFor<Self, S>,
993 rhs: SimdGroupFor<Self, S>,
994 ) -> SimdGroupFor<Self, S> {
995 double::simd_add(simd, lhs, rhs)
996 }
997
998 #[inline(always)]
999 fn faer_simd_sub<S: Simd>(
1000 simd: S,
1001 lhs: SimdGroupFor<Self, S>,
1002 rhs: SimdGroupFor<Self, S>,
1003 ) -> SimdGroupFor<Self, S> {
1004 double::simd_sub(simd, lhs, rhs)
1005 }
1006
1007 #[inline(always)]
1008 fn faer_simd_mul<S: Simd>(
1009 simd: S,
1010 lhs: SimdGroupFor<Self, S>,
1011 rhs: SimdGroupFor<Self, S>,
1012 ) -> SimdGroupFor<Self, S> {
1013 double::simd_mul(simd, lhs, rhs)
1014 }
1015
1016 #[inline(always)]
1017 fn faer_simd_scale_real<S: Simd>(
1018 simd: S,
1019 lhs: SimdGroupFor<Self, S>,
1020 rhs: SimdGroupFor<Self, S>,
1021 ) -> SimdGroupFor<Self, S> {
1022 double::simd_mul(simd, lhs, rhs)
1023 }
1024
1025 #[inline(always)]
1026 fn faer_simd_conj_mul<S: Simd>(
1027 simd: S,
1028 lhs: SimdGroupFor<Self, S>,
1029 rhs: SimdGroupFor<Self, S>,
1030 ) -> SimdGroupFor<Self, S> {
1031 double::simd_mul(simd, lhs, rhs)
1032 }
1033
1034 #[inline(always)]
1035 fn faer_simd_mul_adde<S: Simd>(
1036 simd: S,
1037 lhs: SimdGroupFor<Self, S>,
1038 rhs: SimdGroupFor<Self, S>,
1039 acc: SimdGroupFor<Self, S>,
1040 ) -> SimdGroupFor<Self, S> {
1041 double::simd_add(simd, acc, double::simd_mul(simd, lhs, rhs))
1042 }
1043
1044 #[inline(always)]
1045 fn faer_simd_conj_mul_adde<S: Simd>(
1046 simd: S,
1047 lhs: SimdGroupFor<Self, S>,
1048 rhs: SimdGroupFor<Self, S>,
1049 acc: SimdGroupFor<Self, S>,
1050 ) -> SimdGroupFor<Self, S> {
1051 double::simd_add(simd, acc, double::simd_mul(simd, lhs, rhs))
1052 }
1053
1054 #[inline(always)]
1055 fn faer_simd_score<S: Simd>(
1056 simd: S,
1057 values: SimdGroupFor<Self, S>,
1058 ) -> SimdGroupFor<Self::Real, S> {
1059 double::simd_abs(simd, values)
1060 }
1061
1062 #[inline(always)]
1063 fn faer_simd_abs2_adde<S: Simd>(
1064 simd: S,
1065 values: SimdGroupFor<Self, S>,
1066 acc: SimdGroupFor<Self::Real, S>,
1067 ) -> SimdGroupFor<Self::Real, S> {
1068 Self::faer_simd_add(simd, acc, Self::faer_simd_mul(simd, values, values))
1069 }
1070
1071 #[inline(always)]
1072 fn faer_simd_abs2<S: Simd>(
1073 simd: S,
1074 values: SimdGroupFor<Self, S>,
1075 ) -> SimdGroupFor<Self::Real, S> {
1076 Self::faer_simd_mul(simd, values, values)
1077 }
1078
1079 #[inline(always)]
1080 fn faer_simd_scalar_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
1081 let _ = simd;
1082 lhs * rhs
1083 }
1084
1085 #[inline(always)]
1086 fn faer_simd_scalar_conj_mul<S: Simd>(simd: S, lhs: Self, rhs: Self) -> Self {
1087 let _ = simd;
1088 lhs * rhs
1089 }
1090
1091 #[inline(always)]
1092 fn faer_simd_scalar_mul_adde<S: Simd>(
1093 simd: S,
1094 lhs: Self,
1095 rhs: Self,
1096 acc: Self,
1097 ) -> Self {
1098 let _ = simd;
1099 lhs * rhs + acc
1100 }
1101
1102 #[inline(always)]
1103 fn faer_simd_scalar_conj_mul_adde<S: Simd>(
1104 simd: S,
1105 lhs: Self,
1106 rhs: Self,
1107 acc: Self,
1108 ) -> Self {
1109 let _ = simd;
1110 lhs * rhs + acc
1111 }
1112
1113 #[inline(always)]
1114 fn faer_slice_as_aligned_simd<S: Simd>(
1115 simd: S,
1116 slice: &[UnitFor<Self>],
1117 offset: pulp::Offset<SimdMaskFor<Self, S>>,
1118 ) -> (
1119 pulp::Prefix<'_, UnitFor<Self>, S, SimdMaskFor<Self, S>>,
1120 &[SimdUnitFor<Self, S>],
1121 pulp::Suffix<'_, UnitFor<Self>, S, SimdMaskFor<Self, S>>,
1122 ) {
1123 simd.f64s_as_aligned_simd(slice, offset)
1124 }
1125 #[inline(always)]
1126 fn faer_slice_as_aligned_simd_mut<S: Simd>(
1127 simd: S,
1128 slice: &mut [UnitFor<Self>],
1129 offset: pulp::Offset<SimdMaskFor<Self, S>>,
1130 ) -> (
1131 pulp::PrefixMut<'_, UnitFor<Self>, S, SimdMaskFor<Self, S>>,
1132 &mut [SimdUnitFor<Self, S>],
1133 pulp::SuffixMut<'_, UnitFor<Self>, S, SimdMaskFor<Self, S>>,
1134 ) {
1135 simd.f64s_as_aligned_mut_simd(slice, offset)
1136 }
1137
1138 #[inline(always)]
1139 fn faer_simd_rotate_left<S: Simd>(
1140 simd: S,
1141 values: SimdGroupFor<Self, S>,
1142 amount: usize,
1143 ) -> SimdGroupFor<Self, S> {
1144 Double(
1145 simd.f64s_rotate_left(values.0, amount),
1146 simd.f64s_rotate_left(values.1, amount),
1147 )
1148 }
1149
1150 #[inline(always)]
1151 fn faer_align_offset<S: Simd>(
1152 simd: S,
1153 ptr: *const UnitFor<Self>,
1154 len: usize,
1155 ) -> pulp::Offset<SimdMaskFor<Self, S>> {
1156 simd.f64s_align_offset(ptr, len)
1157 }
1158 }
1159 }
1160}