|
Mundy: Multibody Nonlocal Dynamics Version of the Day
|
constexpr, inline mathematics.
See the MundyMath directory reference.
This subpackage contains shared functionality for performing small highly-optimized mathematical operations. The core functionality includes
The Array class is a container with constexpr access and construction equivalent to Kokkos::Array.
The Vector class is endowed with the mathematical properties of vectors. It supports addition, multiplication, dot products, norms, etc. It is templated by the vector's scalar type and size so Vector<double, 3> would correspond to a double-typed vector in R3. Similar to Eigen, we offer shorthand naming for scalar types float/double and sizes 1-6. For example:
Canonically, we treat the () accessor as the mathematical accessor and [] as the programming accessor into the flattened underlying data. So for a 3x3 matrix this would be mat33(i, j) == mat33[3 * i + j]. For vectors, the two are equivalent.
The following operations can be performed on a vector to compute various reductions:
| Operation | Description | Example (for Vector2d v1{1.1, 2.2}) |
|---|---|---|
| size(v) | Number of components in the vector. | size(v1) → 2 |
| sum(v) | Sum of all components. | sum(v1) → 3.3 |
| product(v) | Product of all components. | product(v1) → 2.42 |
| min(v) | Minimum component value. | min(v1) → 1.1 |
| max(v) | Maximum component value. | max(v1) → 2.2 |
| mean(v) | Mean of all components. | mean(v1) → 1.65 |
| variance(v) | Variance of the components. | variance(v1) → 0.3025 |
| stddev(v) | Standard deviation of the components. | stddev(v1) → 0.55 |
The following operations can be performed on vectors to compute various properties:
| Operation | Description | Example (for Vector2d v1{1., 2.}, v2{3., 4.}) |
|---|---|---|
| dot(v1, v2) | Dot product of two vectors. | dot(v1, v2) → 1. * 3. + 2. * 4. = 11. |
| infinity_norm(v) | Infinity norm (maximum absolute value of components). | infinity_norm(v1) → 2. |
| one_norm(v) | 1-norm (sum of absolute values of components). | one_norm(v1) → 1. + 2. = 3. |
| two_norm(v) | 2-norm (Euclidean norm, square root of the sum of squares). | two_norm(v1) → sqrt(1.^2 + 2.^2) = sqrt(5.) |
| two_norm_squared(v) | Squared 2-norm (sum of squares of components). | two_norm_squared(v1) → 1.^2 + 2.^2 = 5. |
| norm(v) | Default norm (same as two_norm). | norm(v1) → sqrt(5.) |
| norm_squared(v) | Default squared norm (same as two_norm_squared). | norm_squared(v1) → 5. |
| minor_angle(v1, v2) | Minor angle between two vectors (angle in radians, between 0 and π). | minor_angle(v1, v2) → acos(dot(v1, v2) / (norm(v1) * norm(v2))) |
| major_angle(v1, v2) | Major angle between two vectors (angle in radians, between 0 and π). | major_angle(v1, v2) → π - minor_angle(v1, v2) |
Some operations are only defined for vectors of specific sizes. For example, the cross product is only valid for 3D vectors (Vector3).
| Operation | Description | Example (for Vector3d v1{1., 2., 3.}, v2{4., 5., 6.}) |
|---|---|---|
| cross(v1, v2) | Cross product of two 3D vectors. | cross(v1, v2) → Vector3d{-3., 6., -3.} |
The Matrix class is endowed with the mathematical properties of dense matrices. It supports addition, multiplication, matrix-vector, matrix-scalar arithmetic, norms, etc. It is templated by the matrices's scalar type and sizes so Matrix<double, 3, 2> would correspond to a double-typed matrix with 3 rows and 2 columns. Similar to Eigen, we offer shorthand naming for scalar types float/double and sizes 1-6. For example:
Matrices support both row-column accessors (()) and flattened row-major data accessors ([]). For example:
Of course, the matrices and vectors must be of the correct size. We do, however, take the pythonic approach and use lazy transposes for vectors, so left vector-matrix multiplication is just
The following operations can be performed on a matrix to compute various reductions:
| Operation | Description |
|---|---|
| sum(m) | Sum of all elements in the matrix. |
| product(m) | Product of all elements in the matrix. |
| min(m) | Minimum element value in the matrix. |
| max(m) | Maximum element value in the matrix. |
| mean(m) | Mean of all elements in the matrix. |
| variance(m) | Variance of the elements in the matrix. |
| stddev(m) | Standard deviation of the elements in the matrix. |
The following operations can be performed on matrices to compute various properties or transformations:
| Operation | Description |
|---|---|
| determinant(m) | Compute the determinant of a square matrix. |
| trace(m) | Sum of the diagonal elements of the matrix. |
| transpose(m) | Transpose of the matrix. |
| cofactors(m) | Matrix of cofactors. |
| adjugate(m) | Adjugate (transpose of the cofactor matrix). |
| inverse(m) | Inverse of the matrix (if invertible). |
| frobenius_inner_product(m1, m2) | Frobenius inner product of two matrices. |
| outer_product(v1, v2) | Outer product of two vectors, resulting in a matrix. |
| frobenius_norm(m) | Frobenius norm (square root of the sum of squares of all elements). |
| infinity_norm(m) | Maximum absolute row sum. |
| one_norm(m) | Maximum absolute column sum. |
| two_norm(m) | 2-norm (largest singular value of the matrix). |
Mundy's Vector, Matrix, and Quaternion types offer the ability to construct a non-owning mathematical view into existing data, endowing it with all the mathematical properties listed above. Views can either be constructed from pointers:
or from any copy constructable class that offers a [size_t] access operator, such as the following strided array class:
Mundy's Vector and Matrix types provide element-wise atomic operations. "Element-wise" means the atomic is applied independently to each component (each v[i] or m(r,c)), rather than synchronizing on the entire vector/matrix as one big locked object.
These APIs are intended for shared-memory parallel updates (e.g., many threads accumulating into the same vector/matrix) where you want correctness without manually managing locks.
Use these when you want an atomic snapshot of each element (load) or an atomic write to each element (store).
Notes:
- atomic_load(v) returns a value copy.
- atomic_store(&v, x) takes a pointer/reference to the destination being updated.
All atomic update routines come in three return-style flavors:
Each operation is applied per element.
Operations are provided in two operand forms:
| Form | Examples of operations |
|---|---|
| Scalar RHS | add, sub, mul, div |
| Element-wise RHS | add, sub, elementwise_mul, elementwise_div |
Tip: pick the variant based on what you want to do next.
- If you do not need a value, prefer atomic_<op> (it's the simplest and often the cheapest).
- If you need the prior value (e.g., for a conditional), use atomic_fetch_<op>.
- If you need the updated value (e.g., to chain computations), use atomic_<op>_fetch.
Matrix atomics mirror the vector API exactly, but operate on m(r,c) element-by-element.
rhs may be a scalar (broadcast) or a matrix of matching shape (element-wise), depending on the operation.