1use std::ops::{Add, AddAssign, Div, Index, IndexMut, Mul, MulAssign, Sub, SubAssign};
2
3use faer::reborrow::{Reborrow, ReborrowMut};
4use faer::{unzip, zip, Col, Mat, MatMut, MatRef};
5
6use crate::context::broadcast_batch;
7use crate::{scalar::Scale, Context, FaerContext, FaerScalar, IndexType, Vector};
8
9use crate::{FaerMat, VectorCommon, VectorIndex, VectorView, VectorViewMut};
10
11use super::DefaultDenseMatrix;
12
13#[derive(Debug, Clone, PartialEq)]
19pub struct FaerVec<T: FaerScalar> {
20 pub(crate) data: Mat<T>,
21 pub(crate) context: FaerContext,
22}
23
24#[derive(Debug, Clone, PartialEq)]
25pub struct FaerVecIndex {
26 pub(crate) data: Vec<IndexType>,
27 pub(crate) context: FaerContext,
28}
29
30#[derive(Debug, Clone, PartialEq)]
31pub struct FaerVecRef<'a, T: FaerScalar> {
32 pub(crate) data: MatRef<'a, T>,
33 pub(crate) context: FaerContext,
34}
35
36#[derive(Debug, PartialEq)]
37pub struct FaerVecMut<'a, T: FaerScalar> {
38 pub(crate) data: MatMut<'a, T>,
39 pub(crate) context: FaerContext,
40}
41
42impl<T: FaerScalar> FaerVec<T> {
43 #[inline]
44 pub(crate) fn batch(&self, batch: usize, nbatch: usize) -> usize {
45 broadcast_batch(batch, self.data.ncols(), nbatch)
46 }
47
48 pub fn check_for_nan(&self, label: &str) -> bool {
49 for b in 0..self.data.ncols() {
50 let column = self.data.rb().col(b);
51 for i in 0..column.nrows() {
52 if unsafe { *column.get_unchecked(i) }.is_nan() {
53 eprintln!("{}: NaN at index {} of batch {}", label, i, b);
54 return true;
55 }
56 }
57 }
58 false
59 }
60}
61impl<T: FaerScalar> FaerVecRef<'_, T> {
62 #[inline]
63 pub(crate) fn batch(&self, batch: usize, nbatch: usize) -> usize {
64 broadcast_batch(batch, self.data.ncols(), nbatch)
65 }
66}
67
68impl<T: FaerScalar> From<Col<T>> for FaerVec<T> {
69 fn from(data: Col<T>) -> Self {
70 Self {
71 data: Mat::from_fn(data.nrows(), 1, |i, _| data[i]),
72 context: FaerContext::default(),
73 }
74 }
75}
76
77impl<T: FaerScalar> DefaultDenseMatrix for FaerVec<T> {
78 type M = FaerMat<T>;
79}
80
81macro_rules! impl_vector_common {
82 ($t:ty, $inner:ty) => {
83 impl<T: FaerScalar> VectorCommon for $t {
84 type T = T;
85 type C = FaerContext;
86 type Inner = $inner;
87 fn inner(&self) -> &Self::Inner {
88 &self.data
89 }
90 }
91 };
92}
93impl_vector_common!(FaerVec<T>, Mat<T>);
94macro_rules! impl_vector_common_ref {
95 ($t:ty, $inner:ty) => {
96 impl<'a, T: FaerScalar> VectorCommon for $t {
97 type T = T;
98 type C = FaerContext;
99 type Inner = $inner;
100 fn inner(&self) -> &Self::Inner {
101 &self.data
102 }
103 }
104 };
105}
106impl_vector_common_ref!(FaerVecRef<'a, T>, MatRef<'a, T>);
107impl_vector_common_ref!(FaerVecMut<'a, T>, MatMut<'a, T>);
108
109macro_rules! impl_binary_ref_ref {
110 ($trait:ident, $method:ident, $lhs:ty, $rhs:ty, $op:tt, $binary:tt) => {
111 impl<T: FaerScalar> $trait<$rhs> for $lhs {
112 type Output = FaerVec<T>;
113
114 #[allow(clippy::suspicious_arithmetic_impl)]
117 fn $method(self, rhs: $rhs) -> Self::Output {
118 self.context
121 .assert_broadcastable_into(rhs.context.nbatch(), stringify!($method));
122 if self.data.ncols() == 1 && rhs.data.ncols() == 1 {
126 let mut data = Mat::zeros(self.data.nrows(), 1);
127 zip!(
128 data.rb_mut().col_mut(0),
129 self.data.rb().col(0),
130 rhs.data.rb().col(0)
131 )
132 .for_each(|unzip!(o, l, r)| *o = *l $binary *r);
133 return FaerVec {
134 data,
135 context: self.context,
136 };
137 }
138 if self.data.ncols() == rhs.data.ncols() {
139 return FaerVec {
140 data: self.data.rb() $binary rhs.data.rb(),
141 context: self.context,
142 };
143 }
144 let nb = self.data.ncols();
145 let mut data = Mat::zeros(self.data.nrows(), nb);
146 for b in 0..nb {
147 let mut column = data.rb_mut().col_mut(b);
148 column.copy_from(self.data.rb().col(b));
149 column $op rhs.data.rb().col(rhs.batch(b, nb));
150 }
151 FaerVec {
152 data,
153 context: self.context,
154 }
155 }
156 }
157 };
158}
159macro_rules! impl_assign {
160 ($trait:ident, $method:ident, $lhs:ty, $rhs:ty, $op:tt) => {
161 impl<T: FaerScalar> $trait<$rhs> for $lhs {
162 #[allow(clippy::suspicious_op_assign_impl)]
165 fn $method(&mut self, rhs: $rhs) {
166 self.context
167 .assert_broadcastable_into(rhs.context.nbatch(), stringify!($method));
168 if self.data.ncols() == rhs.data.ncols() && self.data.ncols() > 1 {
172 self.data $op rhs.data.rb();
173 return;
174 }
175 let nb = self.data.ncols();
176 for b in 0..nb {
177 let mut column = self.data.rb_mut().col_mut(b);
178 column $op rhs.data.rb().col(rhs.batch(b, nb));
179 }
180 }
181 }
182 };
183}
184
185macro_rules! impl_binary_owned_lhs {
188 ($trait:ident, $method:ident, $assign_trait:ident, $assign:ident, $rhs:ty) => {
189 impl<T: FaerScalar> $trait<$rhs> for FaerVec<T> {
190 type Output = FaerVec<T>;
191
192 fn $method(mut self, rhs: $rhs) -> Self::Output {
193 $assign_trait::$assign(&mut self, rhs);
194 self
195 }
196 }
197 };
198}
199
200macro_rules! impl_binary_owned_rhs {
206 (commutes, $trait:ident, $method:ident, $assign_trait:ident, $assign:ident, $lhs:ty,
207 $op:tt, $combine:expr) => {
208 impl<T: FaerScalar> $trait<FaerVec<T>> for $lhs {
209 type Output = FaerVec<T>;
210
211 fn $method(self, mut rhs: FaerVec<T>) -> Self::Output {
212 $assign_trait::$assign(&mut rhs, self);
213 rhs
214 }
215 }
216 };
217 (noncommutes, $trait:ident, $method:ident, $assign_trait:ident, $assign:ident, $lhs:ty, $op:tt, $combine:expr) => {
218 impl<T: FaerScalar> $trait<FaerVec<T>> for $lhs {
219 type Output = FaerVec<T>;
220
221 fn $method(self, mut rhs: FaerVec<T>) -> Self::Output {
222 rhs.context
223 .assert_broadcastable_into(self.context.nbatch(), stringify!($method));
224 if self.data.ncols() == rhs.data.ncols() {
225 zip!(rhs.data.rb_mut(), self.data.rb())
226 .for_each(|unzip!(r, l)| $combine(r, *l));
227 return rhs;
228 }
229 let nb = rhs.data.ncols();
230 for b in 0..nb {
231 let lhs = self.data.rb().col(self.batch(b, nb));
232 zip!(rhs.data.rb_mut().col_mut(b), lhs)
233 .for_each(|unzip!(r, l)| $combine(r, *l));
234 }
235 rhs
236 }
237 }
238 };
239}
240
241macro_rules! impl_binary_set {
242 ($trait:ident,$method:ident,$assign_trait:ident,$assign:ident,$commutes:ident,
243 $op:tt,$binary:tt,$combine:expr) => {
244 impl_binary_owned_lhs!($trait, $method, $assign_trait, $assign, FaerVec<T>);
245 impl_binary_owned_lhs!($trait, $method, $assign_trait, $assign, &FaerVec<T>);
246 impl_binary_owned_lhs!($trait, $method, $assign_trait, $assign, FaerVecRef<'_, T>);
247 impl_binary_owned_lhs!($trait, $method, $assign_trait, $assign, &FaerVecRef<'_, T>);
248 impl_binary_owned_rhs!(
249 $commutes,
250 $trait,
251 $method,
252 $assign_trait,
253 $assign,
254 FaerVecRef<'_, T>,
255 $op,
256 $combine
257 );
258 impl_binary_owned_rhs!(
259 $commutes,
260 $trait,
261 $method,
262 $assign_trait,
263 $assign,
264 &FaerVec<T>,
265 $op,
266 $combine
267 );
268 impl_binary_ref_ref!(
269 $trait,
270 $method,
271 FaerVecRef<'_, T>,
272 &FaerVec<T>,
273 $op,
274 $binary
275 );
276 impl_binary_ref_ref!(
277 $trait,
278 $method,
279 FaerVecRef<'_, T>,
280 FaerVecRef<'_, T>,
281 $op,
282 $binary
283 );
284 impl_binary_ref_ref!(
285 $trait,
286 $method,
287 FaerVecRef<'_, T>,
288 &FaerVecRef<'_, T>,
289 $op,
290 $binary
291 );
292 impl_binary_ref_ref!($trait, $method, &FaerVec<T>, &FaerVec<T>, $op, $binary);
293 impl_binary_ref_ref!(
294 $trait,
295 $method,
296 &FaerVec<T>,
297 FaerVecRef<'_, T>,
298 $op,
299 $binary
300 );
301 impl_binary_ref_ref!(
302 $trait,
303 $method,
304 &FaerVec<T>,
305 &FaerVecRef<'_, T>,
306 $op,
307 $binary
308 );
309 };
310}
311macro_rules! impl_assign_set {
312 ($trait:ident,$method:ident,$op:tt) => {
313 impl_assign!($trait, $method, FaerVec<T>, FaerVec<T>, $op);
314 impl_assign!($trait, $method, FaerVec<T>, &FaerVec<T>, $op);
315 impl_assign!($trait, $method, FaerVec<T>, FaerVecRef<'_, T>, $op);
316 impl_assign!($trait, $method, FaerVec<T>, &FaerVecRef<'_, T>, $op);
317 impl_assign!($trait, $method, FaerVecMut<'_, T>, FaerVec<T>, $op);
318 impl_assign!($trait, $method, FaerVecMut<'_, T>, &FaerVec<T>, $op);
319 impl_assign!($trait, $method, FaerVecMut<'_, T>, FaerVecRef<'_, T>, $op);
320 impl_assign!($trait, $method, FaerVecMut<'_, T>, &FaerVecRef<'_, T>, $op);
321 };
322}
323impl_binary_set!(Add, add, AddAssign, add_assign, commutes, +=, +, |rhs: &mut T, lhs: T| *rhs += lhs);
324impl_binary_set!(Sub, sub, SubAssign, sub_assign, noncommutes, -=, -, |rhs: &mut T, lhs: T| *rhs = lhs - *rhs);
325impl_assign_set!(AddAssign, add_assign, +=);
326impl_assign_set!(SubAssign, sub_assign, -=);
327
328impl<T: FaerScalar> Mul<Scale<T>> for FaerVec<T> {
329 type Output = Self;
330 fn mul(mut self, rhs: Scale<T>) -> Self {
331 self.data *= faer::Scale(rhs.value());
332 self
333 }
334}
335macro_rules! impl_mul_scalar_alloc {
336 ($t:ty) => {
337 impl<T: FaerScalar> Mul<Scale<T>> for $t {
338 type Output = FaerVec<T>;
339 fn mul(self, rhs: Scale<T>) -> Self::Output {
340 FaerVec {
341 data: self.data.rb() * faer::Scale(rhs.value()),
342 context: self.context,
343 }
344 }
345 }
346 };
347}
348impl_mul_scalar_alloc!(&FaerVec<T>);
349impl_mul_scalar_alloc!(FaerVecRef<'_, T>);
350impl_mul_scalar_alloc!(FaerVecMut<'_, T>);
351impl<T: FaerScalar> Div<Scale<T>> for FaerVec<T> {
352 type Output = Self;
353 #[allow(clippy::suspicious_arithmetic_impl)]
354 fn div(mut self, rhs: Scale<T>) -> Self {
355 self.data *= faer::Scale(T::one() / rhs.value());
357 self
358 }
359}
360macro_rules! impl_mul_assign_scalar {
361 ($t:ty) => {
362 impl<T: FaerScalar> MulAssign<Scale<T>> for $t {
363 fn mul_assign(&mut self, rhs: Scale<T>) {
364 if self.data.ncols() == 1 {
365 let mut column = self.data.rb_mut().col_mut(0);
366 column *= faer::Scale(rhs.value());
367 return;
368 }
369 self.data *= faer::Scale(rhs.value());
370 }
371 }
372 };
373}
374impl_mul_assign_scalar!(FaerVec<T>);
375impl_mul_assign_scalar!(FaerVecMut<'_, T>);
376macro_rules! impl_index {
377 ($t:ty) => {
378 impl<T: FaerScalar> Index<IndexType> for $t {
379 type Output = T;
380 fn index(&self, i: IndexType) -> &T {
381 assert_eq!(
382 self.context.nbatch(),
383 1,
384 "indexing not supported for batched vectors"
385 );
386 &self.data[(i, 0)]
387 }
388 }
389 };
390}
391impl_index!(FaerVec<T>);
392impl_index!(FaerVecRef<'_, T>);
393impl<T: FaerScalar> IndexMut<IndexType> for FaerVec<T> {
394 fn index_mut(&mut self, i: IndexType) -> &mut T {
395 assert_eq!(
396 self.context.nbatch(),
397 1,
398 "indexing not supported for batched vectors"
399 );
400 &mut self.data[(i, 0)]
401 }
402}
403
404impl VectorIndex for FaerVecIndex {
405 type C = FaerContext;
406 fn zeros(len: IndexType, ctx: Self::C) -> Self {
407 Self {
408 data: vec![0; len],
409 context: ctx,
410 }
411 }
412 fn len(&self) -> IndexType {
413 self.data.len()
414 }
415 fn from_vec(v: Vec<IndexType>, ctx: Self::C) -> Self {
416 Self {
417 data: v,
418 context: ctx,
419 }
420 }
421 fn clone_as_vec(&self) -> Vec<IndexType> {
422 self.data.clone()
423 }
424 fn context(&self) -> &Self::C {
425 &self.context
426 }
427}
428
429macro_rules! copy_from_body {
431 ($self:ident, $other:ident, $method:literal) => {
432 $self
433 .context
434 .assert_broadcastable_into($other.context.nbatch(), $method);
435 assert_eq!(
436 $self.data.nrows(),
437 $other.data.nrows(),
438 "copy_from row mismatch"
439 );
440 if $self.data.ncols() == 1 && $other.data.ncols() == 1 {
443 $self
444 .data
445 .rb_mut()
446 .col_mut(0)
447 .copy_from($other.data.rb().col(0));
448 return;
449 }
450 if $self.data.ncols() == $other.data.ncols() {
451 $self.data.rb_mut().copy_from($other.data.rb());
452 return;
453 }
454 let (nb, onc) = ($self.data.ncols(), $other.data.ncols());
455 for b in 0..nb {
456 let src = broadcast_batch(b, onc, nb);
457 $self
458 .data
459 .rb_mut()
460 .col_mut(b)
461 .copy_from($other.data.rb().col(src));
462 }
463 };
464}
465
466macro_rules! axpy_body {
470 ($self:ident, $x:ident, $beta:expr, $op:literal, |$batch:ident| $alpha:expr) => {{
471 $self
472 .context
473 .assert_broadcastable_into($x.context.nbatch(), $op);
474 let nb = $self.data.ncols();
475 if nb == 1 {
478 let $batch = 0;
479 let alpha = $alpha;
480 zip!($self.data.rb_mut().col_mut(0), $x.data.rb().col(0))
481 .for_each(|unzip!(s, xi)| *s = *s * $beta + *xi * alpha);
482 return;
483 }
484 for $batch in 0..nb {
485 let alpha = $alpha;
486 zip!(
487 $self.data.rb_mut().col_mut($batch),
488 $x.data.rb().col($x.batch($batch, nb))
489 )
490 .for_each(|unzip!(s, xi)| *s = *s * $beta + *xi * alpha);
491 }
492 }};
493}
494
495macro_rules! squared_norm_body {
497 ($self:ident, $y:ident, $atol:ident, $rtol:ident) => {{
498 let nrows = $self.data.nrows();
499 assert!(
500 nrows == $y.data.nrows() && nrows == $atol.data.nrows(),
501 "squared_norm row mismatch"
502 );
503 let nstates = T::from_f64(nrows as f64).unwrap();
504 let batch_norm = |xb: usize, yb: usize, atolb: usize| {
506 let x = $self
507 .data
508 .rb()
509 .col(xb)
510 .try_as_col_major()
511 .unwrap()
512 .as_slice();
513 let y = $y.data.rb().col(yb).try_as_col_major().unwrap().as_slice();
514 let atol = $atol
515 .data
516 .rb()
517 .col(atolb)
518 .try_as_col_major()
519 .unwrap()
520 .as_slice();
521 let norm = x.iter().zip(y.iter().zip(atol.iter())).fold(
522 T::zero(),
523 |norm, (&x, (&y, &atol))| {
524 let term = x.algebraic_div(y.abs().algebraic_mul($rtol).algebraic_add(atol));
525 norm.algebraic_add(term.algebraic_mul(term))
526 },
527 );
528 norm / nstates
529 };
530 let nb = $self.data.ncols();
532 $self
533 .context
534 .assert_broadcastable_into($y.context.nbatch(), "squared_norm");
535 $self
536 .context
537 .assert_broadcastable_into($atol.context.nbatch(), "squared_norm");
538 if nb == 1 {
541 return batch_norm(0, 0, 0);
542 }
543 let mut max_norm = T::zero();
544 for b in 0..nb {
545 max_norm = max_norm.max(batch_norm(b, $y.batch(b, nb), $atol.batch(b, nb)));
546 }
547 max_norm
548 }};
549}
550
551impl<T: FaerScalar> Vector for FaerVec<T> {
552 type View<'a> = FaerVecRef<'a, T>;
553 type ViewMut<'a> = FaerVecMut<'a, T>;
554 type Index = FaerVecIndex;
555 fn len(&self) -> IndexType {
556 self.data.nrows()
557 }
558 fn inner_mut(&mut self) -> &mut Self::Inner {
559 &mut self.data
560 }
561 fn context(&self) -> &Self::C {
562 &self.context
563 }
564 fn norm(&self, k: i32) -> T {
565 (0..self.data.ncols())
566 .map(|b| {
567 let column = self.data.rb().col(b);
568 match k {
569 1 => column.norm_l1(),
570 2 => column.norm_l2(),
571 _ => column
572 .iter()
573 .fold(T::zero(), |acc, x| acc.algebraic_add(x.abs().pow(k)))
574 .pow(T::one() / T::from_f64(k as f64).unwrap()),
575 }
576 })
577 .fold(T::zero(), |a, b| a.max(b))
578 }
579 fn get_index(&self, i: IndexType) -> T {
580 assert_eq!(
581 self.context.nbatch(),
582 1,
583 "get_index not supported for batched vectors"
584 );
585 self.data[(i, 0)]
586 }
587 fn set_index(&mut self, i: IndexType, v: T) {
588 assert_eq!(
589 self.context.nbatch(),
590 1,
591 "set_index not supported for batched vectors, use fill_index"
592 );
593 self.data[(i, 0)] = v;
594 }
595 fn fill_index(&mut self, i: IndexType, v: T) {
596 if self.data.ncols() == 1 {
597 self.data[(i, 0)] = v;
598 return;
599 }
600 self.data.rb_mut().row_mut(i).fill(v);
601 }
602 fn squared_norm(&self, y: &Self, atol: &Self, rtol: T) -> T {
603 squared_norm_body!(self, y, atol, rtol)
604 }
605 fn as_view(&self) -> Self::View<'_> {
606 FaerVecRef {
607 data: self.data.rb(),
608 context: self.context,
609 }
610 }
611 fn as_view_mut(&mut self) -> Self::ViewMut<'_> {
612 FaerVecMut {
613 data: self.data.rb_mut(),
614 context: self.context,
615 }
616 }
617 fn get_batch(&self, b: usize) -> Self::View<'_> {
618 FaerVecRef {
619 data: self.data.rb().subcols(b, 1),
620 context: FaerContext::default(),
621 }
622 }
623 fn get_batch_mut(&mut self, b: usize) -> Self::ViewMut<'_> {
624 FaerVecMut {
625 data: self.data.rb_mut().subcols_mut(b, 1),
626 context: FaerContext::default(),
627 }
628 }
629 fn for_each_batch_mut_host<const M: usize, const N: usize>(
630 mut mut_args: [&mut Self; M],
631 args: [&Self; N],
632 mut f: impl FnMut([&mut [T]; M], [&[T]; N], usize),
633 ) {
634 assert!(M > 0, "for_each_batch needs at least one mutable operand");
635 let nbatch = mut_args[0].context.nbatch();
636 {
637 let ctx = &mut_args[0].context;
638 for arg in mut_args.iter() {
639 ctx.assert_broadcastable_into(arg.context.nbatch(), "for_each_batch");
640 }
641 for arg in args.iter() {
642 ctx.assert_broadcastable_into(arg.context.nbatch(), "for_each_batch");
643 }
644 }
645 if nbatch == 1 {
648 let ins = args.map(|a| a.data.col_as_slice(0));
649 let outs = mut_args.map(|v| v.data.col_as_slice_mut(0));
650 f(outs, ins, 0);
651 return;
652 }
653 for b in 0..nbatch {
654 let ins = args.map(|a| a.data.col_as_slice(a.batch(b, nbatch)));
655 let outs = mut_args.each_mut().map(|v| {
656 let vb = v.batch(b, nbatch);
657 v.data.col_as_slice_mut(vb)
658 });
659 f(outs, ins, b);
660 }
661 }
662 fn copy_from(&mut self, o: &Self) {
663 copy_from_body!(self, o, "copy_from");
664 }
665 fn fill(&mut self, v: T) {
666 if self.data.ncols() == 1 {
667 self.data.rb_mut().col_mut(0).fill(v);
668 return;
669 }
670 self.data.rb_mut().fill(v)
671 }
672 fn copy_from_view(&mut self, o: &Self::View<'_>) {
673 copy_from_body!(self, o, "copy_from_view");
674 }
675 fn from_element(n: usize, v: T, ctx: Self::C) -> Self {
676 Self {
677 data: Mat::from_fn(n, ctx.nbatch(), |_, _| v),
678 context: ctx,
679 }
680 }
681 fn from_vec(v: Vec<T>, ctx: Self::C) -> Self {
682 Self::from_slice(v.as_slice(), ctx)
683 }
684 fn from_slice(v: &[T], ctx: Self::C) -> Self {
685 assert!(
686 v.len().is_multiple_of(ctx.nbatch()),
687 "vector length must be divisible by nbatch"
688 );
689 let n = v.len() / ctx.nbatch();
690 Self {
691 data: Mat::from_fn(n, ctx.nbatch(), |i, b| v[b * n + i]),
692 context: ctx,
693 }
694 }
695 fn clone_as_vec(&self) -> Vec<T> {
696 let mut out = Vec::with_capacity(self.data.nrows() * self.data.ncols());
697 for b in 0..self.data.ncols() {
698 out.extend(self.data.rb().col(b).iter().copied());
699 }
700 out
701 }
702 fn zeros(n: usize, ctx: Self::C) -> Self {
703 Self {
704 data: Mat::zeros(n, ctx.nbatch()),
705 context: ctx,
706 }
707 }
708 fn axpy(&mut self, a: T, x: &Self, beta: T) {
709 axpy_body!(self, x, beta, "axpy", |_batch| a)
710 }
711 fn axpy_v(&mut self, a: T, x: &Self::View<'_>, beta: T) {
712 axpy_body!(self, x, beta, "axpy_v", |_batch| a)
713 }
714 fn batched_axpy(&mut self, a: &Self, x: &Self, beta: T) {
715 assert_eq!(
716 a.len(),
717 1,
718 "alpha must be a batched scalar, with len() == 1"
719 );
720 assert_eq!(
721 a.context.nbatch(),
722 self.context.nbatch(),
723 "alpha nbatch must equal nbatch"
724 );
725 axpy_body!(self, x, beta, "batched_axpy", |batch| a.data[(0, batch)])
726 }
727 fn component_div_assign(&mut self, o: &Self) {
728 self.context
729 .assert_broadcastable_into(o.context.nbatch(), "component_div_assign");
730 assert_eq!(
731 self.data.nrows(),
732 o.data.nrows(),
733 "component_div_assign row mismatch"
734 );
735 if self.data.ncols() == o.data.ncols() {
736 zip!(self.data.rb_mut(), o.data.rb()).for_each(|unzip!(s, o)| *s /= *o);
737 return;
738 }
739 let nb = self.data.ncols();
740 for c in 0..nb {
741 zip!(
742 self.data.rb_mut().col_mut(c),
743 o.data.rb().col(o.batch(c, nb))
744 )
745 .for_each(|unzip!(s, o)| *s /= *o);
746 }
747 }
748 fn component_mul_assign(&mut self, o: &Self) {
749 self.context
750 .assert_broadcastable_into(o.context.nbatch(), "component_mul_assign");
751 assert_eq!(
752 self.data.nrows(),
753 o.data.nrows(),
754 "component_mul_assign row mismatch"
755 );
756 if self.data.ncols() == o.data.ncols() {
757 zip!(self.data.rb_mut(), o.data.rb()).for_each(|unzip!(s, o)| *s *= *o);
758 return;
759 }
760 let nb = self.data.ncols();
761 for c in 0..nb {
762 zip!(
763 self.data.rb_mut().col_mut(c),
764 o.data.rb().col(o.batch(c, nb))
765 )
766 .for_each(|unzip!(s, o)| *s *= *o);
767 }
768 }
769 fn root_finding(&self, g1: &Self) -> (bool, T, i32) {
770 self.context
771 .assert_broadcastable_into(g1.context.nbatch(), "root_finding");
772 assert_eq!(self.len(), g1.len(), "Vector lengths do not match");
773 let mut out = None;
774 let nb = self.data.ncols();
776 for b in 0..nb {
777 let mut found = false;
778 let mut frac = T::zero();
779 let mut idx = -1;
780 let g0_column = self.data.rb().col(b);
781 let g1_column = g1.data.rb().col(g1.batch(b, nb));
782 for (i, (&g0, &g)) in g0_column
783 .try_as_col_major()
784 .unwrap()
785 .as_slice()
786 .iter()
787 .zip(g1_column.try_as_col_major().unwrap().as_slice())
788 .enumerate()
789 {
790 if g == T::zero() {
791 found = true
792 }
793 if g0 * g < T::zero() {
794 let q = (g / (g - g0)).abs();
795 if q > frac {
796 frac = q;
797 idx = i as i32
798 }
799 }
800 }
801 if let Some(x) = out {
802 assert_eq!(
803 x,
804 (found, frac, idx),
805 "root finding results differ across batches"
806 )
807 }
808 out = Some((found, frac, idx));
809 }
810 out.unwrap_or((false, T::zero(), -1))
811 }
812 fn assign_at_indices(&mut self, idx: &Self::Index, v: T) {
813 for b in 0..self.data.ncols() {
814 for i in idx.data.iter() {
815 self.data[(*i, b)] = v
816 }
817 }
818 }
819 fn copy_from_indices(&mut self, o: &Self, idx: &Self::Index) {
820 self.context
821 .assert_broadcastable_into(o.context.nbatch(), "copy_from_indices");
822 let nb = self.data.ncols();
823 for b in 0..nb {
824 for i in idx.data.iter() {
825 self.data[(*i, b)] = o.data[(*i, o.batch(b, nb))]
826 }
827 }
828 }
829 fn gather(&mut self, o: &Self, idx: &Self::Index) {
830 assert_eq!(self.len(), idx.len());
831 self.context
832 .assert_broadcastable_into(o.context.nbatch(), "gather");
833 let nb = self.data.ncols();
834 for b in 0..nb {
835 for (i, j) in idx.data.iter().enumerate() {
836 self.data[(i, b)] = o.data[(*j, o.batch(b, nb))]
837 }
838 }
839 }
840 fn scatter(&self, idx: &Self::Index, o: &mut Self) {
841 assert_eq!(self.len(), idx.len());
842 o.context
844 .assert_broadcastable_into(self.data.ncols(), "scatter");
845 let nb = o.data.ncols();
846 for b in 0..nb {
847 let src = broadcast_batch(b, self.data.ncols(), nb);
848 for (i, j) in idx.data.iter().enumerate() {
849 o.data[(*j, b)] = self.data[(i, src)]
850 }
851 }
852 }
853}
854
855impl<'a, T: FaerScalar> VectorView<'a> for FaerVecRef<'a, T> {
856 type Owned = FaerVec<T>;
857 fn get_index(&self, i: IndexType) -> T {
858 assert_eq!(self.context.nbatch(), 1, "get_index requires nbatch == 1");
859 self.data[(i, 0)]
860 }
861 fn into_owned(self) -> Self::Owned {
862 FaerVec {
863 data: self.data.to_owned(),
864 context: self.context,
865 }
866 }
867 fn squared_norm(&self, y: &Self::Owned, atol: &Self::Owned, rtol: T) -> T {
868 squared_norm_body!(self, y, atol, rtol)
869 }
870}
871impl<'a, T: FaerScalar> VectorViewMut<'a> for FaerVecMut<'a, T> {
872 type Owned = FaerVec<T>;
873 type View = FaerVecRef<'a, T>;
874 type Index = FaerVecIndex;
875 fn copy_from(&mut self, o: &Self::Owned) {
876 copy_from_body!(self, o, "copy_from");
877 }
878 fn copy_from_view(&mut self, o: &Self::View) {
879 copy_from_body!(self, o, "copy_from_view");
880 }
881 fn set_index(&mut self, i: IndexType, v: T) {
882 assert_eq!(
883 self.context.nbatch(),
884 1,
885 "set_index not supported for batched vectors, use fill_index"
886 );
887 self.data[(i, 0)] = v;
888 }
889 fn fill_index(&mut self, i: IndexType, v: T) {
890 if self.data.ncols() == 1 {
891 self.data[(i, 0)] = v;
892 return;
893 }
894 self.data.rb_mut().row_mut(i).fill(v);
895 }
896 fn axpy(&mut self, a: T, x: &Self::Owned, beta: T) {
897 axpy_body!(self, x, beta, "axpy", |_batch| a)
898 }
899}
900#[cfg(test)]
901mod tests {
902 use super::*;
903 use crate::scalar::scale;
904
905 #[test]
906 fn test_mult() {
907 let v = FaerVec::from_vec(vec![1.0, -2.0, 3.0], Default::default());
908 let s = scale(2.0);
909 let r = FaerVec::from_vec(vec![2.0, -4.0, 6.0], Default::default());
910 assert_eq!(v * s, r);
911 }
912
913 #[test]
914 fn test_mul_assign() {
915 let mut v = FaerVec::from_vec(vec![1.0, -2.0, 3.0], Default::default());
916 let s = scale(2.0);
917 let r = FaerVec::from_vec(vec![2.0, -4.0, 6.0], Default::default());
918 v.mul_assign(s);
919 assert_eq!(v, r);
920 }
921
922 #[test]
923 fn test_error_norm() {
924 let v: FaerVec<f64> = FaerVec::from_vec(vec![1.0, -2.0, 3.0], Default::default());
925 let y = FaerVec::from_vec(vec![1.0, 2.0, 3.0], Default::default());
926 let atol = FaerVec::from_vec(vec![0.1, 0.2, 0.3], Default::default());
927 let rtol = 0.1;
928 let mut tmp = y.clone() * scale(rtol);
929 tmp += &atol;
930 let mut r = v.clone();
931 r.component_div_assign(&tmp);
932 let errorn_check = r.data.rb().col(0).squared_norm_l2() / 3.0;
933 assert!(
934 (v.squared_norm(&y, &atol, rtol) - errorn_check).abs() < 1e-10,
935 "{} vs {}",
936 v.squared_norm(&y, &atol, rtol),
937 errorn_check
938 );
939 let vview = v.as_view();
940 assert!((VectorView::squared_norm(&vview, &y, &atol, rtol) - errorn_check).abs() < 1e-10);
941 }
942
943 #[test]
944 fn test_root_finding() {
945 super::super::tests::test_root_finding::<FaerVec<f64>>();
946 }
947
948 #[test]
949 fn test_from_slice() {
950 let slice = [1.0, 2.0, 3.0];
951 let v = FaerVec::from_slice(&slice, Default::default());
952 assert_eq!(v.clone_as_vec(), slice);
953 }
954
955 #[test]
956 fn test_into() {
957 let col: Col<f64> = Col::from_fn(3, |i| (i + 1) as f64);
958 let v: FaerVec<f64> = col.into();
959 assert_eq!(v.clone_as_vec(), vec![1.0, 2.0, 3.0]);
960 }
961
962 #[test]
965 fn test_norm_odd_k_uses_magnitudes() {
966 let v = FaerVec::from_vec(vec![-3.0, 4.0], Default::default());
967 let expected: f64 = (27.0f64 + 64.0).powf(1.0 / 3.0);
968 assert!((v.norm(3) - expected).abs() < 1e-12, "{}", v.norm(3));
969 }
970
971 #[test]
974 fn test_empty() {
975 let ctx = FaerContext::with_nbatch(2);
976 for v in [
977 FaerVec::<f64>::zeros(0, ctx),
978 FaerVec::<f64>::from_vec(vec![], ctx),
979 FaerVec::<f64>::from_element(0, 1.0, ctx),
980 ] {
981 assert_eq!(v.len(), 0);
982 assert!(v.is_empty());
983 assert_eq!(v.clone_as_vec(), Vec::<f64>::new());
984 }
985 }
986
987 #[test]
988 fn test_host_only() {
989 super::super::tests::test_host_only::<FaerVec<f64>>();
990 }
991
992 super::super::generate_vector_tests_nonbatched!(faer, FaerVec<f64>);
993 super::super::generate_vector_tests_nonbatched!(faer_f32, FaerVec<f32>);
994 super::super::generate_vector_tests_batched!(
995 faer,
996 FaerVec<f64>,
997 FaerContext::with_nbatch(2),
998 FaerContext::with_nbatch(3)
999 );
1000 super::super::generate_vector_tests_batched!(
1001 faer_f32,
1002 FaerVec<f32>,
1003 FaerContext::with_nbatch(2),
1004 FaerContext::with_nbatch(3)
1005 );
1006}