পাঠ ০৫ · ৫৭-এর মধ্যে · মডিউল ২
Home / Courses / Design and Analysis of Algorithms / গ্রোথ রেট

ফাংশনের গ্রোথ রেট

Growth of functions — comparing complexity classes
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • আটটি প্রমিত গ্রোথ ক্লাসের নাম, ক্রম এবং এদের মধ্যেকার সম্পর্ক
  • কেন ছোট $n$-এ একটি ফাংশন আরেকটির চেয়ে বড় দেখালেও তা asymptotic তুলনায় কিছু প্রমাণ করে না
  • একটি সত্যিকারের কম্পিউটেশনাল পদ্ধতি — কোনো ফাংশন কখন আরেকটিকে চিরতরে ছাড়িয়ে যায় তা প্রোগ্রামগতভাবে বের করা
  • এই তুলনাগুলো কেন L04-এর RAM মডেলের সাথে সরাসরি সম্পর্কিত — "অপারেশন গোনা" আসলে এই গ্রোথ ক্লাসগুলোর একটির সাথে মিলিয়ে দেখা

১ · আটটি প্রমিত গ্রোথ ক্লাস

অ্যালগরিদম অ্যানালাইসিসে ইনপুট সাইজ $n$ বাড়লে রানটাইম কীভাবে বাড়ে তা বর্ণনা করতে কয়েকটি নির্দিষ্ট ফাংশন বারবার দেখা যায়। এদের মধ্যে $n \to \infty$ হলে একটি কঠোর ক্রম প্রতিষ্ঠিত আছে:

$$1 \;\ll\; \log n \;\ll\; n \;\ll\; n\log n \;\ll\; n^2 \;\ll\; n^3 \;\ll\; 2^n \;\ll\; n!$$

এখানে $f(n) \ll g(n)$ মানে "$g(n)$, $f(n)$-এর চেয়ে অসীমগুণ দ্রুত বাড়ে ($n$ যথেষ্ট বড় হলে)" — এটি L07-এ সংজ্ঞায়িত হওয়া little-o নোটেশনেরই একটি প্রাথমিক ইঙ্গিত। আপাতত এটিকে "বাম পাশেরটি ডান পাশেরটির চেয়ে ধীরে বাড়ে" হিসেবে পড়ুন।

১ log n n n log n n² n³ 2ⁿ n!
বাম থেকে ডানে ক্রমবর্ধমান গ্রোথ রেট — গাঢ় বাক্স দুটি (২ⁿ ও n!) "ইনট্র্যাক্টেবল" হিসেবে পরিচিত, বড় $n$-এ যেগুলো ব্যবহারিকভাবে অচল হয়ে যায়।
$O(1)$ — ধ্রুবক
ইনপুট সাইজ নির্বিশেষে একই সময় লাগে — যেমন অ্যারে ইনডেক্সিং।
$O(\log n)$ — লগারিদমিক
প্রতি ধাপে সমস্যা অর্ধেক হয়ে যায় — বাইনারি সার্চ (L17)।
$O(n)$ — লিনিয়ার
প্রতিটি এলিমেন্ট ঠিক একবার দেখা হয় — লিনিয়ার সার্চ (L08)।
$O(n\log n)$ — লিনিয়ারিদমিক
ডিভাইড অ্যান্ড কনকার সর্টিং — মার্জ সর্ট (L15)।
$O(n^2)$ — কোয়াড্রাটিক
প্রতিটি জোড়া তুলনা করা — নেইভ ডুপ্লিকেট-চেক (L01)।
$O(2^n)$, $O(n!)$ — এক্সপোনেনশিয়াল/ফ্যাক্টোরিয়াল
সব সাবসেট/পারমুটেশন — ব্যাকট্র্যাকিং (M8), ব্রুট-ফোর্স TSP (L57)।

২ · কোড সেল — প্রকৃত মান গণনা ও ক্রসওভার পয়েন্ট বের করা

নিচের কোড সেলে প্রতিটি ফাংশনের প্রকৃত মান $n = 1, 2, 4, 8, 16, 32$-এ গণনা করা হয়েছে, এবং তারপর একটি find_permanent_crossover ফাংশন লেখা হয়েছে যা কম্পিউটেশনালি খুঁজে বের করে ঠিক কোন $n$ থেকে একটি ফাংশন আরেকটির চেয়ে চিরতরে বড় থাকে (নির্দিষ্ট একটি পরীক্ষার সীমা পর্যন্ত)।

Python
import math

def const_f(n): return 1
def log_f(n): return math.log2(n) if n >= 1 else 0
def lin_f(n): return n
def linlog_f(n): return n * math.log2(n) if n >= 1 else 0
def quad_f(n): return n ** 2
def cube_f(n): return n ** 3
def exp_f(n): return 2 ** n
def fact_f(n): return math.factorial(n)

sizes = [1, 2, 4, 8, 16, 32]
header = f"{'n':>4} | {'log n':>8} | {'n':>6} | {'n log n':>10} | {'n^2':>8} | {'n^3':>10} | {'2^n':>14} | {'n!':>22}"
print(header)
for n in sizes:
    print(f"{n:>4} | {log_f(n):>8.2f} | {lin_f(n):>6} | {linlog_f(n):>10.2f} | "
          f"{quad_f(n):>8} | {cube_f(n):>10} | {exp_f(n):>14} | {fact_f(n):>22}")

def find_permanent_crossover(f, g, max_n=60):
    # সবচেয়ে ছোট n বের করে যেখান থেকে f(m) > g(m) সবসময় সত্য থাকে (n থেকে max_n পর্যন্ত)
    for n in range(1, max_n + 1):
        if all(f(m) > g(m) for m in range(n, max_n + 1)):
            return n
    return None

pairs = [
    ("log n", log_f, "১ (ধ্রুবক)", const_f),
    ("n log n", linlog_f, "n", lin_f),
    ("2^n", exp_f, "n^3", cube_f),
    ("n!", fact_f, "2^n", exp_f),
]

print("\nক্রসওভার পয়েন্ট (n=60 পর্যন্ত পরীক্ষা করে):")
for name_f, f, name_g, g in pairs:
    n0 = find_permanent_crossover(f, g)
    print(f"{name_f} > {name_g}  চিরতরে সত্য n = {n0} থেকে")

    
টেবিলে লক্ষ্য করুন $n=8$-এ $n^3 = 512$ কিন্তু $2^n = 256$ — অর্থাৎ এখানে $n^3$ বড়! কিন্তু find_permanent_crossover-এর আউটপুট দেখাচ্ছে $n=10$ থেকে $2^n$ চিরতরে $n^3$-কে ছাড়িয়ে যায় (আসলে $n=9$: $2^9=512 < 9^3=729$, কিন্তু $n=10$: $2^{10}=1024 > 10^3=1000$, এবং এরপর ব্যবধান শুধু বাড়তেই থাকে)। একইভাবে $n!$ মাত্র $n=4$ থেকেই $2^n$-কে চিরতরে ছাড়িয়ে যায় ($4!=24 > 2^4=16$) — ফ্যাক্টোরিয়াল গ্রোথ কতটা আক্রমণাত্মকভাবে দ্রুত তার একটি জ্বলন্ত উদাহরণ।

৩ · কেন এটি গুরুত্বপূর্ণ — RAM মডেলের সাথে সংযোগ

L04-এ আমরা দেখেছি RAM মডেলে প্রতিটি মৌলিক অপারেশন $O(1)$ সময় নেয় বলে ধরে নেওয়া হয় — তাই একটি অ্যালগরিদমের "গতি" বোঝাতে আমরা মোট অপারেশন সংখ্যা গণনা করি, এবং সেই গণনাটি সাধারণত এই আটটি ক্লাসের একটির সাথে মিলে যায়। বাস্তব জগতে পার্থক্যটি বিশাল: $n = 1{,}000{,}000$ হলে $\log_2 n \approx 20$, $n\log_2 n \approx 2 \times 10^7$, $n^2 = 10^{12}$ — আধুনিক কম্পিউটারেও এটি সেকেন্ডের বদলে ঘণ্টা লাগাতে পারে। আর $2^n$ বা $n!$-এর মতো ক্লাসে $n=1{,}000{,}000$ ব্যবহারিকভাবে কল্পনাতীত — মহাবিশ্বের বয়সের চেয়েও বেশি সময় লাগবে।

মূল কথা · Key takeaway

গ্রোথ ক্লাস তুলনা করার সময় একটি নির্দিষ্ট $n$-এর মান দেখে সিদ্ধান্ত নেওয়া বিভ্রান্তিকর — আসল প্রশ্ন হলো "$n$ যথেষ্ট বড় হলে কী ঘটে (চিরতরে)?" উপরের কোড সেল ঠিক এই প্রশ্নের উত্তর কম্পিউটেশনালি বের করে দেখিয়েছে। পরবর্তী পাঠ (L06)-এ আমরা এই "চিরতরে বড়/ছোট" ধারণাটিকেই $O$, $\Omega$, $\Theta$ নোটেশনে আনুষ্ঠানিকভাবে সংজ্ঞায়িত করব — $\exists\, c, n_0$ ব্যবহার করে ঠিক এই ধরনের দাবিগুলো প্রমাণযোগ্য করে তুলব।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ টেবিলে $n=8$-এ $n^3 = 512$, $2^n = 256$ — তাহলে কি $n^3$ অ্যালগরিদম $2^n$ অ্যালগরিদমের চেয়ে "খারাপ" গ্রোথ ক্লাস?

না। গ্রোথ ক্লাসের তুলনা একটি নির্দিষ্ট $n$-এ মান দেখে নয়, বরং $n \to \infty$ হলে আচরণ দেখে করা হয়। উপরের কোড সেল দেখিয়েছে $n=9$ পর্যন্ত $n^3$ বড় থাকতে পারে, কিন্তু $n=10$ থেকে $2^n$ চিরতরে এগিয়ে যায় এবং ব্যবধান ক্রমাগত বাড়তে থাকে। এই "সাময়িক ব্যতিক্রম" আসলে বেশ সাধারণ — এই কারণেই আমরা "স্থায়ী ক্রসওভার" (permanent crossover) খুঁজি, শুধু একটি $n$-এ তুলনা নয়।

প্র ০২ উপরের কোডে math.log2 ব্যবহার করা হয়েছে — যদি math.log (প্রাকৃতিক লগ, বেস $e$) বা math.log10 ব্যবহার করতাম, তাহলে কি গ্রোথ ক্লাসের সিদ্ধান্ত পাল্টে যেত?

না। যেকোনো দুটি বেসের লগারিদম একে অপরের সাথে একটি ধ্রুবক গুণিতক সম্পর্কে থাকে: $\log_b n = \dfrac{\log_2 n}{\log_2 b}$। যেহেতু $\dfrac{1}{\log_2 b}$ একটি ধ্রুবক (n-নির্ভর নয়), তাই $O(\log_2 n)$, $O(\ln n)$, এবং $O(\log_{10} n)$ — সবগুলো একই গ্রোথ ক্লাস প্রকাশ করে। এই কারণেই বিগ-ও নোটেশনে সাধারণত লগের বেস উল্লেখ করা হয় না — শুধু লেখা হয় $O(\log n)$।

প্র ০৩ যদি একটি সমস্যার জন্য আপনার কাছে $O(n!)$ সময় লাগা একটি ব্রুট-ফোর্স সমাধান থাকে, এবং ইনপুট সাইজ সবসময় $n \le 8$-এর মধ্যে থাকবে বলে নিশ্চিত জানেন, তাহলে কি এটি ব্যবহার করা যুক্তিসঙ্গত?

হ্যাঁ, বাস্তবিক অর্থে হতে পারে। $8! = 40{,}320$ — আধুনিক হার্ডওয়্যারে এটি চোখের পলকে হিসাব হয়ে যায়। গ্রোথ ক্লাসের গুরুত্ব দেখা যায় $n$ বড় হলে (যেমন $n=20$ হলে $20! \approx 2.4 \times 10^{18}$, যা ব্যবহারিকভাবে অসম্ভব)। এই কারণেই "সবচেয়ে ভালো" অ্যালগরিদম বেছে নেওয়া নির্ভর করে ইনপুট সাইজের বাস্তবসম্মত সীমার উপরেও — L57-এর ক্যাপস্টোনে আমরা ঠিক এই সিদ্ধান্তগুলো একটি সম্পূর্ণ কেস স্টাডিতে দেখব।

অনুশীলন

  1. চিন্তা করুন: pairs লিস্টে ("n!", fact_f, "n^3", cube_f) যোগ করলে কোন $n$ থেকে $n!$ চিরতরে $n^3$-কে ছাড়িয়ে যাবে বলে আপনার ধারণা?

    $n=6$ থেকে। $n=5$-এ $5! = 120 < 5^3 = 125$ (এখনও $n^3$ বড়), কিন্তু $n=6$-এ $6! = 720 > 6^3 = 216$, এবং এরপর ফ্যাক্টোরিয়ালের গ্রোথ এত দ্রুত যে এটি আর কখনো পিছিয়ে পড়ে না।

  2. পরীক্ষা করুন: find_permanent_crossover(exp_f, cube_f, max_n=5) কল করলে (অর্থাৎ পরীক্ষার সীমা $60$ থেকে কমিয়ে $5$ করলে) কী ফলাফল পাবেন বলে মনে হয়? কোড সেলে পরিবর্তন করে চালিয়ে দেখুন।

    ফলাফল হবে None — কারণ $2^n$ আসলে $n^3$-কে চিরতরে ছাড়িয়ে যায় $n=10$ থেকে, কিন্তু পরীক্ষার সীমা মাত্র $5$ পর্যন্ত হওয়ায় ফাংশনটি কখনোই "$n$ থেকে max_n পর্যন্ত সবসময় সত্য" এমন কোনো $n$ খুঁজে পায় না। এটি একটি গুরুত্বপূর্ণ শিক্ষা: কম্পিউটেশনাল যাচাইয়ের ফলাফল সবসময় পরীক্ষার সীমার উপর নির্ভরশীল — একটি প্রকৃত গাণিতিক প্রমাণ (যেমন L06-এ আমরা শিখব) এই সীমাবদ্ধতা থেকে মুক্ত, কারণ সেটি সব $n \ge n_0$-এর জন্য একবারে সত্য প্রমাণ করে, একটি নির্দিষ্ট সংখ্যক $n$ পরীক্ষা করে নয়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ অ্যাসিম্পটোটিক অ্যানালাইসিস, রিকারেন্স, ডিভাইড অ্যান্ড কনকার, গ্রিডি, DP, গ্রাফ অ্যালগরিদম, ব্যাকট্র্যাকিং, স্ট্রিং অ্যালগরিদম, অ্যামর্টাইজড অ্যানালাইসিস, NP-কমপ্লিটনেস ও অ্যাপ্রক্সিমেশন — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Data Structures & Algorithms কোর্স সহোদর কোর্স এই পাঠে উল্লেখিত অ্যালগরিদমগুলোর (লিনিয়ার সার্চ, মার্জ সর্ট) ইমপ্লিমেন্টেশন বিস্তারিত সেই কোর্সে দেখুন।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics, System Design, Cybersecurity, Cloud Computing & DevOps, Computer Networks, Operating Systems, Computer Architecture, Programming Languages & Compiler Design, Software Engineering & Git, Theory of Computation, Engineering Economics, Full-Stack Web Frameworks, Mobile App Development, Ethics in Computing & AI Safety, Software Testing & Quality Assurance ও Design and Analysis of Algorithms — সব এক জায়গায়।
আগের পাঠ
RAM মডেল অফ কম্পিউটেশন