1use super::variance::{Concat, Contract, Contracted, Joined, OtherIndex};
4use super::{ContravariantIndex, CovariantIndex, IndexType, TensorIndex, Variance};
5use crate::coordinates::{ConversionTo, CoordinateSystem, Point};
6use crate::typenum::consts::{B1, U2};
7use crate::typenum::uint::Unsigned;
8use crate::typenum::{Add1, Exp, Pow, Same};
9use generic_array::{ArrayLength, GenericArray};
10use std::ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
11use std::ops::{Index, IndexMut};
12
13pub struct Tensor<T: CoordinateSystem, U: Variance>
25where
26 T::Dimension: Pow<U::Rank>,
27 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
28{
29 p: Point<T>,
30 x: GenericArray<f64, Exp<T::Dimension, U::Rank>>,
31}
32
33impl<T, U> Clone for Tensor<T, U>
34where
35 T: CoordinateSystem,
36 U: Variance,
37 T::Dimension: Pow<U::Rank>,
38 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
39{
40 fn clone(&self) -> Tensor<T, U> {
41 Tensor {
42 p: self.p.clone(),
43 x: self.x.clone(),
44 }
45 }
46}
47
48impl<T, U> Copy for Tensor<T, U>
49where
50 T: CoordinateSystem,
51 U: Variance,
52 T::Dimension: Pow<U::Rank>,
53 <T::Dimension as ArrayLength<f64>>::ArrayType: Copy,
54 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
55 <Exp<T::Dimension, U::Rank> as ArrayLength<f64>>::ArrayType: Copy,
56{
57}
58
59pub struct CoordIterator<U>
61where
62 U: Variance,
63 U::Rank: ArrayLength<usize>,
64{
65 started: bool,
66 dimension: usize,
67 cur_coord: GenericArray<usize, U::Rank>,
68}
69
70impl<U> CoordIterator<U>
71where
72 U: Variance,
73 U::Rank: ArrayLength<usize>,
74{
75 pub fn new(dimension: usize) -> CoordIterator<U> {
76 CoordIterator {
77 started: false,
78 dimension: dimension,
79 cur_coord: GenericArray::default(),
80 }
81 }
82}
83
84impl<U> Iterator for CoordIterator<U>
85where
86 U: Variance,
87 U::Rank: ArrayLength<usize>,
88{
89 type Item = GenericArray<usize, U::Rank>;
90
91 fn next(&mut self) -> Option<Self::Item> {
92 if !self.started {
93 self.started = true;
94 return Some(self.cur_coord.clone());
95 }
96
97 if self.cur_coord.len() < 1 {
99 return None;
100 }
101
102 let mut i = self.cur_coord.len() - 1;
103 loop {
104 self.cur_coord[i] += 1;
105 if self.cur_coord[i] < self.dimension {
106 break;
107 }
108 self.cur_coord[i] = 0;
109 if i == 0 {
110 return None;
111 }
112 i -= 1;
113 }
114
115 Some(self.cur_coord.clone())
116 }
117}
118
119impl<T, V> Tensor<T, V>
120where
121 T: CoordinateSystem,
122 V: Variance,
123 T::Dimension: Pow<V::Rank>,
124 Exp<T::Dimension, V::Rank>: ArrayLength<f64>,
125{
126 pub fn get_point(&self) -> &Point<T> {
128 &self.p
129 }
130
131 pub fn set_point(&mut self, p: Point<T>) {
133 self.p = p;
134 }
135
136 pub fn coords_array(&self) -> &GenericArray<f64, Exp<T::Dimension, V::Rank>> {
138 &self.x
139 }
140
141 pub fn get_coord(i: &[usize]) -> usize {
147 assert_eq!(i.len(), V::rank());
148 let dim = T::dimension();
149 let index = i.into_iter().fold(0, |res, idx| {
150 assert!(*idx < dim);
151 res * dim + idx
152 });
153 index
154 }
155
156 pub fn get_variance() -> Vec<IndexType> {
159 V::variance()
160 }
161
162 pub fn get_rank() -> usize {
164 V::rank()
165 }
166
167 pub fn get_num_coords() -> usize {
169 <T::Dimension as Pow<V::Rank>>::Output::to_usize()
170 }
171
172 pub fn zero(point: Point<T>) -> Tensor<T, V> {
174 Tensor {
175 p: point,
176 x: GenericArray::default(),
177 }
178 }
179
180 pub fn new(
190 point: Point<T>,
191 coords: GenericArray<f64, Exp<T::Dimension, V::Rank>>,
192 ) -> Tensor<T, V> {
193 Tensor {
194 p: point,
195 x: coords,
196 }
197 }
198
199 pub fn from_slice(point: Point<T>, slice: &[f64]) -> Tensor<T, V> {
209 assert_eq!(Tensor::<T, V>::get_num_coords(), slice.len());
210 Tensor {
211 p: point,
212 x: GenericArray::clone_from_slice(slice),
213 }
214 }
215
216 pub fn trace<Ul, Uh>(&self) -> Tensor<T, Contracted<V, Ul, Uh>>
220 where
221 Ul: Unsigned,
222 Uh: Unsigned,
223 V: Contract<Ul, Uh>,
224 <Contracted<V, Ul, Uh> as Variance>::Rank: ArrayLength<usize>,
225 T::Dimension: Pow<<Contracted<V, Ul, Uh> as Variance>::Rank>,
226 Exp<T::Dimension, <Contracted<V, Ul, Uh> as Variance>::Rank>: ArrayLength<f64>,
227 {
228 let index1 = Ul::to_usize();
229 let index2 = Uh::to_usize();
230 let rank = V::Rank::to_usize();
231 let dim = T::Dimension::to_usize();
232
233 let mut result = Tensor::<T, Contracted<V, Ul, Uh>>::zero(self.p.clone());
234 let num_coords_result = Tensor::<T, Contracted<V, Ul, Uh>>::get_num_coords();
235 let modh = dim.pow((rank - 1 - index2) as u32);
236 let modl = dim.pow((rank - 2 - index1) as u32);
237
238 for coord in 0..num_coords_result {
239 let coord1 = coord / modl;
240 let coord1rest = coord % modl;
241 let coord2 = coord1rest / modh;
242 let coord2rest = coord1rest % modh;
243 let coord_template = coord1 * modl * dim * dim + coord2 * modh * dim + coord2rest;
244 let mut sum = 0.0;
245
246 for i in 0..T::dimension() {
247 sum += self[coord_template + i * modl * dim + i * modh];
248 }
249
250 result[coord] = sum;
251 }
252
253 result
254 }
255}
256
257impl<T, U> Tensor<T, U>
258where
259 T: CoordinateSystem,
260 U: Variance,
261 U::Rank: ArrayLength<usize>,
262 T::Dimension: Pow<U::Rank>,
263 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
264{
265 pub fn iter_coords(&self) -> CoordIterator<U> {
267 CoordIterator::new(T::dimension())
268 }
269}
270
271impl<'a, T, U> Index<&'a [usize]> for Tensor<T, U>
272where
273 T: CoordinateSystem,
274 U: Variance,
275 T::Dimension: Pow<U::Rank>,
276 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
277{
278 type Output = f64;
279
280 fn index(&self, idx: &'a [usize]) -> &f64 {
281 &self.x[Self::get_coord(idx)]
282 }
283}
284
285impl<'a, T, U> IndexMut<&'a [usize]> for Tensor<T, U>
286where
287 T: CoordinateSystem,
288 U: Variance,
289 T::Dimension: Pow<U::Rank>,
290 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
291{
292 fn index_mut(&mut self, idx: &'a [usize]) -> &mut f64 {
293 &mut self.x[Self::get_coord(idx)]
294 }
295}
296
297impl<'a, T, U> Index<usize> for Tensor<T, U>
298where
299 T: CoordinateSystem,
300 U: Variance,
301 T::Dimension: Pow<U::Rank>,
302 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
303{
304 type Output = f64;
305
306 fn index(&self, idx: usize) -> &f64 {
307 &self.x[idx]
308 }
309}
310
311impl<'a, T, U> IndexMut<usize> for Tensor<T, U>
312where
313 T: CoordinateSystem,
314 U: Variance,
315 T::Dimension: Pow<U::Rank>,
316 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
317{
318 fn index_mut(&mut self, idx: usize) -> &mut f64 {
319 &mut self.x[idx]
320 }
321}
322
323pub type Scalar<T> = Tensor<T, ()>;
327
328pub type Vector<T> = Tensor<T, ContravariantIndex>;
330
331pub type Covector<T> = Tensor<T, CovariantIndex>;
333
334pub type Matrix<T> = Tensor<T, (ContravariantIndex, CovariantIndex)>;
336
337pub type TwoForm<T> = Tensor<T, (CovariantIndex, CovariantIndex)>;
339
340pub type InvTwoForm<T> = Tensor<T, (ContravariantIndex, ContravariantIndex)>;
342
343impl<T: CoordinateSystem> Deref for Scalar<T> {
344 type Target = f64;
345
346 fn deref(&self) -> &f64 {
347 &self.x[0]
348 }
349}
350
351impl<T: CoordinateSystem> DerefMut for Scalar<T> {
352 fn deref_mut(&mut self) -> &mut f64 {
353 &mut self.x[0]
354 }
355}
356
357impl<T, U> AddAssign<Tensor<T, U>> for Tensor<T, U>
360where
361 T: CoordinateSystem,
362 U: Variance,
363 T::Dimension: Pow<U::Rank>,
364 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
365{
366 fn add_assign(&mut self, rhs: Tensor<T, U>) {
367 assert!(self.p == rhs.p);
368 for i in 0..(Tensor::<T, U>::get_num_coords()) {
369 self[i] += rhs[i];
370 }
371 }
372}
373
374impl<T, U> Add<Tensor<T, U>> for Tensor<T, U>
375where
376 T: CoordinateSystem,
377 U: Variance,
378 T::Dimension: Pow<U::Rank>,
379 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
380{
381 type Output = Tensor<T, U>;
382
383 fn add(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
384 self += rhs;
385 self
386 }
387}
388
389impl<T, U> SubAssign<Tensor<T, U>> for Tensor<T, U>
390where
391 T: CoordinateSystem,
392 U: Variance,
393 T::Dimension: Pow<U::Rank>,
394 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
395{
396 fn sub_assign(&mut self, rhs: Tensor<T, U>) {
397 assert!(self.p == rhs.p);
398 for i in 0..(Tensor::<T, U>::get_num_coords()) {
399 self[i] -= rhs[i];
400 }
401 }
402}
403
404impl<T, U> Sub<Tensor<T, U>> for Tensor<T, U>
405where
406 T: CoordinateSystem,
407 U: Variance,
408 T::Dimension: Pow<U::Rank>,
409 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
410{
411 type Output = Tensor<T, U>;
412
413 fn sub(mut self, rhs: Tensor<T, U>) -> Tensor<T, U> {
414 self -= rhs;
415 self
416 }
417}
418
419impl<T, U> MulAssign<f64> for Tensor<T, U>
420where
421 T: CoordinateSystem,
422 U: Variance,
423 T::Dimension: Pow<U::Rank>,
424 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
425{
426 fn mul_assign(&mut self, rhs: f64) {
427 for i in 0..(Tensor::<T, U>::get_num_coords()) {
428 self[i] *= rhs;
429 }
430 }
431}
432
433impl<T, U> Mul<f64> for Tensor<T, U>
434where
435 T: CoordinateSystem,
436 U: Variance,
437 T::Dimension: Pow<U::Rank>,
438 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
439{
440 type Output = Tensor<T, U>;
441
442 fn mul(mut self, rhs: f64) -> Tensor<T, U> {
443 self *= rhs;
444 self
445 }
446}
447
448impl<T, U> Mul<Tensor<T, U>> for f64
449where
450 T: CoordinateSystem,
451 U: Variance,
452 T::Dimension: Pow<U::Rank>,
453 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
454{
455 type Output = Tensor<T, U>;
456
457 fn mul(self, mut rhs: Tensor<T, U>) -> Tensor<T, U> {
458 rhs *= self;
459 rhs
460 }
461}
462
463impl<T, U> DivAssign<f64> for Tensor<T, U>
464where
465 T: CoordinateSystem,
466 U: Variance,
467 T::Dimension: Pow<U::Rank>,
468 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
469{
470 fn div_assign(&mut self, rhs: f64) {
471 for i in 0..(Tensor::<T, U>::get_num_coords()) {
472 self[i] /= rhs;
473 }
474 }
475}
476
477impl<T, U> Div<f64> for Tensor<T, U>
478where
479 T: CoordinateSystem,
480 U: Variance,
481 T::Dimension: Pow<U::Rank>,
482 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
483{
484 type Output = Tensor<T, U>;
485
486 fn div(mut self, rhs: f64) -> Tensor<T, U> {
487 self /= rhs;
488 self
489 }
490}
491
492impl<T, U, V> Mul<Tensor<T, V>> for Tensor<T, U>
496where
497 T: CoordinateSystem,
498 U: Variance,
499 V: Variance,
500 U::Rank: ArrayLength<usize>,
501 V::Rank: ArrayLength<usize>,
502 T::Dimension: Pow<U::Rank> + Pow<V::Rank>,
503 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
504 Exp<T::Dimension, V::Rank>: ArrayLength<f64>,
505 U: Concat<V>,
506 Joined<U, V>: Variance,
507 T::Dimension: Pow<<Joined<U, V> as Variance>::Rank>,
508 Exp<T::Dimension, <Joined<U, V> as Variance>::Rank>: ArrayLength<f64>,
509{
510 type Output = Tensor<T, Joined<U, V>>;
511
512 fn mul(self, rhs: Tensor<T, V>) -> Tensor<T, Joined<U, V>> {
513 assert!(self.p == rhs.p);
514 let mut result = Tensor::zero(self.p.clone());
515 let num_coords2 = Tensor::<T, V>::get_num_coords();
516 let num_coords_result = Tensor::<T, Joined<U, V>>::get_num_coords();
517 for coord in 0..num_coords_result {
518 let coord1 = coord / num_coords2;
519 let coord2 = coord % num_coords2;
520 result[coord] = self[coord1] * rhs[coord2];
521 }
522 result
523 }
524}
525
526pub trait InnerProduct<Rhs, Ul: Unsigned, Uh: Unsigned> {
533 type Output;
534
535 fn inner_product(self, rhs: Rhs) -> Self::Output;
536}
537
538impl<T, U, V, Ul, Uh> InnerProduct<Tensor<T, V>, Ul, Uh> for Tensor<T, U>
539where
540 T: CoordinateSystem,
541 U: Variance,
542 V: Variance,
543 Ul: Unsigned,
544 Uh: Unsigned,
545 T::Dimension: Pow<U::Rank> + Pow<V::Rank>,
546 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
547 Exp<T::Dimension, V::Rank>: ArrayLength<f64>,
548 U: Concat<V>,
549 Joined<U, V>: Contract<Ul, Uh>,
550 <Contracted<Joined<U, V>, Ul, Uh> as Variance>::Rank: ArrayLength<usize>,
551 T::Dimension: Pow<<Contracted<Joined<U, V>, Ul, Uh> as Variance>::Rank>,
552 Exp<T::Dimension, <Contracted<Joined<U, V>, Ul, Uh> as Variance>::Rank>: ArrayLength<f64>,
553{
554 type Output = Tensor<T, Contracted<Joined<U, V>, Ul, Uh>>;
555
556 fn inner_product(self, rhs: Tensor<T, V>) -> Tensor<T, Contracted<Joined<U, V>, Ul, Uh>> {
557 assert_eq!(self.p, rhs.p);
558 let indexl = Ul::to_usize();
559 let indexh = Uh::to_usize();
560 let num_coords_result = Tensor::<T, Contracted<Joined<U, V>, Ul, Uh>>::get_num_coords();
561 let u_rank = U::Rank::to_usize();
562 let v_rank = V::Rank::to_usize();
563 let dim = T::Dimension::to_usize();
564
565 let mut result = Tensor::<T, Contracted<Joined<U, V>, Ul, Uh>>::zero(self.p.clone());
566 let (modl, modh, modv) = match (indexl < u_rank, indexh < u_rank) {
567 (true, true) => (
568 dim.pow((u_rank - 2 - indexl) as u32),
569 dim.pow((u_rank - 1 - indexh) as u32),
570 dim.pow(v_rank as u32),
571 ),
572 (true, false) => (
573 dim.pow((u_rank - 1 - indexl) as u32),
574 dim.pow((u_rank + v_rank - 1 - indexh) as u32),
575 dim.pow((v_rank - 1) as u32),
576 ),
577 (false, false) => (
578 dim.pow((u_rank + v_rank - 2 - indexl) as u32),
579 dim.pow((u_rank + v_rank - 1 - indexh) as u32),
580 dim.pow(v_rank as u32),
581 ),
582 _ => unreachable!(),
583 };
584
585 let to_templates_both1 = |coord| {
586 let coords1 = coord / modv;
587 let coords2 = coord % modv;
588 let coords1part1 = coords1 / modl;
589 let coords1part2 = (coords1 % modl) / modh;
590 let coords1part3 = coords1 % modh;
591 (
592 coords1part1 * modl * dim * dim + coords1part2 * modh * dim + coords1part3,
593 coords2,
594 modl + modh,
595 0,
596 )
597 };
598
599 let to_templates_both2 = |coord| {
600 let coords1 = coord / modv;
601 let coords2 = coord % modv;
602 let coords2part1 = coords2 / modl;
603 let coords2part2 = (coords2 % modl) / modh;
604 let coords2part3 = coords2 % modh;
605 (
606 coords1,
607 coords2part1 * modl * dim * dim + coords2part2 * modh * dim + coords2part3,
608 0,
609 modl + modh,
610 )
611 };
612
613 let to_templates = |coord| {
614 let coords1 = coord / modv;
615 let coords2 = coord % modv;
616 let coords1part1 = coords1 / modl;
617 let coords1part2 = coords1 % modl;
618 let coords2part1 = coords2 / modh;
619 let coords2part2 = coords2 % modh;
620 (
621 coords1part1 * modl * dim + coords1part2,
622 coords2part1 * modh * dim + coords2part2,
623 modl,
624 modh,
625 )
626 };
627
628 let templates: &Fn(usize) -> (usize, usize, usize, usize) =
629 match (indexl < u_rank, indexh < u_rank) {
630 (false, false) => &to_templates_both2,
631 (true, false) => &to_templates,
632 (true, true) => &to_templates_both1,
633 _ => unreachable!(),
634 };
635
636 for coord in 0..num_coords_result {
637 let mut sum = 0.0;
638 let (mut coord1, mut coord2, step1, step2) = templates(coord);
639 for _ in 0..dim {
640 sum += self[coord1] * rhs[coord2];
641 coord1 += step1;
642 coord2 += step2;
643 }
644 result[coord] = sum;
645 }
646
647 result
648 }
649}
650
651impl<T, Ul, Ur> Tensor<T, (Ul, Ur)>
652where
653 T: CoordinateSystem,
654 Ul: TensorIndex + OtherIndex,
655 Ur: TensorIndex + OtherIndex,
656 Add1<Ul::Rank>: Unsigned + Add<B1>,
657 Add1<Ur::Rank>: Unsigned + Add<B1>,
658 Add1<<<Ul as OtherIndex>::Output as Variance>::Rank>: Unsigned + Add<B1>,
659 Add1<<<Ur as OtherIndex>::Output as Variance>::Rank>: Unsigned + Add<B1>,
660 <(Ul, Ur) as Variance>::Rank: ArrayLength<usize>,
661 T::Dimension: Pow<Add1<Ul::Rank>> + Pow<Add1<Ur::Rank>> + ArrayLength<usize>,
662 T::Dimension: Pow<Add1<<<Ul as OtherIndex>::Output as Variance>::Rank>>,
663 T::Dimension: Pow<Add1<<<Ur as OtherIndex>::Output as Variance>::Rank>>,
664 Exp<T::Dimension, Add1<Ul::Rank>>: ArrayLength<f64>,
665 Exp<T::Dimension, Add1<Ur::Rank>>: ArrayLength<f64>,
666 Exp<T::Dimension, Add1<<<Ul as OtherIndex>::Output as Variance>::Rank>>: ArrayLength<f64>,
667 Exp<T::Dimension, Add1<<<Ur as OtherIndex>::Output as Variance>::Rank>>: ArrayLength<f64>,
668{
669 pub fn unit(p: Point<T>) -> Tensor<T, (Ul, Ur)> {
671 let mut result = Tensor::<T, (Ul, Ur)>::zero(p);
672
673 for i in 0..T::dimension() {
674 let coords: &[usize] = &[i, i];
675 result[coords] = 1.0;
676 }
677
678 result
679 }
680
681 pub fn transpose(&self) -> Tensor<T, (Ur, Ul)> {
683 let mut result = Tensor::<T, (Ur, Ul)>::zero(self.p.clone());
684
685 for coords in self.iter_coords() {
686 let coords2: &[usize] = &[coords[1], coords[0]];
687 result[coords2] = self[&*coords];
688 }
689
690 result
691 }
692
693 fn lu_decompose(&mut self) -> Option<GenericArray<usize, T::Dimension>> {
697 let n = T::dimension();
698 let absmin = 1.0e-30_f64;
699 let mut result = GenericArray::default();
700 let mut row_norm = GenericArray::<f64, T::Dimension>::default();
701
702 let mut max_row = 0;
703
704 for i in 0..n {
705 let mut absmax = 0.0;
706
707 for j in 0..n {
708 let coord: &[usize] = &[i, j];
709 let maxtemp = self[coord].abs();
710 absmax = if maxtemp > absmax { maxtemp } else { absmax };
711 }
712
713 if absmax == 0.0 {
714 return None;
715 }
716
717 row_norm[i] = 1.0 / absmax;
718 }
719
720 for j in 0..n {
721 for i in 0..j {
722 for k in 0..i {
723 let coord1: &[usize] = &[i, j];
724 let coord2: &[usize] = &[i, k];
725 let coord3: &[usize] = &[k, j];
726
727 self[coord1] -= self[coord2] * self[coord3];
728 }
729 }
730
731 let mut absmax = 0.0;
732
733 for i in j..n {
734 let coord1: &[usize] = &[i, j];
735
736 for k in 0..j {
737 let coord2: &[usize] = &[i, k];
738 let coord3: &[usize] = &[k, j];
739
740 self[coord1] -= self[coord2] * self[coord3];
741 }
742
743 let maxtemp = self[coord1].abs() * row_norm[i];
744
745 if maxtemp > absmax {
746 absmax = maxtemp;
747 max_row = i;
748 }
749 }
750
751 if max_row != j {
752 if (j == n - 2) && self[&[j, j + 1] as &[usize]] == 0.0 {
753 max_row = j;
754 } else {
755 for k in 0..n {
756 let jk: &[usize] = &[j, k];
757 let maxrow_k: &[usize] = &[max_row, k];
758 let maxtemp = self[jk];
759 self[jk] = self[maxrow_k];
760 self[maxrow_k] = maxtemp;
761 }
762
763 row_norm[max_row] = row_norm[j];
764 }
765 }
766
767 result[j] = max_row;
768
769 let jj: &[usize] = &[j, j];
770
771 if self[jj] == 0.0 {
772 self[jj] = absmin;
773 }
774
775 if j != n - 1 {
776 let maxtemp = 1.0 / self[jj];
777 for i in j + 1..n {
778 self[&[i, j] as &[usize]] *= maxtemp;
779 }
780 }
781 }
782
783 Some(result)
784 }
785
786 fn lu_substitution(
788 &self,
789 b: &GenericArray<f64, T::Dimension>,
790 permute: &GenericArray<usize, T::Dimension>,
791 ) -> GenericArray<f64, T::Dimension> {
792 let mut result = b.clone();
793 let n = T::dimension();
794
795 for i in 0..n {
796 let mut tmp = result[permute[i]];
797 result[permute[i]] = result[i];
798 for j in (0..i).rev() {
799 tmp -= self[&[i, j] as &[usize]] * result[j];
800 }
801 result[i] = tmp;
802 }
803
804 for i in (0..n).rev() {
805 for j in i + 1..n {
806 result[i] -= self[&[i, j] as &[usize]] * result[j];
807 }
808 result[i] /= self[&[i, i] as &[usize]];
809 }
810
811 result
812 }
813
814 pub fn inverse(
819 &self,
820 ) -> Option<Tensor<T, (<Ul as OtherIndex>::Output, <Ur as OtherIndex>::Output)>> {
821 let mut result =
822 Tensor::<T, (<Ul as OtherIndex>::Output, <Ur as OtherIndex>::Output)>::zero(
823 self.p.clone(),
824 );
825
826 let mut tmp = self.clone();
827
828 let permute = match tmp.lu_decompose() {
829 Some(p) => p,
830 None => return None,
831 };
832
833 for i in 0..T::dimension() {
834 let mut dxm = GenericArray::<f64, T::Dimension>::default();
835 dxm[i] = 1.0;
836
837 let x = tmp.lu_substitution(&dxm, &permute);
838
839 for k in 0..T::dimension() {
840 result[&[k, i] as &[usize]] = x[k];
841 }
842 }
843
844 Some(result)
845 }
846}
847
848impl<T, U> Tensor<T, U>
849where
850 T: CoordinateSystem,
851 U: Variance,
852 U::Rank: ArrayLength<usize>,
853 T::Dimension: Pow<U::Rank>,
854 Exp<T::Dimension, U::Rank>: ArrayLength<f64>,
855{
856 pub fn convert<T2>(&self) -> Tensor<T2, U>
857 where
858 T2: CoordinateSystem + 'static,
859 T2::Dimension: Pow<U::Rank> + Pow<U2> + Same<T::Dimension>,
860 Exp<T2::Dimension, U::Rank>: ArrayLength<f64>,
861 Exp<T2::Dimension, U2>: ArrayLength<f64>,
862 T: ConversionTo<T2>,
863 {
864 let mut result = Tensor::<T2, U>::zero(<T as ConversionTo<T2>>::convert_point(&self.p));
865
866 let jacobian = <T as ConversionTo<T2>>::jacobian(&self.p);
867 let inv_jacobian = <T as ConversionTo<T2>>::inv_jacobian(&self.p);
868 let variance = <U as Variance>::variance();
869
870 for i in result.iter_coords() {
871 let mut temp = 0.0;
872 for j in self.iter_coords() {
873 let mut temp2 = self[&*j];
874 for (k, v) in variance.iter().enumerate() {
875 let coords = [i[k], j[k]];
876 temp2 *= match *v {
877 IndexType::Covariant => inv_jacobian[&coords[..]],
878 IndexType::Contravariant => jacobian[&coords[..]],
879 };
880 }
881 temp += temp2;
882 }
883 result[&*i] = temp;
884 }
885
886 result
887 }
888}