如何加速指数时间码

时间:2013-12-10 15:23:45

标签: python performance algorithm

我正在写一个模拟。我需要解决的问题如下。

我得到一个长度为t的随机二进制向量l(python中的列表)。然后,我对相同长度的二进制矢量进行采样,并测量每个采样矢量和t之间的汉明距离(即对齐的不匹配数)并存储结果。我想确定长度为l的二进制向量与目前找到的距离是否相容。显然t是,但也可能是其他许多人。

我的代码如下。

import random
import itertools
import operator

l=23
t = [random.randint(0,1) for b in range(l)]
stringsleft = set(itertools.product([0,1],repeat=l))

xcoords = []
ycoords = []
iters = l
for i in xrange(iters):
    print i, len(stringsleft)
    xcoords.append(i)
    ycoords.append(math.log(len(stringsleft)))
    pattern = [random.randint(0,1) for b in range(l)]
    distance = sum(itertools.imap(operator.ne, pattern, t))
    stringsleft = stringsleft.intersection(set([y for y in stringsleft if sum(itertools.imap(operator.ne, pattern, y)) == distance]))

不幸的是,它非常慢并且使用了大量内存而且如果我将l增加到30则根本不起作用。是否有可能加快解决l=30的问题?

更新
我通过用整数替换列表进行了一次小优化,现在它与l=26一起运行。

l=26
t = random.randint(0,2**l)
stringsleft = set(range(2**l))
xcoords = []
ycoords = []
iters = l
for i in xrange(iters):
    print i, len(stringsleft)
    if (len(stringsleft) > 1):
        xcoords.append(i)
        ycoords.append(math.log(len(stringsleft),2))
    pattern = random.randint(0,2**l)
    distance = bin(pattern ^ t).count('1')
    stringsleft = stringsleft.intersection(set([y for y in stringsleft if bin(pattern ^ y).count('1') == distance]))

阻止我进入l=30的问题是RAM的使用而不是时间。

3 个答案:

答案 0 :(得分:2)

我一直在想这个,我最后编写的程序基本上是Sneftel的方法。起初,没有选择,我们有汉明距离列表。然后说我们为第一个值选择1,那么所有具有0的序列只有在序列的其余部分与汉明距离兼容时才兼容 - 1.与1相同。

我最初也有一个递归版本,但是使用堆栈将其更改为循环,以便我可以使用yield将其转换为生成兼容序列的生成器。

我做的一个优化是,如果有汉明距离的猜测&gt; l / 2,我翻转0和1,以便新猜测保证汉明距离<= l / 2.

如果l = 30,我会得到不错的表现,不过这取决于猜测的数量和它们的幸运程度。

由于我早期的Mastermind想法,我仍然会想到试图找出'序列'的'猜测'。

代码:

import random

LENGTH = 30
NUMGUESSES = 20


def guess():
    return [random.randint(0, 1) for i in range(LENGTH)]

SEQUENCE = guess()
GUESSES = [guess() for i in range(NUMGUESSES)]


def hamming(a, b):
    return sum(aelem != belem for aelem, belem in zip(a, b))


# Flip if hamming > LENGTH / 2
mid = LENGTH / 2
for i in range(NUMGUESSES):
    if hamming(SEQUENCE, GUESSES[i]) > mid:
        GUESSES[i] = [1 - g for g in GUESSES[i]]

HAMMINGS = [hamming(SEQUENCE, g) for g in GUESSES]

print "Sequence:", SEQUENCE
print
for h, g in zip(HAMMINGS, GUESSES):
    print "Guess and hamming:", g, h
print


def compatible_sequences(guesses, hammings):
    # Use a stack instead of recursion, so we can make this a generator.
    stack = []
    # Start: we have chosen nothing yet, and the hammings have start values
    stack.append(([], hammings))

    while stack:
        so_far, hammingsleft = stack.pop()

        if -1 in hammingsleft:
            # Skip, choices so far are incompatible with the guesses
            continue

        if len(so_far) == LENGTH:
            # Success if all the Hamming distances were exactly correct
            if all(h == 0 for h in hammingsleft):
                yield so_far
            continue

        # Not done yet, add choices 0 and 1 to the queue
        place_in_guess = len(so_far)
        for choice in (1, 0):
            stack.append(
                (so_far + [choice],
                 [h - (g[place_in_guess] != choice)
                  for h, g in zip(hammingsleft, guesses)]))

print "Compatible sequences:"
for nr, sequence in enumerate(compatible_sequences(GUESSES, HAMMINGS), 1):
    print nr, sequence

答案 1 :(得分:1)

编辑:我错了。在Mastermind中,你也知道正确的颜色数量,但不是在正确的位置。这改变了可能的解决方案的数量,因此在这两个问题之间没有明显的确切转换,因此我无法在下面得出结论。暂时留下答案,也许这有助于有人思考这个问题。

我回答:

坏消息,它至少是NP完全的。

你的问题让我想起游戏 Mastermind Wikipedia)。在那个页面上,他们还提到了“Mastermind可满足性问题:给出一套双色Mastermind猜测和答案,是否有正确的猜测?

因此问题的信息比你的信息略多:Mastermind在正确的位置给出正确颜色的数量(==长度减去Hammond距离),加上错误位置的正确颜色数量。并且他们只试图确定可能性的数量是否>根据{{​​3}},这个问题是NP完全的。

答案 2 :(得分:1)

回溯算法可以在这里工作。状态将是(部分)向量和每个示例向量的剩余汉明距离。给定状态,您尝试追加0,并减少每个在该点中具有1的向量的汉明距离。如果任何距离低于零,解决方案是不允许的;否则,你递减。然后用1做同样的事情。一旦矢量完成,如果所有距离都为零,则输出它。

这仍然是指数时间,但应该快得多。