I'd like to suggest a new matrix type derived from MatrixBase with roughly the following constructor and behavior: /** * CalcMatrix is a read-only matrix without storage recalculating the * coefficients in each coeff() call by calling the user function func lazily. * * func may be a function pointer, an object with overloaded operator() or * one of C++0x's lambda functions, std::function. * * coeff(i, j) is calculated as * func(rowOffset + i * rowStride, colOffset + j * colStride) * * This is for matrices where the repeated recalculation of the coefficients * is less costly than creating and accessing the storage only a small but * part of the coefficients is actually accessed (which part is only known at * runtime). * * The common views of CalcMatrix are easily implemented: * (Nontrivial rowStride and colStride settings are propagated to the * views. m_... is the member corresponding to the constructor parameter.) * * - row(i) = CalcMatrix(1, cols(), m_func, i, 0, m_rowStride) * * - col(j) = CalcMatrix(rows(), 1, m_func, 0, j, 1, m_colStride) * * - diagonal() = CalcMatrix(rows(), 1, m_func, 0, 0, * cols() * m_colStride + m_rowStride) * * - block(i, j, rows, cols) = CalcMatrix(rows, cols, m_func, i, j, * m_rowStride, m_colStride) * * * Applications: * * - iota(n) = CalcMatrix(n, [](Index i) { return i; }) * * - Permuted-rows view of another matrix A or a selection of a subset of rows * of A in any order: * * permute_rows(A, perm) = * CalcMatrix(perm.size(), A.cols(), * [&](Index i, Index j) { return A(perm(i), j); } * * - access to non-contiguous matrix layouts of external libraries. * * - Kronecker delta: probably better accomplished with * VectorXd::Ones(rows).asDiagonal() */ template <typename Functype> CalcMatrix(Index rows, Index cols, Functype& func, Index rowOffset, Index colOffset, Index rowStride = 1, Index colStride = 1); As an optimization, rowStride and colStride (and rowOffset, colOffset) could also be offered as compile-time parameters in order to make func(rowOffset + i * rowStride, colOffset + j * colStride) less costly. A similar subclass for ArrayBase would have to be added in order to be able to call array() without significant overhead.
Sorry for the typos: * This is for matrices where the repeated recalculation of the coefficients * is less costly than creating and accessing the storage * or only a small part of the coefficients is actually accessed. * (Which part is only known at runtime).
For cases where there actually is an underlying storage that is indirectly accessed, the user function might be specified to return a reference. Then the read-only-requirement could be dropped.
That seems to be already supported by the CwiseNullaryOp expression except there is no offsets nor strides but these later, if needed, can be attached to the functor.
Thanks for the hint! Sorry for overlooking that.
I tried it out and implemented some permuted views on matrices and vectors based on CwiseNullaryOp. Thanks a lot!
Please add an example like the implementation of identity_op (see src/Core/Functors.h) to the documentation. For the user of CwiseNullaryOp it's very important to know about the traits class functor_has_linear_access that must be specialized if the two-index variant of the overloaded operator() is to be used: template<typename Scalar> struct functor_has_linear_access<scalar_identity_op<Scalar> > { enum { ret = 0 }; }; Otherwise the CwiseNullaryOp will be linearly accessed even if it is declared as a matrix.
Would you like to propose a patch for the documentation? Also, it might be interesting to share your piece of code for the permuted views. Using a CwiseNullaryOp for this use case does not seems natural at a first glance, but that's indeed probably the easiest way. Reshape-like and slicing operations could probably be implemented the same way.
I reopened the bug because CwiseNullaryOp really needs better documentation.
Created attachment 270 [details] Code for some CwiseNullaryOp applications with tests Dear Gael Guennebaud, I attach my code for 5 new utilities based on CwiseNullaryOp here: * iota: virtual column vector with elements 0, ..., n - 1 with optional offset * iota_row: the same as a row vector * selection_of_onedim: a view to a an arbitrarily ordered selection selection of the elements of a vector x * selection_of_rows: a view to a an arbitrarily ordered selection of the rows of 2-dimensional dense data (matrix or two-dimensional array). * selection_of_cols: the same for columns There are also some tests based on Eigen's unit testing framework. Please put <Eigen source>/test/main.h in the current directory and compile this file with g++: g++ -I<path to include for Eigen> eigen_publish.cpp -o eigen_publish In the code, I also discussed a question that arose in the implementation: What is the best way to keep a reference to an Eigen matrix or vector in an object without copying the data?
I tried to support both matrices and arrays in the above tools, the only exception being that the results of selection_of_rows and selection_of_columns are always matrices. Here are the tests/examples: void test_iota() { VectorXl x(4); x = iota(4, 10l); VectorXl expected(4); expected << 10, 11, 12, 13; VERIFY_IS_EQUAL(x, expected); VERIFY_IS_EQUAL(x.sum(), 46); RowVectorXd x2(4); x2 = iota_row(4, 0.0); RowVectorXd expected2(4); expected2 << 0, 1, 2, 3; VERIFY_IS_EQUAL(x2, expected2); } void test_selection_of_onedim() { VectorXd x(5); x << 4, 3, 9, 2, 10; VectorXi selection(4); selection << 4, 0, 2, 4; VectorXd expected(4); expected << 10, 4, 9, 10; VERIFY_IS_EQUAL(selection_of_onedim(x, selection), expected); selection.resize(6); selection << 4, 0, 2, 4, 1, 4; expected.resize(6); expected << 10, 4, 9, 10, 3, 10; VERIFY_IS_EQUAL(selection_of_onedim(x, selection), expected); } void test_selection_of_rows_cols() { MatrixXd A(5, 2); A << 3, 4, 9, 1, 2, 8, 0, 9, 5, 7; VectorXi selection(4); selection << 4, 0, 2, 4; MatrixXd expected(4, 2); expected << 5, 7, 3, 4, 2, 8, 5, 7; VERIFY_IS_EQUAL(selection_of_rows(A, selection), expected); expected.resize(2, 4); expected << 5, 3, 2, 5, 7, 4, 8, 7; VERIFY_IS_EQUAL(selection_of_cols(A.transpose(), selection), expected); }
-- GitLab Migration Automatic Message -- This bug has been migrated to gitlab.com's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.com/libeigen/eigen/issues/457.