Math Classes

RaiSim provides small, header-only matrix/vector types that are compatible with Eigen via lightweight Eigen::Map views.

Core types

  • raisim::Mat<n, m>: fixed-size, column-major storage (double).

  • raisim::Vec<n>: alias for raisim::Mat<n, 1>.

  • raisim::MatDyn / raisim::VecDyn: dynamic-size, RaiSim-owned storage.

  • raisim::SparseJacobian / raisim::SparseJacobian1D: dynamic storage used by some APIs for sparse Jacobians.

Eigen interoperability (.e())

All RaiSim math types provide an .e() accessor returning an Eigen::Map that references the underlying RaiSim storage. This is the preferred way to call APIs that take Eigen types (e.g. Eigen::Ref).

raisim::Vec<3> v;
v << 1.0, 2.0, 3.0;

// Non-owning Eigen view
auto v_e = v.e();  // Eigen::Map<...>
Eigen::Vector3d ev = v_e;  // copies into a real Eigen vector

raisim::VecDyn q(12);
q.setZero();
auto q_e = q.e();  // Eigen::Map

Alignment and ownership

  • raisim::Mat/raisim::Vec are 32-byte aligned fixed-size POD-like types. Standard containers therefore need over-aligned allocation support. The exported RaiSim target requires C++20, which provides the needed language and standard-library baseline.

  • raisim::MatDyn/raisim::VecDyn own their heap storage, which is 32-byte aligned on Linux and macOS and allocated with Eigen’s aligned allocator on Windows. Do not free their memory manually.

  • .e() returns a non-owning map. Its lifetime must not exceed the underlying RaiSim object.

  • Any call to resize() (dynamic types) reallocates the storage, discards the previous contents, and invalidates raw pointers and Eigen maps.

Initialization and indexing

raisim::Mat and raisim::Vec store data in column-major order. Their default constructor leaves the elements uninitialized, so set them before use.

raisim::Mat<3,3> A;
A.setZero();
A(0,0) = 1.0;
A(1,1) = 1.0;
A(2,2) = 1.0;

// Eigen-style comma initializer (fills linear storage; column-major)
raisim::Vec<3> x;
x << 1.0, 2.0, 3.0;

For dynamic types, prefer filling through .e():

raisim::VecDyn y(6);
y.e().setOnes();

Const-ref guidance

To avoid copies, pass math objects by const&:

  • Prefer const raisim::Vec<3>& / const raisim::Mat<3,3>& for fixed-size.

  • Prefer const raisim::VecDyn& / const raisim::MatDyn& for dynamic-size.

  • When accepting either RaiSim or Eigen vectors, use Eigen::Ref and pass vec.e() from RaiSim (e.g. const Eigen::Ref<const Eigen::VectorXd>&).

Blocks and helpers

raisim::Mat provides a small Eigen-like API for sub-views:

  • row(i), col(j)

  • segment<rows, cols>(startRow, startCol)

  • vector-only: head<k>() / tail<k>()

  • corners: topLeftCorner<r,c>() / bottomRightCorner<r,c>() etc.

There are also common vector/matrix helpers implemented directly on expressions:

  • sum(), norm(), squaredNorm(), dot(other)

  • scalar ops: *= /= += -=

  • 3D vector helpers: cross(other), skew() (useful for building skew matrices)

Common pitfalls

  • Column-major layout: RaiSim matrices are column-major. When filling from row-major arrays, transpose or fill by columns.

  • Dangling maps/pointers: .e() and ptr() become invalid after resize() (dynamic types) or when the object goes out of scope.

  • Implicit resizing: assigning an Eigen vector, a Vec<n>, or another VecDyn to a VecDyn resizes the destination when the sizes differ. Resizing reallocates, so maps and pointers taken before the assignment become invalid. Element-wise += and -= between VecDyn objects do not check sizes.

  • Expression templates: arithmetic on Mat/Vec (+, -, *, /) builds lazy expressions that reference their operands. Do not store such an expression with auto when it refers to temporaries; assign it to a Mat/Vec instead. A product or transpose that reads its own destination (a = a * b, a = a.transpose()) gives wrong results; use a separate result variable. Element-wise expressions such as a = a + b are safe.