Yalantis/uCrop · warning

invert(): LAPACK function dgetrf_() returned error code

Error message

invert(): LAPACK function dgetrf_() returned error code %d.

What it means

CImg::invert() with LU decomposition calls LAPACK dgetrf_() to factor the matrix before inverting; a nonzero INFO from dgetrf_ means the LU factorization failed, typically because a diagonal pivot was exactly zero (singular matrix). On failure CImg warns and fills the matrix with zeros instead of throwing.

Solutions

  1. Check the determinant or rank of the matrix before inverting; reject/regularize singular inputs
  2. Use double-precision data (CImg<double>) so near-singular matrices still factor
  3. Add a small regularization term (e.g. A + eps*I) before inverting
  4. Handle the zero-filled result: check INFO behavior and fall back to a pseudo-inverse (e.g. solve via SVD/symmetric eigen)
  5. Avoid inverting at all — solve A*x=b with solve() instead of computing A^-1

Example fix

// before
CImg<float> inv = A.invert(true);
// after
if (std::fabs(A.determinant()) < 1e-10f) {
  // singular: regularize instead of inverting
  for (int i = 0; i < A.width(); ++i) A(i,i) += 1e-6f;
}
CImg<float> inv = A.invert(true);
Defensive patterns

Strategy: validation

Validate before calling

bool invertible(const CImg<float>& A) {
  if (A.width() != A.height() || A.width() == 0) return false;
  return std::fabs(A.determinant()) > 1e-10f;
}

Prevention

When it happens

Trigger: Calling invert(use_LU=true) on a square matrix that is singular or numerically rank-deficient; also possible if N exceeds LAPACK integer limits.

Common situations: Inverting covariance/geometry matrices built from degenerate input data (collinear points, duplicate rows); float32 precision issues making an ill-conditioned matrix effectively singular.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/b82e801b6dcabf97. Report an issue: GitHub.

Appendix: source

Thrown at ucrop/src/main/jni/CImg.h:32869

      } else if (dete!=0. && _width==3) {
        const double
          a = _data[0], d = _data[1], g = _data[2],
          b = _data[3], e = _data[4], h = _data[5],
          c = _data[6], f = _data[7], i = _data[8];
        _data[0] = (T)((i*e - f*h)/dete), _data[1] = (T)((g*f - i*d)/dete), _data[2] = (T)((d*h - g*e)/dete);
        _data[3] = (T)((h*c - i*b)/dete), _data[4] = (T)((i*a - c*g)/dete), _data[5] = (T)((g*b - a*h)/dete);
        _data[6] = (T)((b*f - e*c)/dete), _data[7] = (T)((d*c - a*f)/dete), _data[8] = (T)((a*e - d*b)/dete);
      } else {

#ifdef cimg_use_lapack
        int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];
        Tfloat
          *const lapA = new Tfloat[N*N],
          *const WORK = new Tfloat[LWORK];
        cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));
        cimg::getrf(N,lapA,IPIV,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "invert(): LAPACK function dgetrf_() returned error code %d.",
                     cimg_instance,
                     INFO);
        else {
          cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
          if (INFO)
            cimg::warn(_cimg_instance
                       "invert(): LAPACK function dgetri_() returned error code %d.",
                       cimg_instance,
                       INFO);
        }
        if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0);
        delete[] IPIV; delete[] lapA; delete[] WORK;
#else
        if (use_LU) { // LU solver
          CImg<Tfloat> A(*this,false), indx;
          bool d;
          A._LU(indx,d);

View on GitHub (pinned to f788b534b4)