Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating dependencies on this crate (will need new release) #3

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ keywords = ["python", "numpy", "nalgebra", "matrix", "conversion"]
categories = ["science"]

[dependencies]
nalgebra = "0.24.1"
numpy = "0.11"
pyo3 = "0.11"
nalgebra = "0.31"
numpy = "0.17"
pyo3 = "0.17"

[dev-dependencies]
inline-python = "0.6.0"
inline-python = "0.10.0"
assert2 = "0.3.4"
62 changes: 18 additions & 44 deletions src/from_numpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub struct WrongObjectTypeError {
pub struct IncompatibleArrayError {
pub expected_shape: Shape,
pub actual_shape: Vec<usize>,
pub expected_dtype: numpy::DataType,
pub expected_dtype: String,
pub actual_dtype: String,
}

Expand All @@ -58,15 +58,15 @@ pub struct UnalignedArrayError;
/// The user must ensure that the data is not modified through other pointers or references.
#[allow(clippy::needless_lifetimes)]
pub unsafe fn matrix_slice_from_numpy<'a, N, R, C>(
_py: pyo3::Python,
py: pyo3::Python,
input: &'a PyAny,
) -> Result<nalgebra::MatrixSlice<'a, N, R, C, Dynamic, Dynamic>, Error>
where
N: nalgebra::Scalar + numpy::Element,
R: nalgebra::Dim,
C: nalgebra::Dim,
{
matrix_slice_from_numpy_ptr(input.as_ptr())
matrix_slice_from_numpy_ptr(py, input.as_ptr())
}

/// Create a mutable nalgebra view from a numpy array.
Expand All @@ -80,15 +80,15 @@ where
/// The user must ensure that no other Rust references to the same data exist.
#[allow(clippy::needless_lifetimes)]
pub unsafe fn matrix_slice_mut_from_numpy<'a, N, R, C>(
_py: pyo3::Python,
py: pyo3::Python,
input: &'a PyAny,
) -> Result<nalgebra::MatrixSliceMut<'a, N, R, C, Dynamic, Dynamic>, Error>
where
N: nalgebra::Scalar + numpy::Element,
R: nalgebra::Dim,
C: nalgebra::Dim,
{
matrix_slice_mut_from_numpy_ptr(input.as_ptr())
matrix_slice_mut_from_numpy_ptr(py, input.as_ptr())
}

/// Create an owning nalgebra matrix from a numpy array.
Expand All @@ -98,7 +98,7 @@ where
/// The array dtype must match the output type exactly.
/// If desired, you can convert the array to the desired type in Python
/// using [`numpy.ndarray.astype`](https://numpy.org/devdocs/reference/generated/numpy.ndarray.astype.html).
pub fn matrix_from_numpy<N, R, C>(py: pyo3::Python, input: &PyAny) -> Result<nalgebra::MatrixMN<N, R, C>, Error>
pub fn matrix_from_numpy<N, R, C>(py: pyo3::Python, input: &PyAny) -> Result<nalgebra::OMatrix<N, R, C>, Error>
where
N: nalgebra::Scalar + numpy::Element,
R: nalgebra::Dim,
Expand All @@ -111,15 +111,16 @@ where
/// Same as [`matrix_slice_from_numpy`], but takes a raw [`PyObject`](pyo3::ffi::PyObject) pointer.
#[allow(clippy::missing_safety_doc)]
pub unsafe fn matrix_slice_from_numpy_ptr<'a, N, R, C>(
py: pyo3::Python,
array: *mut pyo3::ffi::PyObject,
) -> Result<nalgebra::MatrixSlice<'a, N, R, C, Dynamic, Dynamic>, Error>
where
N: nalgebra::Scalar + numpy::Element,
R: nalgebra::Dim,
C: nalgebra::Dim,
{
let array = cast_to_py_array(array)?;
let shape = check_array_compatible::<N, R, C>(array)?;
let array = cast_to_py_array(py, array)?;
let shape = check_array_compatible::<N, R, C>(py, array)?;
check_array_alignment(array)?;

let row_stride = Dynamic::new(*(*array).strides.add(0) as usize / std::mem::size_of::<N>());
Expand All @@ -132,15 +133,16 @@ where
/// Same as [`matrix_slice_mut_from_numpy`], but takes a raw [`PyObject`](pyo3::ffi::PyObject) pointer.
#[allow(clippy::missing_safety_doc)]
pub unsafe fn matrix_slice_mut_from_numpy_ptr<'a, N, R, C>(
py: pyo3::Python,
array: *mut pyo3::ffi::PyObject,
) -> Result<nalgebra::MatrixSliceMut<'a, N, R, C, Dynamic, Dynamic>, Error>
where
N: nalgebra::Scalar + numpy::Element,
R: nalgebra::Dim,
C: nalgebra::Dim,
{
let array = cast_to_py_array(array)?;
let shape = check_array_compatible::<N, R, C>(array)?;
let array = cast_to_py_array(py, array)?;
let shape = check_array_compatible::<N, R, C>(py, array)?;
check_array_alignment(array)?;

let row_stride = Dynamic::new(*(*array).strides.add(0) as usize / std::mem::size_of::<N>());
Expand All @@ -151,8 +153,8 @@ where
}

/// Check if an object is numpy array and cast the pointer.
unsafe fn cast_to_py_array(object: *mut pyo3::ffi::PyObject) -> Result<*mut PyArrayObject, WrongObjectTypeError> {
if npyffi::array::PyArray_Check(object) == 1 {
unsafe fn cast_to_py_array(py: pyo3::Python, object: *mut pyo3::ffi::PyObject) -> Result<*mut PyArrayObject, WrongObjectTypeError> {
if npyffi::array::PyArray_Check(py, object) == 1 {
Ok(&mut *(object as *mut npyffi::objects::PyArrayObject))
} else {
Err(WrongObjectTypeError {
Expand All @@ -162,7 +164,7 @@ unsafe fn cast_to_py_array(object: *mut pyo3::ffi::PyObject) -> Result<*mut PyAr
}

/// Check if a numpy array is compatible and return the runtime shape.
unsafe fn check_array_compatible<N, R, C>(array: *mut PyArrayObject) -> Result<(R, C), IncompatibleArrayError>
unsafe fn check_array_compatible<N, R, C>(py: pyo3::Python, array: *mut PyArrayObject) -> Result<(R, C), IncompatibleArrayError>
where
N: numpy::Element,
R: nalgebra::Dim,
Expand All @@ -177,7 +179,7 @@ where
IncompatibleArrayError {
expected_shape,
actual_shape: shape(array),
expected_dtype: N::DATA_TYPE,
expected_dtype: N::get_dtype(py).to_string(),
actual_dtype: data_type_string(array),
}
};
Expand All @@ -201,7 +203,7 @@ where
}

// Check the data type of the input array.
if npyffi::array::PY_ARRAY_API.PyArray_EquivTypenums((*(*array).descr).type_num, N::ffi_dtype() as u32 as i32) != 1 {
if npyffi::array::PY_ARRAY_API.PyArray_EquivTypenums(py, (*(*array).descr).type_num, N::get_dtype(py).num()) != 1 {
return Err(make_error());
}

Expand Down Expand Up @@ -309,10 +311,7 @@ impl std::fmt::Display for IncompatibleArrayError {
write!(
f,
"incompatible array: expected ndarray(shape={}, dtype='{}'), found ndarray(shape={:?}, dtype={:?})",
self.expected_shape,
FormatDataType(&self.expected_dtype),
self.actual_shape,
self.actual_dtype,
self.expected_shape, &self.expected_dtype, self.actual_shape, self.actual_dtype,
)
}
}
Expand All @@ -323,31 +322,6 @@ impl std::fmt::Display for UnalignedArrayError {
}
}

/// Helper to format [`numpy::DataType`] more consistently.
struct FormatDataType<'a>(&'a numpy::DataType);

impl std::fmt::Display for FormatDataType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let Self(dtype) = self;
match dtype {
numpy::DataType::Bool => write!(f, "bool"),
numpy::DataType::Complex32 => write!(f, "complex32"),
numpy::DataType::Complex64 => write!(f, "complex64"),
numpy::DataType::Float32 => write!(f, "float32"),
numpy::DataType::Float64 => write!(f, "float64"),
numpy::DataType::Int8 => write!(f, "int8"),
numpy::DataType::Int16 => write!(f, "int16"),
numpy::DataType::Int32 => write!(f, "int32"),
numpy::DataType::Int64 => write!(f, "int64"),
numpy::DataType::Object => write!(f, "object"),
numpy::DataType::Uint8 => write!(f, "uint8"),
numpy::DataType::Uint16 => write!(f, "uint16"),
numpy::DataType::Uint32 => write!(f, "uint32"),
numpy::DataType::Uint64 => write!(f, "uint64"),
}
}
}

impl std::error::Error for Error {}
impl std::error::Error for WrongObjectTypeError {}
impl std::error::Error for IncompatibleArrayError {}
5 changes: 3 additions & 2 deletions src/to_numpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ where
C: nalgebra::Dim,
S: nalgebra::storage::Storage<N, R, C>,
{
let array = PyArray::new(py, (matrix.nrows(), matrix.ncols()), false);
// TODO: safety!?
let array = unsafe { PyArray::new(py, (matrix.nrows(), matrix.ncols()), false) };
for r in 0..matrix.nrows() {
for c in 0..matrix.ncols() {
unsafe {
*array.uget_mut((r, c)) = matrix[(r, c)].inlined_clone();
*array.uget_mut((r, c)) = matrix[(r, c)].clone();
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions tests/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ use nalgebra_numpy::{matrix_from_numpy, Error};

#[test]
fn wrong_type() {
let gil = pyo3::Python::acquire_gil();
let py = gil.python();
let context = Context::new_with_gil(py);
pyo3::Python::with_gil(|py| {
let context = Context::new_with_gil(py);

context.run(python! {
float = 3.4
int = 8
list = [1.0, 2.0, 3.0]
});
context.run(python! {
float = 3.4
int = 8
list = [1.0, 2.0, 3.0]
});

let get_global = |name| context.globals(py).get_item(name).unwrap();
let get_global = |name| context.globals(py).get_item(name).unwrap();

assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<f64, U1, U1>(py, get_global("float")));
assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<i32, U1, U1>(py, get_global("int")));
assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<f64, U1, U3>(py, get_global("list")));
assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<f64, U1, U1>(py, get_global("float")));
assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<i32, U1, U1>(py, get_global("int")));
assert!(let Err(Error::WrongObjectType(_)) = matrix_from_numpy::<f64, U1, U3>(py, get_global("list")));
});
}

#[test]
Expand Down
13 changes: 6 additions & 7 deletions tests/to_numpy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ use nalgebra_numpy::matrix_to_numpy;
#[test]
#[rustfmt::skip]
fn fixed_size() {
let gil = pyo3::Python::acquire_gil();

let matrix = matrix_to_numpy(gil.python(), &Matrix3::<i32>::new(
pyo3::Python::with_gil(|py| {
let matrix = matrix_to_numpy(py, &Matrix3::<i32>::new(
0, 1, 2,
3, 4, 5,
6, 7, 8,
Expand All @@ -21,14 +20,14 @@ fn fixed_size() {
[6, 7, 8],
])
}
})
}

#[test]
#[rustfmt::skip]
fn dynamic_size() {
let gil = pyo3::Python::acquire_gil();

let matrix = matrix_to_numpy(gil.python(), &DMatrix::<f64>::from_row_slice(3, 4, &[
pyo3::Python::with_gil(|py| -> () {
let matrix = matrix_to_numpy(py, &DMatrix::<f64>::from_row_slice(3, 4, &[
0.0, 1.0, 2.0, 3.0,
4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0,
Expand All @@ -41,5 +40,5 @@ fn dynamic_size() {
[4, 5, 6, 7],
[8, 9, 10, 11],
])
}
}});
}