1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! This crate provides conversion between [`nalgebra`] and [`numpy`](https://numpy.org/).
//! It is intended to be used when you want to share nalgebra matrices between Python and Rust code,
//! for example with [`inline-python`](https://docs.rs/inline-python).
//!
//! # Conversion from numpy to nalgebra.
//!
//! It is possible to create either a view or a copy of a numpy array.
//! You can use [`matrix_from_numpy`] to copy the data into a new matrix,
//! or one of [`matrix_slice_from_numpy`] or [`matrix_slice_mut_from_numpy`] to create a view.
//! If a numpy array is not compatible with the requested matrix type,
//! an error is returned.
//!
//! Keep in mind though that the borrow checker can not enforce rules on data managed by a Python object.
//! You could potentially keep an immutable view around in Rust, and then modify the data from Python.
//! For this reason, creating any view -- even an immutable one -- is unsafe.
//!
//! # Conversion from nalgebra to numpy.
//!
//! A nalgebra matrix can also be converted to a numpy array, using [`matrix_to_numpy`].
//! This function always creates a copy.
//! Since all nalgebra arrays can be represented as a numpy array,
//! this directly returns a [`pyo3::PyObject`] rather than a `Result`.
//!
//! # Examples.
//!
//! Copy a numpy array to a new fixed size matrix:
//!
//! ```
//! use inline_python::{Context, python};
//! use nalgebra_numpy::{matrix_from_numpy};
//!
//! # fn main() -> Result<(), nalgebra_numpy::Error> {
//! let gil = pyo3::Python::acquire_gil();
//! let context = Context::new_with_gil(gil.python());
//! context.run(python! {
//!     import numpy as np
//!     matrix = np.array([
//!         [1.0, 2.0, 3.0],
//!         [4.0, 5.0, 6.0],
//!         [7.0, 8.0, 9.0],
//!     ])
//! });
//!
//! let matrix = context.globals(gil.python()).get_item("matrix").unwrap();
//! let matrix : nalgebra::Matrix3<f64> = matrix_from_numpy(gil.python(), matrix)?;
//!
//! assert_eq!(matrix, nalgebra::Matrix3::new(
//!     1.0, 2.0, 3.0,
//!     4.0, 5.0, 6.0,
//!     7.0, 8.0, 9.0,
//! ));
//! # Ok(())
//! # }
//! ```
//!
//! Dynamic matrices are also supported:
//!
//! ```
//! # use inline_python::{Context, python};
//! # use nalgebra_numpy::{matrix_from_numpy};
//! use nalgebra::DMatrix;
//! # fn main() -> Result<(), nalgebra_numpy::Error> {
//! # let gil = pyo3::Python::acquire_gil();
//! # let context = Context::new_with_gil(gil.python());
//! # context.run(python! {
//! #     import numpy as np
//! #     matrix = np.array([
//! #         [1.0, 2.0, 3.0],
//! #         [4.0, 5.0, 6.0],
//! #         [7.0, 8.0, 9.0],
//! #     ])
//! # });
//! #
//! # let matrix = context.globals(gil.python()).get_item("matrix").unwrap();
//!
//! let matrix : DMatrix<f64> = matrix_from_numpy(gil.python(), matrix)?;
//! assert_eq!(matrix, DMatrix::from_row_slice(3, 3, &[
//!     1.0, 2.0, 3.0,
//!     4.0, 5.0, 6.0,
//!     7.0, 8.0, 9.0,
//! ]));
//! # Ok(())
//! # }
//! ```
//!
//! And so are partially dynamic matrices:
//!
//! ```
//! # use inline_python::{Context, python};
//! # use nalgebra_numpy::{matrix_from_numpy};
//! use nalgebra::{MatrixMN, Dynamic, U3};
//! # fn main() -> Result<(), nalgebra_numpy::Error> {
//! # let gil = pyo3::Python::acquire_gil();
//! # let context = Context::new_with_gil(gil.python());
//! # context.run(python! {
//! #     import numpy as np
//! #     matrix = np.array([
//! #         [1.0, 2.0, 3.0],
//! #         [4.0, 5.0, 6.0],
//! #         [7.0, 8.0, 9.0],
//! #     ])
//! # });
//! # let matrix = context.globals(gil.python()).get_item("matrix").unwrap();
//!
//! let matrix : MatrixMN<f64, U3, Dynamic> = matrix_from_numpy(gil.python(), matrix)?;
//! assert_eq!(matrix, MatrixMN::<f64, U3, Dynamic>::from_row_slice(&[
//!     1.0, 2.0, 3.0,
//!     4.0, 5.0, 6.0,
//!     7.0, 8.0, 9.0,
//! ]));
//! # Ok(())
//! # }
//! ```
//!
//! A conversion to python object looks as follows:
//! ```
//! use nalgebra_numpy::matrix_to_numpy;
//! use nalgebra::Matrix3;
//! use inline_python::python;
//!
//! let gil = pyo3::Python::acquire_gil();
//! let matrix = matrix_to_numpy(gil.python(), &Matrix3::<i32>::new(
//!     0, 1, 2,
//!     3, 4, 5,
//!     6, 7, 8,
//! ));
//!
//! python! {
//!     from numpy import array_equal
//!     assert array_equal('matrix, [
//!         [0, 1, 2],
//!         [3, 4, 5],
//!         [6, 7, 8],
//!     ])
//! }
//! ```

mod from_numpy;
mod to_numpy;

pub use from_numpy::*;
pub use to_numpy::*;