Lagrange
Loading...
Searching...
No Matches
Array.h
1/*
2 * Copyright 2020 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/Logger.h>
15#include <lagrange/common.h>
16#include <lagrange/experimental/Scalar.h>
17#include <lagrange/utils/assert.h>
18#include <lagrange/utils/build.h>
19#include <lagrange/utils/range.h>
20#include <lagrange/utils/strings.h>
21
22#include <algorithm>
23#include <any>
24#include <exception>
25#include <iostream>
26
27namespace lagrange {
28namespace experimental {
29
30template <typename Data>
32{
33};
34
35class ArrayBase
36{
37public:
38 using Index = Eigen::Index; // Default to std::ptrdiff_t
39
40public:
41 ArrayBase(ScalarEnum type)
42 : m_scalar_type(type)
43 {}
44
45 virtual ~ArrayBase() = default;
46
47public:
48 template <typename TargetType>
49 Eigen::Map<TargetType> view()
50 {
52 is_compatible<TargetType>(),
53 "Target view type is not compatible with the data.");
54 return Eigen::Map<TargetType>(data<typename TargetType::Scalar>(), rows(), cols());
55 }
56
57 template <typename TargetType>
58 Eigen::Map<const TargetType> view() const
59 {
61 is_compatible<TargetType>(),
62 "Target view type is not compatible with the data.");
63 return Eigen::Map<const TargetType>(data<typename TargetType::Scalar>(), rows(), cols());
64 }
65
66 virtual std::any get_type_info() const = 0;
67
68 template <typename Derived>
69 bool is_base_of() const
70 {
71 std::any info = get_type_info();
72 return std::any_cast<ArrayTypeInfo<Derived>>(&info) != nullptr;
73 }
74
75 template <typename DerivedPtr>
76 auto down_cast() -> std::add_pointer_t<std::decay_t<std::remove_pointer_t<DerivedPtr>>>
77 {
78 using Derived = std::decay_t<std::remove_pointer_t<DerivedPtr>>;
79#if LAGRANGE_ENABLE_RTTI
80 return dynamic_cast<Derived*>(this);
81#else
82 if (is_base_of<Derived>()) {
83 return static_cast<Derived*>(this);
84 }
85 return nullptr;
86#endif
87 }
88
89 template <typename DerivedPtr>
90 auto down_cast() const
91 -> std::add_pointer_t<std::add_const_t<std::decay_t<std::remove_pointer_t<DerivedPtr>>>>
92 {
93 using Derived = std::decay_t<std::remove_pointer_t<DerivedPtr>>;
94#if LAGRANGE_ENABLE_RTTI
95 return dynamic_cast<const Derived*>(this);
96#else
97 if (is_base_of<Derived>()) {
98 return static_cast<const Derived*>(this);
99 }
100 return nullptr;
101#endif
102 }
103
104 template <typename Derived>
105 void set(const Eigen::MatrixBase<Derived>& data);
106
107 template <typename Derived>
108 void set(Eigen::MatrixBase<Derived>&& data);
109
110 ScalarEnum get_scalar_type() const { return m_scalar_type; }
111
112 template <typename TargetType>
113 const auto& get() const;
114
115 template <typename TargetType>
116 auto& get();
117
118 template <typename Scalar>
119 Scalar* data()
120 {
121 la_runtime_assert(ScalarToEnum_v<Scalar> == m_scalar_type);
122 return static_cast<Scalar*>(data());
123 }
124
125 template <typename Scalar>
126 const Scalar* data() const
127 {
128 la_runtime_assert(ScalarToEnum_v<Scalar> == m_scalar_type);
129 return static_cast<const Scalar*>(data());
130 }
131
132 virtual Index rows() const = 0;
133 virtual Index cols() const = 0;
134 virtual bool is_row_major() const = 0;
135 virtual void* data() = 0;
136 virtual const void* data() const = 0;
137 virtual void resize(Index, Index) = 0;
138 virtual std::unique_ptr<ArrayBase> clone() const = 0;
139
140 using IndexFunction = std::function<Index(Index)>;
141 using WeightedIndexFunction =
142 std::function<void(Index, std::vector<std::pair<Index, double>>&)>;
143
144 template <typename T>
145 std::unique_ptr<ArrayBase> row_slice(const std::vector<T>& row_indices) const
146 {
147 return row_slice(safe_cast<Index>(row_indices.size()), [&](Index i) {
148 return safe_cast<Index>(row_indices[i]);
149 });
150 }
151
159 virtual std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
160 const = 0;
161
169 virtual std::unique_ptr<ArrayBase> row_slice(
170 Index num_rows,
171 const WeightedIndexFunction& mapping_fn) const = 0;
172
173 virtual std::string type_name() const = 0;
174
175protected:
176 template <typename TargetType>
177 bool is_compatible(bool ignore_storage_order = false) const;
178
179 template <typename Derived>
180 static std::unique_ptr<ArrayBase> row_slice_impl(
181 const Eigen::MatrixBase<Derived>& matrix,
182 Index num_rows,
183 const IndexFunction& mapping);
184
185 template <typename Derived>
186 static std::
187 enable_if_t<std::is_integral<typename Derived::Scalar>::value, std::unique_ptr<ArrayBase>>
188 row_slice_impl(
189 const Eigen::MatrixBase<Derived>& matrix,
190 Index num_rows,
191 const WeightedIndexFunction& mapping);
192
193 template <typename Derived>
194 static std::
195 enable_if_t<!std::is_integral<typename Derived::Scalar>::value, std::unique_ptr<ArrayBase>>
196 row_slice_impl(
197 const Eigen::MatrixBase<Derived>& matrix,
198 Index num_rows,
199 const WeightedIndexFunction& mapping);
200
201protected:
202 const ScalarEnum m_scalar_type;
203};
204
209template <typename _EigenType>
210class EigenArray : public ArrayBase
211{
212public:
213 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
214 using EigenType = _EigenType;
215 using Self = EigenArray<EigenType>;
216 using Index = ArrayBase::Index;
217 using ArrayBase::WeightedIndexFunction;
218 static_assert(
219 std::is_base_of<typename Eigen::EigenBase<EigenType>, EigenType>::value,
220 "Template parameter `_EigenType` is not an Eigen type!");
221 static_assert(!std::is_const<EigenType>::value, "EigenType should not be const type.");
222 static_assert(!std::is_reference<EigenType>::value, "EigenType should not be reference type.");
223
224public:
225 EigenArray()
226 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
227 {}
228
229 template <typename T>
230 explicit EigenArray(const Eigen::MatrixBase<T>& data)
231 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
232 , m_data(data)
233 {}
234
235 template <typename T>
236 explicit EigenArray(Eigen::MatrixBase<T>&& data)
237 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
238 , m_data(std::move(data.derived()))
239 {}
240
241 std::any get_type_info() const override { return std::make_any<ArrayTypeInfo<Self>>(); }
242
243public:
244 EigenType& get_ref() { return m_data; }
245 const EigenType& get_ref() const { return m_data; }
246
247 template <typename Derived>
248 void set(Derived&& data)
249 {
250 m_data = std::forward<Derived>(data);
251 }
252
253 Index rows() const override { return m_data.rows(); }
254 Index cols() const override { return m_data.cols(); }
255 bool is_row_major() const override { return EigenType::IsRowMajor != 0; }
256 void* data() override { return static_cast<void*>(m_data.derived().data()); }
257 const void* data() const override { return static_cast<const void*>(m_data.derived().data()); }
258 void resize(Index r, Index c) override { m_data.resize(r, c); }
259
260 std::unique_ptr<ArrayBase> clone() const override
261 {
262 return std::make_unique<EigenArray<EigenType>>(m_data);
263 }
264
265 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
266 const override
267 {
268 return row_slice_impl(m_data, num_rows, mapping_fn);
269 }
270 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const WeightedIndexFunction& mapping_fn)
271 const override
272 {
273 return row_slice_impl(m_data, num_rows, mapping_fn);
274 }
275
276 std::string type_name() const override
277 {
278 std::string scalar_name(ScalarToEnum<typename EigenType::Scalar>::name);
279 return string_format(
280 "EigenArray<Eigen::Matrix<{}, {}, {}, {}>>",
281 scalar_name,
282 static_cast<int>(EigenType::RowsAtCompileTime),
283 static_cast<int>(EigenType::ColsAtCompileTime),
284 static_cast<int>(EigenType::Options));
285 }
286
287private:
288 EigenType m_data;
289};
290
291
296template <typename _EigenType, bool IsConst = std::is_const<_EigenType>::value>
298
299template <typename _EigenType>
300class EigenArrayRef<_EigenType, false> : public ArrayBase
301{
302public:
303 using EigenType = _EigenType;
305 using DecayedEigenType = std::decay_t<_EigenType>;
306 using Index = ArrayBase::Index;
307 using ArrayBase::WeightedIndexFunction;
308 static_assert(
309 std::is_base_of<typename Eigen::EigenBase<DecayedEigenType>, DecayedEigenType>::value,
310 "Template parameter `_EigenType` is not an Eigen type!");
311 static_assert(!std::is_const<EigenType>::value, "EigenType should not be const type.");
312 static_assert(!std::is_reference<EigenType>::value, "EigenType should not be reference type.");
313
314public:
315 template <typename T>
316 explicit EigenArrayRef(Eigen::MatrixBase<T>& data)
317 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
318 , m_data(data.derived())
319 {}
320
321 std::any get_type_info() const override { return std::make_any<ArrayTypeInfo<Self>>(); }
322
323public:
324 EigenType& get_ref() { return m_data; }
325 const EigenType& get_ref() const { return m_data; }
326
327 template <typename Derived>
328 void set(Derived&& data)
329 {
330 m_data = std::forward<Derived>(data);
331 }
332
333 Index rows() const override { return m_data.rows(); }
334 Index cols() const override { return m_data.cols(); }
335 bool is_row_major() const override { return EigenType::IsRowMajor != 0; }
336 void* data() override { return static_cast<void*>(m_data.derived().data()); }
337 const void* data() const override { return static_cast<const void*>(m_data.derived().data()); }
338 void resize(Index r, Index c) override { m_data.resize(r, c); }
339
340 std::unique_ptr<ArrayBase> clone() const override
341 {
342 return std::make_unique<EigenArray<DecayedEigenType>>(m_data);
343 }
344
345 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
346 const override
347 {
348 return row_slice_impl(m_data, num_rows, mapping_fn);
349 }
350 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const WeightedIndexFunction& mapping_fn)
351 const override
352 {
353 return row_slice_impl(m_data, num_rows, mapping_fn);
354 }
355
356 std::string type_name() const override
357 {
358 std::string scalar_name(ScalarToEnum<typename EigenType::Scalar>::name);
359 return string_format(
360 "EigenArrayRef<Eigen::Matrix<{}, {}, {}, {}>>",
361 scalar_name,
362 static_cast<int>(EigenType::RowsAtCompileTime),
363 static_cast<int>(EigenType::ColsAtCompileTime),
364 static_cast<int>(EigenType::Options));
365 }
366
367private:
368 EigenType& m_data;
369};
370
371template <typename _EigenType>
372class EigenArrayRef<_EigenType, true> : public ArrayBase
373{
374public:
375 using EigenType = _EigenType;
376 using Self = EigenArrayRef<_EigenType, true>;
377 using DecayedEigenType = std::decay_t<_EigenType>;
378 using Index = ArrayBase::Index;
379 using ArrayBase::WeightedIndexFunction;
380 static_assert(
381 std::is_base_of<typename Eigen::EigenBase<DecayedEigenType>, DecayedEigenType>::value,
382 "Template parameter `_EigenType` is not an Eigen type!");
383 static_assert(std::is_const<EigenType>::value, "EigenType must const type.");
384 static_assert(!std::is_reference<EigenType>::value, "EigenType should not be reference type.");
385
386public:
387 template <typename T>
388 explicit EigenArrayRef(const Eigen::MatrixBase<T>& data)
389 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
390 , m_data(data.derived())
391 {}
392
393 std::any get_type_info() const override { return std::make_any<ArrayTypeInfo<Self>>(); }
394
395public:
396 const EigenType& get_ref() const { return m_data; }
397
398 Index rows() const override { return m_data.rows(); }
399 Index cols() const override { return m_data.cols(); }
400 bool is_row_major() const override { return EigenType::IsRowMajor != 0; }
401 const void* data() const override { return static_cast<const void*>(m_data.derived().data()); }
402 void* data() override { throw std::runtime_error("This method is not supported"); }
403
404 void resize(Index r, Index c) override
405 {
406 if (r != m_data.rows() || c != m_data.cols()) {
407 throw std::runtime_error("Resizing const EigenArrayRef is not allowed.");
408 }
409 }
410
411 std::unique_ptr<ArrayBase> clone() const override
412 {
413 return std::make_unique<EigenArray<DecayedEigenType>>(m_data);
414 }
415
416 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
417 const override
418 {
419 return row_slice_impl(m_data, num_rows, mapping_fn);
420 }
421 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const WeightedIndexFunction& mapping_fn)
422 const override
423 {
424 return row_slice_impl(m_data, num_rows, mapping_fn);
425 }
426
427 std::string type_name() const override
428 {
429 std::string scalar_name(ScalarToEnum<typename EigenType::Scalar>::name);
430 return string_format(
431 "EigenArrayRef<const Eigen::Matrix<{}, {}, {}, {}>>",
432 scalar_name,
433 static_cast<int>(EigenType::RowsAtCompileTime),
434 static_cast<int>(EigenType::ColsAtCompileTime),
435 static_cast<int>(EigenType::Options));
436 }
437
438private:
439 EigenType& m_data;
440};
441
442
447template <
448 typename _Scalar,
449 int _Rows = Eigen::Dynamic,
450 int _Cols = Eigen::Dynamic,
451 int _Options = Eigen::RowMajor,
452 bool IsConst = std::is_const<_Scalar>::value>
454
455template <typename _Scalar, int _Rows, int _Cols, int _Options>
456class RawArray<_Scalar, _Rows, _Cols, _Options, false> : public ArrayBase
457{
458public:
460 using Scalar = _Scalar;
461 using Index = ArrayBase::Index;
462 using EigenType = Eigen::Matrix<Scalar, _Rows, _Cols, _Options>;
463 using EigenMap = Eigen::Map<EigenType>;
464 using ConstEigenMap = Eigen::Map<const EigenType>;
465 using ArrayBase::WeightedIndexFunction;
466
467public:
468 RawArray(Scalar* data, Index rows, Index cols)
469 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
470 , m_data(data, rows, cols)
471 {}
472
473 std::any get_type_info() const override { return std::make_any<ArrayTypeInfo<Self>>(); }
474
475public:
476 EigenMap& get_ref() { return m_data; }
477 ConstEigenMap get_ref() const { return m_data; }
478
479 template <typename Derived>
480 void set(const Eigen::MatrixBase<Derived>& data)
481 {
482 m_data = data;
483 }
484
485 void set(Scalar* data, Index rows, Index cols) { m_data = EigenMap(data, rows, cols); }
486
487 Index rows() const override { return m_data.rows(); }
488 Index cols() const override { return m_data.cols(); }
489 bool is_row_major() const override { return EigenType::IsRowMajor != 0; }
490 void* data() override { return static_cast<void*>(m_data.data()); }
491 const void* data() const override { return static_cast<const void*>(m_data.data()); }
492 void resize(Index r, Index c) override
493 {
494 if (r != m_data.rows() || c != m_data.cols()) {
495 throw std::runtime_error("Resizing RawArray is not allowed.");
496 }
497 }
498
499 std::unique_ptr<ArrayBase> clone() const override
500 {
501 return std::make_unique<EigenArray<EigenType>>(m_data);
502 }
503
504 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
505 const override
506 {
507 return row_slice_impl(m_data, num_rows, mapping_fn);
508 }
509 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const WeightedIndexFunction& mapping_fn)
510 const override
511 {
512 return row_slice_impl(m_data, num_rows, mapping_fn);
513 }
514
515 std::string type_name() const override
516 {
517 std::string scalar_name(ScalarToEnum<Scalar>::name);
518 return string_format("RawArray<{}, {}, {}, {}>", scalar_name, _Rows, _Cols, _Options);
519 }
520
521private:
522 EigenMap m_data;
523};
524
525template <typename _Scalar, int _Rows, int _Cols, int _Options>
526class RawArray<_Scalar, _Rows, _Cols, _Options, true> : public ArrayBase
527{
528public:
529 using Self = RawArray<_Scalar, _Rows, _Cols, _Options, true>;
530 using Scalar = std::decay_t<_Scalar>;
531 using Index = ArrayBase::Index;
532 using EigenType = Eigen::Matrix<Scalar, _Rows, _Cols, _Options>;
533 using EigenMap = Eigen::Map<const EigenType>;
534 using ArrayBase::WeightedIndexFunction;
535
536public:
537 RawArray(const Scalar* data, Index rows, Index cols)
538 : ArrayBase(ScalarToEnum_v<typename EigenType::Scalar>)
539 , m_data(data, rows, cols)
540 {}
541
542 std::any get_type_info() const override { return std::make_any<ArrayTypeInfo<Self>>(); }
543
544public:
545 const EigenMap& get_ref() const { return m_data; }
546
547 Index rows() const override { return m_data.rows(); }
548 Index cols() const override { return m_data.cols(); }
549 bool is_row_major() const override { return EigenType::IsRowMajor != 0; }
550 const void* data() const override { return static_cast<const void*>(m_data.data()); }
551 void* data() override { throw std::runtime_error("This method is not supported"); }
552
553 void resize(Index r, Index c) override
554 {
555 if (r != m_data.rows() || c != m_data.cols()) {
556 throw std::runtime_error("Resizing RawArray is not allowed.");
557 }
558 }
559
560 std::unique_ptr<ArrayBase> clone() const override
561 {
562 return std::make_unique<EigenArray<EigenType>>(m_data);
563 }
564
565 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const IndexFunction& mapping_fn)
566 const override
567 {
568 return row_slice_impl(m_data, num_rows, mapping_fn);
569 }
570 std::unique_ptr<ArrayBase> row_slice(Index num_rows, const WeightedIndexFunction& mapping_fn)
571 const override
572 {
573 return row_slice_impl(m_data, num_rows, mapping_fn);
574 }
575
576 std::string type_name() const override
577 {
578 std::string scalar_name(ScalarToEnum<Scalar>::name);
579 return string_format("RawArray<const {}, {}, {}, {}>", scalar_name, _Rows, _Cols, _Options);
580 }
581
582private:
583 const EigenMap m_data;
584};
585
586} // namespace experimental
587} // namespace lagrange
588
589#include "Array.impl.h"
590#include "Array.serialization.h"
virtual std::unique_ptr< ArrayBase > row_slice(Index num_rows, const IndexFunction &mapping_fn) const =0
Using index function for row mapping.
virtual std::unique_ptr< ArrayBase > row_slice(Index num_rows, const WeightedIndexFunction &mapping_fn) const =0
This is the most generic version of row_slice method.
std::unique_ptr< ArrayBase > row_slice(Index num_rows, const IndexFunction &mapping_fn) const override
Using index function for row mapping.
Definition Array.h:265
std::unique_ptr< ArrayBase > row_slice(Index num_rows, const WeightedIndexFunction &mapping_fn) const override
This is the most generic version of row_slice method.
Definition Array.h:270
This class is a thin wrapper around an Eigen matrix.
Definition Array.h:297
This class provide a thin wrapper around a raw array.
Definition Array.h:453
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:177
std::string string_format(lagrange::format_string< Args... > format, Args &&... args)
Format args according to the format string fmt, and return the result as a string.
Definition strings.h:97
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:51
Main namespace for Lagrange.