MayaFlux 0.5.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
OperationHelper.hpp
Go to the documentation of this file.
1#pragma once
2
5
7
8namespace MayaFlux::Yantra {
9
10/**
11 * @struct DataStructureInfo
12 * @brief Metadata about data structure for reconstruction
13 */
16 std::vector<Kakshya::DataDimension> dimensions;
17 std::type_index original_type = std::type_index(typeid(void));
18
19 DataStructureInfo() = default;
21 std::vector<Kakshya::DataDimension> dims,
22 std::type_index type)
23 : modality(mod)
24 , dimensions(std::move(dims))
25 , original_type(type)
26 {
27 }
28};
29
30/**
31 * @class OperationHelper
32 * @brief Universal data conversion helper for all Yantra operations
33 *
34 * Provides a unified interface for converting between ComputeData types and
35 * processing formats. All operations (analyzers, sorters, extractors, transformers)
36 * can use this helper to:
37 *
38 * 1. Convert any ComputeData → DataVariant → std::vector<double>
39 * 2. Process data in double format (universal algorithms)
40 * 3. Reconstruct results back to target ComputeData types
41 *
42 * Key Features:
43 * - Universal conversion path for all ComputeData types
44 * - Structure preservation via metadata
45 * - Configurable complex number handling
46 * - Lossless conversions (except complex → double)
47 * - Thread-safe operation
48 */
49class MAYAFLUX_API OperationHelper {
50public:
51 /**
52 * @brief Set global complex conversion strategy
53 * @param strategy How to convert complex numbers to doubles
54 */
55 static inline void set_complex_conversion_strategy(Kakshya::ComplexConversionStrategy strategy) { s_complex_strategy = strategy; }
56
57 /**
58 * @brief Get current complex conversion strategy
59 * @return Current conversion strategy
60 */
61 static inline Kakshya::ComplexConversionStrategy get_complex_conversion_strategy() { return s_complex_strategy; }
62
63 /**
64 * @brief extract numeric data from single-variant types
65 * @tparam T ComputeData type
66 * @param compute_data Input data
67 * @return Span of double data
68 */
69 template <typename T>
70 requires SingleVariant<T>
71 static std::span<double> extract_numeric_data(const T& compute_data)
72 {
73 if constexpr (std::is_same_v<T, Kakshya::DataVariant>) {
74 auto const_span = Kakshya::convert_variant<double>(compute_data);
75 return std::span<double>(const_cast<double*>(const_span.data()), const_span.size());
76 }
77 if constexpr (is_eigen_matrix_v<T>) {
78 Kakshya::DataVariant variant = create_data_variant_from_eigen(compute_data);
79 return Kakshya::convert_variant<double>(variant, s_complex_strategy);
80 }
81
82 Kakshya::DataVariant variant { compute_data };
83 return Kakshya::convert_variant_to_double(variant, s_complex_strategy);
84 }
85
86 /**
87 * @brief extract numeric data from multi-variant types
88 * @tparam T ComputeData type
89 * @param compute_data Input data
90 * @return Vector of spans of double data (one per channel/variant)
91 */
92 template <typename T>
94 static std::vector<std::span<double>> extract_numeric_data(const T& compute_data, bool needs_processig = false)
95 {
96 if constexpr (std::is_same_v<T, std::vector<Kakshya::DataVariant>>) {
97 return Kakshya::convert_variants<double>(compute_data, s_complex_strategy);
98 }
99
100 if constexpr (std::is_same_v<T, std::shared_ptr<Kakshya::SignalSourceContainer>>) {
101 if (needs_processig) {
102 if (compute_data->get_processing_state() != Kakshya::ProcessingState::PROCESSED) {
103 compute_data->process_default();
104 compute_data->update_processing_state(Kakshya::ProcessingState::PROCESSED);
105 }
106 std::vector<Kakshya::DataVariant> variant = compute_data->get_processed_data();
107 return Kakshya::convert_variants<double>(variant, s_complex_strategy);
108 }
109 std::vector<Kakshya::DataVariant> variant = compute_data->get_data();
110 return Kakshya::convert_variants<double>(variant, s_complex_strategy);
111 }
112
113 if constexpr (is_eigen_matrix_v<T>)
114 return extract_from_eigen_matrix(compute_data);
115
116 return std::vector<std::span<double>> {};
117 }
118
119 /**
120 * @brief extract numeric data from region-like types
121 * @tparam T ComputeData type
122 * @param compute_data Input data
123 * @param container Container to extract data from
124 * @return Vector of spans of double data (one per region/segment)
125 */
126 template <typename T>
127 requires RegionLike<T>
128 static std::vector<std::span<double>> extract_numeric_data(
129 const T& compute_data,
130 const std::shared_ptr<Kakshya::SignalSourceContainer>& container)
131 {
132 if (!container) {
133 error<std::invalid_argument>(Journal::Component::Yantra, Journal::Context::ContainerProcessing, std::source_location::current(), "Null container provided for region extraction");
134 }
135
136 if constexpr (std::is_same_v<T, Kakshya::Region>) {
137 auto data = container->get_region_data(compute_data);
138 return Kakshya::convert_variants<double>(data);
139
140 } else if constexpr (std::is_same_v<T, Kakshya::RegionGroup>) {
141 if (compute_data.regions.empty()) {
142 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::ContainerProcessing, std::source_location::current(), "Empty RegionGroup cannot be extracted");
143 }
144 auto data = container->get_region_group_data(compute_data);
145 return Kakshya::convert_variants<double>(data);
146
147 } else if constexpr (std::is_same_v<T, std::vector<Kakshya::RegionSegment>>) {
148 if (compute_data.empty()) {
149 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::ContainerProcessing, std::source_location::current(), "Empty RegionSegment vector cannot be extracted");
150 }
151 auto data = container->get_segments_data(compute_data);
152 return Kakshya::convert_variants<double>(data);
153 }
154 }
155
156 // =========================================================================
157 // Native extraction -- no double coercion
158 //
159 // extract_native_data returns data in the source's own scalar type.
160 // Use this for GPU staging, Kinesis::Vision callers, and any path that
161 // should not widen to double.
162 //
163 // For DataVariant / vector<DataVariant> the native type is runtime-
164 // determined; these overloads return DataSpanVariant / vector<DataSpanVariant>
165 // so the caller can branch on element_type() exactly as with get_frame().
166 //
167 // For SignalSourceContainer the native type is queried via value_element_type().
168 // For Eigen the native type is T::Scalar.
169 // Region types are not supported: region data comes out of containers as
170 // DataVariant and is already accessible via the DataVariant overload below.
171 // =========================================================================
172
173 /**
174 * @brief Extract a single DataVariant as a type-erased span without conversion.
175 *
176 * Returns a DataSpanVariant whose active alternative matches the variant's
177 * native element type. No allocation, no coercion.
178 * Call element_type() on the result or use as<E>() when E is known statically.
179 *
180 * @param variant Source variant.
181 * @return DataSpanVariant aliasing the variant's internal storage.
182 */
184 {
185 return std::visit([](const auto& vec) -> Kakshya::DataSpanVariant {
186 return std::span<const typename std::decay_t<decltype(vec)>::value_type>(
187 vec.data(), vec.size());
188 },
189 variant);
190 }
191
192 /**
193 * @brief Extract a vector of DataVariants as type-erased spans without conversion.
194 *
195 * One DataSpanVariant per channel/variant in the input. Each span aliases
196 * the variant's internal storage; no allocation or coercion.
197 *
198 * @param variants Source variants.
199 * @return Per-channel DataSpanVariants.
200 */
201 static std::vector<Kakshya::DataSpanVariant> extract_native_data(
202 const std::vector<Kakshya::DataVariant>& variants)
203 {
204 std::vector<Kakshya::DataSpanVariant> result;
205 result.reserve(variants.size());
206 for (const auto& v : variants)
207 result.push_back(extract_native_data(v));
208 return result;
209 }
210
211 /**
212 * @brief Extract native-typed channel spans from a SignalSourceContainer.
213 *
214 * Queries value_element_type() to determine the native scalar, then
215 * retrieves each channel's data as a FrameView (which already carries the
216 * native span). Returns one DataSpanVariant per channel; no double coercion.
217 *
218 * @param container Source container. Must have data.
219 * @param use_processed If true, reads processed_data; otherwise raw data.
220 * @return Per-channel DataSpanVariants in native element type.
221 */
222 static std::vector<Kakshya::DataSpanVariant> extract_native_data(
223 const std::shared_ptr<Kakshya::SignalSourceContainer>& container,
224 bool use_processed = false)
225 {
226 if (!container || !container->has_data())
227 return {};
228
229 const auto& variants = use_processed
230 ? container->get_processed_data()
231 : container->get_data();
232
233 return extract_native_data(variants);
234 }
235
236 /**
237 * @brief Extract native-typed column spans from any Eigen matrix.
238 *
239 * Returns one span per column in T::Scalar, aliasing the matrix's own
240 * storage via Eigen::Map. The matrix must outlive the returned spans.
241 *
242 * @tparam EigenMatrix Any Eigen matrix type. T::Scalar is the native type.
243 * @param matrix Source matrix.
244 * @return Per-column spans in T::Scalar.
245 */
246 template <typename EigenMatrix>
247 requires is_eigen_matrix_v<EigenMatrix>
248 static auto extract_native_data(const EigenMatrix& matrix)
249 -> std::vector<std::span<const typename EigenMatrix::Scalar>>
250 {
251 using Scalar = typename EigenMatrix::Scalar;
252 std::vector<std::span<const Scalar>> result;
253 result.reserve(static_cast<size_t>(matrix.cols()));
254
255 for (int col = 0; col < matrix.cols(); ++col) {
256 result.emplace_back(matrix.col(col).data(), static_cast<size_t>(matrix.rows()));
257 }
258 return result;
259 }
260
261 /**
262 * @brief Convert ComputeData to DataVariant format
263 * @tparam T ComputeData type
264 * @param compute_data Input data
265 * @return Vector of DataVariant (one per channel/variant)
266 */
267 template <typename T>
268 requires MultiVariant<T>
269 static std::vector<Kakshya::DataVariant> to_data_variant(const T& compute_data)
270 {
271 if constexpr (std::is_same_v<T, std::vector<Kakshya::DataVariant>>) {
272 return compute_data;
273 }
274
275 if constexpr (std::is_same_v<T, std::shared_ptr<Kakshya::SignalSourceContainer>>) {
276 if (compute_data->get_processing_state() == Kakshya::ProcessingState::PROCESSED) {
277 return compute_data->get_processed_data();
278 }
279 return compute_data->get_data();
280 }
281
282 if constexpr (is_eigen_matrix_v<T>) {
283 return convert_eigen_matrix_to_variant(compute_data);
284 }
285 }
286
287 /**
288 * @brief Convert region-like ComputeData to DataVariant format
289 * @tparam T ComputeData type
290 * @param compute_data Input data
291 * @param container Container to extract data from
292 * @return Vector of DataVariant (one per region/segment)
293 */
294 template <typename T>
295 requires RegionLike<T>
296 static std::vector<Kakshya::DataVariant> to_data_variant(
297 const T& compute_data,
298 const std::shared_ptr<Kakshya::SignalSourceContainer>& container)
299 {
300 if constexpr (std::is_same_v<T, Kakshya::Region>) {
301 return container->get_region_data(compute_data);
302 } else if constexpr (std::is_same_v<T, Kakshya::RegionGroup>) {
303 return container->get_region_group_data(compute_data);
304 } else if constexpr (std::is_same_v<T, std::vector<Kakshya::RegionSegment>>) {
305 return container->get_segments_data(compute_data);
306 }
307 }
308
309 /**
310 * @brief Populate DataStructureInfo from a Datum without extracting spans.
311 * @tparam T OperationReadyData type.
312 * @param compute_data Source Datum.
313 * @return DataStructureInfo with original_type, dimensions, modality populated.
314 */
315 template <OperationReadyData T>
316 static DataStructureInfo get_structure_info(T& compute_data)
317 {
318 if constexpr (is_IO<T>::value) {
319 DataStructureInfo info {};
320 info.original_type = std::type_index(typeid(std::decay_t<decltype(compute_data.data)>));
321 info.dimensions = compute_data.dimensions;
322 info.modality = compute_data.modality;
323 return info;
324 } else {
325 DataStructureInfo info {};
326 info.original_type = std::type_index(typeid(T));
327 auto [dims, mod] = infer_structure(compute_data);
328 info.dimensions = std::move(dims);
329 info.modality = mod;
330 return info;
331 }
332 }
333
334 /**
335 * @brief Extract structured double data from Datum container or direct ComputeData with automatic container handling
336 * @tparam T OperationReadyData type
337 * @param compute_data or Datum container with data and optional container
338 * @return Tuple of [spans, structure_info]
339 * @throws std::runtime_error if container required but not provided
340 */
341 template <OperationReadyData T>
342 static std::tuple<std::vector<std::span<double>>, DataStructureInfo>
344 {
345 if constexpr (is_IO<T>::value) {
346 DataStructureInfo info {};
347 info.original_type = std::type_index(typeid(std::decay_t<decltype(compute_data.data)>));
348 info.dimensions = compute_data.dimensions;
349 info.modality = compute_data.modality;
350
351 if constexpr (RequiresContainer<std::decay_t<decltype(compute_data.data)>>) {
352 if (!compute_data.has_container()) {
353 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::ContainerProcessing, std::source_location::current(), "Container is required for region-like data extraction but not provided");
354 }
355 std::vector<std::span<double>> double_data = extract_numeric_data(compute_data.data, compute_data.container.value());
356 return std::make_tuple(double_data, info);
357 } else {
358 std::vector<std::span<double>> double_data = extract_numeric_data(compute_data.data, compute_data.needs_processig());
359 return std::make_tuple(double_data, info);
360 }
361 } else {
362 DataStructureInfo info {};
363 info.original_type = std::type_index(typeid(T));
364 std::vector<std::span<double>> double_data = extract_numeric_data(compute_data);
365 auto [dimensions, modality] = infer_structure(compute_data);
366 info.dimensions = dimensions;
367 info.modality = modality;
368
369 return std::make_tuple(double_data, info);
370 }
371 }
372
373 /**
374 * @brief Extract native-typed channel spans and structure metadata from
375 * a Datum or direct ComputeData, without double coercion.
376 *
377 * Mirrors extract_structured_double in structure: same DataStructureInfo
378 * population, same Datum unwrapping, same container handling for
379 * RegionLike types. The only difference is that channel data is returned
380 * as DataSpanVariant (type-erased native span) rather than span<double>.
381 *
382 * Use this as the entry point for Kinesis::Vision operations and any
383 * other pipeline that must preserve the source's native element type
384 * (uint8_t pixel data, uint16_t depth, float HDR, etc.).
385 *
386 * For RegionLike data types the region variants are returned as
387 * DataSpanVariant via extract_native_data(DataVariant), consistent with
388 * the non-region overloads.
389 *
390 * Callers branch on DataSpanVariant::element_type() or use
391 * FrameView::as<E>() / DataSpanVariant::get_if<span<const E>>() when
392 * the native type is statically known.
393 *
394 * @tparam T OperationReadyData type.
395 * @param compute_data Datum or direct ComputeData to extract from.
396 * @return Tuple of [native channel spans, DataStructureInfo].
397 * @throws std::runtime_error if a container is required but absent.
398 */
399 template <OperationReadyData T>
400 static std::tuple<std::vector<Kakshya::DataSpanVariant>, DataStructureInfo>
402 {
403 if constexpr (is_IO<T>::value) {
404 DataStructureInfo info {};
405 info.original_type = std::type_index(typeid(std::decay_t<decltype(compute_data.data)>));
406 info.dimensions = compute_data.dimensions;
407 info.modality = compute_data.modality;
408
409 if constexpr (RequiresContainer<std::decay_t<decltype(compute_data.data)>>) {
410 if (!compute_data.has_container()) {
411 error<std::runtime_error>(
412 Journal::Component::Yantra,
413 Journal::Context::ContainerProcessing,
414 std::source_location::current(),
415 "Container is required for region-like data extraction but not provided");
416 }
417
418 const auto region_variants = [&]() -> std::vector<Kakshya::DataVariant> {
419 if constexpr (std::is_same_v<std::decay_t<decltype(compute_data.data)>, Kakshya::Region>) {
420 return compute_data.container.value()->get_region_data(compute_data.data);
421 } else if constexpr (std::is_same_v<std::decay_t<decltype(compute_data.data)>, Kakshya::RegionGroup>) {
422 return compute_data.container.value()->get_region_group_data(compute_data.data);
423 } else {
424 return compute_data.container.value()->get_segments_data(compute_data.data);
425 }
426 }();
427 return { extract_native_data(region_variants), info };
428 } else {
429 auto spans = extract_native_data(compute_data.data);
430 return { std::move(spans), info };
431 }
432 } else {
433 DataStructureInfo info {};
434 info.original_type = std::type_index(typeid(T));
435 auto spans = extract_native_data(compute_data);
436 auto [dimensions, modality] = infer_structure(compute_data);
437 info.dimensions = dimensions;
438 info.modality = modality;
439 return { std::move(spans), info };
440 }
441 }
442
443 /**
444 * @brief Reconstruct ComputeData type from double vector and structure info
445 * @tparam T Target ComputeData type
446 * @param double_data Processed double vector
447 * @param structure_info Original structure metadata
448 * @return Reconstructed data of type T
449 */
450 template <ComputeData T>
451 requires(!is_IO<T>::value)
452 static T reconstruct_from_double(const std::vector<std::vector<double>>& double_data,
453 const DataStructureInfo& structure_info)
454 {
455 if constexpr (std::is_same_v<T, std::vector<std::vector<double>>>) {
456 return double_data;
457 } else if constexpr (std::is_same_v<T, Eigen::MatrixXd>) {
458 return recreate_eigen_matrix(double_data, structure_info);
459 } else if constexpr (std::is_same_v<T, std::vector<Kakshya::DataVariant>>) {
460 std::vector<Kakshya::DataVariant> variants;
461 variants.reserve(double_data.size());
462 for (const auto& vec : double_data) {
463 variants.emplace_back(vec);
464 }
465 return variants;
466 } else if constexpr (std::is_same_v<T, Kakshya::DataVariant>) {
467 auto data = Kakshya::interleave_channels<double>(double_data);
468 return reconstruct_data_variant_from_double(data, structure_info);
469 } else {
470 error<std::runtime_error>(Journal::Component::Yantra, Journal::Context::Runtime, std::source_location::current(), "Reconstruction not implemented for target type {}", structure_info.original_type.name());
471 return T {};
472 }
473 }
474
475 /**
476 * @brief Reconstruct Datum type from double vector and structure info
477 * @tparam T Target Datum type
478 * @param double_data Processed double vector
479 * @param structure_info Original structure metadata
480 * @return Reconstructed data of type T
481 */
482 template <typename T>
483 requires is_IO<T>::value
484 static T reconstruct_from_double(const std::vector<std::vector<double>>& double_data,
485 const DataStructureInfo& structure_info)
486 {
487 using UnderlyingType = std::decay_t<decltype(std::declval<T>().data)>;
488
489 T io_data;
490 io_data.dimensions = structure_info.dimensions;
491 io_data.modality = structure_info.modality;
492
493 io_data.data = reconstruct_from_double<UnderlyingType>(double_data, structure_info);
494
495 return io_data;
496 }
497
498 /**
499 * @brief Setup operation buffer from Datum or ComputeData type
500 * @tparam T Datum or ComputeData type
501 * @param input Datum container or direct ComputeData
502 * @param working_buffer Buffer to setup (will be resized)
503 * @return Tuple of [working_spans, structure_info]
504 */
505 template <OperationReadyData T>
506 static auto setup_operation_buffer(T& input, std::vector<std::vector<double>>& working_buffer)
507 {
508 auto [data_spans, structure_info] = extract_structured_double(input);
509
510 if (working_buffer.size() != data_spans.size()) {
511 working_buffer.resize(data_spans.size());
512 }
513
514 std::vector<std::span<double>> working_spans(working_buffer.size());
515
516 for (size_t i = 0; i < data_spans.size(); i++) {
517 working_buffer[i].resize(data_spans[i].size());
518 std::ranges::copy(data_spans[i], working_buffer[i].begin());
519 working_spans[i] = std::span<double>(working_buffer[i].data(), working_buffer[i].size());
520 }
521
522 return std::make_tuple(working_spans, structure_info);
523 }
524
525private:
526 static inline Kakshya::ComplexConversionStrategy s_complex_strategy = Kakshya::ComplexConversionStrategy::MAGNITUDE;
527
528 /**
529 * @brief Create DataVariant from Eigen matrix/vector
530 */
531 template <typename EigenType>
532 static Kakshya::DataVariant create_data_variant_from_eigen(const EigenType& eigen_data)
533 {
534 std::vector<double> flat_data;
535
536 if constexpr (EigenType::IsVectorAtCompileTime) {
537 flat_data.resize(eigen_data.size());
538 for (int i = 0; i < eigen_data.size(); ++i) {
539 flat_data[i] = static_cast<double>(eigen_data(i));
540 }
541 } else {
542 flat_data.resize(eigen_data.size());
543 int idx = 0;
544 for (int i = 0; i < eigen_data.rows(); ++i) {
545 for (int j = 0; j < eigen_data.cols(); ++j) {
546 flat_data[idx++] = static_cast<double>(eigen_data(i, j));
547 }
548 }
549 }
550
551 return Kakshya::DataVariant { flat_data };
552 }
553
554 /**
555 * @brief Infer data structure from ComputeData type
556 * @tparam T ComputeData type
557 * @param compute_data Input data
558 * @return Pair of (dimensions, modality)
559 */
560 template <typename EigenMatrix>
561 static std::vector<std::span<double>> extract_from_eigen_matrix(const EigenMatrix& matrix)
562 {
563 static thread_local std::vector<std::vector<double>> columns;
564 columns.clear();
565 columns.resize(matrix.cols());
566 std::vector<std::span<double>> spans;
567 spans.reserve(matrix.cols());
568
569 for (int col = 0; col < matrix.cols(); ++col) {
570 columns[col].resize(matrix.rows());
571 for (int row = 0; row < matrix.rows(); ++row) {
572 columns[col][row] = static_cast<double>(matrix(row, col));
573 }
574 spans.emplace_back(columns[col].data(), columns[col].size());
575 }
576 return spans;
577 }
578
579 /**
580 * @brief Extract data from Eigen vector to double span
581 */
582 /* template <typename EigenVector>
583 static std::span<double> extract_from_eigen_vector(const EigenVector& vec)
584 {
585 thread_local std::vector<double> buffer;
586 buffer.clear();
587 buffer.resize(vec.size());
588
589 for (int i = 0; i < vec.size(); ++i) {
590 buffer[i] = static_cast<double>(vec(i));
591 }
592 return { buffer.data(), buffer.size() };
593 } */
594
595 /**
596 * @brief Convert Eigen matrix to DataVariant format
597 */
598 template <typename EigenMatrix>
599 static std::vector<Kakshya::DataVariant> convert_eigen_matrix_to_variant(const EigenMatrix& matrix)
600 {
601 std::vector<Kakshya::DataVariant> columns(matrix.cols());
602
603 for (int col = 0; col < matrix.cols(); ++col) {
604 auto row_indices = std::views::iota(0, matrix.rows());
605 auto col_data = row_indices
606 | std::views::transform([&](int row) { return static_cast<double>(matrix(row, col)); });
607 columns[col] = { std::vector<double>(col_data.begin(), col_data.end()) };
608 }
609 return columns;
610 }
611
612 /**
613 * @brief Infer data structure from ComputeData type
614 * @tparam T ComputeData type
615 * @param compute_data Input data
616 * @return Pair of (dimensions, modality)
617 */
618 template <typename T>
619 static Eigen::MatrixXd create_eigen_matrix(const std::vector<std::vector<T>>& columns)
620 {
621 if (columns.empty()) {
622 return {};
623 }
624
625 int rows = columns[0].size();
626 int cols = columns.size();
627
628 for (const auto& col : columns) {
629 if (col.size() != rows) {
630 error<std::invalid_argument>(Journal::Component::Yantra, Journal::Context::Runtime, std::source_location::current(), "All columns must have same size");
631 }
632 }
633
634 Eigen::MatrixXd matrix(rows, cols);
635 for (int col = 0; col < cols; ++col) {
636 for (int row = 0; row < rows; ++row) {
637 matrix(row, col) = static_cast<double>(columns[col][row]);
638 }
639 }
640 return matrix;
641 }
642
643 /**
644 * @brief Create Eigen matrix from spans
645 */
646 template <typename T>
647 static Eigen::MatrixXd create_eigen_matrix(const std::vector<std::span<const T>>& spans)
648 {
649 if (spans.empty()) {
650 return {};
651 }
652
653 int rows = spans[0].size();
654 int cols = spans.size();
655
656 for (const auto& span : spans) {
657 if (span.size() != rows) {
658 error<std::invalid_argument>(Journal::Component::Yantra, Journal::Context::Runtime, std::source_location::current(), "All spans must have same size");
659 }
660 }
661
662 Eigen::MatrixXd matrix(rows, cols);
663 for (int col = 0; col < cols; ++col) {
664 for (int row = 0; row < rows; ++row) {
665 matrix(row, col) = static_cast<double>(spans[col][row]);
666 }
667 }
668 return matrix;
669 }
670
671 /**
672 * @brief Infer data structure from ComputeData type
673 * @tparam T ComputeData type
674 * @param compute_data Input data
675 * @param container Optional container for region-like types
676 * @return Pair of (dimensions, modality)
677 */
678 static Eigen::MatrixXd recreate_eigen_matrix(
679 const std::vector<std::vector<double>>& columns,
680 const DataStructureInfo& structure_info);
681
682 /**
683 * @brief Infer data structure from ComputeData type
684 * @tparam T ComputeData type
685 * @param compute_data Input data
686 * @param container Optional container for region-like types
687 * @return Pair of (dimensions, modality)
688 */
689 static Eigen::MatrixXd recreate_eigen_matrix(
690 const std::vector<std::span<const double>>& spans,
691 const DataStructureInfo& structure_info);
692
693 /**
694 * @brief Reconstruct DataVariant from double data and structure info
695 */
696 static Kakshya::DataVariant reconstruct_data_variant_from_double(const std::vector<double>& double_data,
697 const DataStructureInfo& structure_info);
698};
699
700} // namespace MayaFlux::Yantra
Core::GlobalInputConfig input
Definition Config.cpp:38
static Eigen::MatrixXd create_eigen_matrix(const std::vector< std::span< const T > > &spans)
Create Eigen matrix from spans.
static DataStructureInfo get_structure_info(T &compute_data)
Populate DataStructureInfo from a Datum without extracting spans.
static std::vector< std::span< double > > extract_from_eigen_matrix(const EigenMatrix &matrix)
Infer data structure from ComputeData type.
static Kakshya::ComplexConversionStrategy get_complex_conversion_strategy()
Get current complex conversion strategy.
static ::value T reconstruct_from_double(const std::vector< std::vector< double > > &double_data, const DataStructureInfo &structure_info)
Reconstruct Datum type from double vector and structure info.
static Eigen::MatrixXd create_eigen_matrix(const std::vector< std::vector< T > > &columns)
Infer data structure from ComputeData type.
static std::tuple< std::vector< Kakshya::DataSpanVariant >, DataStructureInfo > extract_structured_native(T &compute_data)
Extract native-typed channel spans and structure metadata from a Datum or direct ComputeData,...
static std::vector< Kakshya::DataVariant > convert_eigen_matrix_to_variant(const EigenMatrix &matrix)
Extract data from Eigen vector to double span.
static std::vector< Kakshya::DataSpanVariant > extract_native_data(const std::shared_ptr< Kakshya::SignalSourceContainer > &container, bool use_processed=false)
Extract native-typed channel spans from a SignalSourceContainer.
static std::vector< Kakshya::DataVariant > to_data_variant(const T &compute_data, const std::shared_ptr< Kakshya::SignalSourceContainer > &container)
Convert region-like ComputeData to DataVariant format.
static std::vector< std::span< double > > extract_numeric_data(const T &compute_data, const std::shared_ptr< Kakshya::SignalSourceContainer > &container)
extract numeric data from region-like types
static Kakshya::DataSpanVariant extract_native_data(const Kakshya::DataVariant &variant)
Extract a single DataVariant as a type-erased span without conversion.
static std::vector< Kakshya::DataSpanVariant > extract_native_data(const std::vector< Kakshya::DataVariant > &variants)
Extract a vector of DataVariants as type-erased spans without conversion.
static void set_complex_conversion_strategy(Kakshya::ComplexConversionStrategy strategy)
Set global complex conversion strategy.
static std::tuple< std::vector< std::span< double > >, DataStructureInfo > extract_structured_double(T &compute_data)
Extract structured double data from Datum container or direct ComputeData with automatic container ha...
static std::vector< std::span< double > > extract_numeric_data(const T &compute_data, bool needs_processig=false)
extract numeric data from multi-variant types
static auto setup_operation_buffer(T &input, std::vector< std::vector< double > > &working_buffer)
Setup operation buffer from Datum or ComputeData type.
static std::vector< Kakshya::DataVariant > to_data_variant(const T &compute_data)
Convert ComputeData to DataVariant format.
static std::span< double > extract_numeric_data(const T &compute_data)
extract numeric data from single-variant types
static Kakshya::DataVariant create_data_variant_from_eigen(const EigenType &eigen_data)
Create DataVariant from Eigen matrix/vector.
static auto extract_native_data(const EigenMatrix &matrix) -> std::vector< std::span< const typename EigenMatrix::Scalar > >
Extract native-typed column spans from any Eigen matrix.
static T reconstruct_from_double(const std::vector< std::vector< double > > &double_data, const DataStructureInfo &structure_info)
Reconstruct ComputeData type from double vector and structure info.
Universal data conversion helper for all Yantra operations.
Any Eigen matrix type, regardless of scalar type.
Definition DataSpec.hpp:101
Types that yield multiple data channels on extraction.
Definition DataSpec.hpp:83
Types that represent spatial or temporal markers requiring a container to resolve data.
Definition DataSpec.hpp:76
Types that need an associated SignalSourceContainer to extract data.
Definition DataSpec.hpp:90
Single data source: one DataVariant, a column Eigen vector of any scalar type, or any type constructi...
Definition DataSpec.hpp:110
typename detail::span_const_from_vector_variant< DataVariant >::type DataSpanVariant
Definition NDData.hpp:592
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:102
DataModality
Data modality types for cross-modal analysis.
Definition NDData.hpp:164
@ UNKNOWN
Unknown or undefined modality.
ComplexConversionStrategy
Strategy for converting complex numbers to real values.
Definition DataUtils.hpp:15
Organizes related signal regions into a categorized collection.
Represents a point or span in N-dimensional space.
Definition Region.hpp:73
DataStructureInfo(Kakshya::DataModality mod, std::vector< Kakshya::DataDimension > dims, std::type_index type)
std::vector< Kakshya::DataDimension > dimensions
Metadata about data structure for reconstruction.
Helper to detect if a type is an Datum.
Definition DataIO.hpp:329