পাঠ ১৯ · ৫৭-এর মধ্যে · মডিউল ৪
Home / Courses / Numerical Methods / কিউবিক স্প্লাইন

কিউবিক স্প্লাইন ইন্টারপোলেশন

Cubic spline interpolation
১২ মিনিট পড়া মধ্যম-কঠিন · Intermediate-Advanced Python কোডসহ সম্পূর্ণ বাংলায়

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

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

১ · কিউবিক স্প্লাইন কী এবং কেন

কিউবিক স্প্লাইনCubic Splineএকটি পিসওয়াইজ ফাংশন, যেখানে প্রতিটি সাব-ইন্টারভালে একটি আলাদা ডিগ্রি-৩ পলিনোমিয়াল থাকে, এবং এই পলিনোমিয়ালগুলো এমনভাবে বেছে নেওয়া হয় যাতে সংলগ্ন সাব-ইন্টারভালের সংযোগস্থলে (নোড/গিঁট) ফাংশনের মান, প্রথম ডেরিভেটিভ ও দ্বিতীয় ডেরিভেটিভ — সবই মসৃণভাবে মিলে যায়। L18-এর পিসওয়াইজ-লিনিয়ার শুধু ফাংশনের মান মেলায় (ডেরিভেটিভে কোণ থাকে); কিউবিক স্প্লাইন আরও এক ধাপ এগিয়ে গিয়ে ঢাল ও বক্রতাও (curvature) মসৃণ রাখে — এটি চোখে দেখতে প্রাকৃতিক ও মসৃণ লাগে, এবং পদার্থবিজ্ঞান/গ্রাফিক্সের মতো প্রয়োগে গুরুত্বপূর্ণ যেখানে ডেরিভেটিভের অর্থ আছে।

প্রতিটি সাব-ইন্টারভাল [xᵢ, xᵢ₊₁]-এ স্প্লাইন লেখা যায় দুই প্রান্তের মান ও দ্বিতীয় ডেরিভেটিভ (Mᵢ) দিয়ে:

$$S_i(x) = A\,y_i + B\,y_{i+1} + \frac{(A^3-A)M_i + (B^3-B)M_{i+1}}{6}h_i^2$$

যেখানে h_i = x_{i+1} - x_i, A = (x_{i+1}-x)/h_i, B = (x-x_i)/h_i। অজানা রয়ে গেল শুধু Mᵢ-গুলো — প্রতিটি নোডে দ্বিতীয় ডেরিভেটিভ। এগুলো বের করতে একটি ট্রাইডায়াগোনাল সিস্টেম সমাধান করতে হয় (M3/L15-এর টেকনিক):

$$h_{i-1}M_{i-1} + 2(h_{i-1}+h_i)M_i + h_iM_{i+1} = 6\left(\frac{y_{i+1}-y_i}{h_i} - \frac{y_i-y_{i-1}}{h_{i-1}}\right)$$

ন্যাচারাল বাউন্ডারি কন্ডিশনNatural Boundary Conditionস্প্লাইনের দুই প্রান্তে দ্বিতীয় ডেরিভেটিভ শূন্য ধরে নেওয়া (M₀ = Mₙ = 0) — এটি সিস্টেমকে সমাধানযোগ্য করে তোলার সবচেয়ে সহজ, প্রচলিত পছন্দ। ব্যবহার করে M₀ = Mₙ = 0 ধরে নিলে সিস্টেমটি n-1টি অজানা নিয়ে একটি ট্রাইডায়াগোনাল সিস্টেমে পরিণত হয়, যা Thomas অ্যালগরিদম দিয়ে O(n) সময়ে সমাধান করা যায়।

২ · একটি সত্যিকারের ডেমো — রুঙ্গের ফাংশনে স্প্লাইন বনাম পলিনোমিয়াল

নিচের কোড সেলে ঠিক L18-এর একই রুঙ্গে-ফাংশন ডেটাসেট (n = 11 সমান-ব্যবধানের নোড, f(x) = 1/(1+25x²)) ব্যবহার করে একটি ন্যাচারাল কিউবিক স্প্লাইন তৈরি করা হয়েছে, তারপর L18-এর একই কিনারার বিন্দুতে (x = 0.95, 0.98) মূল্যায়ন করে ডিগ্রি-১০ পলিনোমিয়ালের এররের সাথে সরাসরি তুলনা করা হয়েছে।

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

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

def natural_cubic_spline_coeffs(xs, ys):
    n = len(xs) - 1
    h = [xs[i+1] - xs[i] for i in range(n)]
    size = n - 1
    a = [0.0]*size
    b = [0.0]*size
    c = [0.0]*size
    d = [0.0]*size
    for i in range(1, n):
        idx = i - 1
        b[idx] = 2*(h[i-1] + h[i])
        if idx - 1 >= 0:
            a[idx] = h[i-1]
        if idx + 1 < size:
            c[idx] = h[i]
        d[idx] = 6*((ys[i+1]-ys[i])/h[i] - (ys[i]-ys[i-1])/h[i-1])

    # Thomas অ্যালগরিদম (M3/L15-এর মতো)
    cp = [0.0]*size
    dp = [0.0]*size
    cp[0] = c[0]/b[0]
    dp[0] = d[0]/b[0]
    for i in range(1, size):
        m = b[i] - a[i]*cp[i-1]
        cp[i] = c[i]/m if i < size-1 else 0.0
        dp[i] = (d[i] - a[i]*dp[i-1])/m

    Msol = [0.0]*size
    Msol[-1] = dp[-1]
    for i in range(size-2, -1, -1):
        Msol[i] = dp[i] - cp[i]*Msol[i+1]

    M = [0.0]*(n+1)
    for i in range(size):
        M[i+1] = Msol[i]
    M[0] = 0.0
    M[n] = 0.0
    return xs, ys, h, M

def spline_eval(xs, ys, h, M, x):
    n = len(xs) - 1
    i = 0
    for k in range(n):
        if xs[k] <= x <= xs[k+1]:
            i = k
            break
    hi = h[i]
    A = (xs[i+1] - x) / hi
    B = (x - xs[i]) / hi
    term1 = A*ys[i] + B*ys[i+1]
    term2 = ((A**3 - A)*M[i] + (B**3 - B)*M[i+1]) * (hi**2) / 6.0
    return term1 + term2

n = 11
xs = equally_spaced(n)
ys = [runge(x) for x in xs]
xs2, ys2, h, M = natural_cubic_spline_coeffs(xs, ys)

print(f"ন্যাচারাল কিউবিক স্প্লাইন, n = {n} নোড (L18-এর একই ডেটাসেট):")
print()

poly_errors_from_L18 = {0.95: 1.881191, 0.98: 1.190333, 0.0: 0.000000}
for xt in [0.95, 0.98, 0.0]:
    s = spline_eval(xs, ys, h, M, xt)
    true_v = runge(xt)
    err = abs(s - true_v)
    print(f"x={xt}: স্প্লাইন S(x)={s:.6f}  true={true_v:.6f}  স্প্লাইন_এরর={err:.6f}   (ডিগ্রি-১০ পলিনোমিয়ালের এরর ছিল {poly_errors_from_L18[xt]:.6f})")

    
ফলাফল দ্ব্যর্থহীন: x = 0.95-এ স্প্লাইনের এরর মাত্র ০.০০০৪৭১, যেখানে L18-এর ডিগ্রি-১০ পলিনোমিয়ালের এরর ছিল ১.৮৮ — প্রায় ৪,০০০ গুণ কম। একইভাবে x = 0.98-এ স্প্লাইনের এরর ০.০০০২৪৩, পলিনোমিয়ালের ১.১৯-এর তুলনায় প্রায় ৫,০০০ গুণ কম। কেন্দ্রে (x=0.0) দুটোই প্রায় নিখুঁত। একই সংখ্যক ডেটা পয়েন্ট (মাত্র ১১টি), কিন্তু পিসওয়াইজ-কিউবিক কাঠামো সম্পূর্ণ ভিন্ন, অনেক বেশি স্থিতিশীল ফলাফল দেয়।

নিচের কোড সেলে একই স্প্লাইন নোডগুলোর মাঝামাঝি কয়েকটি বিন্দুতেও মূল্যায়ন করে দেখানো হয়েছে — স্প্লাইন শুধু নোডে নয়, পুরো ইন্টারভাল জুড়েই যুক্তিসঙ্গত নির্ভুলতা বজায় রাখে।

Python
# (আগের সেলের xs, ys, h, M ব্যবহার করে — একই Pyodide সেশনে চালাতে হবে)
print("নোডের মাঝামাঝি বিন্দুতে স্প্লাইন মূল্যায়ন:")
for xt in [0.1, 0.5, -0.7]:
    s = spline_eval(xs, ys, h, M, xt)
    true_v = runge(xt)
    print(f"  x={xt}: S(x)={s:.6f}  true={true_v:.6f}  এরর={abs(s-true_v):.6f}")

    
x=0.1-এ এরর ০.০২০৫ (এখানে ফাংশন সবচেয়ে তীক্ষ্ণভাবে বাঁকে, তাই এরর সবচেয়ে বেশি — এটি প্রত্যাশিত), x=0.5-এ ০.০০২২, আর x=-0.7-এ মাত্র ০.০০০৮ — সবই যুক্তিসঙ্গত ছোট মাত্রার, ডিগ্রি-১০ পলিনোমিয়ালের কিনারার এররের ধারেকাছেও নয়।
M3-এর সাথে সংযোগ
স্প্লাইনের দ্বিতীয়-ডেরিভেটিভ সিস্টেম একটি ট্রাইডায়াগোনাল সিস্টেম — L15-এর Thomas অ্যালগরিদম হুবহু এখানে প্রয়োগ হয়, এই কোর্সের মডিউলগুলো কীভাবে একে অপরের উপর নির্মিত তার একটি উদাহরণ।
অন্যান্য বাউন্ডারি কন্ডিশন
ন্যাচারাল ছাড়াও "ক্ল্যাম্পড" (প্রান্তে জানা ঢাল ব্যবহার) বা "নট-এ-নট" স্প্লাইন আছে — এগুলো ভিন্ন অনুমান করে সামান্য ভিন্ন ফলাফল দেয়, কিন্তু মূল পদ্ধতি একই থাকে।
ব্যবহারিক ব্যবহার
কিউবিক স্প্লাইন গ্রাফিক্স (ফন্ট আউটলাইন, কার্ভ ডিজাইন), ডেটা ভিজুয়ালাইজেশনে মসৃণ কার্ভ আঁকা, এবং ইঞ্জিনিয়ারিং সিমুলেশনে ব্যাপকভাবে ব্যবহৃত হয় — এই কোর্সের সবচেয়ে ব্যবহারিক ফলাফলগুলোর একটি।
মূল কথা · Key takeaway

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

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

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

প্র ০১ কোড সেলের আউটপুটে M[5] (কেন্দ্রের নোড, x=0.0) মান -46.79 — অন্য সব M-এর তুলনায় অনেক বড় (পরম মানে)। কেন কেন্দ্রের কাছে দ্বিতীয় ডেরিভেটিভ এত বড়?

দ্বিতীয় ডেরিভেটিভ বক্রতা (curvature) পরিমাপ করে — রুঙ্গের ফাংশন f(x)=1/(1+25x²) x=0-এর কাছে সবচেয়ে তীক্ষ্ণভাবে বাঁকে (একটি সরু চূড়া তৈরি করে), তাই সেখানে প্রকৃত দ্বিতীয় ডেরিভেটিভও বড়। স্প্লাইন এই বাস্তব বক্রতা অনুসরণ করার চেষ্টা করে, তাই কেন্দ্রের নোডে বড় M মান আসাটাই প্রত্যাশিত এবং সঠিক আচরণ — এটি রুঙ্গের ফেনোমেননের বিপরীত ঘটনা (এখানে অস্থিতিশীলতা নয়, বাস্তব বক্রতার সঠিক প্রতিফলন)।

প্র ০২ মাঝামাঝি বিন্দুতে মূল্যায়নে x=0.1-এর এরর (০.০২০৫) অন্য দুটো বিন্দুর (০.০০২২, ০.০০০৮) চেয়ে অনেক বেশি। এটা কি স্প্লাইনের ব্যর্থতা?

না — এটি প্রত্যাশিত। x=0.1 ঠিক ফাংশনের সবচেয়ে তীক্ষ্ণ বাঁকের (x=0) কাছে, যেখানে ডিগ্রি-৩ পলিনোমিয়ালও পুরোপুরি সঠিক আকার ধরতে পারে না মাত্র ১১টি নোডের রেজোলিউশনে। এই এরর তুলনামূলক অর্থে ছোট (০.০২, ফাংশনের সর্বোচ্চ মান ১-এর মাত্র ২%), এবং ডিগ্রি-১০ পলিনোমিয়ালের কিনারার এরর (১.৮৮)-এর তুলনায় এখনও বহুগুণ ছোট — আরও বেশি নোড ব্যবহার করলে এই এররও কমে যাবে।

প্র ০৩ ন্যাচারাল বাউন্ডারি কন্ডিশন ধরে নেয় প্রান্তে দ্বিতীয় ডেরিভেটিভ ০। রুঙ্গের ফাংশনের প্রান্তে (x=±1) প্রকৃত দ্বিতীয় ডেরিভেটিভ কি সত্যিই ০-এর কাছাকাছি?

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

অনুশীলন

  1. চিন্তা করুন: L18-এ দেখেছি ডিগ্রি-২০ পলিনোমিয়ালে (n=21) কিনারার এরর (৩৯.৯৯) ডিগ্রি-১০ (n=11)-এর এরর (১.৮৮) থেকেও বেশি খারাপ ছিল। যদি একই n=21 নোড দিয়ে কিউবিক স্প্লাইন তৈরি করা হয়, কিনারার এরর কেমন হবে বলে আপনার ধারণা — n=11 স্প্লাইনের চেয়ে ভালো নাকি খারাপ?

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

  2. পরীক্ষা করুন: প্রথম কোড সেলে n = 11-কে n = 21-এ পরিবর্তন করে Run চেপে আপনার অনুমান যাচাই করুন।

    n=21-এ স্প্লাইনের কিনারার এরর n=11-এর (০.০০০৪৭১ ও ০.০০০২৪৩) তুলনায় আরও ছোট হয়ে যায় — নিশ্চিত করে স্প্লাইন বেশি নোডে আরও সঠিক হয়, ঠিক বিপরীত আচরণ যা L18-এর ডিগ্রি-২০ পলিনোমিয়াল দেখিয়েছিল (যেখানে বেশি নোড এররকে আরও খারাপ করেছিল)।

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

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