Choosing the Right Vector/Matrix Type

The API has 73 types matching "Vec/Mtx/Vector/Matrix", but only 18 are data containers. The rest are base classes, exceptions, converters, and infrastructure.

Two-question decision tree:

Q1: What element type do you need?

Element type1D (vector)2D (matrix)Notes
Double (default)Vector / TVecMatrix / TMtx90%+ of use cases
IntegerVectorInt / TVecIntMatrixInt / TMtxInt
GPU (OpenCL)clVectorclMatrixGPU compute only
SparseTSparseMtxSparse storage only
Byte / SmallIntTVecByte / TMtxByteTVecSmallInt / TMtxSmallIntRare, compact

Q2: Value type or pool-managed?

ChoiceTypesWhen to use
Value type (default)Vector, Matrix, VectorInt, MatrixIntGeneral use, operator overloading, automatic lifetime
Pool-managedTVec, TMtx, TVecInt, TMtxIntBlock processing loops with CreateIt/FreeIt for L1 cache discipline

See topic declaration-rules for where each type may be declared (local var vs field) and the correct construction patterns.

Relationship between value types and pool-managed types:

Vector wraps a TVec internally, Matrix wraps a TMtx, and so on. They share the same underlying data object. This has two important consequences:

  1. Automatic conversion when passing to methods: When you pass a Vector to a method that accepts TVec (or TMtxVec), the value type automatically converts and dereferences its internal object. No cast needed — just pass it directly. This is also why methods are declared with TVec/TMtx/TVecInt/TMtxInt parameters rather than Vector/Matrix: it allows them to accept both value types and pool-managed types, and when a value type is passed, one layer of encapsulation is stripped away making the code run faster.
  1. Typecast as an escape hatch: Every method that exists on TVec/TMtxVec is mirrored on Vector via thin delegates, so you almost never need to cast. If you do need the underlying TVec object directly — for example to pass it to a method that takes TVec explicitly — use TVec(a) (Delphi) or (TVec)a (C#). The cast returns a reference to the internal object without copying.
Value typeWrapsAuto-converts to
VectorTVecTVec, TDenseMtxVec, TMtxVec
MatrixTMtxTMtx, TDenseMtxVec, TMtxVec
VectorIntTVecIntTVecInt, TMtxVecInt
MatrixIntTMtxIntTMtxInt, TMtxVecInt
  1. Accessing raw arrays:

In Delphi, Vector/TVec auto-converts to array of Double for const parameters (zero-copy).

// Delphi: auto-conversion to const array of Double (zero-copy)
procedure ProcessData(const arr: array of Double);
begin
    // read arr elements directly — zero-copy access to Vector data
end;

var b: Vector;
begin
    b.Size(10);
    ProcessData(b);  // auto-converts to array of Double, no copy
end;

Delphi only — never assign to a local dynamic array variable:

// Unsafe — do not do this:
var arr: array of Double;
    b: Vector;
begin
    b.Size(10);
    arr := b;  // compiles, but fragile
    // Delphi ARC will nil arr when exiting scope,
    // corrupting the Vector's internal storage.
end;

Rule: In Delphi, pass Vector/TVec directly to const array of Double parameters. Never assign to a local dynamic array variable.

  1. Do not dereference matrices to row arrays: TMtx stores data as a flat 1D block. Extracting a "row" from the Values 2D property does not produce a real independent array — it aliases internal memory and can corrupt reference-counting metadata.
// Unsafe — do not do this:
var m: Matrix;
    row: array of Double;
begin
    m.Size(10, 10);
    row := m.Values[0];  // not a real jagged array row — corrupts ARC fields
    SomeProc(row);       // will write to index -1 (ref count), memory corruption
end;

Rule: Never dereference TMtx/TMtxInt/Matrix/MatrixInt to row arrays. Use SetSubRange for zero-copy row access, or access elements through properties.

Memory layout — vectors and matrices share the same storage model:

Both vectors and matrices store their elements in a single contiguous block of memory. This means all element-wise methods that work on vectors (Sin, Add, Mul, etc.) can also be applied to matrices — they simply operate on the flat data block regardless of dimensionality. A matrix with 10 rows and 20 columns is stored as 200 contiguous doubles, identical in memory to a vector of length 200.

However, dimension-specific operations (row/column access, transposition, matrix multiplication, decompositions) require the matrix shape metadata and must use the dedicated matrix methods. The element-wise vector methods ignore row/column structure.

To obtain a zero-copy view of a portion of a matrix (or vector), use SetSubRange. This is similar to Span<T> in C# — it shifts internal pointers without copying data:

// Delphi: same pattern
var m: Matrix;
    rowView: Vector;
begin
    m.Size(10, 20);
    rowView.SetSubRange(m, rowIndex * 20, 20);  // view of one row, no copy
    rowView.Sin;  // operates on the matrix memory directly
    rowView.SetSubRange;  // release view (restore to full range)
end;

Key SetSubRange overloads:

  • a.SetSubRange(Src, Index, Len) — view of Src elements [Index..Index+Len-1]
  • a.SetSubRange(Src, Index, Rows, Cols) — view with matrix dimensions (on TMtx)
  • a.SetSubRange(Index, Len) — narrow the view of self (no source)
  • a.SetSubRange() — reset to full range (same as SetFullRange)

Important: The source must not be resized while a view exists. Call SetSubRange() (no args) to release the view when done.

Key insight about base classes in signatures:

  • Methods accept TVec/TMtx (not Vector/Matrix) by design — this accepts both types.
  • TMtxVec in a method signature means "pass any vector or matrix" (Vector, Matrix, TVec, TMtx, etc.) This is why element-wise operations accept both — the memory layout is the same.
  • TDenseMtxVec is the same — it's a polymorphic base, not a type you instantiate.
  • TMtxVecInt means pass VectorInt, MatrixInt, TVecInt, or TMtxInt.

Default choice: Use Vector (1D) or Matrix (2D). Switch to TVec/TMtx only in performance-critical block loops with explicit CreateIt/FreeIt lifecycle.