fn_eigs_gen.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Copyright 2011-2017 Ryan Curtin (http://www.ratml.org/)
  2. // Copyright 2017 National ICT Australia (NICTA)
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // ------------------------------------------------------------------------
  15. #include <armadillo>
  16. #include "catch.hpp"
  17. using namespace arma;
  18. TEST_CASE("fn_eigs_gen_odd_test")
  19. {
  20. const uword n_rows = 10;
  21. const uword n_eigval = 5;
  22. for (size_t trial = 0; trial < 10; ++trial)
  23. {
  24. sp_mat m;
  25. m.sprandu(n_rows, n_rows, 0.3);
  26. mat d(m);
  27. // Eigendecompose, getting first 5 eigenvectors.
  28. Col< std::complex<double> > sp_eigval;
  29. Mat< std::complex<double> > sp_eigvec;
  30. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  31. // Do the same for the dense case.
  32. Col< std::complex<double> > eigval;
  33. Mat< std::complex<double> > eigvec;
  34. eig_gen(eigval, eigvec, d);
  35. uvec used(n_rows);
  36. used.fill(0);
  37. for (size_t i = 0; i < n_eigval; ++i)
  38. {
  39. // Sorting these is difficult.
  40. // Find which one is the likely dense eigenvalue.
  41. uword dense_eval = n_rows + 1;
  42. for (uword k = 0; k < n_rows; ++k)
  43. {
  44. if ((std::abs(std::complex<double>(sp_eigval[i]).real() - eigval[k].real()) < 1e-4) &&
  45. (std::abs(std::complex<double>(sp_eigval[i]).imag() - eigval[k].imag()) < 1e-4) &&
  46. (used[k] == 0))
  47. {
  48. dense_eval = k;
  49. used[k] = 1;
  50. break;
  51. }
  52. }
  53. REQUIRE( dense_eval != n_rows + 1 );
  54. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.1) );
  55. for (uword j = 0; j < n_rows; ++j)
  56. {
  57. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.1) );
  58. }
  59. }
  60. }
  61. }
  62. TEST_CASE("fn_eigs_gen_even_test")
  63. {
  64. const uword n_rows = 10;
  65. const uword n_eigval = 4;
  66. for (size_t trial = 0; trial < 10; ++trial)
  67. {
  68. sp_mat m;
  69. m.sprandu(n_rows, n_rows, 0.3);
  70. sp_mat z(5, 5);
  71. z.sprandu(5, 5, 0.5);
  72. m.submat(2, 2, 6, 6) += 5 * z;
  73. mat d(m);
  74. // Eigendecompose, getting first 4 eigenvectors.
  75. Col< std::complex<double> > sp_eigval;
  76. Mat< std::complex<double> > sp_eigvec;
  77. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  78. // Do the same for the dense case.
  79. Col< std::complex<double> > eigval;
  80. Mat< std::complex<double> > eigvec;
  81. eig_gen(eigval, eigvec, d);
  82. uvec used(n_rows);
  83. used.fill(0);
  84. for (size_t i = 0; i < n_eigval; ++i)
  85. {
  86. // Sorting these is difficult.
  87. // Find which one is the likely dense eigenvalue.
  88. uword dense_eval = n_rows + 1;
  89. for (uword k = 0; k < n_rows; ++k)
  90. {
  91. if ((std::abs(std::complex<double>(sp_eigval[i]).real() - eigval[k].real()) < 1e-4) &&
  92. (std::abs(std::complex<double>(sp_eigval[i]).imag() - eigval[k].imag()) < 1e-4) &&
  93. (used[k] == 0))
  94. {
  95. dense_eval = k;
  96. used[k] = 1;
  97. break;
  98. }
  99. }
  100. REQUIRE( dense_eval != n_rows + 1 );
  101. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  102. for (uword j = 0; j < n_rows; ++j)
  103. {
  104. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  105. }
  106. }
  107. }
  108. }
  109. TEST_CASE("fn_eigs_gen_odd_float_test")
  110. {
  111. const uword n_rows = 10;
  112. const uword n_eigval = 5;
  113. for (size_t trial = 0; trial < 10; ++trial)
  114. {
  115. SpMat<float> m;
  116. m.sprandu(n_rows, n_rows, 0.3);
  117. for (uword i = 0; i < n_rows; ++i)
  118. {
  119. m(i, i) += 5 * double(i) / double(n_rows);
  120. }
  121. Mat<float> d(m);
  122. // Eigendecompose, getting first 5 eigenvectors.
  123. Col< std::complex<float> > sp_eigval;
  124. Mat< std::complex<float> > sp_eigvec;
  125. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  126. // Do the same for the dense case.
  127. Col< std::complex<float> > eigval;
  128. Mat< std::complex<float> > eigvec;
  129. eig_gen(eigval, eigvec, d);
  130. uvec used(n_rows);
  131. used.fill(0);
  132. for (size_t i = 0; i < n_eigval; ++i)
  133. {
  134. // Sorting these is difficult.
  135. // Find which one is the likely dense eigenvalue.
  136. uword dense_eval = n_rows + 1;
  137. for (uword k = 0; k < n_rows; ++k)
  138. {
  139. if ((std::abs(std::complex<float>(sp_eigval[i]).real() - eigval[k].real()) < 0.001) &&
  140. (std::abs(std::complex<float>(sp_eigval[i]).imag() - eigval[k].imag()) < 0.001) &&
  141. (used[k] == 0))
  142. {
  143. dense_eval = k;
  144. used[k] = 1;
  145. break;
  146. }
  147. }
  148. REQUIRE( dense_eval != n_rows + 1 );
  149. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.001) );
  150. for (uword j = 0; j < n_rows; ++j)
  151. {
  152. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  153. }
  154. }
  155. }
  156. }
  157. TEST_CASE("fn_eigs_gen_even_float_test")
  158. {
  159. const uword n_rows = 12;
  160. const uword n_eigval = 8;
  161. for (size_t trial = 0; trial < 10; ++trial)
  162. {
  163. SpMat<float> m;
  164. m.sprandu(n_rows, n_rows, 0.3);
  165. for (uword i = 0; i < n_rows; ++i)
  166. {
  167. m(i, i) += 5 * double(i) / double(n_rows);
  168. }
  169. Mat<float> d(m);
  170. // Eigendecompose, getting first 8 eigenvectors.
  171. Col< std::complex<float> > sp_eigval;
  172. Mat< std::complex<float> > sp_eigvec;
  173. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  174. // Do the same for the dense case.
  175. Col< std::complex<float> > eigval;
  176. Mat< std::complex<float> > eigvec;
  177. eig_gen(eigval, eigvec, d);
  178. uvec used(n_rows);
  179. used.fill(0);
  180. for (size_t i = 0; i < n_eigval; ++i)
  181. {
  182. // Sorting these is difficult.
  183. // Find which one is the likely dense eigenvalue.
  184. uword dense_eval = n_rows + 1;
  185. for (uword k = 0; k < n_rows; ++k)
  186. {
  187. if ((std::abs(std::complex<float>(sp_eigval[i]).real() - eigval[k].real()) < 0.001) &&
  188. (std::abs(std::complex<float>(sp_eigval[i]).imag() - eigval[k].imag()) < 0.001) &&
  189. (used[k] == 0))
  190. {
  191. dense_eval = k;
  192. used[k] = 1;
  193. break;
  194. }
  195. }
  196. REQUIRE( dense_eval != n_rows + 1 );
  197. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  198. for (uword j = 0; j < n_rows; ++j)
  199. {
  200. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  201. }
  202. }
  203. }
  204. }
  205. TEST_CASE("fn_eigs_gen_odd_complex_float_test")
  206. {
  207. const uword n_rows = 10;
  208. const uword n_eigval = 5;
  209. for (size_t trial = 0; trial < 10; ++trial)
  210. {
  211. SpMat< std::complex<float> > m;
  212. m.sprandu(n_rows, n_rows, 0.3);
  213. Mat< std::complex<float> > d(m);
  214. // Eigendecompose, getting first 5 eigenvectors.
  215. Col< std::complex<float> > sp_eigval;
  216. Mat< std::complex<float> > sp_eigvec;
  217. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  218. // Do the same for the dense case.
  219. Col< std::complex<float> > eigval;
  220. Mat< std::complex<float> > eigvec;
  221. eig_gen(eigval, eigvec, d);
  222. uvec used(n_rows);
  223. used.fill(0);
  224. for (size_t i = 0; i < n_eigval; ++i)
  225. {
  226. // Sorting these is difficult.
  227. // Find which one is the likely dense eigenvalue.
  228. uword dense_eval = n_rows + 1;
  229. for (uword k = 0; k < n_rows; ++k)
  230. {
  231. if ((std::abs(std::complex<float>(sp_eigval[i]).real() - eigval[k].real()) < 0.001) &&
  232. (std::abs(std::complex<float>(sp_eigval[i]).imag() - eigval[k].imag()) < 0.001) &&
  233. (used[k] == 0))
  234. {
  235. dense_eval = k;
  236. used[k] = 1;
  237. break;
  238. }
  239. }
  240. REQUIRE( dense_eval != n_rows + 1 );
  241. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  242. for (uword j = 0; j < n_rows; ++j)
  243. {
  244. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  245. }
  246. }
  247. }
  248. }
  249. TEST_CASE("fn_eigs_gen_even_complex_float_test")
  250. {
  251. const uword n_rows = 12;
  252. const uword n_eigval = 8;
  253. for (size_t trial = 0; trial < 10; ++trial)
  254. {
  255. SpMat< std::complex<float> > m;
  256. m.sprandu(n_rows, n_rows, 0.3);
  257. Mat< std::complex<float> > d(m);
  258. // Eigendecompose, getting first 8 eigenvectors.
  259. Col< std::complex<float> > sp_eigval;
  260. Mat< std::complex<float> > sp_eigvec;
  261. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  262. // Do the same for the dense case.
  263. Col< std::complex<float> > eigval;
  264. Mat< std::complex<float> > eigvec;
  265. eig_gen(eigval, eigvec, d);
  266. uvec used(n_rows);
  267. used.fill(0);
  268. for (size_t i = 0; i < n_eigval; ++i)
  269. {
  270. // Sorting these is difficult.
  271. // Find which one is the likely dense eigenvalue.
  272. uword dense_eval = n_rows + 1;
  273. for (uword k = 0; k < n_rows; ++k)
  274. {
  275. if ((std::abs(std::complex<float>(sp_eigval[i]).real() - eigval[k].real()) < 0.001) &&
  276. (std::abs(std::complex<float>(sp_eigval[i]).imag() - eigval[k].imag()) < 0.001) &&
  277. (used[k] == 0))
  278. {
  279. dense_eval = k;
  280. used[k] = 1;
  281. break;
  282. }
  283. }
  284. REQUIRE( dense_eval != n_rows + 1 );
  285. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  286. for (uword j = 0; j < n_rows; ++j)
  287. {
  288. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  289. }
  290. }
  291. }
  292. }
  293. TEST_CASE("eigs_gen_odd_complex_test")
  294. {
  295. const uword n_rows = 10;
  296. const uword n_eigval = 5;
  297. for (size_t trial = 0; trial < 10; ++trial)
  298. {
  299. SpMat< std::complex<double> > m;
  300. m.sprandu(n_rows, n_rows, 0.3);
  301. Mat< std::complex<double> > d(m);
  302. // Eigendecompose, getting first 5 eigenvectors.
  303. Col< std::complex<double> > sp_eigval;
  304. Mat< std::complex<double> > sp_eigvec;
  305. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  306. // Do the same for the dense case.
  307. Col< std::complex<double> > eigval;
  308. Mat< std::complex<double> > eigvec;
  309. eig_gen(eigval, eigvec, d);
  310. uvec used(n_rows);
  311. used.fill(0);
  312. for (size_t i = 0; i < n_eigval; ++i)
  313. {
  314. // Sorting these is difficult.
  315. // Find which one is the likely dense eigenvalue.
  316. uword dense_eval = n_rows + 1;
  317. for (uword k = 0; k < n_rows; ++k)
  318. {
  319. if ((std::abs(std::complex<double>(sp_eigval[i]).real() - eigval[k].real()) < 1e-10) &&
  320. (std::abs(std::complex<double>(sp_eigval[i]).imag() - eigval[k].imag()) < 1e-10) &&
  321. (used[k] == 0))
  322. {
  323. dense_eval = k;
  324. used[k] = 1;
  325. break;
  326. }
  327. }
  328. REQUIRE( dense_eval != n_rows + 1 );
  329. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  330. for (size_t j = 0; j < n_rows; ++j)
  331. {
  332. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  333. }
  334. }
  335. }
  336. }
  337. TEST_CASE("fn_eigs_gen_even_complex_test")
  338. {
  339. const uword n_rows = 15;
  340. const uword n_eigval = 6;
  341. for (size_t trial = 0; trial < 10; ++trial)
  342. {
  343. SpMat< std::complex<double> > m;
  344. m.sprandu(n_rows, n_rows, 0.3);
  345. Mat< std::complex<double> > d(m);
  346. // Eigendecompose, getting first 6 eigenvectors.
  347. Col< std::complex<double> > sp_eigval;
  348. Mat< std::complex<double> > sp_eigvec;
  349. eigs_gen(sp_eigval, sp_eigvec, m, n_eigval);
  350. // Do the same for the dense case.
  351. Col< std::complex<double> > eigval;
  352. Mat< std::complex<double> > eigvec;
  353. eig_gen(eigval, eigvec, d);
  354. uvec used(n_rows);
  355. used.fill(0);
  356. for (size_t i = 0; i < n_eigval; ++i)
  357. {
  358. // Sorting these is difficult.
  359. // Find which one is the likely dense eigenvalue.
  360. uword dense_eval = n_rows + 1;
  361. for (uword k = 0; k < n_rows; ++k)
  362. {
  363. if ((std::abs(std::complex<double>(sp_eigval[i]).real() - eigval[k].real()) < 1e-10) &&
  364. (std::abs(std::complex<double>(sp_eigval[i]).imag() - eigval[k].imag()) < 1e-10) &&
  365. (used[k] == 0))
  366. {
  367. dense_eval = k;
  368. used[k] = 1;
  369. break;
  370. }
  371. }
  372. REQUIRE( dense_eval != n_rows + 1 );
  373. REQUIRE( std::abs(sp_eigval[i]) == Approx(std::abs(eigval[dense_eval])).epsilon(0.01) );
  374. for (uword j = 0; j < n_rows; ++j)
  375. {
  376. REQUIRE( std::abs(sp_eigvec(j, i)) == Approx(std::abs(eigvec(j, dense_eval))).epsilon(0.01) );
  377. }
  378. }
  379. }
  380. }