123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- namespace Eigen {
- /** \page TopicNewExpressionType Adding a new expression type
- <!--<span style="font-size:130%; color:red; font-weight: 900;"></span>-->
- \warning
- Disclaimer: this page is tailored to very advanced users who are not afraid of dealing with some %Eigen's internal aspects.
- In most cases, a custom expression can be avoided by either using custom \ref MatrixBase::unaryExpr "unary" or \ref MatrixBase::binaryExpr "binary" functors,
- while extremely complex matrix manipulations can be achieved by a nullary functors as described in the \ref TopicCustomizing_NullaryExpr "previous page".
- 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:
- \include make_circulant.out
- */
- }
|