#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use scirs2_numpy::{
Element, PyArray, PyArray1, PyArray2, PyArrayDyn, PyArrayMethods, PyReadonlyArray,
PyReadonlyArrayDyn, PyUntypedArrayMethods,
};
#[cfg(feature = "python")]
pub use ::ndarray::{
arr1, arr2, array, s, Array, Array0, Array1, Array2, Array3, Array4, ArrayBase, ArrayD,
ArrayView, ArrayView1, ArrayView2, ArrayViewD, ArrayViewMut, ArrayViewMut1, ArrayViewMut2,
ArrayViewMutD, Axis, Data, DataMut, DataOwned, Dim, Dimension, Ix0, Ix1, Ix2, Ix3, Ix4, IxDyn,
IxDynImpl, OwnedRepr, RawData, ViewRepr, Zip,
};
#[cfg(feature = "python")]
pub type NumpyCompatArrayD<T> = ArrayD<T>;
#[cfg(feature = "python")]
pub type NumpyCompatArray1<T> = Array1<T>;
#[cfg(feature = "python")]
pub type NumpyCompatArray2<T> = Array2<T>;
#[cfg(feature = "python")]
pub fn numpy_to_scirs_arrayd<'py, T>(array: &Bound<'py, PyArrayDyn<T>>) -> PyResult<ArrayD<T>>
where
T: Element + Clone,
{
let readonly = array.readonly();
let array_ref = readonly.as_array();
Ok(array_ref.to_owned())
}
#[cfg(feature = "python")]
pub fn numpy_readonly_to_scirs_arrayd<T>(array: PyReadonlyArrayDyn<T>) -> PyResult<ArrayD<T>>
where
T: Element + Clone,
{
Ok(array.as_array().to_owned())
}
#[cfg(feature = "python")]
pub fn scirs_to_numpy_arrayd<T: Element>(
array: ArrayD<T>,
py: Python<'_>,
) -> PyResult<Py<PyArrayDyn<T>>> {
Ok(PyArrayDyn::from_owned_array(py, array).unbind())
}
#[cfg(feature = "python")]
pub fn scirs_to_numpy_array1<T: Element>(
array: Array1<T>,
py: Python<'_>,
) -> PyResult<Py<PyArray1<T>>> {
Ok(PyArray1::from_owned_array(py, array).unbind())
}
#[cfg(feature = "python")]
pub fn scirs_to_numpy_array2<T: Element>(
array: Array2<T>,
py: Python<'_>,
) -> PyResult<Py<PyArray2<T>>> {
Ok(PyArray2::from_owned_array(py, array).unbind())
}
#[cfg(feature = "python")]
pub fn numpy_batch_to_scirs<T: Element + Clone>(
arrays: Vec<PyReadonlyArrayDyn<T>>,
) -> PyResult<Vec<ArrayD<T>>> {
arrays
.into_iter()
.map(|arr| Ok(arr.as_array().to_owned()))
.collect()
}
#[cfg(feature = "python")]
pub fn scirs_batch_to_numpy<T: Element>(
arrays: Vec<ArrayD<T>>,
py: Python<'_>,
) -> PyResult<Vec<Py<PyArrayDyn<T>>>> {
arrays
.into_iter()
.map(|arr| Ok(PyArrayDyn::from_owned_array(py, arr).unbind()))
.collect()
}
#[cfg(feature = "python")]
pub fn numpy_readonly_to_scirs_view<'a, T: Element>(
array: &'a PyReadonlyArrayDyn<'a, T>,
) -> ArrayViewD<'a, T> {
array.as_array()
}
#[cfg(feature = "python")]
pub fn is_numpy_compatible<T: Element>(array: &Bound<'_, PyArrayDyn<T>>) -> bool {
array.shape().iter().all(|&dim| dim > 0)
}
#[cfg(feature = "python")]
pub enum MemoryLayout {
CContiguous,
FContiguous,
Neither,
}
#[cfg(feature = "python")]
pub fn get_numpy_layout<T: Element>(array: &Bound<'_, PyArrayDyn<T>>) -> MemoryLayout {
if array.is_c_contiguous() {
MemoryLayout::CContiguous
} else if array.is_fortran_contiguous() {
MemoryLayout::FContiguous
} else {
MemoryLayout::Neither
}
}
#[cfg(all(test, feature = "python"))]
mod tests {
use super::*;
use pyo3::Python;
#[test]
#[allow(deprecated)]
fn test_numpy_scirs_roundtrip() {
pyo3::Python::attach(|py| {
let scirs_array = array![[1.0f32, 2.0], [3.0, 4.0]];
let scirs_arrayd = scirs_array.into_dyn();
let numpy_array =
scirs_to_numpy_arrayd(scirs_arrayd.clone(), py).expect("Operation failed");
let result = numpy_to_scirs_arrayd(&numpy_array.bind(py)).expect("Operation failed");
assert_eq!(result.shape(), scirs_arrayd.shape());
assert_eq!(result, scirs_arrayd);
});
}
#[test]
#[allow(deprecated)]
fn test_zero_copy_view() {
pyo3::Python::attach(|py| {
let scirs_array = array![[1.0f32, 2.0], [3.0, 4.0]].into_dyn();
let numpy_array =
scirs_to_numpy_arrayd(scirs_array.clone(), py).expect("Operation failed");
let readonly = numpy_array.bind(py).readonly();
let view = numpy_readonly_to_scirs_view(&readonly);
assert_eq!(view.shape(), scirs_array.shape());
assert_eq!(view[[0, 0]], 1.0f32);
});
}
}