如何优化这种组合算法?

时间:2019-01-04 00:09:04

标签: c++ algorithm parallel-processing

我正在编写一个分子动力学程序,该程序需要吸收一个分子中的原子并找到它们可能键合的方式。为此,我有一个Atom对象向量,并使用以下算法生成组合对:

    void CombinationKN(std::vector<std::vector<int>> &indices, int K, int N) {
        std::string bitmask(K, 1);
        bitmask.resize(N, 0);

        do {
            /* This loop takes forever with larger N values (approx. 3000) */
            std::vector<int> indexRow;

            for (int i = 0; i < N; i++)
            {
                if (bitmask[i]) indexRow.push_back(i);
            }

            indices.push_back(indexRow);
        } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
    }

这是一种简单的N选择K算法(即返回的索引可以包含(1,2),但不能包含(2,1)),在我的情况下,N是分子中的原子数,而K是2。 / p>

然后我像这样调用算法:

void CalculateBondGraph(const std::vector<Atom *> &atoms, std::map<int, 
    std::map<int, double>> &bondGraph, ForceField *forceField) {
    int natoms = atoms.size();

    std::vector<std::vector<int>> indices;

    utils::CombinationKN(indices, 2, natoms);

    for (auto &v : indices) {
        int i = v[0];
        int j = v[1];

        /*... Check if atoms i and j are bonded based on their coordinates.*/
    }
}

此算法的问题在于,对于具有3000+原子的大分子,它需要永久完成。我曾考虑过将其并行化(特别是与OpenMP并行化),但是即使那样,该工作也仍必须拆分到几个线程中,并且仍然需要大量时间才能完成。我需要一种优化此算法的方法,以便计算组合不会花费很长时间。任何帮助表示赞赏。

谢谢你, 维卡斯

1 个答案:

答案 0 :(得分:1)

如果CombinationKNK小得多,并且N大,那么{ {1}}比N小得多,否则您将很快耗尽内存。

请注意,每个有效的K都是严格小于N的{​​{1}}整数的单调递增序列,反之亦然。直接生成这些代码很容易:

index_row

此外,如果您要对这些组合进行的唯一操作是遍历它们,那么就没有理由浪费存储全部列表所需的(可能非常大量的)内存。上述功能包含在需要时从上一个生成下一个的过程。