অ্যালগরিদম তুলনা — বাস্তব বেঞ্চমার্কিং
এই পাঠে যা শিখবেন
- কেন wall-clock সময়ের বদলে অপারেশন কাউন্ট দিয়ে অ্যালগরিদম তুলনা করা উচিত
- bubble sort-কে তুলনা-কাউন্টার দিয়ে ইনস্ট্রুমেন্ট করা
- increasing input size-এ (১০, ২০, ৪০, ৮০) গণনা করে growth trend পর্যবেক্ষণ করা এবং তাত্ত্বিক Θ(n²) প্রেডিকশনের সাথে ক্রস-চেক করা
- থিওরেটিক্যাল বিশ্লেষণ ও এম্পিরিক্যাল বেঞ্চমার্কিং-এর পার্থক্য বোঝা
১ · কেন Wall-Clock সময় নয়, অপারেশন কাউন্ট
একটি অ্যালগরিদমের বাস্তব গতি সরাসরি সেকেন্ডে পরিমাপ করলে মনে হতে পারে সবচেয়ে সহজ পদ্ধতি — কিন্তু এটি বিভ্রান্তিকর। একই কোড ভিন্ন কম্পিউটারে, ভিন্ন প্রোগ্রামিং ভাষায়, এমনকি একই মেশিনে ভিন্ন মুহূর্তে (background প্রসেসের কারণে) সম্পূর্ণ ভিন্ন সময় নিতে পারে। এর বদলে আমরা মৌলিক অপারেশনের সংখ্যা গোনা — যেমন তুলনা (comparison), সোয়াপ, বা রিকার্সিভ কল — যা হার্ডওয়্যার-নিরপেক্ষ এবং সরাসরি তাত্ত্বিক বিশ্লেষণের সাথে তুলনাযোগ্য।
২ · ওয়ার্কড উদাহরণ — Bubble Sort ইনস্ট্রুমেন্টেড
Bubble sort-এর তত্ত্ব বলে সবচেয়ে খারাপ কেসে (ইতিমধ্যে উল্টো-সাজানো ইনপুট) তুলনা সংখ্যা হলো: $$\text{comparisons} = (n-1) + (n-2) + \cdots + 1 = \frac{n(n-1)}{2}$$ এটি $\Theta(n^2)$ — L39-এর কোয়াড্রেটিক ক্লাস। এই সূত্রটি এম্পিরিক্যালি (বাস্তবে চালিয়ে) যাচাই করি চারটি বিভিন্ন ইনপুট সাইজে — $n=10, 20, 40, 80$।
def bubble_sort_count(arr):
a = list(arr)
n = len(a)
comparisons = 0
for i in range(n - 1):
for j in range(n - 1 - i):
comparisons += 1
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
return a, comparisons
print(f"{'n':>4} | {'comparisons':>12} | {'n^2':>8} | {'comparisons/n^2':>16}")
for n in [10, 20, 40, 80]:
arr = list(range(n, 0, -1)) # worst case — সম্পূর্ণ উল্টো ক্রমে সাজানো ইনপুট
sorted_arr, comps = bubble_sort_count(arr)
ratio = comps / (n ** 2)
print(f"{n:>4} | {comps:>12} | {n**2:>8} | {ratio:>16.4f}")
# সূত্র n(n-1)/2-এর সাথে মিলিয়ে দেখা
expected = n * (n - 1) // 2
assert comps == expected, f"n={n}-এ সূত্রের সাথে মিলছে না!"
print("\nসব মান n(n-1)/2 সূত্রের সাথে হুবহু মিলে গেছে — যাচাই সম্পন্ন।")
comparisons/n² অনুপাত $n=10$-এ প্রায় $0.45$, $n=80$-এ প্রায় $0.494$ — n বাড়ার সাথে সাথে এই
অনুপাত ধীরে ধীরে $0.5$-এর দিকে এগিয়ে যাচ্ছে (যেহেতু $n(n-1)/2 = n^2/2 - n/2$, এবং $n$ বড় হলে $-n/2$ পদটি
তুলনামূলকভাবে নগণ্য হয়ে যায়)। অনুপাতটি প্রায় কনস্ট্যান্ট থাকা-ই হলো $\Theta(n^2)$-এর এম্পিরিক্যাল
স্বাক্ষর — যদি এটি ক্রমাগত বাড়তেই থাকত, তাহলে প্রকৃত জটিলতা $n^2$-এর চেয়ে বেশি হতো ($n^3$ বা তার বেশি)।
৩ · তুলনা: Python-এর বিল্ট-ইন sorted()
Python-এর বিল্ট-ইন sorted() Timsort ব্যবহার করে, যার তাত্ত্বিক জটিলতা $\Theta(n\log n)$
(L31-এ merge sort-এর জন্য দেখা ক্লাস)। যেহেতু sorted()-এর অভ্যন্তরীণ তুলনা C ভাষায় বাস্তবায়িত,
আমরা সরাসরি এর ভেতরের প্রতিটি তুলনা গুনতে পারি না — কিন্তু ধারণাগতভাবে: $n=80$-এ bubble sort-এর প্রায় $3160$টি
তুলনা লাগে (উপরের কোড দেখুন), যেখানে $n\log_2 n \approx 80\times6.3\approx504$ — অর্থাৎ Timsort তাত্ত্বিকভাবে
প্রায় ৬ গুণ কম তুলনায় কাজ শেষ করবে। এটাই দেখায় কেন সঠিক জটিলতা ক্লাস বাছাই বাস্তবে সত্যিকারের পার্থক্য তৈরি
করে, এমনকি n তুলনামূলক ছোট থাকলেও।
৪ · তাত্ত্বিক বনাম এম্পিরিক্যাল বিশ্লেষণ
পুরো M8 মডিউল জুড়ে আমরা তাত্ত্বিক বিশ্লেষণ শিখেছি — একটি অ্যালগরিদমের কোড না চালিয়েই, শুধু তার গঠন দেখে গাণিতিকভাবে বলে দেওয়া এটি asymptotically ($n\to\infty$) কেমন আচরণ করবে। এম্পিরিক্যাল বেঞ্চমার্কিং (এই পাঠ) ভিন্ন কাজ করে — বাস্তবে অ্যালগরিদম চালিয়ে নিশ্চিত করে তত্ত্ব সঠিক প্রমাণিত হচ্ছে কি না, এবং তত্ত্ব যা লুকিয়ে রাখে (কনস্ট্যান্ট ফ্যাক্টর, ছোট $n$-এ আচরণ) তা প্রকাশ করে। দুটোই প্রয়োজনীয় — তত্ত্ব দিক-নির্দেশনা দেয়, পরিমাপ তা নিশ্চিত করে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ একই কোড দুটি ভিন্ন কম্পিউটারে চালালে wall-clock সময় ভিন্ন হতে পারে কেন — এটি কীভাবে অ্যালগরিদম তুলনাকে অবিশ্বস্ত করে তোলে?
CPU গতি, ক্যাশ সাইজ, ব্যাকগ্রাউন্ড প্রসেস, এমনকি প্রোগ্রামিং ভাষার ইন্টারপ্রিটার/কম্পাইলার ভিন্নতা — এসব কিছুই wall-clock সময়কে প্রভাবিত করে, কিন্তু এগুলোর কোনোটিই অ্যালগরিদমের প্রকৃত দক্ষতা সম্পর্কে কিছু বলে না। একটি O(n²) অ্যালগরিদম একটি অতি দ্রুত মেশিনে একটি O(n log n) অ্যালগরিদমের চেয়ে ছোট $n$-এ দ্রুত মনে হতে পারে, কিন্তু $n$ বড় হলে এই ব্যবধান উল্টে যাবে। অপারেশন কাউন্ট হার্ডওয়্যার থেকে সম্পূর্ণ স্বাধীন, তাই এটি প্রকৃত তুলনার ভিত্তি।
প্র ০২ যদি comparisons/n² অনুপাত n বাড়ার সাথে সাথে ক্রমাগত বাড়তেই থাকত (কনস্ট্যান্টের দিকে না এগিয়ে), এর মানে কী দাঁড়াতো?
এর মানে হতো প্রকৃত জটিলতা $\Theta(n^2)$-এর চেয়ে বেশি — হয়তো $\Theta(n^2 \log n)$ বা $\Theta(n^3)$। যদি অনুপাত একটি কনস্ট্যান্টের কাছাকাছি স্থির থাকে (আমাদের উদাহরণে $0.5$-এর দিকে), সেটাই নিশ্চিত করে হর ($n^2$) সঠিক জটিলতা ক্লাস বেছে নেওয়া হয়েছে। এটি এম্পিরিক্যালি জটিলতা ক্লাস "অনুমান" করার একটি বাস্তব কৌশল — বিভিন্ন হর দিয়ে ভাগ করে দেখা কোনটায় অনুপাত স্থির থাকে।
প্র ০৩ L44-এর ক্যাপস্টোনে একটি গ্রাফ অ্যালগরিদমের দাবি করা জটিলতা O(V+E) — এটি কীভাবে এম্পিরিক্যালি যাচাই করবেন?
এই পাঠের ঠিক একই পদ্ধতি প্রয়োগ করা যাবে — অ্যালগরিদমকে ইনস্ট্রুমেন্ট করে প্রতিটি vertex/edge ভিজিট বা
প্রসেস হওয়ার সময় একটি কাউন্টার বাড়ানো, তারপর বিভিন্ন আকারের গ্রাফে ($V, E$ বাড়িয়ে) চালিয়ে দেখা মোট
কাউন্ট $V+E$-এর সমানুপাতিক থাকে কি না (যেমন count/(V+E) অনুপাত স্থির থাকা)। ঠিক bubble
sort-এর comparisons/n²-এর মতোই এই যাচাই কাজ করবে।
অনুশীলন
-
পরীক্ষা করুন: কোড সেলের তালিকায়
n=160যোগ করুন এবং Run চাপুন। আগে থেকে অনুমান করুনcomparisons/n²অনুপাত কত হবে, তারপর মিলিয়ে দেখুন।$n=160$-এ comparisons $=160\times159/2=12{,}720$, এবং $n^2=25{,}600$, তাই অনুপাত $12720/25600 \approx 0.4969$ — আরও কাছাকাছি $0.5$-এর দিকে, নিশ্চিত করে যে প্যাটার্নটি $n$ বাড়ার সাথে সাথে অব্যাহত থাকে।
-
ডিজাইন করুন: ভাবুন কীভাবে insertion sort-কে একইভাবে তুলনা-সংখ্যা দিয়ে ইনস্ট্রুমেন্ট করবেন এবং bubble sort-এর সাথে তুলনা করবেন একই $n$ মানগুলোতে।
Insertion sort-এও worst case (উল্টো-সাজানো ইনপুট) $\Theta(n^2)$ — তাই bubble sort-এর মতোই একটি তুলনা-কাউন্টার ভেরিয়েবল যোগ করে প্রতিটি এলিমেন্ট-তুলনার সময় তা বাড়াতে হবে। উভয়ই একই জটিলতা ক্লাসে পড়লেও, তাদের প্রকৃত তুলনা সংখ্যার কনস্ট্যান্ট ফ্যাক্টর ভিন্ন হতে পারে — এম্পিরিক্যাল তুলনাই বলে দেবে কোনটি বাস্তবে দ্রুত।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৪৪টি পাঠ পরবর্তী পাঠ — চূড়ান্ত ক্যাপস্টোন প্রকল্প — পুরো কোর্সের সব মডিউল একসাথে প্রয়োগ করে।
- চূড়ান্ত ক্যাপস্টোন প্রকল্প L44 · শেষ পাঠ গ্রাফ থিওরি, RSA, কম্বিনেটরিক্স ও অ্যালগরিদম বিশ্লেষণ — একটি বাস্তব সমস্যায় একত্রিত।
- Data Structures & Algorithms কোর্স সঙ্গী কোর্স এই পাঠের বেঞ্চমার্কিং কৌশল বাস্তব ডেটা স্ট্রাকচার ও অ্যালগরিদমে প্রয়োগ করতে DSA কোর্সটিও দেখুন।