缓存矩阵的策略和技术

时间:2009-01-14 15:10:08

标签: c++ caching

如前所述,我目前正在开发一个小型线性代数库,用于个人项目。矩阵实现为C ++向量和元素赋值(a(i,j)= v;)被委托给向量元素的赋值。对于我的项目,我需要解决大量的方方程式系统,为了做到这一点,我实现了方形矩阵的LU分解(高斯消元)。在当前的实现中,我避免每次通过缓存L和U矩阵来重新计算LU分解,问题是因为我将元素赋值委托给向量,所以我找不到一种方法来说明矩阵正在改变以及是否重新计算因子分解。关于如何解决这个问题的任何想法?

谢谢

5 个答案:

答案 0 :(得分:4)

template<class T>
class matrix {
public:
    class accessor {
    public:
        accessor(T& dest, matrix& parent) : dest(dest), parent(parent) { }
        operator T const& () const { return dest; }
        accessor& operator=(T const& t) { dest = t; parent.invalidate_cache(); return *this; }
    private:
        T& dest;
        matrix& parent;
    };

    // replace those with actual implementation..
    accessor operator()(int x, int y) {
        static T t; return accessor(t, *this);
    }
    T const& operator()(int x, int y) const {
        static T t; return t;
    }

private:
    void invalidate_cache() { cout << "Cache invalidated !!\n"; }
    vector<T> impl;
};

感谢## iso-c ++ @ irc.freenode.net进行一些有用的更正

答案 1 :(得分:3)

如果我理解正确,您需要在执行代码期间检查矩阵是否已更改。

好吧,矢量不支持这样的功能。但是,您可以做的是编写自己的Matrix类,向其添加此类功能并使用它而不是向量。

示例实现可以是:

class Matrix {
public:
    Matrix() : hasChanged(false) {}

    double setElement(int i, int j, double value) {
        innerStorage[i][j] = value;
        hasChanged = true;
    }

    double getElement(int i, int j) {
        return innerStorage[i][j];
    }

    void clearHasChangedFlag() {
        hasChanged = false;
    }

private:
    vector<vector<double> > innerStorage;
    bool hasChanged;
}

答案 2 :(得分:0)

您的描述听起来就像您正在进行LU分解一样。从内存的角度来看,这肯定更有效。这意味着在执行分解时覆盖矩阵值。如果这是真的,那么“被改变以及是否重新计算因子分解”是一个有争议的问题。使用LU分解覆盖原始矩阵时会丢失原始矩阵。

如果您没有覆盖原始文件,那么每当您为矩阵元素赋予新值时,您也会想要重新计算分解。我建议你不要这样做。这对我来说似乎效率低下。如果客户想要改变许多值,他们可能不希望在完成所有操作之前支付另一个LU分解的成本。

您可以尝试使用工厂界面进行矩阵变换/分解。这是一个简单的将接收矩阵并返回(分解)矩阵。你可以保持原来的矩阵;返回值是一个新实例。您可以更改原件,然后将其传递给工厂以重新计算LU分解。这会花费你的记忆力,这对于非常大的基质来说可能是一个问题。

在Java中,我会这样写:

public interface MatrixDecomposition
{  
    Matrix decompose(Matrix original);
}

在C ++中,它是一个纯虚函数。 (太久了 - 我记不起语法了。)

还有其他类型的分解(例如,QR,SVD等),因此这种设计可以很好地适应您需要的那些。只需为界面编写另一个实现,Bob就是你的叔叔。

许多物理问题的特征是“稀疏”的基质,其具有在对角线周围聚集的非零值带宽和外部的零。如果使用不在带宽之外存储零值的特殊技术,则可以解决内存中较大的问题。

答案 3 :(得分:0)

Frederick建议的setElement和getElement版本是一个选项,但使用它太无聊了。我想用相同的语法访问(i,j)读取和写入,如果我正在修改矩阵,则不用打扰。可能最好的办法是让用户修改矩阵并委托他在判断必要时重新计算LU分解的责任。但它会很无聊。

答案 4 :(得分:0)

如何保留与最后一个LU分解一起使用的Matrix的完整隐藏副本,并在重新执行之前在O(n * m)时间内检查它?丑陋但可以工作。