TMtxExpression is a math expression parser that evaluates Matlab-like syntax at runtime. It is designed for zero-allocation evaluation: memory is allocated once at parse time, then reused across repeated evaluations. This makes it faster than most scripting engines for numerical workloads.
Location: MtxParseExpr.pas (TMtxExpression). Related units: MtxParseClass.pas, MtxParseOperator.pas, MtxParseProbabilities.pas.
Key design principles:
- No memory allocation during evaluation — all buffers allocated at parse time
- Statically typed variables (type set on first assignment, immutable until
undefine()) - 0-based arrays and matrices (row-major storage)
- Matlab-like syntax with some differences (see below)
Differences from Matlab:
- Arrays are 0-based (not 1-based)
- Integer division is strict:
5./6 = 0(per-element/returns integer for integer operands) - Concatenation
[1, 2]requires commas between elements *on two vectors is treated as.*(element-wise)- Case-sensitive (but many aliases exist:
Tan()=tan(),False=false) - Colon
:has higher precedence than+,-,*,/:2:3+1=3:4 - Explicit type conversions required (no implicit integer→double promotion in loops)
Built-in types:
| Type | Description |
|---|---|
| double | 64-bit float (or 32-bit depending on build) |
| integer | 64-bit integer (overflow/division-by-zero checked) |
| complex | Double-precision real + imaginary (struct) |
| string | String value |
| boolean | True/False (stored as 32-bit integer) |
| vector | Double-precision 1D array (can hold complex) |
| matrix | Double-precision 2D array (can hold complex, row-major) |
| integer vector/matrix | 32/16/8-bit integer arrays |
| boolean vector/matrix | 32-bit boolean arrays |
| range | Two or three values: 1:10 or 10:-1:0 |
| custom | Arbitrary object types (for grid integration, etc.) |
Variable declaration by example:
a = 0.0 // double
a = 0 // 64-bit integer
a = [1.0, 2, 3, 4] // double vector (at least one element must be double)
a = [1, 2, 3, 4] // integer vector
a = [1+1i, 2, 3] // complex vector
A = [1, 2; 3, 4] // 2x2 matrix (semicolon separates rows)
b = Boolean(a) // explicit conversion
d = double(a) // explicit conversion
undefine(a) // reset type, allows reassignment to new type
Control flow:
// If-else (keywords must be on their own lines)
if b == 2
a = 2
else
a = 3
end
// While loop
while (b < 10)
b = b + 1
end
// For loop with range
for k = 1:10
j = j + 1
end
// For loop over vector elements
a = [4, 5, 6]
for k = a
j = j + k // j = 15 after loop
end
// Break and continue
for k = a
if k > 2
continue
end
j = j + k
end
Operators (by priority, lowest number = highest priority):
| Priority | Operator | Description | |
|---|---|---|---|
| 10 | !x, ~x, not x | Logical/bitwise NOT | |
| 10 | -x, +x | Unary minus/plus | |
| 10 | x' | Transpose (adjungate) | |
| 15 | x:y, x:step:y | Range operator | |
| 20 | x ^ y | Power | |
| 30 | x * y | Matrix multiply | |
| 30 | x *. y, x .* y | Element-wise multiply | |
| 30 | x / y | Matrix division | |
| 30 | x /. y, x ./ y | Element-wise division | |
| 30 | A \ y | Back-division: x = A^(-1)*y | |
| 30 | x div y | Integer-only division | |
| 10 | x % y, x mod y | Remainder | |
| 40 | x + y | Add (also string concatenation) | |
| 40 | x - y | Subtract | |
| 40 | x +. y, x .- y | Element-wise add/subtract | |
| 45 | x >> y, x shr y | Bit shift right | |
| 45 | x << y, x shl y | Bit shift left | |
| 50 | <, <=, >, >= | Comparison (returns bool/mask) | |
| 55 | ==, !=, <>, ~= | Equality/inequality | |
| 70 | x & y, x and y | Logical/bitwise AND | |
| 70 | x xor y | Logical/bitwise XOR | |
| 80 | x or y, `x \ | y` | Logical/bitwise OR |
| 200 | x = y | Assignment |
Index operations (gather/scatter):
a = [1, 0, 3, 4]
mask = a <> 0 // boolean mask: [true, false, true, true]
d = a(mask) // gather by mask: [1, 3, 4]
d = d + 2 // modify: [3, 5, 6]
a(mask) = d // scatter back
A(0:2, 2:3) = B(2:4, 5:6) // sub-matrix copy
a(2:) = b // copy b into a starting at index 2
a(2:) = 3 // fill a from index 2 to end with 3
// Multiple return values
(mag, phase) = CartToPolar(FFT([0:511]))
Complete function reference (from TMtxExpression.GetFuncList runtime v6.3.10):
Trigonometric: Abs, Sin, Cos, Tan, Sec, Csc, Cot, Sinh, Cosh, Tanh, Sech, Csch, Coth, ArcSin, ArcCos, ArcTan, ArcTan(x,y), ArcSec, ArcCsc, ArcCot, ArcSinh, ArcCosh, ArcTanh, ArcSech, ArcCsch, ArcCoth, SinCos, SinhCosh, FixAngle, DegToRad, RadToDeg
Exponential/logarithmic: Exp, Exp2, Exp10, Ln, Log, Log2, Log10, LogN, Sqrt, Sqr, Cbrt, Power, Pow, IntPow, IntPower, Root(x,k,n)
Complex: Cplx(x), Cplx(re,im), Conj, Flip, Imag, Real, Arg, Expj, Cis, IsComplex, CartToPolar, PolarToCart, Norm (squared norm)
Rounding/conversion: Ceil, Floor, Frac, Round, RoundToInt, Trunc, TruncToInt, Double(x), Integer(x), Boolean(x), Sgn
Checks: IsNaN, IsInf, IsInfNan, IsNanInf, IsEqual, IfThen(a,b,c)
Vector statistics: Sum, SumOfSqr, Product, Mean, MeanCols, MeanRows, Median, StdDev, StdDevCols, StdDevRows, Rms, Min, Max, Kurtosis, Skewness, Normalize, NormL1, NormL2, NormC, ZScore, Length
Vector operations: CumSum, Difference, Reverse, Rotate, SortAscend, SortDescend, ThreshBottom, ThreshTop, Ones, Zeros, Ramp, Integrate
Random: Random (uniform -1..1), RandG/RandomG (Gaussian mean=0, stddev=1)
Signal processing: FFT, IFFT, IFFTToReal, FFT2D, IFFT2D, IFFT2DToReal, DCT, IDCT, Convolve, Deconv, Hilbert, DotProd, AutoCorrBiased, AutoCorrNormal, AutoCorrUnbiased, CrossCorr
Polynomial: PolyCoeff, PolyEval, PolyRoots
Matrix operations: Rows, Cols, Eye, Eig, SVD, SVDSolve, LQR, Cholesky, Determinant, Trace, Diag, MtxIntPower, MtxPower, MtxSqrt, Rotate90, FlipHor, FlipVer, LowerTriangle, UpperTriangle, Hankel, Toeplitz, Vandermonde, Kron, Kac, Pascl, Norm1, NormFro, NormInf
Special functions: Erf, Erfc, ErfInv, Gamma, LnGamma, Pythag, Primes, Rem, RemDiv, Lcm, Gcd
String: CompareStr, CompareText, CplxToStr, FormatCplx, FormatSample, SampleToStr, IntToStr, Pos, ReplaceStr, ReplaceText, Lower, Upper, Trim
File I/O: csvRead, csvWrite, FileOpen, FileClose, FileRead, FileWrite, FilePosition, FileSetPosition, FileSize, FileCopy, FileMove, FileDelete, FileExists, DirectoryCreate, DirectoryDelete, DirectoryExists
Variable management: Undefine(x,...), Assign(Dst, Range, Src)
Aliases: Ln = Log, Expj = Cis, Integer() = TruncToInt(), Pow = Power
API — interactive evaluation (console/REPL style):
var expr = new TMtxExpression();
// Evaluate one expression at a time
expr.AddExpr("j = -2");
TValueRec a = expr.Evaluate();
string varName = expr.EvaluatedVarName(0);
TValueRec val = expr.VarByName[varName]; // inspect result
// Multi-line: vectorized math
expr.AddExpr("x = j + 10:15");
expr.Evaluate();
expr.AddExpr("y = double(x)");
expr.Evaluate();
// List all defined variables
var varNames = new TStringList();
expr.GetVarList(varNames);
// Get help: list all functions and operators
var funcList = new TStringList();
var hlpList = new TStringList();
expr.GetFuncList(funcList, hlpList, true); // functions with help text
expr.GetOperList(funcList, hlpList); // operators with help text
// Reset everything
expr.ClearAll();
API — scalar evaluation (fast repeated evaluation):
var expr = new TMtxExpression();
expr.ClearAll();
TValueRec x1 = expr.DefineDouble("x"); // define scalar variable
expr.Expressions = "x *. Sin( x / pi )"; // set formula
// Evaluate many times with different x values (zero allocation per call)
for (int i = 0; i < values.Length; i++) {
x1.DoubleValue = values[i]; // set input
results[i] = expr.EvaluateDouble(); // fast scalar result
}
API — vectorized evaluation (10-20x faster than scalar loop):
var expr = new TMtxExpression();
expr.ClearAll();
expr.DefineVector("x", xVector); // bind vector variable
expr.Expressions = "Sin(x) + Cos(x)"; // set formula
TVec yResult = expr.EvaluateVector(); // entire vector at once
API — compiled scripts (multi-line):
var expr = new TMtxExpression();
expr.ClearExpressions();
for (int i = 0; i < scriptLines.Count; i++)
expr.AddExpr(scriptLines[i]);
expr.Compile(); // compile once
TValueRec result = expr.EvaluateCompiled(); // run compiled script
// Step-by-step execution (debugger)
int line = expr.EvaluateStep(currentLine); // execute one line, returns next
API — custom functions and grid integration:
// Register custom function
expr.DefineFunction("drawvalues", myCallback, 5, 0,
"drawvalues(Y, series, xOffset, xStep, downsample): Draws Y to chart series.");
// Grid integration (spreadsheet-like access from expressions)
var gridVar = new TExprGridVariable();
gridVar.OnSetValue = (sender, src, row, col) => grid.Cells[col+1, row+1] = src;
gridVar.OnGetValue = (sender, ref dst, row, col) => dst = grid.Cells[col+1, row+1];
expr.DefineCustomValue("grid1", gridVar);
// Now in expressions: grid1(0, 0) = "Test"; a = grid1(1:3, 0:2)