147 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
/*
 | 
						|
 * Tensor1Expression.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 <math.h>
 | 
						|
#include <iostream>
 | 
						|
#include <stdexcept>
 | 
						|
#include "tensors.h"
 | 
						|
 | 
						|
namespace tensors {
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Templated class to provide a rank 1 tensor interface to a class.
 | 
						|
	 * This class does not store any data but the result of an expression.
 | 
						|
	 * It is associated with an index.
 | 
						|
	 */
 | 
						|
	template<class A, class I> class Tensor1Expression {
 | 
						|
 | 
						|
	private:
 | 
						|
 | 
						|
		A iter;
 | 
						|
 | 
						|
		typedef Tensor1Expression<A, I> This;
 | 
						|
 | 
						|
		/** 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) const {
 | 
						|
				return iter(i) * s;
 | 
						|
			}
 | 
						|
		};
 | 
						|
 | 
						|
	public:
 | 
						|
 | 
						|
		/** constructor */
 | 
						|
		Tensor1Expression(const A &a) :
 | 
						|
			iter(a) {
 | 
						|
		}
 | 
						|
 | 
						|
		/** Print */
 | 
						|
		void print(const std::string s = "") const {
 | 
						|
			std::cout << s << "{";
 | 
						|
			std::cout << (*this)(0);
 | 
						|
			for (int i = 1; i < I::dim; i++)
 | 
						|
				std::cout << ", "<< (*this)(i);
 | 
						|
			std::cout << "}" << std::endl;
 | 
						|
		}
 | 
						|
 | 
						|
		template<class B>
 | 
						|
		bool equals(const Tensor1Expression<B, I> & q, double tol) const {
 | 
						|
			for (int i = 0; i < I::dim; i++)
 | 
						|
				if (fabs((*this)(i) - q(i)) > tol) return false;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		/** norm */
 | 
						|
		double norm() const {
 | 
						|
			double sumsqr = 0.0;
 | 
						|
			for (int i = 0; i < I::dim; i++)
 | 
						|
				sumsqr += iter(i) * iter(i);
 | 
						|
			return sqrt(sumsqr);
 | 
						|
		}
 | 
						|
 | 
						|
		template<class B>
 | 
						|
		bool equivalent(const Tensor1Expression<B, I> & q, double tol = 1e-9) const {
 | 
						|
			return ((*this) * (1.0 / norm())).equals(q * (1.0 / q.norm()), tol);
 | 
						|
		}
 | 
						|
 | 
						|
		/** Check if two expressions are equal */
 | 
						|
		template<class B>
 | 
						|
		bool operator==(const Tensor1Expression<B, I>& e) const {
 | 
						|
			for (int i = 0; i < I::dim; i++)
 | 
						|
				if (iter(i) != e(i)) return false;
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
 | 
						|
		/** element access */
 | 
						|
		double operator()(int i) const {
 | 
						|
			return iter(i);
 | 
						|
		}
 | 
						|
 | 
						|
		/** mutliply with a double. */
 | 
						|
		inline Tensor1Expression<TimesDouble_, I> operator*(double s) const {
 | 
						|
			return TimesDouble_(iter, s);
 | 
						|
		}
 | 
						|
 | 
						|
		/** Class for contracting two rank 1 tensor expressions, yielding a double. */
 | 
						|
		template<class B>
 | 
						|
		inline double operator*(const Tensor1Expression<B, I> &b) const {
 | 
						|
			double sum = 0.0;
 | 
						|
			for (int i = 0; i < I::dim; i++)
 | 
						|
				sum += (*this)(i) * b(i);
 | 
						|
			return sum;
 | 
						|
		}
 | 
						|
 | 
						|
	}; // Tensor1Expression
 | 
						|
 | 
						|
	/** Print a rank 1 expression */
 | 
						|
	template<class A, class I>
 | 
						|
	void print(const Tensor1Expression<A, I>& T, const std::string s = "") {
 | 
						|
		T.print(s);
 | 
						|
	}
 | 
						|
 | 
						|
	/** norm */
 | 
						|
	template<class A, class I>
 | 
						|
	double norm(const Tensor1Expression<A, I>& T) {
 | 
						|
		return T.norm();
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * This template works for any two expressions
 | 
						|
	 */
 | 
						|
	template<class A, class B, class I>
 | 
						|
	bool assert_equality(const Tensor1Expression<A, I>& expected,
 | 
						|
			const Tensor1Expression<B, I>& 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<class A, class B, class I>
 | 
						|
	bool assert_equivalent(const Tensor1Expression<A, I>& expected,
 | 
						|
			const Tensor1Expression<B, I>& 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
 |