23  API Reference

Complete reference for the scicloj.lalinea public API:

scicloj.lalinea.tensor

matrix

[rows]

Create a matrix (rank-2 tensor) from nested sequences.

(matrix [[1 2] [3 4]])
(t/matrix [[1 2] [3 4]])
#la/R [:float64 [2 2]
       [[1.000 2.000]
        [3.000 4.000]]]

eye

[n]

Identity matrix of size \(n \times n\).

(t/eye 3)
#la/R [:float64 [3 3]
       [[1.000 0.000 0.000]
        [0.000 1.000 0.000]
        [0.000 0.000 1.000]]]

zeros

[r c]

Zero matrix of size \(r \times c\).

(t/zeros 2 3)
#la/R [:float64 [2 3]
       [[0.000 0.000 0.000]
        [0.000 0.000 0.000]]]

ones

[r c]

Matrix of ones, size \(r \times c\).

(t/ones 2 3)
#la/R [:float64 [2 3]
       [[1.000 1.000 1.000]
        [1.000 1.000 1.000]]]

diag

[a]

Diagonal operations:

  • Given a 2D matrix: extract the main diagonal as a 1D tensor.
  • Given a 1D sequence/tensor: create a diagonal matrix.
(t/diag [3 5 7])
#la/R [:float64 [3 3]
       [[3.000 0.000 0.000]
        [0.000 5.000 0.000]
        [0.000 0.000 7.000]]]

Extract diagonal from a 2D matrix:

(t/diag (t/matrix [[1 2 3] [4 5 6] [7 8 9]]))
#la/R [:float64 [3] [1.000 5.000 9.000]]

column

[xs]

Create a column vector (shape [n 1]) from a sequence.

(t/column [1 2 3])
#la/R [:float64 [3 1]
       [[1.000]
        [2.000]
        [3.000]]]

row

[xs]

Create a row vector (shape [1 n]) from a sequence.

(t/row [1 2 3])
#la/R [:float64 [1 3]
       [[1.000 2.000 3.000]]]

compute-matrix

[r c f]

Build an [r c] matrix from a function of row and column indices. f takes two longs (row, col) and returns a double.

(t/compute-matrix 3 3 (fn [i j] (if (== i j) 1.0 0.0)))
#la/R [:float64 [3 3]
       [[1.000 0.000 0.000]
        [0.000 1.000 0.000]
        [0.000 0.000 1.000]]]

compute-tensor

[shape-vec f datatype]

Create a tensor by calling a function at each index. Returns a RealTensor for 1D and 2D shapes, raw tensor for 3D+. Use materialize or clone to force evaluation when needed.

(t/compute-tensor [2 3] (fn [i j] (+ (* 10.0 i) j)) :float64)
#la/R [:float64 [2 3]
       [[0.000 1.000 2.000]
        [10.00 11.00 12.00]]]

complex-tensor

[tensor-or-re]

[re-data im-data]

Create a ComplexTensor.

Arities: (complex-tensor tensor) — wrap an existing tensor with last dim = 2 (complex-tensor re-data im-data) — from separate real and imaginary parts

re-data and im-data can be: double arrays, seqs, dtype readers, or tensors. They must have the same shape.

(t/complex-tensor [1.0 2.0 3.0] [4.0 5.0 6.0])
#la/C [:float64 [3] [1.000 + 4.000 i  2.000 + 5.000 i  3.000 + 6.000 i]]

complex-tensor-real

[re-data]

Create a ComplexTensor from real data only (imaginary parts = 0).

(t/complex-tensor-real [5.0 6.0 7.0])
#la/C [:float64 [3] [5.000 + 0.000 i  6.000 + 0.000 i  7.000 + 0.000 i]]

complex

[re im]

Create a scalar ComplexTensor from real and imaginary parts.

(t/complex 3.0 4.0)
#la/C [:float64 [] [3.000 + 4.000 i]]

wrap-tensor

Wrap a raw interleaved [… 2] tensor as a ComplexTensor. Inverse of ->tensor on ComplexTensors.

(let [raw (t/matrix [[1.0 2.0] [3.0 4.0]])
      ct (t/wrap-tensor raw)]
  [(t/complex? ct) (t/complex-shape ct)])
[true [2]]

real-tensor?

[x]

True if x is a RealTensor.

(t/real-tensor? (t/matrix [[1 2] [3 4]]))
true
(t/real-tensor? [1 2 3])
false

complex?

True if x is a ComplexTensor.

(t/complex? (t/complex 3.0 4.0))
true
(t/complex? (t/eye 2))
false

scalar?

True if this ComplexTensor represents a scalar complex number.

(t/scalar? (t/complex 3.0 4.0))
true

shape

[a]

Return the logical shape of a tensor as a vector. For ComplexTensors, returns the complex shape (without the trailing interleaved dimension).

(t/shape (t/matrix [[1 2 3] [4 5 6]]))
[2 3]

For ComplexTensors, returns the logical shape (without the trailing interleaved dimension):

(t/shape (t/complex-tensor [1.0 2.0] [3.0 4.0]))
[2]

complex-shape

The complex shape (underlying shape without trailing 2).

(t/complex-shape (t/complex-tensor [[1.0 2.0] [3.0 4.0]]
                                   [[5.0 6.0] [7.0 8.0]]))
[2 2]

reshape

[a new-shape]

Reshape a tensor to a new shape. Zero-copy when possible. Returns a RealTensor for real input, ComplexTensor for complex.

(t/reshape (t/matrix [[1 2] [3 4]]) [4])
#la/R [:float64 [4] [1.000 2.000 3.000 4.000]]

select

[a & args]

Slice a tensor along dimensions. Each argument selects along one axis: an index (long), :all, or a sequence of indices. Returns a RealTensor for real input, ComplexTensor for complex.

Row 0 of a matrix:

(t/select (t/matrix [[1 2] [3 4] [5 6]]) 0 :all)
#la/R [:float64 [2] [1.000 2.000]]

submatrix

[m rows cols]

Extract a contiguous submatrix. rows and cols can be :all or a range.

For ComplexTensors, operates on the complex dimensions and preserves the ComplexTensor type.

(t/submatrix (t/eye 4) :all (range 2))
#la/R [:float64 [4 2]
       [[1.000 0.000]
        [0.000 1.000]
        [0.000 0.000]
        [0.000 0.000]]]

flatten

[a]

Reshape a tensor to 1D, preserving element order. Column vectors [n 1] become [n], matrices [r c] become [r*c]. For ComplexTensors, flattens the logical dimensions (trailing 2 preserved).

(t/flatten (t/column [1 2 3]))
#la/R [:float64 [3] [1.000 2.000 3.000]]

hstack

[cols]

Assemble a matrix by placing column vectors side by side. Each element should be a column vector [n 1] or a 1D tensor [n]. Returns an [n k] matrix where k is the number of columns.

(t/hstack [(t/column [1 2]) (t/column [3 4])])
#la/R [:float64 [2 2]
       [[1.000 3.000]
        [2.000 4.000]]]

reduce-axis

[a reduce-fn axis]

Reduce a tensor along an axis.

reduce-fn is applied to each slice along the given axis (e.g. elem/sum, elem/reduce-max).

For a 2D matrix: axis 0 reduces across rows (one result per column), axis 1 reduces across columns (one result per row).

Returns a RealTensor for real input, ComplexTensor for complex input.

Row sums (axis 1) and column sums (axis 0):

(t/reduce-axis (t/matrix [[1 2 3] [4 5 6]]) el/sum 1)
#la/R [:float64 [2] [6.000 15.00]]

clone

[a]

Deep-copy a tensor into a fresh contiguous array. Always allocates, even when the input is already concrete. Use materialize when you only need to ensure the result is concrete without a redundant copy.

Always allocates a fresh copy:

(let [m (t/matrix [[1 2] [3 4]])]
  (identical? m (t/clone m)))
false

concrete?

[a]

True if the tensor is backed by a contiguous array (not a lazy reader chain).

Concrete (backed by array):

(t/concrete? (t/matrix [[1 2] [3 4]]))
true

Lazy (reader chain from el/+):

(t/concrete? (el/+ (t/matrix [[1 2] [3 4]])
                   (t/matrix [[10 20] [30 40]])))
false

materialize

[a]

Ensure a tensor is backed by a contiguous array. Returns the input unchanged if already concrete; clones if lazy. Use clone when you need a guaranteed independent copy.

No-op on concrete:

(let [m (t/matrix [[1 2] [3 4]])]
  (identical? m (t/materialize m)))
true

Materializes lazy results:

(t/materialize (el/+ (t/matrix [[1 2] [3 4]])
                     (t/matrix [[10 20] [30 40]])))
#la/R [:float64 [2 2]
       [[11.00 22.00]
        [33.00 44.00]]]

->tensor

[x]

Extract the underlying dtype-next tensor from a RealTensor or ComplexTensor. Returns x unchanged if it is neither.

(t/->tensor (t/matrix [[1 2] [3 4]]))
#tech.v3.tensor<float64>[2 2]
[[1.000 2.000]
 [3.000 4.000]]

For ComplexTensors, returns the underlying [... 2] tensor:

(t/shape (t/->tensor (t/complex-tensor [1.0 2.0] [3.0 4.0])))
[2 2]

->real-tensor

[t]

Wrap a dtype-next tensor in a RealTensor.

(t/->real-tensor (t/matrix [[1 2] [3 4]]))
#la/R [:float64 [2 2]
       [[1.000 2.000]
        [3.000 4.000]]]

->double-array

[a]

Get the backing double[] of a tensor. Zero-copy when the tensor is backed by a contiguous array; copies for subviews or lazy tensors. Works for both RealTensors and ComplexTensors.

(let [arr (t/->double-array (t/matrix [[1 2] [3 4]]))]
  (alength arr))
4

For ComplexTensors, returns the interleaved [re im ...] array:

(let [ct (t/complex-tensor [1.0 2.0] [3.0 4.0])]
  (seq (t/->double-array ct)))
(1.0 3.0 2.0 4.0)

backing-array

[t]

Return the shared backing double[] of a tensor, or nil if the tensor is lazy or not array-backed. Never copies. Useful for checking whether two tensors share memory.

(let [A (t/matrix [[1 2] [3 4]])
      B (t/clone A)]
  [(some? (t/backing-array A))
   (identical? (t/backing-array A)
               (t/backing-array B))])
[true false]

->reader

[a]

[a datatype]

Get a read-only indexed view of a tensor’s elements.

(let [rdr (t/->reader (t/column [10 20 30]))]
  (rdr 2))
30.0

array-buffer

[a]

Return the array buffer backing a tensor, or nil if none exists (e.g. for lazy or strided tensors).

(some? (t/array-buffer (t/clone (t/eye 3))))
true

make-reader

[datatype n body]

Create a lazy functional buffer that computes values on the fly. idx is bound in the body expression. Returns a raw dtype-next reader (not a RealTensor) for compatibility with dataset pipelines.

(t/make-reader :float64 10 (* 2.0 idx))
(t/make-reader :float64 5 (* idx idx))
[0.0 1.0 4.0 9.0 16.0]

make-container

[datatype n-or-data]

Create a mutable buffer of the given dtype and size (or from data). Returns a RealTensor wrapping a concrete buffer.

(t/make-container :float64 4)
#la/R [:float64 [4] [0.000 0.000 0.000 0.000]]

elemwise-cast

[a datatype]

Cast a tensor or buffer to a different element type. Returns a raw dtype-next buffer.

(t/elemwise-cast (t/matrix [[1 2] [3 4]]) :int32)
#tech.v3.tensor<int32>[2 2]
[[1 2]
 [3 4]]

mset!

[a & args-and-val]

Mutate a tensor element in place. Takes a tensor, indices, and a value. For RealTensors, unwraps to the backing tensor before mutation.

(let [m (t/clone (t/matrix [[1 2] [3 4]]))]
  (t/mset! m 0 0 99.0)
  (m 0 0))
99.0

set-value!

[a idx val]

Set a value at a flat (linear) index. Mutates in place.

(let [buf (t/make-container :float64 3)]
  (t/set-value! buf 1 42.0)
  (buf 1))
42.0

tensor->dmat

[tensor]

Zero-copy: convert a [r c] tensor to an EJML DMatrixRMaj sharing the same double[]. Falls back to a copy for lazy/strided tensors.

(let [t (t/matrix [[1 2] [3 4]])
      dm (t/tensor->dmat t)]
  (= org.ejml.data.DMatrixRMaj (type dm)))
true

dmat->tensor

[dm]

Zero-copy: convert an EJML DMatrixRMaj to a raw [r c] dtype-next tensor sharing the same double[]. Wrap with ->real-tensor if needed.

(let [dm (t/tensor->dmat (t/eye 2))
      t (t/dmat->tensor dm)]
  (= [2 2] (t/shape t)))
true

complex-tensor->zmat

[ct]

Zero-copy: convert a ComplexTensor to an EJML ZMatrixRMaj sharing the same double[]. Falls back to a copy for lazy ComplexTensors.

(let [ct (t/complex-tensor [1.0 2.0] [3.0 4.0])
      zm (t/complex-tensor->zmat ct)]
  (= org.ejml.data.ZMatrixRMaj (type zm)))
true

zmat->complex-tensor

[zm]

Zero-copy: convert an EJML ZMatrixRMaj to a ComplexTensor [r c] sharing the same double[].

(let [zm (t/complex-tensor->zmat (t/complex-tensor [1.0 2.0] [3.0 4.0]))
      ct (t/zmat->complex-tensor zm)]
  (t/complex? ct))
true

scicloj.lalinea.linalg

Most la/ functions are polymorphic — they accept both real tensors and ComplexTensors.

mmul

[a b]

Matrix multiply. Accepts dtype-next tensors or ComplexTensors.

For real matrices: \(C = A B\). For complex matrices: delegates to EJML’s ZMatrixRMaj multiply.

(la/mmul (t/matrix [[1 2] [3 4]])
         (t/column [5 6]))
#la/R [:float64 [2 1]
       [[17.00]
        [39.00]]]

dot

[u v]

Inner product. For real vectors: \(\sum u_i v_i\) (returns double). For complex vectors: Hermitian \(\langle u,v \rangle = \sum u_i \overline{v_i}\) (returns scalar ComplexTensor).

(la/dot (t/column [1 2 3]) (t/column [4 5 6]))
32.0

dot-conj

[u v]

Hermitian inner product: \(\sum u_i \overline{v_i}\). For real vectors: same as dot (\(\sum u_i v_i\)). For complex vectors: \(\sum u_i \overline{v_i}\) (returns scalar ComplexTensor).

Hermitian inner product: \(\langle a, a \rangle = \|a\|^2\).

(let [a (t/complex-tensor [3.0 1.0] [4.0 2.0])
      result (la/dot-conj a a)]
  (la/close-scalar? (el/re result) 30.0))
true

mpow

[a k]

Matrix power \(A^k\) for non-negative integer \(k\). Uses exponentiation by squaring — \(O(\log k)\) multiplications. Returns the identity for \(k=0\).

(la/mpow (t/matrix [[1 1] [0 1]]) 5)
#la/R [:float64 [2 2]
       [[1.000 5.000]
        [0.000 1.000]]]

transpose

[a]

Matrix transpose (real) or conjugate transpose (complex).

For real matrices: returns a zero-copy strided view sharing the same backing data. For complex matrices: \(B = A^\dagger\) (Hermitian adjoint).

(la/transpose (t/matrix [[1 2 3] [4 5 6]]))
#la/R [:float64 [3 2]
       [[1.000 4.000]
        [2.000 5.000]
        [3.000 6.000]]]

trace

[a]

Matrix trace. Returns a double for real matrices, a scalar ComplexTensor for complex matrices.

(la/trace (t/matrix [[1 2] [3 4]]))
5.0

det

[a]

Matrix determinant. Returns a double for real matrices, a scalar ComplexTensor for complex matrices.

(la/det (t/matrix [[1 2] [3 4]]))
-2.0

norm

[a]

Frobenius norm.

(la/norm (t/matrix [[3 0] [0 4]]))
5.0

rank

[a]

[a tol]

Matrix rank: number of singular values above tol (default 1e-10).

(la/rank (t/matrix [[1 2] [2 4]]))
1

condition-number

[a]

Condition number \(\kappa(A) = \sigma_{\max} / \sigma_{\min}\) from the SVD.

(la/condition-number (t/matrix [[2 1] [1 3]]))
2.618033988749894

solve

[a b]

Solve \(AX = B\) for \(X\). Returns nil if singular. \(A\) is [n n], \(B\) is [n m]. Returns \(X\) as a RealTensor or ComplexTensor.

Solve \(Ax = b\):

(let [A (t/matrix [[2 1] [1 3]])
      b (t/column [5 7])]
  (la/solve A b))
#la/R [:float64 [2 1]
       [[1.600]
        [1.800]]]

invert

[a]

Matrix inverse. Returns nil if singular.

(let [A (t/matrix [[1 2] [3 5]])]
  (la/close? (la/mmul A (la/invert A)) (t/eye 2)))
true

lstsq

[a b]

[a b tol]

Least-squares solve: minimise \(\|Ax - b\|_2\). Returns a map with :x, :residuals (\(\|Ax-b\|^2\)), and :rank.

(let [{:keys [x rank]} (la/lstsq (t/matrix [[1 1] [1 2] [1 3]])
                                 (t/column [1 2 3]))]
  {:rank rank :close? (la/close? x (t/column [0 1]))})
{:rank 2, :close? true}

pinv

[a]

[a tol]

Moore-Penrose pseudoinverse via SVD: \(V \Sigma^{-1} U^T\). Singular values below tol (default 1e-10) are treated as zero.

(let [A (t/matrix [[2 1] [1 3]])]
  (la/close? (la/mmul A (la/pinv A)) (t/eye 2)))
true

eigen

[a]

Eigendecomposition of a real matrix. Returns a map: :eigenvalues — ComplexTensor of shape [n] (complex vector) :eigenvectors — vector of column eigenvectors as real tensors (or nil)

Use (el/re (:eigenvalues result)) for the real parts, or real-eigenvalues for a sorted real tensor.

(let [result (la/eigen (t/matrix [[2 1] [1 2]]))]
  [(count (:eigenvectors result))
   (t/complex-shape (:eigenvalues result))])
[2 [2]]

real-eigenvalues

[a]

Sorted real eigenvalues of a symmetric/Hermitian matrix. Returns a real [n] tensor, sorted ascending.

(la/real-eigenvalues (t/matrix [[2 1] [1 2]]))
#la/R [:float64 [2] [1.000 3.000]]

svd

[a]

Singular value decomposition of a real matrix: \(A = U \Sigma V^T\). Returns a map with :U, :S (singular values), :Vt.

(let [{:keys [U S Vt]} (la/svd (t/matrix [[1 0] [0 2] [0 0]]))]
  [(t/shape U)
   (count S)
   (t/shape Vt)])
[[3 3] 2 [2 2]]

qr

[a]

QR decomposition: \(A = QR\). Returns a map with :Q and :R.

(let [{:keys [Q R]} (la/qr (t/matrix [[1 1] [1 2] [0 1]]))]
  (la/close? (la/mmul Q R) (t/matrix [[1 1] [1 2] [0 1]])))
true

cholesky

[a]

Cholesky decomposition: \(A = LL^T\) (real) or \(A = LL^\dagger\) (complex). Returns the lower-triangular \(L\), or nil if not SPD/HPD.

(let [A (t/matrix [[4 2] [2 3]])
      L (la/cholesky A)]
  (la/close? (la/mmul L (la/transpose L)) A))
true

null-space

[a]

[a tol]

Null space basis: columns of \(V\) corresponding to singular values \(\approx 0\). Returns a matrix whose columns span \(\mathrm{Null}(A)\), or nil if full rank.

(let [ns (la/null-space (t/matrix [[1 2] [2 4]]))]
  (la/close? (la/mmul (t/matrix [[1 2] [2 4]]) ns)
             (t/zeros 2 1)))
true

col-space

[a]

[a tol]

Column space basis: first \(r\) columns of \(U\) from the SVD, where \(r\) is the number of singular values above tol.

(second (t/shape (la/col-space (t/matrix [[1 2] [2 4]]))))
1

close?

[a b]

[a b tol]

True when two matrices (or ComplexTensors) are approximately equal: \(\|a - b\|_F < \mathrm{tol}\). Default tolerance is 1e-10.

(la/close? (t/eye 2) (t/eye 2))
true
(la/close? (t/eye 2) (t/zeros 2 2))
false

close-scalar?

[a b]

[a b tol]

True when two scalars are approximately equal: \(|a - b| < \mathrm{tol}\). Default tolerance is 1e-10.

(la/close-scalar? 1.00000000001 1.0)
true

lift

[f-or-var & args]

Apply an external function to La Linea tensors (one-shot).

Unwraps RealTensor/ComplexTensor arguments, applies f, and re-wraps the result. Pass a Var for tape recording: (la/lift #’dfn/sqrt A) ;; tape-recorded (la/lift dfn/sqrt A) ;; not recorded

One-shot bridge: unwrap, apply, re-wrap. Pass a Var for tape recording.

(la/lift el/sqrt (t/matrix [[4 9] [16 25]]))
#la/R [:float64 [2 2]
       [[2.000 3.000]
        [4.000 5.000]]]

lifted

[f-or-var]

Return a lifted version of an external function (curried).

Pass a Var for tape recording: (def my-sqrt (la/lifted #’dfn/sqrt)) ;; tape-aware (def my-sqrt (la/lifted dfn/sqrt)) ;; not recorded

Curried version — returns a reusable function.

(let [my-sqrt (la/lifted el/sqrt)]
  (my-sqrt (t/column [4 9 16])))
#la/R [:float64 [3 1]
       [[2.000]
        [3.000]
        [4.000]]]

scicloj.lalinea.elementwise

The canonical namespace for element-wise operations. All functions are tape-aware and dispatch on t/complex? for complex inputs. Naming follows dtype-next’s dfn/ conventions (+, -, *, /).

+

[a b]

Element-wise addition.

(el/+ (t/column [1 2 3]) (t/column [10 20 30]))
#la/R [:float64 [3 1]
       [[11.00]
        [22.00]
        [33.00]]]

Complex addition:

(let [a (t/complex-tensor [1.0 2.0] [3.0 4.0])
      b (t/complex-tensor [10.0 20.0] [30.0 40.0])]
  (el/re (el/+ a b)))
#la/R [:float64 [2] [11.00 22.00]]

-

[a b]

Element-wise subtraction.

(el/- (t/column [10 20 30]) (t/column [1 2 3]))
#la/R [:float64 [3 1]
       [[9.000]
        [18.00]
        [27.00]]]

scale

[a alpha]

Scalar multiply. Returns α · a.

(el/scale (t/column [2 3 4]) 5.0)
#la/R [:float64 [3 1]
       [[10.00]
        [15.00]
        [20.00]]]

*

[a b]

Element-wise multiply (Hadamard product for real, pointwise complex multiply for complex).

(el/* (t/column [2 3 4]) (t/column [10 20 30]))
#la/R [:float64 [3 1]
       [[20.00]
        [60.00]
        [120.0]]]

Complex multiplication: \((1+3i)(2+4i) = -10 + 10i\)

(let [a (t/complex-tensor [1.0] [3.0])
      b (t/complex-tensor [2.0] [4.0])
      c (el/* a b)]
  [(el/re (c 0)) (el/im (c 0))])
[-10.0 10.0]

/

[a b]

Element-wise division. Supports both real and complex inputs.

(el// (t/column [10 20 30]) (t/column [2 4 5]))
#la/R [:float64 [3 1]
       [[5.000]
        [5.000]
        [6.000]]]

Complex division:

(el// (t/complex 3.0 4.0) (t/complex 1.0 2.0))
#la/C [:float64 [] [2.200 - 0.4000 i]]

re

[a]

Real part(s). For complex: returns a RealTensor view (or double for scalars). For real: returns the input unchanged.

(el/re (t/complex-tensor [1.0 2.0] [3.0 4.0]))
#la/R [:float64 [2] [1.000 2.000]]

im

[a]

Imaginary part(s). For complex: returns a RealTensor view (or double for scalars). For real: returns zeros matching the input shape.

(el/im (t/complex-tensor [1.0 2.0] [3.0 4.0]))
#la/R [:float64 [2] [3.000 4.000]]

conj

[a]

Complex conjugate. For complex: negates imaginary parts. For real: returns the input unchanged.

(let [z (t/complex 3.0 4.0)]
  (el/im (el/conj z)))
-4.0

sq

[a]

Element-wise square.

(el/sq (t/column [2 3 4]))
#la/R [:float64 [3 1]
       [[4.000]
        [9.000]
        [16.00]]]

sqrt

[a]

Element-wise square root.

(el/sqrt (t/column [4 9 16]))
#la/R [:float64 [3 1]
       [[2.000]
        [3.000]
        [4.000]]]

pow

[a exponent]

Element-wise power. Real only.

((el/pow (t/column [2]) 3) 0 0)
8.0

cbrt

[a]

Element-wise cube root. Real only.

(la/close-scalar? ((el/cbrt (t/column [27])) 0 0) 3.0)
true

exp

[a]

Element-wise exponential.

(la/close-scalar? ((el/exp (t/column [0])) 0 0) 1.0)
true

log

[a]

Element-wise natural logarithm.

(la/close-scalar? ((el/log (t/column [math/E])) 0 0) 1.0)
true

log10

[a]

Element-wise base-10 logarithm. Real only.

(la/close-scalar? ((el/log10 (t/column [100])) 0 0) 2.0)
true

log1p

[a]

Element-wise log(1 + x), accurate for small x. Real only.

((el/log1p (t/column [0.0])) 0 0)
0.0

expm1

[a]

Element-wise exp(x) - 1, accurate for small x. Real only.

((el/expm1 (t/column [0.0])) 0 0)
0.0

sin

[a]

Element-wise sine.

(la/close-scalar? ((el/sin (t/column [(/ math/PI 2)])) 0 0) 1.0)
true

cos

[a]

Element-wise cosine.

(la/close-scalar? ((el/cos (t/column [0])) 0 0) 1.0)
true

tan

[a]

Element-wise tangent. Real only.

(la/close-scalar? ((el/tan (t/column [(/ math/PI 4)])) 0 0) 1.0)
true

asin

[a]

Element-wise arcsine. Real only.

((el/asin (t/column [0.5])) 0 0)
0.5235987755982989

acos

[a]

Element-wise arccosine. Real only.

((el/acos (t/column [0.5])) 0 0)
1.0471975511965979

atan

[a]

Element-wise arctangent. Real only.

((el/atan (t/column [1.0])) 0 0)
0.7853981633974483

sinh

[a]

Element-wise hyperbolic sine.

(la/close-scalar? ((el/sinh (t/column [0])) 0 0) 0.0)
true

cosh

[a]

Element-wise hyperbolic cosine.

(la/close-scalar? ((el/cosh (t/column [0])) 0 0) 1.0)
true

tanh

[a]

Element-wise hyperbolic tangent. Real only.

(la/close-scalar? ((el/tanh (t/column [0])) 0 0) 0.0)
true

floor

[a]

Element-wise floor. Real only.

((el/floor (t/column [2.7])) 0 0)
2.0

ceil

[a]

Element-wise ceiling. Real only.

((el/ceil (t/column [2.3])) 0 0)
3.0

round

[a]

Element-wise rounding to nearest integer. Real only.

((el/round (t/column [2.7])) 0 0)
3.0

clip

[a lo hi]

Element-wise clipping to [lo, hi]. Real only.

(t/flatten (el/clip (t/column [-2 0.5 3]) -1 1))
#la/R [:float64 [3] [-1.000 0.5000 1.000]]

abs

[a]

Element-wise absolute value (magnitude for complex). Returns a RealTensor.

((el/abs (t/column [-5])) 0 0)
5.0

Complex magnitude: \(|3+4i| = 5\)

(let [m (el/abs (t/complex-tensor [3.0] [4.0]))]
  (la/close-scalar? (double (m 0)) 5.0))
true

sum

[a]

Sum of all elements. Returns double for real, scalar ComplexTensor for complex.

(el/sum (t/column [1 2 3 4]))
10.0

Complex sum:

(let [ct (t/complex-tensor [1.0 2.0 3.0] [4.0 5.0 6.0])
      s (el/sum ct)]
  [(el/re s) (el/im s)])
[6.0 15.0]

mean

[a]

Mean of all elements. Real only.

(el/mean (t/column [2 4 6]))
4.0

reduce-*

[a]

Product of all elements. Returns a double. Real only.

(el/reduce-* (t/column [2 3 4]))
24.0

reduce-max

[a]

Maximum element value. Returns double. Real only.

(el/reduce-max (t/column [3 7 2 9 1]))
9.0

reduce-min

[a]

Minimum element value. Returns double. Real only.

(el/reduce-min (t/column [3 7 2 9 1]))
1.0

>

[a b]

Element-wise greater-than. Returns a RealTensor of 0.0/1.0. Real only.

(el/> (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[0.000]
        [1.000]
        [0.000]]]

<

[a b]

Element-wise less-than. Returns a RealTensor of 0.0/1.0. Real only.

(el/< (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[1.000]
        [0.000]
        [0.000]]]

>=

[a b]

Element-wise greater-or-equal. Returns a RealTensor of 0.0/1.0. Real only.

(el/>= (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[0.000]
        [1.000]
        [1.000]]]

<=

[a b]

Element-wise less-or-equal. Returns a RealTensor of 0.0/1.0. Real only.

(el/<= (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[1.000]
        [0.000]
        [1.000]]]

eq

[a b]

Element-wise equality. Returns a RealTensor of 0.0/1.0. Real only.

(el/eq (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[0.000]
        [0.000]
        [1.000]]]

not-eq

[a b]

Element-wise not-equal. Returns a RealTensor of 0.0/1.0. Real only.

(el/not-eq (t/column [1 5 3]) (t/column [2 4 3]))
#la/R [:float64 [3 1]
       [[1.000]
        [1.000]
        [0.000]]]

min

[a b]

Element-wise minimum. Real only.

((el/min (t/column [3]) (t/column [5])) 0 0)
3.0

max

[a b]

Element-wise maximum. Real only.

((el/max (t/column [3]) (t/column [5])) 0 0)
5.0

argmax

[a]

Index of the maximum element. Returns long. Real only.

(el/argmax (t/column [3 7 2 9 1]))
3

argmin

[a]

Index of the minimum element. Returns long. Real only.

(el/argmin (t/column [3 7 2 9 1]))
4

argsort

[a]

[comp a]

Indices that would sort the tensor in ascending order. Returns a Clojure vector of longs. Real only. With comparator: (argsort > a) for descending.

Ascending:

(el/argsort (t/column [3 7 2 9 1]))
[4 2 0 1 3]

Descending:

(el/argsort > (t/column [3 7 2 9 1]))
[3 1 0 2 4]

sort

[a]

[comp a]

Sorted copy of the tensor. Returns RealTensor. Real only. With comparator: (sort > a) for descending.

Ascending:

(el/sort (t/column [3 7 2 9 1]))
#la/R [:float64 [5] [1.000 2.000 3.000 7.000 9.000]]

Descending:

(el/sort > (t/column [3 7 2 9 1]))
#la/R [:float64 [5] [9.000 7.000 3.000 2.000 1.000]]

scicloj.lalinea.transform

Bridge between Fastmath transforms and La Linea tensors. The FFT takes a real signal and returns a ComplexTensor spectrum.

forward

[signal]

Forward FFT of a real signal. Returns a ComplexTensor of the spectrum.

The input can be a Clojure seq, double[], or dtype-next buffer. The output is a ComplexTensor of shape [n] where n = length of input.

(let [signal [1.0 0.0 0.0 0.0]
      spectrum (ft/forward signal)]
  (t/complex-shape spectrum))
[4]

inverse

[spectrum]

Inverse FFT from a ComplexTensor spectrum back to a ComplexTensor signal.

(let [spectrum (ft/forward [1.0 2.0 3.0 4.0])
      roundtrip (ft/inverse spectrum)]
  (la/close-scalar? (el/re (roundtrip 0)) 1.0))
true

inverse-real

[spectrum]

Inverse FFT from a ComplexTensor spectrum, returning only the real part. Useful when you know the result should be purely real.

(let [signal [1.0 2.0 3.0 4.0]
      roundtrip (ft/inverse-real (ft/forward signal))]
  (la/close-scalar? (roundtrip 0) 1.0))
true

forward-complex

[signal]

Forward FFT of a ComplexTensor signal. Returns a ComplexTensor spectrum.

(let [ct (t/complex-tensor-real [1.0 0.0 0.0 0.0])
      spectrum (ft/forward-complex ct)]
  (t/complex-shape spectrum))
[4]

dct-forward

[signal]

Forward Discrete Cosine Transform. Real -> real.

(ft/dct-forward [1.0 2.0 3.0 4.0])
#la/R [:float64 [4] [5.000 -2.230 0.000 -0.1585]]

dct-inverse

[spectrum]

Inverse Discrete Cosine Transform. Real -> real.

(let [signal [1.0 2.0 3.0 4.0]
      roundtrip (ft/dct-inverse (ft/dct-forward signal))]
  (la/close-scalar? (roundtrip 0) 1.0))
true

dst-forward

[signal]

Forward Discrete Sine Transform. Real -> real.

(ft/dst-forward [1.0 2.0 3.0 4.0])
#la/R [:float64 [4] [4.619 -2.000 1.913 -1.000]]

dst-inverse

[spectrum]

Inverse Discrete Sine Transform. Real -> real.

(let [signal [1.0 2.0 3.0 4.0]
      roundtrip (ft/dst-inverse (ft/dst-forward signal))]
  (la/close-scalar? (roundtrip 0) 1.0))
true

dht-forward

[signal]

Forward Discrete Hartley Transform. Real -> real.

(ft/dht-forward [1.0 2.0 3.0 4.0])
#la/R [:float64 [4] [10.00 -4.000 -2.000 0.000]]

dht-inverse

[spectrum]

Inverse Discrete Hartley Transform. Real -> real.

(let [signal [1.0 2.0 3.0 4.0]
      roundtrip (ft/dht-inverse (ft/dht-forward signal))]
  (la/close-scalar? (roundtrip 0) 1.0))
true

scicloj.lalinea.tape

Computation DAG recording and memory inspection.

memory-status

[t]

Classify a tensor’s memory backing.

Returns:

  • :contiguous — backed by a full double[] (fast, mutable)
  • :strided — shares a double[] but with non-standard strides (e.g. transpose)
  • :lazy — no backing array, recomputes on each access

Works on both real tensors and ComplexTensors.

(tape/memory-status (t/matrix [[1 2] [3 4]]))
:contiguous
(tape/memory-status (la/transpose (t/matrix [[1 2] [3 4]])))
:strided
(tape/memory-status (el/+ (t/eye 2) (t/eye 2)))
:lazy

memory-relation

[a b]

Classify the memory relationship between two tensors.

Returns:

  • :shared — same backing double[]
  • :independent — separate backing arrays
  • :unknown-lazy — at least one is lazy; relationship indeterminate

For lazy tensors, the relationship depends on whether the lazy reader reads through to the other tensor’s backing array — but dtype-next does not expose this dependency chain. Use the tape (detect-memory-status) for the full picture.

(let [A (t/matrix [[1 2] [3 4]])]
  (tape/memory-relation A (la/transpose A)))
:shared
(tape/memory-relation (t/matrix [[1 0] [0 1]]) (t/matrix [[5 6] [7 8]]))
:independent
(tape/memory-relation (t/matrix [[1 2] [3 4]]) (el/+ (t/eye 2) (t/eye 2)))
:unknown-lazy

with-tape

[& body]

Execute body while recording a computation tape. Returns {:result <body-result> :entries <tape-entries>}.

(def tape-example
  (tape/with-tape
    (let [A (t/matrix [[1 2] [3 4]])
          B (el/scale A 2.0)]
      (la/mmul B (la/transpose A)))))
(select-keys tape-example [:result :entries])
{:result #la/R [:float64 [2 2]
       [[10.00 22.00]
        [22.00 50.00]]]
,
 :entries
 [{:id "t1",
   :op :t/matrix,
   :inputs [{:external true}],
   :input-tensors [[[1 2] [3 4]]],
   :output #la/R [:float64 [2 2]
       [[1.000 2.000]
        [3.000 4.000]]]
,
   :shape [2 2],
   :complex? false}
  {:id "t2",
   :op :el/scale,
   :inputs [{:id "t1"} {:external true}],
   :input-tensors [#la/R [:float64 [2 2]
       [[1.000 2.000]
        [3.000 4.000]]]
 2.0],
   :output #la/R [:float64 [2 2]
       [[2.000 4.000]
        [6.000 8.000]]]
,
   :shape [2 2],
   :complex? false}
  {:id "t3",
   :op :la/transpose,
   :inputs [{:id "t1"}],
   :input-tensors [#la/R [:float64 [2 2]
       [[1.000 2.000]
        [3.000 4.000]]]
],
   :output #la/R [:float64 [2 2]
       [[1.000 3.000]
        [2.000 4.000]]]
,
   :shape [2 2],
   :complex? false}
  {:id "t4",
   :op :la/mmul,
   :inputs [{:id "t2"} {:id "t3"}],
   :input-tensors [#la/R [:float64 [2 2]
       [[2.000 4.000]
        [6.000 8.000]]]
 #la/R [:float64 [2 2]
       [[1.000 3.000]
        [2.000 4.000]]]
],
   :output #la/R [:float64 [2 2]
       [[10.00 22.00]
        [22.00 50.00]]]
,
   :shape [2 2],
   :complex? false}]}

summary

[tape-result]

Aggregate stats about a tape result.

Returns a map with:

  • :total — total operations recorded
  • :by-op — count per operation type
  • :by-memory — count per memory status (:reads-through, :shared, :independent)
(tape/summary tape-example)
{:total 4,
 :by-op {:t/matrix 1, :el/scale 1, :la/transpose 1, :la/mmul 1},
 :by-memory {:independent 2, :reads-through 1, :shared 1}}

origin

[tape-result value]

Walk the tape backwards from a value to build its computation DAG.

Returns a nested map: each node has :id, :op, :shape, and :inputs. Inputs that were not recorded on the tape appear as {:external true}. Shared nodes (DAG diamonds) appear as {:ref <id>} after the first occurrence.

(tape/origin tape-example (:result tape-example))
{:id "t4",
 :op :la/mmul,
 :shape [2 2],
 :inputs
 [{:id "t2",
   :op :el/scale,
   :shape [2 2],
   :inputs
   [{:id "t1", :op :t/matrix, :shape [2 2], :inputs [{:external true}]}
    {:external true}]}
  {:id "t3", :op :la/transpose, :shape [2 2], :inputs [{:ref "t1"}]}]}

mermaid

[tape-result value]

Render the computation DAG for a value as a Mermaid diagram.

Memory status is annotated on each node:

  • ~ reads-through (lazy, recomputes on access)
  • = shared (shares backing array with an input)
  • + independent (fresh allocation)

Returns a kind/mermaid value, renderable in notebooks.

Returns a renderable Mermaid diagram.

(tape/mermaid tape-example (:result tape-example))
flowchart TD t4["mmul [2 2] +"] t2["scale [2 2] ~"] t1["matrix [2 2] +"] ext3[/"external"/] ext3 --> t1 t1 --> t2 ext6[/"external"/] ext6 --> t2 t2 --> t4 t3["transpose [2 2] ="] t1 --> t3 t3 --> t4

detect-memory-status

[entry]

Classify a tape entry’s output relative to its inputs.

Returns:

  • :shared — output shares backing array with an input
  • :independent — output has its own backing array (fresh allocation)
  • :reads-through — output has no backing array; reads from inputs on access

Classifies a tape entry’s output relative to its inputs: :reads-through, :shared, or :independent.

(mapv tape/detect-memory-status (:entries tape-example))
[:independent :reads-through :shared :independent]

scicloj.lalinea.grad

Reverse-mode automatic differentiation on the computation tape.

grad

[tape-result target wrt]

Gradient of a scalar w.r.t. one or more inputs.

tape-result — map returned by tape/with-tape target — scalar output (must be on the tape) wrt — input tensor, or vector of input tensors

For a single input, returns its gradient tensor directly. For a vector of inputs, returns a map {input gradient}.

Example: clojure (let [A (t/matrix [[1 2] [3 4]]) tape-result (tape/with-tape (la/trace (la/mmul A A)))] (grad/grad tape-result (:result tape-result) A))

(let [A (t/matrix [[1 2] [3 4]])
      tape-result (tape/with-tape
                    (la/trace (la/mmul (la/transpose A) A)))]
  (la/close? (grad/grad tape-result
                        (:result tape-result) A)
             (el/scale A 2)))
true

scicloj.lalinea.vis

SVG and image helpers for visual linear algebra.

arrow-plot

[arrows opts]

Render 2D vectors as arrows on an SVG grid.

arrows is a sequence of maps, each with: :xy — [dx dy] displacement vector (required) :color — CSS color string (required) :label — text label (optional) :from — [fx fy] origin offset, default [0 0] (optional) :dashed? — dashed stroke (optional)

opts is a map with: :width — SVG width in pixels, default 600 (optional)

(vis/arrow-plot [{:xy [2 1] :color "#2266cc" :label "u"}
                 {:xy [-1 1.5] :color "#cc4422" :label "v"}]
                {:width 600})
uv

graph-plot

[positions edges opts]

Render a graph as an SVG diagram with nodes and edges.

positions is a vector of [x y] coordinates for each node. edges is a sequence of [i j] index pairs. opts is a map with: :width — SVG width in pixels, default 300 (optional) :labels — vector of node labels, default [“0” “1” …] (optional) :node-colors — vector of CSS colors per node (optional) :edge-highlight — set of [i j] pairs to highlight in red (optional)

(vis/graph-plot [[0 0] [1 0] [0.5 0.87]]
                [[0 1] [1 2] [2 0]]
                {:width 600 :labels ["A" "B" "C"]})
ABC

matrix->gray-image

[m]

Convert a numeric [h w] matrix to a [h w 3] uint8 grayscale tensor suitable for display as an image. Values are clamped to [0, 255].

(let [m (t/compute-tensor [200 200]
                          (fn [r c] (* 255.0 (/ (+ r c) 400.0)))
                          :float64)]
  (bufimg/tensor->image (vis/matrix->gray-image m)))

extract-channel

[img ch]

Extract a single channel from an [h w c] image tensor and return it as a [h w 3] grayscale tensor (the channel replicated three times).

(let [img (t/compute-tensor [200 200 3]
                            (fn [r c ch]
                              (case (int ch) 0 (int (* 255 (/ r 200.0))) 1 128 2 64))
                            :uint8)]
  (bufimg/tensor->image (vis/extract-channel img 0)))

source: notebooks/lalinea_book/api_reference.clj