实施Eigen的块或Boost的项目方法

时间:2019-11-15 06:22:11

标签: c++ boost eigen

我正在努力提高C ++技能-特别是模板的使用。我正在创建一个过滤数学库,该数学库通过使用模板与包括Boost和Eigen在内的不同矢量/矩阵类兼容。到目前为止,我对库非常满意,但是在扩展功能时遇到了问题。

Eigen和Boost不同,例如后者没有乘法运算符(请参见1),因此这在我的实现中是一个选择。我决定确保模板库中使用的矩阵/矢量方法和运算符使用为Eigen定义的矩阵/矢量方法和运算符,以便至少一个库与数学库真正兼容。在我的库中,我将使用*乘以矩阵,这不适用于增强。为了增强效果,我为矩阵和向量创建了一个包装器类,以允许通过自定义运算符使用*。矩阵包装器的示例如下:

class matrixBoost{
        private:
                boost::numeric::ublas::matrix<double> value;

        public:
                matrixBoost(){
                }

                matrixBoost(boost::numeric::ublas::matrix<double> value):value(value){}

                static matrixBoost Identity(int dimension,int dimension2){
                        return matrixBoost(boost::numeric::ublas::identity_matrix<double>(dimension,dimension2));
                }

                matrixBoost transpose(){
                        matrixBoost t(boost::numeric::ublas::trans(value));
                        return t;
                }

                boost::numeric::ublas::matrix<double> getSystemValue() const{
                        return value;
                }
};

//example operator - one of many
matrixBoost operator*(const matrixBoost &lhs, const matrixBoost &rhs){
        matrixBoost res(boost::numeric::ublas::prod(lhs.getSystemValue(),rhs.getSystemValue()));
        return res;
}

我现在正尝试将Eigen的block添加到boost的包装器类中,以使Eigen的库中具有以下行为:

Eigen::MatrixXd m(2,2);m<<1,2,3,4;
Eigen::MatrixXd n = m.block(0, 0, 1, 2) + m.block(0,0,1,2);
m.block(0,0,1,2) = n;

现在m等于

2 4
3 4

我的第一个问题是,有人可以链接或显示如何编码块函数的示例(甚至不考虑包装器类)。我曾尝试使用Google搜索,但要么Google变得更糟,要么我没有使用正确的关键字-结果充斥着operator []结果。我很难理解。我尝试在Eigen库源代码中进行搜索,并想象代码必须位于here,但是模板语言对我来说很难解析。

我知道boost也有类似的概念,如here所示:

project(A, r1, r2) = C;    // assign the submatrix of A specified by the two index ranges r1 and r2
C = project(A, r1, r2);    // the submatrix of A specified by the two index ranges r1 and r2

我不确定是否可以向我的包装器类中添加块函数。现在,我有以下内容:

matrixBoost block(int index1,int index2, int length1, int length2){
    boost::numeric::ublas::range r1(i1,l1);
    boost::numeric::ublas::range r2(i2,l2);
    return matrixBoost(boost::numeric::ublas::project(value,r1,r2));
}

当该方法位于等号的右侧时,此方法将起作用。但是,我在如何允许在左侧调用该方法方面遇到困难。也许我应该利用boost的项目方法。任何帮助将非常感激!

谢谢。

1 个答案:

答案 0 :(得分:0)

因此,我找到了一个包装boost类的解决方案,但是该解决方案有点混乱。上面问题中推导的block函数必须返回一个引用。如果它在等号的右侧,则需要返回包裹在matrixBoost中的子矩阵,以获得表达式中可能存在的其他* / +乘法。但是,如果在等号的左侧调用该方法怎么办?

我的解决方案是使用一个布尔标志(subMatrixCopy),在其中我将其设置为true并通过使用{{1来备份value中的完整矩阵valBack },然后返回子矩阵。此修改将允许在右侧进行正确的表达评估。对于左侧,一旦调用std::swap运算符,则布尔值标志将确保正确地将右侧分配给=中备份矩阵值的指定块。

valBack

,这是我用来测试的代码示例。有用!但是,我相信该解决方案可以防止执行某些操作,例如将等号链接起来。

#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/matrix.hpp>
#include <boost/qvm/mat_operations.hpp>
#include <boost/numeric/ublas/vector_proxy.hpp>
#include <boost/numeric/ublas/triangular.hpp>
#include <boost/numeric/ublas/lu.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <lapacke.h>

class matrixBoost{
   private:
        boost::numeric::ublas::matrix<double> value;
        boost::numeric::ublas::range r1;
        boost::numeric::ublas::range r2;
        boost::numeric::ublas::matrix<double>valBack;
        bool subMatrixCopy = false;

        void setSystemValue(boost::numeric::ublas::matrix<double> v){
            value = v;
        }

   public:
        matrixBoost(){}

        matrixBoost(int rowCount, int colCount){
            value = boost::numeric::ublas::zero_matrix<double>(rowCount,colCount);
        }

        matrixBoost(boost::numeric::ublas::matrix<double> value):value(value){}

        static matrixBoost Identity(int dimension,int dimension2){
           return matrixBoost(boost::numeric::ublas::identity_matrix<double>(dimension,dimension2));
         }

         matrixBoost transpose(){
              matrixBoost t(boost::numeric::ublas::trans(value));
              return t;
          }

          boost::numeric::ublas::matrix<double> getSystemValue() const{
              return value;
          }

         matrixBoost & block(int i1, int i2, int l1, int l2){
             if(subMatrixCopy){
                 std::swap(valBack,value);
              }
              subMatrixCopy = true;
              r1 = boost::numeric::ublas::range(i1,i1+l1);
              r2 = boost::numeric::ublas::range(i2,i2+l2);
              valBack = boost::numeric::ublas::project(value,r1,r2);
              std::swap(valBack,value);
              return *this;
        }

        matrixBoost &operator=( const matrixBoost other){
            if(subMatrixCopy){
                subMatrixCopy = false;
                boost::numeric::ublas::project(valBack,r1,r2) = other.getSystemValue();
                std::swap(valBack,value);
            }else{
                value = other.getSystemValue();
            }
            return *this;//better be no chaining of equal signs
        }
};