diff --git a/CHANGELOG.md b/CHANGELOG.md index ab56eaa2..7dcecaeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ longer unsafe. Instead, their name end with `_unchecked`. In particular: well. It is clear that performing computations with floats requires approximate equality. +Still WIP: add implementations of abstract algebra traits from the `algebra` +crate for vectors, rotations and points. To enable them, activate the +`abstract_algebra` feature. + ## [0.8.0] ### Modified * Almost everything (types, methods, and traits) now use full names instead diff --git a/Cargo.toml b/Cargo.toml index 253be7f1..4cbd8a8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ path = "src/lib.rs" # Generate arbitrary instances of nalgebra types for testing with quickcheck arbitrary = [ "quickcheck" ] generic_sizes = [ "generic-array", "typenum" ] +abstract_algebra = [ "algebra" ] [dependencies] rustc-serialize = "0.3.*" rand = "0.3.*" num = "0.1.*" -# algebra = "*" [dependencies.generic-array] optional = true @@ -37,3 +37,7 @@ version = "1.3.*" [dependencies.quickcheck] optional = true version = "0.2.*" + +[dependencies.algebra] +optional = true +version = "0.2.*" diff --git a/Makefile b/Makefile index 87cc39fb..78a080ee 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,18 @@ tmp=_git_distcheck all: - cargo build --release --features "arbitrary generic_sizes" + cargo build --release --features "arbitrary generic_sizes abstract_algebra" test: - cargo test --features "arbitrary generic_sizes" + cargo test --features "arbitrary generic_sizes abstract_algebra" bench: - cargo bench --features "arbitrary generic_sizes" + cargo bench --features "arbitrary generic_sizes abstract_algebra" doc: - cargo doc --no-deps --features "arbitrary generic_sizes" + cargo doc --no-deps --features "arbitrary generic_sizes abstract_algebra" clean: diff --git a/README.md b/README.md index a5fca593..719d0b31 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,8 @@ an optimized set of tools for computer graphics and physics. Those features incl * Points with static sizes: `Point1`, `Point2`, `Point3`, `Point4`, `Point5`, `Point6`. * Square matrices with static sizes: `Matrix1`, `Matrix2`, `Matrix3`, `Matrix4`, `Matrix5`, `Matrix6 `. * Rotation matrices: `Rotation2`, `Rotation3` -* Quaternions: `Quaternion`, `UnitQuaternion`. +* Quaternions: `Quaternion`, `Unit`. +* Unit-sized values (unit vectors, unit quaternions, etc.): `Unit`, e.g., `Unit>`. * Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3` * Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`. * 3D projections for computer graphics: `Persp3`, `PerspMatrix3`, `Ortho3`, `OrthoMatrix3`. diff --git a/src/lib.rs b/src/lib.rs index df41c059..7e6c70d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,7 @@ an optimized set of tools for computer graphics and physics. Those features incl * Square matrices with static sizes: `Matrix1`, `Matrix2`, `Matrix3`, `Matrix4`, `Matrix5`, `Matrix6 `. * Rotation matrices: `Rotation2`, `Rotation3` * Quaternions: `Quaternion`, `UnitQuaternion`. +* Unit-sized values (unit vectors, unit quaternions, etc.): `Unit`, e.g., `Unit>`. * Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3` * Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`. * 3D projections for computer graphics: `Perspective3`, `PerspectiveMatrix3`, `Orthographic3`, `OrthographicMatrix3`. @@ -85,6 +86,9 @@ extern crate generic_array; #[cfg(feature="arbitrary")] extern crate quickcheck; +#[cfg(feature="abstract_algebra")] +extern crate algebra; + use std::cmp; use std::ops::{Neg, Mul}; use num::{Zero, One}; diff --git a/src/structs/algebra/dummy.rs b/src/structs/algebra/dummy.rs new file mode 100644 index 00000000..0f687775 --- /dev/null +++ b/src/structs/algebra/dummy.rs @@ -0,0 +1,17 @@ +#![macro_use] + +macro_rules! vector_space_impl( + ($t: ident, $dimension: expr, $($compN: ident),+) => { } +); + +macro_rules! special_orthogonal_group_impl( + ($t: ident, $point: ident, $vector: ident) => { } +); + +macro_rules! euclidean_space_impl( + ($t: ident, $vector: ident) => { } +); + +macro_rules! matrix_group_approx_impl( + ($t: ident, $($compN: ident),+) => { } +); diff --git a/src/structs/algebra/matrix.rs b/src/structs/algebra/matrix.rs new file mode 100644 index 00000000..68fc7fe7 --- /dev/null +++ b/src/structs/algebra/matrix.rs @@ -0,0 +1,25 @@ +#![macro_use] + +macro_rules! use_matrix_group_modules( + () => { + use algebra::cmp::ApproxEq as AlgebraApproxEq; + } +); + +macro_rules! matrix_group_approx_impl( + ($t: ident, $($compN: ident),+) => { + impl AlgebraApproxEq for $t { + type Eps = N::Eps; + + #[inline] + fn default_epsilon() -> N::Eps { + N::default_epsilon() + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N::Eps) -> bool { + $(AlgebraApproxEq::approx_eq_eps(&self.$compN, &other.$compN, &epsilon))&&+ + } + } + } +); diff --git a/src/structs/algebra/mod.rs b/src/structs/algebra/mod.rs new file mode 100644 index 00000000..3bd34405 --- /dev/null +++ b/src/structs/algebra/mod.rs @@ -0,0 +1,13 @@ +#![macro_use] + +#[cfg(not(feature="abstract_algebra"))] +mod dummy; + +#[cfg(feature="abstract_algebra")] +mod vector; +#[cfg(feature="abstract_algebra")] +mod rotation; +#[cfg(feature="abstract_algebra")] +mod point; +#[cfg(feature="abstract_algebra")] +mod matrix; diff --git a/src/structs/algebra/point.rs b/src/structs/algebra/point.rs new file mode 100644 index 00000000..a273f022 --- /dev/null +++ b/src/structs/algebra/point.rs @@ -0,0 +1,34 @@ +#![macro_use] + +macro_rules! use_euclidean_space_modules( + () => { + use algebra::structure::{AffineSpaceApprox, EuclideanSpaceApprox, + FieldApprox, RealApprox}; + use algebra::cmp::ApproxEq as AlgebraApproxEq; + } +); + + +macro_rules! euclidean_space_impl( + ($t: ident, $vector: ident) => { + impl AffineSpaceApprox for $t + where N: Copy + Neg + Add + + Sub + AlgebraApproxEq + FieldApprox { + type Translation = $vector; + + #[inline] + fn translate_by(&self, vector: &Self::Translation) -> Self { + *self + *vector + } + + #[inline] + fn subtract(&self, other: &Self) -> Self::Translation { + *self - *other + } + } + + impl EuclideanSpaceApprox for $t { + type Vector = $vector; + } + } +); diff --git a/src/structs/algebra/rotation.rs b/src/structs/algebra/rotation.rs new file mode 100644 index 00000000..786aae63 --- /dev/null +++ b/src/structs/algebra/rotation.rs @@ -0,0 +1,92 @@ +#![macro_use] + +macro_rules! use_special_orthogonal_group_modules( + () => { + use algebra::structure::{EuclideanGroupApprox, SpecialEuclideanGroupApprox, + OrthogonalGroupApprox, SpecialOrthogonalGroupApprox, + GroupApprox, LoopApprox, MonoidApprox, + QuasigroupApprox, SemigroupApprox, + RealApprox}; + use algebra::cmp::ApproxEq as AlgebraApproxEq; + use algebra::ident::Identity; + use algebra::ops::{Recip, Multiplicative}; + } +); + +macro_rules! special_orthogonal_group_impl( + ($t: ident, $point: ident, $vector: ident) => { + /* + * Operations. + */ + impl Identity for $t { + #[inline] + fn id() -> Self { + ::one() + } + } + + impl> AlgebraApproxEq for $t { + type Eps = N; + + #[inline] + fn default_epsilon() -> N { + ::default_epsilon() + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N) -> bool { + AlgebraApproxEq::approx_eq_eps(&self.submatrix, &other.submatrix, &epsilon) + } + } + + impl Recip for $t { + type Result = $t; + + #[inline] + fn recip(mut self) -> $t { + self.inverse_mut(); + + self + } + } + + + /* + * + * Algebraic structures. + * + */ + // FIXME: in the end, we will keep only RealApprox. + impl GroupApprox for $t { } + impl LoopApprox for $t { } + impl MonoidApprox for $t { } + impl QuasigroupApprox for $t { } + impl SemigroupApprox for $t { } + + /* + * + * Matrix groups. + * + */ + impl EuclideanGroupApprox> for $t { + #[inline] + fn transform_point(&self, pt: &$point) -> $point { + *self * *pt + } + + #[inline] + fn transform_vector(&self, v: &$vector) -> $vector { + *self * *v + } + } + + impl SpecialEuclideanGroupApprox> for $t { + } + + impl OrthogonalGroupApprox> for $t { + } + + impl SpecialOrthogonalGroupApprox> for $t { + } + } +); diff --git a/src/structs/algebra/vector.rs b/src/structs/algebra/vector.rs new file mode 100644 index 00000000..ebcf2e30 --- /dev/null +++ b/src/structs/algebra/vector.rs @@ -0,0 +1,186 @@ +#![macro_use] + +macro_rules! use_vector_space_modules( + () => { + use algebra::structure::{FieldApprox, RingCommutativeApprox, GroupAbelianApprox, + GroupApprox, LoopApprox, MonoidApprox, QuasigroupApprox, + SemigroupApprox, VectorSpaceApprox, ModuleApprox, + NormedSpaceApprox, InnerSpaceApprox, + FiniteDimVectorSpaceApprox, + Field, RingCommutative, GroupAbelian, + Group, Loop, Monoid, Quasigroup, + Semigroup, VectorSpace, Module, RealApprox}; + use algebra::cmp::ApproxEq as AlgebraApproxEq; + use algebra::ident::Identity; + use algebra::ops::Additive; + } +); + +macro_rules! vector_space_impl( + ($t: ident, $dimension: expr, $($compN: ident),+) => { + /* + * Identity & ApproxEq + */ + impl> Identity for $t { + #[inline] + fn id() -> Self { + Repeat::repeat(Identity::id()) + } + } + + impl AlgebraApproxEq for $t { + type Eps = N::Eps; + + #[inline] + fn default_epsilon() -> N::Eps { + N::default_epsilon() + } + + #[inline] + fn approx_eq_eps(&self, other: &$t, epsilon: &N::Eps) -> bool { + $(AlgebraApproxEq::approx_eq_eps(&self.$compN, &other.$compN, &epsilon))&&+ + } + } + + /* + * + * Approximate algebraic structures. + * + */ + product_space_inherit_structure!($t, GroupAbelianApprox); + product_space_inherit_structure!($t, GroupApprox); + product_space_inherit_structure!($t, LoopApprox); + product_space_inherit_structure!($t, MonoidApprox); + product_space_inherit_structure!($t, QuasigroupApprox); + product_space_inherit_structure!($t, SemigroupApprox); + + /* + * Module. + */ + impl ModuleApprox for $t where N: Copy + Neg + Add + + AlgebraApproxEq + RingCommutativeApprox + { } + + /* + * Vector spaces. + */ + impl VectorSpaceApprox for $t + where N: Copy + Neg + Add + + AlgebraApproxEq + FieldApprox { } + + impl FiniteDimVectorSpaceApprox for $t + where N: Copy + Zero + One + Neg + Add + + AlgebraApproxEq + FieldApprox { + #[inline] + fn dimension() -> usize { + $dimension + } + + #[inline] + fn canonical_basis])>(f: F) { + let basis = [ + $($t::$compN()),* + ]; + + f(&basis[..]) + } + + #[inline] + fn component(&self, i: usize) -> N { + self[i] + } + + #[inline] + unsafe fn component_unchecked(&self, i: usize) -> N { + self.at_fast(i) + } + } + + impl NormedSpaceApprox for $t { + #[inline] + fn norm_squared(&self) -> N { + self.inner_product(self) + } + + #[inline] + fn norm(&self) -> N { + self.norm_squared().sqrt() + } + + #[inline] + fn normalize(&self) -> Self { + *self / self.norm() + } + + #[inline] + fn normalize_mut(&mut self) -> N { + let n = self.norm(); + *self /= n; + + n + } + + #[inline] + fn try_normalize(&self, min_norm: &N) -> Option { + let n = self.norm(); + + if n <= *min_norm { + None + } + else { + Some(*self / n) + } + } + + #[inline] + fn try_normalize_mut(&mut self, min_norm: &N) -> Option { + let n = self.norm(); + + if n <= *min_norm { + None + } + else { + *self /= n; + Some(n) + } + } + } + + impl InnerSpaceApprox for $t { + #[inline] + fn inner_product(&self, other: &Self) -> N { + fold_add!($(self.$compN * other.$compN ),+) + } + } + + /* + * + * Exact algebraic structures. + * + */ + + product_space_inherit_structure!($t, GroupAbelian); + product_space_inherit_structure!($t, Group); + product_space_inherit_structure!($t, Loop); + product_space_inherit_structure!($t, Monoid); + product_space_inherit_structure!($t, Quasigroup); + product_space_inherit_structure!($t, Semigroup); + + impl VectorSpace for $t + where N: Copy + Neg + Add + AlgebraApproxEq + Field + { } + + impl Module for $t + where N: Copy + Neg + Add + AlgebraApproxEq + RingCommutative + { } + } +); + +macro_rules! product_space_inherit_structure( + ($t: ident, $marker: ident<$operator: ident>) => { + impl $marker<$operator> for $t + where N: Copy + Neg + Add + AlgebraApproxEq + + $marker<$operator> + { } + } +); diff --git a/src/structs/common_macros.rs b/src/structs/common_macros.rs index ac5438ad..78fabb5e 100644 --- a/src/structs/common_macros.rs +++ b/src/structs/common_macros.rs @@ -349,3 +349,16 @@ macro_rules! component_new( } ); ); + + +macro_rules! fold_add( + // base case + ($x:expr) => { + $x + }; + // `$x` followed by at least one `$y,` + ($x:expr, $($y:expr),+) => { + // call min! on the tail `$y` + Add::add($x, fold_add!($($y),+)) + } +); diff --git a/src/structs/matrix.rs b/src/structs/matrix.rs index 7e07c663..9b44fe31 100644 --- a/src/structs/matrix.rs +++ b/src/structs/matrix.rs @@ -18,9 +18,13 @@ use traits::structure::{Cast, Row, Column, Iterable, IterableMut, Dimension, Ind use traits::operations::{Absolute, Transpose, Inverse, Outer, EigenQR, Mean}; use traits::geometry::{ToHomogeneous, FromHomogeneous, Origin}; use linalg; + #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature="abstract_algebra")] +use_matrix_group_modules!(); + /// Special identity matrix. All its operation are no-ops. #[repr(C)] diff --git a/src/structs/matrix_macros.rs b/src/structs/matrix_macros.rs index 21404076..acfeb2cf 100644 --- a/src/structs/matrix_macros.rs +++ b/src/structs/matrix_macros.rs @@ -2,6 +2,9 @@ macro_rules! matrix_impl( ($t: ident, $dimension: expr, $vector: ident, $dvector: ident, $($compN: ident),+) => ( + + matrix_group_approx_impl!($t, $($compN),+); + impl $t { #[inline] pub fn new($($compN: N ),+) -> $t { diff --git a/src/structs/mod.rs b/src/structs/mod.rs index 983b8ac5..befc49a7 100644 --- a/src/structs/mod.rs +++ b/src/structs/mod.rs @@ -17,6 +17,7 @@ pub use self::unit::Unit; pub use self::vectorn::VectorN; mod common_macros; +mod algebra; mod dmatrix_macros; mod dmatrix; mod vectorn_macros; diff --git a/src/structs/point.rs b/src/structs/point.rs index 699d7aaa..4bb95b24 100644 --- a/src/structs/point.rs +++ b/src/structs/point.rs @@ -12,9 +12,13 @@ use traits::structure::{Cast, Dimension, Indexable, Iterable, IterableMut, Point NumPoint, FloatPoint, BaseFloat, BaseNum, Bounded, Repeat}; use traits::geometry::{Origin, FromHomogeneous, ToHomogeneous}; use structs::vector::{Vector1, Vector2, Vector3, Vector4, Vector5, Vector6}; + #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature="abstract_algebra")] +use_euclidean_space_modules!(); + /// Point of dimension 1. /// diff --git a/src/structs/point_macros.rs b/src/structs/point_macros.rs index 077255cb..0fdec197 100644 --- a/src/structs/point_macros.rs +++ b/src/structs/point_macros.rs @@ -3,6 +3,8 @@ macro_rules! point_impl( ($t: ident, $tv: ident | $($compN: ident),+) => ( + euclidean_space_impl!($t, $tv); + /* * * Origin. diff --git a/src/structs/quaternion.rs b/src/structs/quaternion.rs index 737ec988..3d96e51a 100644 --- a/src/structs/quaternion.rs +++ b/src/structs/quaternion.rs @@ -17,7 +17,7 @@ use traits::geometry::{Norm, Rotation, RotationMatrix, Rotate, RotationTo, Trans use quickcheck::{Arbitrary, Gen}; -/// A quaternion. See `UnitQuaternion` for a quaternion that can be used as a rotation. +/// A quaternion. See the `UnitQuaternion` type alias for a quaternion that can be used as a rotation. #[repr(C)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] pub struct Quaternion { diff --git a/src/structs/rotation.rs b/src/structs/rotation.rs index c8be3a11..c5354fba 100644 --- a/src/structs/rotation.rs +++ b/src/structs/rotation.rs @@ -11,9 +11,12 @@ use traits::operations::{Absolute, Inverse, Transpose, ApproxEq}; use structs::vector::{Vector1, Vector2, Vector3}; use structs::point::{Point2, Point3}; use structs::matrix::{Matrix2, Matrix3, Matrix4}; + #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature="abstract_algebra")] +use_special_orthogonal_group_modules!(); /// Two dimensional rotation matrix. #[repr(C)] diff --git a/src/structs/rotation_macros.rs b/src/structs/rotation_macros.rs index 22307968..dfcdd835 100644 --- a/src/structs/rotation_macros.rs +++ b/src/structs/rotation_macros.rs @@ -2,6 +2,9 @@ macro_rules! rotation_impl( ($t: ident, $submatrix: ident, $vector: ident, $rotvector: ident, $point: ident, $homogeneous: ident) => ( + + special_orthogonal_group_impl!($t, $point, $vector); + impl $t { /// This rotation's underlying matrix. #[inline] diff --git a/src/structs/unit.rs b/src/structs/unit.rs index f6730e96..d48af8e1 100644 --- a/src/structs/unit.rs +++ b/src/structs/unit.rs @@ -2,6 +2,8 @@ use traits::geometry::Norm; /// A wrapper that ensures the undelying algebraic entity has a unit norm. +/// +/// Use `.as_ref()` or `.unwrap()` to obtain the undelying value by-reference or by-move. #[repr(C)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] pub struct Unit { @@ -47,7 +49,7 @@ impl Unit { /// Normalizes this value again. This is useful when repeated computations /// might cause a drift in the norm because of float inaccuracies. /// - /// Returns the norm beform re-normalization (should be close to `1.0`). + /// Returns the norm before re-normalization (should be close to `1.0`). #[inline] pub fn renormalize(&mut self) -> T::NormType { self.v.normalize_mut() diff --git a/src/structs/vector.rs b/src/structs/vector.rs index 45ac1646..1c3fa4d3 100644 --- a/src/structs/vector.rs +++ b/src/structs/vector.rs @@ -17,6 +17,9 @@ use structs::point::{Point1, Point2, Point3, Point4, Point5, Point6}; #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; +#[cfg(feature="abstract_algebra")] +use_vector_space_modules!(); + /// Vector of dimension 1. /// @@ -29,7 +32,7 @@ pub struct Vector1 { pub x: N } -vector_impl!(Vector1, Point1, x); +vector_impl!(Vector1, Point1, 1, x); vectorlike_impl!(Vector1, 1, x); from_iterator_impl!(Vector1, iterator); // (specialized); basis_impl!(Vector1, 1); @@ -51,7 +54,7 @@ pub struct Vector2 { pub y: N } -vector_impl!(Vector2, Point2, x, y); +vector_impl!(Vector2, Point2, 2, x, y); vectorlike_impl!(Vector2, 2, x, y); from_iterator_impl!(Vector2, iterator, iterator); // (specialized); basis_impl!(Vector2, 1); @@ -75,7 +78,7 @@ pub struct Vector3 { pub z: N } -vector_impl!(Vector3, Point3, x, y, z); +vector_impl!(Vector3, Point3, 3, x, y, z); vectorlike_impl!(Vector3, 3, x, y, z); from_iterator_impl!(Vector3, iterator, iterator, iterator); // (specialized); basis_impl!(Vector3, 1); @@ -100,7 +103,7 @@ pub struct Vector4 { pub w: N } -vector_impl!(Vector4, Point4, x, y, z, w); +vector_impl!(Vector4, Point4, 4, x, y, z, w); vectorlike_impl!(Vector4, 4, x, y, z, w); from_iterator_impl!(Vector4, iterator, iterator, iterator, iterator); basis_impl!(Vector4, 4); @@ -128,7 +131,7 @@ pub struct Vector5 { pub a: N } -vector_impl!(Vector5, Point5, x, y, z, w, a); +vector_impl!(Vector5, Point5, 5, x, y, z, w, a); vectorlike_impl!(Vector5, 5, x, y, z, w, a); from_iterator_impl!(Vector5, iterator, iterator, iterator, iterator, iterator); basis_impl!(Vector5, 5); @@ -157,7 +160,7 @@ pub struct Vector6 { pub b: N } -vector_impl!(Vector6, Point6, x, y, z, w, a, b); +vector_impl!(Vector6, Point6, 6, x, y, z, w, a, b); vectorlike_impl!(Vector6, 6, x, y, z, w, a, b); from_iterator_impl!(Vector6, iterator, iterator, iterator, iterator, iterator, iterator); diff --git a/src/structs/vector_macros.rs b/src/structs/vector_macros.rs index e2343261..7bd0e931 100644 --- a/src/structs/vector_macros.rs +++ b/src/structs/vector_macros.rs @@ -270,7 +270,7 @@ macro_rules! vectorlike_impl( ); macro_rules! vector_impl( - ($t: ident, $tp: ident, $($compN: ident),+) => ( + ($t: ident, $tp: ident, $dimension: expr, $($compN: ident),+) => ( pointwise_add!($t, $($compN),+); pointwise_sub!($t, $($compN),+); pointwise_mul!($t, $($compN),+); @@ -279,7 +279,7 @@ macro_rules! vector_impl( componentwise_one!($t, $($compN),+); componentwise_absolute!($t, $($compN),+); component_basis_element!($t, $($compN),+); - + vector_space_impl!($t, $dimension, $($compN),+); /* * @@ -289,11 +289,10 @@ macro_rules! vector_impl( impl Dot for $t { #[inline] fn dot(&self, other: &$t) -> N { - add!($(self.$compN * other.$compN ),+) + fold_add!($(self.$compN * other.$compN ),+) } } - /* * * Norm @@ -597,18 +596,6 @@ macro_rules! basis_impl( ); -macro_rules! add ( - // base case - ($x:expr) => { - $x - }; - // `$x` followed by at least one `$y,` - ($x:expr, $($y:expr),+) => { - // call min! on the tail `$y` - Add::add($x, add!($($y),+)) - } -); - macro_rules! from_iterator_impl( ($t: ident, $param0: ident) => ( diff --git a/src/structs/vectorn.rs b/src/structs/vectorn.rs index 9b0fec3e..c5433dce 100644 --- a/src/structs/vectorn.rs +++ b/src/structs/vectorn.rs @@ -11,7 +11,7 @@ use traits::structure::{Iterable, IterableMut, Indexable, Shape, BaseFloat, Base #[cfg(feature="arbitrary")] use quickcheck::{Arbitrary, Gen}; -/// A static array of arbitrary dimension. +/// A stack-allocated vector of arbitrary dimension. #[repr(C)] #[derive(Eq, PartialEq, Debug)] // FIXME: Hash, RustcEncodable, RustcDecodable pub struct VectorN> {