পাইপিয়ন এবং পিপি ব্যবহার করে পাইথন 2: 3 মিনিটের মধ্যে n = 15
এছাড়াও কেবল একটি সাধারণ উদ্দীপনা। দেখতে আকর্ষণীয়, আমি সি ++ এর সাথে কুরোই নেখোর প্রায় একই গতি পেয়েছি। আমার কোডটি n = 12
প্রায় 5 মিনিটের মধ্যে পৌঁছতে পারে । এবং আমি কেবল এটি একটি ভার্চুয়াল কোর উপর চালানো।
সম্পাদনা করুন: এর একটি উপাদান দ্বারা অনুসন্ধানের স্থান হ্রাস করুন n
আমি লক্ষ্য করেছি, যে একটি আবর্তিত ভেক্টর A*
এর A
সম্ভাব্যতা (একই নম্বর) হিসাবে একই সংখ্যার উৎপন্ন মূল বাহক হিসেবে 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
। অতএব আমাকে এই 6 টি ভেক্টরের প্রত্যেকটির উপরে পুনরাবৃত্তি করতে হবে না, তবে কেবল 1 টি এবং এর সাথে প্রতিস্থাপন 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 এর মানগুলিকে অগ্রাহ্য করি তবে প্রশ্নে উল্লিখিত হিসাবে মানগুলির জন্য i = 1
ক্রম A081671 রয়েছে । সেগুলি গণনা করার অনেকগুলি উপায় রয়েছে। আমি সহজ পুনরাবৃত্তি নির্বাচন করুন: 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:
দ্রুত Kuroi Neko এর মহান ধারণা, যা, বলছেন যে বাস্তবায়িত B
এবং -B
একই ফলাফল উৎপন্ন হয়। স্পিডআপ এক্স 2। বাস্তবায়ন শুধুমাত্র দ্রুত হ্যাক, যদিও। n = 15
3 মিনিটে
কোড:
সম্পূর্ণ কোডের জন্য গিথুব দেখুন । নিম্নলিখিত কোডটি কেবল প্রধান বৈশিষ্ট্যগুলির উপস্থাপনা। আমি আমদানি, মাল্টিকোর প্রোগ্রামিং, ফলাফল মুদ্রণ, ...
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
ব্যবহার:
আপনাকে পাইপি ইনস্টল করতে হবে (পাইথন 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%
নোট এবং ধারণা:
- আমার কাছে একটি আই 7-4600 মি প্রসেসর রয়েছে যার সাথে 2 টি কোর এবং 4 টি থ্রেড রয়েছে। আমি 2 বা 4 টি থ্রেড ব্যবহার করি না তবে কিছু যায় আসে না। সিপিইউ-ব্যবহার 2 টি থ্রেড সহ 50% এবং 4 টি থ্রেড সহ 100%, তবে এটি এখনও একই পরিমাণে সময় নেয়। কেন জানি না। আমি পরীক্ষা করে দেখেছি যে প্রতিটি থ্রেডের কেবলমাত্র অর্ধ পরিমাণ তথ্য থাকে, যখন 4 টি থ্রেড থাকে, ফলাফলগুলি পরীক্ষা করে, ...
- আমি প্রচুর তালিকাগুলি ব্যবহার করি। পাইথন সংরক্ষণে বেশ দক্ষ নয়, আমাকে প্রচুর তালিকাগুলি অনুলিপি করতে হবে, ... সুতরাং আমি পরিবর্তে একটি পূর্ণসংখ্যা ব্যবহার করার কথা ভেবেছিলাম। আমি ভেক্টর এ-তে বিটস 00 (0 এর জন্য) এবং 11 (1 এর জন্য), এবং বিটস 10 (-1 এর জন্য), 00 (0) এবং 01 (1 এর জন্য) ভেক্টর বিতে ব্যবহার করতে পারি A এবং B এর, আমাকে কেবল
A & B
01 এবং 10 ব্লক গণনা করতে হবে এবং তা গণনা করতে হবে। সেক্টরটি ভেক্টর স্থানান্তর এবং মাস্কগুলি ব্যবহার করে করা যেতে পারে, ... আমি আসলে এগুলি বাস্তবায়ন করেছি, আপনি এটি গিথুব সম্পর্কে আমার কিছু পুরানো প্রতিশ্রুতিতে খুঁজে পেতে পারেন। তবে দেখা গেল তালিকার তুলনায় ধীর হতে হবে। আমার ধারণা, পাইপি সত্যিই তালিকার ক্রিয়াকলাপকে অনুকূল করে তোলে।