Skip to content

Maths, reductions, sorting

AI assistant

Build this with Claude Code, Cursor or Copilot

Copy a Tessero-tuned prompt for Maths, reductions, sorting, grounded in 16 real API signatures , into your IDE's AI. No chatbot, just exact context.

Binary operations

Method Operator (ext) NumPy
add, sub, mul, div + - * / add subtract multiply true_divide
pow ** power
mod, floorDiv % remainder floor_divide (Python sign rules)
maximum, minimum NaN-propagating
atan2, hypot
eq ne lt le gt ge comparisons → bool
logicalAnd logicalOr logicalXor → bool
rsub, rdiv, rpow 2 - $a etc. reflected: the scalar on the left

All of them broadcast and accept PHP scalars, PHP arrays or arrays. On the FFI package they take an optional out: array that receives the result, which avoids an allocation in hot loops:

$acc = zeros(1_000_000);
foreach ($batches as $b) {
    $acc->add($b, out: $acc);
}

Integer overflow wraps (two's complement), exactly like NumPy. It is never undefined behaviour: the C kernel is tested under UBSan.

Unary functions

neg abs square sign sqrt exp log log10 log2 expm1 log1p sin cos tan arcsin arccos arctan sinh cosh tanh floor ceil rint reciprocal isnan isfinite isinf invert logicalNot, plus round($decimals) and clip($min, $max). The FFI package adds real imag conj angle for complex arrays.

Integer input to a floating-point function (sqrt, exp, …) gives float64.

Reductions

$x = arange(12)->reshape(3, 4)->astype('float64');

$x->sum();                        // 66.0
$x->sum(axis: 0);                 // column sums, shape [4]
$x->mean(axis: -1, keepdims: true);   // shape [3, 1]
$x->sum(axis: [0, 1]);            // several axes (FFI package)
$x->var(ddof: 1);                 // sample variance
$x->std(axis: 0);
$x->min(); $x->max(); $x->argmax();   // argmax: index into the flattened array
$x->any(); $x->all();
$x->cumsum(axis: 1);
$x->diff();                       // FFI package

Accuracy:

  • sum and mean use pairwise summation, like NumPy. The error grows with log n rather than n, so a million values sum to within a few ulps.
  • mean, var and std are computed as NumPy computes them: the mean is the pairwise sum divided by n, and the variance is the pairwise sum of squared deviations from that mean. This is stable when the mean is large compared with the spread (unlike the textbook E[x²]−E[x]² formula), and bit-identical to NumPy on contiguous data.
  • Reductions of integers accumulate in int64 (wrapping). The mean of integers is float64.
  • NaN propagates through sum, min, max, mean, as in NumPy.

Sorting

arr([3, 1, 2])->sort();            // [1, 2, 3]  (new array)
arr([3, 1, 2])->argsort();         // [1, 2, 0]
$m->sort(axis: 0);                 // along any axis

sort is a radix sort for every dtype (an MSD pass, then cache-sized LSD passes, with buckets sorted in parallel when threads > 1). argsort is a stable LSD radix sort. NaN sorts last, as in NumPy. On 1M float64 values sort takes about 30 ms against NumPy's 7.5 ms (AVX-512 quicksort), and argsort is on par with NumPy's stable argsort.

Matrix products

$a->matmul($b);        // or dot(); ext: $a->matmul($b)

Batched and broadcast like numpy.matmul. The FFI package calls OpenBLAS dgemm/sgemm when OpenBLAS is available, and otherwise a blocked C kernel that uses FMA. The extension always uses the C kernel.

Threads

Element-wise kernels on arrays of at least 131 072 elements are split across OpenMP threads when threads > 1 (Tessero::setThreads(), Engine::setMaxThreads(), tessero.threads). Each thread handles a contiguous chunk, so results are bit-identical to one thread. Reductions stay serial to keep the pairwise summation order fixed. See [Memory and threads(https://github.com/DMJ-CV-91913/tessero/blob/main/docs/operations/memory-and-threads.md).

Edit this page on GitHub