cheatah
Module

ndarray

Our own numpy-flavored N-dimensional array, generic over its element type, with full NumPy broadcasting.

The array is basic_ndarray<T> for any Field element type T — a real arithmetic type (int or float family) or a std::complex of a floating type, so complex matrices/vectors (and the complex eigenvalues a real matrix can have) are first-class. The element type is deduced from the literalsarray([1, 2, 3]) is an integer array, array([1.0, …]) is a double array. NDArray is the default basic_ndarray<double>. A complex array prints element-wise Python-style, e.g. [0+1j, 0-1j]. (Ordering-dependent ops like arange, and mean which returns a double, stay real-only.)

Elements live in a shared buffer (shared_ptr<vector<T>>); an array is a VIEW into it — {shape, strides, offset} — so reshape and broadcast are zero-copy (a stretched dimension just gets stride 0). Shared ownership keeps it memory-safe.

Element-wise ops vectorize declaratively: a contiguous fast path uses std::transform(std::execution::unseq, …) (and sum uses std::reduce(unseq)), so the compiler emits SIMD for any T; broadcast/strided views fall back to a correct C-order walk.

Usage

import io
import ndarray

let a = ndarray.array([1.0, 2.0, 3.0])                  # 1-D
let m = ndarray.array([[1.0, 2.0], [3.0, 4.0]])         # 2-D, shape read off the nesting
let t = ndarray.array([[[1.0], [2.0]], [[3.0], [4.0]]]) # 3-D — nests to any depth
let c = ndarray.add(m, ndarray.scalar(10.0))            # broadcasts the scalar
io.print(ndarray.to_string(c))

An ndarray is genuinely N-dimensional: array(...) infers the shape from a nested list to any rank (a ragged list is rejected, as in numpy), and broadcasting/reductions work at every rank — reshape is the other way to set a shape.

import ndarray includes ndarray.hpp and links libcheatah_ndarray.

API

Factories

  • array(values) — array from a list; a nested list builds an N-D array (array([[1,2],[3,4]]) is 2-D), with the shape inferred from the nesting.

  • scalar(value) — 0-D array (broadcasts to anything).

  • zeros(shape) / ones(shape) / full(shape, value) — filled arrays.

  • zeros_like(a) / ones_like(a) / full_like(a, value) — filled arrays with the same shape and element type as a (numpy's *_like family).

  • arange(start, stop, step) — 1-D range, like Python range.

  • reshape(a, shape) — same data, new shape (C-order).

  • a.astype(dtype) — convert the element type (numpy's a.astype), e.g. array([1,2,3]).astype(i16). This is how you build a narrow-element array for a smaller memory footprint (i8u64/f32/f64): the result is a real basic_ndarray<int16_t> (2 bytes/element, not 8). Widening is exact; narrowing truncates at the target width (like a numpy fixed dtype). A declared narrow type drives it too — let a: ndarray<i8> = array([…]) converts for you.

Broadcasting

  • broadcast_shapes(a, b) — the NumPy result shape of two shapes.

  • broadcast_to(a, target) — a zero-copy view of a stretched to target.

Element-wise ops (broadcasting)

  • add / sub / mul / dividea op b over the common shape.

Hot-loop notes (all selected automatically, nothing to call): infix a + b etc. are the same functions; an expiring operand's buffer is reused in place (a + b + c allocates once, not twice); and each op also has an allocation-free out-parameter overload (add(out, a, b)) in ndarray.hpp for buffer-reuse loops.

Element-wise math (numpy-style ufuncs)

The array forms of the scalar math module: where math.sqrt(x) takes one number, ndarray.sqrt(a) applies the function to every element of an array, SIMD-vectorized on the contiguous fast path:

  • sqrt / cbrt / exp / log — roots, exponential, natural log.

  • sin / cos / tan — trigonometric (radians).

  • abs — absolute value.

io.print(ndarray.to_string(ndarray.sqrt(ndarray.array([1.0, 4.0, 9.0]))))   # [1, 2, 3]

Complex

  • complex(re, im) — build a complex array from real & imaginary parts (broadcasts).

  • real(a) / imag(a) — the real / imaginary parts as a real array.

  • conj(a) — element-wise complex conjugate (identity on a real array).

let z = ndarray.complex(ndarray.array([0.0, 2.0]), ndarray.array([1.0, -3.0]))
io.print(ndarray.to_string(z))            # [0+1j, 2-3j]
io.print(ndarray.to_string(ndarray.conj(z)))   # [0-1j, 2+3j]

Reductions, access, display

  • sum(a) / mean(a) — reduce all elements.

  • get(a, index) — read one element (bounds-checked).

  • shape_of(a) / size_of(a) — query dimensions / element count.

  • to_string(a) — nested-bracket text, e.g. "[[1, 2], [3, 4]]".

The NDArray class exposes shape(), strides(), ndim(), size(), at(index), buffer(), and offset().

Negative dims/indices and size-overflowing shapes throw rather than corrupting memory.

Performance vs NumPy

The element-wise math ufuncs are benchmarked against NumPy's vectorized equivalents (same fixed-seed array to both, op run many times, results cross-checked) by scripts/numpy_compare.py. Each function's Performance row above carries its own number. The table below is generated by that harness — see docs/performance.md for the methodology (striated rounds, medians, paired ratios) and the reference machine. The band column is the range of the per-round ratios, which on the large-array rows is wide enough to matter: a bare headline would hide that sqrt at 16384 lands anywhere from 0.6× to 1.1× depending on the round.

op

operand dimensions

cheatah

NumPy

winner

band

ndarray.sqrt

64

0.09

0.35

cheatah 3.9x

3.48-4.12

ndarray.sqrt

16384

11.85

11.89

cheatah 1.0x

0.83-1.03

ndarray.exp

16384

10.66

46.94

cheatah 4.4x

3.61-4.66

ndarray.sin

16384

11.45

95.75

cheatah 8.5x

6.31-9.39

X + scalar

16384

2.85

3.07

cheatah 1.1x

0.94-1.40

ndarray.add

16384

3.43

9.62

cheatah 2.6x

1.71-2.97

exp/sin route their contiguous-double case through glibc's libmvec vector math (_ZGVdN4v_exp, …) compiled with -fveclib=libmvec -fno-math-errnowithout -ffast-math, so results stay strictly IEEE — and so beat NumPy ≈4–7× at 16384 elements. sqrt is memory-bandwidth-bound (wins small, ties large). The plain element-wise ops like add are bandwidth-bound too: their result buffer is allocated uninitialized (no throwaway zero-fill before the overwrite), so they read once and write once — matching or beating NumPy. See the Performance guide for the single-core-by-design rationale.

Per-function docs (parameters, complexity, heap behavior) are in ndarray.hpp. Tested in ../tests/ndarray_test.cpp; ASan + Valgrind clean via the QA gate (security/run-valgrind.sh).

Classes

Functions

fn std::vector< std::size_t > broadcast_shapes(const std::vector< std::size_t > &a, const std::vector< std::size_t > &b) source#

The broadcast result shape of two shapes (NumPy rules).

Aligns the shapes from the trailing (rightmost) dimension, treating missing leading dims as 1; each output dim is the non-1 input dim, and two unequal dims that are both not 1 are incompatible and throw.

Parameters
a

first shape.

b

second shape.

Returns

the broadcast shape (trailing-aligned).

Complexity

O(max(ndim)).

Allocation

allocates the small result vector; throws if the shapes are incompatible.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn long long subscript_index(Ix i) noexcept source#

The integer position an Subscript addresses.

For a scoped enum this is its underlying ordinal; this static_cast is the whole of the enum-to-index conversion the language sanctions.

Template parameters
Ix

the subscript type: an integer, or a scoped enum class.

Parameters
i

the subscript to resolve.

Returns

the integer position it names (a scoped enum's underlying ordinal).

Complexity

O(1).

Allocation

none.

fn bool is_contiguous(const basic_ndarray< T > &a) source#

Whether a is a contiguous C-order block (no broadcast/stride-0/permuted view), so its elements live consecutively from offset() and can be walked flatly.

Parameters
a

the array (or view) to test.

Returns

true if a's strides are the C-order strides for its shape.

Complexity

O(ndim).

Allocation

none.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > broadcast_to(const basic_ndarray< T > &a, const std::vector< std::size_t > &target) source#

A zero-copy view of a stretched to target (size-1 / missing dims get stride 0).

Parameters
a

source array.

target

the shape to stretch to.

Returns

a VIEW sharing a's buffer (no element copy).

Complexity

O(rank of target).

Allocation

no element copy — only the view's stride vector; throws if the shapes are not broadcast-compatible.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn array · 4 overloads
basic_ndarray< T > array(const std::vector< T > &values)source#
basic_ndarray< T > array(std::vector< T > &&values)source#
basic_ndarray< detail::nested_scalar_t< V > > array(const std::vector< V > &values)source#
basic_ndarray< T > array(std::initializer_list< T > values)source#

1-D array from a list of values; the element type is the list's element type (array([1,2,3]) is integer, array([1.0,…]) is double).

Parameters
values

the elements, copied into a fresh contiguous buffer.

Returns

a contiguous 1-D basic_ndarray<T>.

Complexity

O(n).

Allocation

allocates a new buffer of values.size() elements.

Compile-run testNdarrayCompileRun.Array
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > scalar(T value) source#

0-D scalar array (broadcasts to anything); element type deduced from value.

Parameters
value

the single element.

Returns

a 0-d basic_ndarray<T>.

Complexity

O(1).

Allocation

allocates a one-element buffer.

Compile-run testNdarrayCompileRun.Scalar
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn NDArray zeros(const std::vector< long long > &shape) source#

Array of shape filled with 0 (a double array by default; rejects negatives).

Parameters
shape

the dimensions (signed; throws on a negative).

Returns

a zero-filled NDArray.

Complexity

O(size).

Allocation

allocates a new buffer; throws on negative/overflowing dims.

Compile-run testNdarrayCompileRun.Zeros
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn NDArray ones(const std::vector< long long > &shape) source#

Array of shape filled with 1 (a double array by default; rejects negatives).

Parameters
shape

the dimensions (signed; throws on a negative).

Returns

a one-filled NDArray.

Complexity

O(size).

Allocation

allocates a new buffer; throws on negative/overflowing dims.

Compile-run testNdarrayCompileRun.Ones
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > full(const std::vector< long long > &shape, T value) source#

Array of shape filled with value; element type deduced from value.

Parameters
shape

the dimensions (signed; throws on a negative).

value

the fill value (its type is the array's element type).

Returns

a filled basic_ndarray<T>.

Complexity

O(size).

Allocation

allocates a new buffer; throws on negative/overflowing dims.

Compile-run testNdarrayCompileRun.Full
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > full_like(const basic_ndarray< T > &a, T value) source#

A fresh array with the SAME shape and element type as a, filled with value (≈ numpy.full_like).

The companion zeros_like / ones_like default the fill.

Parameters
a

the array whose shape and element type to mirror.

value

the fill value.

Returns

a same-shape basic_ndarray<T> filled with value.

Complexity

O(size).

Allocation

allocates a new buffer.

fn basic_ndarray< T > zeros_like(const basic_ndarray< T > &a) source#

A zero-filled array with the SAME shape and element type as a (≈ numpy.zeros_like) — the idiomatic way to allocate a matching gradient/velocity/scratch buffer for an existing array.

Parameters
a

the array whose shape and element type to mirror.

Returns

a same-shape basic_ndarray<T> of zeros.

Complexity

O(size).

Allocation

allocates a new buffer.

fn basic_ndarray< T > ones_like(const basic_ndarray< T > &a) source#

A one-filled array with the SAME shape and element type as a (≈ numpy.ones_like).

Parameters
a

the array whose shape and element type to mirror.

Returns

a same-shape basic_ndarray<T> of ones.

Complexity

O(size).

Allocation

allocates a new buffer.

fn basic_ndarray< T > arange(T start, T stop, T step) source#

1-D range [start, stop) stepping by step; element type deduced from the args.

Parameters
start

first value.

stop

exclusive bound.

step

increment (throws if zero); a step pointing away from stop yields empty.

Returns

a 1-D basic_ndarray<T> of the generated values.

Complexity

O(count).

Allocation

allocates a new buffer (built via a growing temporary vector, then copied); throws if step is zero.

Compile-run testNdarrayCompileRun.Arange
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > reshape(const basic_ndarray< T > &a, const std::vector< long long > &shape) source#

Reshape a to shape (same element count); reads in C-order so views/broadcasts are flattened into a fresh contiguous buffer (a copy, not an alias).

Parameters
a

source array.

shape

the new dimensions (signed; throws on a negative).

Returns

a new contiguous basic_ndarray<T> with the data in C-order.

Complexity

O(size).

Allocation

allocates a new buffer; throws on size mismatch or negative dims.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< U > astype(const basic_ndarray< T > &a) source#

Convert a to a new array with element type U — numpy's a.astype(dtype).

Every element is static_cast into U, so this is the way to build a NARROW-element array (a smaller memory footprint): array([1,2,3]).astype(i16) is a basic_ndarray<std::int16_t> — 2 bytes/element, not 8. Reads a in C-order (a view/broadcast is flattened into a fresh contiguous buffer — a copy, never an alias), same shape out as in. Widening is exact; narrowing truncates/wraps at the target width (as in C / a numpy fixed dtype). Constrained to conversions that actually exist (convertible_to), so e.g. complex→real fails with a clear concept error, not template spam.

Template parameters
U

the destination element type (the only type spelled at the call site).

Parameters
a

source array (any Field element type convertible to U).

Returns

a fresh contiguous basic_ndarray<U> of a's shape.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Astype
fn basic_ndarray< T > add(const basic_ndarray< T > &a, const basic_ndarray< T > &b) source#

Element-wise a + b with broadcasting.

Parameters
a

first operand.

b

second operand.

Returns

a + b broadcast to the common shape.

Complexity

O(size of result).

Allocation

allocates the result.

Compile-run testNdarrayCompileRun.Add
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > sub(const basic_ndarray< T > &a, const basic_ndarray< T > &b) source#

Element-wise a - b with broadcasting.

Parameters
a

first operand.

b

second operand.

Returns

a - b broadcast to the common shape.

Complexity

O(size of result).

Allocation

allocates the result.

Compile-run testNdarrayCompileRun.Sub
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > mul(const basic_ndarray< T > &a, const basic_ndarray< T > &b) source#

Element-wise a * b with broadcasting.

Parameters
a

first operand.

b

second operand.

Returns

a * b broadcast to the common shape.

Complexity

O(size of result).

Allocation

allocates the result.

Compile-run testNdarrayCompileRun.Mul
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > divide(const basic_ndarray< T > &a, const basic_ndarray< T > &b) source#

Element-wise a / b with broadcasting (an integer element type does integer division).

Parameters
a

numerator.

b

denominator (float division follows IEEE-754: /0 yields inf/nan, no throw).

Returns

a / b broadcast to the common shape.

Complexity

O(size of result).

Allocation

allocates the result.

Compile-run testNdarrayCompileRun.Divide
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn operator+ · 3 overloads
basic_ndarray< T > operator+(const basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > operator+(const basic_ndarray< T > &a, S s)source#
basic_ndarray< T > operator+(S s, const basic_ndarray< T > &a)source#

Elementwise infix forms: a + b, a - b, a * b, a / b (broadcasting).

Elementwise a + b with broadcasting (infix form of add()).

Parameters
a

first operand.

b

second operand.

Returns

the broadcast sum (a fresh array).

Complexity

O(size of result).

Allocation

the result.

fn operator- · 3 overloads
basic_ndarray< T > operator-(const basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > operator-(const basic_ndarray< T > &a, S s)source#
basic_ndarray< T > operator-(S s, const basic_ndarray< T > &a)source#

Elementwise a - b with broadcasting (infix form of sub()).

Parameters
a

first operand.

b

second operand.

Returns

the broadcast difference (a fresh array).

Complexity

O(size of result).

Allocation

the result.

fn operator* · 3 overloads
basic_ndarray< T > operator*(const basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > operator*(const basic_ndarray< T > &a, S s)source#
basic_ndarray< T > operator*(S s, const basic_ndarray< T > &a)source#

Elementwise a * b with broadcasting (infix form of mul()).

Parameters
a

first operand.

b

second operand.

Returns

the broadcast product (a fresh array).

Complexity

O(size of result).

Allocation

the result.

fn operator/ · 3 overloads
basic_ndarray< T > operator/(const basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > operator/(const basic_ndarray< T > &a, S s)source#
basic_ndarray< T > operator/(S s, const basic_ndarray< T > &a)source#

Elementwise a / b with broadcasting (infix form of divide()).

Parameters
a

numerator.

b

denominator.

Returns

the broadcast quotient (a fresh array).

Complexity

O(size of result).

Allocation

the result.

fn operator+= · 2 overloads
basic_ndarray< T > & operator+=(basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > & operator+=(basic_ndarray< T > &a, S s)source#

In-place compound assignment: a += b, a -= b, a *= b, a /= b (array or arithmetic-scalar right operand).

See compound_apply. In-place a += b, updating a's buffer (see compound_apply).

Parameters
a

the array to update in place.

b

the right operand (same shape or single-element).

Returns

reference to a.

Complexity

O(size of a).

Allocation

none on the contiguous fast path.

fn operator-= · 2 overloads
basic_ndarray< T > & operator-=(basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > & operator-=(basic_ndarray< T > &a, S s)source#

In-place a -= b, updating a's buffer (see compound_apply).

Parameters
a

the array to update in place.

b

the right operand (same shape or single-element).

Returns

reference to a.

Complexity

O(size of a).

Allocation

none on the contiguous fast path.

fn operator*= · 2 overloads
basic_ndarray< T > & operator*=(basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > & operator*=(basic_ndarray< T > &a, S s)source#

In-place a *= b, updating a's buffer (see compound_apply).

Parameters
a

the array to update in place.

b

the right operand (same shape or single-element).

Returns

reference to a.

Complexity

O(size of a).

Allocation

none on the contiguous fast path.

fn operator/= · 2 overloads
basic_ndarray< T > & operator/=(basic_ndarray< T > &a, const basic_ndarray< T > &b)source#
basic_ndarray< T > & operator/=(basic_ndarray< T > &a, S s)source#

In-place a /= b, updating a's buffer (see compound_apply).

Parameters
a

the array to update in place.

b

the right operand (same shape or single-element).

Returns

reference to a.

Complexity

O(size of a).

Allocation

none on the contiguous fast path.

fn basic_ndarray< std::complex< T > > complex(const basic_ndarray< T > &re, const basic_ndarray< T > &im) source#

Build a complex array from real and imaginary parts (element-wise re + im·j), broadcasting the two together — the way to construct a complex matrix/vector (a wavefunction, a Hermitian operator) since cheatah literals are real.

Parameters
re

the real parts (a real floating array).

im

the imaginary parts (a real floating array, broadcast against re).

Returns

a basic_ndarray<std::complex<T>> of re + im·j; throws if the shapes don't broadcast.

Complexity

O(size of result).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > conj(const basic_ndarray< T > &a) source#

Element-wise complex conjugate (a − b·j for each a + b·j); on a real array it is the identity (a copy).

Type-preserving. Used to form Hermitian adjoints and conjugate-linear inner products.

Parameters
a

the array.

Returns

a fresh array of the same element type with each element conjugated.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Conj
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< real_base_t< T > > real(const basic_ndarray< T > &a) source#

The real parts as a real array (the identity on a real array).

For a + b·j it returns a.

Parameters
a

the array.

Returns

a basic_ndarray<real_base_t<T>> of the real parts.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Real
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< real_base_t< T > > imag(const basic_ndarray< T > &a) source#

The imaginary parts as a real array (all zeros for a real array).

For a + b·j it returns b.

Parameters
a

the array.

Returns

a basic_ndarray<real_base_t<T>> of the imaginary parts.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Imag
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > sqrt(const basic_ndarray< T > &a) source#

Element-wise square root (the array form of math.sqrt; ≈ numpy.sqrt).

Parameters
a

a floating-point array.

Returns

a fresh same-shape array with √x for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Sqrt
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > cbrt(const basic_ndarray< T > &a) source#

Element-wise cube root (the array form of math.cbrt; ≈ numpy.cbrt).

Parameters
a

a floating-point array.

Returns

a fresh same-shape array with ∛x for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > exp(const basic_ndarray< T > &a) source#

Element-wise eˣ (the array form of math.exp; ≈ numpy.exp).

Parameters
a

a floating-point array.

Returns

a fresh same-shape array with exp(x) for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Exp
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > log(const basic_ndarray< T > &a) source#

Element-wise natural log (the array form of math.log; ≈ numpy.log).

Parameters
a

a floating-point array.

Returns

a fresh same-shape array with ln(x) for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > sin(const basic_ndarray< T > &a) source#

Element-wise sine (the array form of math.sin; ≈ numpy.sin).

Parameters
a

a floating-point array (radians).

Returns

a fresh same-shape array with sin(x) for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Compile-run testNdarrayCompileRun.Sin
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > cos(const basic_ndarray< T > &a) source#

Element-wise cosine (the array form of math.cos; ≈ numpy.cos).

Parameters
a

a floating-point array (radians).

Returns

a fresh same-shape array with cos(x) for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > tan(const basic_ndarray< T > &a) source#

Element-wise tangent (the array form of math.tan; ≈ numpy.tan).

Parameters
a

a floating-point array (radians).

Returns

a fresh same-shape array with tan(x) for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn basic_ndarray< T > abs(const basic_ndarray< T > &a) source#

Element-wise absolute value (the array form of math.abs; ≈ numpy.abs).

Parameters
a

a floating-point array.

Returns

a fresh same-shape array with |x| for each element.

Complexity

O(size).

Allocation

allocates the result buffer.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn T sum(const basic_ndarray< T > &a) source#

Sum of all elements — a full reduction across every axis (a contiguous array goes through the shared multi-accumulator SIMD reduction detail::reduce_lanes, else a C-order walk); empty sums to 0.

Parameters
a

the array.

Returns

the total, as the element type T.

Complexity

O(size).

Allocation

none.

Compile-run testNdarrayCompileRun.Sum
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn double mean(const basic_ndarray< T > &a) source#

Mean of all elements, always as a double (0.0 for an empty array — no divide-by-zero).

Parameters
a

the array.

Returns

the average as a double.

Complexity

O(size).

Allocation

none.

Compile-run testNdarrayCompileRun.Mean
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn T get(const basic_ndarray< T > &a, const std::vector< long long > &index) source#

Read one element by signed multi-index (the cheatah-facing wrapper over basic_ndarray::at; rejects negative coordinates).

Parameters
a

the array.

index

one coordinate per dimension (signed; throws on a negative).

Returns

the element value (type T); throws on a wrong-rank/out-of-range index.

Complexity

O(ndim).

Allocation

none.

Compile-run testNdarrayCompileRun.Get
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn std::vector< long long > shape_of(const basic_ndarray< T > &a) source#

The shape as signed dims (cheatah integers are signed; a 0-d array yields an empty list).

Parameters
a

the array.

Returns

the dimensions as a long long vector.

Complexity

O(ndim).

Allocation

allocates the result vector.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn long long size_of(const basic_ndarray< T > &a) source#

The element count as a signed value (1 for a 0-d array).

Parameters
a

the array.

Returns

the number of elements as a long long.

Complexity

O(ndim).

Allocation

none.

Compile-run testNdarrayCompileRun.SizeOf
Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn std::string to_string(const basic_ndarray< T > &a) source#

Render as a nested-bracket string, e.g.

"[[1, 2], [3, 4]]" (a 0-d scalar renders as the bare number). Each element is formatted with the default ostream precision.

Parameters
a

the array.

Returns

the textual representation.

Complexity

O(size).

Allocation

allocates the result string.

Performancenumeric — the honest baseline is NumPy/LAPACK, not a pure-Python loop; see the vs-NumPy table on this page
fn std::ostream & operator<<(std::ostream &os, const basic_ndarray< T > &a) source#

Stream an array to a std::ostream (the FULL nested-bracket form) — so an NDArray is directly Streamable, like a primitive or a cheatah struct, without going through to_string/str().

io.rprint, str(), and a struct that holds an array all stream it this way; io.print instead uses cheatah_pretty_print to abbreviate large arrays.

Parameters
os

the stream.

a

the array.

Returns

os.

Complexity

O(size).

Allocation

allocates the intermediate string.

Constants & variables

var bool is_complex_v source#

Whether T is a std::complex of a floating type — the trait behind Field.

Types

type typename real_base< T >::type real_base_t source#

The real type underlying a Field T (double for both double and complex<double>).

type std::complex< real_base_t< T > > complex_of_t source#

complex_of_t<T>: the complex type over T's real base.

eig/eigvals return an array of these, because a real matrix can have complex eigenvalues (conjugate pairs) — e.g. the rotation matrix [[0,-1],[1,0]] has eigenvalues ±i.

type std::vector< T, detail::default_init_allocator< T > > buffer_t source#

The backing store of an ndarray: a flat, contiguous, shared element buffer.

It uses detail::default_init_allocator so a freshly-sized result buffer that an op is about to overwrite in full is not needlessly zero-filled first. zeros/full/scalar, which value-fill, are unaffected — only the no-value sizing path skips initialization.

type basic_ndarray< double > NDArray source#

The default ndarray element type is doubleNDArray names that instantiation (the std::string ↔ std::basic_string<char> pattern), so existing code and the linalg routines keep working unchanged.