基于整数向量执行位排列的有效方法?

时间:2018-06-02 17:27:21

标签: c++ bit-manipulation

我有一组64位整数,我需要在其上应用一定数量的“对称操作”。对称操作只是一组位置换,存储在int的向量中为{i0,i1,i2,..},其中位[0] - >位[i0],位[1] - >位[i1]​​等......事实上,我只是使用N个第一位,其中N是在运行时确定的,但原则上可以达到64位。

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

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;
}

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

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

提前致谢。

1 个答案:

答案 0 :(得分:0)

首先,如果您在代码中添加注释来解释什么是有用的,那将会有所帮助。同时选择描述性变量名,不要为变量名选择's_i'或's_moved',这会使代码不可读。 'symmetry_ops'对于一个名字来说是一个很好的选择,所以'state'也是如此,其他的并不是那么多。

无论如何,为了加速你的代码:如果你有一个对称操作,它将位i发送到位x,而下一个对称操作将位x发送到位y,那么组合这两个就像将位i发送到位y in一个操作。

首先,单独循环操作。

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

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 ++代码看起来很好,只需重写即可使用这种新算法。