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