请教一下,如何把Vec<Vec<f64>>
转化为 &[[T]]
。
想做一点科学计算,需要用到ndarray
来加速矩阵的计算。写了如下的Enum
并使用raw2array
来互相转化:
#[derive(Debug, PartialEq)]
pub enum Matrix {
Raw(Vec<Vec<f64>>),
Array(Array2<f64>),
}
impl Matrix {
pub fn raw2array(&self) -> Self {
match self {
Matrix::Raw(x) => {
let m = x.len();
let n = x[0].len();
let arr: Vec<f64> = x.into_iter().flatten().cloned().collect();
let foo = Array::from_iter(arr.into_iter()).into_shape((m, n)).unwrap();
Matrix::Array(foo)
},
_ => {panic!("It is not a Matrix::Raw so that cannot be converted to a Matrix::Array using function raw2array!")},
}
}
}
ndarray
无法接收一个Vec<Vec<f64>>
来进行转化,而是需要使用如arr2(&[[0., 1.], [2., 3.]])
来生成一个二维矩阵。我知道as_slice()
有类似功能,但是对于二维Vec
来说,貌似会变成&[Vec<f64>]
这种形式。在这里,我目前的做法是想把二维的Vec
压成一维,然后使用ndarray
自带的into_shape
功能进行转化。
但我总觉得这样的效率可能有些低,请问有更直接一点的方法吗?
PS:因为我希望使用的时候只用Vec<T>
进行输入输出,内部转化和加速计算细节不对外暴露,所以输入是强制性的Vec<T>
, Vec<Vec<T>>
,或Vec<Vec<Vec<T>>>
。
1
共 13 条评论, 1 页
评论区
写评论非常感谢你的回复。我现在意识到了不能转化了。一行行复制的话,
ndarray
库有现成的运行时定长的数组生成功能,实测还蛮好用。--
👇
Aya0wind: 不能直接转化,这两个内存布局都不一样。你只能创建一个新的二维数组,然后一行行的复制。 如果你要一个不定长的内存连续的二维数组,那就用一维的vec,然后外面包一层wrapper,提供一套使用二维下标的接口,你在里面把二维的下标换算成一维的,vec长度就是长乘宽。
感谢你持续关注这个帖子。不过,vec自带len计数,所以没必要添加额外的dimension来吧。目前看下来,估计只有重建这一条路了。你的这个
into_array2
函数的想法非常好用。实测,大概效率是我原先的三倍。感谢!--
👇
ezlearning: 关键还是要知道矩阵维度。这样做吧:
不能直接转化,这两个内存布局都不一样。你只能创建一个新的二维数组,然后一行行的复制。 如果你要一个不定长的内存连续的二维数组,那就用一维的vec,然后外面包一层wrapper,提供一套使用二维下标的接口,你在里面把二维的下标换算成一维的,vec长度就是长乘宽。
是的,估计这也是为什么要求转成
array
的原因吧。1.51 stable还没出吧?之后我会关注下的。谢谢你,学到了可能会用到的新知识。--
👇
Neutron3529: 试试1.51的常量泛型好了。
反正如果用Vec<Vec>,你几乎没办法获得任何加速的。
感谢你的回复,学到了很多关于内存布局的细节。但是原函数要求输入是
&[[f64]]
而不是&[&[f64]]
,想来原库是要求完全按照array
来布局数据,然后传入&array
引用。在你科普之后,我个人的想法是,估计还是只能老办法,重建一个array
了。--
👇
cnwzhjs: 很不幸,
Vec<Vec<f64>>
是无法转化为&[[f64]]
的。 根本原因在于Vec的内存布局:可以看到,在内存中,它有一个pointer、一个cap,一个len。而slice的在内存中额数据结构是一个pointer、一个len。
所以,当你持有一个
Vec<Vec<f64>>
时,是可以生成一个&[Vec<64>]的slice的,做法上只需把外层Vec的ptr和len拿出来即可生成slice。但是,由于内层每个也都是Vec的时候,没法直接生成slice of array的。
对应的,你可以生成Vec<&[f64]>,进而再生成&[&[f64]],也就是slice of slice:
关键还是要知道矩阵维度。这样做吧:
试试1.51的常量泛型好了。
反正如果用Vec<Vec>,你几乎没办法获得任何加速的。
很不幸,
Vec<Vec<f64>>
是无法转化为&[[f64]]
的。 根本原因在于Vec的内存布局:可以看到,在内存中,它有一个pointer、一个cap,一个len。而slice的在内存中额数据结构是一个pointer、一个len。
所以,当你持有一个
Vec<Vec<f64>>
时,是可以生成一个&[Vec<64>]的slice的,做法上只需把外层Vec的ptr和len拿出来即可生成slice。但是,由于内层每个也都是Vec的时候,没法直接生成slice of array的。
对应的,你可以生成Vec<&[f64]>,进而再生成&[&[f64]],也就是slice of slice:
我可能会出现
500 x 500
或者300 x 300
的矩阵。这取决于问题。不能固定这个数值。👇
ezlearning: 不要用Vec, 这表示不了维度。 用:Vec<[f64; 2]>。
感谢你的回复!但是问题在于,我的
v
是一个n x n
的方阵。不仅如此,我的这个n
是无法固定的,由运行时输入的参数决定的。所以我希望的是能够使用Vec<Vec<f64>>
来表达数组。比如一个3 x 3
的数组,可以写成如vec![vec![0., 1., 2.], vec![3., 4., 5.], vec![6., 7., 8.]]
。 字面值的一个问题是我无法设定一个类似[[0; n]; n]的数组字面值。--
👇
ezlearning: 不要用Vec, 这表示不了维度。 用:Vec<[f64; 2]>。
不要用Vec, 这表示不了维度。 用:Vec<[f64; 2]>。
非常感谢你的回复,这个quick-start的帮助很大。但是我看了下,里面仍然没有可以满足我想法的写法例子。
ndarray
的指南中,基本都是用数组字面
也就是[T]
来生成Array
。而为了方便,我的输入强制要求是Vec
。当然,一维的Vec
很容易转化为&[T]
,但是Vec<Vec<T>>
我一直没找到好的办法。👇
ezlearning: https://github.com/rust-ndarray/ndarray/blob/master/README-quick-start.md
也许这个已经能满足你的需要了哈
https://github.com/rust-ndarray/ndarray/blob/master/README-quick-start.md
也许这个已经能满足你的需要了哈