找到一个乘数,可以将给定的索引转化为位形成。

huangapple go评论64阅读模式
英文:

Find a multiplier which multiplies given indices into a formation of bits

问题

我有一组索引和一组位掩码(集合大小相同,介于6到4096之间,但更接近较小的边界)。我还有一个称为超集的单一位掩码。我需要找到一个因子,对于任何给定的索引,如果我将该因子与索引和掩码按位与,然后与超集进行乘法运算,结果就是子集。这些掩码和因子都将是64位宽的。这个例子是8位的,因为在这里我无法写64位的掩码。

index=3 sub=00010000 => ((p * 3) & mask) == 00010000
index=5 sub=00100000 => ((p * 5) & mask) == 00100000

实际上,我的输入只是一组索引{i0,i1,... iN},一组掩码{s0,s1,... sN},和一个超集掩码。当然,所有的子集都是超集的子集。目前来说,对于不同的索引,可能会有相同的子集结果,但我很乐意接受不考虑这个约束的解决方案。

到目前为止,我尝试的最好办法就是猜测因子的随机数,并检查对于每个索引-子集对是否成立。如果不成立,我就尝试下一个数字。但对于这个问题的最小形式,我有13对这样的组合。由于蛮力算法是“O(2^n)”且具有非常大的常数因子,我找不到一个即使对于7对也成立的因子!

我想的是观察乘法的结果值。让我们从8位形式来看这个问题:(这里的a、b、c、d等表示如果乘法结果中的第i位被设置)

P * Index = 2^0*a + 2^1*b + 2^2*c + 2^3*d + 2^4*e + 2^5*f + 2^6*g + 2^7*h
P = (1a + 2b + 4c + 8d + 16e + 32f + 64g + 128h) / Index
现在我们希望P是整数,所以对模取余(假设Index是5,例如)
P = (1a + 2b + 4c + 3d + 1e + 2f + 4g + 3h) / 5
P = (1(a+e) + 2(b+f) + 4(c+g) + 3(d+h)) / 5

因此现在我们可以说,每个比特掩码,其集合位的总和乘以上述系数对5取模为0,就是一个有效的P * Index,然后我们可以通过简单的除法找到P。希望你理解我的意思。

但问题是,我不知道如何将这个扩展到多个索引-结果对,现在我真的不知道该怎么办。

英文:

I have a set of indices and a set of bit masks (the size of the sets is the same, and between 6-4096 but much closer to the lower bound). I also have a single bit mask which I will call the superset. I need to find a factor, that if for any index I have, if I multiply the factor and the index and mask bitand with the superset, the result is the subset. The masks and factor will all be 64-bit wide. This example is 8-bit cause I can't write 64-bit masks here obviously

mask = 00111000         ((p * index) & mask) == subset
index=3 sub=00010000 => ((p * 3) & mask) == 00010000
index=5 sub=00100000 => ((p * 5) & mask) == 00100000

Really, my input is just a set {i0, i1, ... iN} of indices, {s0, s1, ... sN} of masks, and a superset mask.
Of course, all the subsets are subsets of the super-set. For now, for different indices, there can be the same subset results, but I will be happy to receive soloutions that act as if this was not a constraint.

My best try for now is just guessing random numbers for the factor, and checking to see for each indice-subset pair if it holds true. If not, I go to the next number. But for the smallest form of this problem, I had 13 such pairs, but since the brute force algorithm is O(2^n) with a very large constant factor, I can't find a factor which holds true even for 7 pairs!

What I thought about is looking at the resulting values from the multiplication. Let's look at this problem from an 8-bit form: (Here a,b,c,d, etc mean if the i'th bit is set in the result of the multiplication)

P * Index = 2^0*a + 2^1*b + 2^2*c + 2^3*d + 2^4*e + 2^5*f + 2^6*g + 2^7*h
P = (1a + 2b + 4c + 8d + 16e + 32f + 64g + 128h) / Index
Now we want P to be integer, so do modulo (let's say Index is 5 for example)
P = (1a + 2b + 4c + 3d + 1e + 2f + 4g + 3h) / 5
P = (1(a+e) + 2(b+f) + 4(c+g) + 3(d+h)) / 5

So now we can say that every bit-mask that its sum of set bits multiplied by the coefficients above modulo 5 is 0, it's a valid P * Index, then we can find P by a simple divison. Hope you get me.

But the problem is I don't know how to extend this to multiple index-result pairs, and I really don't know what to do now.

答案1

得分: 1

你可以使用像z3这样的SMT求解器来实现这个功能。你可以为所有需要计算的变量创建变量,然后对它们设置约束条件。在这里,我假设你可以选择的值是p和索引,但从你的问题中还不太清楚。以下是一个完全未经测试的示例:

void solve(const std::vector<uint64_t>& subs, uint64_t mask) {
    using namespace z3;
    context c;
    solver s(c);
    expr p = c.bv_const("p", 64);
    std::vector<expr> indices;
    for (int i = 0; i < subs.size(); ++i)
        indices.push_back(c.bv_const(("indices_" + std::to_string(i)).c_str(), 9));

    for (int i = 0; i < subs.size(); ++i)
        s.add((p * zext(indices[i], 64 - 9) & mask) == subs[i]);

    if (s.check() == sat) {
        model m = s.get_model();
        uint64_t p_result = m.eval(p).get_numeral_uint64();
        std::vector<uint16_t> indices_result;
        for (int i = 0; i < subs.size(); ++i)
            indices_result.push_back(m.eval(indices[i]).get_numeral_uint64());
        // 处理结果的代码
    } else {
        // 没有解决方案
    }
}

希望这能帮助你实现你的目标。

英文:

You can use an SMT solver like z3 for this. You can create variables for all the things you want calculated and then set constraints on them. Here I'm assuming that the values you can choose are p and the indices, that is still not clear from your question. Completely untested example:

void solve(const std::vector&lt;uint64_t&gt;&amp; subs, uint64_t mask) {
    using namespace z3;
    context c;
    solver s(c);
    expr p = c.bv_const(&quot;p&quot;, 64);
    std::vector&lt;expr&gt; indices;
    for (int i = 0; i &lt; subs.size(); ++i)
        indices.push_back(c.bv_const((&quot;indices_&quot; + std::to_string(i)).c_str(), 9));

    for (int i = 0; i &lt; subs.size(); ++i)
        s.add((p * zext(indices[i], 64 - 9) &amp; mask) == subs[i]);

    if (s.check() == sat) {
        model m = s.get_model();
        uint64_t p_result = m.eval(p).get_numeral_uint64();
        std::vector&lt;uint16_t&gt; indices_result;
        for (int i = 0; i &lt; subs.size(); ++i)
           indices_result.push_back(m.eval(indices[i]).get_numeral_uint64());
        // do something with the result
    } else {
        // no solution
    }
}

huangapple
  • 本文由 发表于 2023年5月25日 03:50:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76326959.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定