Package-level declarations

Types

Link copied to clipboard
data class CycleEigenMode(val eigenvalue: Double, val frequencyRatio: Double, val n: Int, val values: DoubleArray)

One eigenmode of n points arranged around a closed curve, as produced by extractCycleEigenModes -- the discrete, boundary-only analogue of GridEigenMode. These are the eigenvectors of the cycle graph Laplacian, i.e. a generalization of the sine/cosine basis used by classical Fourier shape descriptors to a curve sampled at non-uniform detail.

Link copied to clipboard
data class Eigenpair(val eigenvalue: Double, val eigenvector: DoubleArray)

An eigenvalue paired with its eigenvector.

Link copied to clipboard
data class GridEigenMode(val eigenvalue: Double, val frequencyRatio: Double, val width: Int, val height: Int, val values: DoubleArray)

One vibrational eigenmode of a domain rasterized to a width x height grid, as produced by extractEigenModes. Values are zero outside the domain that was passed in.

Functions

Link copied to clipboard
fun bilinearSample(values: DoubleArray, width: Int, height: Int, x: Double, y: Double): Double

Bilinearly samples a row-major width x height grid of values at grid coordinates (x, y), where x ranges over 0 until width and y over 0 until height. Positions outside that range are clamped.

Link copied to clipboard

Builds the graph Laplacian of an n-node cycle graph (node i connected to i - 1 and i + 1, indices modulo n) -- the discrete analogue of the periodic 1D Laplacian, and the natural graph to put on n points sampled around a closed curve. Symmetric positive semi-definite, with the constant vector as its null (zero-eigenvalue) eigenvector -- see extractCycleEigenModes.

Link copied to clipboard

Builds the discrete Dirichlet Laplacian for the interior grid points marked true in mask, a width x height grid stored row-major (index = y * width + x).

Link copied to clipboard

Builds the discrete Neumann ("free edge") Laplacian for the interior grid points marked true in mask, a width x height grid stored row-major (index = y * width + x).

Link copied to clipboard

Extracts the main diagonal of this sparse matrix.

Link copied to clipboard
fun extractCycleEigenModes(n: Int, count: Int, random: Random = Random(0)): List<CycleEigenMode>

Extracts the count lowest-frequency eigenmodes of n points arranged around a closed curve, by solving the eigenproblem of the buildCycleLaplacian graph Laplacian -- the boundary-only counterpart to extractEigenModes/extractNeumannEigenModes, which instead act on the curve's interior.

Link copied to clipboard
fun extractEigenModes(mask: BooleanArray, width: Int, height: Int, count: Int, random: Random = Random(0)): List<GridEigenMode>

Extracts the count lowest-frequency Dirichlet ("fixed edge") vibrational eigenmodes of the domain marked true in mask, a width x height grid. This is the discrete analogue of solving -Δu = λu on the domain with u = 0 on its boundary -- the same problem that produces Chladni figures on a clamped drum head.

Link copied to clipboard
fun extractNeumannEigenModes(mask: BooleanArray, width: Int, height: Int, count: Int, random: Random = Random(0)): List<GridEigenMode>

Extracts the count lowest-frequency Neumann ("free edge") vibrational eigenmodes of the domain marked true in mask, a width x height grid. This is the discrete analogue of solving -Δu = λu on the domain with a zero-derivative (reflecting) boundary -- the free-plate counterpart to extractEigenModes's clamped drum head.

Link copied to clipboard

Flips the sign of v in place, if needed, so that its largest-magnitude component is positive. Eigenvectors are only defined up to sign; this picks a canonical one so that repeated extraction (across seeds, resolutions, or re-runs) doesn't flip a mode's polarity arbitrarily.

Link copied to clipboard
fun SparseMatrix.smallestEigenpairs(count: Int, knownEigenpairs: List<Eigenpair> = emptyList(), random: Random = Random(0), cgTolerance: Double = 1.0E-10): List<Eigenpair>

Finds the count smallest eigenpairs of this symmetric positive-semidefinite sparse matrix, using shift-invert Lanczos: builds one Krylov subspace for the operator v -> solve(this, v) (via SparseMatrix.solveCG) -- which maps this matrix's smallest eigenvalues to its largest, the ones Lanczos converges to fastest -- and extracts Ritz pairs from the resulting small, dense tridiagonal eigenproblem.

Link copied to clipboard
fun SparseMatrix.solveCG(b: DoubleArray, tolerance: Double = 1.0E-10, maxIterations: Int = max(50, rows * 2)): DoubleArray

Solves the symmetric positive-definite system this * x = b using the Jacobi-preconditioned conjugate gradient method.

Link copied to clipboard

Multiplies this sparse matrix with a dense vector.