1use crate::blas1;
10use crate::vector::{Vector, VectorCache};
11use pounce_common::tagged::{Tag, TaggedObject};
12use pounce_common::types::{Index, Number};
13use std::any::Any;
14use std::cell::RefCell;
15use std::collections::BTreeMap;
16use std::rc::Rc;
17
18#[derive(Debug, Default)]
22pub struct DenseVectorSpace {
23 dim: Index,
24 string_meta: RefCell<BTreeMap<String, Vec<String>>>,
25 integer_meta: RefCell<BTreeMap<String, Vec<Index>>>,
26 numeric_meta: RefCell<BTreeMap<String, Vec<Number>>>,
27}
28
29impl DenseVectorSpace {
30 pub fn new(dim: Index) -> Rc<Self> {
31 Rc::new(Self {
32 dim,
33 string_meta: RefCell::new(BTreeMap::new()),
34 integer_meta: RefCell::new(BTreeMap::new()),
35 numeric_meta: RefCell::new(BTreeMap::new()),
36 })
37 }
38
39 pub fn dim(&self) -> Index {
40 self.dim
41 }
42
43 pub fn make_new_dense(self: &Rc<Self>) -> DenseVector {
44 DenseVector::new(Rc::clone(self))
45 }
46
47 pub fn has_string_meta(&self, tag: &str) -> bool {
48 self.string_meta.borrow().contains_key(tag)
49 }
50 pub fn set_string_meta(&self, tag: &str, data: Vec<String>) {
51 self.string_meta.borrow_mut().insert(tag.to_string(), data);
52 }
53 pub fn get_string_meta(&self, tag: &str) -> Option<Vec<String>> {
54 self.string_meta.borrow().get(tag).cloned()
55 }
56
57 pub fn has_integer_meta(&self, tag: &str) -> bool {
58 self.integer_meta.borrow().contains_key(tag)
59 }
60 pub fn set_integer_meta(&self, tag: &str, data: Vec<Index>) {
61 self.integer_meta.borrow_mut().insert(tag.to_string(), data);
62 }
63 pub fn get_integer_meta(&self, tag: &str) -> Option<Vec<Index>> {
64 self.integer_meta.borrow().get(tag).cloned()
65 }
66
67 pub fn has_numeric_meta(&self, tag: &str) -> bool {
68 self.numeric_meta.borrow().contains_key(tag)
69 }
70 pub fn set_numeric_meta(&self, tag: &str, data: Vec<Number>) {
71 self.numeric_meta.borrow_mut().insert(tag.to_string(), data);
72 }
73 pub fn get_numeric_meta(&self, tag: &str) -> Option<Vec<Number>> {
74 self.numeric_meta.borrow().get(tag).cloned()
75 }
76}
77
78#[derive(Debug)]
80pub struct DenseVector {
81 space: Rc<DenseVectorSpace>,
82 cache: VectorCache,
83 values: Vec<Number>,
85 initialized: bool,
86 homogeneous: bool,
87 scalar: Number,
88}
89
90impl DenseVector {
91 pub fn new(space: Rc<DenseVectorSpace>) -> Self {
92 let dim = space.dim();
93 let (initialized, homogeneous, scalar) = if dim == 0 {
95 (true, true, 0.0)
96 } else {
97 (false, false, 0.0)
98 };
99 Self {
100 space,
101 cache: VectorCache::new(),
102 values: Vec::new(),
103 initialized,
104 homogeneous,
105 scalar,
106 }
107 }
108
109 pub fn space(&self) -> &Rc<DenseVectorSpace> {
110 &self.space
111 }
112
113 pub fn is_homogeneous(&self) -> bool {
114 self.homogeneous
115 }
116
117 pub fn scalar(&self) -> Number {
118 debug_assert!(self.homogeneous);
119 self.scalar
120 }
121
122 pub fn is_initialized(&self) -> bool {
123 self.initialized
124 }
125
126 pub fn values(&self) -> &[Number] {
131 debug_assert!(self.initialized && !self.homogeneous);
132 &self.values
133 }
134
135 pub fn values_mut(&mut self) -> &mut [Number] {
138 if self.initialized && self.homogeneous {
139 self.materialize_from_scalar();
140 }
141 self.ensure_storage();
142 self.cache.bump();
143 self.initialized = true;
144 self.homogeneous = false;
145 &mut self.values
146 }
147
148 pub fn expanded_values(&self) -> Vec<Number> {
152 if self.homogeneous {
153 vec![self.scalar; self.space.dim() as usize]
154 } else {
155 self.values.clone()
156 }
157 }
158
159 pub fn set_values(&mut self, x: &[Number]) {
160 let dim = self.space.dim() as usize;
161 assert_eq!(x.len(), dim);
162 self.ensure_storage();
163 self.values[..dim].copy_from_slice(x);
164 self.initialized = true;
165 self.homogeneous = false;
166 self.cache.bump();
167 }
168
169 pub fn copy_to_pos(&mut self, pos: Index, x: &dyn Vector) {
171 let pos = pos as usize;
172 let dim_x = x.dim() as usize;
173 assert!(pos + dim_x <= self.space.dim() as usize);
174 let dense_x = downcast_dense(x);
175 if self.homogeneous && self.initialized {
176 self.materialize_from_scalar();
177 }
178 self.ensure_storage();
179 self.homogeneous = false;
180 if dense_x.homogeneous {
181 for v in &mut self.values[pos..pos + dim_x] {
182 *v = dense_x.scalar;
183 }
184 } else {
185 self.values[pos..pos + dim_x].copy_from_slice(&dense_x.values[..dim_x]);
186 }
187 self.initialized = true;
188 self.cache.bump();
189 }
190
191 pub fn copy_from_pos(&mut self, pos: Index, x: &dyn Vector) {
193 let pos = pos as usize;
194 let dim = self.space.dim() as usize;
195 assert!(pos + dim <= x.dim() as usize);
196 let dense_x = downcast_dense(x);
197 if dense_x.homogeneous {
198 self.set(dense_x.scalar);
199 } else {
200 self.ensure_storage();
201 self.values[..dim].copy_from_slice(&dense_x.values[pos..pos + dim]);
202 self.initialized = true;
203 self.homogeneous = false;
204 self.cache.bump();
205 }
206 }
207
208 pub fn ensure_storage(&mut self) {
209 let dim = self.space.dim() as usize;
210 if self.values.len() != dim {
211 self.values.resize(dim, 0.0);
212 }
213 }
214
215 fn materialize_from_scalar(&mut self) {
217 debug_assert!(self.homogeneous);
218 let dim = self.space.dim() as usize;
219 self.values.clear();
220 self.values.resize(dim, self.scalar);
221 self.homogeneous = false;
222 self.initialized = true;
223 }
224}
225
226fn downcast_dense(x: &dyn Vector) -> &DenseVector {
227 match x.as_any().downcast_ref::<DenseVector>() {
228 Some(v) => v,
229 None => panic!(
230 "Vector argument is not a DenseVector — mixed-type linear algebra is not supported in v1.0"
231 ),
232 }
233}
234
235impl TaggedObject for DenseVector {
236 fn get_tag(&self) -> Tag {
237 self.cache.tag()
238 }
239}
240
241#[derive(Clone, Copy)]
250enum Operand<'a> {
251 Zero,
252 Scalar(Number),
253 Dense(&'a [Number]),
254}
255
256impl<'a> Operand<'a> {
257 fn of(dv: Option<&'a DenseVector>, n: usize) -> Self {
258 match dv {
259 None => Operand::Zero,
260 Some(d) if d.homogeneous => Operand::Scalar(d.scalar),
261 Some(d) => Operand::Dense(&d.values[..n]),
262 }
263 }
264
265 #[inline(always)]
266 fn at(self, i: usize) -> Number {
267 match self {
268 Operand::Zero => 0.0,
269 Operand::Scalar(s) => s,
270 Operand::Dense(v) => v[i],
271 }
272 }
273}
274
275impl Vector for DenseVector {
276 fn dim(&self) -> Index {
277 self.space.dim()
278 }
279
280 fn cache(&self) -> &VectorCache {
281 &self.cache
282 }
283
284 fn make_new(&self) -> Box<dyn Vector> {
285 Box::new(DenseVector::new(Rc::clone(&self.space)))
286 }
287
288 fn as_any(&self) -> &dyn Any {
289 self
290 }
291
292 fn as_any_mut(&mut self) -> &mut dyn Any {
293 self
294 }
295
296 fn as_tagged(&self) -> &dyn TaggedObject {
297 self
298 }
299
300 fn as_dyn_vector(&self) -> &dyn Vector {
301 self
302 }
303
304 fn copy_impl(&mut self, x: &dyn Vector) {
305 let dx = downcast_dense(x);
306 debug_assert!(dx.initialized);
307 debug_assert_eq!(self.space.dim(), dx.space.dim());
308 self.homogeneous = dx.homogeneous;
309 if dx.homogeneous {
310 self.scalar = dx.scalar;
311 self.values.clear();
312 } else {
313 self.ensure_storage();
314 let dim = self.space.dim() as usize;
315 self.values[..dim].copy_from_slice(&dx.values[..dim]);
316 }
317 self.initialized = true;
318 }
319
320 fn scal_impl(&mut self, alpha: Number) {
321 debug_assert!(self.initialized);
322 if self.homogeneous {
323 self.scalar *= alpha;
324 } else {
325 blas1::scal(alpha, &mut self.values, 1, self.space.dim());
326 }
327 }
328
329 fn axpy_impl(&mut self, alpha: Number, x: &dyn Vector) {
330 debug_assert!(self.initialized);
331 let dx = downcast_dense(x);
332 debug_assert!(dx.initialized);
333 let dim = self.space.dim();
334 if dim == 0 {
335 return;
336 }
337 if self.homogeneous {
338 if dx.homogeneous {
339 self.scalar += alpha * dx.scalar;
340 } else {
341 let s0 = self.scalar;
342 self.homogeneous = false;
343 self.ensure_storage();
344 let n = dim as usize;
345 for i in 0..n {
346 self.values[i] = s0 + alpha * dx.values[i];
347 }
348 }
349 } else if dx.homogeneous {
350 if dx.scalar != 0.0 {
351 let inc = alpha * dx.scalar;
352 for v in &mut self.values[..dim as usize] {
353 *v += inc;
354 }
355 }
356 } else {
357 blas1::axpy(alpha, &dx.values, 1, &mut self.values, 1, dim);
358 }
359 }
360
361 fn dot_impl(&self, x: &dyn Vector) -> Number {
362 debug_assert!(self.initialized);
363 let dx = downcast_dense(x);
364 debug_assert!(dx.initialized);
365 let dim = self.space.dim();
366 let n = dim as usize;
367 if dim == 0 {
368 return 0.0;
369 }
370 match (self.homogeneous, dx.homogeneous) {
371 (true, true) => (n as Number) * self.scalar * dx.scalar,
372 (true, false) => {
373 let mut s = 0.0;
375 for v in &dx.values[..n] {
376 s += self.scalar * v;
377 }
378 s
379 }
380 (false, true) => {
381 let mut s = 0.0;
382 for v in &self.values[..n] {
383 s += dx.scalar * v;
384 }
385 s
386 }
387 (false, false) => blas1::dot(&self.values, 1, &dx.values, 1, dim),
388 }
389 }
390
391 fn nrm2_impl(&self) -> Number {
392 debug_assert!(self.initialized);
393 if self.homogeneous {
394 (self.space.dim() as Number).sqrt() * self.scalar.abs()
395 } else {
396 blas1::nrm2(&self.values, 1, self.space.dim())
397 }
398 }
399
400 fn asum_impl(&self) -> Number {
401 debug_assert!(self.initialized);
402 if self.homogeneous {
403 (self.space.dim() as Number) * self.scalar.abs()
404 } else {
405 blas1::asum(&self.values, 1, self.space.dim())
406 }
407 }
408
409 fn amax_impl(&self) -> Number {
410 debug_assert!(self.initialized);
411 if self.space.dim() == 0 {
412 return 0.0;
413 }
414 if self.homogeneous {
415 return self.scalar.abs();
416 }
417 let i = blas1::iamax(&self.values, 1, self.space.dim()) as usize;
418 self.values[i].abs()
419 }
420
421 fn set_impl(&mut self, value: Number) {
422 self.initialized = true;
423 self.homogeneous = true;
424 self.scalar = value;
425 self.values.clear();
427 self.values.shrink_to_fit();
428 }
429
430 fn element_wise_divide_impl(&mut self, x: &dyn Vector) {
431 debug_assert!(self.initialized);
432 let dx = downcast_dense(x);
433 debug_assert!(dx.initialized);
434 let n = self.space.dim() as usize;
435 if n == 0 {
436 return;
437 }
438 match (self.homogeneous, dx.homogeneous) {
439 (true, true) => self.scalar /= dx.scalar,
440 (true, false) => {
441 let s0 = self.scalar;
442 self.homogeneous = false;
443 self.ensure_storage();
444 for i in 0..n {
445 self.values[i] = s0 / dx.values[i];
446 }
447 }
448 (false, true) => {
449 for v in &mut self.values[..n] {
450 *v /= dx.scalar;
451 }
452 }
453 (false, false) => {
454 for i in 0..n {
455 self.values[i] /= dx.values[i];
456 }
457 }
458 }
459 }
460
461 fn element_wise_multiply_impl(&mut self, x: &dyn Vector) {
462 debug_assert!(self.initialized);
463 let dx = downcast_dense(x);
464 debug_assert!(dx.initialized);
465 let n = self.space.dim() as usize;
466 if n == 0 {
467 return;
468 }
469 match (self.homogeneous, dx.homogeneous) {
470 (true, true) => self.scalar *= dx.scalar,
471 (true, false) => {
472 let s0 = self.scalar;
473 self.homogeneous = false;
474 self.ensure_storage();
475 for i in 0..n {
476 self.values[i] = s0 * dx.values[i];
477 }
478 }
479 (false, true) => {
480 if dx.scalar != 1.0 {
481 for v in &mut self.values[..n] {
482 *v *= dx.scalar;
483 }
484 }
485 }
486 (false, false) => {
487 for i in 0..n {
488 self.values[i] *= dx.values[i];
489 }
490 }
491 }
492 }
493
494 fn element_wise_select_impl(&mut self, x: &dyn Vector) {
495 debug_assert!(self.initialized);
496 let dx = downcast_dense(x);
497 debug_assert!(dx.initialized);
498 let n = self.space.dim() as usize;
499 if n == 0 {
500 return;
501 }
502 if self.homogeneous {
503 if self.scalar == 0.0 {
504 return;
505 }
506 if dx.homogeneous {
507 self.scalar *= dx.scalar;
508 } else {
509 let s0 = self.scalar;
510 self.homogeneous = false;
511 self.ensure_storage();
512 for i in 0..n {
513 self.values[i] = s0 * dx.values[i];
514 }
515 }
516 } else if dx.homogeneous {
517 if dx.scalar != 1.0 {
518 for v in &mut self.values[..n] {
519 if *v > 0.0 {
520 *v = dx.scalar;
521 } else if *v < 0.0 {
522 *v = -dx.scalar;
523 }
524 }
525 }
526 } else {
527 for i in 0..n {
528 if self.values[i] > 0.0 {
529 self.values[i] = dx.values[i];
530 } else if self.values[i] < 0.0 {
531 self.values[i] = -dx.values[i];
532 }
533 }
534 }
535 }
536
537 fn element_wise_max_impl(&mut self, x: &dyn Vector) {
538 debug_assert!(self.initialized);
539 let dx = downcast_dense(x);
540 debug_assert!(dx.initialized);
541 let n = self.space.dim() as usize;
542 if n == 0 {
543 return;
544 }
545 match (self.homogeneous, dx.homogeneous) {
546 (true, true) => self.scalar = self.scalar.max(dx.scalar),
547 (true, false) => {
548 let s0 = self.scalar;
549 self.homogeneous = false;
550 self.ensure_storage();
551 for i in 0..n {
552 self.values[i] = s0.max(dx.values[i]);
553 }
554 }
555 (false, true) => {
556 for v in &mut self.values[..n] {
557 *v = (*v).max(dx.scalar);
558 }
559 }
560 (false, false) => {
561 for i in 0..n {
562 self.values[i] = self.values[i].max(dx.values[i]);
563 }
564 }
565 }
566 }
567
568 fn element_wise_min_impl(&mut self, x: &dyn Vector) {
569 debug_assert!(self.initialized);
570 let dx = downcast_dense(x);
571 debug_assert!(dx.initialized);
572 let n = self.space.dim() as usize;
573 if n == 0 {
574 return;
575 }
576 match (self.homogeneous, dx.homogeneous) {
577 (true, true) => self.scalar = self.scalar.min(dx.scalar),
578 (true, false) => {
579 let s0 = self.scalar;
580 self.homogeneous = false;
581 self.ensure_storage();
582 for i in 0..n {
583 self.values[i] = s0.min(dx.values[i]);
584 }
585 }
586 (false, true) => {
587 for v in &mut self.values[..n] {
588 *v = (*v).min(dx.scalar);
589 }
590 }
591 (false, false) => {
592 for i in 0..n {
593 self.values[i] = self.values[i].min(dx.values[i]);
594 }
595 }
596 }
597 }
598
599 fn element_wise_reciprocal_impl(&mut self) {
600 debug_assert!(self.initialized);
601 let n = self.space.dim() as usize;
602 if n == 0 {
603 return;
604 }
605 if self.homogeneous {
606 self.scalar = 1.0 / self.scalar;
607 } else {
608 for v in &mut self.values[..n] {
609 *v = 1.0 / *v;
610 }
611 }
612 }
613
614 fn element_wise_abs_impl(&mut self) {
615 debug_assert!(self.initialized);
616 if self.homogeneous {
617 self.scalar = self.scalar.abs();
618 } else {
619 for v in &mut self.values[..self.space.dim() as usize] {
620 *v = v.abs();
621 }
622 }
623 }
624
625 fn element_wise_sqrt_impl(&mut self) {
626 debug_assert!(self.initialized);
627 if self.homogeneous {
628 self.scalar = self.scalar.sqrt();
629 } else {
630 for v in &mut self.values[..self.space.dim() as usize] {
631 *v = v.sqrt();
632 }
633 }
634 }
635
636 fn element_wise_sgn_impl(&mut self) {
637 debug_assert!(self.initialized);
638 let sgn = |v: Number| -> Number {
639 if v > 0.0 {
640 1.0
641 } else if v < 0.0 {
642 -1.0
643 } else {
644 0.0
645 }
646 };
647 if self.homogeneous {
648 self.scalar = sgn(self.scalar);
649 } else {
650 for v in &mut self.values[..self.space.dim() as usize] {
651 *v = sgn(*v);
652 }
653 }
654 }
655
656 fn add_scalar_impl(&mut self, scalar: Number) {
657 debug_assert!(self.initialized);
658 if self.homogeneous {
659 self.scalar += scalar;
660 } else {
661 for v in &mut self.values[..self.space.dim() as usize] {
662 *v += scalar;
663 }
664 }
665 }
666
667 fn max_impl(&self) -> Number {
668 debug_assert!(self.initialized);
669 let n = self.space.dim() as usize;
670 if n == 0 {
671 return -Number::MAX;
672 }
673 if self.homogeneous {
674 return self.scalar;
675 }
676 let mut m = self.values[0];
677 for &v in &self.values[1..n] {
678 if v > m {
679 m = v;
680 }
681 }
682 m
683 }
684
685 fn min_impl(&self) -> Number {
686 debug_assert!(self.initialized);
687 let n = self.space.dim() as usize;
688 if n == 0 {
689 return Number::MAX;
690 }
691 if self.homogeneous {
692 return self.scalar;
693 }
694 let mut m = self.values[0];
695 for &v in &self.values[1..n] {
696 if v < m {
697 m = v;
698 }
699 }
700 m
701 }
702
703 fn sum_impl(&self) -> Number {
704 debug_assert!(self.initialized);
705 let n = self.space.dim() as usize;
706 if self.homogeneous {
707 (n as Number) * self.scalar
708 } else {
709 let mut s = 0.0;
710 for &v in &self.values[..n] {
711 s += v;
712 }
713 s
714 }
715 }
716
717 fn sum_logs_impl(&self) -> Number {
718 debug_assert!(self.initialized);
719 let n = self.space.dim() as usize;
720 if n == 0 {
721 return 0.0;
722 }
723 if self.homogeneous {
724 (n as Number) * self.scalar.ln()
725 } else {
726 let mut s = 0.0;
727 for &v in &self.values[..n] {
728 s += v.ln();
729 }
730 s
731 }
732 }
733
734 fn frac_to_bound_impl(&self, delta: &dyn Vector, tau: Number) -> Number {
735 debug_assert_eq!(self.space.dim(), delta.dim());
736 debug_assert!(tau >= 0.0);
737 let dd = downcast_dense(delta);
738 let n = self.space.dim() as usize;
739 if n == 0 {
740 return 1.0;
741 }
742 let mut alpha: Number = 1.0;
743 match (self.homogeneous, dd.homogeneous) {
744 (true, true) => {
745 if dd.scalar < 0.0 {
746 alpha = alpha.min(-tau / dd.scalar * self.scalar);
747 }
748 }
749 (true, false) => {
750 for &d in &dd.values[..n] {
751 if d < 0.0 {
752 alpha = alpha.min(-tau / d * self.scalar);
753 }
754 }
755 }
756 (false, true) => {
757 if dd.scalar < 0.0 {
758 let f = -tau / dd.scalar;
759 for &x in &self.values[..n] {
760 alpha = alpha.min(f * x);
761 }
762 }
763 }
764 (false, false) => {
765 for i in 0..n {
766 let d = dd.values[i];
767 if d < 0.0 {
768 alpha = alpha.min(-tau / d * self.values[i]);
769 }
770 }
771 }
772 }
773 debug_assert!(alpha >= 0.0);
774 alpha
775 }
776
777 fn add_two_vectors_impl(
778 &mut self,
779 a: Number,
780 v1: &dyn Vector,
781 b: Number,
782 v2: &dyn Vector,
783 c: Number,
784 ) {
785 let n = self.space.dim() as usize;
786 if n == 0 {
787 debug_assert!(self.initialized);
788 return;
789 }
790 let dv1 = if a != 0.0 {
791 Some(downcast_dense(v1))
792 } else {
793 None
794 };
795 let dv2 = if b != 0.0 {
796 Some(downcast_dense(v2))
797 } else {
798 None
799 };
800 let homog_v1 = dv1.map(|d| d.homogeneous).unwrap_or(true);
801 let homog_v2 = dv2.map(|d| d.homogeneous).unwrap_or(true);
802 let s_v1 = dv1.map(|d| d.scalar).unwrap_or(0.0);
803 let s_v2 = dv2.map(|d| d.scalar).unwrap_or(0.0);
804
805 if (c == 0.0 || self.homogeneous) && homog_v1 && homog_v2 {
807 let prev = if c == 0.0 { 0.0 } else { c * self.scalar };
808 self.scalar = prev + a * s_v1 + b * s_v2;
809 self.homogeneous = true;
810 self.initialized = true;
811 return;
812 }
813
814 if c == 0.0 {
816 self.ensure_storage();
817 self.homogeneous = false;
818 } else if self.homogeneous {
819 self.materialize_from_scalar();
820 }
821
822 let v1_op = Operand::of(dv1, n);
832 let v2_op = Operand::of(dv2, n);
833
834 let out = &mut self.values[..n];
838 if c == 0.0 {
839 for (i, o) in out.iter_mut().enumerate() {
840 *o = a * v1_op.at(i) + b * v2_op.at(i);
841 }
842 } else {
843 for (i, o) in out.iter_mut().enumerate() {
844 *o = a * v1_op.at(i) + b * v2_op.at(i) + c * *o;
845 }
846 }
847 self.initialized = true;
848 }
849
850 fn add_vector_quotient_impl(&mut self, a: Number, z: &dyn Vector, s: &dyn Vector, c: Number) {
851 debug_assert_eq!(self.space.dim(), z.dim());
852 debug_assert_eq!(self.space.dim(), s.dim());
853 let dz = downcast_dense(z);
854 let ds = downcast_dense(s);
855 debug_assert!(dz.initialized && ds.initialized);
856 let n = self.space.dim() as usize;
857 if n == 0 {
858 return;
859 }
860 let homog_z = dz.homogeneous;
861 let homog_s = ds.homogeneous;
862 if (c == 0.0 || self.homogeneous) && homog_z && homog_s {
863 self.scalar = if c == 0.0 {
864 a * dz.scalar / ds.scalar
865 } else {
866 c * self.scalar + a * dz.scalar / ds.scalar
867 };
868 self.initialized = true;
869 self.homogeneous = true;
870 self.values.clear();
871 return;
872 }
873 if c == 0.0 {
875 self.ensure_storage();
876 self.homogeneous = false;
877 } else if self.homogeneous {
878 self.materialize_from_scalar();
879 }
880 let z_op = Operand::of(Some(dz), n);
884 let s_op = Operand::of(Some(ds), n);
885 let out = &mut self.values[..n];
886 if c == 0.0 {
887 for (i, o) in out.iter_mut().enumerate() {
888 *o = a * z_op.at(i) / s_op.at(i);
889 }
890 } else {
891 for (i, o) in out.iter_mut().enumerate() {
892 *o = c * *o + a * z_op.at(i) / s_op.at(i);
893 }
894 }
895 self.initialized = true;
896 self.homogeneous = false;
897 }
898}
899
900#[cfg(test)]
901mod tests {
902 use super::*;
903
904 fn vec_of(space: &Rc<DenseVectorSpace>, vals: &[Number]) -> DenseVector {
905 let mut v = DenseVector::new(Rc::clone(space));
906 v.set_values(vals);
907 v
908 }
909
910 #[test]
911 fn axpy_basic() {
912 let s = DenseVectorSpace::new(3);
913 let x = vec_of(&s, &[1.0, 2.0, 3.0]);
914 let mut y = vec_of(&s, &[10.0, 20.0, 30.0]);
915 y.axpy(2.0, &x);
916 assert_eq!(y.values(), &[12.0, 24.0, 36.0]);
917 }
918
919 #[test]
920 fn dot_homogeneous_pair() {
921 let s = DenseVectorSpace::new(4);
922 let mut x = DenseVector::new(Rc::clone(&s));
923 x.set(2.0); let mut y = DenseVector::new(Rc::clone(&s));
925 y.set(3.0); assert_eq!(x.dot(&y), 24.0);
928 }
929
930 #[test]
931 fn dot_mixed_homog_dense() {
932 let s = DenseVectorSpace::new(3);
933 let mut x = DenseVector::new(Rc::clone(&s));
934 x.set(2.0);
935 let y = vec_of(&s, &[1.0, 2.0, 3.0]);
936 assert_eq!(x.dot(&y), 12.0);
938 assert_eq!(y.dot(&x), 12.0);
939 }
940
941 #[test]
942 fn nrm2_homogeneous_uses_sqrt_n() {
943 let s = DenseVectorSpace::new(4);
944 let mut x = DenseVector::new(Rc::clone(&s));
945 x.set(3.0);
946 assert!((x.nrm2() - 6.0).abs() < 1e-15);
948 }
949
950 #[test]
951 fn nrm2_cache_invalidated_by_mutation() {
952 let s = DenseVectorSpace::new(2);
953 let mut x = vec_of(&s, &[3.0, 4.0]);
954 assert_eq!(x.nrm2(), 5.0);
955 x.scal(2.0);
956 assert!((x.nrm2() - 10.0).abs() < 1e-15);
957 }
958
959 #[test]
960 fn dot_cache_hits_after_first_call() {
961 let s = DenseVectorSpace::new(3);
962 let x = vec_of(&s, &[1.0, 2.0, 3.0]);
963 let y = vec_of(&s, &[1.0, 1.0, 1.0]);
964 assert_eq!(x.dot(&y), 6.0);
965 assert_eq!(x.dot(&y), 6.0);
967 }
968
969 #[test]
970 fn dot_self_uses_nrm2_squared_path() {
971 let s = DenseVectorSpace::new(2);
972 let x = vec_of(&s, &[3.0, 4.0]);
973 assert_eq!(x.dot(&x), 25.0);
975 }
976
977 #[test]
978 fn add_two_vectors_all_homogeneous() {
979 let s = DenseVectorSpace::new(5);
980 let mut y = DenseVector::new(Rc::clone(&s));
981 y.set(1.0);
982 let mut v1 = DenseVector::new(Rc::clone(&s));
983 v1.set(2.0);
984 let mut v2 = DenseVector::new(Rc::clone(&s));
985 v2.set(3.0);
986 y.add_two_vectors(4.0, &v1, 5.0, &v2, 0.5);
988 assert!(y.is_homogeneous());
989 assert_eq!(y.scalar(), 23.5);
990 }
991
992 #[test]
993 fn add_two_vectors_mixed_dense_overrides_homog() {
994 let s = DenseVectorSpace::new(3);
995 let mut y = DenseVector::new(Rc::clone(&s));
996 y.set(0.0);
997 let v1 = vec_of(&s, &[1.0, 2.0, 3.0]);
998 let v2 = vec_of(&s, &[10.0, 10.0, 10.0]);
999 y.add_two_vectors(1.0, &v1, 1.0, &v2, 0.0);
1001 assert!(!y.is_homogeneous());
1002 assert_eq!(y.values(), &[11.0, 12.0, 13.0]);
1003 }
1004
1005 #[test]
1006 fn frac_to_bound_basic() {
1007 let s = DenseVectorSpace::new(3);
1008 let x = vec_of(&s, &[1.0, 2.0, 3.0]);
1009 let delta = vec_of(&s, &[-2.0, 1.0, -1.5]);
1010 let alpha = x.frac_to_bound(&delta, 1.0);
1014 assert!((alpha - 0.5).abs() < 1e-15);
1015 }
1016
1017 #[test]
1018 fn element_wise_divide_homog_dense() {
1019 let s = DenseVectorSpace::new(3);
1020 let mut y = DenseVector::new(Rc::clone(&s));
1021 y.set(6.0);
1022 let x = vec_of(&s, &[1.0, 2.0, 3.0]);
1023 y.element_wise_divide(&x);
1024 assert!(!y.is_homogeneous());
1025 assert_eq!(y.values(), &[6.0, 3.0, 2.0]);
1026 }
1027
1028 #[test]
1029 fn element_wise_sgn_handles_all_three_signs() {
1030 let s = DenseVectorSpace::new(3);
1031 let mut x = vec_of(&s, &[-2.5, 0.0, 7.0]);
1032 x.element_wise_sgn();
1033 assert_eq!(x.values(), &[-1.0, 0.0, 1.0]);
1034 }
1035
1036 #[test]
1037 fn sum_and_max_min_homogeneous() {
1038 let s = DenseVectorSpace::new(4);
1039 let mut x = DenseVector::new(Rc::clone(&s));
1040 x.set(2.5);
1041 assert_eq!(x.sum(), 10.0);
1042 assert_eq!(x.max(), 2.5);
1043 assert_eq!(x.min(), 2.5);
1044 }
1045
1046 #[test]
1047 fn has_valid_numbers_detects_nan() {
1048 let s = DenseVectorSpace::new(3);
1049 let bad = vec_of(&s, &[1.0, Number::NAN, 2.0]);
1050 assert!(!bad.has_valid_numbers());
1051 let good = vec_of(&s, &[1.0, 2.0, 3.0]);
1052 assert!(good.has_valid_numbers());
1053 }
1054
1055 #[test]
1056 fn copy_to_pos_pastes_into_subrange() {
1057 let s_big = DenseVectorSpace::new(5);
1058 let s_small = DenseVectorSpace::new(2);
1059 let mut y = DenseVector::new(Rc::clone(&s_big));
1060 y.set(0.0);
1061 let x = vec_of(&s_small, &[7.0, 8.0]);
1062 y.copy_to_pos(2, &x);
1063 assert_eq!(y.values(), &[0.0, 0.0, 7.0, 8.0, 0.0]);
1064 }
1065
1066 #[test]
1067 fn make_new_copy_clones_values() {
1068 let s = DenseVectorSpace::new(3);
1069 let x = vec_of(&s, &[1.0, 2.0, 3.0]);
1070 let y = x.make_new_copy();
1071 let dy = y.as_any().downcast_ref::<DenseVector>().unwrap();
1072 assert_eq!(dy.values(), &[1.0, 2.0, 3.0]);
1073 }
1074
1075 #[test]
1076 fn add_vector_quotient_all_homogeneous() {
1077 let s = DenseVectorSpace::new(4);
1078 let mut y = DenseVector::new(Rc::clone(&s));
1079 y.set(1.0);
1080 let mut z = DenseVector::new(Rc::clone(&s));
1081 z.set(6.0);
1082 let mut sd = DenseVector::new(Rc::clone(&s));
1083 sd.set(2.0);
1084 y.add_vector_quotient(2.0, &z, &sd, 0.5);
1086 assert!(y.is_homogeneous());
1087 assert_eq!(y.scalar(), 6.5);
1088 }
1089
1090 #[test]
1091 fn dim_zero_is_consistent() {
1092 let s = DenseVectorSpace::new(0);
1093 let x = DenseVector::new(Rc::clone(&s));
1094 assert!(x.is_initialized());
1095 assert!(x.is_homogeneous());
1096 assert_eq!(x.nrm2(), 0.0);
1097 }
1098}