{"record":{"id":"60f3a789658a380b","repo":"Yalantis/uCrop","slug":"eigen-complex-eigenvalues-found","errorCode":null,"errorMessage":"eigen(): Complex eigenvalues found.","messagePattern":"eigen\\(\\): Complex eigenvalues found\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":33158,"sourceCode":"       \\param[out] vec Matrix of the estimated eigenvectors, sorted by columns.\n    **/\n    template<typename t>\n    const CImg<T>& eigen(CImg<t>& val, CImg<t> &vec) const {\n      if (is_empty()) { val.assign(); vec.assign(); }\n      else {\n        if (_width!=_height || _depth>1 || _spectrum>1)\n          throw CImgInstanceException(_cimg_instance\n                                      \"eigen(): Instance is not a square matrix.\",\n                                      cimg_instance);\n\n        if (val.size()<(ulongT)_width) val.assign(1,_width);\n        if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width);\n        switch (_width) {\n        case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break;\n        case 2 : {\n          const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d;\n          double f = e*e - 4*(a*d - b*c);\n          if (f<0) cimg::warn(_cimg_instance\n                              \"eigen(): Complex eigenvalues found.\",\n                              cimg_instance);\n          f = std::sqrt(f);\n          const double\n            l1 = 0.5*(e - f),\n            l2 = 0.5*(e + f),\n            b2 = b*b,\n            norm1 = std::sqrt(cimg::sqr(l2 - a) + b2),\n            norm2 = std::sqrt(cimg::sqr(l1 - a) + b2);\n          val[0] = (t)l2;\n          val[1] = (t)l1;\n          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; }\n          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; }\n        } break;\n        default :\n          throw CImgInstanceException(_cimg_instance\n                                      \"eigen(): Eigenvalues computation of general matrices is limited \"\n                                      \"to 2x2 matrices.\",","sourceCodeStart":33140,"sourceCodeEnd":33176,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L33140-L33176","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Symmetrize the input before calling: M = (M + M.get_transpose())/2","Sanitize the matrix: replace NaN/Inf values and validate the data feeding the matrix","If complex eigenvalues are legitimately possible, use a general (non-symmetric) eigensolver library (e.g. Eigen/LAPACK) instead of CImg's real-only eigen()","Check for negative discriminant yourself before calling and handle the degenerate 2x2 case explicitly"],"exampleFix":"// before\nCImg<T> val, vec;\nM.eigen(val, vec); // warns if matrix not truly symmetric\n// after\nCImg<T> S = (M + M.get_transpose()) * 0.5;\nS.eigen(val, vec);","handlingStrategy":"validation","validationCode":"bool symmetric_ok(const CImg<double>& M) {\n  if (M.width() != M.height()) return false;\n  for (unsigned i = 0; i < M.width(); ++i)\n    for (unsigned j = i + 1; j < M.width(); ++j)\n      if (M(i,j) != M(j,i) || !std::isfinite(M(i,j))) return false;\n  return true;\n}\n// then: CImg<double> S = (M + M.get_transpose()) * 0.5; S.eigen(val, vec);","typeGuard":"bool is_finite_symmetric(const CImg<double>& M) {\n  if (M.width() != M.height()) return false;\n  for (unsigned i = 0; i < M.width(); ++i)\n    for (unsigned j = 0; j < M.width(); ++j)\n      if (!std::isfinite(M(i, j)) || M(i, j) != M(j, i)) return false;\n  return true;\n}","tryCatchPattern":null,"preventionTips":["Symmetrize matrices ((M + M^T)/2) before eigen-decomposition","Reject/repair NaN and Inf entries before numeric routines","Use a general eigensolver (Eigen/LAPACK) when complex eigenvalues are possible","Compute the discriminant yourself for 2x2 cases and branch explicitly"],"tags":["linear-algebra","eigenvalues","numerical","matrix","cimg"],"backgroundTag":"invalid-argument-value","analyzedSha":"f788b534b48c144edf786c8cddbf0e029e637804","analyzedAt":"2026-09-08T08:36:04.887Z","contentChangedAt":"2026-09-08T08:36:04.887Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}