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
203//=============================================================================================================
204// TOKENIZE
205//=============================================================================================================
206
207std::vector<InvToken> tokenize(const InvSourceEstimate &estimate, const InvTokenizeOptions &options)
208{
209 std::vector<InvToken> tokens;
210
211 // Rough capacity estimate to avoid excessive reallocations
212 int nSrc = static_cast<int>(estimate.data.rows());
213 int nTimes = static_cast<int>(estimate.data.cols());
214 int srcStride = stride(nSrc, options.maxSources);
215 int timeStride = stride(nTimes, options.maxTimePoints);
216 int effSrc = (nSrc + srcStride - 1) / srcStride;
217 int effTime = (nTimes + timeStride - 1) / timeStride;
218
219 size_t est = 10; // structural overhead
220 if (options.includeGridData && estimate.hasGridData())
221 est += static_cast<size_t>(effSrc) * (1 + effTime) + effSrc + 6;
222 est += estimate.focalDipoles.size() * 16;
223 est += estimate.couplings.size() * 20;
224 est += estimate.connectivity.size() * 10;
225 if (estimate.hasPositions())
226 est += static_cast<size_t>(estimate.positions.rows()) * 3 + 2;
227 tokens.reserve(est);
228
229 // --- BOS ---
230 tokens.emplace_back(InvTokenId::Bos);
231
232 // --- Metadata ---
233 tokens.emplace_back(InvTokenId::MetaBegin);
234 tokens.emplace_back(methodToTokenId(estimate.method));
235 tokens.emplace_back(spaceToTokenId(estimate.sourceSpaceType));
236 tokens.emplace_back(orientToTokenId(estimate.orientationType));
237 tokens.emplace_back(InvTokenId::MetaEnd);
238
239 // --- Grid data ---
240 if (options.includeGridData && estimate.hasGridData()) {
241 tokens.emplace_back(InvTokenId::GridBegin);
242 tokens.emplace_back(InvTokenId::NSources, static_cast<float>(effSrc));
243 tokens.emplace_back(InvTokenId::NTimes, static_cast<float>(effTime));
244 tokens.emplace_back(InvTokenId::TimeVal, estimate.tmin);
245 tokens.emplace_back(InvTokenId::TStep, estimate.tstep);
246
247 // Vertex indices
248 for (int s = 0; s < nSrc; s += srcStride)
249 tokens.emplace_back(InvTokenId::Vertex, static_cast<float>(estimate.vertices[s]));
250
251 // Amplitude data row by row
252 for (int s = 0; s < nSrc; s += srcStride) {
253 tokens.emplace_back(InvTokenId::GridRow);
254 for (int t = 0; t < nTimes; t += timeStride)
255 tokens.emplace_back(InvTokenId::Amplitude, static_cast<float>(estimate.data(s, t)));
256 }
257 tokens.emplace_back(InvTokenId::GridEnd);
258 }
259
260 // --- Positions ---
261 if (options.includePositions && estimate.hasPositions()) {
262 tokens.emplace_back(InvTokenId::PosBegin);
263 int nPos = static_cast<int>(estimate.positions.rows());
264 for (int i = 0; i < nPos; i += srcStride) {
265 tokens.emplace_back(InvTokenId::PosX, estimate.positions(i, 0));
266 tokens.emplace_back(InvTokenId::PosY, estimate.positions(i, 1));
267 tokens.emplace_back(InvTokenId::PosZ, estimate.positions(i, 2));
268 }
269 tokens.emplace_back(InvTokenId::PosEnd);
270 }
271
272 // --- Couplings ---
273 if (options.includeCouplings && estimate.hasCouplings()) {
274 tokens.emplace_back(InvTokenId::CouplingBegin);
275 tokens.emplace_back(InvTokenId::NGroups, static_cast<float>(estimate.couplings.size()));
276
277 for (const auto &grp : estimate.couplings) {
278 tokens.emplace_back(InvTokenId::GroupBegin);
279 tokens.emplace_back(InvTokenId::TimeVal, grp.tmin);
280 tokens.emplace_back(InvTokenId::TimeVal, grp.tmax);
281 tokens.emplace_back(InvTokenId::NIndices, static_cast<float>(grp.gridIndices.size()));
282
283 for (size_t k = 0; k < grp.gridIndices.size(); ++k) {
284 tokens.emplace_back(InvTokenId::GridIndex, static_cast<float>(grp.gridIndices[k]));
285 if (k < grp.moments.size()) {
286 tokens.emplace_back(InvTokenId::MomX, static_cast<float>(grp.moments[k].x()));
287 tokens.emplace_back(InvTokenId::MomY, static_cast<float>(grp.moments[k].y()));
288 tokens.emplace_back(InvTokenId::MomZ, static_cast<float>(grp.moments[k].z()));
289 }
290 }
291
292 // Upper-triangle of N×N correlation matrix
293 int n = static_cast<int>(grp.gridIndices.size());
294 for (int r = 0; r < n && r < grp.correlations.rows(); ++r)
295 for (int c = r; c < n && c < grp.correlations.cols(); ++c)
296 tokens.emplace_back(InvTokenId::Correlation, static_cast<float>(grp.correlations(r, c)));
297
298 tokens.emplace_back(InvTokenId::GroupEnd);
299 }
300 tokens.emplace_back(InvTokenId::CouplingEnd);
301 }
302
303 // --- Focal dipoles ---
304 if (options.includeFocalDipoles && estimate.hasFocalDipoles()) {
305 tokens.emplace_back(InvTokenId::FocalBegin);
306 tokens.emplace_back(InvTokenId::NDipoles, static_cast<float>(estimate.focalDipoles.size()));
307
308 for (const auto &dip : estimate.focalDipoles) {
309 tokens.emplace_back(InvTokenId::DipoleBegin);
310 tokens.emplace_back(InvTokenId::TimeVal, dip.tmin);
311 tokens.emplace_back(InvTokenId::TimeVal, dip.tmax);
312 tokens.emplace_back(InvTokenId::PosX, dip.position.x());
313 tokens.emplace_back(InvTokenId::PosY, dip.position.y());
314 tokens.emplace_back(InvTokenId::PosZ, dip.position.z());
315 tokens.emplace_back(InvTokenId::MomX, dip.moment.x());
316 tokens.emplace_back(InvTokenId::MomY, dip.moment.y());
317 tokens.emplace_back(InvTokenId::MomZ, dip.moment.z());
318 tokens.emplace_back(InvTokenId::GridIndex, static_cast<float>(dip.gridIndex));
319 tokens.emplace_back(InvTokenId::Goodness, dip.goodness);
320 tokens.emplace_back(InvTokenId::ChiSquared, dip.khi2);
321 tokens.emplace_back(InvTokenId::NFreeDof, static_cast<float>(dip.nfree));
322 tokens.emplace_back(dip.valid ? InvTokenId::ValidTrue : InvTokenId::ValidFalse);
323 tokens.emplace_back(InvTokenId::DipoleEnd);
324 }
325 tokens.emplace_back(InvTokenId::FocalEnd);
326 }
327
328 // --- Connectivity ---
329 if (options.includeConnectivity && estimate.hasConnectivity()) {
330 tokens.emplace_back(InvTokenId::ConnBegin);
331 tokens.emplace_back(InvTokenId::NMeasures, static_cast<float>(estimate.connectivity.size()));
332
333 for (const auto &conn : estimate.connectivity) {
334 tokens.emplace_back(InvTokenId::ConnEntryBegin);
335 tokens.emplace_back(measureToTokenId(conn.measure));
336 tokens.emplace_back(conn.directed ? InvTokenId::DirectedTrue : InvTokenId::DirectedFalse);
337 tokens.emplace_back(InvTokenId::FreqVal, conn.fmin);
338 tokens.emplace_back(InvTokenId::FreqVal, conn.fmax);
339 tokens.emplace_back(InvTokenId::TimeVal, conn.tmin);
340 tokens.emplace_back(InvTokenId::TimeVal, conn.tmax);
341
342 int n = static_cast<int>(conn.matrix.rows());
343 tokens.emplace_back(InvTokenId::NSources, static_cast<float>(n));
344 for (int r = 0; r < n; ++r)
345 for (int c = 0; c < n; ++c)
346 tokens.emplace_back(InvTokenId::ConnValue, static_cast<float>(conn.matrix(r, c)));
347
348 tokens.emplace_back(InvTokenId::ConnEntryEnd);
349 }
350 tokens.emplace_back(InvTokenId::ConnEnd);
351 }
352
353 // --- EOS ---
354 tokens.emplace_back(InvTokenId::Eos);
355 return tokens;
356}
357
358//=============================================================================================================
359// FROM TOKENS — reconstruct InvSourceEstimate from a token sequence
360//=============================================================================================================
361
362InvSourceEstimate fromTokens(const std::vector<InvToken> &tokens)
363{
365 size_t pos = 0;
366 const size_t len = tokens.size();
367
368 auto advance = [&]() -> const InvToken& {
369 return tokens[pos++];
370 };
371
372 auto peek = [&]() -> InvTokenId {
373 return (pos < len) ? tokens[pos].id : InvTokenId::Eos;
374 };
375
376 // Skip BOS
377 if (pos < len && tokens[pos].id == InvTokenId::Bos) ++pos;
378
379 while (pos < len && tokens[pos].id != InvTokenId::Eos) {
380 const InvToken &tok = tokens[pos];
381
382 // --- Metadata ---
383 if (tok.id == InvTokenId::MetaBegin) {
384 ++pos;
385 while (pos < len && peek() != InvTokenId::MetaEnd) {
386 if (isMethodToken(peek()))
387 est.method = tokenIdToMethod(advance().id);
388 else if (isSpaceToken(peek()))
389 est.sourceSpaceType = tokenIdToSpace(advance().id);
390 else if (isOrientToken(peek()))
391 est.orientationType = tokenIdToOrient(advance().id);
392 else
393 ++pos;
394 }
395 if (pos < len) ++pos; // skip MetaEnd
396 }
397
398 // --- Grid data ---
399 else if (tok.id == InvTokenId::GridBegin) {
400 ++pos;
401 int nSrc = 0, nTime = 0;
402 std::vector<int> verts;
403 std::vector<std::vector<float>> rows;
404
405 while (pos < len && peek() != InvTokenId::GridEnd) {
406 const InvToken &g = tokens[pos];
407
408 if (g.id == InvTokenId::NSources) {
409 nSrc = static_cast<int>(g.value); ++pos;
410 } else if (g.id == InvTokenId::NTimes) {
411 nTime = static_cast<int>(g.value); ++pos;
412 } else if (g.id == InvTokenId::TimeVal && est.tmin == 0 && est.tstep == -1) {
413 est.tmin = g.value; ++pos;
414 } else if (g.id == InvTokenId::TStep) {
415 est.tstep = g.value; ++pos;
416 } else if (g.id == InvTokenId::TimeVal) {
417 // Second TimeVal inside grid is still tmin if tstep wasn't set yet
418 ++pos;
419 } else if (g.id == InvTokenId::Vertex) {
420 verts.push_back(static_cast<int>(g.value)); ++pos;
421 } else if (g.id == InvTokenId::GridRow) {
422 ++pos;
423 std::vector<float> row;
424 while (pos < len && tokens[pos].id == InvTokenId::Amplitude) {
425 row.push_back(tokens[pos].value);
426 ++pos;
427 }
428 rows.push_back(std::move(row));
429 } else {
430 ++pos;
431 }
432 }
433 if (pos < len) ++pos; // skip GridEnd
434
435 // Fill Eigen structures
436 int effSrc = static_cast<int>(rows.size());
437 int effTime = effSrc > 0 ? static_cast<int>(rows[0].size()) : 0;
438 if (effSrc > 0 && effTime > 0) {
439 est.data = MatrixXd(effSrc, effTime);
440 for (int s = 0; s < effSrc; ++s)
441 for (int t = 0; t < effTime && t < static_cast<int>(rows[s].size()); ++t)
442 est.data(s, t) = static_cast<double>(rows[s][t]);
443 }
444 est.vertices = VectorXi(static_cast<int>(verts.size()));
445 for (int i = 0; i < static_cast<int>(verts.size()); ++i)
446 est.vertices[i] = verts[i];
447 }
448
449 // --- Positions ---
450 else if (tok.id == InvTokenId::PosBegin) {
451 ++pos;
452 std::vector<Vector3f> posVec;
453 while (pos + 2 < len && peek() != InvTokenId::PosEnd) {
454 if (tokens[pos].id == InvTokenId::PosX) {
455 Vector3f p;
456 p.x() = tokens[pos].value;
457 p.y() = tokens[pos + 1].value;
458 p.z() = tokens[pos + 2].value;
459 posVec.push_back(p);
460 pos += 3;
461 } else {
462 ++pos;
463 }
464 }
465 if (pos < len) ++pos; // skip PosEnd
466
467 est.positions = MatrixX3f(static_cast<int>(posVec.size()), 3);
468 for (int i = 0; i < static_cast<int>(posVec.size()); ++i)
469 est.positions.row(i) = posVec[i].transpose();
470 }
471
472 // --- Couplings ---
473 else if (tok.id == InvTokenId::CouplingBegin) {
474 ++pos;
475 if (pos < len && tokens[pos].id == InvTokenId::NGroups) ++pos; // skip count
476
477 while (pos < len && peek() != InvTokenId::CouplingEnd) {
478 if (peek() == InvTokenId::GroupBegin) {
479 ++pos;
481 int nIdx = 0;
482
483 while (pos < len && peek() != InvTokenId::GroupEnd) {
484 const InvToken &ct = tokens[pos];
485 if (ct.id == InvTokenId::TimeVal) {
486 if (grp.tmin == 0.0f && grp.tmax == 0.0f)
487 grp.tmin = ct.value;
488 else
489 grp.tmax = ct.value;
490 ++pos;
491 } else if (ct.id == InvTokenId::NIndices) {
492 nIdx = static_cast<int>(ct.value); ++pos;
493 } else if (ct.id == InvTokenId::GridIndex) {
494 grp.gridIndices.push_back(static_cast<int>(ct.value)); ++pos;
495 } else if (ct.id == InvTokenId::MomX && pos + 2 < len) {
496 Vector3d m;
497 m.x() = static_cast<double>(tokens[pos].value);
498 m.y() = static_cast<double>(tokens[pos + 1].value);
499 m.z() = static_cast<double>(tokens[pos + 2].value);
500 grp.moments.push_back(m);
501 pos += 3;
502 } else if (ct.id == InvTokenId::Correlation) {
503 // Reconstruct upper-triangle
504 int n = static_cast<int>(grp.gridIndices.size());
505 if (n > 0 && grp.correlations.size() == 0) {
506 grp.correlations = MatrixXd::Zero(n, n);
507 for (int r = 0; r < n; ++r) {
508 for (int c = r; c < n && pos < len && tokens[pos].id == InvTokenId::Correlation; ++c) {
509 double v = static_cast<double>(tokens[pos].value);
510 grp.correlations(r, c) = v;
511 grp.correlations(c, r) = v;
512 ++pos;
513 }
514 }
515 } else {
516 ++pos;
517 }
518 } else {
519 ++pos;
520 }
521 }
522 if (pos < len) ++pos; // skip GroupEnd
523 est.couplings.push_back(std::move(grp));
524 } else {
525 ++pos;
526 }
527 }
528 if (pos < len) ++pos; // skip CouplingEnd
529 }
530
531 // --- Focal dipoles ---
532 else if (tok.id == InvTokenId::FocalBegin) {
533 ++pos;
534 if (pos < len && tokens[pos].id == InvTokenId::NDipoles) ++pos;
535
536 while (pos < len && peek() != InvTokenId::FocalEnd) {
537 if (peek() == InvTokenId::DipoleBegin) {
538 ++pos;
539 InvFocalDipole dip;
540 int timeIdx = 0;
541
542 while (pos < len && peek() != InvTokenId::DipoleEnd) {
543 const InvToken &dt = tokens[pos];
544 if (dt.id == InvTokenId::TimeVal) {
545 if (timeIdx == 0) dip.tmin = dt.value;
546 else dip.tmax = dt.value;
547 ++timeIdx; ++pos;
548 } else if (dt.id == InvTokenId::PosX) { dip.position.x() = dt.value; ++pos; }
549 else if (dt.id == InvTokenId::PosY) { dip.position.y() = dt.value; ++pos; }
550 else if (dt.id == InvTokenId::PosZ) { dip.position.z() = dt.value; ++pos; }
551 else if (dt.id == InvTokenId::MomX) { dip.moment.x() = dt.value; ++pos; }
552 else if (dt.id == InvTokenId::MomY) { dip.moment.y() = dt.value; ++pos; }
553 else if (dt.id == InvTokenId::MomZ) { dip.moment.z() = dt.value; ++pos; }
554 else if (dt.id == InvTokenId::GridIndex) { dip.gridIndex = static_cast<int>(dt.value); ++pos; }
555 else if (dt.id == InvTokenId::Goodness) { dip.goodness = dt.value; ++pos; }
556 else if (dt.id == InvTokenId::ChiSquared){ dip.khi2 = dt.value; ++pos; }
557 else if (dt.id == InvTokenId::NFreeDof) { dip.nfree = static_cast<int>(dt.value); ++pos; }
558 else if (dt.id == InvTokenId::ValidTrue) { dip.valid = true; ++pos; }
559 else if (dt.id == InvTokenId::ValidFalse){ dip.valid = false; ++pos; }
560 else { ++pos; }
561 }
562 if (pos < len) ++pos; // skip DipoleEnd
563 est.focalDipoles.push_back(dip);
564 } else {
565 ++pos;
566 }
567 }
568 if (pos < len) ++pos; // skip FocalEnd
569 }
570
571 // --- Connectivity ---
572 else if (tok.id == InvTokenId::ConnBegin) {
573 ++pos;
574 if (pos < len && tokens[pos].id == InvTokenId::NMeasures) ++pos;
575
576 while (pos < len && peek() != InvTokenId::ConnEnd) {
577 if (peek() == InvTokenId::ConnEntryBegin) {
578 ++pos;
579 InvConnectivity conn;
580 int n = 0;
581 int freqIdx = 0, timeIdx = 0;
582
583 while (pos < len && peek() != InvTokenId::ConnEntryEnd) {
584 const InvToken &ct = tokens[pos];
585 if (isMeasureToken(ct.id)) {
586 conn.measure = tokenIdToMeasure(ct.id); ++pos;
587 } else if (ct.id == InvTokenId::DirectedTrue) { conn.directed = true; ++pos; }
588 else if (ct.id == InvTokenId::DirectedFalse) { conn.directed = false; ++pos; }
589 else if (ct.id == InvTokenId::FreqVal) {
590 if (freqIdx == 0) conn.fmin = ct.value;
591 else conn.fmax = ct.value;
592 ++freqIdx; ++pos;
593 } else if (ct.id == InvTokenId::TimeVal) {
594 if (timeIdx == 0) conn.tmin = ct.value;
595 else conn.tmax = ct.value;
596 ++timeIdx; ++pos;
597 } else if (ct.id == InvTokenId::NSources) {
598 n = static_cast<int>(ct.value); ++pos;
599 } else if (ct.id == InvTokenId::ConnValue && n > 0) {
600 conn.matrix = MatrixXd(n, n);
601 for (int r = 0; r < n; ++r)
602 for (int c = 0; c < n && pos < len && tokens[pos].id == InvTokenId::ConnValue; ++c, ++pos)
603 conn.matrix(r, c) = static_cast<double>(tokens[pos].value);
604 } else {
605 ++pos;
606 }
607 }
608 if (pos < len) ++pos; // skip ConnEntryEnd
609 est.connectivity.push_back(std::move(conn));
610 } else {
611 ++pos;
612 }
613 }
614 if (pos < len) ++pos; // skip ConnEnd
615 }
616
617 else {
618 ++pos; // skip unrecognised tokens
619 }
620 }
621
622 // Rebuild times vector
623 if (est.data.cols() > 0 && est.tstep > 0) {
624 est.times = RowVectorXf(est.data.cols());
625 est.times[0] = est.tmin;
626 for (int i = 1; i < est.times.size(); ++i)
627 est.times[i] = est.times[i - 1] + est.tstep;
628 }
629
630 return est;
631}
Tokenization and de-tokenization of InvSourceEstimate for foundation-model interfacing.
std::vector< InvToken > tokenize(const InvSourceEstimate &estimate, const InvTokenizeOptions &options)
InvSourceEstimate fromTokens(const std::vector< InvToken > &tokens)
InvSourceEstimate class declaration.
Inverse source estimation (MNE, dSPM, sLORETA, dipole fitting).
InvEstimateMethod
Definition inv_types.h:50
InvOrientationType
Definition inv_types.h:84
InvSourceSpaceType
Definition inv_types.h:71
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