43#include <QCryptographicHash>
45#include <QElapsedTimer>
47#include <QTemporaryFile>
71 const QVariantMap& graphInputs)
77 for (
auto it = graphInputs.constBegin(); it != graphInputs.constEnd(); ++it) {
78 ctx.
results.insert(QStringLiteral(
"graph::") + it.key(), it.value());
83 applyParamTree(graph);
86 const int total = order.size();
88 for (
int i = 0; i < total; ++i) {
89 const QString& nodeId = order[i];
91 if (s_progressCallback) {
92 s_progressCallback(nodeId, i + 1, total);
95 if (!runNode(graph, graph.
node(nodeId), ctx)) {
113 QSet<QString> toExecute;
114 for (
const QString& nodeId : dirty) {
115 toExecute.insert(nodeId);
117 for (
const QString& d : downstream) {
122 applyParamTree(graph);
127 for (
const QString& nodeId : fullOrder) {
128 if (toExecute.contains(nodeId)) {
129 order.append(nodeId);
133 const int total = order.size();
135 for (
int i = 0; i < total; ++i) {
136 const QString& nodeId = order[i];
138 if (s_progressCallback) {
139 s_progressCallback(nodeId, i + 1, total);
142 if (!runNode(graph, graph.
node(nodeId), existing)) {
154void MnaGraphExecutor::applyParamTree(
MnaGraph& graph)
158 const int sep = path.indexOf(QLatin1Char(
'/'));
159 if (sep > 0 && graph.
hasNode(path.left(sep))) {
167bool MnaGraphExecutor::runNode(
MnaGraph& graph,
MnaNode& node, Context& ctx)
170 for (
const MnaPort& p : node.
inputs) {
177 scope.insert(inputs);
180 MnaProvenance& provenance = verification.
provenance;
181 provenance = MnaProvenance();
183 provenance.
qtVersion = QString::fromLatin1(qVersion());
184 provenance.
osInfo = QSysInfo::prettyProductName() + QLatin1Char(
' ') + QSysInfo::currentCpuArchitecture();
185 provenance.
hostName = QSysInfo::machineHostName();
187 for (
auto it = inputs.constBegin(); it != inputs.constEnd(); ++it) {
188 provenance.
inputHashes.insert(it.key(), QString::fromLatin1(QCryptographicHash::hash(it.value().toString().toUtf8(), QCryptographicHash::Sha256).toHex()));
191 const auto failsHard = [](
const QList<MnaVerificationResult>& results) {
192 return std::any_of(results.cbegin(), results.cend(), [](
const MnaVerificationResult& r) {
193 return !r.passed && r.severity == QLatin1String(
"error");
196 verification.
preResults = runChecks(graph, node, QStringLiteral(
"pre"), scope);
199 ctx.abortedNode = node.
id;
203 provenance.
startedAt = QDateTime::currentDateTimeUtc();
206 const QVariantMap outputs =
executeNode(node, inputs);
208 provenance.
finishedAt = QDateTime::currentDateTimeUtc();
210 for (
auto it = outputs.constBegin(); it != outputs.constEnd(); ++it) {
211 ctx.results.insert(node.
id + QStringLiteral(
"::") + it.key(), it.value());
216 scope.insert(outputs);
217 verification.
postResults = runChecks(graph, node, QStringLiteral(
"post"), scope);
219 ctx.abortedNode = node.
id;
227QList<MnaVerificationResult> MnaGraphExecutor::runChecks(
const MnaGraph& graph,
const MnaNode& node,
const QString& phase,
const QVariantMap& scope)
229 QList<MnaVerificationResult> results;
231 if (check.
phase != phase) {
234 MnaVerificationResult result;
237 result.
evaluatedAt = QDateTime::currentDateTimeUtc();
239 MnaNode scriptNode = node;
242 const QVariantMap out =
executeNode(scriptNode, scope);
243 result.
actualValue = out.value(QStringLiteral(
"exit_code"));
254 results.append(result);
262 const QVariantMap& inputs)
268 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"Script execution not supported in WebAssembly build (QProcess unavailable)"));
269 outputs.insert(QStringLiteral(
"exit_code"), -1);
275 QString ext = QStringLiteral(
".txt");
276 if (script.
language == QLatin1String(
"python"))
277 ext = QStringLiteral(
".py");
278 else if (script.
language == QLatin1String(
"shell"))
279 ext = QStringLiteral(
".sh");
280 else if (script.
language == QLatin1String(
"r"))
281 ext = QStringLiteral(
".R");
282 else if (script.
language == QLatin1String(
"matlab"))
283 ext = QStringLiteral(
".m");
284 else if (script.
language == QLatin1String(
"octave"))
285 ext = QStringLiteral(
".m");
286 else if (script.
language == QLatin1String(
"julia"))
287 ext = QStringLiteral(
".jl");
290 QString code = script.
code;
291 for (
auto it = inputs.constBegin(); it != inputs.constEnd(); ++it) {
292 code.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
293 it.value().toString());
296 code.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
297 it.value().toString());
301 QTemporaryFile tempFile(QDir::tempPath() + QStringLiteral(
"/mna_script_XXXXXX") + ext);
303 if (!tempFile.open()) {
305 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"Failed to create temporary script file"));
306 outputs.insert(QStringLiteral(
"exit_code"), -1);
309 tempFile.write(code.toUtf8());
314 if (interpreter.isEmpty()) {
315 if (script.
language == QLatin1String(
"python"))
316 interpreter = QStringLiteral(
"python3");
317 else if (script.
language == QLatin1String(
"shell"))
318 interpreter = QStringLiteral(
"/bin/bash");
319 else if (script.
language == QLatin1String(
"r"))
320 interpreter = QStringLiteral(
"Rscript");
321 else if (script.
language == QLatin1String(
"matlab"))
322 interpreter = QStringLiteral(
"matlab");
323 else if (script.
language == QLatin1String(
"octave"))
324 interpreter = QStringLiteral(
"octave");
325 else if (script.
language == QLatin1String(
"julia"))
326 interpreter = QStringLiteral(
"julia");
330 args.append(tempFile.fileName());
333 process.start(interpreter, args);
334 process.waitForFinished(-1);
337 outputs.insert(QStringLiteral(
"stdout"), QString::fromUtf8(process.readAllStandardOutput()));
338 outputs.insert(QStringLiteral(
"stderr"), QString::fromUtf8(process.readAllStandardError()));
339 outputs.insert(QStringLiteral(
"exit_code"), process.exitCode());
349 outputs.insert(QStringLiteral(
"stderr"), QStringLiteral(
"IPC execution not supported in WebAssembly build (QProcess unavailable)"));
350 outputs.insert(QStringLiteral(
"exit_code"), -1);
359 QStringList resolvedArgs;
360 for (
const QString& arg : node.
ipcArgs) {
361 QString resolved = arg;
362 for (
auto it = inputs.constBegin(); it != inputs.constEnd(); ++it) {
363 resolved.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
364 it.value().toString());
368 resolved.replace(QStringLiteral(
"{{") + it.key() + QStringLiteral(
"}}"),
369 it.value().toString());
371 resolvedArgs.append(resolved);
375 process.waitForFinished(-1);
378 outputs.insert(QStringLiteral(
"stdout"), QString::fromUtf8(process.readAllStandardOutput()));
379 outputs.insert(QStringLiteral(
"stderr"), QString::fromUtf8(process.readAllStandardError()));
380 outputs.insert(QStringLiteral(
"exit_code"), process.exitCode());
409 s_progressCallback = cb;
425 qWarning() <<
"MnaGraphExecutor::startStream - graph validation failed:" << errors;
433 applyParamTree(graph);
438 QObject* plugin = factory(n.
opType);
440 qWarning() <<
"MnaGraphExecutor::startStream - factory returned nullptr for opType:" << n.
opType;
In-memory directed acyclic graph of MNALIB::MnaNode operations — connectivity, validation,...
Stateless executor that runs an MNALIB::MnaGraph in topological order, in batch or stream mode,...
Process-wide singleton catalog mapping opType strings to their MNALIB::MnaOpSchema and (for built-in ...
MNE Analysis Container Format (mna/mnx).
@ Ipc
Delegates to an external process via inter-process communication.
@ Script
Inline code executed via interpreter (Python, shell, R, …).
In-memory DAG of MnaNode operations with validation, topological sort and JSON/CBOR persistence.
MnaNode & node(const QString &nodeId)
bool validate(QStringList *errors=nullptr) const
QStringList dirtyNodes() const
bool hasNode(const QString &nodeId) const
QStringList downstreamNodes(const QString &nodeId) const
MnaParamTree paramTree
Hierarchical parameter store with formula-driven bindings.
QStringList topologicalSort() const
static void setProgressCallback(ProgressCallback cb)
static Context executeIncremental(MnaGraph &graph, Context &existing)
static StreamContext startStream(MnaGraph &graph, PluginFactory factory)
static QVariantMap executeNode(const MnaNode &node, const QVariantMap &inputs)
std::function< void(const QString &nodeId, int current, int total)> ProgressCallback
Progress callback type.
std::function< QObject *(const QString &opType)> PluginFactory
static void stopStream(StreamContext &ctx)
static Context execute(MnaGraph &graph, const QVariantMap &graphInputs)
QMap< QString, QVariant > results
nodeId::portName → data (QVariant wrapping domain objects or file paths)
QVariantMap graphInputs
Graph-level inputs (populated before execution).
QStringList executionOrder
Topological order used for startup/shutdown.
bool running
Whether the stream is active.
MnaGraph * graph
The pipeline graph (owned externally).
QMap< QString, QObject * > livePlugins
nodeId → live plugin instance (QObject* avoids scan dependency)
Single executable step in an MNA pipeline graph, with attributes, typed ports, exec mode,...
MnaNodeExecMode execMode
Execution mode.
QString ipcCommand
External executable command.
QStringList ipcArgs
Command-line arguments (supports {{placeholder}} tokens).
bool dirty
Whether node needs re-execution.
MnaScript script
Inline source code, interpreter, language.
QList< MnaPort > inputs
Input ports.
QVariantMap attributes
Operation parameters.
QDateTime executedAt
Timestamp of last execution.
QString opType
Operation type (looked up in MnaOpRegistry).
MnaVerification verification
Explanation, checks, results, and provenance snapshot.
QString ipcWorkDir
Working directory for external process.
QList< MnaPort > outputs
Output ports.
QString id
Unique node identifier.
Process-wide lookup from opType to MnaOpSchema and implementation function.
static MnaOpRegistry & instance()
OpFunc opFunc(const QString &opType) const
std::function< QVariantMap(const QVariantMap &inputs, const QVariantMap &attributes)> OpFunc
Operation implementation callback type.
QVariant evaluateExpression(const QString &expr, const QMap< QString, QVariant > &results) const
QStringList evaluate(const QMap< QString, QVariant > &results)
QStringList allPaths() const
QVariant param(const QString &path) const
Named, typed port on an MNA graph node with upstream link and optional real-time stream binding.
QString name
Port name (unique within a node).
QString sourcePortName
Which output port on that node?
QString cachedResultPath
Relative path to cached result.
QString sourceNodeId
Which node produces this input? (empty → graph-level input).
Inline interpreter-launched source code carried by a Script-mode MnaNode.
bool keepTempFile
true → preserve temp script file after execution (debug aid)
QString code
The inline source code (resolved at save-time if sourceUri is set).
QString language
"python", "shell", "r", "matlab", "octave", "julia"
QStringList interpreterArgs
Extra args before the script file (e.g. ["-u"] for unbuffered Python).
QString severity
"error" (abort), "warning" (log + continue), "info" (always continue)
QString expression
MnaParamTree expression over attributes, inputs and (post) outputs: "rank > 0".
QString phase
"pre" (before execution) or "post" (after execution)
QString description
Human-readable: "Covariance matrix must be positive-definite".
QString onFail
Optional remediation hint.
QString id
Unique check identifier within the node (e.g. "cov_posdef").
QString message
Formatted message: "PASS: ..." or "FAIL [error]: ...".
QString checkId
References MnaVerificationCheck::id.
QVariant actualValue
The evaluated expression result.
QString severity
Echoed from the check definition.
QDateTime evaluatedAt
When this check was evaluated.
bool passed
true if the expression evaluated to true
QString osInfo
e.g. "macOS 15.4 arm64"
QString qtVersion
e.g. "6.11.0"
qint64 wallTimeMs
Wall-clock duration in milliseconds.
QString hostName
Machine name (for cluster provenance).
QVariantMap resolvedAttributes
QMap< QString, QString > inputHashes
portName → SHA-256
QString mneCppVersion
e.g. "2.2.0"
MnaProvenance provenance
Complete provenance snapshot (populated by executor).
QList< MnaVerificationCheck > checks
Declarative checks (authored by user, evaluated by executor).
QList< MnaVerificationResult > preResults
Results of pre-execution checks (populated by executor).
QList< MnaVerificationResult > postResults
Results of post-execution checks (populated by executor).