pca.inl 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /// @ref gtx_pca
  2. #ifndef GLM_HAS_CXX11_STL
  3. #include <algorithm>
  4. #else
  5. #include <utility>
  6. #endif
  7. namespace glm {
  8. template<length_t D, typename T, qualifier Q>
  9. GLM_INLINE mat<D, D, T, Q> computeCovarianceMatrix(vec<D, T, Q> const* v, size_t n)
  10. {
  11. return computeCovarianceMatrix<D, T, Q, vec<D, T, Q> const*>(v, v + n);
  12. }
  13. template<length_t D, typename T, qualifier Q>
  14. GLM_INLINE mat<D, D, T, Q> computeCovarianceMatrix(vec<D, T, Q> const* v, size_t n, vec<D, T, Q> const& c)
  15. {
  16. return computeCovarianceMatrix<D, T, Q, vec<D, T, Q> const*>(v, v + n, c);
  17. }
  18. template<length_t D, typename T, qualifier Q, typename I>
  19. GLM_FUNC_DECL mat<D, D, T, Q> computeCovarianceMatrix(I const& b, I const& e)
  20. {
  21. glm::mat<D, D, T, Q> m(0);
  22. size_t cnt = 0;
  23. for(I i = b; i != e; i++)
  24. {
  25. vec<D, T, Q> const& v = *i;
  26. for(length_t x = 0; x < D; ++x)
  27. for(length_t y = 0; y < D; ++y)
  28. m[x][y] += static_cast<T>(v[x] * v[y]);
  29. cnt++;
  30. }
  31. if(cnt > 0)
  32. m /= static_cast<T>(cnt);
  33. return m;
  34. }
  35. template<length_t D, typename T, qualifier Q, typename I>
  36. GLM_FUNC_DECL mat<D, D, T, Q> computeCovarianceMatrix(I const& b, I const& e, vec<D, T, Q> const& c)
  37. {
  38. glm::mat<D, D, T, Q> m(0);
  39. glm::vec<D, T, Q> v;
  40. size_t cnt = 0;
  41. for(I i = b; i != e; i++)
  42. {
  43. v = *i - c;
  44. for(length_t x = 0; x < D; ++x)
  45. for(length_t y = 0; y < D; ++y)
  46. m[x][y] += static_cast<T>(v[x] * v[y]);
  47. cnt++;
  48. }
  49. if(cnt > 0)
  50. m /= static_cast<T>(cnt);
  51. return m;
  52. }
  53. namespace _internal_
  54. {
  55. template<typename T>
  56. GLM_INLINE T transferSign(T const& v, T const& s)
  57. {
  58. return ((s) >= 0 ? glm::abs(v) : -glm::abs(v));
  59. }
  60. template<typename T>
  61. GLM_INLINE T pythag(T const& a, T const& b) {
  62. static const T epsilon = static_cast<T>(0.0000001);
  63. T absa = glm::abs(a);
  64. T absb = glm::abs(b);
  65. if(absa > absb) {
  66. absb /= absa;
  67. absb *= absb;
  68. return absa * glm::sqrt(static_cast<T>(1) + absb);
  69. }
  70. if(glm::equal<T>(absb, 0, epsilon)) return static_cast<T>(0);
  71. absa /= absb;
  72. absa *= absa;
  73. return absb * glm::sqrt(static_cast<T>(1) + absa);
  74. }
  75. }
  76. template<length_t D, typename T, qualifier Q>
  77. GLM_FUNC_DECL unsigned int findEigenvaluesSymReal
  78. (
  79. mat<D, D, T, Q> const& covarMat,
  80. vec<D, T, Q>& outEigenvalues,
  81. mat<D, D, T, Q>& outEigenvectors
  82. )
  83. {
  84. using _internal_::transferSign;
  85. using _internal_::pythag;
  86. T a[D * D]; // matrix -- input and workspace for algorithm (will be changed inplace)
  87. T d[D]; // diagonal elements
  88. T e[D]; // off-diagonal elements
  89. for(length_t r = 0; r < D; r++)
  90. for(length_t c = 0; c < D; c++)
  91. a[(r) * D + (c)] = covarMat[c][r];
  92. // 1. Householder reduction.
  93. length_t l, k, j, i;
  94. T scale, hh, h, g, f;
  95. static const T epsilon = static_cast<T>(0.0000001);
  96. for(i = D; i >= 2; i--)
  97. {
  98. l = i - 1;
  99. h = scale = 0;
  100. if(l > 1)
  101. {
  102. for(k = 1; k <= l; k++)
  103. {
  104. scale += glm::abs(a[(i - 1) * D + (k - 1)]);
  105. }
  106. if(glm::equal<T>(scale, 0, epsilon))
  107. {
  108. e[i - 1] = a[(i - 1) * D + (l - 1)];
  109. }
  110. else
  111. {
  112. for(k = 1; k <= l; k++)
  113. {
  114. a[(i - 1) * D + (k - 1)] /= scale;
  115. h += a[(i - 1) * D + (k - 1)] * a[(i - 1) * D + (k - 1)];
  116. }
  117. f = a[(i - 1) * D + (l - 1)];
  118. g = ((f >= 0) ? -glm::sqrt(h) : glm::sqrt(h));
  119. e[i - 1] = scale * g;
  120. h -= f * g;
  121. a[(i - 1) * D + (l - 1)] = f - g;
  122. f = 0;
  123. for(j = 1; j <= l; j++)
  124. {
  125. a[(j - 1) * D + (i - 1)] = a[(i - 1) * D + (j - 1)] / h;
  126. g = 0;
  127. for(k = 1; k <= j; k++)
  128. {
  129. g += a[(j - 1) * D + (k - 1)] * a[(i - 1) * D + (k - 1)];
  130. }
  131. for(k = j + 1; k <= l; k++)
  132. {
  133. g += a[(k - 1) * D + (j - 1)] * a[(i - 1) * D + (k - 1)];
  134. }
  135. e[j - 1] = g / h;
  136. f += e[j - 1] * a[(i - 1) * D + (j - 1)];
  137. }
  138. hh = f / (h + h);
  139. for(j = 1; j <= l; j++)
  140. {
  141. f = a[(i - 1) * D + (j - 1)];
  142. e[j - 1] = g = e[j - 1] - hh * f;
  143. for(k = 1; k <= j; k++)
  144. {
  145. a[(j - 1) * D + (k - 1)] -= (f * e[k - 1] + g * a[(i - 1) * D + (k - 1)]);
  146. }
  147. }
  148. }
  149. }
  150. else
  151. {
  152. e[i - 1] = a[(i - 1) * D + (l - 1)];
  153. }
  154. d[i - 1] = h;
  155. }
  156. d[0] = 0;
  157. e[0] = 0;
  158. for(i = 1; i <= D; i++)
  159. {
  160. l = i - 1;
  161. if(!glm::equal<T>(d[i - 1], 0, epsilon))
  162. {
  163. for(j = 1; j <= l; j++)
  164. {
  165. g = 0;
  166. for(k = 1; k <= l; k++)
  167. {
  168. g += a[(i - 1) * D + (k - 1)] * a[(k - 1) * D + (j - 1)];
  169. }
  170. for(k = 1; k <= l; k++)
  171. {
  172. a[(k - 1) * D + (j - 1)] -= g * a[(k - 1) * D + (i - 1)];
  173. }
  174. }
  175. }
  176. d[i - 1] = a[(i - 1) * D + (i - 1)];
  177. a[(i - 1) * D + (i - 1)] = 1;
  178. for(j = 1; j <= l; j++)
  179. {
  180. a[(j - 1) * D + (i - 1)] = a[(i - 1) * D + (j - 1)] = 0;
  181. }
  182. }
  183. // 2. Calculation of eigenvalues and eigenvectors (QL algorithm)
  184. length_t m, iter;
  185. T s, r, p, dd, c, b;
  186. const length_t MAX_ITER = 30;
  187. for(i = 2; i <= D; i++)
  188. {
  189. e[i - 2] = e[i - 1];
  190. }
  191. e[D - 1] = 0;
  192. for(l = 1; l <= D; l++)
  193. {
  194. iter = 0;
  195. do
  196. {
  197. for(m = l; m <= D - 1; m++)
  198. {
  199. dd = glm::abs(d[m - 1]) + glm::abs(d[m - 1 + 1]);
  200. if(glm::equal<T>(glm::abs(e[m - 1]) + dd, dd, epsilon))
  201. break;
  202. }
  203. if(m != l)
  204. {
  205. if(iter++ == MAX_ITER)
  206. {
  207. return 0; // Too many iterations in FindEigenvalues
  208. }
  209. g = (d[l - 1 + 1] - d[l - 1]) / (2 * e[l - 1]);
  210. r = pythag<T>(g, 1);
  211. g = d[m - 1] - d[l - 1] + e[l - 1] / (g + transferSign(r, g));
  212. s = c = 1;
  213. p = 0;
  214. for(i = m - 1; i >= l; i--)
  215. {
  216. f = s * e[i - 1];
  217. b = c * e[i - 1];
  218. e[i - 1 + 1] = r = pythag(f, g);
  219. if(glm::equal<T>(r, 0, epsilon))
  220. {
  221. d[i - 1 + 1] -= p;
  222. e[m - 1] = 0;
  223. break;
  224. }
  225. s = f / r;
  226. c = g / r;
  227. g = d[i - 1 + 1] - p;
  228. r = (d[i - 1] - g) * s + 2 * c * b;
  229. d[i - 1 + 1] = g + (p = s * r);
  230. g = c * r - b;
  231. for(k = 1; k <= D; k++)
  232. {
  233. f = a[(k - 1) * D + (i - 1 + 1)];
  234. a[(k - 1) * D + (i - 1 + 1)] = s * a[(k - 1) * D + (i - 1)] + c * f;
  235. a[(k - 1) * D + (i - 1)] = c * a[(k - 1) * D + (i - 1)] - s * f;
  236. }
  237. }
  238. if(glm::equal<T>(r, 0, epsilon) && (i >= l))
  239. continue;
  240. d[l - 1] -= p;
  241. e[l - 1] = g;
  242. e[m - 1] = 0;
  243. }
  244. } while(m != l);
  245. }
  246. // 3. output
  247. for(i = 0; i < D; i++)
  248. outEigenvalues[i] = d[i];
  249. for(i = 0; i < D; i++)
  250. for(j = 0; j < D; j++)
  251. outEigenvectors[i][j] = a[(j) * D + (i)];
  252. return D;
  253. }
  254. template<typename T, qualifier Q>
  255. GLM_INLINE void sortEigenvalues(vec<2, T, Q>& eigenvalues, mat<2, 2, T, Q>& eigenvectors)
  256. {
  257. if (eigenvalues[0] < eigenvalues[1])
  258. {
  259. std::swap(eigenvalues[0], eigenvalues[1]);
  260. std::swap(eigenvectors[0], eigenvectors[1]);
  261. }
  262. }
  263. template<typename T, qualifier Q>
  264. GLM_INLINE void sortEigenvalues(vec<3, T, Q>& eigenvalues, mat<3, 3, T, Q>& eigenvectors)
  265. {
  266. if (eigenvalues[0] < eigenvalues[1])
  267. {
  268. std::swap(eigenvalues[0], eigenvalues[1]);
  269. std::swap(eigenvectors[0], eigenvectors[1]);
  270. }
  271. if (eigenvalues[0] < eigenvalues[2])
  272. {
  273. std::swap(eigenvalues[0], eigenvalues[2]);
  274. std::swap(eigenvectors[0], eigenvectors[2]);
  275. }
  276. if (eigenvalues[1] < eigenvalues[2])
  277. {
  278. std::swap(eigenvalues[1], eigenvalues[2]);
  279. std::swap(eigenvectors[1], eigenvectors[2]);
  280. }
  281. }
  282. template<typename T, qualifier Q>
  283. GLM_INLINE void sortEigenvalues(vec<4, T, Q>& eigenvalues, mat<4, 4, T, Q>& eigenvectors)
  284. {
  285. if (eigenvalues[0] < eigenvalues[2])
  286. {
  287. std::swap(eigenvalues[0], eigenvalues[2]);
  288. std::swap(eigenvectors[0], eigenvectors[2]);
  289. }
  290. if (eigenvalues[1] < eigenvalues[3])
  291. {
  292. std::swap(eigenvalues[1], eigenvalues[3]);
  293. std::swap(eigenvectors[1], eigenvectors[3]);
  294. }
  295. if (eigenvalues[0] < eigenvalues[1])
  296. {
  297. std::swap(eigenvalues[0], eigenvalues[1]);
  298. std::swap(eigenvectors[0], eigenvectors[1]);
  299. }
  300. if (eigenvalues[2] < eigenvalues[3])
  301. {
  302. std::swap(eigenvalues[2], eigenvalues[3]);
  303. std::swap(eigenvectors[2], eigenvectors[3]);
  304. }
  305. if (eigenvalues[1] < eigenvalues[2])
  306. {
  307. std::swap(eigenvalues[1], eigenvalues[2]);
  308. std::swap(eigenvectors[1], eigenvectors[2]);
  309. }
  310. }
  311. }//namespace glm