Pypy ve pp: n = 15 kullanarak 3 dakikada python 2
Ayrıca basit bir kaba kuvvet. İlginçti, neredeyse C ++ ile kuroi neko ile aynı hızı elde ediyorum. Kodum n = 12yaklaşık 5 dakika içinde ulaşabilir. Ve sadece bir sanal çekirdek üzerinde çalıştırıyorum.
edit: Arama alanını bir faktör kadar azaltır n
Döngüsüz bir vektör vektörünün A*, tekrarladığımda Aorijinal vektörle aynı sayıları (aynı sayılar) ürettiğini fark ettim . EG vektör vektörlerinin her biriyle aynı olasılıkları vardır , , , ve rasgele seçme . Bu nedenle bu 6 vektörlerin her yineleme zorunda, ama sadece yaklaşık 1 ve değiştirmeyin ile .AB(1, 1, 0, 1, 0, 0)(1, 0, 1, 0, 0, 1)(0, 1, 0, 0, 1, 1)(1, 0, 0, 1, 1, 0)(0, 0, 1, 1, 0, 1)(0, 1, 1, 0, 1, 0)Bcount[i] += 1count[i] += cycle_number
Bu karmaşıklığı azaltır Theta(n) = 6^niçin Theta(n) = 6^n / n. Bu nedenle n = 13önceki sürümümden yaklaşık 13 kat daha hızlı. n = 13Yaklaşık 2 dakika 20 saniye içinde hesaplar . Çünkü n = 14hala biraz fazla yavaş. Yaklaşık 13 dakika sürer.
değiştir 2: Çok çekirdekli programlama
Bir sonraki gelişmeden gerçekten memnun değil. Programımı birden çok çekirdek üzerinde yürütmeye de karar verdim. 2 + 2 çekirdeklerimde şimdi n = 14yaklaşık 7 dakika içinde hesaplayabilirim . Sadece 2 gelişme faktörü.
Kod bu github deposunda kullanılabilir: Link . Çok çekirdekli programlama biraz çirkin.
edit 3: AVektörler ve Bvektörler için arama alanını azaltma
AKuroi neko'nun yaptığı gibi vektörler için aynı ayna simetrisini fark ettim . Hala neden işe yaradığından emin değilim (ve her biri için işe yarayıp yaramadığını n).
BVektörler için arama alanının azaltılması biraz daha zekidir. Vektörlerin ( itertools.product) neslini kendi fonksiyonuyla değiştirdim. Temel olarak, boş bir listeyle başlıyorum ve bir yığına koyuyorum. Yığın boş olana kadar, bir listeyi kaldırırım, eğer uzunluğu ile aynı değilse, nbaşka 3 liste (-1, 0, 1 ekleyerek) oluşturur ve bunları yığının üzerine iterim. Bir liste ile aynı uzunlukta nolan toplamları değerlendirebilirim.
Şimdi vektörleri kendim ürettiğime göre, toplam = 0'a ulaşıp ulaşamayacağımıza bağlı olarak bunları filtreleyebilirim. Benim vektör eğer Ör Aolduğunu (1, 1, 1, 0, 0)ve benim vektör Bgörünüyor (1, 1, ?, ?, ?), biliyorum, ben doldurmak olamaz ?böylece, değerlerle A*B = 0. Bu yüzden B, formun bu 6 vektörünü yinelemek zorunda değilim (1, 1, ?, ?, ?).
Biz değerleri için, söz konusu belirtildiği gibi 1. değerlerini göz ardı edersek biz bu konuda artırabilir i = 1dizisi olan A081671 . Bunları hesaplamanın birçok yolu vardır. Basit tekrarını seç: a(n) = (4*(2*n-1)*a(n-1) - 12*(n-1)*a(n-2)) / n. i = 1Temelde hiçbir zaman hesaplayamadığımız için daha fazla vektörü filtreleyebiliriz B. Örneğin A = (0, 1, 0, 1, 1)ve B = (1, -1, ?, ?, ?). İlkleri vektörleri görmezden gelebiliriz ? = 1, çünkü A * cycled(B) > 0tüm bu vektörler için. Umarım takip edebilirsin. Muhtemelen en iyi örnek değil.
Bununla n = 156 dakika içinde hesaplayabilirim .
düzenleme 4:
Çabuk, söylüyor kuroi neko harika bir fikir, hayata Bve -Baynı sonuçlar üretir. Hızlanma x2. Ancak uygulama sadece hızlı bir saldırıdır. n = 153 dakika içinde.
Kod:
Kodun tamamı için Github'u ziyaret edin . Aşağıdaki kod sadece ana özelliklerin bir gösterimidir. İthalatları, çok çekirdekli programlamayı, sonuçları yazdırmayı, ...
count = [0] * n
count[0] = oeis_A081671(n)
#generating all important vector A
visited = set(); todo = dict()
for A in product((0, 1), repeat=n):
if A not in visited:
# generate all vectors, which have the same probability
# mirrored and cycled vectors
same_probability_set = set()
for i in range(n):
tmp = [A[(i+j) % n] for j in range(n)]
same_probability_set.add(tuple(tmp))
same_probability_set.add(tuple(tmp[::-1]))
visited.update(same_probability_set)
todo[A] = len(same_probability_set)
# for each vector A, create all possible vectors B
stack = []
for A, cycled_count in dict_A.iteritems():
ones = [sum(A[i:]) for i in range(n)] + [0]
# + [0], so that later ones[n] doesn't throw a exception
stack.append(([0] * n, 0, 0, 0, False))
while stack:
B, index, sum1, sum2, used_negative = stack.pop()
if index < n:
# fill vector B[index] in all possible ways,
# so that it's still possible to reach 0.
if used_negative:
for v in (-1, 0, 1):
sum1_new = sum1 + v * A[index]
sum2_new = sum2 + v * A[index - 1 if index else n - 1]
if abs(sum1_new) <= ones[index+1]:
if abs(sum2_new) <= ones[index] - A[n-1]:
C = B[:]
C[index] = v
stack.append((C, index + 1, sum1_new, sum2_new, True))
else:
for v in (0, 1):
sum1_new = sum1 + v * A[index]
sum2_new = sum2 + v * A[index - 1 if index else n - 1]
if abs(sum1_new) <= ones[index+1]:
if abs(sum2_new) <= ones[index] - A[n-1]:
C = B[:]
C[index] = v
stack.append((C, index + 1, sum1_new, sum2_new, v == 1))
else:
# B is complete, calculate the sums
count[1] += cycled_count # we know that the sum = 0 for i = 1
for i in range(2, n):
sum_prod = 0
for j in range(n-i):
sum_prod += A[j] * B[i+j]
for j in range(i):
sum_prod += A[n-i+j] * B[j]
if sum_prod:
break
else:
if used_negative:
count[i] += 2*cycled_count
else:
count[i] += cycled_count
Kullanımı:
Pypy yüklemeniz gerekiyor (Python 2 için !!!). Paralel python modülü Python 3 için taşınmaz . Sonra paralel python modülünü pp-1.6.4.zip kurmanız gerekir . cdKlasöre ayıklayın ve arayın pypy setup.py install.
Sonra programımı
pypy you-do-the-math.py 15
Otomatik olarak cpu sayısını belirler. Programı bitirdikten sonra bazı hata mesajları olabilir, sadece dikkate almayın. n = 16makinenizde mümkün olmalıdır.
Çıktı:
Calculation for n = 15 took 2:50 minutes
1 83940771168 / 470184984576 17.85%
2 17379109692 / 470184984576 3.70%
3 3805906050 / 470184984576 0.81%
4 887959110 / 470184984576 0.19%
5 223260870 / 470184984576 0.05%
6 67664580 / 470184984576 0.01%
7 30019950 / 470184984576 0.01%
8 20720730 / 470184984576 0.00%
9 18352740 / 470184984576 0.00%
10 17730480 / 470184984576 0.00%
11 17566920 / 470184984576 0.00%
12 17521470 / 470184984576 0.00%
13 17510280 / 470184984576 0.00%
14 17507100 / 470184984576 0.00%
15 17506680 / 470184984576 0.00%
Notlar ve fikirler:
- 2 çekirdekli ve 4 yivli i7-4600m işlemcim var. 2 veya 4 iş parçacığı kullanırsam önemli değil. İşlemci kullanımı 2 iş parçacığı ile% 50 ve 4 iş parçacığı ile% 100'dür, ancak yine de aynı miktarda zaman alır. Neden bilmiyorum. 4 iş parçacığı olduğunda, her iş parçacığı sadece veri yarıya kadar olduğunu kontrol ettim, sonuçları kontrol, ...
- Çok fazla liste kullanıyorum. Python depolamakta oldukça verimli değil, birçok listeyi kopyalamak zorundayım, ... Bunun yerine bir tamsayı kullanmayı düşündüm. A vektöründe 00 (0 için) ve 11 (1 için) bitlerini ve B vektöründe 10 (-1 için), 00 (0 için) ve 01 (1 için) bitlerini kullanabilirim. Ürün için A ve B, sadece
A & B01 ve 10 blokları hesaplamak ve saymak zorunda kalacaktım . Bisiklete binme vektörü değiştirerek ve maskeleri kullanarak yapılabilir, ... Aslında tüm bunları uyguladım, Github'daki bazı eski taahhütlerimde bulabilirsiniz. Ancak, listelerden daha yavaş olduğu ortaya çıktı. Sanırım pypy liste işlemlerini gerçekten optimize ediyor.