VTK  9.3.20240726
vtkMatrixUtilities.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
2// SPDX-License-Identifier: BSD-3-Clause
15#ifndef vtkMatrixUtilities_h
16#define vtkMatrixUtilities_h
17
18#include "vtkABINamespace.h"
19
20#include <type_traits> // for type traits
21#include <utility> // for std::forward
22
24{
25VTK_ABI_NAMESPACE_BEGIN
26//=============================================================================
31struct Layout
32{
36 struct Identity;
37 /*
38 * Input matrix is transposed, i.e. sorted in column-wise ordered.
39 */
40 struct Transpose;
41
46 struct Diag;
47};
48
49namespace detail
50{
51// Extracting for STL-like containers
52template <int ContainerTypeT, class ContainerT>
54{
55 typedef typename std::decay<typename std::decay<ContainerT>::type::value_type>::type value_type;
56 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
57 "value_type is not a numeric type");
58};
59
60// Extracting for C++ arrays
61template <class ContainerT>
62struct ScalarTypeExtractor<1, ContainerT>
63{
64private:
65 typedef typename std::remove_reference<ContainerT>::type DerefContainer;
66
67public:
68 typedef typename std::decay<typename std::remove_pointer<typename std::remove_all_extents<
69 typename std::remove_pointer<DerefContainer>::type>::type>::type>::type value_type;
70
71 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
72 "value_type is not a numeric type");
73};
74
75//=============================================================================
76template <class MatrixT, int Depth = 0>
78{
79 static constexpr int Value = Depth;
80};
81
82//=============================================================================
83template <class MatrixT, int Depth>
84struct ArrayOrPointerDepth<MatrixT[], Depth>
85{
87};
88
89//=============================================================================
90template <class MatrixT, int N, int Depth>
91struct ArrayOrPointerDepth<MatrixT[N], Depth>
92{
94};
95
96//=============================================================================
97template <class MatrixT, int Depth>
98struct ArrayOrPointerDepth<MatrixT*, Depth>
99{
101};
102
103//=============================================================================
104template <class MatrixT, int Depth>
105struct ArrayOrPointerDepth<MatrixT&, Depth>
106{
107 static constexpr int Value = ArrayOrPointerDepth<MatrixT, Depth>::Value;
108};
109} // namespace detail
110
111//-----------------------------------------------------------------------------
116template <class MatrixT>
117static constexpr bool MatrixIs2DArray()
118{
120}
121
122namespace detail
123{
124//=============================================================================
125template <class MatrixT, class = void>
127
128//=============================================================================
129template <class MatrixT>
130struct ExtractRawComponentType<MatrixT, typename std::enable_if<MatrixIs2DArray<MatrixT>()>::type>
131{
132 using Type = decltype(std::declval<MatrixT>()[0][0]);
133};
134
135//=============================================================================
136template <class MatrixT>
137struct ExtractRawComponentType<MatrixT, typename std::enable_if<!MatrixIs2DArray<MatrixT>()>::type>
138{
139 using Type = decltype(std::declval<MatrixT>()[0]);
140};
141} // namespace detail
142
143//=============================================================================
152template <class ContainerT>
154{
155private:
156 typedef typename std::remove_reference<ContainerT>::type DerefContainer;
157
158public:
163 // This parameter equals 0 or 1
164 std::is_array<DerefContainer>::value || std::is_pointer<DerefContainer>::value,
165 ContainerT>::value_type;
166 static_assert(std::is_integral<value_type>::value || std::is_floating_point<value_type>::value,
167 "value_type is not a numeric type");
168
174
178 using ComponentType = typename std::conditional<std::is_rvalue_reference<RawComponentType>::value,
179 typename std::remove_reference<RawComponentType>::type, RawComponentType>::type;
180};
181
182//-----------------------------------------------------------------------------
187template <class MatrixT>
188static constexpr bool MatrixIsPointerToPointer()
189{
190 typedef typename std::remove_pointer<MatrixT>::type Row;
191 typedef typename std::remove_pointer<Row>::type Value;
192 return std::is_pointer<MatrixT>::value && std::is_pointer<Row>::value &&
193 !std::is_pointer<Value>::value;
194}
195
196//-----------------------------------------------------------------------------
201template <class MatrixT>
202static constexpr bool MatrixLayoutIs2D()
203{
204 return MatrixIs2DArray<MatrixT>();
205}
206
207namespace detail
208{
209// Class actually implementing matrix mapping.
210template <int RowsT, int ColsT, class LayoutT>
211struct Mapper;
212
213// Specialization of the matrix mapper for when the layout is the identity
214template <int RowsT, int ColsT>
215struct Mapper<RowsT, ColsT, Layout::Identity>
216{
217 template <int RowT, int ColT>
218 static constexpr int GetIndex()
219 {
220 static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds");
221 static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds");
222 return ColsT * RowT + ColT;
223 }
224};
225
226template <int RowsT, int ColsT>
227struct Mapper<RowsT, ColsT, Layout::Transpose>
228{
229 template <int RowT, int ColT>
230 static constexpr int GetIndex()
231 {
232 static_assert(RowT >= 0 && RowT < RowsT, "RowT out of bounds");
233 static_assert(ColT >= 0 && ColT < ColsT, "ColT out of bounds");
234 return RowsT * ColT + RowT;
235 }
236};
237} // namespace detail
238
239//=============================================================================
251template <int RowsT, int ColsT, class LayoutT = Layout::Identity>
252struct Mapper
253{
254 template <int RowT, int ColT>
255 static constexpr int GetIndex()
256 {
257 return detail::Mapper<RowsT, ColsT, LayoutT>::template GetIndex<RowT, ColT>();
258 }
259};
260
261namespace detail
262{
263// Class implementing matrix wrapping.
264template <int RowsT, int ColsT, class MatrixT, class LayoutT, bool MatrixLayoutIs2DT>
266
267// Specializaion of matrix wrapping for matrices stored as 1D arrays
268// in row-wise order
269template <int RowsT, int ColsT, class MatrixT, class LayoutT>
270class Wrapper<RowsT, ColsT, MatrixT, LayoutT, false>
271{
272private:
274
275public:
276 template <int RowT, int ColT, class MatrixTT>
277 static ComponentType Get(MatrixTT&& M)
278 {
279 return M[Mapper<RowsT, ColsT, LayoutT>::template GetIndex<RowT, ColT>()];
280 }
281};
282
283// Specialization for matrices stored as 2D arrays with an unchanged layout
284template <int RowsT, int ColsT, class MatrixT>
285class Wrapper<RowsT, ColsT, MatrixT, Layout::Identity, true>
286{
287private:
289
290public:
291 template <int RowT, int ColT, class MatrixTT>
292 static ComponentType Get(MatrixTT&& M)
293 {
294 return M[RowT][ColT];
295 }
296};
297
298// Specialization for matrices stored as 2D arrays read as its transposed self.
299template <int RowsT, int ColsT, class MatrixT>
300class Wrapper<RowsT, ColsT, MatrixT, Layout::Transpose, true>
301{
302private:
304
305public:
306 template <int RowT, int ColT, class MatrixTT>
307 static ComponentType Get(MatrixTT&& M)
308 {
309 return M[ColT][RowT];
310 }
311};
312
313// Specialization for diagonal matrices.
314// Note: a diagonal matrix has to be stored in a 1D array.
315template <int RowsT, int ColsT, class MatrixT>
316class Wrapper<RowsT, ColsT, MatrixT, Layout::Diag, false>
317{
318private:
321
322 template <int RowT, int ColT>
323 struct Helper
324 {
325 static constexpr Scalar ZERO = Scalar(0);
326
327 template <class MatrixTT>
328 static ComponentType Get(MatrixTT&&)
329 {
330 return ZERO;
331 }
332 };
333
334 template <int RowT>
335 struct Helper<RowT, RowT>
336 {
337 template <class MatrixTT>
338 static ComponentType Get(MatrixTT&& M)
339 {
340 return M[RowT];
341 }
342 };
343
344public:
345 template <int RowT, int ColT, class MatrixTT>
346 ComponentType Get(MatrixTT& M)
347 {
348 return Helper<RowT, ColT>::Get(std::forward<MatrixTT>(M));
349 }
350};
351} // namespace detail
352
353//=============================================================================
368template <int RowsT, int ColsT, class MatrixT, class LayoutT = Layout::Identity>
370{
371private:
372 using Scalar = typename ScalarTypeExtractor<MatrixT>::value_type;
374
375 static_assert(!MatrixLayoutIs2D<MatrixT>() || !std::is_same<LayoutT, Layout::Diag>::value,
376 "A diagonal matrix cannot be a 2D array");
377
378public:
379 template <int RowT, int ColT, class MatrixTT>
380 static ComponentType Get(MatrixTT&& M)
381 {
382 return detail::Wrapper<RowsT, ColsT, MatrixT, LayoutT,
383 MatrixLayoutIs2D<MatrixT>()>::template Get<RowT, ColT>(std::forward<MatrixTT>(M));
384 }
385};
386VTK_ABI_NAMESPACE_END
387} // namespace vtkMatrixUtilities
388#endif
389
390// VTK-HeaderTest-Exclude: vtkMatrixUtilities.h
const RealT ZERO
Definition PyrC2Basis.h:1
static ComponentType Get(MatrixTT &&M)
static constexpr bool MatrixIsPointerToPointer()
At compile time, returns true if the templated parameter is a pointer to pointer (double** for instan...
static constexpr bool MatrixIs2DArray()
At compile time, returns true if the templated parameter is a 2D array (double[3][3] for instance),...
static constexpr bool MatrixLayoutIs2D()
At compile time, returns true if the templated parameter layout is 2D, i.e.
This struct determines a prior transform to input matrices, changing the way they are indexed.
This class is a helper class to compute at compile time the index of a matrix stored as a 1D array fr...
static constexpr int GetIndex()
This class extract the underlying value type of containers.
typename detail::ExtractRawComponentType< ContainerT >::Type RawComponentType
RawComponentType is the type given by operator[] for 1D containers, or operator[][] for 2D containers...
typename detail::ScalarTypeExtractor< std::is_array< DerefContainer >::value||std::is_pointer< DerefContainer >::value, ContainerT >::value_type value_type
value_type is the underlying arithmetic type held in ContainerT
typename std::conditional< std::is_rvalue_reference< RawComponentType >::value, typename std::remove_reference< RawComponentType >::type, RawComponentType >::type ComponentType
ComponentType is the RawComponentType dereferenced if it was an rvalue reference.
std::decay< typenamestd::remove_pointer< typenamestd::remove_all_extents< typenamestd::remove_pointer< DerefContainer >::type >::type >::type >::type value_type
std::decay< typenamestd::decay< ContainerT >::type::value_type >::type value_type