我正在写一个模拟。我需要解决的问题如下。
我得到一个长度为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的使用而不是时间。
答案 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)
我回答:
坏消息,它至少是NP完全的。
你的问题让我想起游戏 Mastermind (Wikipedia)。在那个页面上,他们还提到了“Mastermind可满足性问题:给出一套双色Mastermind猜测和答案,是否有正确的猜测?
因此问题的信息比你的信息略多:Mastermind在正确的位置给出正确颜色的数量(==长度减去Hammond距离),加上错误位置的正确颜色数量。并且他们只试图确定可能性的数量是否>根据{{3}},这个问题是NP完全的。
答案 2 :(得分:1)
回溯算法可以在这里工作。状态将是(部分)向量和每个示例向量的剩余汉明距离。给定状态,您尝试追加0,并减少每个在该点中具有1的向量的汉明距离。如果任何距离低于零,解决方案是不允许的;否则,你递减。然后用1做同样的事情。一旦矢量完成,如果所有距离都为零,则输出它。
这仍然是指数时间,但应该快得多。