在犰狳中,如何解释子矩阵上的查找结果

时间:2015-03-17 12:16:23

标签: c++ armadillo

考虑以下代码,使用Armadillo在矩阵的指定行和列中查找前7个(首先搜索列):

using namespace arma;

uvec2 firstEqual7(const mat& X, const uvec& rows, const uvec& cols)
{
    const uword findCount = 1;
    uvec results = find(X.submat(rows, cols) == 7, findCount);
    if (results.empty()) throw std::logic_error("no 7 found!");
    return ind2sub(X, results[0]);
}

这有两个问题。首先,find为每个结果提供了一个矢量化索引,因此要将其转换为行和列,我们必须像MATLAB' s ind2sub一样调用函数,但令人惊讶的是,Armadillo中不存在。好吧,这很痛苦,但我可以用两行自己写一个。 (但我提到它以防有人知道更好的方法。)

更大的问题是结果是索引进入子矩阵,例如如果X为100x100但rows=cols={98,99},则右下角由find(...)==3而不是find(...)==9999表示。我怎么能得到绝对结果?

一种选择是:

using namespace arma;

uvec2 firstEqual7(const mat& X, const uvec& rows, const uvec& cols)
{
    const uword findCount = 1;
    auto submatOfX = X.submat(rows, cols);  // DO NOT DO THIS!
    uvec results = find(submatOfX == 7, findCount);
    if (results.empty()) throw std::logic_error("no 7 found!");
    uvec2 submatIndices = ind2sub(submatOfX, results[0]);
    return uvec2{rows[submatIndices[0]], cols[submatIndices[1]]}; 
}

我认为这将会运行(假设我们已经实现了ind2sub),但效率非常低。问题涉及这样一个事实:submatOfX实际上不是一个矩阵而是一个小代理类型,因此Armadillo不需要将所有子矩阵元素复制到一个新矩阵中来执行查找操作。但是将其传递给ind2sub会隐式地将其转换为mat,这会使矩阵副本完全发生!

继续使用这个可能的解决方案,我可以在类似矩阵的类型上设置ind2sub模板,以便直接传入代理。这可能会起作用,但对于我原本希望的功能非常短暂而言似乎相当复杂。更重要的是,犰狳中的代理类型并没有真正记录在案,而且我不认为用户是打算弄乱他们的,所以我担心在变量中保留一个,甚至简单地说,有点脆弱。有没有人有更好的想法?

1 个答案:

答案 0 :(得分:0)

在没有任何答案的情况下,我认为结论必须是Armadillo的类似MATLAB的语法对于像这样的任务来说还不够强大。对于适合一行的小东西来说它很不错,但如果它更复杂,那么我们就不得不自己拼出迭代。可以说下面的代码至少和第一个代码片段一样清晰,尽管稍长一些。

using namespace arma;

// NOTE: rows and cols are now logical vectors (i.e. {1 0 1 1 0 ...}),
// rather than vectors of indices (i.e. {0, 2, 3, ...})
uvec2 firstEqual7(const mat& X, const uvec& rows, const uvec& cols)
{
    for (uword c = 0; c < X.n_cols; ++c) {
        if (!cols(c)) continue;
        for (uword r = 0; r < X.n_rows; ++r) {
            if (!rows(r)) continue;
            if (X(r, c) == 7) {
                return uvec2{r, c};
            }
        }
    }
    throw std::logic_error("no 7 found!");
}

请注意,外部循环是列而内部循环是行,这一点非常重要。矩阵由Armadillo按列存储,因此以这种方式迭代通过内存进行而不是跳跃,这会加快速度,因为我们获得了更多的缓存命中率。