Zum Hauptinhalt springen

Formula Engine

Die Formula Engine wertet kleine numerische Ausdrücke überall dort aus, wo die Plattform eine vom Benutzer eingegebene Formel akzeptiert — DataPointMapping-Ausdrücke, berechnete Archivspalten und @-Ausdrücke in Runtime-Queries. Die Ausdruckssyntax, die diese Funktionen bereitstellen, ist im Tech-Guide dokumentiert (Formula Expressions); diese Seite beschreibt die Engine aus Sicht eines Entwicklers: den Service-Vertrag, die zugrunde liegende Bibliothek und die Konventionen, die jeder Aufrufer teilt.

Library​

Die Engine kapselt das NuGet-Paket MathParser.org-mXparser (aktuell v6.1.1, referenziert in Runtime.Engine.Formulas.csproj). mXparser ist ein ausgereifter Parser für mathematische Ausdrücke; die gesamte mXparser-math collection (Funktionen, Operatoren, Konstanten) steht Ausdrücken zur Verfügung — nichts ist deaktiviert. Da jede Eingabe und das Ergebnis ein double sind, ist praktisch nur der numerische Teil dieser Collection nützlich (es gibt keine String-, Einheiten- oder Objekteingaben). Siehe die mXparser math collection für die versionsabgestimmte Liste all dessen, was der Parser akzeptiert.

Die Bibliothek wird gekapselt statt direkt verwendet, damit die Ternär-Normalisierung, die null-/NaN- Behandlung und die Cast-back-Leiter an genau einer Stelle liegen, statt über die Aufrufer hinweg dupliziert zu werden.

IFormulaEngine​

Jede Auswertung läuft über einen einzigen Dienst, IFormulaEngine (Meshmakers.Octo.Runtime.Contracts.Formulas), implementiert durch FormulaEngine im Projekt Runtime.Engine.Formulas. Er ist zustandslos und als Singleton über AddFormulaEngine() registriert.

MethodPurpose
Validate(expression, arguments)Bindet Testwerte, prüft die Syntax und wertet aus; meldet ein NaN-Ergebnis als ungültig. Untermauert den validate-expression-Endpunkt.
CheckSyntax(expression, argumentNames)Syntax- + Referenzprüfung ohne Auswertung — sodass eine nur zur Laufzeit auftretende Division durch null (a / (b - b)) kein False Positive ist.
EvaluateRaw(expression, arguments)Wertet zu einem rohen double aus. NaN = konnte nicht ausgewertet werden; -Infinity = das null-Sentinel.
Evaluate(expression, arguments, resultType)EvaluateRaw plus die Cast-back-Leiter; gibt null für NaN / null-Sentinel zurück.
NormalizeTernary(expression)Stellt das Rewrite cond ? a : b → if(cond, a, b) eigenständig bereit.

Argumente sind immer ein IReadOnlyDictionary<string, double>; mXparser-Argumente werden namentlich aus diesem Dictionary gebunden. Ein Ausdruck, der auf einen Namen verweist, der nicht im Dictionary ist, besteht die Syntax- prüfung nicht.

// scale and clamp a polled value, then cast to the column's stored type
var args = new Dictionary<string, double> { ["value"] = 42.0 };
object? result = _formulaEngine.Evaluate(
"min(max(value, 0), 100)", args, FormulaResultType.Double);

Konventionen, die jeder Aufrufer teilt​

Ternär-Normalisierung​

Das Ternär im C-Stil cond ? a : b wird vor der Auswertung in das if(cond, a, b) von mXparser umgeschrieben (FormulaEngine.ConvertTernaryToIf). Das Rewrite sucht nach dem passenden : auf derselben Klammertiefe, sodass verschachtelte Ternärausdrücke und geklammerte Zweige behandelt werden:

a > 0 ? (b > 0 ? 1 : 2) : 3 → if(a > 0, (if(b > 0, 1, 2)), 3)

Validate / CheckSyntax geben die umgeschriebene Zeichenkette in NormalizedExpression zurück, sodass eine UI dem Benutzer genau zeigen kann, was ausgewertet wurde.

Null-Sentinel und NaN​

Die Engine reserviert zwei double-Werte:

  • double.NegativeInfinity ist das null-Sentinel, den Ausdrücken als null- Konstante bereitgestellt. Eine fehlende / null-Eingabe bindet daran.
  • double.NaN bedeutet, dass die Formel für diese Eingaben keinen Wert erzeugen konnte (z. B. 0 / 0).

Evaluate bildet beide auf ein CLR-null ab — niemals auf eine halb fertige Zahl. Aufrufer persistieren das als SQL- NULL (berechnete Spalten) oder greifen auf den Rohwert zurück (DataPointMapping). Validate behandelt ein NaN-Ergebnis als ungültig, während CheckSyntax nicht auswertet und daher niemals ein nur zur Laufzeit auftretendes NaN kennzeichnet.

Ergebnistypen und die Cast-back-Leiter​

Evaluate castet das rohe double gemäß FormulaResultType zurück:

FormulaResultTypeCast-back
Doubleder Rohwert
Intauf int abgeschnitten
Int64auf long abgeschnitten
Booleanfalse, wenn 0, andernfalls true
DateTimeder Wert wird als .NET ticks interpretiert

Der DateTime-Pfad passt zu den OctoMesh-spezifischen Funktionen now(addMinutes) und startOfDay(dayCount), die beide DateTime-Ticks als double zurückgeben. Diese Erweiterungen sowie die null- Konstante sind in OctoExpression registriert (NowFunction, StartOfDayFunction).

Callers​

CallerProjectBound variables
ApplyDataPointMappingsNodeocto-mesh-adaptervalue (der abgefragte Quellwert) — verwendet EvaluateRaw
CrateDbStreamDataRepository (berechnete Spalten)octo-construction-kit-engine-mongodbjede Quellspalte über ihren physischen Spaltennamen — verwendet Evaluate mit dem gespeicherten ResultType der Spalte
ExpressionValidationService (validate-expression-REST-Endpunkt)octo-communication-controller-servicesvalue (ein Testwert, Standard 42.0) — verwendet Validate

Wenn Sie einen neuen Aufrufer hinzufügen, hängen Sie von IFormulaEngine ab und rufen Sie AddFormulaEngine() während der Dienst- registrierung auf; referenzieren Sie mXparser nicht direkt, damit die oben genannten gemeinsamen Konventionen weiterhin gelten.