【问题标题】:Efficient way to perform bit permutations based on a vector of integers?基于整数向量执行位排列的有效方法?
【发布时间】:2018-06-02 17:27:21
【问题描述】:

我有一组 64 位整数,我需要在其上应用一定数量的“对称运算”。对称操作只是一系列位排列,以 {i0,i1,i2,..} 形式存储在 int 的向量中,其中 bit[0]->bit[i0], bit[1]->bit[i1 ],等等...实际上,我只是使用前 N 位,其中 N 是在运行时确定的,但原则上可以达到 64。

例如,我正在使用 N=4,输入是整数 3 或 0011,并且我有 4 个对称操作存储在向量对称操作的向量中

symmetry_ops[0] = {0,1,2,3};
symmetry_ops[1] = {1,2,3,0};
symmetry_ops[2] = {2,3,0,1};
symmetry_ops[4] = {3,0,1,2};

我想要一个函数,它返回通过将这些操作应用于 3 获得的 4 个整数,即 0011、0110、1100 和 1001。这个例子很简单,但实际上排列可能比仅仅移动到离开了。

我编写了以下简单(天真的?)代码:

std::vector<unsigned long> apply_symmetries(const std::vector<std::vector<unsigned> > &symmetry_ops, unsigned long state)
{
   unsigned N = symmetry_ops[0].size();
   std::vector<unsigned long> s_moved(symmetry_ops.size(),0);
   for (unsigned i = 0; i < N; i++) {
     unsigned long s_i = (state&(1UL<<i))>>i; // extracts bit i in state
     for (unsigned op = 0; op != symmetry_ops.size(); op++)
       s_moved[op] = s_moved[op]|(s_i<<symmetry_ops[op][i]);
   }
   return s_moved;
}

它对整数“状态”执行所有对称操作。我只是在 i 上的循环中一个接一个地进行,首先将其存储在 s_i 中,然后为每个对称操作移动它。

知道,这是我的程序中最耗时的部分之一,因为典型的大小是 ~100-200 对称操作,适用于 ~10^10 整数,N 约为 40。代码正常工作,但我想知道这个功能是否可以优化?

提前致谢。

【问题讨论】:

    标签: c++ bit-manipulation


    【解决方案1】:

    首先,如果您在代码中添加 cmets 来解释什么是什么,将会有所帮助。还要选择描述性变量名,不要为变量名选择“s_i”或“s_moved”,这会使代码不可读。 'symmetry_ops' 是一个不错的名称选择,'state' 也是如此,其他的则不然。

    无论如何,为了加快你的代码速度:如果你有一个对称操作将位 i 发送到位 x,而下一个对称操作将位 x 发送到位 y,则将两者结合起来与将位 i 发送到位 y 相同一个操作。

    所以从单独循环操作开始。

    对于每个对称操作,将其应用于前一个,然后通过循环将新的用作前一个。然后你可以为整个事物构建一个单一的对称操作。我正在编写伪代码来说明这一点。

    identity_op = {0, 1, 2, 3, 4, 5, 6, 7} //vector of int, maps each bit to same bit
    previous_op = identity_op
    for each op { //op is vector of ints, op[i] maps bit i to op[i]
        //combine op with prev_op to make a new prev_op
        for each i in op { 
            prev_op[i] = op[prev_op[i]] //bit i is mapped by prev_op and then mapped again by op, giving new value for prev_op
        }
    } 
    combined_op = previous_op
    apply combined_op to the bits, this is only place you need to to bit shifting
    

    您的 C++ 代码看起来不错,只需重写以使用此新算法。

    【讨论】:

    • 我认为我的问题没有很好地提出。我进行了编辑以使其更清楚,我认为您的建议不正是我想要的?!
    • 好吧,您的代码与我的提议具有相同的顺序复杂性,O(n) 其中 n 是操作数(我认为 O(n) 是最小值),但我的代码避免做任何或'ing 或每次迭代的位移。每次迭代都简单得多,因此速度更快。此外,您通过每个操作 N 次,其中 N 是位数,我的每个操作只通过一次。也更快。
    • 您的代码获取每个位,然后将每个操作应用于该位。我的每个操作只遍历一次以创建组合操作,然后将组合操作应用于每个位。
    • 嗯,也许是我,但我看不出你的方法将如何生成我,比如说,通过将每个 Symmetry_ops[] 应用于初始状态获得的 Nop 整数......?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 2013-08-05
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    相关资源
    最近更新 更多