Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 1 | namespace Eigen { |
| 2 | |
| 3 | /** \page TopicCustomizing_NullaryExpr Matrix manipulation via nullary-expressions |
| 4 | |
| 5 | |
| 6 | The main purpose of the class CwiseNullaryOp is to define \em procedural matrices such as constant or random matrices as returned by the Ones(), Zero(), Constant(), Identity() and Random() methods. |
| 7 | Nevertheless, with some imagination it is possible to accomplish very sophisticated matrix manipulation with minimal efforts such that \ref TopicNewExpressionType "implementing new expression" is rarely needed. |
| 8 | |
| 9 | \section NullaryExpr_Circulant Example 1: circulant matrix |
| 10 | |
| 11 | To explore these possibilities let us start with the \em circulant example of the \ref TopicNewExpressionType "implementing new expression" topic. |
| 12 | Let us recall that a circulant matrix is a matrix where each column is the same as the |
| 13 | column to the left, except that it is cyclically shifted downwards. |
| 14 | For example, here is a 4-by-4 circulant matrix: |
| 15 | \f[ \begin{bmatrix} |
| 16 | 1 & 8 & 4 & 2 \\ |
| 17 | 2 & 1 & 8 & 4 \\ |
| 18 | 4 & 2 & 1 & 8 \\ |
| 19 | 8 & 4 & 2 & 1 |
| 20 | \end{bmatrix} \f] |
| 21 | A circulant matrix is uniquely determined by its first column. We wish |
| 22 | to write a function \c makeCirculant which, given the first column, |
| 23 | returns an expression representing the circulant matrix. |
| 24 | |
| 25 | For this exercise, the return type of \c makeCirculant will be a CwiseNullaryOp that we need to instantiate with: |
| 26 | 1 - a proper \c circulant_functor storing the input vector and implementing the adequate coefficient accessor \c operator(i,j) |
| 27 | 2 - a template instantiation of class Matrix conveying compile-time information such as the scalar type, sizes, and preferred storage layout. |
| 28 | |
| 29 | Calling \c ArgType the type of the input vector, we can construct the equivalent squared Matrix type as follows: |
| 30 | |
| 31 | \snippet make_circulant2.cpp square |
| 32 | |
| 33 | This little helper structure will help us to implement our \c makeCirculant function as follows: |
| 34 | |
| 35 | \snippet make_circulant2.cpp makeCirculant |
| 36 | |
| 37 | As usual, our function takes as argument a \c MatrixBase (see this \ref TopicFunctionTakingEigenTypes "page" for more details). |
| 38 | Then, the CwiseNullaryOp object is constructed through the DenseBase::NullaryExpr static method with the adequate runtime sizes. |
| 39 | |
| 40 | Then, we need to implement our \c circulant_functor, which is a straightforward exercise: |
| 41 | |
| 42 | \snippet make_circulant2.cpp circulant_func |
| 43 | |
| 44 | We are now all set to try our new feature: |
| 45 | |
| 46 | \snippet make_circulant2.cpp main |
| 47 | |
| 48 | |
| 49 | If all the fragments are combined, the following output is produced, |
| 50 | showing that the program works as expected: |
| 51 | |
| 52 | \include make_circulant2.out |
| 53 | |
| 54 | This implementation of \c makeCirculant is much simpler than \ref TopicNewExpressionType "defining a new expression" from scratch. |
| 55 | |
| 56 | |
| 57 | \section NullaryExpr_Indexing Example 2: indexing rows and columns |
| 58 | |
| 59 | The goal here is to mimic MatLab's ability to index a matrix through two vectors of indices referencing the rows and columns to be picked respectively, like this: |
| 60 | |
| 61 | \snippet nullary_indexing.out main1 |
| 62 | |
| 63 | To this end, let us first write a nullary-functor storing references to the input matrix and to the two arrays of indices, and implementing the required \c operator()(i,j): |
| 64 | |
| 65 | \snippet nullary_indexing.cpp functor |
| 66 | |
| 67 | Then, let's create an \c indexing(A,rows,cols) function creating the nullary expression: |
| 68 | |
| 69 | \snippet nullary_indexing.cpp function |
| 70 | |
| 71 | Finally, here is an example of how this function can be used: |
| 72 | |
| 73 | \snippet nullary_indexing.cpp main1 |
| 74 | |
| 75 | This straightforward implementation is already quite powerful as the row or column index arrays can also be expressions to perform offsetting, modulo, striding, reverse, etc. |
| 76 | |
| 77 | \snippet nullary_indexing.cpp main2 |
| 78 | |
| 79 | and the output is: |
| 80 | |
| 81 | \snippet nullary_indexing.out main2 |
| 82 | |
| 83 | */ |
| 84 | |
| 85 | } |
| 86 | |