获取由向量向量表示的矩阵的第一列

Posted

技术标签:

【中文标题】获取由向量向量表示的矩阵的第一列【英文标题】:Get the first column of a matrix represented by a vector of vectors 【发布时间】:2013-03-24 14:08:51 【问题描述】:

假设我使用std::vector 表示值矩阵foo

int rows = 5;
int cols = 10;    
auto foo = vector<vector<double>>(rows, vector<double>(cols));

有没有一种巧妙简单的方法让我得到一个大小为rowsvector&lt;int&gt;,其中包含foo 的第一个“列”:

foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] 

换句话说,我可以“转置” foo 以使以下三件事为真:

foo_transpose.size() == cols
foo_transpose[0].size() == rows
foo_transpose[0] == foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] 

澄清说明

对于表示“矩阵”的替代方法,有一些很好的建议。当我使用术语“矩阵”时,我的意思是每个第二级vector 的大小都相同。我并不是要建议我将这个数据结构用于线性代数类型的运算。实际上,我确实需要一个向量向量,或者一个可以从中“拉出”一维向量的数据结构,因为我有对向量进行操作的函数,例如:

double sum(vector<double> const & v);

我打电话的人:

sum(foo[0]);

只是在特殊情况下我想出了一个需要做的情况:

sum(foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] ;

For 循环解决方案

有一个明显的 for 循环解决方案,但我一直在寻找更强大和更高效的解决方案。

【问题讨论】:

我强烈建议反对以这种方式表示矩阵。缓存局部性会很糟糕,像切片、重塑或转置矩阵这样的琐碎操作会变得非常痛苦。 您必须滚动自己的矩阵吗?如果没有,我建议使用Boost.MultiArray。 您是否要求返回的列向量可以直接修改到源矩阵(即更改列中的值,它会在矩阵中更改)?它在可能的解决方案的复杂性上产生了相当大的差异。顺便说一句,我和稻谷在一起。使用向量的向量的唯一原因是受益于可变的行宽,根据定义,真正的矩阵将具有。 如果你的矩阵大小是已知的,最好使用数组:array&lt;array&lt;double, cols&gt;, rows&gt;&gt; matrix;这会将数据放在一个连续的内存区域,提高缓存效率。 @paddy,所有行的长度相同,大小不变。请添加您的建议作为答案。 【参考方案1】:

正如我在 cmets 中提到的,使用向量的向量表示矩阵是不切实际的,原因如下:

    设置繁琐; 很难改变; 缓存局部性不好。

这是我创建的一个非常简单的类,它将在单个向量中保存一个 2D 矩阵。这几乎就是 MATLAB 等软件的工作方式......尽管是一个巨大的简化。

template <class T>
class SimpleMatrix

public:
    SimpleMatrix( int rows, int cols, const T& initVal = T() );

    // Size and structure
    int NumRows() const                        return m_rows; 
    int NumColumns() const                     return m_cols; 
    int NumElements() const                    return m_data.size(); 

    // Direct vector access and indexing
    operator const vector<T>& () const         return m_data; 
    int Index( int row, int col ) const        return row * m_cols + col; 

    // Get a single value
          T & Value( int row, int col )        return m_data[Index(row,col)]; 
    const T & Value( int row, int col ) const  return m_data[Index(row,col)]; 
          T & operator[]( size_t idx )         return m_data[idx]; 
    const T & operator[]( size_t idx ) const   return m_data[idx]; 

    // Simple row or column slices
    vector<T> Row( int row, int colBegin = 0, int colEnd = -1 ) const;
    vector<T> Column( int row, int colBegin = 0, int colEnd = -1 ) const;

private:
    vector<T> StridedSlice( int start, int length, int stride ) const;

    int m_rows;
    int m_cols;

    vector<T> m_data;
;

这个类基本上是围绕一个单一的功能——StridedSlice。它的实现是:

template <class T>
vector<T> SimpleMatrix<T>::StridedSlice( int start, int length, int stride ) const

    vector<T> result;
    result.reserve( length );
    const T *pos = &m_data[start];
    for( int i = 0; i < length; i++ ) 
        result.push_back(*pos);
        pos += stride;
    
    return result;

剩下的就很简单了:

template <class T>
SimpleMatrix<T>::SimpleMatrix( int rows, int cols, const T& initVal )
    : m_data( rows * cols, initVal )
    , m_rows( rows )
    , m_cols( cols )
    


template <class T>
vector<T> SimpleMatrix<T>::Row( int row, int colBegin, int colEnd ) const

    if( colEnd < 0 ) colEnd = m_cols-1;
    if( colBegin <= colEnd )
        return StridedSlice( Index(row,colBegin), colEnd-colBegin+1, 1 );
    else
        return StridedSlice( Index(row,colBegin), colBegin-colEnd+1, -1 );


template <class T>
vector<T> SimpleMatrix<T>::Column( int col, int rowBegin, int rowEnd ) const

    if( rowEnd < 0 ) rowEnd = m_rows-1;
    if( rowBegin <= rowEnd )
        return StridedSlice( Index(rowBegin,col), rowEnd-rowBegin+1, m_cols );
    else
        return StridedSlice( Index(rowBegin,col), rowBegin-rowEnd+1, -m_cols );

请注意,RowColumn 函数的设置方式使您可以轻松请求整行或整列,但功能更强大一些,因为您可以通过传递一个或两个以上来分割范围参数。是的,您可以通过使起始值大于结束值来反向返回行/列。

这些函数没有内置边界检查,但您可以轻松添加。

您还可以添加一些内容以将区域切片返回为另一个 SimpleMatrix&lt;T&gt;

玩得开心。

【讨论】:

我应该明确指出这是一个行主要表示。我含糊地将它与 MATLAB 进行了比较,我应该提到它是列主要的。使用最适合您的访问需求的表示。 这是一个很好的答案。可以让它变得更好的一件事 - 特别是对于像我这样的新手 - 将是一些示例用例:即,启动一个矩阵,对其切片,设置值,. . . 这是一个我正在努力解决的特定示例:您将如何为 SimpleMatrix 实例的第一列分配值。 auto V = SimpleMatrix&lt;double&gt;(N, n_t, 0);V.Column(0) = . . . 对我不起作用。 进一步考虑,在我看来,需要其他方法来支持将值分配给矩阵。问题:为什么每种方法都有重复项,一个以const 开头,而另一个没有? 是的,设置一个透明的方法来返回一个切片作为参考会很棘手。也许这可以通过valarray 以某种方式实现。至于 const 和 non-const 方法,它们允许分配给特定值,但如果您只从容器的 const 版本读取值,也可以保持 const 正确性。

以上是关于获取由向量向量表示的矩阵的第一列的主要内容,如果未能解决你的问题,请参考以下文章

怎么用Matlab求矩阵的特征值和特征向量

向量乘矩阵表示啥?

在犰狳中将矩阵除以向量

矩阵和向量相乘

标量向量矩阵和张量

一个行矩阵乘以一个列矩阵(一样大小)有啥物理或者几何意义?