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:
Matrix a = new Matrix(2, 2); // Size first
a.CopyFromArray([-3.0, -1.0, 1.0, 2.0]); // then the values
Vector v = new Vector(4);
v.CopyFromArray([1.0, 2.0, 3.0, 4.0]);
A flat array carries no shape, so the size has to be stated first — assigning one to an unsized matrix raises EMtxVecInvalidArgument: TMtx: Length can not be set. Use Size!. A Vector has no such requirement, because a vector's length is its shape.
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:
The element type selects the CopyFromArray overload:
| Storage | Element type | Literal |
|---|---|---|
| double | double | -3.0 |
| single | float | -3.0f |
| complex double | TCplx | Cplx(1, 2) |
| complex single | TSCplx | CplxSingle(1, 2) |
using static Dew.Math.Units.Math387; // Cplx, CplxSingle, IntPower, ...
var s = new Matrix(2, 2, TMtxFloatPrecision.mvSingle);
s.CopyFromArray([-3.0f, -1.0f, 1.0f, 2.0f]);
var c = new Matrix(2, 2, TMtxFloatPrecision.mvDoubleComplex);
c.CopyFromArray([Cplx(1, 2), Cplx(3, 4), Cplx(5, 6), Cplx(7, 8)]);
Declare using static Dew.Math.Units.Math387; in code that uses the library's scalar functions, so Cplx, IntPower and the rest are written unqualified.
---
There are three ways to read/write individual elements, with different trade-offs.
Three access methods on TVec/TMtx (pool-managed types):
| Access method | Speed | Range checking | Single/Double conversion |
|---|---|---|---|
Array field (Values1D[i], CValues1D[i], etc.) | Fastest | Limited | No |
Array property (Values[i]) | Medium | Yes (if Assertions ON) | No |
Default array property (a[i], a[i,j]) | Slowest | Yes (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); // Cplx returns a TCplx
Example — all access methods:
var a = new Matrix();
var v = new Vector();
a.Size(10, 10);
a[1, 0] = 2; // indexer property (range-checked, precision-converting)
a.Values[1, 0] = 2; // Values property (range-checked)
v.Size(10);
v[1] = 2; // indexer property
v.Values[1] = 2; // Values property
// Cast to TMtx/TVec for fastest field access
TMtx af = (TMtx)a; // explicit cast to internal TMtx
TVec vf = (TVec)v; // explicit cast to internal TVec
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
Recommended pattern for element traversal:
In C#, cast to TVec/TMtx to access the fast array fields.
void DoValueTraversalMath(TMtx a, TVec v)
{
for (int i = 0; i < v.Length; i++)
v.Values[i] = i; // array field access — fast
}
var a = new Matrix();
var v = new Vector();
a.Size(10, 10);
v.Size(10);
DoValueTraversalMath((TMtx)a, (TVec)v); // cast to pool types for fast access
Why this pattern works:
constsaves 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)- Passing Vector/Matrix to TVec/TMtx const parameters triggers implicit conversion, returning the pointer to the internal storage object (zero-copy)
- Inside the function, array field access (
.Values[i]) is as fast as raw Delphi dynamic arrays
Two cardinal rules for element access:
- 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.
- Never return Vector/Matrix as function results. Return via a
constparameter instead. This avoids an extra memory allocation on function return.
C# Span<T> support (zero-copy interop):
In C#, all floating-point types implicitly convert to Span<T>. This means you can pass a Vector, TVec, Matrix, or TMtx directly to any method expecting Span<double>, Span<Single>, Span<TCplx>, or Span<TSCplx> — zero-copy.
// Pass directly to Span-accepting methods — implicit conversion, zero-copy
void ProcessData(Span<double> data) { ... }
var v = new Vector();
v.Size(1000);
ProcessData(v); // Vector → Span<double> (implicit)
ProcessData(v.Values); // also works: TDouble1DAccess → Span<double>
TVec t = (TVec)v;
ProcessData(t); // TVec → Span<double> (implicit)
ProcessData(t.Values); // same via accessor
// Matrix: flat 1D span of all elements (row-major)
var m = new Matrix();
m.Size(10, 20);
ProcessData(m); // Matrix → Span<double> via Values1D (all 200 elements)
ProcessData(m.Values1D); // same, explicit
// Matrix: per-row spans
Span<double> row = m.Values.RowSpan(3); // row 3 only
Span<double> blk = m.Values.BlockSpan(2, 5, 10); // 10 elements from (2,5)
// Create Vector from Span (copies data IN)
ReadOnlySpan<double> src = stackalloc double[] { 1, 2, 3 };
Vector fromSpan = src; // implicit ReadOnlySpan<double> → Vector (copy)
Span conversion summary:
| Type | → Span<double> | → Span<Single> | → Span<TCplx> | → Span<TSCplx> |
|---|---|---|---|---|
| TVec | yes | yes | yes | yes |
| TMtx | yes (flat) | yes | yes | yes |
| Vector | yes | yes | yes | yes |
| Matrix | yes (flat) | yes | yes | yes |
| TVecInt | no | no | no | no |
| TMtxInt | no | no | no | no |
| VectorInt | no | no | no | no |
| MatrixInt | no | no | no | no |
Integer types (TVecInt, TMtxInt, VectorInt, MatrixInt) do not support Span conversions. Use CopyToArray() to get a managed int[] if needed.
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.