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:

(zero-copy). In C#, use Values1D property to access the internal double[].

// C#: access internal array via Values1D property
var b = new Vector();
b.Size(10);
double[] arr = ((TVec)b).Values1D;   // direct reference to internal storage
ProcessData(arr);                     // pass to methods that take double[]
// Do not resize the Vector while arr is in use
  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 in C# as well — do not do this:
var m = new Matrix();
m.Size(10, 10);
// double[] row = m.Values[0];  // aliases internal storage — unsafe
// Instead, use SetSubRange for zero-copy row access:
var rowView = new Vector();
((TVec)rowView).SetSubRange((TMtx)m, 0, 10);  // view of row 0

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:

// C#: Create a vector view of matrix row data (zero-copy)
var m = new Matrix();
m.Size(10, 20);
var rowView = new Vector();
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)

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.