New doc page on implementing a new expression class.
This commit is contained in:
		
							parent
							
								
									6d0f0b8cec
								
							
						
					
					
						commit
						ce2035af86
					
				| @ -13,6 +13,7 @@ namespace Eigen { | ||||
|   - \subpage TopicUsingIntelMKL | ||||
|   - \subpage TopicCUDA | ||||
|   - \subpage TopicTemplateKeyword | ||||
|   - \subpage TopicNewExpressionType | ||||
|   - \subpage UserManual_UnderstandingEigen | ||||
| */ | ||||
|    | ||||
|  | ||||
							
								
								
									
										137
									
								
								doc/NewExpressionType.dox
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								doc/NewExpressionType.dox
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,137 @@ | ||||
| namespace Eigen { | ||||
| 
 | ||||
| /** \page TopicNewExpressionType Adding a new expression type | ||||
| 
 | ||||
| This page describes with the help of an example how to implement a new | ||||
| light-weight expression type in %Eigen. This consists of three parts: | ||||
| the expression type itself, a traits class containing compile-time | ||||
| information about the expression, and the evaluator class which is | ||||
| used to evaluate the expression to a matrix. | ||||
| 
 | ||||
| \b TO \b DO: Write a page explaining the design, with details on | ||||
| vectorization etc., and refer to that page here. | ||||
| 
 | ||||
| 
 | ||||
| \eigenAutoToc | ||||
| 
 | ||||
| \section TopicSetting The setting | ||||
| 
 | ||||
| A circulant matrix is a matrix where each column is the same as the | ||||
| column to the left, except that it is cyclically shifted downwards. | ||||
| For example, here is a 4-by-4 circulant matrix: | ||||
| \f[ \begin{bmatrix}  | ||||
|     1 & 8 & 4 & 2 \\  | ||||
|     2 & 1 & 8 & 4 \\ | ||||
|     4 & 2 & 1 & 8 \\ | ||||
|     8 & 4 & 2 & 1 | ||||
| \end{bmatrix} \f] | ||||
| A circulant matrix is uniquely determined by its first column. We wish | ||||
| to write a function \c makeCirculant which, given the first column, | ||||
| returns an expression representing the circulant matrix. | ||||
| 
 | ||||
| For simplicity, we restrict the \c makeCirculant function to dense | ||||
| matrices. It may make sense to also allow arrays, or sparse matrices, | ||||
| but we will not do so here. We also do not want to support | ||||
| vectorization. | ||||
| 
 | ||||
| 
 | ||||
| \section TopicPreamble Getting started | ||||
| 
 | ||||
| We will present the file implementing the \c makeCirculant function | ||||
| part by part. We start by including the appropriate header files and | ||||
| forward declaring the expression class, which we will call | ||||
| \c Circulant. The \c makeCirculant function will return an object of | ||||
| this type. The class \c Circulant is in fact a class template; the | ||||
| template argument \c ArgType refers to the type of the vector passed | ||||
| to the \c makeCirculant function. | ||||
| 
 | ||||
| \include make_circulant.cpp.preamble | ||||
| 
 | ||||
| 
 | ||||
| \section TopicTraits The traits class | ||||
| 
 | ||||
| For every expression class \c X, there should be a traits class  | ||||
| \c Traits<X> in the \c Eigen::internal namespace containing | ||||
| information about \c X known as compile time. | ||||
| 
 | ||||
| As explained in \ref TopicSetting, we designed the \c Circulant | ||||
| expression class to refer to dense matrices. The entries of the | ||||
| circulant matrix have the same type as the entries of the vector | ||||
| passed to the \c makeCirculant function. The type used to index the | ||||
| entries is also the same. Again for simplicity, we will only return | ||||
| column-major matrices. Finally, the circulant matrix is a square | ||||
| matrix (number of rows equals number of columns), and the number of | ||||
| rows equals the number of rows of the column vector passed to the | ||||
| \c makeCirculant function. If this is a dynamic-size vector, then the | ||||
| size of the circulant matrix is not known at compile-time. | ||||
| 
 | ||||
| This leads to the following code: | ||||
| 
 | ||||
| \include make_circulant.cpp.traits | ||||
| 
 | ||||
| 
 | ||||
| \section TopicExpression The expression class | ||||
| 
 | ||||
| The next step is to define the expression class itself. In our case, | ||||
| we want to inherit from \c MatrixBase in order to expose the interface | ||||
| for dense matrices. In the constructor, we check that we are passed a | ||||
| column vector (see \ref TopicAssertions) and we store the vector from | ||||
| which we are going to build the circulant matrix in the member | ||||
| variable \c m_arg. Finally, the expression class should compute the | ||||
| size of the corresponding circulant matrix. As explained above, this | ||||
| is a square matrix with as many columns as the vector used to | ||||
| construct the matrix. | ||||
| 
 | ||||
| \b TO \b DO: What about the \c Nested typedef? It seems to be | ||||
| necessary; is this only temporary? | ||||
| 
 | ||||
| \include make_circulant.cpp.expression | ||||
| 
 | ||||
| 
 | ||||
| \section TopicEvaluator The evaluator | ||||
| 
 | ||||
| The last big fragment implements the evaluator for the \c Circulant | ||||
| expression. The evaluator computes the entries of the circulant | ||||
| matrix; this is done in the \c .coeff() member function. The entries | ||||
| are computed by finding the corresponding entry of the vector from | ||||
| which the circulant matrix is constructed. Getting this entry may | ||||
| actually be non-trivial when the circulant matrix is constructed from | ||||
| a vector which is given by a complicated expression, so we use the | ||||
| evaluator which corresponds to the vector. | ||||
| 
 | ||||
| The \c CoeffReadCost constant records the cost of computing an entry | ||||
| of the circulant matrix; we ignore the index computation and say that | ||||
| this is the same as the cost of computing an entry of the vector from | ||||
| which the circulant matrix is constructed. | ||||
| 
 | ||||
| In the constructor, we save the evaluator for the column vector which | ||||
| defined the circulant matrix. We also save the size of that vector; | ||||
| remember that we can query an expression object to find the size but | ||||
| not the evaluator.  | ||||
| 
 | ||||
| \include make_circulant.cpp.evaluator | ||||
| 
 | ||||
| 
 | ||||
| \section TopicEntry The entry point | ||||
| 
 | ||||
| After all this, the \c makeCirculant function is very simple. It | ||||
| simply creates an expression object and returns it. | ||||
| 
 | ||||
| \include make_circulant.cpp.entry | ||||
| 
 | ||||
| 
 | ||||
| \section TopicMain A simple main function for testing | ||||
| 
 | ||||
| Finally, a short \c main function that shows how the \c makeCirculant | ||||
| function can be called. | ||||
| 
 | ||||
| \include make_circulant.cpp.main | ||||
| 
 | ||||
| If all the fragments are combined, the following output is produced, | ||||
| showing that the program works as expected: | ||||
| 
 | ||||
| \verbinclude make_circulant.out | ||||
| 
 | ||||
| */ | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										11
									
								
								doc/examples/make_circulant.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								doc/examples/make_circulant.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| /*
 | ||||
| This program is presented in several fragments in the doc page. | ||||
| Every fragment is in its own file; this file simply combines them. | ||||
| */ | ||||
| 
 | ||||
| #include "make_circulant.cpp.preamble" | ||||
| #include "make_circulant.cpp.traits" | ||||
| #include "make_circulant.cpp.expression" | ||||
| #include "make_circulant.cpp.evaluator" | ||||
| #include "make_circulant.cpp.entry" | ||||
| #include "make_circulant.cpp.main" | ||||
							
								
								
									
										5
									
								
								doc/examples/make_circulant.cpp.entry
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								doc/examples/make_circulant.cpp.entry
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| template <class ArgType> | ||||
| Circulant<ArgType> makeCirculant(const Eigen::MatrixBase<ArgType>& arg) | ||||
| { | ||||
|   return Circulant<ArgType>(arg.derived()); | ||||
| } | ||||
							
								
								
									
										33
									
								
								doc/examples/make_circulant.cpp.evaluator
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								doc/examples/make_circulant.cpp.evaluator
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| namespace Eigen { | ||||
|   namespace internal { | ||||
|     template<typename ArgType> | ||||
|     struct evaluator<Circulant<ArgType> > | ||||
|       : evaluator_base<Circulant<ArgType> > | ||||
|     { | ||||
|       typedef Circulant<ArgType> XprType; | ||||
|       typedef typename nested_eval<ArgType, XprType::ColsAtCompileTime>::type ArgTypeNested; | ||||
|       typedef typename remove_all<ArgTypeNested>::type ArgTypeNestedCleaned; | ||||
|       typedef typename XprType::CoeffReturnType CoeffReturnType; | ||||
|       typedef typename XprType::Index Index; | ||||
| 
 | ||||
|       enum {  | ||||
|         CoeffReadCost = evaluator<ArgTypeNestedCleaned>::CoeffReadCost, | ||||
|         Flags = Eigen::ColMajor  | ||||
|       }; | ||||
|        | ||||
|       evaluator(const XprType& xpr) | ||||
|         : m_argImpl(xpr.m_arg), m_rows(xpr.rows()) | ||||
|       { } | ||||
| 
 | ||||
|       CoeffReturnType coeff(Index row, Index col) const | ||||
|       { | ||||
|         Index index = row - col; | ||||
|         if (index < 0) index += m_rows; | ||||
|         return m_argImpl.coeff(index); | ||||
|       } | ||||
| 
 | ||||
|       typename evaluator<ArgTypeNestedCleaned>::nestedType m_argImpl; | ||||
|       const Index m_rows; | ||||
|     }; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										20
									
								
								doc/examples/make_circulant.cpp.expression
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								doc/examples/make_circulant.cpp.expression
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| template <class ArgType> | ||||
| class Circulant : public Eigen::MatrixBase<Circulant<ArgType> > | ||||
| { | ||||
| public: | ||||
|   Circulant(const ArgType& arg) | ||||
|     : m_arg(arg) | ||||
|   {  | ||||
|     EIGEN_STATIC_ASSERT(ArgType::ColsAtCompileTime == 1, | ||||
|                         YOU_TRIED_CALLING_A_VECTOR_METHOD_ON_A_MATRIX); | ||||
|   } | ||||
| 
 | ||||
|   typedef typename Eigen::internal::ref_selector<Circulant>::type Nested;  | ||||
| 
 | ||||
|   typedef typename Eigen::internal::traits<Circulant>::Index Index; | ||||
|   Index rows() const { return m_arg.rows(); } | ||||
|   Index cols() const { return m_arg.rows(); } | ||||
| 
 | ||||
|   typedef typename Eigen::internal::ref_selector<ArgType>::type ArgTypeNested; | ||||
|   ArgTypeNested m_arg; | ||||
| }; | ||||
							
								
								
									
										8
									
								
								doc/examples/make_circulant.cpp.main
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								doc/examples/make_circulant.cpp.main
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| int main() | ||||
| { | ||||
|   Eigen::VectorXd vec(4); | ||||
|   vec << 1, 2, 4, 8; | ||||
|   Eigen::MatrixXd mat; | ||||
|   mat = makeCirculant(vec); | ||||
|   std::cout << mat << std::endl; | ||||
| } | ||||
							
								
								
									
										4
									
								
								doc/examples/make_circulant.cpp.preamble
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								doc/examples/make_circulant.cpp.preamble
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| #include <Eigen/Core> | ||||
| #include <iostream> | ||||
| 
 | ||||
| template <class ArgType> class Circulant; | ||||
							
								
								
									
										19
									
								
								doc/examples/make_circulant.cpp.traits
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								doc/examples/make_circulant.cpp.traits
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| namespace Eigen { | ||||
|   namespace internal { | ||||
|     template <class ArgType> | ||||
|     struct traits<Circulant<ArgType> >  | ||||
|     { | ||||
|       typedef Eigen::Dense StorageKind; | ||||
|       typedef Eigen::MatrixXpr XprKind; | ||||
|       typedef typename ArgType::Index Index; | ||||
|       typedef typename ArgType::Scalar Scalar; | ||||
|       enum {  | ||||
|         Flags = Eigen::ColMajor, | ||||
|         RowsAtCompileTime = ArgType::RowsAtCompileTime, | ||||
|         ColsAtCompileTime = ArgType::RowsAtCompileTime, | ||||
|         MaxRowsAtCompileTime = ArgType::MaxRowsAtCompileTime, | ||||
|         MaxColsAtCompileTime = ArgType::MaxRowsAtCompileTime | ||||
|       }; | ||||
|     }; | ||||
|   } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Jitse Niesen
						Jitse Niesen