Accessing Vector/Matrix Element Values

Assign whole arrays at once. Element-by-element assignment is for the rare case where the values are computed one at a time — see the second half of this topic.

Assigning values in bulk. Allocate with Size — the users guide calls it the preferred method for memory allocation, because setting Rows and Cols separately can allocate an intermediate the final shape never needs — then assign the values:

var a: Matrix;
    v: Vector;
begin
    a := [[-3.0, -1.0], [1.0, 2.0]];   // sizes rows and columns as it assigns
    v := [1.0, 2.0, 3.0, 4.0];
end;

The literal carries both dimensions, so it sizes the matrix as it assigns, and it writes into whatever precision the matrix already has.

Do not use SetIt to populate an object. It encodes the complex flag as a positional argument (SetIt(2, 2, false, ...)), which says nothing at the call site about what the storage holds.

The values name their own precision. A vector or matrix holds one of four storage precisions, and the element type of the values says which one they are. The precision is never spelled out as a separate argument, and nothing converts silently:

StorageElement typeLiteral
doubledouble-3.0
singleSingle-3.0
complex doubleTCplxCplx(1, 2)
complex singleTSCplxCplxSingle(1, 2)
var c: Matrix;
    s: Matrix;
begin
    c := [[Cplx(1, 2), Cplx(3, 4)], [Cplx(5, 6), Cplx(7, 8)]];
    s.Size(2, 2, TMtxFloatPrecision.mvSingle);
    s := [[-3.0, -1.0], [1.0, 2.0]];   // written into single-precision storage
end;

---

There are three ways to read/write individual elements, with different trade-offs.

Three access methods on TVec/TMtx (pool-managed types):

Access methodSpeedRange checkingSingle/Double conversion
Array field (Values1D[i], CValues1D[i], etc.)FastestLimitedNo
Array property (Values[i])MediumYes (if Assertions ON)No
Default array property (a[i], a[i,j])SlowestYes (if Assertions ON)Yes (automatic)

Vector and Matrix value types support only property access and are always range-checked.

Default array properties are slower because they also support implicit single/double precision conversion. If the internal storage is single precision but you assign a double, the conversion happens automatically. This flexibility has a performance cost.

There is no default array property for complex data — an object can have only one, and it is the real one. So a[i, j] is a double even when the storage is complex, and complex elements are reached through CValues:

a.CValues[1, 0] := Cplx(2, 0);

Example — all access methods:

var a: Matrix;
    v: Vector;
    af: TMtx;
    vf: TVec;
begin
    a.Size(10, 10);
    a[1, 0] := 2;           // default array property (range-checked, precision-converting)
    a.Values[1, 0] := 2;    // array property (range-checked)

    v.Size(10);
    v[1] := 2;              // default array property
    v.Values[1] := 2;       // array property

    af := a;   // obtain pointer to internal TMtx object (implicit conversion)
    vf := v;   // obtain pointer to internal TVec object (implicit conversion)

    af.Values1D[1] := 2;    // array field (fastest, no range check)
    vf.Values[1] := 2;      // array field
    af.SValues1D[1] := 2;   // single-precision array field
    vf.SValues[1] := 2;     // single-precision array field
    af.CValues1D[1] := 2;   // complex array field
    vf.CValues[1] := 2;     // complex array field
end;

Recommended pattern for element traversal:

In Delphi, use const TVec/TMtx parameters for fast array field access via implicit conversion.

procedure DoValueTraversalMath(const a: TMtx; const v: TVec);
var i: Integer;
begin
    for i := 0 to v.Length - 1 do
        v.Values[i] := i;   // array field access — fast as raw dynamic array
end;

var a: Matrix;
    v: Vector;
begin
    a.Size(10, 10);
    v.Size(10);
    DoValueTraversalMath(a, v);  // implicit Vector→TVec, Matrix→TMtx conversion
end;

Why this pattern works:

  1. const saves a compiler var assignment and prevents accidental pointer modification (const applies to the pointer, not the data it points to — you can still write elements)
  2. Passing Vector/Matrix to TVec/TMtx const parameters triggers implicit conversion, returning the pointer to the internal storage object (zero-copy)
  3. Inside the function, array field access (.Values[i]) is as fast as raw Delphi dynamic arrays

Two cardinal rules for element access:

  1. Allocate Vector/Matrix as local vars, but declare TVec/TMtx in parameter lists. This triggers implicit conversion and gives you fast array field access inside functions.
  1. Never return Vector/Matrix as function results. Return via a const parameter instead. This avoids an extra memory allocation on function return.

Direct array-field access (Delphi): Delphi has no Span<T> type. For zero-copy element traversal, cast Vector/Matrix to the underlying TVec/TMtx and read Values1D, SValues1D, or CValues1D (the same array fields used in the traversal example above). const parameters do this implicitly without a cast.

Single/double precision conversion warning: When working with single precision, the Delphi compiler may implicitly apply floating-point conversion, affecting performance. Use disassembly to verify no conversion exists. Use fixed-type constants instead of numeric literals.

Important: In most cases, you should not access elements individually. Use the vectorized methods (Sin, Add, Mul, etc.) which operate on entire arrays using SIMD instructions and are orders of magnitude faster than element-by-element loops.