Skip to content

Commit 421b6d5

Browse files
committed
Add conversions from nalgebra types
1 parent 27c84a5 commit 421b6d5

File tree

4 files changed

+314
-1
lines changed

4 files changed

+314
-1
lines changed

Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,17 @@ blas-src = { version = "0.2.0", optional = true, default-features = false }
4242
matrixmultiply = { version = "0.2.0" }
4343
# Use via the `serde-1` crate feature!
4444
serde = { version = "1.0", optional = true }
45+
# Conversions from `nalgebra` types with `nalgebra-0_16` crate feature!
46+
nalgebra = { version = "0.16", optional = true }
4547

4648
[dev-dependencies]
4749
defmac = "0.2"
4850
quickcheck = { version = "0.7.2", default-features = false }
4951
rawpointer = "0.1"
5052

5153
[features]
54+
default = []
55+
5256
# Enable blas usage
5357
# See README for more instructions
5458
blas = ["cblas-sys", "blas-src"]
@@ -61,7 +65,10 @@ test-blas-openblas-sys = ["blas"]
6165
test = ["test-blas-openblas-sys"]
6266

6367
# This feature is used for docs
64-
docs = ["serde-1", "rayon"]
68+
docs = ["serde-1", "rayon", "nalgebra-0_16"]
69+
70+
# Conversions from nalgebra types
71+
nalgebra-0_16 = ["nalgebra"]
6572

6673
[profile.release]
6774
[profile.bench]

README.rst

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ your `Cargo.toml`.
5757
- Optional, compatible with Rust stable
5858
- Enables parallel iterators, parallelized methods and ``par_azip!``.
5959

60+
- ``nalgebra-0_16``
61+
62+
- Optional, compatible with Rust stable
63+
- Enables conversions from nalgebra 0.16 vectors/matrices
64+
6065
- ``blas``
6166

6267
- Optional and experimental, compatible with Rust stable

src/convert_nalgebra.rs

+296
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
use dimension;
2+
use imp_prelude::*;
3+
use nalgebra as na;
4+
use std::isize;
5+
6+
/// **Requires crate feature `"nalgebra-0_16"`**
7+
impl<A, R, S1, S2> From<na::Matrix<A, R, na::U1, S1>> for ArrayBase<S2, Ix1>
8+
where
9+
A: na::Scalar,
10+
R: na::Dim,
11+
S1: na::storage::Storage<A, R, na::U1>,
12+
S2: DataOwned<Elem = A>,
13+
{
14+
/// Converts the `nalgebra::Vector` to `ndarray::ArrayBase`.
15+
///
16+
/// **Panics** if the number of elements overflows `isize`.
17+
///
18+
/// # Example
19+
///
20+
/// ```
21+
/// # extern crate nalgebra;
22+
/// # extern crate ndarray;
23+
///
24+
/// use nalgebra::Vector3;
25+
/// use ndarray::{array, Array1};
26+
///
27+
/// # fn main() {
28+
/// let vector = Vector3::new(1, 2, 3);
29+
/// let array = Array1::from(vector);
30+
/// assert_eq!(array, array![1, 2, 3]);
31+
/// # }
32+
/// ```
33+
fn from(vector: na::Matrix<A, R, na::U1, S1>) -> ArrayBase<S2, Ix1> {
34+
ArrayBase::from_vec(vector.iter().cloned().collect())
35+
}
36+
}
37+
38+
/// **Requires crate feature `"nalgebra-0_16"`**
39+
impl<'a, A, R, RStride, CStride> From<na::MatrixSlice<'a, A, R, na::U1, RStride, CStride>>
40+
for ArrayView<'a, A, Ix1>
41+
where
42+
A: na::Scalar,
43+
R: na::Dim,
44+
RStride: na::Dim,
45+
CStride: na::Dim,
46+
{
47+
/// Converts the 1-D `nalgebra::MatrixSlice` to `ndarray::ArrayView`.
48+
///
49+
/// **Panics** if the number of elements, row stride, or size in bytes
50+
/// overflows `isize`.
51+
///
52+
/// # Example
53+
///
54+
/// ```
55+
/// # extern crate nalgebra;
56+
/// # extern crate ndarray;
57+
///
58+
/// use nalgebra::MatrixSlice3x1;
59+
/// use ndarray::{array, ArrayView1};
60+
///
61+
/// # fn main() {
62+
/// let slice = MatrixSlice3x1::from_slice(&[1, 2, 3]);
63+
/// let view = ArrayView1::from(slice);
64+
/// assert_eq!(view, array![1, 2, 3]);
65+
/// # }
66+
/// ```
67+
fn from(slice: na::MatrixSlice<'a, A, R, na::U1, RStride, CStride>) -> ArrayView<'a, A, Ix1> {
68+
if slice.is_empty() {
69+
ArrayView::from_shape(slice.shape().0, &[]).unwrap()
70+
} else {
71+
let dim = Dim(slice.shape().0);
72+
let strides = Dim(slice.strides().0);
73+
ndassert!(
74+
strides[0] <= isize::MAX as usize,
75+
"stride {} must not exceed `isize::MAX`",
76+
strides[0],
77+
);
78+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides)
79+
.expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`");
80+
let ptr: *const A = slice.iter().next().unwrap();
81+
unsafe { ArrayView::from_shape_ptr(dim.strides(strides), ptr) }
82+
}
83+
}
84+
}
85+
86+
/// **Requires crate feature `"nalgebra-0_16"`**
87+
impl<'a, A, R, RStride, CStride> From<na::MatrixSliceMut<'a, A, R, na::U1, RStride, CStride>>
88+
for ArrayViewMut<'a, A, Ix1>
89+
where
90+
A: na::Scalar,
91+
R: na::Dim,
92+
RStride: na::Dim,
93+
CStride: na::Dim,
94+
{
95+
/// Converts the 1-D `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`.
96+
///
97+
/// **Panics** if the number of elements, row stride, or size in bytes
98+
/// overflows `isize`. Also panics if the row stride is zero when there is
99+
/// more than one row.
100+
///
101+
/// # Example
102+
///
103+
/// ```
104+
/// # extern crate nalgebra;
105+
/// # extern crate ndarray;
106+
///
107+
/// use nalgebra::MatrixSliceMut3x1;
108+
/// use ndarray::{array, ArrayViewMut1};
109+
///
110+
/// # fn main() {
111+
/// // `from_slice` assumes column-major memory layout.
112+
/// let mut data = [1, 2, 3];
113+
/// let slice = MatrixSliceMut3x1::from_slice(&mut data);
114+
/// let view = ArrayViewMut1::from(slice);
115+
/// assert_eq!(view, array![1, 2, 3]);
116+
/// # }
117+
/// ```
118+
fn from(
119+
mut slice: na::MatrixSliceMut<'a, A, R, na::U1, RStride, CStride>,
120+
) -> ArrayViewMut<'a, A, Ix1> {
121+
if slice.is_empty() {
122+
ArrayViewMut::from_shape(slice.shape().0, &mut []).unwrap()
123+
} else {
124+
let dim = Dim(slice.shape().0);
125+
let strides = Dim(slice.strides().0);
126+
ndassert!(
127+
strides[0] <= isize::MAX as usize,
128+
"stride {} must not exceed `isize::MAX`",
129+
strides[0],
130+
);
131+
// `nalgebra` should prevent this ever being violated but currently
132+
// doesn't (rustsim/nalgebra#473).
133+
ndassert!(
134+
dim[0] <= 1 || strides[0] != 0,
135+
"stride {} must be nonzero when axis length {} is > 1",
136+
strides[0],
137+
dim[0],
138+
);
139+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).expect(
140+
"overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`",
141+
);
142+
let ptr: *mut A = slice.iter_mut().next().unwrap();
143+
unsafe { ArrayViewMut::from_shape_ptr(dim.strides(strides), ptr) }
144+
}
145+
}
146+
}
147+
148+
/// **Requires crate feature `"nalgebra-0_16"`**
149+
impl<A, R, C, S1, S2> From<na::Matrix<A, R, C, S1>> for ArrayBase<S2, Ix2>
150+
where
151+
A: na::Scalar,
152+
R: na::Dim,
153+
C: na::Dim,
154+
S1: na::storage::Storage<A, R, C>,
155+
S2: DataOwned<Elem = A>,
156+
{
157+
/// Converts the `nalgebra::Matrix` to `ndarray::ArrayBase`.
158+
///
159+
/// **Panics** if the number of rows, columns, or elements overflows `isize`.
160+
///
161+
/// # Example
162+
///
163+
/// ```
164+
/// # extern crate nalgebra;
165+
/// # extern crate ndarray;
166+
///
167+
/// use nalgebra::Matrix2x3;
168+
/// use ndarray::{array, Array2};
169+
///
170+
/// # fn main() {
171+
/// let matrix = Matrix2x3::new(1, 2, 3, 4, 5, 6);
172+
/// let array = Array2::from(matrix);
173+
/// assert_eq!(array, array![[1, 2, 3], [4, 5, 6]]);
174+
/// # }
175+
/// ```
176+
fn from(matrix: na::Matrix<A, R, C, S1>) -> ArrayBase<S2, Ix2> {
177+
let (rows, cols) = matrix.shape();
178+
ArrayBase::from_shape_vec((cols, rows), matrix.iter().cloned().collect())
179+
.expect("convert `nalgebra::Matrix` to `ndarray::ArrayBase`")
180+
.reversed_axes()
181+
}
182+
}
183+
184+
/// **Requires crate feature `"nalgebra-0_16"`**
185+
impl<'a, A, R, C, RStride, CStride> From<na::MatrixSlice<'a, A, R, C, RStride, CStride>>
186+
for ArrayView<'a, A, Ix2>
187+
where
188+
A: na::Scalar,
189+
R: na::Dim,
190+
C: na::Dim,
191+
RStride: na::Dim,
192+
CStride: na::Dim,
193+
{
194+
/// Converts the `nalgebra::MatrixSlice` to `ndarray::ArrayView`.
195+
///
196+
/// **Panics** if the number of rows, number of columns, row stride, column
197+
/// stride, number of elements, or size in bytes overflows `isize`.
198+
///
199+
/// # Example
200+
///
201+
/// ```
202+
/// # extern crate nalgebra;
203+
/// # extern crate ndarray;
204+
///
205+
/// use nalgebra::MatrixSlice2x3;
206+
/// use ndarray::{array, ArrayView2};
207+
///
208+
/// # fn main() {
209+
/// // `from_slice` assumes column-major memory layout.
210+
/// let slice = MatrixSlice2x3::from_slice(&[1, 4, 2, 5, 3, 6]);
211+
/// let view = ArrayView2::from(slice);
212+
/// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]);
213+
/// # }
214+
/// ```
215+
fn from(slice: na::MatrixSlice<'a, A, R, C, RStride, CStride>) -> ArrayView<'a, A, Ix2> {
216+
if slice.is_empty() {
217+
ArrayView::from_shape(slice.shape(), &[]).unwrap()
218+
} else {
219+
let dim = Dim(slice.shape());
220+
let strides = Dim(slice.strides());
221+
ndassert!(
222+
strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize,
223+
"strides {:?} must not exceed `isize::MAX`",
224+
strides,
225+
);
226+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides)
227+
.expect("overflow converting `nalgebra::MatrixSlice` to `nalgebra::ArrayView`");
228+
let ptr: *const A = slice.iter().next().unwrap();
229+
unsafe { ArrayView::from_shape_ptr(dim.strides(strides), ptr) }
230+
}
231+
}
232+
}
233+
234+
/// **Requires crate feature `"nalgebra-0_16"`**
235+
impl<'a, A, R, C, RStride, CStride> From<na::MatrixSliceMut<'a, A, R, C, RStride, CStride>>
236+
for ArrayViewMut<'a, A, Ix2>
237+
where
238+
A: na::Scalar,
239+
R: na::Dim,
240+
C: na::Dim,
241+
RStride: na::Dim,
242+
CStride: na::Dim,
243+
{
244+
/// Converts the `nalgebra::MatrixSliceMut` to `ndarray::ArrayViewMut`.
245+
///
246+
/// **Panics** if the number of rows, number of columns, row stride, column
247+
/// stride, number of elements, or size in bytes overflows `isize`. Also
248+
/// panics if the row stride or column stride is zero when the length of
249+
/// the corresponding axis is greater than one.
250+
///
251+
/// # Example
252+
///
253+
/// ```
254+
/// # extern crate nalgebra;
255+
/// # extern crate ndarray;
256+
///
257+
/// use nalgebra::MatrixSliceMut2x3;
258+
/// use ndarray::{array, ArrayViewMut2};
259+
///
260+
/// # fn main() {
261+
/// // `from_slice` assumes column-major memory layout.
262+
/// let mut data = [1, 4, 2, 5, 3, 6];
263+
/// let slice = MatrixSliceMut2x3::from_slice(&mut data);
264+
/// let view = ArrayViewMut2::from(slice);
265+
/// assert_eq!(view, array![[1, 2, 3], [4, 5, 6]]);
266+
/// # }
267+
/// ```
268+
fn from(
269+
mut slice: na::MatrixSliceMut<'a, A, R, C, RStride, CStride>,
270+
) -> ArrayViewMut<'a, A, Ix2> {
271+
if slice.is_empty() {
272+
ArrayViewMut::from_shape(slice.shape(), &mut []).unwrap()
273+
} else {
274+
let dim = Dim(slice.shape());
275+
let strides = Dim(slice.strides());
276+
ndassert!(
277+
strides[0] <= isize::MAX as usize && strides[1] <= isize::MAX as usize,
278+
"strides {:?} must not exceed `isize::MAX`",
279+
strides,
280+
);
281+
// `nalgebra` should prevent this ever being violated but currently
282+
// doesn't (rustsim/nalgebra#473).
283+
ndassert!(
284+
(dim[0] <= 1 || strides[0] != 0) && (dim[1] <= 1 || strides[1] != 0),
285+
"strides {:?} must be nonzero when corresponding lengths {:?} are > 1",
286+
strides,
287+
dim,
288+
);
289+
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).expect(
290+
"overflow converting `nalgebra::MatrixSliceMut` to `nalgebra::ArrayViewMut`",
291+
);
292+
let ptr: *mut A = slice.iter_mut().next().unwrap();
293+
unsafe { ArrayViewMut::from_shape_ptr(dim.strides(strides), ptr) }
294+
}
295+
}
296+
}

src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ extern crate serde;
9090
#[cfg(feature="rayon")]
9191
extern crate rayon;
9292

93+
#[cfg(feature = "nalgebra-0_16")]
94+
extern crate nalgebra;
95+
9396
#[cfg(feature="blas")]
9497
extern crate cblas_sys;
9598
#[cfg(feature="blas")]
@@ -146,6 +149,8 @@ mod aliases;
146149
mod arraytraits;
147150
#[cfg(feature = "serde-1")]
148151
mod array_serde;
152+
#[cfg(feature = "nalgebra-0_16")]
153+
mod convert_nalgebra;
149154
mod arrayformat;
150155
mod data_traits;
151156

0 commit comments

Comments
 (0)