Valkyrie 2026
Loading...
Searching...
No Matches
UnitMatrix.h
1#pragma once
2
3#include <tuple>
4
5#include <units/base.h>
6
7#include "valkyrie/util/eigenunit/Common.h"
8#include "valkyrie/util/eigenunit/UnitVector.h"
9
10namespace valor {
11namespace EigenUnit {
12
22template <typename OutputTagsTuple, typename InputTagsTuple>
24
28template <typename... OutTags, typename... InTags>
29class UnitMatrix<std::tuple<OutTags...>, std::tuple<InTags...>> {
30 public:
32 using StorageType = Eigen::Matrix<double, sizeof...(OutTags), sizeof...(InTags)>;
34 using OutTuple = std::tuple<OutTags...>;
36 using InTuple = std::tuple<InTags...>;
37
38 static constexpr std::size_t RowCount = sizeof...(OutTags);
39 static constexpr std::size_t ColCount = sizeof...(InTags);
40
45
50 constexpr explicit UnitMatrix(const StorageType& d) : data(d) {}
51
56 constexpr explicit UnitMatrix(StorageType&& d) : data(std::move(d)) {}
57
59 constexpr UnitMatrix(const UnitMatrix&) = default;
61 constexpr UnitMatrix(UnitMatrix&&) = default;
63 constexpr UnitMatrix& operator=(const UnitMatrix&) = default;
65 constexpr UnitMatrix& operator=(UnitMatrix&&) = default;
66
71 static constexpr UnitMatrix Zero() { return UnitMatrix{}; }
72
78 static constexpr UnitMatrix Identity()
80 {
81 return UnitMatrix(StorageType::Identity());
82 }
83
90 static UnitMatrix Constant(units::dimensionless::scalar_t val)
92 {
93 return UnitMatrix(StorageType::Constant(val.value()));
94 }
95
102 template <typename... ColVecs>
103 requires(sizeof...(ColVecs) == ColCount) && ColVecsMatchOutput<OutTuple, ColVecs...>
104 static constexpr UnitMatrix FromCols(const ColVecs&... cols) {
105 StorageType d;
106 std::size_t i = 0;
107 ((d.col(i) = cols.Raw(), ++i), ...);
108 return UnitMatrix(std::move(d));
109 }
110
117 template <typename... RowVecs>
118 requires(sizeof...(RowVecs) == RowCount) && RowVecsMatchInput<InTuple, RowVecs...>
119 static constexpr UnitMatrix FromRows(const RowVecs&... rows) {
120 StorageType d;
121 std::size_t i = 0;
122 ((d.row(i) = rows.Raw().transpose(), ++i), ...);
123 return UnitMatrix(std::move(d));
124 }
125
132 template <typename... Args>
133 requires ValidElemArgs<OutTuple, InTuple, Args...>
134 static constexpr UnitMatrix FromElems(Args&&... args) {
135 StorageType d;
136 std::size_t idx = 0;
137 ((d(idx / ColCount, idx % ColCount) = args.value(), ++idx), ...);
138 return UnitMatrix(std::move(d));
139 }
140
141 template <typename OutTuple, typename InTuple, typename... Args>
142 auto MakeMatrix(Args&&... args) {
143 return UnitMatrix<OutTuple, InTuple>::FromElems(std::forward<Args>(args)...);
144 }
145
158 template <typename TL, typename TR, typename BL, typename BR>
159 requires ValidBlockLayout<TL, TR, BL, BR, RowCount, ColCount>
160 static constexpr UnitMatrix FromBlocks(const TL& tl, const TR& tr, const BL& bl, const BR& br) {
161 StorageType d;
162 d.template block<TL::RowCount, TL::ColCount>(0, 0) = tl.Raw();
163 d.template block<TR::RowCount, TR::ColCount>(0, TL::ColCount) = tr.Raw();
164 d.template block<BL::RowCount, BL::ColCount>(TL::RowCount, 0) = bl.Raw();
165 d.template block<BR::RowCount, BR::ColCount>(TL::RowCount, TL::ColCount) = br.Raw();
166 return UnitMatrix(std::move(d));
167 }
168
170 constexpr const StorageType& Raw() const { return data; }
171
173 constexpr StorageType& Raw() { return data; }
174
183 template <std::size_t RowStart, std::size_t ColStart, std::size_t RowN, std::size_t ColN>
184 constexpr auto Block() const {
185 using RawSubOutTuple = typename SliceTuple<RowStart, RowN, OutTuple>::type;
186 using RawSubInTuple = typename SliceTuple<ColStart, ColN, InTuple>::type;
187
189
190 using SubOutTuple = typename Normalized::NormalizedOut;
191 using SubInTuple = typename Normalized::NormalizedIn;
192
193 return UnitMatrix<SubOutTuple, SubInTuple>(data.template block<RowN, ColN>(RowStart, ColStart));
194 }
195
197 template <std::size_t RowN, std::size_t ColN>
198 constexpr auto TopLeft() const {
200 }
201
203 template <std::size_t RowN, std::size_t ColN>
204 constexpr auto TopRight() const {
205 return Block<0, ColCount - ColN, RowN, ColN>();
206 }
207
209 template <std::size_t RowN, std::size_t ColN>
210 constexpr auto BottomLeft() const {
211 return Block<RowCount - RowN, 0, RowN, ColN>();
212 }
213
215 template <std::size_t RowN, std::size_t ColN>
216 constexpr auto BottomRight() const {
217 return Block<RowCount - RowN, ColCount - ColN, RowN, ColN>();
218 }
219
224 auto Trace() const
225 requires SquareMatrix<UnitMatrix>
226 {
227 using T = std::tuple_element_t<0, OutTuple>;
228 return units::unit_t<T>(data.trace());
229 }
230
232 template <typename OtherOut, typename OtherIn>
233 [[nodiscard]]
234 constexpr auto operator+(const UnitMatrix<OtherOut, OtherIn>& other) const
236 {
237 return UnitMatrix<OutTuple, InTuple>(data + other.Raw());
238 }
239
241 template <typename OtherOut, typename OtherIn>
242 [[nodiscard]]
243 constexpr auto operator-(const UnitMatrix<OtherOut, OtherIn>& other) const
245 {
246 return UnitMatrix<OutTuple, InTuple>(data - other.Raw());
247 }
248
254 template <typename... VecTags>
255 [[nodiscard]]
256 constexpr auto operator*(const UnitVector<VecTags...>& vec) const
257 requires UnitEquality<InTuple, std::tuple<VecTags...>>
258 {
259 return UnitVector<OutTags...>(data * vec.Raw());
260 }
261
268 template <typename ScalarTag>
269 [[nodiscard]]
270 constexpr auto operator*(const units::unit_t<ScalarTag>& scalar) const {
271 using NewOutTuple = std::tuple<MultiplyResult<OutTags, ScalarTag>...>;
272 return UnitMatrix<NewOutTuple, InTuple>(data * scalar.value());
273 }
274
281 template <typename ScalarTag>
282 [[nodiscard]]
283 constexpr auto operator/(const units::unit_t<ScalarTag>& scalar) const {
284 using NewOutTuple = std::tuple<DivideResult<OutTags, ScalarTag>...>;
285 return UnitMatrix<NewOutTuple, InTuple>(data / scalar.value());
286 }
287
293 [[nodiscard]]
294 constexpr UnitMatrix operator*(double scalar) const {
295 return UnitMatrix(data * scalar);
296 }
297
303 [[nodiscard]]
304 constexpr UnitMatrix operator/(double scalar) const {
305 return UnitMatrix(data / scalar);
306 }
307
309 template <typename OtherOut, typename OtherIn>
312 {
313 data += other.Raw();
314 return *this;
315 }
316
318 template <typename OtherOut, typename OtherIn>
321 {
322 data -= other.Raw();
323 return *this;
324 }
325
327 template <typename OtherOut, typename OtherIn>
328 constexpr bool operator==(const UnitMatrix<OtherOut, OtherIn>& other) const
330 {
331 return data == other.Raw();
332 }
333
339 template <std::size_t R>
340 requires ValidIndex<R, OutTags...>
341 constexpr auto Row() const {
342 return UnitVector<InTags...>(data.row(R).Transpose());
343 }
344
350 template <std::size_t C>
351 requires ValidIndex<C, InTags...>
352 constexpr auto Col() const {
353 return UnitVector<OutTags...>(data.col(C));
354 }
355
362 template <std::size_t R, std::size_t C>
363 requires ValidIndex<R, OutTags...> && ValidIndex<C, InTags...>
364 auto Get() const {
365 using RowT = std::tuple_element_t<R, OutTuple>;
366 using ColT = std::tuple_element_t<C, InTuple>;
367 using ElemUnit = DivideResult<RowT, ColT>;
368 return units::unit_t<ElemUnit>(data(R, C));
369 }
370
377 template <std::size_t R, std::size_t C>
378 requires ValidIndex<R, OutTags...> && ValidIndex<C, InTags...>
379 void Set(units::unit_t<DivideResult<std::tuple_element_t<R, OutTuple>, std::tuple_element_t<C, InTuple>>> val) {
380 data(R, C) = val.value();
381 }
382
387 [[nodiscard]]
388 auto Inverse() const
389 requires SquareMatrix<UnitMatrix>
390 {
391 return UnitMatrix<InTuple, OutTuple>(data.inverse());
392 }
393
398 [[nodiscard]]
399 constexpr auto Transpose() const {
400 return UnitMatrix<InTuple, OutTuple>(data.transpose());
401 }
402
409 auto Eigenvalues() const
411 {
412 return data.eigenvalues();
413 }
414
423 template <typename... VecTags>
424 [[nodiscard]]
425 auto Solve(const UnitVector<VecTags...>& b) const
426 requires SquareMatrix<UnitMatrix> && UnitEquality<OutTuple, std::tuple<VecTags...>>
427 {
428 return UnitVector<InTags...>(data.partialPivLu().solve(b.Raw()));
429 }
430
439 template <typename... B_InTags>
440 [[nodiscard]]
441 auto Solve(const UnitMatrix<OutTuple, std::tuple<B_InTags...>>& B) const
443 {
444 return UnitMatrix<InTuple, std::tuple<B_InTags...>>(data.partialPivLu().solve(B.Raw()));
445 }
446
454 template <typename... VecTags>
455 [[nodiscard]]
456 auto SolveQR(const UnitVector<VecTags...>& b) const
457 requires UnitEquality<OutTuple, std::tuple<VecTags...>>
458 {
459 return UnitVector<InTags...>(data.colPivHouseholderQr().solve(b.Raw()));
460 }
461
468 template <typename... B_InTags>
469 [[nodiscard]]
470 auto SolveQR(const UnitMatrix<OutTuple, std::tuple<B_InTags...>>& B) const
472 {
473 return UnitMatrix<InTuple, std::tuple<B_InTags...>>(data.colPivHouseholderQr().solve(B.Raw()));
474 }
475
483 template <typename... OtherOutTags, typename... OtherInTags>
484 requires((sizeof...(OtherOutTags) == RowCount) && (sizeof...(OtherInTags) == ColCount))
485 [[nodiscard]]
486 constexpr auto CWiseProduct(const UnitMatrix<std::tuple<OtherOutTags...>, std::tuple<OtherInTags...>>& other) const {
487 using ResultOut = std::tuple<MultiplyResult<OutTags, OtherOutTags>...>;
488 using ResultIn = std::tuple<MultiplyResult<InTags, OtherInTags>...>;
489 return UnitMatrix<ResultOut, ResultIn>(data.cwiseProduct(other.Raw()));
490 }
491
498 bool IsApprox(const UnitMatrix& other, double tol) const
500 {
501 return data.isApprox(other.Raw(), tol);
502 }
503
510 bool IsApprox(const UnitMatrix& other, units::dimensionless::scalar_t tol = units::dimensionless::scalar_t{1e-9}) const
512 {
513 return data.IsApprox(other.Raw(), tol.value());
514 }
515
522 friend std::ostream& operator<<(std::ostream& os, const UnitMatrix& mat) {
523 os << "UnitMatrix (\n";
524 mat.print_all_rows(os, std::make_index_sequence<RowCount>{});
525 os << ")";
526 return os;
527 }
528
529 private:
530 template <std::size_t... Rows>
531 void print_all_rows(std::ostream& os, std::index_sequence<Rows...>) const {
532 ((os << " [", print_row<Rows>(os, std::make_index_sequence<ColCount>{}), os << "]\n"), ...);
533 }
534
535 template <std::size_t Row, std::size_t... Cols>
536 void print_row(std::ostream& os, std::index_sequence<Cols...>) const {
537 ((os << units::unit_t<DivideResult<std::tuple_element_t<Row, OutTuple>, std::tuple_element_t<Cols, InTuple>>>(data(Row, Cols))
538 << (Cols == ColCount - 1 ? "" : ", ")),
539 ...);
540 }
541
542 StorageType data;
543};
544
555template <typename... OutA, typename... InA, typename... OutB, typename... InB>
556[[nodiscard]]
557constexpr auto operator*(const UnitMatrix<std::tuple<OutA...>, std::tuple<InA...>>& A,
558 const UnitMatrix<std::tuple<OutB...>, std::tuple<InB...>>& B)
559 requires UnitEquality<std::tuple<InA...>, std::tuple<OutB...>>
560{
561 return UnitMatrix<std::tuple<OutA...>, std::tuple<InB...>>(A.Raw() * B.Raw());
562}
563
569template <typename... OutTags, typename... InTags, typename... VecTags>
570[[nodiscard]]
571constexpr auto operator*(const UnitMatrix<std::tuple<OutTags...>, std::tuple<InTags...>>& mat, const UnitVector<VecTags...>& vec)
572 requires std::is_same_v<std::tuple<OutTags...>, typename ScalarTuple_Builder<sizeof...(OutTags)>::type> &&
573 std::is_same_v<std::tuple<InTags...>, typename ScalarTuple_Builder<sizeof...(InTags)>::type> &&
574 (sizeof...(InTags) == sizeof...(VecTags))
575{
576 return UnitVector<VecTags...>(mat.Raw() * vec.Raw());
577}
578
579template <typename ScalarTag, typename OutTuple, typename InTuple>
580[[nodiscard]]
581constexpr auto operator*(const units::unit_t<ScalarTag>& scalar, const UnitMatrix<OutTuple, InTuple>& mat) {
582 return mat * scalar;
583}
584
585template <typename OutTuple, typename InTuple>
586[[nodiscard]]
587constexpr auto operator*(double scalar, const UnitMatrix<OutTuple, InTuple>& mat) {
588 return mat * scalar;
589}
590
596template <typename VecOut, typename VecIn>
598
599template <typename Derived, typename Base>
600struct NamedPhysicalMatrix : Base {
601 using Base::Base;
602
603 NamedPhysicalMatrix(const Base& base) : Base(base.Raw()) {}
604
605 Derived Inverse() const { return Derived(Base::Inverse()); }
606
607 template <std::size_t RowStart, std::size_t ColStart, std::size_t RowN, std::size_t ColN>
608 auto Block() const {
609 return Base::template Block<RowStart, ColStart, RowN, ColN>();
610 }
611};
612
613// Implementation of UnitVector::asDiagonal()
614template <typename... UnitTags>
616 using Dimensionless = units::dimensionless::scalar_t;
617 using DimensionlessTuple = typename detail::VectorN_Builder<Dimensionless, std::make_index_sequence<Size>>::type::UnitTuple;
618 return UnitMatrix<UnitTuple, DimensionlessTuple>(data.asDiagonal());
619}
620
621} // namespace EigenUnit
622} // namespace valor
auto SolveQR(const UnitVector< VecTags... > &b) const
Solves the system Ax = b using QR decomposition. Useful for non-square matrices (Least Squares) or hi...
Definition UnitMatrix.h:456
constexpr auto Transpose() const
Transpose the matrix. Maps OutTags -> InTags.
Definition UnitMatrix.h:399
void Set(units::unit_t< DivideResult< std::tuple_element_t< R, OutTuple >, std::tuple_element_t< C, InTuple > > > val)
Set a single element value.
Definition UnitMatrix.h:379
Eigen::Matrix< double, sizeof...(OutTags), sizeof...(InTags)> StorageType
The underlying Eigen storage type.
Definition UnitMatrix.h:32
constexpr UnitMatrix operator/(double scalar) const
Raw scaling (division by double).
Definition UnitMatrix.h:304
static constexpr UnitMatrix FromElems(Args &&... args)
Construct a matrix from a flat list of elements in row-major order.
Definition UnitMatrix.h:134
constexpr auto BottomLeft() const
Extract the bottom-left block.
Definition UnitMatrix.h:210
auto Solve(const UnitVector< VecTags... > &b) const
Solves the linear system Ax = b. Deduces that if b has the output units of this matrix,...
Definition UnitMatrix.h:425
std::tuple< InTags... > InTuple
A tuple of input unit tags.
Definition UnitMatrix.h:36
constexpr const StorageType & Raw() const
Get a constant reference to the underlying raw Eigen data.
Definition UnitMatrix.h:170
constexpr auto operator-(const UnitMatrix< OtherOut, OtherIn > &other) const
Matrix subtraction.
Definition UnitMatrix.h:243
constexpr UnitMatrix & operator=(const UnitMatrix &)=default
Copy assignment.
friend std::ostream & operator<<(std::ostream &os, const UnitMatrix &mat)
Debug printing support.
Definition UnitMatrix.h:522
constexpr StorageType & Raw()
Get a reference to the underlying raw Eigen data.
Definition UnitMatrix.h:173
static constexpr UnitMatrix Zero()
Create a zero-initialized matrix.
Definition UnitMatrix.h:71
constexpr auto Block() const
Extract a sub-matrix as a new UnitMatrix.
Definition UnitMatrix.h:184
constexpr auto TopLeft() const
Extract the top-left block.
Definition UnitMatrix.h:198
constexpr UnitMatrix(const UnitMatrix &)=default
Copy constructor.
auto Inverse() const
Invert the matrix. Maps OutTags -> InTags.
Definition UnitMatrix.h:388
constexpr auto Row() const
Extract a single row as a UnitVector.
Definition UnitMatrix.h:341
constexpr auto operator/(const units::unit_t< ScalarTag > &scalar) const
Scalar division. Resulting matrix maps to scaled output units.
Definition UnitMatrix.h:283
constexpr auto operator*(const UnitVector< VecTags... > &vec) const
Multiplies the matrix by a compatible UnitVector.
Definition UnitMatrix.h:256
static constexpr UnitMatrix FromCols(const ColVecs &... cols)
Construct a matrix from a list of column vectors.
Definition UnitMatrix.h:104
constexpr auto CWiseProduct(const UnitMatrix< std::tuple< OtherOutTags... >, std::tuple< OtherInTags... > > &other) const
Component-wise product with another UnitMatrix.
Definition UnitMatrix.h:486
constexpr auto Col() const
Extract a single column as a UnitVector.
Definition UnitMatrix.h:352
constexpr UnitMatrix & operator+=(const UnitMatrix< OtherOut, OtherIn > &other)
In-place matrix addition.
Definition UnitMatrix.h:310
constexpr UnitMatrix & operator-=(const UnitMatrix< OtherOut, OtherIn > &other)
In-place matrix subtraction.
Definition UnitMatrix.h:319
constexpr UnitMatrix operator*(double scalar) const
Raw scaling (multiplication by double).
Definition UnitMatrix.h:294
constexpr bool operator==(const UnitMatrix< OtherOut, OtherIn > &other) const
Equality operator.
Definition UnitMatrix.h:328
auto Get() const
Extract a single element with its derived unit (OutUnit / InUnit).
Definition UnitMatrix.h:364
static UnitMatrix Constant(units::dimensionless::scalar_t val)
Create a matrix where all elements are set to a constant value. Only valid for square matrices.
Definition UnitMatrix.h:90
constexpr auto operator+(const UnitMatrix< OtherOut, OtherIn > &other) const
Matrix addition.
Definition UnitMatrix.h:234
static constexpr UnitMatrix Identity()
Create an identity matrix. Only valid if input and output units match exactly.
Definition UnitMatrix.h:78
auto SolveQR(const UnitMatrix< OutTuple, std::tuple< B_InTags... > > &B) const
Solves the system AX = B using QR decomposition.
Definition UnitMatrix.h:470
bool IsApprox(const UnitMatrix &other, double tol) const
Check if two matrices are approximately equal.
Definition UnitMatrix.h:498
constexpr auto operator*(const units::unit_t< ScalarTag > &scalar) const
Scalar multiplication. Resulting matrix maps to scaled output units.
Definition UnitMatrix.h:270
constexpr auto TopRight() const
Extract the top-right block.
Definition UnitMatrix.h:204
constexpr UnitMatrix(const StorageType &d)
Construct from a raw Eigen matrix.
Definition UnitMatrix.h:50
auto Trace() const
Computes the trace (sum of diagonals). Only valid for square matrices.
Definition UnitMatrix.h:224
constexpr UnitMatrix(StorageType &&d)
Construct from a raw Eigen matrix (move).
Definition UnitMatrix.h:56
static constexpr UnitMatrix FromBlocks(const TL &tl, const TR &tr, const BL &bl, const BR &br)
Construct a matrix by combining four blocks.
Definition UnitMatrix.h:160
auto Eigenvalues() const
Get eigenvalues. Only supported for square matrices where InTags == OutTags. Eigenvalues are dimensio...
Definition UnitMatrix.h:409
constexpr UnitMatrix & operator=(UnitMatrix &&)=default
Move assignment.
bool IsApprox(const UnitMatrix &other, units::dimensionless::scalar_t tol=units::dimensionless::scalar_t{1e-9}) const
Check if two matrices are approximately equal.
Definition UnitMatrix.h:510
auto Solve(const UnitMatrix< OutTuple, std::tuple< B_InTags... > > &B) const
Solves the linear system AX = B (Matrix-Matrix solve). If A: In -> Out and B: OtherIn -> Out,...
Definition UnitMatrix.h:441
constexpr UnitMatrix()
Default constructor. Initializes all elements to zero.
Definition UnitMatrix.h:44
static constexpr UnitMatrix FromRows(const RowVecs &... rows)
Construct a matrix from a list of row vectors.
Definition UnitMatrix.h:119
std::tuple< OutTags... > OutTuple
A tuple of output unit tags.
Definition UnitMatrix.h:34
constexpr auto BottomRight() const
Extract the bottom-right block.
Definition UnitMatrix.h:216
A matrix wrapper representing a linear map between two UnitVectors.
Definition UnitMatrix.h:23
A vector wrapper that enforces units for each element.
Definition UnitVector.h:22
auto AsDiagonal() const
Converts the vector to a diagonal matrix.
Definition UnitMatrix.h:615
Checks that a pack of column vectors all match the output tuple.
Definition Common.h:275
Concept verifying that a UnitMatrix is square AND has matching units for rows and columns.
Definition Common.h:237
Checks that a pack of row vectors all match the input tuple.
Definition Common.h:281
Concept verifying that a UnitMatrix is square.
Definition Common.h:228
Concept verifying that two tuple-based unit types match exactly.
Definition Common.h:216
Concept verifying that a pack of arguments matches the required units for a UnitMatrix.
Definition Common.h:315
Concept verifying that index N is within the bounds of a pack.
Definition Common.h:192
Template specializations for std::tuple_size and std::tuple_element to support UnitVector.
Definition Formatters.h:8
typename impl< std::make_index_sequence< Length > >::type type
The resulting sliced tuple type.
Definition Common.h:45
Builder for N-dimensional UnitVectors with uniform units.
Definition Common.h:126