Valkyrie 2026
Loading...
Searching...
No Matches
UnitMatrix.h
1#pragma once
2
3#include <tuple>
4
5#include <units/base.h>
6#include <valkyrie/util/eigenunit/Common.h>
7#include <valkyrie/util/eigenunit/UnitVector.h>
8
9namespace valor {
10namespace EigenUnit {
11
21template <typename OutputTagsTuple, typename InputTagsTuple>
23
27template <typename... OutTags, typename... InTags>
28class UnitMatrix<std::tuple<OutTags...>, std::tuple<InTags...>> {
29 public:
31 using StorageType = Eigen::Matrix<double, sizeof...(OutTags), sizeof...(InTags)>;
33 using OutTuple = std::tuple<OutTags...>;
35 using InTuple = std::tuple<InTags...>;
36
37 static constexpr std::size_t RowCount = sizeof...(OutTags);
38 static constexpr std::size_t ColCount = sizeof...(InTags);
39
44
49 constexpr explicit UnitMatrix(const StorageType& d) : data(d) {}
50
55 constexpr explicit UnitMatrix(StorageType&& d) : data(std::move(d)) {}
56
58 constexpr UnitMatrix(const UnitMatrix&) = default;
60 constexpr UnitMatrix(UnitMatrix&&) = default;
62 constexpr UnitMatrix& operator=(const UnitMatrix&) = default;
64 constexpr UnitMatrix& operator=(UnitMatrix&&) = default;
65
70 static constexpr UnitMatrix Zero() { return UnitMatrix{}; }
71
77 static constexpr UnitMatrix Identity()
79 {
80 return UnitMatrix(StorageType::Identity());
81 }
82
89 static UnitMatrix Constant(units::dimensionless::scalar_t val)
91 {
92 return UnitMatrix(StorageType::Constant(val.value()));
93 }
94
101 template <typename... ColVecs>
102 requires(sizeof...(ColVecs) == ColCount) && ColVecsMatchOutput<OutTuple, ColVecs...>
103 static constexpr UnitMatrix FromCols(const ColVecs&... cols) {
104 StorageType d;
105 std::size_t i = 0;
106 ((d.col(i) = cols.Raw(), ++i), ...);
107 return UnitMatrix(std::move(d));
108 }
109
116 template <typename... RowVecs>
117 requires(sizeof...(RowVecs) == RowCount) && RowVecsMatchInput<InTuple, RowVecs...>
118 static constexpr UnitMatrix FromRows(const RowVecs&... rows) {
119 StorageType d;
120 std::size_t i = 0;
121 ((d.row(i) = rows.Raw().transpose(), ++i), ...);
122 return UnitMatrix(std::move(d));
123 }
124
131 template <typename... Args>
132 requires ValidElemArgs<OutTuple, InTuple, Args...>
133 static constexpr UnitMatrix FromElems(Args&&... args) {
134 StorageType d;
135 std::size_t idx = 0;
136 ((d(idx / ColCount, idx % ColCount) = args.value(), ++idx), ...);
137 return UnitMatrix(std::move(d));
138 }
139
140 template <typename OutTuple, typename InTuple, typename... Args>
141 auto MakeMatrix(Args&&... args) {
142 return UnitMatrix<OutTuple, InTuple>::FromElems(std::forward<Args>(args)...);
143 }
144
157 template <typename TL, typename TR, typename BL, typename BR>
158 requires ValidBlockLayout<TL, TR, BL, BR, RowCount, ColCount>
159 static constexpr UnitMatrix FromBlocks(const TL& tl, const TR& tr, const BL& bl, const BR& br) {
160 StorageType d;
161 d.template block<TL::RowCount, TL::ColCount>(0, 0) = tl.Raw();
162 d.template block<TR::RowCount, TR::ColCount>(0, TL::ColCount) = tr.Raw();
163 d.template block<BL::RowCount, BL::ColCount>(TL::RowCount, 0) = bl.Raw();
164 d.template block<BR::RowCount, BR::ColCount>(TL::RowCount, TL::ColCount) = br.Raw();
165 return UnitMatrix(std::move(d));
166 }
167
169 constexpr const StorageType& Raw() const { return data; }
170
172 constexpr StorageType& Raw() { return data; }
173
182 template <std::size_t RowStart, std::size_t ColStart, std::size_t RowN, std::size_t ColN>
183 constexpr auto Block() const {
184 using RawSubOutTuple = typename SliceTuple<RowStart, RowN, OutTuple>::type;
185 using RawSubInTuple = typename SliceTuple<ColStart, ColN, InTuple>::type;
186
188
189 using SubOutTuple = typename Normalized::NormalizedOut;
190 using SubInTuple = typename Normalized::NormalizedIn;
191
192 return UnitMatrix<SubOutTuple, SubInTuple>(data.template block<RowN, ColN>(RowStart, ColStart));
193 }
194
196 template <std::size_t RowN, std::size_t ColN>
197 constexpr auto TopLeft() const {
199 }
200
202 template <std::size_t RowN, std::size_t ColN>
203 constexpr auto TopRight() const {
204 return Block<0, ColCount - ColN, RowN, ColN>();
205 }
206
208 template <std::size_t RowN, std::size_t ColN>
209 constexpr auto BottomLeft() const {
210 return Block<RowCount - RowN, 0, RowN, ColN>();
211 }
212
214 template <std::size_t RowN, std::size_t ColN>
215 constexpr auto BottomRight() const {
216 return Block<RowCount - RowN, ColCount - ColN, RowN, ColN>();
217 }
218
223 auto Trace() const
224 requires SquareMatrix<UnitMatrix>
225 {
226 using T = std::tuple_element_t<0, OutTuple>;
227 return units::unit_t<T>(data.trace());
228 }
229
231 template <typename OtherOut, typename OtherIn>
232 [[nodiscard]]
233 constexpr auto operator+(const UnitMatrix<OtherOut, OtherIn>& other) const
235 {
236 return UnitMatrix<OutTuple, InTuple>(data + other.Raw());
237 }
238
240 template <typename OtherOut, typename OtherIn>
241 [[nodiscard]]
242 constexpr auto operator-(const UnitMatrix<OtherOut, OtherIn>& other) const
244 {
245 return UnitMatrix<OutTuple, InTuple>(data - other.Raw());
246 }
247
253 template <typename... VecTags>
254 [[nodiscard]]
255 constexpr auto operator*(const UnitVector<VecTags...>& vec) const
256 requires UnitEquality<InTuple, std::tuple<VecTags...>>
257 {
258 return UnitVector<OutTags...>(data * vec.Raw());
259 }
260
267 template <typename ScalarTag>
268 [[nodiscard]]
269 constexpr auto operator*(const units::unit_t<ScalarTag>& scalar) const {
270 using NewOutTuple = std::tuple<MultiplyResult<OutTags, ScalarTag>...>;
271 return UnitMatrix<NewOutTuple, InTuple>(data * scalar.value());
272 }
273
280 template <typename ScalarTag>
281 [[nodiscard]]
282 constexpr auto operator/(const units::unit_t<ScalarTag>& scalar) const {
283 using NewOutTuple = std::tuple<DivideResult<OutTags, ScalarTag>...>;
284 return UnitMatrix<NewOutTuple, InTuple>(data / scalar.value());
285 }
286
292 [[nodiscard]]
293 constexpr UnitMatrix operator*(double scalar) const {
294 return UnitMatrix(data * scalar);
295 }
296
302 [[nodiscard]]
303 constexpr UnitMatrix operator/(double scalar) const {
304 return UnitMatrix(data / scalar);
305 }
306
308 template <typename OtherOut, typename OtherIn>
311 {
312 data += other.Raw();
313 return *this;
314 }
315
317 template <typename OtherOut, typename OtherIn>
320 {
321 data -= other.Raw();
322 return *this;
323 }
324
326 template <typename OtherOut, typename OtherIn>
327 constexpr bool operator==(const UnitMatrix<OtherOut, OtherIn>& other) const
329 {
330 return data == other.Raw();
331 }
332
338 template <std::size_t R>
339 requires ValidIndex<R, OutTags...>
340 constexpr auto Row() const {
341 return UnitVector<InTags...>(data.row(R).Transpose());
342 }
343
349 template <std::size_t C>
350 requires ValidIndex<C, InTags...>
351 constexpr auto Col() const {
352 return UnitVector<OutTags...>(data.col(C));
353 }
354
361 template <std::size_t R, std::size_t C>
362 requires ValidIndex<R, OutTags...> && ValidIndex<C, InTags...>
363 auto Get() const {
364 using RowT = std::tuple_element_t<R, OutTuple>;
365 using ColT = std::tuple_element_t<C, InTuple>;
366 using ElemUnit = DivideResult<RowT, ColT>;
367 return units::unit_t<ElemUnit>(data(R, C));
368 }
369
376 template <std::size_t R, std::size_t C>
377 requires ValidIndex<R, OutTags...> && ValidIndex<C, InTags...>
378 void Set(units::unit_t<DivideResult<std::tuple_element_t<R, OutTuple>, std::tuple_element_t<C, InTuple>>> val) {
379 data(R, C) = val.value();
380 }
381
386 [[nodiscard]]
387 auto Inverse() const
388 requires SquareMatrix<UnitMatrix>
389 {
390 return UnitMatrix<InTuple, OutTuple>(data.inverse());
391 }
392
397 [[nodiscard]]
398 constexpr auto Transpose() const {
399 return UnitMatrix<InTuple, OutTuple>(data.transpose());
400 }
401
408 auto Eigenvalues() const
410 {
411 return data.eigenvalues();
412 }
413
422 template <typename... VecTags>
423 [[nodiscard]]
424 auto Solve(const UnitVector<VecTags...>& b) const
425 requires SquareMatrix<UnitMatrix> && UnitEquality<OutTuple, std::tuple<VecTags...>>
426 {
427 return UnitVector<InTags...>(data.partialPivLu().solve(b.Raw()));
428 }
429
438 template <typename... B_InTags>
439 [[nodiscard]]
440 auto Solve(const UnitMatrix<OutTuple, std::tuple<B_InTags...>>& B) const
442 {
443 return UnitMatrix<InTuple, std::tuple<B_InTags...>>(data.partialPivLu().solve(B.Raw()));
444 }
445
453 template <typename... VecTags>
454 [[nodiscard]]
455 auto SolveQR(const UnitVector<VecTags...>& b) const
456 requires UnitEquality<OutTuple, std::tuple<VecTags...>>
457 {
458 return UnitVector<InTags...>(data.colPivHouseholderQr().solve(b.Raw()));
459 }
460
467 template <typename... B_InTags>
468 [[nodiscard]]
469 auto SolveQR(const UnitMatrix<OutTuple, std::tuple<B_InTags...>>& B) const
471 {
472 return UnitMatrix<InTuple, std::tuple<B_InTags...>>(data.colPivHouseholderQr().solve(B.Raw()));
473 }
474
482 template <typename... OtherOutTags, typename... OtherInTags>
483 requires((sizeof...(OtherOutTags) == RowCount) && (sizeof...(OtherInTags) == ColCount))
484 [[nodiscard]]
485 constexpr auto CWiseProduct(const UnitMatrix<std::tuple<OtherOutTags...>, std::tuple<OtherInTags...>>& other) const {
486 using ResultOut = std::tuple<MultiplyResult<OutTags, OtherOutTags>...>;
487 using ResultIn = std::tuple<MultiplyResult<InTags, OtherInTags>...>;
488 return UnitMatrix<ResultOut, ResultIn>(data.cwiseProduct(other.Raw()));
489 }
490
497 bool IsApprox(const UnitMatrix& other, double tol) const
499 {
500 return data.isApprox(other.Raw(), tol);
501 }
502
509 bool IsApprox(const UnitMatrix& other, units::dimensionless::scalar_t tol = units::dimensionless::scalar_t{1e-9}) const
511 {
512 return data.IsApprox(other.Raw(), tol.value());
513 }
514
521 friend std::ostream& operator<<(std::ostream& os, const UnitMatrix& mat) {
522 os << "UnitMatrix (\n";
523 mat.print_all_rows(os, std::make_index_sequence<RowCount>{});
524 os << ")";
525 return os;
526 }
527
528 private:
529 template <std::size_t... Rows>
530 void print_all_rows(std::ostream& os, std::index_sequence<Rows...>) const {
531 ((os << " [", print_row<Rows>(os, std::make_index_sequence<ColCount>{}), os << "]\n"), ...);
532 }
533
534 template <std::size_t Row, std::size_t... Cols>
535 void print_row(std::ostream& os, std::index_sequence<Cols...>) const {
536 ((os << units::unit_t<DivideResult<std::tuple_element_t<Row, OutTuple>, std::tuple_element_t<Cols, InTuple>>>(data(Row, Cols))
537 << (Cols == ColCount - 1 ? "" : ", ")),
538 ...);
539 }
540
541 StorageType data;
542};
543
554template <typename... OutA, typename... InA, typename... OutB, typename... InB>
555[[nodiscard]]
556constexpr auto operator*(const UnitMatrix<std::tuple<OutA...>, std::tuple<InA...>>& A,
557 const UnitMatrix<std::tuple<OutB...>, std::tuple<InB...>>& B)
558 requires UnitEquality<std::tuple<InA...>, std::tuple<OutB...>>
559{
560 return UnitMatrix<std::tuple<OutA...>, std::tuple<InB...>>(A.Raw() * B.Raw());
561}
562
568template <typename... OutTags, typename... InTags, typename... VecTags>
569[[nodiscard]]
570constexpr auto operator*(const UnitMatrix<std::tuple<OutTags...>, std::tuple<InTags...>>& mat, const UnitVector<VecTags...>& vec)
571 requires std::is_same_v<std::tuple<OutTags...>, typename ScalarTuple_Builder<sizeof...(OutTags)>::type> &&
572 std::is_same_v<std::tuple<InTags...>, typename ScalarTuple_Builder<sizeof...(InTags)>::type> &&
573 (sizeof...(InTags) == sizeof...(VecTags))
574{
575 return UnitVector<VecTags...>(mat.Raw() * vec.Raw());
576}
577
578template <typename ScalarTag, typename OutTuple, typename InTuple>
579[[nodiscard]]
580constexpr auto operator*(const units::unit_t<ScalarTag>& scalar, const UnitMatrix<OutTuple, InTuple>& mat) {
581 return mat * scalar;
582}
583
584template <typename OutTuple, typename InTuple>
585[[nodiscard]]
586constexpr auto operator*(double scalar, const UnitMatrix<OutTuple, InTuple>& mat) {
587 return mat * scalar;
588}
589
595template <typename VecOut, typename VecIn>
597
598template <typename Derived, typename Base>
599struct NamedPhysicalMatrix : Base {
600 using Base::Base;
601
602 NamedPhysicalMatrix(const Base& base) : Base(base.Raw()) {}
603
604 Derived Inverse() const { return Derived(Base::Inverse()); }
605
606 template <std::size_t RowStart, std::size_t ColStart, std::size_t RowN, std::size_t ColN>
607 auto Block() const {
608 return Base::template Block<RowStart, ColStart, RowN, ColN>();
609 }
610};
611
612// Implementation of UnitVector::asDiagonal()
613template <typename... UnitTags>
615 using Dimensionless = units::dimensionless::scalar_t;
616 using DimensionlessTuple = typename detail::VectorN_Builder<Dimensionless, std::make_index_sequence<Size>>::type::UnitTuple;
617 return UnitMatrix<UnitTuple, DimensionlessTuple>(data.asDiagonal());
618}
619
620} // namespace EigenUnit
621} // 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:455
constexpr auto Transpose() const
Transpose the matrix. Maps OutTags -> InTags.
Definition UnitMatrix.h:398
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:378
Eigen::Matrix< double, sizeof...(OutTags), sizeof...(InTags)> StorageType
The underlying Eigen storage type.
Definition UnitMatrix.h:31
constexpr UnitMatrix operator/(double scalar) const
Raw scaling (division by double).
Definition UnitMatrix.h:303
static constexpr UnitMatrix FromElems(Args &&... args)
Construct a matrix from a flat list of elements in row-major order.
Definition UnitMatrix.h:133
constexpr auto BottomLeft() const
Extract the bottom-left block.
Definition UnitMatrix.h:209
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:424
std::tuple< InTags... > InTuple
A tuple of input unit tags.
Definition UnitMatrix.h:35
constexpr const StorageType & Raw() const
Get a constant reference to the underlying raw Eigen data.
Definition UnitMatrix.h:169
constexpr auto operator-(const UnitMatrix< OtherOut, OtherIn > &other) const
Matrix subtraction.
Definition UnitMatrix.h:242
constexpr UnitMatrix & operator=(const UnitMatrix &)=default
Copy assignment.
friend std::ostream & operator<<(std::ostream &os, const UnitMatrix &mat)
Debug printing support.
Definition UnitMatrix.h:521
constexpr StorageType & Raw()
Get a reference to the underlying raw Eigen data.
Definition UnitMatrix.h:172
static constexpr UnitMatrix Zero()
Create a zero-initialized matrix.
Definition UnitMatrix.h:70
constexpr auto Block() const
Extract a sub-matrix as a new UnitMatrix.
Definition UnitMatrix.h:183
constexpr auto TopLeft() const
Extract the top-left block.
Definition UnitMatrix.h:197
constexpr UnitMatrix(const UnitMatrix &)=default
Copy constructor.
auto Inverse() const
Invert the matrix. Maps OutTags -> InTags.
Definition UnitMatrix.h:387
constexpr auto Row() const
Extract a single row as a UnitVector.
Definition UnitMatrix.h:340
constexpr auto operator/(const units::unit_t< ScalarTag > &scalar) const
Scalar division. Resulting matrix maps to scaled output units.
Definition UnitMatrix.h:282
constexpr auto operator*(const UnitVector< VecTags... > &vec) const
Multiplies the matrix by a compatible UnitVector.
Definition UnitMatrix.h:255
static constexpr UnitMatrix FromCols(const ColVecs &... cols)
Construct a matrix from a list of column vectors.
Definition UnitMatrix.h:103
constexpr auto CWiseProduct(const UnitMatrix< std::tuple< OtherOutTags... >, std::tuple< OtherInTags... > > &other) const
Component-wise product with another UnitMatrix.
Definition UnitMatrix.h:485
constexpr auto Col() const
Extract a single column as a UnitVector.
Definition UnitMatrix.h:351
constexpr UnitMatrix & operator+=(const UnitMatrix< OtherOut, OtherIn > &other)
In-place matrix addition.
Definition UnitMatrix.h:309
constexpr UnitMatrix & operator-=(const UnitMatrix< OtherOut, OtherIn > &other)
In-place matrix subtraction.
Definition UnitMatrix.h:318
constexpr UnitMatrix operator*(double scalar) const
Raw scaling (multiplication by double).
Definition UnitMatrix.h:293
constexpr bool operator==(const UnitMatrix< OtherOut, OtherIn > &other) const
Equality operator.
Definition UnitMatrix.h:327
auto Get() const
Extract a single element with its derived unit (OutUnit / InUnit).
Definition UnitMatrix.h:363
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:89
constexpr auto operator+(const UnitMatrix< OtherOut, OtherIn > &other) const
Matrix addition.
Definition UnitMatrix.h:233
static constexpr UnitMatrix Identity()
Create an identity matrix. Only valid if input and output units match exactly.
Definition UnitMatrix.h:77
auto SolveQR(const UnitMatrix< OutTuple, std::tuple< B_InTags... > > &B) const
Solves the system AX = B using QR decomposition.
Definition UnitMatrix.h:469
bool IsApprox(const UnitMatrix &other, double tol) const
Check if two matrices are approximately equal.
Definition UnitMatrix.h:497
constexpr auto operator*(const units::unit_t< ScalarTag > &scalar) const
Scalar multiplication. Resulting matrix maps to scaled output units.
Definition UnitMatrix.h:269
constexpr auto TopRight() const
Extract the top-right block.
Definition UnitMatrix.h:203
constexpr UnitMatrix(const StorageType &d)
Construct from a raw Eigen matrix.
Definition UnitMatrix.h:49
auto Trace() const
Computes the trace (sum of diagonals). Only valid for square matrices.
Definition UnitMatrix.h:223
constexpr UnitMatrix(StorageType &&d)
Construct from a raw Eigen matrix (move).
Definition UnitMatrix.h:55
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:159
auto Eigenvalues() const
Get eigenvalues. Only supported for square matrices where InTags == OutTags. Eigenvalues are dimensio...
Definition UnitMatrix.h:408
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:509
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:440
constexpr UnitMatrix()
Default constructor. Initializes all elements to zero.
Definition UnitMatrix.h:43
static constexpr UnitMatrix FromRows(const RowVecs &... rows)
Construct a matrix from a list of row vectors.
Definition UnitMatrix.h:118
std::tuple< OutTags... > OutTuple
A tuple of output unit tags.
Definition UnitMatrix.h:33
constexpr auto BottomRight() const
Extract the bottom-right block.
Definition UnitMatrix.h:215
A matrix wrapper representing a linear map between two UnitVectors.
Definition UnitMatrix.h:22
A vector wrapper that enforces units for each element.
Definition UnitVector.h:21
auto AsDiagonal() const
Converts the vector to a diagonal matrix.
Definition UnitMatrix.h:614
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