Monty.Geometry.LinearAlgebra (ExTbpMonty.Core v0.1.0)

Copy Markdown View Source

The linear algebra Monty's sensors ask numpy for.

A sensor module fits a plane and then a quadric to a patch of points, which in Python is np.linalg.solve and np.linalg.eig (frameworks/utils/sensor_processing.py). There is no numpy here, and the fits are small — three to six unknowns — so this module carries the three routines those fits need and nothing else:

  • solve/2 — Gaussian elimination with partial pivoting;
  • symmetric_eigen/1 — Jacobi rotations, for a real symmetric matrix;
  • eigen_2x2/1 — the closed form for a two-by-two matrix, which is what a shape operator is.

Nothing here is ported from Monty: Monty calls numpy, and this is the part of numpy it calls. Matrices are row-major lists, the same shape the rest of this port writes them in.

Summary

Types

A row-major matrix.

Functions

The eigenvalues and eigenvectors of a two-by-two matrix, largest first.

The count×count identity matrix.

The vector x that solves matrix · x = vector, or :singular.

The eigenvalues and eigenvectors of a real symmetric matrix, ascending.

Types

matrix()

@type matrix() :: [[float()]]

A row-major matrix.

Functions

eigen_2x2(list)

@spec eigen_2x2([[number()]]) :: [{float(), [float()]}]

The eigenvalues and eigenvectors of a two-by-two matrix, largest first.

The characteristic quadratic λ² − tr λ + det = 0 solved in closed form, then a null vector for each root. A shape operator is two-by-two, symmetric up to rounding, and its eigenvalues order the principal curvatures — Monty sorts them largest first, so this does too.

identity(count)

@spec identity(pos_integer()) :: matrix()

The count×count identity matrix.

solve(matrix, vector)

@spec solve([[number()]], [number()]) :: {:ok, [float()]} | :singular

The vector x that solves matrix · x = vector, or :singular.

Gaussian elimination with partial pivoting: at each column the row with the largest entry is moved into place, so a small pivot is only ever used when the matrix genuinely has none bigger. :singular is answered rather than NaNs.

symmetric_eigen(matrix)

@spec symmetric_eigen([[number()]]) :: [{float(), [float()]}]

The eigenvalues and eigenvectors of a real symmetric matrix, ascending.

Jacobi rotations: each pass zeroes the largest off-diagonal entry by turning the matrix in its plane, and the turning is accumulated into the identity to leave the eigenvectors as its columns. Ascending order is this module's choice, not numpy's; callers that want the smallest or largest say so.