METHINKS IT IS A WEASEL
Posted feedbacks - Python
ごくごく素直にPythonで実装しました。増やす数(MULTIPLY)が3だと収束しなかったので、5にしてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import random
GOAL = "METHINKSITISAWEASEL"
DOMAIN = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
SET_SIZE = 300
MULTIPLY = 5
def create_random():
s = ""
for i in range(len(GOAL)):
s += random.choice(DOMAIN)
return s
def initial_set():
s = []
for i in range(SET_SIZE):
s += [create_random()]
return s
def mutate(s):
i = random.randrange(0, len(s))
result = s[:i] + random.choice(DOMAIN) + s[i+1:]
return result
def mutate_set(s):
result = []
for e in s:
for i in range(MULTIPLY):
result.append(mutate(e))
return result
def distance(s):
d = 0
for c1, c2 in zip(s, GOAL):
if c1 != c2:
d += 1
return d
def sorted_set(s):
work = [(distance(e), e) for e in s]
def mycmp(e1, e2):
return cmp(e1[0], e2[0])
work.sort(mycmp)
return work
def main():
s = initial_set()
i = 0
while True:
new_s = mutate_set(s)
s = [e for (d,e) in sorted_set(new_s)[:SET_SIZE]]
print "%04d: %2d %s"%(i + 1, distance(s[0]), s[0])
if s[0] == GOAL:
break
i += 1
if __name__=='__main__':
main()
|
収束しないのでmutationしないものも次世代に持ち越してしまうようしてしまいましたが・・・。
ng = ng + list(g.spawn_mutant()) + [g]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | #!/usr/bin/python
# -*- encoding=us-ascii -*-
#
import random
class Gene(object):
seed = 0
base_alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
goal = "METHINKSITISAWEASEL"
memoize = dict()
def generate_rnd_code(self):
return ''.join([random.choice(self.base_alpha) for i in range(len(self.goal))])
def __init__(self, code=None):
if code is None:
self.code = self.generate_rnd_code()
else:
self.code = code
def score(self):
def score(goal, target):
if goal:
diff = ord(goal[0]) - ord(target[0])
return diff * diff + score(goal[1:], target[1:])
#return abs(diff) + score(goal[1:], target[1:])
else:
return 0
s = score(self.goal, self.code)
return s
def which_base_to_mutate(self):
return random.randint(0, len(self.goal)-1)
def substitute_candidates(self, base, count):
#cand = self.base_alpha.replace(base, '')
cand = self.base_alpha[:]
cand=list(cand)
cand.remove(base)
random.shuffle(cand)
return cand[:count]
def spawn_mutant(self, n_children=None):
if n_children is None:
n_children = 3
nth = self.which_base_to_mutate()
old_base = self.code[nth]
for new_base in self.substitute_candidates(old_base, n_children):
yield Gene(code= self.code[:nth] + new_base + self.code[nth+1:])
class GeneVat(object):
def __init__(self, mass, n_children):
self.genes = [Gene() for i in range(mass)]
self.n_children = n_children
self.mass = mass
def create_ng(self):
ng = list()
for g in self.genes:
ng = ng + list(g.spawn_mutant()) + [g]
return ng
def filter(self, xs):
def cmp_by_score(x, y):
xs = x.score()
ys = y.score()
if xs < ys:
return -1
elif xs > ys:
return 1
else:
assert(xs == ys)
return 0
xs.sort(cmp_by_score)
return xs[:self.mass]
def evolve(self):
self.genes = self.filter(self.create_ng())
def head(self):
for g in self.genes[:5]:
print g.score(), g.code
vat = GeneVat(300, 3)
vat.head()
i = 0
while vat.genes[0].score()!= 0:
i += 1
vat.evolve()
print 'generation %i'%i
vat.head()
|
お題を次のように変更しました。
1. 目標文字列は "METHINKS IT IS LIKE A WEASEL" を使う。
2. お題では変化させた文字列3通りだけをソートするようになってい(ると思い)ますが、収束を保証できないので、元の文字列も残すようにする。
3. 変化は3通りでなくて、1通りとする。
手元で一回走らせた限りでは、200回程度で収束しました。
1. 目標文字列は "METHINKS IT IS LIKE A WEASEL" を使う。
2. お題では変化させた文字列3通りだけをソートするようになってい(ると思い)ますが、収束を保証できないので、元の文字列も残すようにする。
3. 変化は3通りでなくて、1通りとする。
手元で一回走らせた限りでは、200回程度で収束しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import string
import random
import itertools
def main():
goal = "METHINKS IT IS LIKE A WEASEL"
count = 300
def char():
return random.choice(string.ascii_uppercase + " ")
a = ["".join(char() for _ in goal) for _ in xrange(count)]
for generation in itertools.count(1):
def key(s):
return sum(int(c1 != c2) for c1, c2 in itertools.izip(goal, s))
a.sort(key=key)
del a[count:]
print "%4d: %s" % (generation, a[0])
if a[0] == goal:
break
for s in a[:]:
i = random.randint(0, len(s) - 1)
a.append(s[:i] + char() + s[i+1:])
if __name__ == '__main__':
main()
|



ytakenaka
#6287()
Rating4/8=0.50
ランダムな文字からMETHINKS IT IS A WEASELを作るプログラムを作れ。
簡単に流れを書いてみます。
1:ランダムな20文字を持つ文字列をもった300個作ります。
2:その文字列が"METHINKSITISAWEASEL"に近いものからソートします。
3:それぞれの文字列のなか1文字を別の文字に変化させたものを3つ用意します。
4:それを2:のソートをして上位300個残す。(900個あるうちで上位300個残すということです。)
5:以後3:と4:を繰り返す。
ランダムな文字変化は大文字だけでいいです。簡単にするために空白文字を外してあります。
METHINKS IT IS WEASELができたら終了。3と4の間でソートしたもので一番上位のものを毎回表示させると変化が楽しめます。:-)
Rickard Dawkinsがブラインドウォッチメイカー(現題:盲目の時計職人)の3章で書いていた有名なものです。さらに一般化してもらってもいいです。
参考
[ reply ]