v2.0.0
Loading...
Searching...
No Matches
inv_source_estimate_token.cpp
Go to the documentation of this file.
1//=============================================================================================================
22
23//=============================================================================================================
24// INCLUDES
25//=============================================================================================================
26
28#include "inv_source_estimate.h"
29
30#include <algorithm>
31#include <cmath>
32
33//=============================================================================================================
34// USED NAMESPACES
35//=============================================================================================================
36
37using namespace INVLIB;
38using namespace Eigen;
39
40//=============================================================================================================
41// LOCAL HELPERS — enum ↔ token mapping
42//=============================================================================================================
43
44namespace {
45
46InvTokenId methodToTokenId(InvEstimateMethod m)
47{
48 switch (m) {
61 default: return InvTokenId::MethodUnknown;
62 }
63}
64
65InvEstimateMethod tokenIdToMethod(InvTokenId id)
66{
67 switch (id) {
80 default: return InvEstimateMethod::Unknown;
81 }
82}
83
84InvTokenId spaceToTokenId(InvSourceSpaceType s)
85{
86 switch (s) {
91 default: return InvTokenId::SpaceUnknown;
92 }
93}
94
95InvSourceSpaceType tokenIdToSpace(InvTokenId id)
96{
97 switch (id) {
102 default: return InvSourceSpaceType::Unknown;
103 }
104}
105
106InvTokenId orientToTokenId(InvOrientationType o)
107{
108 switch (o) {
112 default: return InvTokenId::OrientUnknown;
113 }
114}
115
116InvOrientationType tokenIdToOrient(InvTokenId id)
117{
118 switch (id) {
122 default: return InvOrientationType::Unknown;
123 }
124}
125
126InvTokenId measureToTokenId(const std::string &m)
127{
128 if (m == "coh") return InvTokenId::MeasCoh;
129 if (m == "imcoh") return InvTokenId::MeasImCoh;
130 if (m == "plv") return InvTokenId::MeasPlv;
131 if (m == "pli") return InvTokenId::MeasPli;
132 if (m == "wpli") return InvTokenId::MeasWpli;
133 if (m == "granger") return InvTokenId::MeasGranger;
134 if (m == "pdc") return InvTokenId::MeasPdc;
135 if (m == "dtf") return InvTokenId::MeasDtf;
136 if (m == "correlation") return InvTokenId::MeasCorrelation;
137 if (m == "crosscorrelation") return InvTokenId::MeasCrossCorr;
139}
140
141std::string tokenIdToMeasure(InvTokenId id)
142{
143 switch (id) {
144 case InvTokenId::MeasCoh: return "coh";
145 case InvTokenId::MeasImCoh: return "imcoh";
146 case InvTokenId::MeasPlv: return "plv";
147 case InvTokenId::MeasPli: return "pli";
148 case InvTokenId::MeasWpli: return "wpli";
149 case InvTokenId::MeasGranger: return "granger";
150 case InvTokenId::MeasPdc: return "pdc";
151 case InvTokenId::MeasDtf: return "dtf";
152 case InvTokenId::MeasCorrelation: return "correlation";
153 case InvTokenId::MeasCrossCorr: return "crosscorrelation";
154 default: return "";
155 }
156}
157
158// Check whether a token ID falls in the method label range
159bool isMethodToken(InvTokenId id) {
160 int v = static_cast<int>(id);
161 return v >= 100 && v <= 112;
162}
163
164// Check whether a token ID falls in the source-space label range
165bool isSpaceToken(InvTokenId id) {
166 int v = static_cast<int>(id);
167 return v >= 150 && v <= 154;
168}
169
170// Check whether a token ID falls in the orientation label range
171bool isOrientToken(InvTokenId id) {
172 int v = static_cast<int>(id);
173 return v >= 170 && v <= 173;
174}
175
176// Check whether a token ID falls in the connectivity measure label range
177bool isMeasureToken(InvTokenId id) {
178 int v = static_cast<int>(id);
179 return v >= 300 && v <= 310;
180}
181
182// Compute sub-sampling stride
183int stride(int total, int max)
184{
185 if (max <= 0 || max >= total) return 1;
186 return std::max(1, total / max);
187}
188
189} // anonymous namespace
190
191namespace INVLIB
192{
193
194//=============================================================================================================
195// TOKENIZE
196//=============================================================================================================
197
198std::vector<InvToken> tokenize(const InvSourceEstimate &estimate, const InvTokenizeOptions &options)
199{
200 std::vector<InvToken> tokens;
201
202 // Rough capacity estimate to avoid excessive reallocations
203 int nSrc = static_cast<int>(estimate.data.rows());
204 int nTimes = static_cast<int>(estimate.data.cols());
205 int srcStride = stride(nSrc, options.maxSources);
206 int timeStride = stride(nTimes, options.maxTimePoints);
207 int effSrc = (nSrc + srcStride - 1) / srcStride;
208 int effTime = (nTimes + timeStride - 1) / timeStride;
209
210 size_t est = 10; // structural overhead
211 if (options.includeGridData && estimate.hasGridData())
212 est += static_cast<size_t>(effSrc) * (1 + effTime) + effSrc + 6;
213 est += estimate.focalDipoles.size() * 16;
214 est += estimate.couplings.size() * 20;
215 est += estimate.connectivity.size() * 10;
216 if (estimate.hasPositions())
217 est += static_cast<size_t>(estimate.positions.rows()) * 3 + 2;
218 tokens.reserve(est);
219
220 // --- BOS ---
221 tokens.emplace_back(InvTokenId::Bos);
222
223 // --- Metadata ---
224 tokens.emplace_back(InvTokenId::MetaBegin);
225 tokens.emplace_back(methodToTokenId(estimate.method));
226 tokens.emplace_back(spaceToTokenId(estimate.sourceSpaceType));
227 tokens.emplace_back(orientToTokenId(estimate.orientationType));
228 tokens.emplace_back(InvTokenId::MetaEnd);
229
230 // --- Grid data ---
231 if (options.includeGridData && estimate.hasGridData()) {
232 tokens.emplace_back(InvTokenId::GridBegin);
233 tokens.emplace_back(InvTokenId::NSources, static_cast<float>(effSrc));
234 tokens.emplace_back(InvTokenId::NTimes, static_cast<float>(effTime));
235 tokens.emplace_back(InvTokenId::TimeVal, estimate.tmin);
236 tokens.emplace_back(InvTokenId::TStep, estimate.tstep);
237
238 // Vertex indices
239 for (int s = 0; s < nSrc; s += srcStride)
240 tokens.emplace_back(InvTokenId::Vertex, static_cast<float>(estimate.vertices[s]));
241
242 // Amplitude data row by row
243 for (int s = 0; s < nSrc; s += srcStride) {
244 tokens.emplace_back(InvTokenId::GridRow);
245 for (int t = 0; t < nTimes; t += timeStride)
246 tokens.emplace_back(InvTokenId::Amplitude, static_cast<float>(estimate.data(s, t)));
247 }
248 tokens.emplace_back(InvTokenId::GridEnd);
249 }
250
251 // --- Positions ---
252 if (options.includePositions && estimate.hasPositions()) {
253 tokens.emplace_back(InvTokenId::PosBegin);
254 int nPos = static_cast<int>(estimate.positions.rows());
255 for (int i = 0; i < nPos; i += srcStride) {
256 tokens.emplace_back(InvTokenId::PosX, estimate.positions(i, 0));
257 tokens.emplace_back(InvTokenId::PosY, estimate.positions(i, 1));
258 tokens.emplace_back(InvTokenId::PosZ, estimate.positions(i, 2));
259 }
260 tokens.emplace_back(InvTokenId::PosEnd);
261 }
262
263 // --- Couplings ---
264 if (options.includeCouplings && estimate.hasCouplings()) {
265 tokens.emplace_back(InvTokenId::CouplingBegin);
266 tokens.emplace_back(InvTokenId::NGroups, static_cast<float>(estimate.couplings.size()));
267
268 for (const auto &grp : estimate.couplings) {
269 tokens.emplace_back(InvTokenId::GroupBegin);
270 tokens.emplace_back(InvTokenId::TimeVal, grp.tmin);
271 tokens.emplace_back(InvTokenId::TimeVal, grp.tmax);
272 tokens.emplace_back(InvTokenId::NIndices, static_cast<float>(grp.gridIndices.size()));
273
274 for (size_t k = 0; k < grp.gridIndices.size(); ++k) {
275 tokens.emplace_back(InvTokenId::GridIndex, static_cast<float>(grp.gridIndices[k]));
276 if (k < grp.moments.size()) {
277 tokens.emplace_back(InvTokenId::MomX, static_cast<float>(grp.moments[k].x()));
278 tokens.emplace_back(InvTokenId::MomY, static_cast<float>(grp.moments[k].y()));
279 tokens.emplace_back(InvTokenId::MomZ, static_cast<float>(grp.moments[k].z()));
280 }
281 }
282
283 // Upper-triangle of N×N correlation matrix
284 int n = static_cast<int>(grp.gridIndices.size());
285 for (int r = 0; r < n && r < grp.correlations.rows(); ++r)
286 for (int c = r; c < n && c < grp.correlations.cols(); ++c)
287 tokens.emplace_back(InvTokenId::Correlation, static_cast<float>(grp.correlations(r, c)));
288
289 tokens.emplace_back(InvTokenId::GroupEnd);
290 }
291 tokens.emplace_back(InvTokenId::CouplingEnd);
292 }
293
294 // --- Focal dipoles ---
295 if (options.includeFocalDipoles && estimate.hasFocalDipoles()) {
296 tokens.emplace_back(InvTokenId::FocalBegin);
297 tokens.emplace_back(InvTokenId::NDipoles, static_cast<float>(estimate.focalDipoles.size()));
298
299 for (const auto &dip : estimate.focalDipoles) {
300 tokens.emplace_back(InvTokenId::DipoleBegin);
301 tokens.emplace_back(InvTokenId::TimeVal, dip.tmin);
302 tokens.emplace_back(InvTokenId::TimeVal, dip.tmax);
303 tokens.emplace_back(InvTokenId::PosX, dip.position.x());
304 tokens.emplace_back(InvTokenId::PosY, dip.position.y());
305 tokens.emplace_back(InvTokenId::PosZ, dip.position.z());
306 tokens.emplace_back(InvTokenId::MomX, dip.moment.x());
307 tokens.emplace_back(InvTokenId::MomY, dip.moment.y());
308 tokens.emplace_back(InvTokenId::MomZ, dip.moment.z());
309 tokens.emplace_back(InvTokenId::GridIndex, static_cast<float>(dip.gridIndex));
310 tokens.emplace_back(InvTokenId::Goodness, dip.goodness);
311 tokens.emplace_back(InvTokenId::ChiSquared, dip.khi2);
312 tokens.emplace_back(InvTokenId::NFreeDof, static_cast<float>(dip.nfree));
313 tokens.emplace_back(dip.valid ? InvTokenId::ValidTrue : InvTokenId::ValidFalse);
314 tokens.emplace_back(InvTokenId::DipoleEnd);
315 }
316 tokens.emplace_back(InvTokenId::FocalEnd);
317 }
318
319 // --- Connectivity ---
320 if (options.includeConnectivity && estimate.hasConnectivity()) {
321 tokens.emplace_back(InvTokenId::ConnBegin);
322 tokens.emplace_back(InvTokenId::NMeasures, static_cast<float>(estimate.connectivity.size()));
323
324 for (const auto &conn : estimate.connectivity) {
325 tokens.emplace_back(InvTokenId::ConnEntryBegin);
326 tokens.emplace_back(measureToTokenId(conn.measure));
327 tokens.emplace_back(conn.directed ? InvTokenId::DirectedTrue : InvTokenId::DirectedFalse);
328 tokens.emplace_back(InvTokenId::FreqVal, conn.fmin);
329 tokens.emplace_back(InvTokenId::FreqVal, conn.fmax);
330 tokens.emplace_back(InvTokenId::TimeVal, conn.tmin);
331 tokens.emplace_back(InvTokenId::TimeVal, conn.tmax);
332
333 int n = static_cast<int>(conn.matrix.rows());
334 tokens.emplace_back(InvTokenId::NSources, static_cast<float>(n));
335 for (int r = 0; r < n; ++r)
336 for (int c = 0; c < n; ++c)
337 tokens.emplace_back(InvTokenId::ConnValue, static_cast<float>(conn.matrix(r, c)));
338
339 tokens.emplace_back(InvTokenId::ConnEntryEnd);
340 }
341 tokens.emplace_back(InvTokenId::ConnEnd);
342 }
343
344 // --- EOS ---
345 tokens.emplace_back(InvTokenId::Eos);
346 return tokens;
347}
348
349//=============================================================================================================
350// FROM TOKENS — reconstruct InvSourceEstimate from a token sequence
351//=============================================================================================================
352
353InvSourceEstimate fromTokens(const std::vector<InvToken> &tokens)
354{
356 size_t pos = 0;
357 const size_t len = tokens.size();
358
359 auto advance = [&]() -> const InvToken& {
360 return tokens[pos++];
361 };
362
363 auto peek = [&]() -> InvTokenId {
364 return (pos < len) ? tokens[pos].id : InvTokenId::Eos;
365 };
366
367 // Skip BOS
368 if (pos < len && tokens[pos].id == InvTokenId::Bos) ++pos;
369
370 while (pos < len && tokens[pos].id != InvTokenId::Eos) {
371 const InvToken &tok = tokens[pos];
372
373 // --- Metadata ---
374 if (tok.id == InvTokenId::MetaBegin) {
375 ++pos;
376 while (pos < len && peek() != InvTokenId::MetaEnd) {
377 if (isMethodToken(peek()))
378 est.method = tokenIdToMethod(advance().id);
379 else if (isSpaceToken(peek()))
380 est.sourceSpaceType = tokenIdToSpace(advance().id);
381 else if (isOrientToken(peek()))
382 est.orientationType = tokenIdToOrient(advance().id);
383 else
384 ++pos;
385 }
386 if (pos < len) ++pos; // skip MetaEnd
387 }
388
389 // --- Grid data ---
390 else if (tok.id == InvTokenId::GridBegin) {
391 ++pos;
392 int nSrc = 0, nTime = 0;
393 std::vector<int> verts;
394 std::vector<std::vector<float>> rows;
395
396 while (pos < len && peek() != InvTokenId::GridEnd) {
397 const InvToken &g = tokens[pos];
398
399 if (g.id == InvTokenId::NSources) {
400 nSrc = static_cast<int>(g.value); ++pos;
401 } else if (g.id == InvTokenId::NTimes) {
402 nTime = static_cast<int>(g.value); ++pos;
403 } else if (g.id == InvTokenId::TimeVal && est.tmin == 0 && est.tstep == -1) {
404 est.tmin = g.value; ++pos;
405 } else if (g.id == InvTokenId::TStep) {
406 est.tstep = g.value; ++pos;
407 } else if (g.id == InvTokenId::TimeVal) {
408 // Second TimeVal inside grid is still tmin if tstep wasn't set yet
409 ++pos;
410 } else if (g.id == InvTokenId::Vertex) {
411 verts.push_back(static_cast<int>(g.value)); ++pos;
412 } else if (g.id == InvTokenId::GridRow) {
413 ++pos;
414 std::vector<float> row;
415 while (pos < len && tokens[pos].id == InvTokenId::Amplitude) {
416 row.push_back(tokens[pos].value);
417 ++pos;
418 }
419 rows.push_back(std::move(row));
420 } else {
421 ++pos;
422 }
423 }
424 if (pos < len) ++pos; // skip GridEnd
425
426 // Fill Eigen structures
427 int effSrc = static_cast<int>(rows.size());
428 int effTime = effSrc > 0 ? static_cast<int>(rows[0].size()) : 0;
429 if (effSrc > 0 && effTime > 0) {
430 est.data = MatrixXd(effSrc, effTime);
431 for (int s = 0; s < effSrc; ++s)
432 for (int t = 0; t < effTime && t < static_cast<int>(rows[s].size()); ++t)
433 est.data(s, t) = static_cast<double>(rows[s][t]);
434 }
435 est.vertices = VectorXi(static_cast<int>(verts.size()));
436 for (int i = 0; i < static_cast<int>(verts.size()); ++i)
437 est.vertices[i] = verts[i];
438 }
439
440 // --- Positions ---
441 else if (tok.id == InvTokenId::PosBegin) {
442 ++pos;
443 std::vector<Vector3f> posVec;
444 while (pos + 2 < len && peek() != InvTokenId::PosEnd) {
445 if (tokens[pos].id == InvTokenId::PosX) {
446 Vector3f p;
447 p.x() = tokens[pos].value;
448 p.y() = tokens[pos + 1].value;
449 p.z() = tokens[pos + 2].value;
450 posVec.push_back(p);
451 pos += 3;
452 } else {
453 ++pos;
454 }
455 }
456 if (pos < len) ++pos; // skip PosEnd
457
458 est.positions = MatrixX3f(static_cast<int>(posVec.size()), 3);
459 for (int i = 0; i < static_cast<int>(posVec.size()); ++i)
460 est.positions.row(i) = posVec[i].transpose();
461 }
462
463 // --- Couplings ---
464 else if (tok.id == InvTokenId::CouplingBegin) {
465 ++pos;
466 if (pos < len && tokens[pos].id == InvTokenId::NGroups) ++pos; // skip count
467
468 while (pos < len && peek() != InvTokenId::CouplingEnd) {
469 if (peek() == InvTokenId::GroupBegin) {
470 ++pos;
472 int nIdx = 0;
473
474 while (pos < len && peek() != InvTokenId::GroupEnd) {
475 const InvToken &ct = tokens[pos];
476 if (ct.id == InvTokenId::TimeVal) {
477 if (grp.tmin == 0.0f && grp.tmax == 0.0f)
478 grp.tmin = ct.value;
479 else
480 grp.tmax = ct.value;
481 ++pos;
482 } else if (ct.id == InvTokenId::NIndices) {
483 nIdx = static_cast<int>(ct.value); ++pos;
484 } else if (ct.id == InvTokenId::GridIndex) {
485 grp.gridIndices.push_back(static_cast<int>(ct.value)); ++pos;
486 } else if (ct.id == InvTokenId::MomX && pos + 2 < len) {
487 Vector3d m;
488 m.x() = static_cast<double>(tokens[pos].value);
489 m.y() = static_cast<double>(tokens[pos + 1].value);
490 m.z() = static_cast<double>(tokens[pos + 2].value);
491 grp.moments.push_back(m);
492 pos += 3;
493 } else if (ct.id == InvTokenId::Correlation) {
494 // Reconstruct upper-triangle
495 int n = static_cast<int>(grp.gridIndices.size());
496 if (n > 0 && grp.correlations.size() == 0) {
497 grp.correlations = MatrixXd::Zero(n, n);
498 for (int r = 0; r < n; ++r) {
499 for (int c = r; c < n && pos < len && tokens[pos].id == InvTokenId::Correlation; ++c) {
500 double v = static_cast<double>(tokens[pos].value);
501 grp.correlations(r, c) = v;
502 grp.correlations(c, r) = v;
503 ++pos;
504 }
505 }
506 } else {
507 ++pos;
508 }
509 } else {
510 ++pos;
511 }
512 }
513 if (pos < len) ++pos; // skip GroupEnd
514 est.couplings.push_back(std::move(grp));
515 } else {
516 ++pos;
517 }
518 }
519 if (pos < len) ++pos; // skip CouplingEnd
520 }
521
522 // --- Focal dipoles ---
523 else if (tok.id == InvTokenId::FocalBegin) {
524 ++pos;
525 if (pos < len && tokens[pos].id == InvTokenId::NDipoles) ++pos;
526
527 while (pos < len && peek() != InvTokenId::FocalEnd) {
528 if (peek() == InvTokenId::DipoleBegin) {
529 ++pos;
530 InvFocalDipole dip;
531 int timeIdx = 0;
532
533 while (pos < len && peek() != InvTokenId::DipoleEnd) {
534 const InvToken &dt = tokens[pos];
535 if (dt.id == InvTokenId::TimeVal) {
536 if (timeIdx == 0) dip.tmin = dt.value;
537 else dip.tmax = dt.value;
538 ++timeIdx; ++pos;
539 } else if (dt.id == InvTokenId::PosX) { dip.position.x() = dt.value; ++pos; }
540 else if (dt.id == InvTokenId::PosY) { dip.position.y() = dt.value; ++pos; }
541 else if (dt.id == InvTokenId::PosZ) { dip.position.z() = dt.value; ++pos; }
542 else if (dt.id == InvTokenId::MomX) { dip.moment.x() = dt.value; ++pos; }
543 else if (dt.id == InvTokenId::MomY) { dip.moment.y() = dt.value; ++pos; }
544 else if (dt.id == InvTokenId::MomZ) { dip.moment.z() = dt.value; ++pos; }
545 else if (dt.id == InvTokenId::GridIndex) { dip.gridIndex = static_cast<int>(dt.value); ++pos; }
546 else if (dt.id == InvTokenId::Goodness) { dip.goodness = dt.value; ++pos; }
547 else if (dt.id == InvTokenId::ChiSquared){ dip.khi2 = dt.value; ++pos; }
548 else if (dt.id == InvTokenId::NFreeDof) { dip.nfree = static_cast<int>(dt.value); ++pos; }
549 else if (dt.id == InvTokenId::ValidTrue) { dip.valid = true; ++pos; }
550 else if (dt.id == InvTokenId::ValidFalse){ dip.valid = false; ++pos; }
551 else { ++pos; }
552 }
553 if (pos < len) ++pos; // skip DipoleEnd
554 est.focalDipoles.push_back(dip);
555 } else {
556 ++pos;
557 }
558 }
559 if (pos < len) ++pos; // skip FocalEnd
560 }
561
562 // --- Connectivity ---
563 else if (tok.id == InvTokenId::ConnBegin) {
564 ++pos;
565 if (pos < len && tokens[pos].id == InvTokenId::NMeasures) ++pos;
566
567 while (pos < len && peek() != InvTokenId::ConnEnd) {
568 if (peek() == InvTokenId::ConnEntryBegin) {
569 ++pos;
570 InvConnectivity conn;
571 int n = 0;
572 int freqIdx = 0, timeIdx = 0;
573
574 while (pos < len && peek() != InvTokenId::ConnEntryEnd) {
575 const InvToken &ct = tokens[pos];
576 if (isMeasureToken(ct.id)) {
577 conn.measure = tokenIdToMeasure(ct.id); ++pos;
578 } else if (ct.id == InvTokenId::DirectedTrue) { conn.directed = true; ++pos; }
579 else if (ct.id == InvTokenId::DirectedFalse) { conn.directed = false; ++pos; }
580 else if (ct.id == InvTokenId::FreqVal) {
581 if (freqIdx == 0) conn.fmin = ct.value;
582 else conn.fmax = ct.value;
583 ++freqIdx; ++pos;
584 } else if (ct.id == InvTokenId::TimeVal) {
585 if (timeIdx == 0) conn.tmin = ct.value;
586 else conn.tmax = ct.value;
587 ++timeIdx; ++pos;
588 } else if (ct.id == InvTokenId::NSources) {
589 n = static_cast<int>(ct.value); ++pos;
590 } else if (ct.id == InvTokenId::ConnValue && n > 0) {
591 conn.matrix = MatrixXd(n, n);
592 for (int r = 0; r < n; ++r)
593 for (int c = 0; c < n && pos < len && tokens[pos].id == InvTokenId::ConnValue; ++c, ++pos)
594 conn.matrix(r, c) = static_cast<double>(tokens[pos].value);
595 } else {
596 ++pos;
597 }
598 }
599 if (pos < len) ++pos; // skip ConnEntryEnd
600 est.connectivity.push_back(std::move(conn));
601 } else {
602 ++pos;
603 }
604 }
605 if (pos < len) ++pos; // skip ConnEnd
606 }
607
608 else {
609 ++pos; // skip unrecognised tokens
610 }
611 }
612
613 // Rebuild times vector
614 if (est.data.cols() > 0 && est.tstep > 0) {
615 est.times = RowVectorXf(est.data.cols());
616 est.times[0] = est.tmin;
617 for (int i = 1; i < est.times.size(); ++i)
618 est.times[i] = est.times[i - 1] + est.tstep;
619 }
620
621 return est;
622}
623
624} // namespace INVLIB
Tokeniser and de-tokeniser that turn an INVLIB::InvSourceEstimate into a flat sequence consumable by ...
InvSourceEstimate value type — central source-space data container produced by every INVLIB inverse s...
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
InvEstimateMethod
Definition inv_types.h:37
InvSourceEstimate fromTokens(const std::vector< InvToken > &tokens)
Reconstruct an InvSourceEstimate from a token sequence.
InvOrientationType
Definition inv_types.h:71
InvSourceSpaceType
Definition inv_types.h:58
std::vector< InvToken > tokenize(const InvSourceEstimate &estimate, const InvTokenizeOptions &options)
Serialise an InvSourceEstimate into a flat token sequence.
Pairwise source connectivity matrix with measure, directionality, and frequency/time metadata.
Single focal dipole with free 3D position, moment, and fit-quality metrics.
N-tuple of correlated grid sources with orientations and correlation matrix.
std::vector< Eigen::Vector3d > moments
Source-space inverse-solution container with dense grid plus optional focal-dipole,...
std::vector< InvSourceCoupling > couplings
std::vector< InvFocalDipole > focalDipoles
InvSourceSpaceType sourceSpaceType
InvOrientationType orientationType
std::vector< InvConnectivity > connectivity
One element of a tokenised neural-source representation.
Definition inv_token.h:187
InvTokenId id
Definition inv_token.h:188
Tokenization options controlling layer inclusion and sub-sampling.
Definition inv_token.h:206