//===-- test_funcs.cpp - test duals/dual ------------------------*- C++ -*-===// // // Part of the cppduals project. // https://gitlab.com/tesch1/cppduals // // See https://gitlab.com/tesch1/cppduals/blob/master/LICENSE.txt for // license information. // // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // // (c)2019 Michael Tesch. tesch1@gmail.com // /** * \file test_eigen Dual number Eigen integration tests * * (c)2019 Michael Tesch. tesch1@gmail.com */ #include #include "type_name.hpp" #include #include #include #include //#include #include "eexpokit/padm.hpp" #include "gtest/gtest.h" using duals::rpart; using duals::dpart; using duals::dualf; using duals::duald; using duals::dualld; using duals::hyperdualf; using duals::hyperduald; using duals::hyperdualld; using duals::is_dual; using duals::is_complex; using duals::dual_traits; using namespace duals::literals; typedef long double ldouble; typedef std::complex complexf; typedef std::complex complexd; typedef std::complex complexld; typedef std::complex cdualf; typedef std::complex cduald; typedef std::complex cdualld; template using emtx = Eigen::Matrix; template using smtx = Eigen::SparseMatrix; template using ecf = Eigen::Matrix ; template using edf = Eigen::Matrix ; template using ecdf = Eigen::Matrix ; #define _EXPECT_TRUE(...) {typedef __VA_ARGS__ tru; EXPECT_TRUE(tru::value); static_assert(tru::value, "sa"); } #define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); } #define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B)) #define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B)) #define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B)) #define EXPECT_DNEAR(A,B,tol) \ EXPECT_NEAR(rpart(A), rpart(B),tol); \ EXPECT_NEAR(dpart(A), dpart(B),tol) TEST(Eigen, NumTraits) { //::testing::StaticAssertTypeEq>::Real, float>(); _EXPECT_TRUE(std::is_same>::Real, dualf>); _EXPECT_TRUE(std::is_same::Real, dualf>); EXPECT_EQ(Eigen::NumTraits>::dummy_precision(), Eigen::NumTraits::dummy_precision()); EXPECT_EQ(Eigen::NumTraits>::digits10(), Eigen::NumTraits::digits10()); EXPECT_EQ(Eigen::NumTraits::dummy_precision(), Eigen::NumTraits::dummy_precision()); } TEST(Eigen, construction) { emtx ed; emtx ef; emtx ecd; emtx ecf; emtx edd; emtx edf_; emtx ecdd; emtx ecdf_; } TEST(Eigen, sparse) { smtx ed; smtx ef; smtx ecd; smtx ecf; smtx edd; smtx edf_; smtx ecdd; smtx ecdf_; } TEST(Eigen, expr_type_dense) { emtx ed; emtx ef; emtx ecd; emtx ecf; emtx edd; emtx edf_; emtx ecdd; emtx ecdf_; //_EXPECT_TRUE(std::is_base_of,U >::value); //_EXPECT_TRUE(std::is_same,dualf>::type, emtx>); ecf = ecf * 1; #define PO_EXPR_TYPE(...) typename std::decay::type::PlainObject _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); //_EXPECT_TRUE(std::is_same>); [1] //_EXPECT_TRUE(std::is_same>); [1] _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); static_assert(!duals::can_promote>::value, "nope"); _EXPECT_TRUE(std::is_same>); //_EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); auto a1 = ecf * 1; auto a2 = ecf * ecf; //auto a3 = ecf * edf_; [1] //auto a4 = ecf * 1_ef; [1] auto a5 = ecf * cdualf(1,2); auto a6 = edf_ * 2; auto a7 = edf_ * 2_ef; auto a8 = ecf * complexf(1,2); auto a9 = ecdf_ * 1; ecdf_ = ecdf_ * complexf(1,2); ecdf_ = ecdf_ * cdualf(1_ef,2_ef); auto a12 = edd * 1_e; auto a13 = ed * 1; auto A1 = a1.eval(); A1 += A1; auto A2 = a2.eval(); A2 += A2; //auto A3 = a3.eval(); A3 += A3; [1] //auto A4 = a4.eval(); A4 += A4; [1] auto A5 = a5.eval(); A5 += A5; auto A6 = a6.eval(); A6 += A6; auto A7 = a7.eval(); A7 += A7; auto A8 = a8.eval(); A8 += A8; auto A9 = a9.eval(); A9 += A9; auto A12 = a12.eval(); A12 += A12; auto A13 = a13.eval(); A13 += A13; } TEST(init, Constant) { edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef); ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef)); EXPECT_EQ(a(1,1), 5 + 8_ef); EXPECT_EQ(b(0,1), cdualf(4,2 + 3_ef)); EXPECT_TRUE((a.array() < 6).all()); EXPECT_FALSE((a.array() != 5 + 8_ef).any()); EXPECT_EQ((a.array() == 5 + 8_ef).count(), 9); } TEST(init, setIdentity) { edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef); ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef)); a.setIdentity(); b.setIdentity(); EXPECT_EQ(a(0,0), 1); EXPECT_EQ(a(0,1), 0); EXPECT_EQ(a(0,2), 0); EXPECT_EQ(a(1,0), 0); EXPECT_EQ(a(1,1), 1); EXPECT_EQ(a(1,2), 0); EXPECT_EQ(a(2,0), 0); EXPECT_EQ(a(2,1), 0); EXPECT_EQ(a(2,2), 1); EXPECT_EQ(b(0,0).real(), 1); EXPECT_EQ(b(0,1).real(), 0); EXPECT_EQ(b(0,2).real(), 0); EXPECT_EQ(b(1,0).real(), 0); EXPECT_EQ(b(1,1).real(), 1); EXPECT_EQ(b(1,2).real(), 0); EXPECT_EQ(b(2,0).real(), 0); EXPECT_EQ(b(2,1).real(), 0); EXPECT_EQ(b(2,2).real(), 1); } TEST(init, setZero) { edf<3> a = edf<3>::Constant(3,3, 5 + 8_ef); ecdf<3> b = ecdf<3>::Constant(3,3, cdualf(4,2 + 3_ef)); EXPECT_EQ(a(1,1), 5 + 8_ef); a.setZero(); b.setZero(); EXPECT_EQ(a(0,0), 0); EXPECT_EQ(a(0,1), 0); EXPECT_EQ(a(0,2), 0); EXPECT_EQ(a(1,0), 0); EXPECT_EQ(a(1,1), 0); EXPECT_EQ(a(1,2), 0); EXPECT_EQ(a(2,0), 0); EXPECT_EQ(a(2,1), 0); EXPECT_EQ(a(2,2), 0); EXPECT_EQ(b(0,0).real(), 0); EXPECT_EQ(b(0,1).real(), 0); EXPECT_EQ(b(0,2).real(), 0); EXPECT_EQ(b(1,0).real(), 0); EXPECT_EQ(b(1,1).real(), 0); EXPECT_EQ(b(1,2).real(), 0); EXPECT_EQ(b(2,0).real(), 0); EXPECT_EQ(b(2,1).real(), 0); EXPECT_EQ(b(2,2).real(), 0); EXPECT_EQ(b(0,0).imag(), 0); EXPECT_EQ(b(0,1).imag(), 0); EXPECT_EQ(b(0,2).imag(), 0); EXPECT_EQ(b(1,0).imag(), 0); EXPECT_EQ(b(1,1).imag(), 0); EXPECT_EQ(b(1,2).imag(), 0); EXPECT_EQ(b(2,0).imag(), 0); EXPECT_EQ(b(2,1).imag(), 0); EXPECT_EQ(b(2,2).imag(), 0); } TEST(init, LinSpaced) { ecf<3,1> a = ecf<3,1>::LinSpaced(3, 4, complexf(6,7)); EXPECT_EQ(a(0).real(), 4); EXPECT_EQ(a(1).real(), 5); EXPECT_EQ(a(2).real(), 6); edf<3,1> b = edf<3,1>::LinSpaced(3, 4, 6 + 6_ef); EXPECT_EQ(b(0), 4); EXPECT_EQ(b(1), 5 + 3_ef); EXPECT_EQ(b(2), 6 + 6_ef); } TEST(init, Random) { complexf c = emtx::Random()(0,0); EXPECT_NE(c.real(), 0); EXPECT_NE(c.imag(), 0); typedef dualf Rt; using duals::random; Rt b = emtx::Random()(0,0); EXPECT_NE(b.rpart(), 0); //EXPECT_NE(b.dpart(), 0); // edf<3> j = edf<3>::Random(3,3); EXPECT_NE(j(1,2).rpart(), 0); //EXPECT_NE(j(2,0).dpart(), 0); // ecdf<3> k = ecdf<3>::Random(3,3); EXPECT_NE(k(0,1).real().rpart(), 0); //EXPECT_NE(k(1,1).imag().dpart(), 0); // using duals::randos::random2; dualf x = random2(); EXPECT_NE(x.rpart(), 0); EXPECT_NE(x.dpart(), 0); duald y = random2(); EXPECT_NE(y.rpart(), 0); EXPECT_NE(y.dpart(), 0); //EXPECT_NE(k(1,1).imag().dpart(), 0); // } TEST(assign, ops) { emtx ed; emtx ef; emtx ecd; emtx ecf; emtx edd; emtx edf_; emtx ecdd; emtx ecdf_; ed *= 2; ef *= 2; //ecd *= 2; //ecf *= 2; //ecd *= 2_e; //ecf *= 2_ef; edd *= 2; edf_ *= 2; edd *= 2_e; edf_ *= 2_ef; //ecdd *= 2; // ecdf_ *= 2; } TEST(Array, math) { int N = 5; emtx x(N,1); emtx y(N,1); emtx z(N,1); x.array() += 1; x += y + z; x *= 2; emtx a(N,1); emtx A(N,1); emtx c(N,1); a.array() = 1 + 1_e; a.array() += 3_e; a.array() = 0; a.array() += 1; A.array() += 2; c = a + A; c = a * 2; c = a * 2_e; c = 2 * a; c = (3 + 2_e) * a; c *= 3; c *= 3_e; EXPECT_EQ(c(N-1), 27_e); } TEST(access, CwiseRpartOp) { // on float matrices (pass-through) emtx a, b = emtx::Random(); a = b.unaryExpr(duals::CwiseRpartOp()); EXPECT_NE(a.norm(), 0); // on dual matrices emtx d; a = d.unaryExpr(duals::CwiseRpartOp()); a = d.unaryExpr(duals::CwiseDpartOp()); a = rpart(d); a = dpart(d); // on complex> matrices emtx g, f = emtx::Random(); emtx e; e.array() = f.array().cast() - 1_ef * f.array().cast(); g = e.unaryExpr(duals::CwiseRpartOp()); EXPECT_EQ((f-g).norm(), 0); g = f.unaryExpr(duals::CwiseRpartOp()); EXPECT_EQ((f-g).norm(), 0); g = rpart(f); EXPECT_EQ((f-g).norm(), 0); g = e.unaryExpr(duals::CwiseDpartOp()); EXPECT_EQ((f+g).norm(), 0); g = f.unaryExpr(duals::CwiseDpartOp()); EXPECT_EQ((g).norm(), 0); g = dpart(f); EXPECT_EQ((g).norm(), 0); } TEST(access, CwiseDpartOp) { // on float matrices (pass-through) emtx a, b = emtx::Random(); a = b.unaryExpr(duals::CwiseDpartOp()); EXPECT_EQ(a.norm(), 0); // on dual matrices emtx d = b - 1_ef * b; a = d.unaryExpr(duals::CwiseDpartOp()); EXPECT_NE(a.norm(), 0); EXPECT_EQ((a+b).norm(), 0); // on complex> matrices emtx g, f = emtx::Random(); emtx e; e.array() = f.array().cast() - 1_ef * f.array().cast(); g = e.unaryExpr(duals::CwiseDpartOp()); EXPECT_EQ((g+f).norm(), 0); d = e.real(); EXPECT_NE(d.norm(), 0); } TEST(measure, norm) { typedef emtx MatrixC; MatrixC c = (MatrixC() << 1,2,3, 4,5,6, 7,8,9).finished(); EXPECT_EQ(c.cwiseAbs().colwise().sum().maxCoeff(), complexf(18)); //EXPECT_EQ(c.maxCoeff(), complexf(9)); //typedef duald Rt; typedef dualf Rt; //typedef cdualf Rt; typedef emtx MatrixD; Rt b = 1+0_ef; b = 3; Rt d(1); MatrixD x; x.array() = d; MatrixD a = (MatrixD() << 1,2,3, 4,5+5_ef,6, 7,8,9).finished(); //typename MatrixD::Index index; EXPECT_EQ(a.sum(), 45 + 5_ef); EXPECT_EQ(x.sum(), 9); EXPECT_NEAR(rpart(a.norm()), 16.8819430161341337282, 1e-5); EXPECT_NEAR(rpart(a.mean()), 5, 1e-5); EXPECT_NEAR(dpart(a.mean()), 0.555555555555555, 1e-5); EXPECT_EQ(a.minCoeff(), 1); EXPECT_EQ(a.maxCoeff(), 9); EXPECT_EQ(a.trace(), 15 + 5_ef); EXPECT_EQ(a.squaredNorm(), 285+0_e); EXPECT_EQ(a.lpNorm<1>(), 45 + 5_ef); //EXPECT_EQ(a.lpNorm(), 9); // 1-norm //EXPECT_EQ(a.colwise().lpNorm<1>().maxCoeff(), 45 + 5_ef); EXPECT_EQ(a.cwiseAbs().colwise().sum().maxCoeff(), 18); } TEST(dual_decay, stat) { emtx ef; emtx ecd; emtx ecf; emtx edd; emtx edf_; emtx ecdd; emtx ecdf_; _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); _EXPECT_TRUE(std::is_same>); } TEST(dpart, matrix) { emtx a = emtx::Random(3,3); emtx b = emtx::Random(3,3); emtx c = emtx::Random(3,3); emtx d = emtx::Random(3,3); emtx A = a + 1_ef * b; emtx B = c + 1_ef * d; emtx AA; emtx BB,CC; AA.real() = A; AA.imag() = B; BB.real() = a; BB.imag() = c; CC.real() = b; CC.imag() = d; EXPECT_EQ((rpart(A) - a).norm(),0); EXPECT_EQ((dpart(A) - b).norm(),0); EXPECT_EQ((rpart(AA) - BB).norm(),0); EXPECT_EQ((dpart(AA) - CC).norm(),0); } TEST(eigen, exp_typechecks) { typedef emtx Mat; typedef emtx Matd; EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); typedef emtx Matc; typedef emtx Matcd; EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); EXPECT_FALSE(Eigen::internal::is_exp_known_type::value); } const bool _exp = true; const bool _padm = false; #define TEST_EXP(SCALAR_T, SIDE, EXP_OR_PADM) \ TEST(func, exp_##SCALAR_T##_##SIDE##EXP_OR_PADM) { \ emtx a,b; \ a = emtx::Random(); \ a.setZero(); \ if (EXP_OR_PADM == _exp) a = a.exp(); \ else a = eexpokit::padm(a); \ EXPECT_LT((a - emtx::Identity()).norm(), 1e-6) << "a=" << a << "\n"; \ } #define TEST_EXP_SIZES(SCALAR_T, EXP_OR_PADM) \ TEST_EXP(SCALAR_T, 3, EXP_OR_PADM) \ TEST_EXP(SCALAR_T, 4, EXP_OR_PADM) \ TEST_EXP(SCALAR_T, 17, EXP_OR_PADM) #define TEST_EXP_SIZES_EOP(SCALAR_T) \ TEST_EXP_SIZES(SCALAR_T, _padm) \ TEST_EXP_SIZES(SCALAR_T, _exp) // just make sure padm is working TEST_EXP_SIZES_EOP(float) TEST_EXP_SIZES_EOP(double) TEST_EXP_SIZES_EOP(ldouble) TEST_EXP_SIZES_EOP(complexf) TEST_EXP_SIZES_EOP(complexd) TEST_EXP_SIZES_EOP(complexld) /* testing engine */ #define QUOTE(...) STRFY(__VA_ARGS__) #define STRFY(...) #__VA_ARGS__ int main(int argc, char **argv) { std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n"; std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n"; ::testing::InitGoogleTest(&argc, argv); std::cout.precision(20); std::cerr.precision(20); return RUN_ALL_TESTS(); }