Yalantis/uCrop · warning

eigen(): Complex eigenvalues found.

Error message

eigen(): Complex eigenvalues found.

What it means

CImg<T>::get_eigen()/eigen() computes eigenvalues/vectors of a symmetric matrix; for the 2x2 case it computes the discriminant f = e^2 - 4*(ad-bc). If f<0 the eigenvalues are complex and cannot be represented in the real output matrices, so cimg::warn() emits a non-fatal warning and the code proceeds with sqrt of a negative value clamped/behaving per std::sqrt (NaN), producing invalid results.

Source

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

       \param[out] vec Matrix of the estimated eigenvectors, sorted by columns.
    **/
    template<typename t>
    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {
      if (is_empty()) { val.assign(); vec.assign(); }
      else {
        if (_width!=_height || _depth>1 || _spectrum>1)
          throw CImgInstanceException(_cimg_instance
                                      "eigen(): Instance is not a square matrix.",
                                      cimg_instance);

        if (val.size()<(ulongT)_width) val.assign(1,_width);
        if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width);
        switch (_width) {
        case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;
        case 2 : {
          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;
          double f = e*e - 4*(a*d - b*c);
          if (f<0) cimg::warn(_cimg_instance
                              "eigen(): Complex eigenvalues found.",
                              cimg_instance);
          f = std::sqrt(f);
          const double
            l1 = 0.5*(e - f),
            l2 = 0.5*(e + f),
            b2 = b*b,
            norm1 = std::sqrt(cimg::sqr(l2 - a) + b2),
            norm2 = std::sqrt(cimg::sqr(l1 - a) + b2);
          val[0] = (t)l2;
          val[1] = (t)l1;
          if (norm1>0) { vec(0,0) = (t)(b/norm1); vec(0,1) = (t)((l2 - a)/norm1); } else { vec(0,0) = 1; vec(0,1) = 0; }
          if (norm2>0) { vec(1,0) = (t)(b/norm2); vec(1,1) = (t)((l1 - a)/norm2); } else { vec(1,0) = 1; vec(1,1) = 0; }
        } break;
        default :
          throw CImgInstanceException(_cimg_instance
                                      "eigen(): Eigenvalues computation of general matrices is limited "
                                      "to 2x2 matrices.",

View on GitHub (pinned to f788b534b4)

Solutions

  1. Symmetrize the input before calling: M = (M + M.get_transpose())/2
  2. Sanitize the matrix: replace NaN/Inf values and validate the data feeding the matrix
  3. If complex eigenvalues are legitimately possible, use a general (non-symmetric) eigensolver library (e.g. Eigen/LAPACK) instead of CImg's real-only eigen()
  4. Check for negative discriminant yourself before calling and handle the degenerate 2x2 case explicitly

Example fix

// before
CImg<T> val, vec;
M.eigen(val, vec); // warns if matrix not truly symmetric
// after
CImg<T> S = (M + M.get_transpose()) * 0.5;
S.eigen(val, vec);
Defensive patterns

Strategy: validation

Validate before calling

bool symmetric_ok(const CImg<double>& M) {
  if (M.width() != M.height()) return false;
  for (unsigned i = 0; i < M.width(); ++i)
    for (unsigned j = i + 1; j < M.width(); ++j)
      if (M(i,j) != M(j,i) || !std::isfinite(M(i,j))) return false;
  return true;
}
// then: CImg<double> S = (M + M.get_transpose()) * 0.5; S.eigen(val, vec);

Type guard

bool is_finite_symmetric(const CImg<double>& M) {
  if (M.width() != M.height()) return false;
  for (unsigned i = 0; i < M.width(); ++i)
    for (unsigned j = 0; j < M.width(); ++j)
      if (!std::isfinite(M(i, j)) || M(i, j) != M(j, i)) return false;
  return true;
}

Prevention

When it happens

Trigger: Calling eigen()/symmetric eigen-decomposition on a 2x2 (or larger, in general paths) matrix whose characteristic polynomial has negative discriminant — i.e. the input is not positive-definite / not a valid symmetric matrix with real spectrum, often due to floating-point asymmetry or garbage data.

Common situations: Running eigen() on nearly-symmetric matrices polluted by NaNs or noise, covariance/structure-tensor computations with degenerate input, passing a non-symmetric matrix where symmetry is assumed.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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