अजगर और पीपी का उपयोग करके पायथन 2: 3 मिनट में n = 15
इसके अलावा सिर्फ एक सरल जानवर बल। यह देखने के लिए दिलचस्प है, कि मुझे लगभग वही गति मिलती है, जो कुरो नेको को सी ++ के साथ मिलती है। मेरा कोड n = 12
लगभग 5 मिनट में पहुंच सकता है । और मैं इसे केवल एक वर्चुअल कोर पर चलाता हूं।
संपादित करें: के एक कारक द्वारा खोज स्थान को कम करें n
मैंने देखा, कि जब मैं पुनरावृति करता हूं, तो एक चक्रीय वेक्टर मूल वेक्टर के रूप में संभाव्यता (समान संख्या) के समान संख्याओं A*
का A
उत्पादन करता है । उदाहरण के लिए वेक्टर ही संभावनाओं वैक्टर में से प्रत्येक के रूप में है , , , और जब एक यादृच्छिक चुनने । इसलिए मुझे इन 6 वैक्टरों में से प्रत्येक पर पुनरावृत्ति नहीं करनी है, लेकिन केवल 1 के बारे में है और इसके साथ बदलें ।A
B
(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)
B
count[i] += 1
count[i] += cycle_number
इससे जटिलता कम हो Theta(n) = 6^n
जाती है Theta(n) = 6^n / n
। इसलिए n = 13
यह मेरे पिछले संस्करण के रूप में उपवास के बारे में 13 गुना है। यह n = 13
लगभग 2 मिनट 20 सेकंड में गणना करता है। के लिए n = 14
यह अभी भी थोड़ा धीमा है। इसमें लगभग 13 मिनट लगते हैं।
संपादन 2: मल्टी-कोर-प्रोग्रामिंग
अगले सुधार से वास्तव में खुश नहीं हैं। मैंने कई कोर पर अपने कार्यक्रम को निष्पादित करने का प्रयास करने का भी फैसला किया। मेरे 2 + 2 कोर पर अब मैं n = 14
लगभग 7 मिनट में गणना कर सकता हूं । केवल 2 सुधार का एक कारक।
इस github रेपो में लिंक उपलब्ध है: लिंक । मल्टी-कोर प्रोग्रामिंग बनाता है थोड़ा बदसूरत है।
संपादन 3: A
वैक्टर और B
वैक्टर के लिए खोज स्थान कम करना
मैंने वैक्टर के लिए उसी दर्पण-समरूपता को देखा A
जैसा कि कुरोइ नेको ने किया था। अभी भी यकीन नहीं है, यह क्यों काम करता है (और अगर यह प्रत्येक के लिए काम करता है n
)।
B
वैक्टर के लिए खोज स्थान को कम करना थोड़ा चालाक है। मैंने itertools.product
अपने स्वयं के फ़ंक्शन के साथ वैक्टर ( ) की पीढ़ी को बदल दिया । मूल रूप से, मैं एक खाली सूची से शुरू करता हूं और इसे स्टैक पर रखता हूं। जब तक स्टैक खाली नहीं होता है, मैं एक सूची को हटा देता हूं, अगर यह उसी के समान नहीं है n
, तो मैं 3 अन्य सूचियां (-1, 0, 1 जोड़कर) उत्पन्न करता हूं और उन्हें स्टैक पर धकेलता हूं। मेरी सूची में लंबाई समान है n
, मैं रकम का मूल्यांकन कर सकता हूं।
अब जब मैं स्वयं वैक्टर तैयार करता हूं, तो मैं उन्हें इस आधार पर फ़िल्टर कर सकता हूं कि मैं योग = 0 तक पहुंच सकता हूं या नहीं। जैसे अगर मेरा वेक्टर A
है (1, 1, 1, 0, 0)
, और मेरा वेक्टर B
दिखता है (1, 1, ?, ?, ?)
, मुझे पता है, कि मैं ?
मूल्यों के साथ नहीं भर सकता , ताकि A*B = 0
। इसलिए मुझे B
फॉर्म के उन सभी 6 वैक्टरों पर ध्यान नहीं देना है (1, 1, ?, ?, ?)
।
हम इस पर सुधार कर सकते हैं, यदि हम मानों को नजरअंदाज करते हैं। 1. जैसा कि सवाल में कहा गया है, के लिए मान A081671i = 1
क्रम के हैं । उन लोगों की गणना करने के कई तरीके हैं। मैं सरल पुनरावृत्ति चुनता हूं :। चूंकि हम मूल रूप से समय में गणना कर सकते हैं , इसलिए हम अधिक वैक्टर को फ़िल्टर कर सकते हैं । जैसे और । हम इन सभी वैक्टरों के लिए वैक्टर, जहां पहले , को अनदेखा कर सकते हैं । मुझे आशा है कि आप अनुसरण कर सकते हैं। यह शायद सबसे अच्छा उदाहरण नहीं है।a(n) = (4*(2*n-1)*a(n-1) - 12*(n-1)*a(n-2)) / n
i = 1
B
A = (0, 1, 0, 1, 1)
B = (1, -1, ?, ?, ?)
? = 1
A * cycled(B) > 0
इसके साथ मैं n = 15
6 मिनट में गणना कर सकता हूं ।
4 संपादित करें:
त्वरित रूप से कार्यान्वित की गई कुरोइ नेको के महान विचार, जो कहता है, B
और -B
वही परिणाम उत्पन्न करता है। स्पीडअप x2। कार्यान्वयन केवल एक त्वरित हैक है, हालांकि। n = 15
3 मिनट में।
कोड:
पूरा कोड देखने के लिए Github । निम्नलिखित कोड केवल मुख्य विशेषताओं का प्रतिनिधित्व है। मैंने आयातों को छोड़ दिया, मल्टीकोर प्रोग्रामिंग, परिणाम छपाई, ...
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
उपयोग:
आपको pypy (Python 2 !!! के लिए) इंस्टॉल करना होगा। समानांतर अजगर मॉड्यूल को पाइथन 3 के लिए पोर्ट नहीं किया गया है। फिर आपको समानांतर अजगर मॉड्यूल pp-1.6.4.zip को स्थापित करना होगा । इसे cd
फोल्डर में निकालें और कॉल करें pypy setup.py install
।
तब आप मेरे कार्यक्रम को कॉल कर सकते हैं
pypy you-do-the-math.py 15
यह स्वचालित रूप से सीपीयू की संख्या निर्धारित करेगा। कार्यक्रम खत्म करने के बाद कुछ त्रुटि संदेश हो सकते हैं, बस उन्हें अनदेखा करें। n = 16
आपकी मशीन पर संभव होना चाहिए।
आउटपुट:
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%
नोट्स और विचार:
- मेरे पास 2 कोर और 4 थ्रेड्स के साथ एक i7-4600m प्रोसेसर है। इससे कोई फर्क नहीं पड़ता कि मैं 2 या 4 धागे का उपयोग करता हूं। सीपीयू-उपयोग 2 थ्रेड्स के साथ 50% और 4 थ्रेड्स के साथ 100% है, लेकिन इसमें अभी भी उतना ही समय लगता है। मुझे पता नहीं क्यों। मैंने जाँच की, कि प्रत्येक थ्रेड में केवल आधा डेटा होता है, जब 4 थ्रेड्स होते हैं, परिणाम की जाँच की, ...
- मैं बहुत सारी सूचियों का उपयोग करता हूं। पायथन भंडारण में बहुत कुशल नहीं है, मुझे बहुत सारी सूचियों को कॉपी करना है, ... इसलिए मैंने इसके बजाय पूर्णांक का उपयोग करने के बारे में सोचा। मैं वेक्टर ए में बिट्स 00 (0 के लिए) और 11 (1 के लिए) और बिट्स 10 (-1 के लिए), 00 (0 के लिए) और 01 (1 के लिए) वेक्टर बी में उत्पाद के लिए उपयोग कर सकता हूं। ए और बी में, मुझे केवल
A & B
01 और 10 ब्लॉकों की गणना और गणना करनी होगी । साइकिल को वेक्टर को स्थानांतरित करने और मास्क का उपयोग करने के साथ किया जा सकता है, ... मैंने वास्तव में यह सब लागू किया है, आप इसे जीथब पर मेरे कुछ पुराने कमिट्स में पा सकते हैं। लेकिन यह सूचियों की तुलना में धीमा हो गया। मुझे लगता है, pypy वास्तव में सूची संचालन का अनुकूलन करता है।