fn_princomp.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #include <armadillo>
  2. #include "catch.hpp"
  3. using namespace arma;
  4. namespace
  5. {
  6. void
  7. initMatrix(mat& m)
  8. {
  9. for(uword ii = 0; ii < m.n_rows; ++ii)
  10. for(uword jj = 0; jj < m.n_cols; ++jj)
  11. {
  12. const int i = int(ii);
  13. const int j = int(jj);
  14. m(ii, jj) = 5 * (i % 17) + (i + j) % 13 - 7 * ((j + 2) % 5) + double(i)/double(m.n_rows);
  15. }
  16. }
  17. void checkEigenvectors(const mat& coeff)
  18. {
  19. // sign of the eigenvectors can be flipped
  20. REQUIRE(std::abs(coeff(0,0)) == Approx(2.2366412109e-01));
  21. REQUIRE(std::abs(coeff(0,1)) == Approx(3.1197826828e-01));
  22. REQUIRE(std::abs(coeff(0,2)) == Approx(5.1847537613e-02));
  23. REQUIRE(std::abs(coeff(1,0)) == Approx(2.2419616512e-01));
  24. REQUIRE(std::abs(coeff(1,1)) == Approx(2.7564301912e-01));
  25. REQUIRE(std::abs(coeff(1,2)) == Approx(1.0953921221e-01));
  26. REQUIRE(std::abs(coeff(2,0)) == Approx(2.2427613980e-01));
  27. REQUIRE(std::abs(coeff(2,1)) == Approx(1.6088934501e-01));
  28. REQUIRE(std::abs(coeff(2,2)) == Approx(2.3660988967e-01));
  29. }
  30. void checkScore(const mat& score)
  31. {
  32. REQUIRE(score(0,0) == Approx(-1.8538115696e+02));
  33. REQUIRE(score(0,1) == Approx(4.6671842099e+00));
  34. REQUIRE(score(0,2) == Approx(1.1026881736e+01));
  35. REQUIRE(score(1,0) == Approx(-1.6144314244e+02));
  36. REQUIRE(score(1,1) == Approx(8.0636602200e+00));
  37. REQUIRE(score(1,2) == Approx(8.5129014856e+00));
  38. REQUIRE(score(2,0) == Approx(-1.3750123749e+02));
  39. REQUIRE(score(2,1) == Approx(1.0312494525e+01));
  40. REQUIRE(score(2,2) == Approx(4.5214633042e+00));
  41. }
  42. void checkEigenvalues(const vec& latent)
  43. {
  44. REQUIRE(latent(0) == Approx(1.1989436021e+04));
  45. REQUIRE(latent(1) == Approx(9.2136913098e+01));
  46. REQUIRE(latent(2) == Approx(7.8335565832e+01));
  47. REQUIRE(latent(3) == Approx(2.4204644513e+01));
  48. REQUIRE(latent(4) == Approx(2.1302619671e+01));
  49. REQUIRE(latent(5) == Approx(1.1615198930e+01));
  50. REQUIRE(latent(6) == Approx(1.1040034957e+01));
  51. REQUIRE(latent(7) == Approx(7.7918177707e+00));
  52. REQUIRE(latent(8) == Approx(7.2862524567e+00));
  53. REQUIRE(latent(9) == Approx(6.5039856845e+00));
  54. }
  55. void checkHotteling(const vec& tsquared)
  56. {
  57. REQUIRE(tsquared(0) == Approx(7.1983631370e+02));
  58. REQUIRE(tsquared(1) == Approx(6.5616053343e+02));
  59. REQUIRE(tsquared(2) == Approx(5.6308987454e+02));
  60. REQUIRE(tsquared(3) == Approx(3.6908398978e+02));
  61. REQUIRE(tsquared(4) == Approx(2.4632493795e+02));
  62. REQUIRE(tsquared(5) == Approx(1.3213013367e+02));
  63. REQUIRE(tsquared(6) == Approx(5.7414718234e+01));
  64. REQUIRE(tsquared(7) == Approx(1.5157746233e+01));
  65. REQUIRE(tsquared(8) == Approx(1.7316032365e+01));
  66. REQUIRE(tsquared(9) == Approx(2.9290529527e+01));
  67. REQUIRE(tsquared(20) == Approx(2.6159738840e+02));
  68. }
  69. }
  70. TEST_CASE("fn_princomp_1")
  71. {
  72. mat m(1000, 20);
  73. initMatrix(m);
  74. mat coeff = princomp(m);
  75. checkEigenvectors(coeff);
  76. }
  77. TEST_CASE("fn_princomp_2")
  78. {
  79. mat m(1000, 20);
  80. initMatrix(m);
  81. mat coeff;
  82. princomp(coeff, m);
  83. checkEigenvectors(coeff);
  84. }
  85. TEST_CASE("fn_princomp_3")
  86. {
  87. mat m(1000, 20);
  88. initMatrix(m);
  89. mat coeff;
  90. mat score;
  91. princomp(coeff, score, m);
  92. checkScore(score);
  93. checkEigenvectors(coeff);
  94. }
  95. TEST_CASE("fn_princomp_4")
  96. {
  97. mat m(1000, 20);
  98. initMatrix(m);
  99. mat coeff;
  100. mat score;
  101. vec latent;
  102. princomp(coeff, score, latent, m);
  103. checkEigenvectors(coeff);
  104. checkScore(score);
  105. checkEigenvalues(latent);
  106. }
  107. TEST_CASE("fn_princomp_5")
  108. {
  109. mat m(1000, 20);
  110. initMatrix(m);
  111. mat coeff;
  112. mat score;
  113. vec latent;
  114. vec tsquared;
  115. princomp(coeff, score, latent, tsquared, m);
  116. checkEigenvectors(coeff);
  117. checkScore(score);
  118. checkEigenvalues(latent);
  119. // checkHotteling(tsquared); // TODO
  120. }
  121. TEST_CASE("fn_princomp_6")
  122. {
  123. mat m(5, 20);
  124. initMatrix(m);
  125. mat coeff = princomp(m);
  126. REQUIRE(std::abs(coeff(0,0)) == Approx(2.4288979933e-01));
  127. REQUIRE(std::abs(coeff(0,1)) == Approx(3.9409505019e-16));
  128. REQUIRE(std::abs(coeff(0,2)) == Approx(1.2516285718e-02));
  129. REQUIRE(std::abs(coeff(1,0)) == Approx(2.4288979933e-01));
  130. REQUIRE(std::abs(coeff(1,1)) == Approx(2.9190770799e-16));
  131. REQUIRE(std::abs(coeff(1,2)) == Approx(1.2516285718e-02));
  132. REQUIRE(std::abs(coeff(2,0)) == Approx(2.4288979933e-01));
  133. REQUIRE(std::abs(coeff(2,1)) == Approx(3.4719806003e-17));
  134. REQUIRE(std::abs(coeff(2,2)) == Approx(1.2516285718e-02));
  135. REQUIRE(std::abs(coeff(19,19)) == Approx(9.5528446175e-01).epsilon(0.01));
  136. }