Я хотел бы создать 3d-ndarray для представления координат из трех 1d-ndarray, аналогично тому, как работает сетка numpy. например каков эквивалент ржавчины для Python:
a = np.array(
np.meshgrid(
np.linspace(-1, 1, 50),
np.linspace(-1, 1, 50),
np.linspace(-1, 1, 50),
indexing = "ij"
)
)
Хотя он не встроен, мы можем написать свой собственный. Несмотря на то, что он кажется универсальным для всех измерений, он будет работать только с 5 входными массивами, поскольку Dim<[Ix; 6]>
— это наибольшая размерность, реализующая Dimension
. (Помимо этого нам нужно будет выделить динамические массивы и/или использовать IxDyn
.)
use ndarray::{prelude::*, Data, Ix, OwnedRepr, RawData};
use num_traits::Zero;
enum Indexing {
Ij,
Xy,
}
fn meshgrid<S, const N: usize>(
arrs: [ArrayBase<S, Ix1>; N],
indexing: Indexing,
) -> ArrayBase<
OwnedRepr<<S as RawData>::Elem>,
<Dim<[Ix; N]> as Dimension>::Larger,
>
where
S: Data + RawData + Clone,
<S as ndarray::RawData>::Elem: Clone,
Dim<[Ix; N]>: Dimension,
<Dim<[Ix; N]> as Dimension>::Larger: Dimension + Zero,
{
let mut out_shape = <Dim<[Ix; N]> as Dimension>::Larger::zero();
for (i, dim) in out_shape.as_array_view_mut().iter_mut().enumerate() {
*dim = if i == 0 { N } else { arrs[i - 1].len() };
}
let mut out_arrs = Array::uninit(out_shape);
for (i, (mut out_arr, in_arr)) in
out_arrs.outer_iter_mut().zip(&arrs).enumerate()
{
for lane in out_arr.view_mut().lanes_mut(Axis(i)) {
in_arr.assign_to(lane);
}
}
if matches!(indexing, Indexing::Xy) && N > 1 {
out_arrs.swap_axes(N - 1, N - 2);
}
unsafe { out_arrs.assume_init() }
}
fn main() {
let arr1 = Array1::linspace(-1.0, 1.0, 2);
let arr2 = Array1::linspace(-1.0, 1.0, 3);
let arr3 = Array1::linspace(-1.0, 1.0, 4);
let grid = meshgrid([arr1, arr2, arr3], Indexing::Ij);
println!("{grid:?}");
}
[[[[-1.0, -1.0, -1.0, -1.0],
[-1.0, -1.0, -1.0, -1.0],
[-1.0, -1.0, -1.0, -1.0]],
[[1.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 1.0, 1.0],
[1.0, 1.0, 1.0, 1.0]]],
[[[-1.0, -1.0, -1.0, -1.0],
[0.0, 0.0, 0.0, 0.0],
[1.0, 1.0, 1.0, 1.0]],
[[-1.0, -1.0, -1.0, -1.0],
[0.0, 0.0, 0.0, 0.0],
[1.0, 1.0, 1.0, 1.0]]],
[[[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0],
[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0],
[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0]],
[[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0],
[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0],
[-1.0, -0.33333333333333337, 0.33333333333333326, 1.0]]]], shape=[3, 2, 3, 4], strides=[24, 12, 4, 1], layout=Cc (0x5), const ndim=4
Меня не волнует кредит. Не стесняйтесь сделать этот пиар самостоятельно.
Я провел еще немного тестирования и обнаружил, что ваша функция сетки повторяет выходные данные столько же раз, сколько и измерений. Например. meshgrid для 3d выводит массив 4d, содержащий три идентичных массива 3d, например:
let n = 3; let max = 1.0; let min = -1.0; let grid = meshgrid( [ nd::Array::linspace(min, max, n), nd::Array::linspace(min, max, n), nd::Array::zeros(n), ], Indexing::Ij ); println!("{:#?}", grid.slice(nd::s![.., .., .., 0])); println!("========================================================= = "); println!("{:#?}", grid.slice(nd::s![.., .., .., 1])); println!("========================================================= = "); println!("{:#?}", grid.slice(nd::s![.., .., .., 2]));
Не могли бы вы сообщить мне, как я могу это исправить? Я ожидаю, что это относится к этой строке: let mut out_shape = <Dim<[Ix; N]> as Dimension>::Larger::zero();
но, честно говоря, я не так хорошо знаком с чертами ndarray, как вы
Спасибо, есть идеи, почему этого еще нет в
ndarray
? кажется странной вещью, которую стоит опустить, учитывая, насколько популяренmeshgrid
дляnumpy
и что (хотя ваше решение значительно более элегантно, чем то, что я мог бы придумать) реализовать его не кажется очень сложной вещью. P.S. если вы еще не сделали/не планируете делать запрос на включение этой функции вndarray
, вы не возражаете, если я это сделаю (я, конечно, отдам вам должное и дам ссылку на этот вопрос)?