/* * Tensor2Expression.h * @brief Tensor expression templates based on http://www.gps.caltech.edu/~walter/FTensor/FTensor.pdf * Created on: Feb 10, 2010 * @author: Frank Dellaert */ #pragma once #include #include #include namespace tensors { /** Templated class to hold a rank 2 tensor expression. */ template class Tensor2Expression { private: A iter; typedef Tensor2Expression This; /** Helper class for instantiating one index */ class FixJ_ { const int j; const A iter; public: FixJ_(int j_, const A &a) : j(j_), iter(a) { } double operator()(int i) const { return iter(i, j); } }; /** Helper class for swapping indices */ class Swap_ { const A iter; public: Swap_(const A &a) : iter(a) { } double operator()(int j, int i) const { return iter(i, j); } }; /** Helper class for multiplying with a double */ class TimesDouble_ { A iter; const double s; public: TimesDouble_(const A &a, double s_) : iter(a), s(s_) { } inline double operator()(int i, int j) const { return iter(i, j) * s; } }; /** Helper class for contracting index I with rank 1 tensor */ template class ITimesRank1_ { const This a; const Tensor1Expression b; public: ITimesRank1_(const This &a_, const Tensor1Expression &b_) : a(a_), b(b_) { } double operator()(int j) const { double sum = 0.0; for (int i = 0; i < I::dim; i++) sum += a(i, j) * b(i); return sum; } }; /** Helper class for contracting index J with rank 1 tensor */ template class JTimesRank1_ { const This a; const Tensor1Expression b; public: JTimesRank1_(const This &a_, const Tensor1Expression &b_) : a(a_), b(b_) { } double operator()(int i) const { double sum = 0.0; for (int j = 0; j < J::dim; j++) sum += a(i, j) * b(j); return sum; } }; /** Helper class for contracting index I with rank 2 tensor */ template class ITimesRank2_ { const This a; const Tensor2Expression b; public: ITimesRank2_(const This &a_, const Tensor2Expression &b_) : a(a_), b(b_) { } double operator()(int j, int k) const { double sum = 0.0; for (int i = 0; i < I::dim; i++) sum += a(i, j) * b(i, k); return sum; } }; public: /** constructor */ Tensor2Expression(const A &a) : iter(a) { } /** Print */ void print(const std::string& s = "Tensor2:") const { std::cout << s << "{"; (*this)(0).print(); for (int j = 1; j < J::dim; j++) { std::cout << ","; (*this)(j).print(""); } std::cout << "}" << std::endl; } template bool equals(const Tensor2Expression & q, double tol) const { for (int j = 0; j < J::dim; j++) if (!(*this)(j).equals(q(j), tol)) return false; return true; } // TODO: broken !!!! Should not treat Tensor1's separately: one scale only! template bool equivalent(const Tensor2Expression & q, double tol) const { for (int j = 0; j < J::dim; j++) if (!(*this)(j).equivalent(q(j), tol)) return false; return true; } /** element access */ double operator()(int i, int j) const { return iter(i, j); } /** swap indices */ typedef Tensor2Expression Swapped; Swapped swap() { return Swap_(iter); } /** mutliply with a double. */ inline Tensor2Expression operator*(double s) const { return TimesDouble_(iter, s); } /** Fix a single index */ Tensor1Expression operator()(int j) const { return FixJ_(j, iter); } /** Check if two expressions are equal */ template bool operator==(const Tensor2Expression& T) const { for (int i = 0; i < I::dim; i++) for (int j = 0; j < J::dim; j++) if (iter(i, j) != T(i, j)) return false; return true; } /** c(j) = a(i,j)*b(i) */ template inline Tensor1Expression , J> operator*( const Tensor1Expression& p) { return ITimesRank1_ (*this, p); } /** c(i) = a(i,j)*b(j) */ template inline Tensor1Expression , I> operator*( const Tensor1Expression &p) { return JTimesRank1_ (*this, p); } /** c(j,k) = a(i,j)*T(i,k) */ template inline Tensor2Expression , J, K> operator*( const Tensor2Expression& p) { return ITimesRank2_ (*this, p); } }; // Tensor2Expression /** Print */ template void print(const Tensor2Expression& T, const std::string& s = "Tensor2:") { T.print(s); } /** Helper class for multiplying two covariant tensors */ template class Rank1Rank1_ { const Tensor1Expression iterA; const Tensor1Expression iterB; public: Rank1Rank1_(const Tensor1Expression &a, const Tensor1Expression &b) : iterA(a), iterB(b) { } double operator()(int i, int j) const { return iterA(i) * iterB(j); } }; /** Multiplying two different indices yields an outer product */ template inline Tensor2Expression , I, J> operator*( const Tensor1Expression &a, const Tensor1Expression &b) { return Rank1Rank1_ (a, b); } /** * This template works for any two expressions */ template bool assert_equality(const Tensor2Expression& expected, const Tensor2Expression& actual, double tol = 1e-9) { if (actual.equals(expected, tol)) return true; std::cout << "Not equal:\n"; expected.print("expected:\n"); actual.print("actual:\n"); return false; } /** * This template works for any two expressions */ template bool assert_equivalent(const Tensor2Expression& expected, const Tensor2Expression& actual, double tol = 1e-9) { if (actual.equivalent(expected, tol)) return true; std::cout << "Not equal:\n"; expected.print("expected:\n"); actual.print("actual:\n"); return false; } } // namespace tensors