Standard library Numerics NDArray

Math and Scientific Computing

klyn.math combines scalar mathematics, typed multidimensional arrays, random sampling, complex numbers, and exact rational values. Generic numeric types remain visible to the compiler; NDArray<Double> uses contiguous native storage for hot kernels, while other numeric specializations currently retain boxed Klyn storage.

Scalar Mathematics
import klyn.math

radius = 4.0
area = Math.PI * radius ** 2

assert Math.gcd(84, 30) == 6
assert Math.fact(5) == 120
assert Math.sqrt(81) == 9.0
assert Math.isClose(Math.sin(Math.PI / 2.0), 1.0)

print(area)

Math exposes E, PI, and TAU, plus roots, trigonometric and hyperbolic functions, logarithms, powers, rounding, angle conversion, and helpers such as gcd() and fact(). Integer inputs return a Double when the mathematical result is not constrained to an integer.

Compare Floating-Point Results

Use Math.isClose() for computed floating-point values. Exact equality remains appropriate for values that are expected to have identical representations.

assert Math.isClose(0.1 + 0.2, 0.3)
assert Math.isClose(0.0, 1e-12, abs_tol=1e-9)
assert not Math.isClose(1.0, 1.0001)

assert not Math.isClose(nan, nan)
assert Math.isClose(inf, inf)
assert not Math.isClose(inf, -inf)

Defaults are rel_tol=1e-9 and abs_tol=0.0. Both tolerances must be non-negative. NaN is close to no value, and an infinity is close only to the same infinity.

Create Typed NDArrays
import klyn.math

matrix = NDArray<Double>.fromList([
    [1.0, 2.0, 3.0],
    [4.0, 5.0, 6.0]
])

assert matrix.ndim == 2u
assert matrix.size == 6u
assert matrix[1, 2] == 6.0

zeros = NDArray<Double>.zeros([2, 3])
ones = NDArray<Double>.ones([2, 3])
identity = NDArray<Double>.eye(3)

Shapes are validated before allocation, including negative dimensions and total-size overflow. fromList() rejects ragged rows instead of guessing a shape. Use reshape(), flatten(), and t to obtain new views or arrays without weakening the element type.

Calculate with Arrays
left = NDArray<Double>.fromList([
    [1.0, 2.0],
    [3.0, 4.0]
])
right = NDArray<Double>.eye(2)

sum = left + right
product = left @ right

assert product.toString() == left.toString()
assert Math.isClose(left.mean(), 2.5)
assert left.mean(axis=0).toString() == "[2.0, 3.0]"
assert left.argMin() == 0
assert left.argMax() == 3

Arithmetic operators are element-wise. @ performs matrix multiplication. Reductions include sum(), min(), max(), mean(), argMin(), and argMax(); axis-aware operations validate dimensions and axis bounds explicitly.

In-place sorting

sort() and sort(axis) modify the array and return the same instance. Arithmetic and mathematical transforms return new arrays.

Random Sampling
import klyn.math

roll = Random.randInt(1, 7)       # 1 through 6
temperature = Random.randRange(-5.0, 35.0)

names = ["Ada", "Grace", "Linus"]
selected = Random.choice(names)
Random.shuffle(names)

uniform = NDArray<Double>.random([4, 4])
normal = NDArray<Double>.randn([4, 4])

Integer ranges use an exclusive upper bound. choice() rejects an empty list, and shuffle() changes a mutable List in place.

Not for secrets

Random is for simulations, sampling, and application behavior. Use SecureRandom from klyn.cryptography for keys, tokens, salts, or any security-sensitive value.

Complex and Rational Values
Complex numbers
import klyn.math

z = Complex(3.0, 4.0)
conjugate = z.conjugate()

assert z.magnitude() == 5.0
assert conjugate.real == 3.0
assert conjugate.imag == -4.0
print(z.phase())
Exact rational numbers
import klyn.math

oneThird = Rational(1, 3)
oneSixth = Rational(1, 6)
result = oneThird + oneSixth

assert result == Rational(1, 2)
assert result.hash() == Rational(2, 4).hash()

Rational compares equivalent fractions by value, rejects a zero denominator, and implements a hash consistent with equality. Call simplify() when the stored numerator and denominator must be reduced. Complex<Float> can be used when float-sized components are required; Complex<Double> is the default.

Numerical Performance Guidelines
  • Choose the element type once and keep it stable through a calculation.
  • Prefer NDArray operators and transforms over repeatedly converting values to Object.
  • Allocate reusable arrays outside hot loops when the algorithm permits it.
  • Use toList() only at an API boundary; it copies every element.
  • Benchmark optimized Klyn execution rather than drawing conclusions from a --clean compile.