cxx11_tensor_expr.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. #include <numeric>
  10. #include "main.h"
  11. #include <Eigen/CXX11/Tensor>
  12. using Eigen::Tensor;
  13. using Eigen::RowMajor;
  14. static void test_1d()
  15. {
  16. Tensor<float, 1> vec1(6);
  17. Tensor<float, 1, RowMajor> vec2(6);
  18. vec1(0) = 4.0; vec2(0) = 0.0;
  19. vec1(1) = 8.0; vec2(1) = 1.0;
  20. vec1(2) = 15.0; vec2(2) = 2.0;
  21. vec1(3) = 16.0; vec2(3) = 3.0;
  22. vec1(4) = 23.0; vec2(4) = 4.0;
  23. vec1(5) = 42.0; vec2(5) = 5.0;
  24. float data3[6];
  25. TensorMap<Tensor<float, 1>> vec3(data3, 6);
  26. vec3 = vec1.sqrt();
  27. float data4[6];
  28. TensorMap<Tensor<float, 1, RowMajor>> vec4(data4, 6);
  29. vec4 = vec2.square();
  30. float data5[6];
  31. TensorMap<Tensor<float, 1, RowMajor>> vec5(data5, 6);
  32. vec5 = vec2.cube();
  33. VERIFY_IS_APPROX(vec3(0), sqrtf(4.0));
  34. VERIFY_IS_APPROX(vec3(1), sqrtf(8.0));
  35. VERIFY_IS_APPROX(vec3(2), sqrtf(15.0));
  36. VERIFY_IS_APPROX(vec3(3), sqrtf(16.0));
  37. VERIFY_IS_APPROX(vec3(4), sqrtf(23.0));
  38. VERIFY_IS_APPROX(vec3(5), sqrtf(42.0));
  39. VERIFY_IS_APPROX(vec4(0), 0.0f);
  40. VERIFY_IS_APPROX(vec4(1), 1.0f);
  41. VERIFY_IS_APPROX(vec4(2), 2.0f * 2.0f);
  42. VERIFY_IS_APPROX(vec4(3), 3.0f * 3.0f);
  43. VERIFY_IS_APPROX(vec4(4), 4.0f * 4.0f);
  44. VERIFY_IS_APPROX(vec4(5), 5.0f * 5.0f);
  45. VERIFY_IS_APPROX(vec5(0), 0.0f);
  46. VERIFY_IS_APPROX(vec5(1), 1.0f);
  47. VERIFY_IS_APPROX(vec5(2), 2.0f * 2.0f * 2.0f);
  48. VERIFY_IS_APPROX(vec5(3), 3.0f * 3.0f * 3.0f);
  49. VERIFY_IS_APPROX(vec5(4), 4.0f * 4.0f * 4.0f);
  50. VERIFY_IS_APPROX(vec5(5), 5.0f * 5.0f * 5.0f);
  51. vec3 = vec1 + vec2;
  52. VERIFY_IS_APPROX(vec3(0), 4.0f + 0.0f);
  53. VERIFY_IS_APPROX(vec3(1), 8.0f + 1.0f);
  54. VERIFY_IS_APPROX(vec3(2), 15.0f + 2.0f);
  55. VERIFY_IS_APPROX(vec3(3), 16.0f + 3.0f);
  56. VERIFY_IS_APPROX(vec3(4), 23.0f + 4.0f);
  57. VERIFY_IS_APPROX(vec3(5), 42.0f + 5.0f);
  58. }
  59. static void test_2d()
  60. {
  61. float data1[6];
  62. TensorMap<Tensor<float, 2>> mat1(data1, 2, 3);
  63. float data2[6];
  64. TensorMap<Tensor<float, 2, RowMajor>> mat2(data2, 2, 3);
  65. mat1(0,0) = 0.0;
  66. mat1(0,1) = 1.0;
  67. mat1(0,2) = 2.0;
  68. mat1(1,0) = 3.0;
  69. mat1(1,1) = 4.0;
  70. mat1(1,2) = 5.0;
  71. mat2(0,0) = -0.0;
  72. mat2(0,1) = -1.0;
  73. mat2(0,2) = -2.0;
  74. mat2(1,0) = -3.0;
  75. mat2(1,1) = -4.0;
  76. mat2(1,2) = -5.0;
  77. Tensor<float, 2> mat3(2,3);
  78. Tensor<float, 2, RowMajor> mat4(2,3);
  79. mat3 = mat1.abs();
  80. mat4 = mat2.abs();
  81. VERIFY_IS_APPROX(mat3(0,0), 0.0f);
  82. VERIFY_IS_APPROX(mat3(0,1), 1.0f);
  83. VERIFY_IS_APPROX(mat3(0,2), 2.0f);
  84. VERIFY_IS_APPROX(mat3(1,0), 3.0f);
  85. VERIFY_IS_APPROX(mat3(1,1), 4.0f);
  86. VERIFY_IS_APPROX(mat3(1,2), 5.0f);
  87. VERIFY_IS_APPROX(mat4(0,0), 0.0f);
  88. VERIFY_IS_APPROX(mat4(0,1), 1.0f);
  89. VERIFY_IS_APPROX(mat4(0,2), 2.0f);
  90. VERIFY_IS_APPROX(mat4(1,0), 3.0f);
  91. VERIFY_IS_APPROX(mat4(1,1), 4.0f);
  92. VERIFY_IS_APPROX(mat4(1,2), 5.0f);
  93. }
  94. static void test_3d()
  95. {
  96. Tensor<float, 3> mat1(2,3,7);
  97. Tensor<float, 3, RowMajor> mat2(2,3,7);
  98. float val = 1.0f;
  99. for (int i = 0; i < 2; ++i) {
  100. for (int j = 0; j < 3; ++j) {
  101. for (int k = 0; k < 7; ++k) {
  102. mat1(i,j,k) = val;
  103. mat2(i,j,k) = val;
  104. val += 1.0f;
  105. }
  106. }
  107. }
  108. Tensor<float, 3> mat3(2,3,7);
  109. mat3 = mat1 + mat1;
  110. Tensor<float, 3, RowMajor> mat4(2,3,7);
  111. mat4 = mat2 * 3.14f;
  112. Tensor<float, 3> mat5(2,3,7);
  113. mat5 = mat1.inverse().log();
  114. Tensor<float, 3, RowMajor> mat6(2,3,7);
  115. mat6 = mat2.pow(0.5f) * 3.14f;
  116. Tensor<float, 3> mat7(2,3,7);
  117. mat7 = mat1.cwiseMax(mat5 * 2.0f).exp();
  118. Tensor<float, 3, RowMajor> mat8(2,3,7);
  119. mat8 = (-mat2).exp() * 3.14f;
  120. Tensor<float, 3, RowMajor> mat9(2,3,7);
  121. mat9 = mat2 + 3.14f;
  122. Tensor<float, 3, RowMajor> mat10(2,3,7);
  123. mat10 = mat2 - 3.14f;
  124. Tensor<float, 3, RowMajor> mat11(2,3,7);
  125. mat11 = mat2 / 3.14f;
  126. val = 1.0f;
  127. for (int i = 0; i < 2; ++i) {
  128. for (int j = 0; j < 3; ++j) {
  129. for (int k = 0; k < 7; ++k) {
  130. VERIFY_IS_APPROX(mat3(i,j,k), val + val);
  131. VERIFY_IS_APPROX(mat4(i,j,k), val * 3.14f);
  132. VERIFY_IS_APPROX(mat5(i,j,k), logf(1.0f/val));
  133. VERIFY_IS_APPROX(mat6(i,j,k), sqrtf(val) * 3.14f);
  134. VERIFY_IS_APPROX(mat7(i,j,k), expf((std::max)(val, mat5(i,j,k) * 2.0f)));
  135. VERIFY_IS_APPROX(mat8(i,j,k), expf(-val) * 3.14f);
  136. VERIFY_IS_APPROX(mat9(i,j,k), val + 3.14f);
  137. VERIFY_IS_APPROX(mat10(i,j,k), val - 3.14f);
  138. VERIFY_IS_APPROX(mat11(i,j,k), val / 3.14f);
  139. val += 1.0f;
  140. }
  141. }
  142. }
  143. }
  144. static void test_constants()
  145. {
  146. Tensor<float, 3> mat1(2,3,7);
  147. Tensor<float, 3> mat2(2,3,7);
  148. Tensor<float, 3> mat3(2,3,7);
  149. float val = 1.0f;
  150. for (int i = 0; i < 2; ++i) {
  151. for (int j = 0; j < 3; ++j) {
  152. for (int k = 0; k < 7; ++k) {
  153. mat1(i,j,k) = val;
  154. val += 1.0f;
  155. }
  156. }
  157. }
  158. mat2 = mat1.constant(3.14f);
  159. mat3 = mat1.cwiseMax(7.3f).exp();
  160. val = 1.0f;
  161. for (int i = 0; i < 2; ++i) {
  162. for (int j = 0; j < 3; ++j) {
  163. for (int k = 0; k < 7; ++k) {
  164. VERIFY_IS_APPROX(mat2(i,j,k), 3.14f);
  165. VERIFY_IS_APPROX(mat3(i,j,k), expf((std::max)(val, 7.3f)));
  166. val += 1.0f;
  167. }
  168. }
  169. }
  170. }
  171. static void test_boolean()
  172. {
  173. const int kSize = 31;
  174. Tensor<int, 1> vec(kSize);
  175. std::iota(vec.data(), vec.data() + kSize, 0);
  176. // Test ||.
  177. Tensor<bool, 1> bool1 = vec < vec.constant(1) || vec > vec.constant(4);
  178. for (int i = 0; i < kSize; ++i) {
  179. bool expected = i < 1 || i > 4;
  180. VERIFY_IS_EQUAL(bool1[i], expected);
  181. }
  182. // Test &&, including cast of operand vec.
  183. Tensor<bool, 1> bool2 = vec.cast<bool>() && vec < vec.constant(4);
  184. for (int i = 0; i < kSize; ++i) {
  185. bool expected = bool(i) && i < 4;
  186. VERIFY_IS_EQUAL(bool2[i], expected);
  187. }
  188. // Compilation tests:
  189. // Test Tensor<bool> against results of cast or comparison; verifies that
  190. // CoeffReturnType is set to match Op return type of bool for Unary and Binary
  191. // Ops.
  192. Tensor<bool, 1> bool3 = vec.cast<bool>() && bool2;
  193. bool3 = vec < vec.constant(4) && bool2;
  194. }
  195. static void test_functors()
  196. {
  197. Tensor<float, 3> mat1(2,3,7);
  198. Tensor<float, 3> mat2(2,3,7);
  199. Tensor<float, 3> mat3(2,3,7);
  200. float val = 1.0f;
  201. for (int i = 0; i < 2; ++i) {
  202. for (int j = 0; j < 3; ++j) {
  203. for (int k = 0; k < 7; ++k) {
  204. mat1(i,j,k) = val;
  205. val += 1.0f;
  206. }
  207. }
  208. }
  209. mat2 = mat1.inverse().unaryExpr(&asinf);
  210. mat3 = mat1.unaryExpr(&tanhf);
  211. val = 1.0f;
  212. for (int i = 0; i < 2; ++i) {
  213. for (int j = 0; j < 3; ++j) {
  214. for (int k = 0; k < 7; ++k) {
  215. VERIFY_IS_APPROX(mat2(i,j,k), asinf(1.0f / mat1(i,j,k)));
  216. VERIFY_IS_APPROX(mat3(i,j,k), tanhf(mat1(i,j,k)));
  217. val += 1.0f;
  218. }
  219. }
  220. }
  221. }
  222. static void test_type_casting()
  223. {
  224. Tensor<bool, 3> mat1(2,3,7);
  225. Tensor<float, 3> mat2(2,3,7);
  226. Tensor<double, 3> mat3(2,3,7);
  227. mat1.setRandom();
  228. mat2.setRandom();
  229. mat3 = mat1.cast<double>();
  230. for (int i = 0; i < 2; ++i) {
  231. for (int j = 0; j < 3; ++j) {
  232. for (int k = 0; k < 7; ++k) {
  233. VERIFY_IS_APPROX(mat3(i,j,k), mat1(i,j,k) ? 1.0 : 0.0);
  234. }
  235. }
  236. }
  237. mat3 = mat2.cast<double>();
  238. for (int i = 0; i < 2; ++i) {
  239. for (int j = 0; j < 3; ++j) {
  240. for (int k = 0; k < 7; ++k) {
  241. VERIFY_IS_APPROX(mat3(i,j,k), static_cast<double>(mat2(i,j,k)));
  242. }
  243. }
  244. }
  245. }
  246. static void test_select()
  247. {
  248. Tensor<float, 3> selector(2,3,7);
  249. Tensor<float, 3> mat1(2,3,7);
  250. Tensor<float, 3> mat2(2,3,7);
  251. Tensor<float, 3> result(2,3,7);
  252. selector.setRandom();
  253. mat1.setRandom();
  254. mat2.setRandom();
  255. result = (selector > selector.constant(0.5f)).select(mat1, mat2);
  256. for (int i = 0; i < 2; ++i) {
  257. for (int j = 0; j < 3; ++j) {
  258. for (int k = 0; k < 7; ++k) {
  259. VERIFY_IS_APPROX(result(i,j,k), (selector(i,j,k) > 0.5f) ? mat1(i,j,k) : mat2(i,j,k));
  260. }
  261. }
  262. }
  263. }
  264. template <typename Scalar>
  265. void test_minmax_nan_propagation_templ() {
  266. for (int size = 1; size < 17; ++size) {
  267. const Scalar kNaN = std::numeric_limits<Scalar>::quiet_NaN();
  268. const Scalar kInf = std::numeric_limits<Scalar>::infinity();
  269. const Scalar kZero(0);
  270. Tensor<Scalar, 1> vec_all_nan(size);
  271. Tensor<Scalar, 1> vec_one_nan(size);
  272. Tensor<Scalar, 1> vec_zero(size);
  273. vec_all_nan.setConstant(kNaN);
  274. vec_zero.setZero();
  275. vec_one_nan.setZero();
  276. vec_one_nan(size/2) = kNaN;
  277. auto verify_all_nan = [&](const Tensor<Scalar, 1>& v) {
  278. for (int i = 0; i < size; ++i) {
  279. VERIFY((numext::isnan)(v(i)));
  280. }
  281. };
  282. auto verify_all_zero = [&](const Tensor<Scalar, 1>& v) {
  283. for (int i = 0; i < size; ++i) {
  284. VERIFY_IS_EQUAL(v(i), Scalar(0));
  285. }
  286. };
  287. // Test NaN propagating max.
  288. // max(nan, nan) = nan
  289. // max(nan, 0) = nan
  290. // max(0, nan) = nan
  291. // max(0, 0) = 0
  292. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(kNaN));
  293. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(vec_all_nan));
  294. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(kZero));
  295. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNaN>(vec_zero));
  296. verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(kNaN));
  297. verify_all_nan(vec_zero.template cwiseMax<PropagateNaN>(vec_all_nan));
  298. verify_all_zero(vec_zero.template cwiseMax<PropagateNaN>(kZero));
  299. verify_all_zero(vec_zero.template cwiseMax<PropagateNaN>(vec_zero));
  300. // Test number propagating max.
  301. // max(nan, nan) = nan
  302. // max(nan, 0) = 0
  303. // max(0, nan) = 0
  304. // max(0, 0) = 0
  305. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNumbers>(kNaN));
  306. verify_all_nan(vec_all_nan.template cwiseMax<PropagateNumbers>(vec_all_nan));
  307. verify_all_zero(vec_all_nan.template cwiseMax<PropagateNumbers>(kZero));
  308. verify_all_zero(vec_all_nan.template cwiseMax<PropagateNumbers>(vec_zero));
  309. verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(kNaN));
  310. verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(vec_all_nan));
  311. verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(kZero));
  312. verify_all_zero(vec_zero.template cwiseMax<PropagateNumbers>(vec_zero));
  313. // Test NaN propagating min.
  314. // min(nan, nan) = nan
  315. // min(nan, 0) = nan
  316. // min(0, nan) = nan
  317. // min(0, 0) = 0
  318. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(kNaN));
  319. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(vec_all_nan));
  320. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(kZero));
  321. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNaN>(vec_zero));
  322. verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(kNaN));
  323. verify_all_nan(vec_zero.template cwiseMin<PropagateNaN>(vec_all_nan));
  324. verify_all_zero(vec_zero.template cwiseMin<PropagateNaN>(kZero));
  325. verify_all_zero(vec_zero.template cwiseMin<PropagateNaN>(vec_zero));
  326. // Test number propagating min.
  327. // min(nan, nan) = nan
  328. // min(nan, 0) = 0
  329. // min(0, nan) = 0
  330. // min(0, 0) = 0
  331. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNumbers>(kNaN));
  332. verify_all_nan(vec_all_nan.template cwiseMin<PropagateNumbers>(vec_all_nan));
  333. verify_all_zero(vec_all_nan.template cwiseMin<PropagateNumbers>(kZero));
  334. verify_all_zero(vec_all_nan.template cwiseMin<PropagateNumbers>(vec_zero));
  335. verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(kNaN));
  336. verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(vec_all_nan));
  337. verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(kZero));
  338. verify_all_zero(vec_zero.template cwiseMin<PropagateNumbers>(vec_zero));
  339. // Test min and max reduction
  340. Tensor<Scalar, 0> val;
  341. val = vec_zero.minimum();
  342. VERIFY_IS_EQUAL(val(), kZero);
  343. val = vec_zero.template minimum<PropagateNaN>();
  344. VERIFY_IS_EQUAL(val(), kZero);
  345. val = vec_zero.template minimum<PropagateNumbers>();
  346. VERIFY_IS_EQUAL(val(), kZero);
  347. val = vec_zero.maximum();
  348. VERIFY_IS_EQUAL(val(), kZero);
  349. val = vec_zero.template maximum<PropagateNaN>();
  350. VERIFY_IS_EQUAL(val(), kZero);
  351. val = vec_zero.template maximum<PropagateNumbers>();
  352. VERIFY_IS_EQUAL(val(), kZero);
  353. // Test NaN propagation for tensor of all NaNs.
  354. val = vec_all_nan.template minimum<PropagateNaN>();
  355. VERIFY((numext::isnan)(val()));
  356. val = vec_all_nan.template minimum<PropagateNumbers>();
  357. VERIFY_IS_EQUAL(val(), kInf);
  358. val = vec_all_nan.template maximum<PropagateNaN>();
  359. VERIFY((numext::isnan)(val()));
  360. val = vec_all_nan.template maximum<PropagateNumbers>();
  361. VERIFY_IS_EQUAL(val(), -kInf);
  362. // Test NaN propagation for tensor with a single NaN.
  363. val = vec_one_nan.template minimum<PropagateNaN>();
  364. VERIFY((numext::isnan)(val()));
  365. val = vec_one_nan.template minimum<PropagateNumbers>();
  366. VERIFY_IS_EQUAL(val(), (size == 1 ? kInf : kZero));
  367. val = vec_one_nan.template maximum<PropagateNaN>();
  368. VERIFY((numext::isnan)(val()));
  369. val = vec_one_nan.template maximum<PropagateNumbers>();
  370. VERIFY_IS_EQUAL(val(), (size == 1 ? -kInf : kZero));
  371. }
  372. }
  373. static void test_clip()
  374. {
  375. Tensor<float, 1> vec(6);
  376. vec(0) = 4.0;
  377. vec(1) = 8.0;
  378. vec(2) = 15.0;
  379. vec(3) = 16.0;
  380. vec(4) = 23.0;
  381. vec(5) = 42.0;
  382. float kMin = 20;
  383. float kMax = 30;
  384. Tensor<float, 1> vec_clipped(6);
  385. vec_clipped = vec.clip(kMin, kMax);
  386. for (int i = 0; i < 6; ++i) {
  387. VERIFY_IS_EQUAL(vec_clipped(i), numext::mini(numext::maxi(vec(i), kMin), kMax));
  388. }
  389. }
  390. static void test_minmax_nan_propagation()
  391. {
  392. test_minmax_nan_propagation_templ<float>();
  393. test_minmax_nan_propagation_templ<double>();
  394. }
  395. EIGEN_DECLARE_TEST(cxx11_tensor_expr)
  396. {
  397. CALL_SUBTEST(test_1d());
  398. CALL_SUBTEST(test_2d());
  399. CALL_SUBTEST(test_3d());
  400. CALL_SUBTEST(test_constants());
  401. CALL_SUBTEST(test_boolean());
  402. CALL_SUBTEST(test_functors());
  403. CALL_SUBTEST(test_type_casting());
  404. CALL_SUBTEST(test_select());
  405. CALL_SUBTEST(test_clip());
  406. // Nan propagation does currently not work like one would expect from std::max/std::min,
  407. // so we disable it for now
  408. #if !EIGEN_ARCH_ARM_OR_ARM64
  409. CALL_SUBTEST(test_minmax_nan_propagation());
  410. #endif
  411. }