ndarray_linalg/
convert.rs

1//! utilities for convert array
2
3use lax::UPLO;
4use ndarray::*;
5
6use super::error::*;
7use super::layout::*;
8use super::types::*;
9
10pub fn into_col<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
11where
12    S: Data,
13{
14    let n = a.len();
15    a.into_shape_with_order((n, 1)).unwrap()
16}
17
18pub fn into_row<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
19where
20    S: Data,
21{
22    let n = a.len();
23    a.into_shape_with_order((1, n)).unwrap()
24}
25
26pub fn flatten<S>(a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix1>
27where
28    S: Data,
29{
30    let n = a.len();
31    a.into_shape_with_order(n).unwrap()
32}
33
34pub fn into_matrix<A, S>(l: MatrixLayout, a: Vec<A>) -> Result<ArrayBase<S, Ix2>>
35where
36    S: DataOwned<Elem = A>,
37{
38    match l {
39        MatrixLayout::C { row, lda } => {
40            Ok(ArrayBase::from_shape_vec((row as usize, lda as usize), a)?)
41        }
42        MatrixLayout::F { col, lda } => Ok(ArrayBase::from_shape_vec(
43            (lda as usize, col as usize).f(),
44            a,
45        )?),
46    }
47}
48
49pub fn replicate<A, Sv, So, D>(a: &ArrayBase<Sv, D>) -> ArrayBase<So, D>
50where
51    A: Copy,
52    Sv: Data<Elem = A>,
53    So: DataOwned<Elem = A> + DataMut,
54    D: Dimension,
55{
56    unsafe {
57        let ret = ArrayBase::<So, D>::build_uninit(a.dim(), |view| {
58            a.assign_to(view);
59        });
60        ret.assume_init()
61    }
62}
63
64fn clone_with_layout<A, Si, So>(l: MatrixLayout, a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
65where
66    A: Copy,
67    Si: Data<Elem = A>,
68    So: DataOwned<Elem = A> + DataMut,
69{
70    let shape_builder = match l {
71        MatrixLayout::C { row, lda } => (row as usize, lda as usize).set_f(false),
72        MatrixLayout::F { col, lda } => (lda as usize, col as usize).set_f(true),
73    };
74    unsafe {
75        let ret = ArrayBase::<So, _>::build_uninit(shape_builder, |view| {
76            a.assign_to(view);
77        });
78        ret.assume_init()
79    }
80}
81
82pub fn transpose_data<A, S>(a: &mut ArrayBase<S, Ix2>) -> Result<&mut ArrayBase<S, Ix2>>
83where
84    A: Copy,
85    S: DataOwned<Elem = A> + DataMut,
86{
87    let l = a.layout()?.toggle_order();
88    let new = clone_with_layout(l, a);
89    *a = new;
90    Ok(a)
91}
92
93pub fn generalize<A, S, D>(a: Array<A, D>) -> ArrayBase<S, D>
94where
95    S: DataOwned<Elem = A>,
96    D: Dimension,
97{
98    // FIXME
99    // https://github.com/bluss/rust-ndarray/issues/325
100    let strides: Vec<isize> = a.strides().to_vec();
101    let new = if a.is_standard_layout() {
102        ArrayBase::from_shape_vec(a.dim(), a.into_raw_vec_and_offset().0).unwrap()
103    } else {
104        ArrayBase::from_shape_vec(a.dim().f(), a.into_raw_vec_and_offset().0).unwrap()
105    };
106    assert_eq!(
107        new.strides(),
108        strides.as_slice(),
109        "Custom stride is not supported"
110    );
111    new
112}
113
114/// Fills in the remainder of a Hermitian matrix that's represented by only one
115/// triangle.
116///
117/// LAPACK methods on Hermitian matrices usually read/write only one triangular
118/// portion of the matrix. This function fills in the other half based on the
119/// data in the triangular portion corresponding to `uplo`.
120///
121/// ***Panics*** if `a` is not square.
122pub(crate) fn triangular_fill_hermitian<A, S>(a: &mut ArrayBase<S, Ix2>, uplo: UPLO)
123where
124    A: Scalar + Lapack,
125    S: DataMut<Elem = A>,
126{
127    assert!(a.is_square());
128    match uplo {
129        UPLO::Upper => {
130            for row in 0..a.nrows() {
131                for col in 0..row {
132                    a[(row, col)] = a[(col, row)].conj();
133                }
134            }
135        }
136        UPLO::Lower => {
137            for col in 0..a.ncols() {
138                for row in 0..col {
139                    a[(row, col)] = a[(col, row)].conj();
140                }
141            }
142        }
143    }
144}