পাঠ ১৮ · ৫৭-এর মধ্যে · মডিউল ৪
Home / Courses / Numerical Methods / রুঙ্গের ফেনোমেনন

রুঙ্গের ফেনোমেনন ও পিসওয়াইজ ইন্টারপোলেশন

Runge's phenomenon & piecewise interpolation
১১ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • রুঙ্গের ফেনোমেনন কী, এবং কেন এটি "বেশি ডেটা = বেশি নির্ভুল" ধারণাকে চ্যালেঞ্জ করে
  • কেন সমান-ব্যবধানের নোডে উঁচু-ডিগ্রি পলিনোমিয়াল ইন্টারপোলেশন কিনারায় অস্থিতিশীল হয়ে যায়
  • Python-এ সত্যিকারের গণনা দিয়ে এই ফেনোমেনন পর্যবেক্ষণ করা — ডিগ্রি বাড়ার সাথে এরর বাড়তে দেখা
  • পিসওয়াইজ-লিনিয়ার ইন্টারপোলেশন কীভাবে একই ডেটা দিয়ে অনেক বেশি স্থিতিশীল ফলাফল দেয়

১ · রুঙ্গের ফেনোমেনন কী

L16-L17-এ আমরা ধরে নিয়েছিলাম বেশি ডেটা পয়েন্ট মানেই স্বাভাবিকভাবে বেশি সঠিক ইন্টারপোলেশন। কিন্তু রুঙ্গের ফেনোমেননRunge's Phenomenonএকটি সুপরিচিত ঘটনা যেখানে সমান-ব্যবধানের নোডে উঁচু-ডিগ্রি পলিনোমিয়াল ইন্টারপোলেশনের এরর ইন্টারভালের কেন্দ্রে কমলেও কিনারায় নাটকীয়ভাবে বাড়তে থাকে — ডিগ্রি যত বাড়ে, কিনারার দোলন তত তীব্র হয়। (Runge's phenomenon, ১৯০১ সালে কার্ল রুঙ্গে আবিষ্কৃত) এই ধারণাকে ভুল প্রমাণ করে একটি নির্দিষ্ট শ্রেণীর ফাংশনের জন্য — বিশেষত যেগুলোর গ্রাফে তীক্ষ্ণ পরিবর্তন (steep curvature) আছে।

ক্লাসিক উদাহরণ হলো:

$$f(x) = \frac{1}{1 + 25x^2}, \quad x \in [-1, 1]$$

এই ফাংশনটি x = 0-এর কাছে তীক্ষ্ণভাবে বেঁকে যায় (একটি সরু "চূড়া"), আর ±1-এর কাছে অনেক সমতল। যখন এই ফাংশনকে সমান-ব্যবধানের নোডে স্যাম্পল করে একটি উঁচু-ডিগ্রি পলিনোমিয়াল ফিট করা হয়, পলিনোমিয়ালটি কেন্দ্রে ভালো ফিট করলেও কিনারার কাছে বন্য দোলন (wild oscillation) শুরু করে।

২ · একটি সত্যিকারের ডেমো — এরর বাড়তে দেখা

নিচের কোড সেলে n = 5, 11, 15, 21টি সমান-ব্যবধানের নোডে (অর্থাৎ ডিগ্রি 4, 10, 14, 20-এর পলিনোমিয়াল) লাগ্রাঞ্জ ইন্টারপোলেশন করে দুটো কিনারার-কাছের বিন্দুতে (x = 0.95, 0.98) এবং একটি কেন্দ্রের বিন্দুতে (x = 0.0) পরম এরর গণনা করা হয়েছে।

Python
def runge(x):
    return 1.0 / (1.0 + 25.0 * x**2)

def lagrange_interpolate(xs, ys, x):
    total = 0.0
    n = len(xs)
    for i in range(n):
        term = ys[i]
        for j in range(n):
            if j != i:
                term *= (x - xs[j]) / (xs[i] - xs[j])
        total += term
    return total

def equally_spaced(n, a=-1.0, b=1.0):
    return [a + i*(b-a)/(n-1) for i in range(n)]

for n in [5, 11, 15, 21]:
    xs = equally_spaced(n)
    ys = [runge(x) for x in xs]
    print(f"n = {n} নোড (ডিগ্রি {n-1} পলিনোমিয়াল):")
    for xt in [0.95, 0.98]:
        p = lagrange_interpolate(xs, ys, xt)
        true_v = runge(xt)
        err = abs(p - true_v)
        print(f"  x={xt}: P(x)={p:.6f}  true={true_v:.6f}  এরর={err:.6f}")
    xt = 0.0
    p = lagrange_interpolate(xs, ys, xt)
    true_v = runge(xt)
    print(f"  x={xt}: P(x)={p:.6f}  true={true_v:.6f}  এরর={abs(p-true_v):.6f}  (কেন্দ্র, তুলনার জন্য)")
    print()

    
ফলাফল স্পষ্ট এবং নাটকীয়: x = 0.95-এ এরর n=5-এ ০.২০, n=11-এ বেড়ে ১.৮৮, n=15-এ ৬.৯০, আর n=21-এ বিস্ফোরিত হয়ে ৩৯.৯৯-তে পৌঁছায় — যেখানে প্রকৃত ফাংশন মান মাত্র ০.০৪-এর কাছাকাছি! একই প্যাটার্ন x = 0.98-এও (এরর ০.০৯ → ১.১৯ → ৫.৮৮ → ৫৮.২৮)। অথচ কেন্দ্রের বিন্দু x = 0.0-তে এরর সবসময় প্রায় ০ থাকে — এটাই রুঙ্গের ফেনোমেননের বৈশিষ্ট্য: বেশি ডেটা পয়েন্ট আসলে কিনারায় ফলাফল আরও খারাপ করছে।

৩ · সমাধান — পিসওয়াইজ-লিনিয়ার ইন্টারপোলেশন

সমস্যাটি একক উঁচু-ডিগ্রি পলিনোমিয়ালে — পুরো ইন্টারভাল জুড়ে একটিমাত্র বাঁকানো কার্ভ জোর করে ফিট করানো। পিসওয়াইজ ইন্টারপোলেশন ভিন্ন কৌশল নেয়: পুরো ইন্টারভালকে ছোট ছোট সাব-ইন্টারভালে ভাগ করে প্রতিটিতে একটি সরল (নিচু-ডিগ্রি) ফাংশন ফিট করা — সবচেয়ে সহজ সংস্করণ হলো প্রতিটি দুই পাশের নোডের মধ্যে একটি সরলরেখা টানা (পিসওয়াইজ-লিনিয়ার)।

Python
def piecewise_linear(xs, ys, x):
    n = len(xs)
    for i in range(n-1):
        if xs[i] <= x <= xs[i+1]:
            t = (x - xs[i]) / (xs[i+1] - xs[i])
            return ys[i] + t*(ys[i+1]-ys[i])
    return None

n_pw = 21
xs_pw = equally_spaced(n_pw)
ys_pw = [runge(x) for x in xs_pw]

print(f"পিসওয়াইজ-লিনিয়ার ইন্টারপোলেশন, n = {n_pw} পয়েন্ট (উপরের একই n=21 ডেটাসেট, কিন্তু ডিগ্রি-২০ পলিনোমিয়ালের বদলে সরল রেখাংশ):")
for xt in [0.95, 0.98, 0.0]:
    p = piecewise_linear(xs_pw, ys_pw, xt)
    true_v = runge(xt)
    err = abs(p - true_v)
    print(f"  x={xt}: P_linear(x)={p:.6f}  true={true_v:.6f}  এরর={err:.6f}")

    
একই n = 21 ডেটাসেটে পিসওয়াইজ-লিনিয়ার ইন্টারপোলেশন দেয়: x = 0.95-এ এরর মাত্র ০.০০০৩২০, আর x = 0.98-এ মাত্র ০.০০০১৯৭ — ডিগ্রি-২০ পলিনোমিয়ালের এরর (যথাক্রমে ৩৯.৯৯ ও ৫৮.২৮) থেকে প্রায় এক লক্ষ গুণেরও বেশি ছোট! একই সংখ্যক ডেটা পয়েন্ট, কিন্তু কৌশল বদলে দিলে ফলাফল সম্পূর্ণ ভিন্ন — এটাই এই পাঠের মূল শিক্ষা।
কারণ: বেসিস ফাংশনের আচরণ
উঁচু-ডিগ্রি লাগ্রাঞ্জ বেসিস পলিনোমিয়াল Lᵢ(x) কিনারার কাছে অত্যন্ত বড় মান নিতে পারে (সাব-ইন্টারভালের বাইরে "ওভারশুট" করে), যা যেকোনো ছোট ডেটা এরর বা রাউন্ড-অফকে বিপুলভাবে বিবর্ধিত করে।
পিসওয়াইজের সুবিধা
প্রতিটি সাব-ইন্টারভালে ডিগ্রি সবসময় নিচু (লিনিয়ারের ক্ষেত্রে ডিগ্রি ১) থাকে, তাই কোনো একটি অংশের সমস্যা পুরো ফাংশনে ছড়ায় না — এটি "স্থানীয়করণ" (localization) নামে পরিচিত একটি গুরুত্বপূর্ণ ধর্ম।
স্মুথনেসের খরচ
পিসওয়াইজ-লিনিয়ার নির্ভরযোগ্য কিন্তু নোডে "কোণ" (কিঙ্ক) তৈরি করে — সম্পূর্ণ মসৃণ (স্মুথ) ইন্টারপোলেশনের জন্য L19-এ কিউবিক স্প্লাইন দেখাবে কীভাবে স্থিতিশীলতা ও মসৃণতা দুটোই পাওয়া যায়।
মূল কথা · Key takeaway

রুঙ্গের ফেনোমেনন একটি গুরুত্বপূর্ণ সতর্কতা: সমান-ব্যবধানের নোডে উঁচু-ডিগ্রি পলিনোমিয়াল ইন্টারপোলেশন সবসময় নিরাপদ নয় — কিছু ফাংশনের জন্য ডিগ্রি বাড়ানো ফলাফল আরও খারাপ করে। এর ব্যবহারিক সমাধান দুটি: (১) পিসওয়াইজ পদ্ধতি ব্যবহার করা (এই পাঠ, L19), অথবা (২) নোডগুলো সমান-ব্যবধানে না রেখে কিনারার কাছে ঘন করে বসানো (যেমন চেবিশেভ নোড — এই কোর্সের সীমার বাইরে কিন্তু উল্লেখযোগ্য একটি বিকল্প)।

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

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

প্র ০১ কোড সেলে x = 0.0 (কেন্দ্র)-এ এরর সবসময় প্রায় ০ থাকে, এমনকি n = 21-এও। কেন কেন্দ্র রুঙ্গের ফেনোমেননের প্রভাব থেকে মুক্ত?

x = 0.0 সবসময় একটি স্যাম্পল নোডের সাথে মিলে যায় (যেহেতু সমান-ব্যবধানের নোডগুলো প্রতিসম, ০ সবসময় একটি নোড), তাই সংজ্ঞা অনুযায়ী ইন্টারপোলেটিং পলিনোমিয়াল সেখানে ঠিক প্রকৃত মান দিতে বাধ্য। এছাড়া, রুঙ্গের ফেনোমেননের দোলন মূলত ইন্টারভালের কিনারার কাছে কেন্দ্রীভূত — কেন্দ্রের কাছাকাছি নোডগুলো ঘনিষ্ঠভাবে ঘিরে থাকে বলে সেখানে পলিনোমিয়াল ভালো আচরণ করে।

প্র ০২ L16-এ sin(x)-এর জন্য ৫টি পয়েন্টে ইন্টারপোলেশন ভালো কাজ করেছিল (এরর মাত্র ০.০০০১৭ মাত্রার), কিন্তু এখানে রুঙ্গের ফাংশনে ৫টি পয়েন্টেই এরর ০.২ মাত্রার এবং বাড়তে থাকে। পার্থক্যটা কী?

পার্থক্যটা ফাংশনের প্রকৃতিতে — sin(x) সব জায়গায় মসৃণভাবে বাঁকে (তার সব ডেরিভেটিভ বাউন্ডেড), যেখানে 1/(1+25x²)-এর কেন্দ্রে একটি তীক্ষ্ণ, সরু চূড়া আছে। জটিল বিশ্লেষণে দেখানো যায় এই ফাংশনের একটি "সিঙ্গুলারিটি" জটিল সমতলে (complex plane) ইন্টারপোলেশন ইন্টারভালের যথেষ্ট কাছে থাকে, যা সমান-ব্যবধানের নোডে উঁচু-ডিগ্রি পলিনোমিয়ালকে অস্থিতিশীল করে তোলে — এটি এই কোর্সের গভীরতার বাইরে, কিন্তু ফলাফলটি (কিছু ফাংশন খারাপ আচরণ করে) মনে রাখা গুরুত্বপূর্ণ।

প্র ০৩ পিসওয়াইজ-লিনিয়ার ইন্টারপোলেশন কিনারায় খুব সঠিক ফলাফল দিলেও, এটি প্রতিটি নোডে একটি "কোণ" (কিঙ্ক, অর্থাৎ ডেরিভেটিভ অবিচ্ছিন্ন নয়) তৈরি করে। কোন ধরনের বাস্তব প্রয়োগে এটি সমস্যা হতে পারে?

যেকোনো প্রয়োগ যেখানে ইন্টারপোলেটেড ফাংশনের ডেরিভেটিভ (ঢাল, গতি, ত্বরণ) গুরুত্বপূর্ণ — যেমন CAD/গ্রাফিক্সে মসৃণ কার্ভ আঁকা, রোবোটিক্সে গতিপথ পরিকল্পনা (trajectory planning) যেখানে আকস্মিক ঢাল-পরিবর্তন যান্ত্রিক ঝাঁকুনি তৈরি করে, বা পদার্থবিজ্ঞানের সিমুলেশনে যেখানে বল (force) অবস্থানের ডেরিভেটিভ থেকে আসে। এই ক্ষেত্রে L19-এর কিউবিক স্প্লাইন প্রয়োজন, যা নোডে ডেরিভেটিভও মসৃণ রাখে।

অনুশীলন

  1. চিন্তা করুন: যদি প্রথম কোড সেলে n = 31 যোগ করা হয় (ডিগ্রি-৩০ পলিনোমিয়াল), x = 0.95-এ এরর আগের প্যাটার্ন (৫→১১→১৫→২১-এ ০.২→১.৯→৬.৯→৪০) অনুসরণ করে কেমন হবে বলে আপনার ধারণা?

    প্যাটার্ন অনুযায়ী এরর আরও অনেক গুণ বাড়ার কথা — সম্ভবত শত বা হাজার মাত্রার সংখ্যায়, কারণ প্রতিটি ধাপে এরর প্রায় সূচকীয় (exponential) হারে বাড়ছে। বাস্তবে n=31-এ Python-এর ফ্লোটিং-পয়েন্ট গণনায় এত বড় মধ্যবর্তী মান তৈরি হতে পারে যে ফলাফল সংখ্যাগতভাবে অস্থিতিশীল হয়ে যেতে পারে।

  2. পরীক্ষা করুন: প্রথম কোড সেলের for n in [5, 11, 15, 21]: লাইনে 31 যোগ করে Run চেপে আপনার অনুমান যাচাই করুন।

    n = 31-এ x = 0.95-এর এরর হাজার বা তারও বেশি মাত্রায় পৌঁছাতে পারে — প্যাটার্নটি নিশ্চিত হয়: প্যাটার্নটি স্পষ্টভাবে সূচকীয়ভাবে বাড়তে থাকে এবং সমান-ব্যবধানের নোডে সমস্যাটি আরও ভয়াবহ হতে থাকে ডিগ্রি বাড়ানোর সাথে সাথে।

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

আগের পাঠ
নিউটনের ডিভাইডেড ডিফারেন্স