Hello,
I think this is a good start. Some comments:
- I'm not fan of the name "Proxy". It is too generic. Perhaps: "IndirectView", not sure though.
RowColProxy would be less generic. However I like IndirectView or IndirectAdresser or only Indirect. - in ei_traits, it'd be better to write ei_traits<RowType>::RowsAtCompileTime instead of RowType::RowsAtCompileTime. This will allow to write a ei_traits for some std containers (std::vector, std::, whatever), or other classes comming from different libs.
okay.
I started on an operator that returns the 'proxy'. I'm not so sure but I think constructor copies the whole matrix. For the operator (or in general) I guess this is not necessary, is it?
template <typename RowType, typename ColType> RowColProxy<Derived, RowType, ColType> operator()(RowType rowProxy, ColType colProxy) { Eigen::RowColProxy<Derived,RowType,ColType> proxy(*this, rowProxy, colProxy); return proxy; }
- for the same reason I'd use operator[] instead of operator().
- would be cool to implement Range on top of CwiseNullaryOp (like Ones, Zeros and Identity). This will allow us to use it to select a range of slices, and also to do some fancy things: VectorXf v1to10 = VectorXf::Range(1,10); // this one is boring VectorXf allpowerOfTwo = VectorXf::Constant(10,2).cwise().pow(VectorXf::Range(1,10)); // this one is cooler but not optimal
- regarding the API in MatrixBase, I guess we could afford something similar than in mathlab: VectorXi colIndices = ...; VectorXi rowIndices = ....; mat(Range(...),colIndices); mat(5,colIndices); // the integer 5 will be automatically converted to Range(5,5) mat(rowIndices,Identity); mat(Range(...),Range(...)); // no index vector => return a Block
For the Range I thought about three versions 1. the normal range
template<int Size> inline CwiseNullaryOp<ei_scalar_range_op<int>, Matrix<int,Size,1> > Range(int from, int to) { int size = (to-from); return CwiseNullaryOp<ei_scalar_range_op<int>, Matrix<int,Size,1> >(size, 1, ei_scalar_range_op<int>(from)); }; 2. slices // typedef for return type (template parameter Size) template<int Size> inline CwiseNullaryOp<ei_scalar_slice_op<int>, Matrix<int,Size,1> > Range(int from, int to, int stride) { int size = (int) ((to-from)/stride); return CwiseNullaryOp<ei_scalar_slice_op<int>, Matrix<int,Size,1> >(size, 1, ei_scalar_slice_op<int>(from,stride)); };
3. the identity interval template<int Size> inline CwiseNullaryOp<ei_scalar_id_range_op<int>, Matrix<int,Size,1> > Range() { return CwiseNullaryOp<ei_scalar_id_range_op<int>, Matrix<int,Size,1> >(Size, 1, ei_scalar_id_range_op<int>()); };
The question is if it's better to define it dynamically sized (there are no default template parameters for functions) or like I did?
The according functors are:
#define EIGEN_FUNCTORS_PLUGIN "./Range.hpp"
#ifndef __RANGE_HPP__ #define __RANGE_HPP__
template<typename Scalar> class ei_scalar_range_op EIGEN_EMPTY_STRUCT { private: Scalar _start; public: inline ei_scalar_range_op(Scalar start) : _start(start) {}; inline const Scalar operator() (int i) const { return _start+((Scalar) i); } inline const Scalar operator() (int i,int j) const { assert(j==0); return this->operator()(i); } };
template<typename Scalar> struct ei_functor_traits<ei_scalar_range_op<Scalar> > { enum { Cost = 1/*NumTraits<Scalar>::AddCost*/, PacketAccess = false, IsRepeatable = true }; };
template<typename Scalar> class ei_scalar_slice_op EIGEN_EMPTY_STRUCT { private: Scalar _start,_stride; public: inline ei_scalar_slice_op(Scalar start, Scalar stride) : _start(start), _stride(stride) {}; inline const Scalar operator() (int i) const { return _start+((Scalar) i)*_stride; } inline const Scalar operator() (int i,int j) const { assert(j==0); return this->operator()(i); } };
template<typename Scalar> struct ei_functor_traits<ei_scalar_slice_op<Scalar> > { enum { Cost = 1/*NumTraits<Scalar>::AddCost*/, PacketAccess = false, IsRepeatable = true }; };
template<typename Scalar> struct ei_scalar_id_range_op EIGEN_EMPTY_STRUCT { inline ei_scalar_id_range_op() {}; inline const Scalar operator() (int i) const { return i; } inline const Scalar operator() (int i,int j) const { assert(j==0); return i; } };
template<typename Scalar> struct ei_functor_traits<ei_scalar_id_range_op<Scalar> > { enum { Cost = 1/*NumTraits<Scalar>::AddCost*/, PacketAccess = false, IsRepeatable = true }; };
/* template<typename Scalar> struct ei_scalar_identity_op EIGEN_EMPTY_STRUCT { EIGEN_STRONG_INLINE ei_scalar_identity_op(void) {} EIGEN_STRONG_INLINE const Scalar operator() (int row, int col) const { return row==col ? Scalar(1) : Scalar(0); } }; template<typename Scalar> struct ei_functor_traits<ei_scalar_identity_op<Scalar> > { enum { Cost = NumTraits<Scalar>::AddCost, PacketAccess = false, IsRepeatable = true }; };
*/
#endif
that's it for now,
gael.
On Mon, Jul 6, 2009 at 8:04 PM, Stefan Ulbrich <s.ulbrich@xxxxxxxxxxxxxx> wrote: Hi, this is how I implemented the "Proxy" class. In MatrixBase one could add a ::getColumnProxy (and Row,RowColumn). In case only a partial proxy is chosen, matrix base could pass some kind of Range Vector class which efficiently returns the index as coeff(). Alternatively, one could do a type check at compile time if the template parameter was a constant 'identity'. What do you think? cheers, stefan template<typename MatrixType, typename RowType, typename ColType> class Proxy : public MatrixBase<Proxy<MatrixType, RowType, ColType> > { public: EIGEN_GENERIC_PUBLIC_INTERFACE(Proxy) inline Proxy(const MatrixType& matrix, RowType rows, ColType cols) : m_matrix(matrix), m_rows(rows), m_cols(cols) { std::cout << "Debug: " << m_rows.minCoeff() << "," << m_rows.maxCoeff() << "," << matrix.rows() << std::endl; std::cout << "Debug: " << m_cols.minCoeff() << "," << m_cols.maxCoeff() << "," << matrix.cols() << std::endl; ei_assert(m_rows.minCoeff() >= 0 && m_rows.maxCoeff() < matrix.rows() && m_cols.minCoeff() >= 0 && m_cols.maxCoeff() < matrix.cols()); } EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Proxy) inline int rows() const { return m_rows.rows(); } inline int cols() const { return m_cols.rows(); } inline Scalar& coeffRef(int row, int col) { return m_matrix.const_cast_derived().coeffRef(m_rows(row), m_cols(col)); } inline const Scalar coeff(int row, int col) const { return m_matrix.coeff(m_rows(row), m_cols(col)); } protected: const typename MatrixType::Nested m_matrix; const typename RowType::Nested m_rows; const typename ColType::Nested m_cols; }; template<typename MatrixType, typename RowType, typename ColType> struct ei_traits<Proxy<MatrixType, RowType, ColType> > { typedef typename MatrixType::Scalar Scalar; typedef typename ei_nested<MatrixType>::type MatrixTypeNested; typedef typename ei_unref<MatrixTypeNested>::type _MatrixTypeNested; enum { RowsAtCompileTime = (MatrixType::RowsAtCompileTime != Dynamic && RowType::RowsAtCompileTime != Dynamic) ? int(RowType::RowsAtCompileTime) : Dynamic, ColsAtCompileTime = (MatrixType::ColsAtCompileTime != Dynamic && ColType::RowsAtCompileTime != Dynamic) ? int(ColType::RowsAtCompileTime) : Dynamic, MaxRowsAtCompileTime = (MatrixType::MaxRowsAtCompileTime != Dynamic ) ? int(RowType::MaxRowsAtCompileTime) : Dynamic, MaxColsAtCompileTime = (MatrixType::MaxColsAtCompileTime != Dynamic ) ? int(ColType::MaxRowsAtCompileTime) : Dynamic, Flags = _MatrixTypeNested::Flags & HereditaryBits, CoeffReadCost = _MatrixTypeNested::CoeffReadCost }; }; Am 03.07.2009 um 09:55vorm. schrieb Gael Guennebaud: On Fri, Jul 3, 2009 at 9:12 AM, Stefan Ulbrich<s.ulbrich@xxxxxxxxxxxxxx> wrote: thanks for the answer. Actually, block / corner and minor don't allow you to select the for example the columns 1,3,4,6. The closest thing I found in Eigen is the Minor Class which allows to omit one row/col. I now tried to clone and to modificate this class but haven't finished it yet (still problems with io.h). This class will take two row-vectors that serve as a proxy for the addressing of the coefficients (allows for permutations, repetition of elements...). What do you think: do I have to worry about speed using this method? Does the use of Minor result in lower speed? Indeed this requires a novel _expression_ with a coeff(i,j) method which looks like: Scalar coeff(i,j) { return m_matrix.coeff(m_rowIndices[i], m_colIndices[j]); } Assuming the compiler is able to move one of the m_*Indices[] out of the inner evaluation loop, I guess this should be quite efficient. Regarding API I think it'd be nice to be able to only provide a list of rows or columns. To this end, the type of m_rowIndices could be a template parameter for which the possibilities would be any kind of integer vectors and a special class having n operator[i] always returning "i". Regarding the names of these additional classes and methods, I have no clue. In the same way I want to create a class that connects matrix with the same amount of rows (cols) to a single one. yes it is quite easy to write such a matrix _expression_. Here is how the coeff(i,j) method would look like: Scalar coeff(i,j) { if (j<m_matrixA.cols()) return m_matrixA.coeff(i,j); else return m_matrixB.coeff(i,j-m_matrixA.cols()); } The problem is the "if" which will kill the performance (+ no vectorization, etc.). So, if the memory consumption is not critical for you I suggest you to copy the matrices to a single bigger one: MatrixXf A, B, C; /* ... */ A.resize(B.rows(), B.cols()+C.cols()); A << B, C; This assignment is fast (vectorized), and then the use of A will be fast too. Also note that this syntax is very powerful: it allows you to assemble as many as scalars and/or matrix expressions as you want in any direction. This is also why you have to set the size of the matrix A manually. For instance you can also assemble B and C vertically: A.resize(B.rows()+C.rows(), B.cols()); A << B, C; See the tutorial for other more fancy examples. cheers, Gael cheers, stefan Am 02.07.2009 um 19:46nachm. schrieb Thomas Capricelli: Erm, all of this seems already available,have you read the tutorial http://eigen.tuxfamily.org/dox/TutorialCore.html especially the part http://eigen.tuxfamily.org/dox/TutorialCore.html#TutorialCoreMatrixBlocks Anything specific you think about that can not currently be done ? regards, Thomas In data giovedì 02 luglio 2009 18:47:16, Stefan Ulbrich ha scritto: : > Hello, in matlab you can select a partial matrix by explicitly specifying which cols and rows to take from the original matrix, e.g. with A([1,3],[2 4]) further, it would be interesting to combine blocks into a matrix that serves as a proxy to the elements: A = [B C] I'd really would really like to see that functionality in eigen2. Do you think this is possible? Do you have any suggestions on how to start implementing it? best regards, Stefan -- Thomas Capricelli <orzel@xxxxxxxxxxxxxxx> http://www.freehackers.org/thomas
|