【发布时间】:2021-09-22 17:59:49
【问题描述】:
我有一个应用程序需要减少矩阵类的内存使用量。我的许多矩阵都是对称的,因此只需要 N(N+1)/2 内存而不是 N2。我不能简单地拥有一个派生自我的Matrix 类的MatrixSym 类,因为子类总是使用比基类更多的内存。我已经定义了一个 MatrixAbstract 类,两个类都从该类继承,但是我无法让矩阵乘法函数对它们都起作用。
我的问题
如何定义一个C = multiply(A,B) 函数,该函数接受Matrix 或MatrixSym 对象用于任何输入/输出?我的最小工作示例并不是那么简单,因为它包含四个multiply 的定义,它们都使用相同的代码并且应该合并为一个。
要求
- 仅静态分配
- 矩阵元素必须使用
std::array - 最少的重复代码:我有许多矩阵运算,而
MatrixSym唯一不同的是它存储和访问底层matVals数组中元素的方式。
#include <array>
#include <iostream>
template<unsigned int ROWS, unsigned int COLS, unsigned int NUMEL>
class MatrixAbstract
{
private:
static constexpr unsigned int numel = NUMEL;
std::array<double, NUMEL> matVals; // The array of matrix elements
public:
MatrixSuperclass(){}
virtual unsigned int index_from_rc(const unsigned int& row, const unsigned int& col) const = 0;
// get the value at a given row and column
double get_value(const int& row, const int& col) const
{
return this->matVals[this->index_from_rc(row,col)];
}
// set the value, given the row and column
void set_value(const int& row, const int& col, double value)
{
this->matVals[this->index_from_rc(row,col)] = value;
}
};
template<unsigned int ROWS, unsigned int COLS, unsigned int NUMEL = ROWS*COLS>
class Matrix : public MatrixSuperclass<ROWS, COLS, NUMEL>
{
public:
Matrix(){}
// get the linear index in matVals corresponding to a row,column input
unsigned int index_from_rc(const unsigned int& row, const unsigned int& col) const {
return row*COLS + col;
}
};
template<unsigned int ROWS, unsigned int COLS = ROWS, unsigned int NUMEL = ROWS*(ROWS+1)/2>
class MatrixSym : public MatrixSuperclass<ROWS, COLS, NUMEL>
{
public:
MatrixSym(){}
// get the linear index in matVals corresponding to a row,column input (Symmetric matrix)
unsigned int index_from_rc(const unsigned int& row, const unsigned int& col) const {
unsigned int z;
return ( ( z = ( row < col ? col : row ) ) * ( z + 1 ) >> 1 ) + ( col < row ? col : row ) ;
}
};
// THE FOLLOWING FOUR FUNCTIONS ALL USE THE EXACT SAME CODE, ONLY INPUT/OUTPUT TYPES CHANGE
// Multiply a Matrix and Matrix and output a Matrix
template<unsigned int ROWS, unsigned int COLS, unsigned int INNER>
Matrix<ROWS,COLS> multiply (Matrix<ROWS,INNER>& inMatrix1, Matrix<INNER,COLS>& inMatrix2) {
Matrix<ROWS,COLS> outMatrix;
for (unsigned int r = 0; r < ROWS; r++) {
for (unsigned int c = 0; c < COLS; c++) {
double val = 0.0;
for (unsigned int rc = 0; rc < INNER; rc++) {
val += inMatrix1.get_value(r,rc)*inMatrix2.get_value(rc,c);
}
outMatrix.set_value(r,c,val);
}
}
return outMatrix;
}
// Multiply a Matrix and MatrixSym and output a Matrix
template<unsigned int ROWS, unsigned int COLS, unsigned int INNER>
Matrix<ROWS,COLS> multiply (Matrix<ROWS,INNER>& inMatrix1, MatrixSym<INNER,COLS>& inMatrix2) {
Matrix<ROWS,COLS> outMatrix;
for (unsigned int r = 0; r < ROWS; r++) {
for (unsigned int c = 0; c < COLS; c++) {
double val = 0.0;
for (unsigned int rc = 0; rc < INNER; rc++) {
val += inMatrix1.get_value(r,rc)*inMatrix2.get_value(rc,c);
}
outMatrix.set_value(r,c,val);
}
}
return outMatrix;
}
// Multiply a MatrixSym and Matrix and output a Matrix
template<unsigned int ROWS, unsigned int COLS, unsigned int INNER>
Matrix<ROWS,COLS> multiply (MatrixSym<ROWS,INNER>& inMatrix1, Matrix<INNER,COLS>& inMatrix2) {
//MatrixSym<ROWS,COLS> outMatrixSym;
Matrix<ROWS,COLS> outMatrix;
for (unsigned int r = 0; r < ROWS; r++) {
for (unsigned int c = 0; c < COLS; c++) {
double val = 0.0;
for (unsigned int rc = 0; rc < INNER; rc++) {
val += inMatrix1.get_value(r,rc)*inMatrix2.get_value(rc,c);
}
outMatrix.set_value(r,c,val);
}
}
return outMatrix;
}
// Multiply a MatrixSym and MatrixSym and output a MatrixSym
template<unsigned int ROWS, unsigned int COLS, unsigned int INNER>
MatrixSym<ROWS,COLS> multiply (MatrixSym<ROWS,INNER>& inMatrix1, MatrixSym<INNER,COLS>& inMatrix2) {
//MatrixSym<ROWS,COLS> outMatrixSym;
MatrixSym<ROWS,COLS> outMatrix;
for (unsigned int r = 0; r < ROWS; r++) {
for (unsigned int c = 0; c < COLS; c++) {
double val = 0.0;
for (unsigned int rc = 0; rc < INNER; rc++) {
val += inMatrix1.get_value(r,rc)*inMatrix2.get_value(rc,c);
}
outMatrix.set_value(r,c,val);
}
}
return outMatrix;
}
int main()
{
Matrix<3,3> A;
MatrixSym<3> S;
Matrix<3,3> AtimesA = multiply(A,A);
Matrix<3,3> AtimesS = multiply(A,S);
Matrix<3,3> StimesA = multiply(S,A);
MatrixSym<3> StimesS = multiply(S,S);
// Make sure that symmetric matrix S is indeed smaller than A
std::cout << "sizeof(A)/sizeof(double) = " << sizeof(A)/sizeof(double) << std::endl;
std::cout << "sizeof(S)/sizeof(double) = " << sizeof(S)/sizeof(double) << std::endl;
return 0;
}
输出:
sizeof(A)/sizeof(double) = 9
sizeof(S)/sizeof(double) = 15
我尝试过的
- 如果我尝试让函数使用
MatrixAbstract作为参数,我需要使用模板参数,因为我不能将NUMEL作为模板参数。此外,我无法为返回值实例化MatrixAbstract。 - 我不知道如何为
Matrix或MatrixSym模板化函数。我的直觉是这是解决它的方法,但我不明白如何为模板化类输入模板化函数,但仍然能够使用ROWS和COLS作为模板参数。
template<class InMatrix1Type, class InMatrix2Type, class OutMatrixType, unsigned int ROWS, unsigned int COLS, unsigned int INNER>
OutMatrixType<ROWS,COLS> multiply (InMatrix1Type<ROWS,INNER>& inMatrix1, InMatrix2Type<INNER,COLS>& inMatrix2)
给我一个以
开头的编译器错误error: ‘OutMatrixType’ is not a template
OutMatrixType<ROWS,COLS> multiply (InMatrix1Type<ROWS,INNER>& inMatrix1, InMatrix2Type<INNER,COLS>& inMatrix2)
^~~~~~~~~~~~~
【问题讨论】:
-
您是否使用部分模板专业化 - en.wikipedia.org/wiki/Partial_template_specialization ?
-
继承在这里是错误的工具。将您的
multiply函数编写为一个模板,该模板接受两个类型参数,一个用于每个矩阵。编写一个“普通”Matrix类,它提供(如果我正在快速浏览您的代码)get_value(unsigned, unsigned)返回对这些索引值的引用。编写第二个SymmetricMatrix类,该类提供get_value(unsigned, unsigned),该类返回对这些索引处的值的引用。multiply不关心它得到的值是来自完整矩阵还是来自对称(较小)矩阵。 -
除非您是出于学习目的,否则请考虑使用现有的矩阵库。
-
@PeteBecker、
Matrix和SymmetricMatrix几乎相同,只是它们存储数据的方式不同。对于这种情况,继承不是最好的方法吗?我的代码中的每个矩阵都有许多其他成员函数和属性,而且我还有第三种专用矩阵类型,它使用更少的存储空间(与SymmetricMatrix不同。我不想复制和粘贴每种矩阵类型的代码。 -
我使用旧的 Matrix 库 Newmat11。 SymmetricMatrix 使用的内存确实比 Matrix 少,但它使用动态内存分配。