diff --git a/.gitignore b/.gitignore
index 9a3f7ae..947d38b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
/target/
Cargo.lock
**/*.rs.bk
+examples
.DS_Store
diff --git a/Cargo.toml b/Cargo.toml
index c3d15b9..9604567 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,7 @@ license = "Apache-2.0"
edition = "2021"
keywords = ["vector", "math", "real", "imaginary", "complex"]
repository = "https://github.com/chrissimpkins/vectora"
-description = "A vector computation library"
+description = "Fast, Flexible n-Dimensional Vector Math for Rust"
readme = "README.md"
exclude = [
@@ -34,3 +34,6 @@ harness = false
[package.metadata.docs.rs]
# Whether to pass `--all-features` to Cargo (default: false)
all-features = true
+
+[profile.release]
+lto = true
diff --git a/README.md b/README.md
index 26f874f..42da406 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-## A Rust library for vector computation
+## Fast, Flexible n-Dimensional Vector Math for Rust
[](https://crates.io/crates/vectora)
[](https://docs.rs/vectora)
@@ -15,7 +15,7 @@
## About
-Vectora is a library for n-dimensional vector computation with real and complex scalar types. The main library entry point is the [`Vector`](https://docs.rs/vectora/latest/vectora/types/vector/struct.Vector.html) struct. Please see the [Gettting Started Guide](https://docs.rs/vectora/latest/vectora/#getting-started) for a detailed library API overview with examples.
+Vectora is a library for n-dimensional vector math with real and complex scalar types. The main library entry point is the [`Vector`](https://docs.rs/vectora/latest/vectora/types/vector/struct.Vector.html) struct. Please see the [Gettting Started Guide](https://docs.rs/vectora/latest/vectora/#getting-started) for a detailed library API overview with examples.
## User documentation
diff --git a/src/errors.rs b/src/errors.rs
index b11e5cc..62f5a4e 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -1,11 +1,15 @@
//! Error types.
-/// Errors that occur while working with [`crate::types::vector::Vector`]
+/// Errors that occur while working with vector types.
#[derive(Debug)]
pub enum VectorError {
- /// Occurs when an operation that requires data in a [`crate::types::vector::Vector`] is
- /// requested with an empty [`crate::types::vector::Vector`]
+ /// Occurs when an operation that requires data in a vector type is
+ /// requested with an empty vector type.
EmptyVectorError(String),
+ /// Occurs when two vectors need to be the same length to complete an operation, and are not.
+ MismatchedLengthError(String),
+ /// Occurs when a value extends outside of a mandatory range.
+ OutOfRangeError(String),
/// Occurs when there is invalid data during an attempt to convert
/// from [`slice`] data.
TryFromSliceError(String),
@@ -14,6 +18,8 @@ pub enum VectorError {
TryFromVecError(String),
/// ValueError occurs when an invalid value is used in an operation
ValueError(String),
+ /// Errors with invalid zero vectors
+ ZeroVectorError(String),
}
impl std::fmt::Display for VectorError {
@@ -22,6 +28,12 @@ impl std::fmt::Display for VectorError {
VectorError::EmptyVectorError(s) => {
write!(f, "VectorError::EmptyVectorError: {s}")
}
+ VectorError::MismatchedLengthError(s) => {
+ write!(f, "VectorError::MismatchedLengthError: {s}")
+ }
+ VectorError::OutOfRangeError(s) => {
+ write!(f, "VectorError::OutOfRangeError: {s}")
+ }
VectorError::TryFromVecError(s) => {
write!(f, "VectorError::TryFromVecError: {s}")
}
@@ -31,6 +43,9 @@ impl std::fmt::Display for VectorError {
VectorError::ValueError(s) => {
write!(f, "VectorError::ValueError: {s}")
}
+ VectorError::ZeroVectorError(s) => {
+ write!(f, "VectorError::ZeroVectorError: {s}")
+ }
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f92d617..f96f7b7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -893,6 +893,29 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod errors;
+pub mod macros;
pub mod types;
+pub use types::flexvector::FlexVector;
pub use types::vector::Vector;
+
+/// The vectora prelude: import this module to bring all core traits, types, and macros into scope.
+///
+/// This prelude includes:
+/// - Core traits
+/// - Main types
+/// - Main macros
+pub mod prelude {
+ // Traits
+ pub use crate::types::traits::{
+ Transposable, VectorBase, VectorBaseMut, VectorHasOrientation, VectorOps, VectorOpsComplex,
+ VectorOpsComplexMut, VectorOpsFloat, VectorOpsFloatMut, VectorOpsMut,
+ };
+ // Types
+ pub use crate::types::flexvector::FlexVector;
+ pub use crate::types::orientation::{Column, Row, VectorOrientation};
+ pub use crate::types::vector::Vector;
+ pub use crate::types::vectorslice::{VectorSlice, VectorSliceMut};
+ // Macros
+ pub use crate::{fv, fv_from, fv_iter, try_fv_iter, try_vector, vector};
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..efccd1d
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,1448 @@
+//! Macros.
+
+/// Creates a [`Vector`] with the given elements or repeated value.
+///
+/// - `vector![x, y, z]` creates a Vector from the elements.
+/// - `vector![elem; n]` creates a Vector of length `n` with all elements set to `elem`.
+///
+/// # Examples
+///
+/// ```
+/// use vectora::vector;
+/// use num::Complex;
+///
+/// let v = vector![1, 2, 3];
+/// let v_f64 = vector![1.0, 2.0, 3.0];
+/// let v_repeat = vector![0; 4];
+/// let v_complex = vector![Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)];
+/// ```
+#[macro_export]
+macro_rules! vector {
+ ($elem:expr; $n:expr) => (
+ $crate::types::vector::Vector::from([$elem; $n])
+ );
+ ($($x:expr),+ $(,)?) => (
+ $crate::types::vector::Vector::from([$($x),+])
+ );
+}
+
+/// Converts a collection (like a `Vec` or slice) into a [`Vector`] of matching length, returning a `Result`.
+///
+/// - `try_vector!(data)` tries to create a Vector from a runtime collection, returning an error if the length does not match.
+///
+/// # Examples
+///
+/// ```
+/// use vectora::prelude::*;
+/// use num::Complex;
+///
+/// let v: Vector = try_vector!(vec![1, 2, 3]).unwrap();
+/// let v_f64: Vector = try_vector!([1.0, 2.0, 3.0]).unwrap();
+/// let v_complex: Vector, 2> = try_vector!(vec![Complex::new(1.0, 2.0), Complex::new(3.0, 4.0)]).unwrap();
+/// ```
+///
+/// /// Error example:
+///
+/// ```
+/// use vectora::prelude::*;
+/// // This will return an Err because the length does not match the Vector's size.
+/// let result: Result, _> = try_vector!(vec![1, 2]); // Suppose you want Vector
+/// assert!(result.is_err());
+#[macro_export]
+macro_rules! try_vector {
+ ($elem:expr) => {
+ $crate::types::vector::Vector::try_from($elem)
+ };
+}
+
+/// Creates a [`FlexVector`] with the list of given elements or repeated value, optionally specifying
+/// vector row or column orientation.
+///
+/// - `fv![x, y, z]` creates a default (column) FlexVector.
+/// - `fv![Column; x, y, z]` creates a Column FlexVector.
+/// - `fv![Row; x, y, z]` creates a Row FlexVector.
+/// - `fv![elem; n]` creates a default (column) FlexVector of length `n` with all elements set to `elem`.
+/// - `fv![Column; elem; n]` creates a Column FlexVector of length `n` with all elements set to `elem`.
+/// - `fv![Row; elem; n]` creates a Row FlexVector of length `n` with all elements set to `elem`.
+///
+/// # Examples
+/// ```
+/// use vectora::prelude::*;
+///
+/// let fv_default: FlexVector = fv![1, 2, 3];
+/// let fv_col = fv![Column; 1, 2, 3];
+/// let fv_row = fv![Row; 1, 2, 3];
+/// let fv_default_repeat: FlexVector = fv![0; 4];
+/// let fv_col_repeat = fv![Column; 0; 4];
+/// let fv_row_repeat = fv![Row; 0; 4];
+/// ```
+#[macro_export]
+macro_rules! fv {
+ // Row vector, repeated element: fv![Row; elem; n]
+ (Row; $elem:expr; $n:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Row>::from_vec(vec![$elem; $n])
+ };
+ // Column vector, repeated element: fv![Column; elem; n]
+ (Column; $elem:expr; $n:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Column>::from_vec(vec![$elem; $n])
+ };
+ // Default (column) vector, repeated element: fv![elem; n]
+ ($elem:expr; $n:expr) => {
+ $crate::types::flexvector::FlexVector::from_vec(vec![$elem; $n])
+ };
+ // Row vector, list: fv![Row; x, y, z, ...]
+ (Row; $($x:expr),+ $(,)?) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Row>::from_vec(vec![$($x),+])
+ };
+ // Column vector, list: fv![Column; x, y, z, ...]
+ (Column; $($x:expr),+ $(,)?) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Column>::from_vec(vec![$($x),+])
+ };
+ // Default (column) vector, list: fv![x, y, z, ...]
+ ($($x:expr),+ $(,)?) => {
+ $crate::types::flexvector::FlexVector::from_vec(vec![$($x),+])
+ };
+}
+
+/// Creates a [`FlexVector`] from a collection (slice, Vec, or Cow), optionally specifying row or column orientation.
+///
+/// - `fv_from![data]` creates a default (column) FlexVector from any collection accepted by `from_cow`.
+/// - `fv_from![Row; data]` creates a Row FlexVector from a collection.
+/// - `fv_from![Column; data]` creates a Column FlexVector from a collection.
+///
+/// # Examples
+/// ```
+/// use vectora::prelude::*;
+/// use std::borrow::Cow;
+///
+/// let slice: &[i32] = &[1, 2, 3];
+/// let fv: FlexVector = fv_from![slice];
+///
+/// let vec = vec![4, 5, 6];
+/// let fv_col = fv_from![Column; vec];
+///
+/// let cow: Cow<[i32]> = Cow::Borrowed(&[7, 8, 9]);
+/// let fv_row = fv_from![Row; cow];
+/// ```
+#[macro_export]
+macro_rules! fv_from {
+ (Row; $data:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Row>::from_cow($data)
+ };
+ (Column; $data:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Column>::from_cow(
+ $data,
+ )
+ };
+ ($data:expr) => {
+ $crate::types::flexvector::FlexVector::from_cow($data)
+ };
+}
+
+/// Creates a [`FlexVector`] from any iterable (such as an iterator, range, Vec, or array),
+/// optionally specifying row or column orientation.
+///
+/// - `fv_iter![data]` creates a default (column) FlexVector from any iterable.
+/// - `fv_iter![Row; data]` creates a Row FlexVector from any iterable.
+/// - `fv_iter![Column; data]` creates a Column FlexVector from any iterable.
+///
+/// # Examples
+/// ```
+/// use vectora::prelude::*;
+///
+/// // From a range
+/// let fv: FlexVector = fv_iter![0..3];
+/// assert_eq!(fv.as_slice(), &[0, 1, 2]);
+///
+/// // From a Vec
+/// let v = vec![10, 20, 30];
+/// let fv_col = fv_iter![Column; v.clone()];
+/// assert_eq!(fv_col.as_slice(), &[10, 20, 30]);
+///
+/// // From an iterator
+/// let fv_row = fv_iter![Row; (1..=3).map(|x| x * 2)];
+/// assert_eq!(fv_row.as_slice(), &[2, 4, 6]);
+/// ```
+#[macro_export]
+macro_rules! fv_iter {
+ (Row; $data:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Row>::from_iter(
+ $data,
+ )
+ };
+ (Column; $data:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Column>::from_iter(
+ $data,
+ )
+ };
+ ($data:expr) => {
+ $crate::types::flexvector::FlexVector::from_iter($data)
+ };
+}
+
+/// Fallibly constructs a [`FlexVector`] from an iterator of `Result`, propagating the first error,
+/// optionally specifying vector row or column orientation.
+///
+/// - `try_fv_iter!(iter)` collects all `Ok(T)` values into a default (column) FlexVector, or returns the first `Err(E)` encountered.
+/// - `try_fv_iter!(Column; iter)` collects into a Column FlexVector.
+/// - `try_fv_iter!(Row; iter)` collects into a Row FlexVector.
+///
+/// # Examples
+/// ```
+/// use vectora::prelude::*;
+///
+/// let data = vec!["1", "2", "oops"];
+/// let fv: Result, _> = try_fv_iter!(data.iter().map(|s| s.parse::()));
+/// assert!(fv.is_err());
+///
+/// let data = vec!["1", "2", "3"];
+/// let fv = try_fv_iter!(Row; data.iter().map(|s| s.parse::())).unwrap();
+/// assert_eq!(fv.as_slice(), &[1, 2, 3]);
+/// ```
+#[macro_export]
+macro_rules! try_fv_iter {
+ // Row vector: try_fv!(Row; iter)
+ (Row; $iter:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Row>::try_from_iter($iter)
+ };
+ // Column vector: try_fv!(Column; iter)
+ (Column; $iter:expr) => {
+ $crate::types::flexvector::FlexVector::<_, $crate::types::orientation::Column>::try_from_iter($iter)
+ };
+ // Default (column) vector: try_fv!(iter)
+ ($iter:expr) => {
+ $crate::types::flexvector::FlexVector::try_from_iter($iter)
+ };
+}
+
+/// ...
+#[macro_export]
+macro_rules! impl_vector_unary_op {
+ ($VectorType:ident, $trait:ident, $method:ident, $op:tt) => {
+ impl std::ops::$trait for $VectorType
+ where
+ T: num::Num + Clone + std::ops::Neg