假设我有一个Eigen::MatrixXf
来自时间序列的样本。每行对应一个时间步,列是当时测量的不同属性。
为了进一步处理,我想对这些数据应用延时嵌入。这意味着,时间x_t
的每个样本t
都会变为x'_t = (x_t, x_(t-1), ..., x_(t-k+1))
。因此,样本将使用先前样本的属性进行扩充。
我可以简单地复制矩阵k
次,移动行并将它们堆叠在一起,但这会使数据大小增加k
倍。我希望有一个像这样的矩阵行为的对象,但在内部计算原始矩阵中每个系数的索引并访问相应的原始数据。
我试图调整Eigen::MapBase
的代码来创建这样一个类,但它的行为不一致:
#ifndef TIMEDELAYEMBEDDINGMAP_H
#define TIMEDELAYEMBEDDINGMAP_H
#include <Eigen/Core>
#define EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS(Derived) \
EIGEN_STATIC_ASSERT((int(internal::traits<Derived>::Flags) & LinearAccessBit) || Derived::IsVectorAtCompileTime, \
YOU_ARE_TRYING_TO_USE_AN_INDEX_BASED_ACCESSOR_ON_AN_EXPRESSION_THAT_DOES_NOT_SUPPORT_THAT)
namespace Eigen
{
/** \class TimeDelayEmbeddingMap
*
* \brief Wraps data and extends it with time-delay embedding
*/
template<typename Derived> class TimeDelayEmbeddingMap
: public internal::dense_xpr_base<Derived>::type
{
public:
typedef typename internal::dense_xpr_base<Derived>::type Base;
enum {
RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
SizeAtCompileTime = Base::SizeAtCompileTime
};
typedef typename internal::traits<Derived>::StorageKind StorageKind;
typedef typename internal::traits<Derived>::Index Index;
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef typename internal::conditional<
bool(internal::is_lvalue<Derived>::value),
Scalar *,
const Scalar *>::type
PointerType;
using Base::derived;
// using Base::RowsAtCompileTime;
// using Base::ColsAtCompileTime;
// using Base::SizeAtCompileTime;
using Base::MaxRowsAtCompileTime;
using Base::MaxColsAtCompileTime;
using Base::MaxSizeAtCompileTime;
using Base::IsVectorAtCompileTime;
using Base::Flags;
using Base::IsRowMajor;
using Base::rows;
using Base::cols;
using Base::size;
using Base::coeff;
using Base::coeffRef;
using Base::lazyAssign;
using Base::eval;
using Base::innerStride;
using Base::outerStride;
using Base::rowStride;
using Base::colStride;
using Base::operator=;
typedef typename Base::CoeffReturnType CoeffReturnType;
inline Index rows() const { return m_rows.value(); }
inline Index cols() const { return m_cols.value() * m_k; }
inline Index size() const { return rows() * cols(); }
inline unsigned long k() const { return m_k; }
inline const Scalar* data() const { return m_data; }
inline const Scalar& coeff(Index rowId, Index colId) const
{
Index dt = colId / m_k;
Index col = colId % m_k;
Index row = (rowId >= dt) ? rowId - dt : dt - rowId;
return m_data[col * colStride() + row * rowStride()];
}
inline const Scalar& coeffRef(Index rowId, Index colId) const
{
Index dt = colId / m_k;
Index col = colId % m_k;
Index row = (rowId >= dt) ? rowId - dt : dt - rowId;
return this->m_data[col * colStride() + row * rowStride()];
}
template<int LoadMode>
inline PacketScalar packet(Index rowId, Index colId) const
{
Index dt = colId / m_k;
Index col = colId % m_k;
Index row = (rowId >= dt) ? rowId - dt : dt - rowId;
return internal::ploadt<PacketScalar, LoadMode>
(m_data + (col * colStride() + row * rowStride()));
}
inline TimeDelayEmbeddingMap(PointerType dataPtr, unsigned long k, Index nbRows, Index nbCols)
: m_data(dataPtr), m_rows(nbRows), m_cols(nbCols), m_k(k)
{
eigen_assert( (dataPtr == 0)
|| ( nbRows >= 0 && (RowsAtCompileTime == Dynamic || RowsAtCompileTime == nbRows)
&& nbCols >= 0 && (ColsAtCompileTime == Dynamic || ColsAtCompileTime == nbCols)));
eigen_assert(k > 0);
checkSanity();
}
protected:
void checkSanity() const
{
EIGEN_STATIC_ASSERT(EIGEN_IMPLIES(internal::traits<Derived>::Flags&PacketAccessBit,
internal::inner_stride_at_compile_time<Derived>::ret==1),
PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1);
eigen_assert(EIGEN_IMPLIES(internal::traits<Derived>::Flags&AlignedBit, (size_t(m_data) % 16) == 0)
&& "input pointer is not aligned on a 16 byte boundary");
}
PointerType m_data;
const internal::variable_if_dynamic<Index, RowsAtCompileTime> m_rows;
const internal::variable_if_dynamic<Index, ColsAtCompileTime> m_cols;
unsigned long m_k;
};
#undef EIGEN_STATIC_ASSERT_INDEX_BASED_ACCESS
} // end namespace Eigen
#endif // TIMEDELAYEMBEDDINGMAP_H
这是一个简单的测试代码:
#include <iostream>
#include "TimeDelayEmbeddingMap.h"
int main()
{
Eigen::MatrixXf m(10, 3);
m.setRandom();
std::cout << m << std::endl << std::endl;
Eigen::TimeDelayEmbeddingMap<Eigen::MatrixXf> tdm(m.data(), 3, m.rows(), m.cols());
std::cout << tdm.cols() << std::endl << std::endl << tdm << std::endl;
return 0;
}
产生以下输出:
-0.997497 -0.651784 0.97705
0.127171 0.717887 -0.108615
-0.613392 0.421003 -0.761834
0.617481 0.0270699 -0.990661
0.170019 -0.39201 -0.982177
-0.0402539 -0.970031 -0.24424
-0.299417 -0.817194 0.0633259
0.791925 -0.271096 0.142369
0.64568 -0.705374 0.203528
0.49321 -0.668203 0.214331
9
-0.997497 -0.651784 0.97705
0.127171 0.717887 -0.108615
-0.613392 0.421003 -0.761834
0.617481 0.0270699 -0.990661
0.170019 -0.39201 -0.982177
-0.0402539 -0.970031 -0.24424
-0.299417 -0.817194 0.0633259
0.791925 -0.271096 0.142369
0.64568 -0.705374 0.203528
0.49321 -0.668203 0.214331
它正确报告有9列,但只打印3,就像原始矩阵一样。似乎我错过了一些东西,但我对Eigen
的内部结构知之甚少,无法弄清楚是什么问题。
答案 0 :(得分:0)
operator<<(std::ostream&, const DenseBase<Derived>& m)
(在Eigen/src/Core/IO.h
中定义)调用m.eval()
您未重新定义的内容会发生什么。
我建议您查看Replicate
(Eigen/src/Core/Replicate.h
)的实施方式。除了稍微不同的索引计算之外,这几乎已经达到了你想要的效果。