Skip to content

Add determinant and sign-log-determinant functions to mlx.core.linalg#3416

Open
abhilashreddys wants to merge 4 commits intoml-explore:mainfrom
abhilashreddys:feat/det
Open

Add determinant and sign-log-determinant functions to mlx.core.linalg#3416
abhilashreddys wants to merge 4 commits intoml-explore:mainfrom
abhilashreddys:feat/det

Conversation

@abhilashreddys
Copy link
Copy Markdown

@abhilashreddys abhilashreddys commented Apr 15, 2026

Proposed changes: Add linalg.det and linalg.slogdet

Related: #3335

Add determinant (det) and sign-log-determinant (slogdet) functions to mlx.core.linalg.

  • mx.linalg.det(a) - returns the determinant of a square matrix
  • mx.linalg.slogdet(a) - returns (sign, logabsdet) for numerical stability

Design Choices

Composite on lu_factor(), no new primitive

Both functions compose on the existing lu_factor() primitive rather than introducing a new one. This mirrors how JAX implements slogdet and is consistent with how solve() already builds on lu() in this codebase.

slogdet as the core, det derived from it

slogdet is the numerically stable. For the general case (N > 3), det simply calls slogdet and reconstructs via sign * exp(logabsdet). This avoids duplicating the LU-based logic. An internal slogdet_impl function handles the shared logic so the public det and slogdet entry points each validate and promote types exactly once.

Small-matrix fast paths (1x1, 2x2, 3x3)

A shared det_raw_small() helper computes determinants directly using closed-form formulas (element extraction via slice/squeeze, then the standard cofactor expansion for 3x3). This avoids LU overhead for the small matrices common in batched ML workloads (e.g., 3x3 covariance matrices in normalizing flows).

det calls det_raw_small directly for N <= 3, skipping the log/exp round-trip entirely. slogdet calls it too, then splits the raw result into sign(raw) and log(abs(raw)).

Integer auto-promotion

det/slogdet promote integer inputs to float32 via at_least_float(). This matches NumPy's behavior (np.linalg.det accepts integer arrays).

Singular matrix handling

For the LU path, singularity is detected by checking for exact zeros on the U diagonal (same approach as NumPy). Singular matrices return (sign=0, logabsdet=-inf) from slogdet, and 0.0 from det.

Thanks @Lucas-Fernandes-Martins for pointing out the singular matrix issue in LU factorization.

Testing

  • Correctness: Compared against np.linalg.det / np.linalg.slogdet for 1x1 through 5x5, random matrices, identity
  • Batched: Shapes (3, 4, 4) and (2, 3, 3, 3) match NumPy
  • Numerical stability: 0.1 * I_100 (det underflows in float32, slogdet stays finite)
  • Singular matrices: sign=0, logabsdet=-inf
  • Consistency: sign * exp(logabsdet) matches det for non-singular inputs
  • Dtypes: float32, float64, integer auto-promotion
  • Error handling: non-square and 1D inputs raise ValueError
  • Full suite: All 18 existing linalg tests continue to pass (186 subtests)

Checklist

Put an x in the boxes that apply.

  • I have read the CONTRIBUTING document
  • I have run pre-commit run --all-files to format my code / installed pre-commit prior to committing changes
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the necessary documentation (if needed)

LAPACK's getrf returns info > 0 for singular matrices, which is informational (factorization completed, U has zeros on diagonal), not an error. Previously LUF threw on info != 0, blocking det/slogdet from handling singular matrices with n >= 4. Now only throw on info < 0 (illegal argument). Downstream consumers like slogdet already handle singular U correctly (returning sign=0, logabsdet=-inf).

Co-Authored-By: Lucas Fernandes Martins <Lucas-Fernandes-Martins@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant