Merge branch 'neachdainn-reshape' into dev
This commit is contained in:
commit
ce7d767d37
|
@ -0,0 +1,50 @@
|
||||||
|
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
|
|
||||||
|
extern crate nalgebra as na;
|
||||||
|
|
||||||
|
use na::{DMatrix, Dynamic, Matrix2x3, Matrix3x2, U2, U3};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Matrices can be reshaped in-place without moving or copying values.
|
||||||
|
let m1 = Matrix2x3::new(
|
||||||
|
1.1, 1.2, 1.3,
|
||||||
|
2.1, 2.2, 2.3
|
||||||
|
);
|
||||||
|
let m2 = Matrix3x2::new(
|
||||||
|
1.1, 2.2,
|
||||||
|
2.1, 1.3,
|
||||||
|
1.2, 2.3
|
||||||
|
);
|
||||||
|
|
||||||
|
let m3 = m1.reshape_generic(U3, U2);
|
||||||
|
assert_eq!(m3, m2);
|
||||||
|
|
||||||
|
// Note that, for statically sized matrices, invalid reshapes will not compile:
|
||||||
|
//let m4 = m3.reshape_generic(U3, U3);
|
||||||
|
|
||||||
|
// If dynamically sized matrices are used, the reshaping is checked at run-time.
|
||||||
|
let dm1 = DMatrix::from_row_slice(
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
&[
|
||||||
|
1.0, 0.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0,
|
||||||
|
0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0
|
||||||
|
],
|
||||||
|
);
|
||||||
|
let dm2 = DMatrix::from_row_slice(
|
||||||
|
6,
|
||||||
|
2,
|
||||||
|
&[
|
||||||
|
1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
|
0.0, 0.0, 0.0, 0.0, 1.0, 0.0
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
let dm3 = dm1.reshape_generic(Dynamic::new(6), Dynamic::new(2));
|
||||||
|
assert_eq!(dm3, dm2);
|
||||||
|
|
||||||
|
// Invalid reshapings of dynamic matrices will panic at run-time.
|
||||||
|
//let dm4 = dm3.reshape_generic(Dynamic::new(6), Dynamic::new(6));
|
||||||
|
}
|
|
@ -24,7 +24,9 @@ use typenum::Prod;
|
||||||
use crate::base::allocator::Allocator;
|
use crate::base::allocator::Allocator;
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{DimName, U1};
|
use crate::base::dimension::{DimName, U1};
|
||||||
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
|
use crate::base::storage::{
|
||||||
|
ContiguousStorage, ContiguousStorageMut, Owned, ReshapableStorage, Storage, StorageMut,
|
||||||
|
};
|
||||||
use crate::base::Scalar;
|
use crate::base::Scalar;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -267,6 +269,25 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, R1, C1, R2, C2> ReshapableStorage<N, R1, C1, R2, C2> for ArrayStorage<N, R1, C1>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R1: DimName,
|
||||||
|
C1: DimName,
|
||||||
|
R1::Value: Mul<C1::Value>,
|
||||||
|
Prod<R1::Value, C1::Value>: ArrayLength<N>,
|
||||||
|
R2: DimName,
|
||||||
|
C2: DimName,
|
||||||
|
R2::Value: Mul<C2::Value, Output = Prod<R1::Value, C1::Value>>,
|
||||||
|
Prod<R2::Value, C2::Value>: ArrayLength<N>,
|
||||||
|
{
|
||||||
|
type Output = ArrayStorage<N, R2, C2>;
|
||||||
|
|
||||||
|
fn reshape_generic(self, _: R2, _: C2) -> Self::Output {
|
||||||
|
ArrayStorage { data: self.data }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Allocation-less serde impls.
|
* Allocation-less serde impls.
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::base::dimension::Dynamic;
|
||||||
use crate::base::dimension::{
|
use crate::base::dimension::{
|
||||||
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1,
|
Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1,
|
||||||
};
|
};
|
||||||
use crate::base::storage::{Storage, StorageMut};
|
use crate::base::storage::{ReshapableStorage, Storage, StorageMut};
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
use crate::base::DMatrix;
|
use crate::base::DMatrix;
|
||||||
use crate::base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector};
|
use crate::base::{DefaultAllocator, Matrix, MatrixMN, RowVector, Scalar, Vector};
|
||||||
|
@ -745,7 +745,7 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
self.resize_generic(R2::name(), C2::name(), val)
|
self.resize_generic(R2::name(), C2::name(), val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resizes `self` such that it has dimensions `new_nrows × now_ncols`.
|
/// Resizes `self` such that it has dimensions `new_nrows × new_ncols`.
|
||||||
///
|
///
|
||||||
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
/// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more
|
||||||
/// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
|
/// rows and/or columns than `self`, then the extra rows or columns are filled with `val`.
|
||||||
|
@ -813,6 +813,76 @@ impl<N: Scalar, R: Dim, C: Dim, S: Storage<N, R, C>> Matrix<N, R, C, S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, R, C, S> Matrix<N, R, C, S>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R: Dim,
|
||||||
|
C: Dim,
|
||||||
|
{
|
||||||
|
/// Reshapes `self` such that it has dimensions `new_nrows × new_ncols`.
|
||||||
|
///
|
||||||
|
/// This will reinterpret `self` as if it is a matrix with `new_nrows` rows and `new_ncols`
|
||||||
|
/// columns. The arrangements of the component in the output matrix are the same as what
|
||||||
|
/// would be obtained by `Matrix::from_slice_generic(self.as_slice(), new_nrows, new_ncols)`.
|
||||||
|
///
|
||||||
|
/// If `self` is a dynamically-sized matrix, then its components are neither copied nor moved.
|
||||||
|
/// If `self` is staticyll-sized, then a copy may happen in some situations.
|
||||||
|
/// This function will panic if the given dimensions are such that the number of elements of
|
||||||
|
/// the input matrix are not equal to the number of elements of the output matrix.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use nalgebra::{Matrix3x2, Matrix2x3, DMatrix, U2, U3, Dynamic};
|
||||||
|
///
|
||||||
|
/// let m1 = Matrix2x3::new(
|
||||||
|
/// 1.1, 1.2, 1.3,
|
||||||
|
/// 2.1, 2.2, 2.3
|
||||||
|
/// );
|
||||||
|
/// let m2 = Matrix3x2::new(
|
||||||
|
/// 1.1, 2.2,
|
||||||
|
/// 2.1, 1.3,
|
||||||
|
/// 1.2, 2.3
|
||||||
|
/// );
|
||||||
|
/// let reshaped = m1.reshape_generic(U3, U2);
|
||||||
|
/// assert_eq!(reshaped, m2);
|
||||||
|
///
|
||||||
|
/// let dm1 = DMatrix::from_row_slice(
|
||||||
|
/// 4,
|
||||||
|
/// 3,
|
||||||
|
/// &[
|
||||||
|
/// 1.0, 0.0, 0.0,
|
||||||
|
/// 0.0, 0.0, 1.0,
|
||||||
|
/// 0.0, 0.0, 0.0,
|
||||||
|
/// 0.0, 1.0, 0.0
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// let dm2 = DMatrix::from_row_slice(
|
||||||
|
/// 6,
|
||||||
|
/// 2,
|
||||||
|
/// &[
|
||||||
|
/// 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
|
||||||
|
/// 0.0, 0.0, 0.0, 0.0, 1.0, 0.0
|
||||||
|
/// ],
|
||||||
|
/// );
|
||||||
|
/// let reshaped = dm1.reshape_generic(Dynamic::new(6), Dynamic::new(2));
|
||||||
|
/// assert_eq!(reshaped, dm2);
|
||||||
|
/// ```
|
||||||
|
pub fn reshape_generic<R2, C2>(
|
||||||
|
self,
|
||||||
|
new_nrows: R2,
|
||||||
|
new_ncols: C2,
|
||||||
|
) -> Matrix<N, R2, C2, S::Output>
|
||||||
|
where
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
S: ReshapableStorage<N, R, C, R2, C2>,
|
||||||
|
{
|
||||||
|
let data = self.data.reshape_generic(new_nrows, new_ncols);
|
||||||
|
Matrix::from_data(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "alloc"))]
|
#[cfg(any(feature = "std", feature = "alloc"))]
|
||||||
impl<N: Scalar> DMatrix<N> {
|
impl<N: Scalar> DMatrix<N> {
|
||||||
/// Resizes this matrix in-place.
|
/// Resizes this matrix in-place.
|
||||||
|
|
|
@ -171,7 +171,7 @@ pub unsafe trait StorageMut<N: Scalar, R: Dim, C: Dim = U1>: Storage<N, R, C> {
|
||||||
|
|
||||||
/// A matrix storage that is stored contiguously in memory.
|
/// A matrix storage that is stored contiguously in memory.
|
||||||
///
|
///
|
||||||
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value
|
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
|
||||||
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
||||||
/// failing to comply to this may cause Undefined Behaviors.
|
/// failing to comply to this may cause Undefined Behaviors.
|
||||||
pub unsafe trait ContiguousStorage<N: Scalar, R: Dim, C: Dim = U1>:
|
pub unsafe trait ContiguousStorage<N: Scalar, R: Dim, C: Dim = U1>:
|
||||||
|
@ -181,10 +181,26 @@ pub unsafe trait ContiguousStorage<N: Scalar, R: Dim, C: Dim = U1>:
|
||||||
|
|
||||||
/// A mutable matrix storage that is stored contiguously in memory.
|
/// A mutable matrix storage that is stored contiguously in memory.
|
||||||
///
|
///
|
||||||
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols[`, the value
|
/// The storage requirement means that for any value of `i` in `[0, nrows * ncols - 1]`, the value
|
||||||
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
/// `.get_unchecked_linear` returns one of the matrix component. This trait is unsafe because
|
||||||
/// failing to comply to this may cause Undefined Behaviors.
|
/// failing to comply to this may cause Undefined Behaviors.
|
||||||
pub unsafe trait ContiguousStorageMut<N: Scalar, R: Dim, C: Dim = U1>:
|
pub unsafe trait ContiguousStorageMut<N: Scalar, R: Dim, C: Dim = U1>:
|
||||||
ContiguousStorage<N, R, C> + StorageMut<N, R, C>
|
ContiguousStorage<N, R, C> + StorageMut<N, R, C>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A matrix storage that can be reshaped in-place.
|
||||||
|
pub trait ReshapableStorage<N, R1, C1, R2, C2>: Storage<N, R1, C1>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R1: Dim,
|
||||||
|
C1: Dim,
|
||||||
|
R2: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
{
|
||||||
|
/// The reshaped storage type.
|
||||||
|
type Output: Storage<N, R2, C2>;
|
||||||
|
|
||||||
|
/// Reshapes the storage into the output storage type.
|
||||||
|
fn reshape_generic(self, nrows: R2, ncols: C2) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ use crate::base::allocator::Allocator;
|
||||||
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
|
use crate::base::constraint::{SameNumberOfRows, ShapeConstraint};
|
||||||
use crate::base::default_allocator::DefaultAllocator;
|
use crate::base::default_allocator::DefaultAllocator;
|
||||||
use crate::base::dimension::{Dim, DimName, Dynamic, U1};
|
use crate::base::dimension::{Dim, DimName, Dynamic, U1};
|
||||||
use crate::base::storage::{ContiguousStorage, ContiguousStorageMut, Owned, Storage, StorageMut};
|
use crate::base::storage::{
|
||||||
|
ContiguousStorage, ContiguousStorageMut, Owned, ReshapableStorage, Storage, StorageMut,
|
||||||
|
};
|
||||||
use crate::base::{Scalar, Vector};
|
use crate::base::{Scalar, Vector};
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
|
@ -225,6 +227,42 @@ unsafe impl<N: Scalar, C: Dim> ContiguousStorageMut<N, Dynamic, C> for VecStorag
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, C1, C2> ReshapableStorage<N, Dynamic, C1, Dynamic, C2> for VecStorage<N, Dynamic, C1>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
C1: Dim,
|
||||||
|
C2: Dim,
|
||||||
|
{
|
||||||
|
type Output = VecStorage<N, Dynamic, C2>;
|
||||||
|
|
||||||
|
fn reshape_generic(self, nrows: Dynamic, ncols: C2) -> Self::Output {
|
||||||
|
assert_eq!(nrows.value() * ncols.value(), self.data.len());
|
||||||
|
VecStorage {
|
||||||
|
data: self.data,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N, C1, R2> ReshapableStorage<N, Dynamic, C1, R2, Dynamic> for VecStorage<N, Dynamic, C1>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
C1: Dim,
|
||||||
|
R2: DimName,
|
||||||
|
{
|
||||||
|
type Output = VecStorage<N, R2, Dynamic>;
|
||||||
|
|
||||||
|
fn reshape_generic(self, nrows: R2, ncols: Dynamic) -> Self::Output {
|
||||||
|
assert_eq!(nrows.value() * ncols.value(), self.data.len());
|
||||||
|
VecStorage {
|
||||||
|
data: self.data,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic>
|
unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for VecStorage<N, R, Dynamic>
|
||||||
where
|
where
|
||||||
DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>,
|
DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self>,
|
||||||
|
@ -240,6 +278,42 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N, R1, C2> ReshapableStorage<N, R1, Dynamic, Dynamic, C2> for VecStorage<N, R1, Dynamic>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R1: DimName,
|
||||||
|
C2: Dim,
|
||||||
|
{
|
||||||
|
type Output = VecStorage<N, Dynamic, C2>;
|
||||||
|
|
||||||
|
fn reshape_generic(self, nrows: Dynamic, ncols: C2) -> Self::Output {
|
||||||
|
assert_eq!(nrows.value() * ncols.value(), self.data.len());
|
||||||
|
VecStorage {
|
||||||
|
data: self.data,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N, R1, R2> ReshapableStorage<N, R1, Dynamic, R2, Dynamic> for VecStorage<N, R1, Dynamic>
|
||||||
|
where
|
||||||
|
N: Scalar,
|
||||||
|
R1: DimName,
|
||||||
|
R2: DimName,
|
||||||
|
{
|
||||||
|
type Output = VecStorage<N, R2, Dynamic>;
|
||||||
|
|
||||||
|
fn reshape_generic(self, nrows: R2, ncols: Dynamic) -> Self::Output {
|
||||||
|
assert_eq!(nrows.value() * ncols.value(), self.data.len());
|
||||||
|
VecStorage {
|
||||||
|
data: self.data,
|
||||||
|
nrows,
|
||||||
|
ncols,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "abomonation-serialize")]
|
#[cfg(feature = "abomonation-serialize")]
|
||||||
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<N, R, C> {
|
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for VecStorage<N, R, C> {
|
||||||
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
unsafe fn entomb<W: Write>(&self, writer: &mut W) -> IOResult<()> {
|
||||||
|
|
|
@ -129,7 +129,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exp_complex() {
|
fn exp_complex() {
|
||||||
use nalgebra::{Complex, ComplexField, DMatrix, DVector, Matrix2, RealField};
|
use nalgebra::{Complex, DMatrix, DVector, Matrix2, RealField};
|
||||||
|
|
||||||
{
|
{
|
||||||
let z = Matrix2::<Complex<f64>>::zeros();
|
let z = Matrix2::<Complex<f64>>::zeros();
|
||||||
|
|
Loading…
Reference in New Issue