MtxVec Expression Parser (TMtxExpression)

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:

  1. Arrays are 0-based (not 1-based)
  2. Integer division is strict: 5./6 = 0 (per-element / returns integer for integer operands)
  3. Concatenation [1, 2] requires commas between elements
  4. * on two vectors is treated as .* (element-wise)
  5. Case-sensitive (but many aliases exist: Tan() = tan(), False = false)
  6. Colon : has higher precedence than +,-,*,/: 2:3+1 = 3:4
  7. Explicit type conversions required (no implicit integer→double promotion in loops)

Built-in types:

TypeDescription
double64-bit float (or 32-bit depending on build)
integer64-bit integer (overflow/division-by-zero checked)
complexDouble-precision real + imaginary (struct)
stringString value
booleanTrue/False (stored as 32-bit integer)
vectorDouble-precision 1D array (can hold complex)
matrixDouble-precision 2D array (can hold complex, row-major)
integer vector/matrix32/16/8-bit integer arrays
boolean vector/matrix32-bit boolean arrays
rangeTwo or three values: 1:10 or 10:-1:0
customArbitrary 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):

PriorityOperatorDescription
10!x, ~x, not xLogical/bitwise NOT
10-x, +xUnary minus/plus
10x'Transpose (adjungate)
15x:y, x:step:yRange operator
20x ^ yPower
30x * yMatrix multiply
30x *. y, x .* yElement-wise multiply
30x / yMatrix division
30x /. y, x ./ yElement-wise division
30A \ yBack-division: x = A^(-1)*y
30x div yInteger-only division
10x % y, x mod yRemainder
40x + yAdd (also string concatenation)
40x - ySubtract
40x +. y, x .- yElement-wise add/subtract
45x >> y, x shr yBit shift right
45x << y, x shl yBit shift left
50<, <=, >, >=Comparison (returns bool/mask)
55==, !=, <>, ~=Equality/inequality
70x & y, x and yLogical/bitwise AND
70x xor yLogical/bitwise XOR
80x or y, `x \y`Logical/bitwise OR
200x = yAssignment

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)