1#[cfg(feature = "python")]
39use pyo3::prelude::*;
40
41#[cfg(feature = "python")]
42use scirs2_numpy::{
43 Element, PyArray, PyArray1, PyArray2, PyArrayDyn, PyArrayMethods, PyReadonlyArray,
44 PyReadonlyArrayDyn, PyUntypedArrayMethods,
45};
46
47#[cfg(feature = "python")]
50pub use ::ndarray::{
51 arr1, arr2, array, s, Array, Array0, Array1, Array2, Array3, Array4, ArrayBase, ArrayD,
52 ArrayView, ArrayView1, ArrayView2, ArrayViewD, ArrayViewMut, ArrayViewMut1, ArrayViewMut2,
53 ArrayViewMutD, Axis, Data, DataMut, DataOwned, Dim, Dimension, Ix0, Ix1, Ix2, Ix3, Ix4, IxDyn,
54 IxDynImpl, OwnedRepr, RawData, ViewRepr, Zip,
55};
56
57#[cfg(feature = "python")]
59pub type NumpyCompatArrayD<T> = ArrayD<T>;
60
61#[cfg(feature = "python")]
63pub type NumpyCompatArray1<T> = Array1<T>;
64
65#[cfg(feature = "python")]
67pub type NumpyCompatArray2<T> = Array2<T>;
68
69#[cfg(feature = "python")]
78pub fn numpy_to_scirs_arrayd<'py, T>(array: &Bound<'py, PyArrayDyn<T>>) -> PyResult<ArrayD<T>>
79where
80 T: Element + Clone,
81{
82 let readonly = array.readonly();
83 let array_ref = readonly.as_array();
84
85 Ok(array_ref.to_owned())
90}
91
92#[cfg(feature = "python")]
94pub fn numpy_readonly_to_scirs_arrayd<T>(array: PyReadonlyArrayDyn<T>) -> PyResult<ArrayD<T>>
95where
96 T: Element + Clone,
97{
98 Ok(array.as_array().to_owned())
99}
100
101#[cfg(feature = "python")]
103pub fn scirs_to_numpy_arrayd<T: Element>(
104 array: ArrayD<T>,
105 py: Python<'_>,
106) -> PyResult<Py<PyArrayDyn<T>>> {
107 Ok(PyArrayDyn::from_owned_array(py, array).unbind())
108}
109
110#[cfg(feature = "python")]
112pub fn scirs_to_numpy_array1<T: Element>(
113 array: Array1<T>,
114 py: Python<'_>,
115) -> PyResult<Py<PyArray1<T>>> {
116 Ok(PyArray1::from_owned_array(py, array).unbind())
117}
118
119#[cfg(feature = "python")]
121pub fn scirs_to_numpy_array2<T: Element>(
122 array: Array2<T>,
123 py: Python<'_>,
124) -> PyResult<Py<PyArray2<T>>> {
125 Ok(PyArray2::from_owned_array(py, array).unbind())
126}
127
128#[cfg(feature = "python")]
134pub fn numpy_batch_to_scirs<T: Element + Clone>(
135 arrays: Vec<PyReadonlyArrayDyn<T>>,
136) -> PyResult<Vec<ArrayD<T>>> {
137 arrays
138 .into_iter()
139 .map(|arr| Ok(arr.as_array().to_owned()))
140 .collect()
141}
142
143#[cfg(feature = "python")]
145pub fn scirs_batch_to_numpy<T: Element>(
146 arrays: Vec<ArrayD<T>>,
147 py: Python<'_>,
148) -> PyResult<Vec<Py<PyArrayDyn<T>>>> {
149 arrays
150 .into_iter()
151 .map(|arr| Ok(PyArrayDyn::from_owned_array(py, arr).unbind()))
152 .collect()
153}
154
155#[cfg(feature = "python")]
172pub fn numpy_readonly_to_scirs_view<'a, T: Element>(
173 array: &'a PyReadonlyArrayDyn<'a, T>,
174) -> ArrayViewD<'a, T> {
175 array.as_array()
176}
177
178#[cfg(feature = "python")]
184pub fn is_numpy_compatible<T: Element>(array: &Bound<'_, PyArrayDyn<T>>) -> bool {
185 array.shape().iter().all(|&dim| dim > 0)
187}
188
189#[cfg(feature = "python")]
191pub enum MemoryLayout {
192 CContiguous,
193 FContiguous,
194 Neither,
195}
196
197#[cfg(feature = "python")]
198pub fn get_numpy_layout<T: Element>(array: &Bound<'_, PyArrayDyn<T>>) -> MemoryLayout {
199 if array.is_c_contiguous() {
200 MemoryLayout::CContiguous
201 } else if array.is_fortran_contiguous() {
202 MemoryLayout::FContiguous
203 } else {
204 MemoryLayout::Neither
205 }
206}
207
208#[cfg(all(test, feature = "python"))]
213mod tests {
214 use super::*;
215 use pyo3::Python;
216
217 #[test]
218 #[allow(deprecated)]
219 fn test_numpy_scirs_roundtrip() {
220 pyo3::Python::attach(|py| {
221 let scirs_array = array![[1.0f32, 2.0], [3.0, 4.0]];
223 let scirs_arrayd = scirs_array.into_dyn();
224
225 let numpy_array =
227 scirs_to_numpy_arrayd(scirs_arrayd.clone(), py).expect("Operation failed");
228
229 let result = numpy_to_scirs_arrayd(&numpy_array.bind(py)).expect("Operation failed");
231
232 assert_eq!(result.shape(), scirs_arrayd.shape());
234 assert_eq!(result, scirs_arrayd);
235 });
236 }
237
238 #[test]
239 #[allow(deprecated)]
240 fn test_zero_copy_view() {
241 pyo3::Python::attach(|py| {
242 let scirs_array = array![[1.0f32, 2.0], [3.0, 4.0]].into_dyn();
243 let numpy_array =
244 scirs_to_numpy_arrayd(scirs_array.clone(), py).expect("Operation failed");
245
246 let readonly = numpy_array.bind(py).readonly();
248 let view = numpy_readonly_to_scirs_view(&readonly);
249
250 assert_eq!(view.shape(), scirs_array.shape());
252 assert_eq!(view[[0, 0]], 1.0f32);
253 });
254 }
255}