পাঠ ৩১ · ৫৭-এর মধ্যে · মডিউল ৬
Home / Courses / Numerical Methods / মাল্টিস্টেপ মেথড

মাল্টিস্টেপ মেথড — অ্যাডামস-ব্যাশফোর্থ/মৌলটন

Multistep methods — Adams-Bashforth / Moulton
১১ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • সিঙ্গল-স্টেপ ও মাল্টিস্টেপ মেথডের পার্থক্য এবং মাল্টিস্টেপ মেথডের হিসাব-খরচ সুবিধা
  • ২-স্টেপ অ্যাডামস-ব্যাশফোর্থ (AB2) সূত্র এবং কেন এর "বুটস্ট্র্যাপিং" প্রয়োজন
  • RK4 দিয়ে বুটস্ট্র্যাপ করে একটি সম্পূর্ণ AB2 সলভার হাতে-লেখা Python-এ বাস্তবায়ন করা
  • একই টেস্ট IVP-তে AB2 বনাম RK4-এর সত্যিকারের অ্যাকুরেসি ও কনভারজেন্স-অর্ডার তুলনা

১ · সিঙ্গল-স্টেপ বনাম মাল্টিস্টেপ

L27–L30-এর প্রতিটি মেথড — অয়লার, হয়েন, RK4 — সিঙ্গল-স্টেপ: y_{n+1} বের করতে শুধু (x_n, y_n)-এর তথ্য লাগে, তার আগের কোনো বিন্দুর তথ্য নয়। RK4 প্রতি ধাপে চারবার f মূল্যায়ন করে নির্ভুলতা কেনে — কিন্তু প্রতিটি মূল্যায়নই "একবার ব্যবহার করে ফেলে দেওয়া" হয়।

মাল্টিস্টেপ মেথড একটি ভিন্ন কৌশল নেয়: যেহেতু আমরা ইতিমধ্যে আগের কয়েকটি বিন্দুতে f-এর মান গণনা করে ফেলেছি (আগের ধাপগুলো থেকে), কেন সেই তথ্য ফেলে দেওয়া হবে? এর বদলে, আগের কয়েকটি বিন্দুর f-মান দিয়ে একটি পলিনোমিয়াল ফিট করে (M4-এর ইন্টারপোলেশনের সাথে ধারণাগতভাবে ঘনিষ্ঠ) সেই পলিনোমিয়াল ব্যবহার করে পরবর্তী বিন্দু আনুমানিক করা হয় — নতুন করে অতিরিক্ত মূল্যায়ন ছাড়াই (শুধু বর্তমান বিন্দুর একটি নতুন মূল্যায়ন যোগ হয়)।

২ · ২-স্টেপ অ্যাডামস-ব্যাশফোর্থ (AB2)

সবচেয়ে সরল এক্সপ্লিসিট মাল্টিস্টেপ মেথডগুলোর একটি হলো ২-স্টেপ অ্যাডামস-ব্যাশফোর্থ, যা শেষ দুই বিন্দুর f-মান দিয়ে একটি রৈখিক এক্সট্রাপোলেশন ব্যবহার করে:

$$y_{n+1} = y_n + h\left(\frac{3}{2}f(x_n, y_n) - \frac{1}{2}f(x_{n-1}, y_{n-1})\right)$$

লক্ষ্য করুন — এই সূত্রে মাত্র একটি নতুন f-মূল্যায়ন লাগে (f(x_n, y_n)); f(x_{n-1}, y_{n-1}) আগের ধাপ থেকে ইতিমধ্যে গণনা করা এবং সংরক্ষিত আছে। ওজন 3/2 ও -1/2 এমনভাবে নির্বাচিত (রৈখিক এক্সট্রাপোলেশনের গাণিতিক ফলাফল) যাতে সামগ্রিক মেথড দ্বিতীয়-ক্রম নির্ভুল (O(h²)) হয় — অর্থাৎ প্রতি ধাপে RK4-এর চতুর্থাংশ হিসাব-খরচে (১টি বনাম ৪টি f-মূল্যায়ন) হয়েনের সমান কনভারজেন্স-অর্ডার পাওয়া যায়।

সমস্যা: y_{n+1} বের করতে y_n ও y_{n-1} দুটোই লাগে — কিন্তু শুরুতে আমাদের কাছে শুধু y_0 (শুরুর শর্ত) আছে, y_1 নেই। তাই প্রথম ধাপটি এই মেথড নিজে চালাতে পারে না — একে বলে বুটস্ট্র্যাপিং সমস্যা, এবং এর সমাধান হলো প্রথম ধাপের জন্য একটি নির্ভরযোগ্য সিঙ্গল-স্টেপ মেথড (RK4) ব্যবহার করা, তারপর থেকে AB2 নিজেই চালিয়ে যাওয়া।

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

৩ · সত্যিকারের বাস্তবায়ন — RK4 দিয়ে বুটস্ট্র্যাপ করে AB2

L27–L30-এর একই টেস্ট IVP (dy/dx = -y, y(0) = 1, y(x) = e⁻ˣ) ব্যবহার করে, নিচের কোড সেলে AB2 হাতে-লেখা হয়েছে — প্রথম ধাপ RK4 দিয়ে, তারপরের সব ধাপ AB2-এর নিজস্ব সূত্র দিয়ে।

Python
import math

def f(x, y):
    return -y

def exact(x):
    return math.exp(-x)

def rk4_step(x, y, h):
    k1 = f(x, y)
    k2 = f(x + h / 2, y + h / 2 * k1)
    k3 = f(x + h / 2, y + h / 2 * k2)
    k4 = f(x + h, y + h * k3)
    return y + (h / 6) * (k1 + 2 * k2 + 2 * k3 + k4)

def ab2(h, x0=0.0, y0=1.0, xend=2.0):
    xs, ys = [x0], [y0]
    n = round((xend - x0) / h)

    # বুটস্ট্র্যাপ: প্রথম ধাপ RK4 দিয়ে (AB2 নিজে এটা করতে পারে না)
    x1 = x0 + h
    y1 = rk4_step(x0, y0, h)
    xs.append(x1); ys.append(y1)

    f_prev = f(x0, y0)   # f_{n-1}
    f_curr = f(x1, y1)   # f_n
    x, y = x1, y1
    for i in range(1, n):
        y_next = y + h * (1.5 * f_curr - 0.5 * f_prev)   # AB2 সূত্র
        x_next = x + h
        xs.append(x_next); ys.append(y_next)
        f_prev = f_curr
        f_curr = f(x_next, y_next)
        x, y = x_next, y_next
    return xs, ys

print("AB2 দিয়ে dy/dx = -y, y(0) = 1 সমাধান, h = 0.2:")
print(f"{'x':>6} | {'y_ab2':>10} | {'y_exact':>10} | {'|error|':>10}")
xs, ys = ab2(0.2)
for x, y in zip(xs, ys):
    err = abs(y - exact(x))
    print(f"{x:>6.2f} | {y:>10.6f} | {exact(x):>10.6f} | {err:>10.6f}")

    
প্রকৃত আউটপুট দেখায় প্রথম ধাপে (x = 0.2, RK4 দিয়ে বুটস্ট্র্যাপ করা) এরর অত্যন্ত ছোট (০.০০০০০৩) কারণ RK4 নিজেই চতুর্থ-ক্রম নির্ভুল। এরপর থেকে AB2 নিজে চালায় — এরর ধীরে ধীরে বাড়ে (x = 1.2-এ সর্বোচ্চ ০.০০৫৬৪৪) তারপর কিছুটা কমে চূড়ান্ত বিন্দুতে (x = 2.0) দাঁড়ায় ০.০০৪৫৪৬।

৪ · সত্যিকারের তুলনা — AB2 বনাম RK4

নিচের কোড সেলে একই h-মানে AB2 ও RK4-এর চূড়ান্ত এরর সরাসরি পাশাপাশি তুলনা করা হয়েছে।

Python
def rk4(h, x0=0.0, y0=1.0, xend=2.0):
    x, y = x0, y0
    n = round((xend - x0) / h)
    for i in range(n):
        y = rk4_step(x, y, h)
        x = x + h
    return y

ex = exact(2.0)
hs = [0.4, 0.2, 0.1, 0.05, 0.025]
print(f"{'h':>8} | {'err_ab2':>12} | {'err_rk4':>16} | {'ab2/rk4':>10}")
prev_ab2 = None
for h in hs:
    ab2_final = ab2(h)[1][-1]
    rk4_final = rk4(h)
    err_ab2 = abs(ab2_final - ex)
    err_rk4 = abs(rk4_final - ex)
    print(f"{h:>8} | {err_ab2:>12.8f} | {err_rk4:>16.10f} | {err_ab2 / err_rk4:>10.1f}")

print()
print("AB2-এর নিজস্ব কনভারজেন্স-অর্ডার যাচাই (h অর্ধেক -> এরর প্রায় কত ভাগ?):")
prev_err = None
for h in hs:
    err = abs(ab2(h)[1][-1] - ex)
    ratio = (prev_err / err) if prev_err is not None else None
    ratio_str = f"{ratio:.3f}" if ratio is not None else "  --  "
    print(f"h={h:<8} err={err:.8f}  ratio_prev/curr={ratio_str}")
    prev_err = err

    
প্রকৃত আউটপুট: h = 0.1-এ AB2-এর এরর ০.০০১১৩৫৮৩, RK4-এর এরর মাত্র ০.০০০০০০২৪৫২ — RK4 প্রায় ৪,৬৩২ গুণ বেশি নির্ভুল, প্রত্যাশিত মতোই (RK4 চতুর্থ-ক্রম, AB2 দ্বিতীয়-ক্রম)। AB2-এর নিজস্ব কনভারজেন্স-অর্ডার যাচাইয়ে অনুপাত h = 0.4 → 0.2 -এ ৩.৯১৬, 0.2 → 0.1-এ ৪.০০৩, 0.1 → 0.05-এ ৪.০১১, আর 0.05 → 0.025-এ ৪.০০৮ — ঠিক ৪-এর কাছাকাছি, নিশ্চিত করে AB2 সত্যিই দ্বিতীয়-ক্রম (O(h²)), হয়েনের (L29) সমান কনভারজেন্স-অর্ডার কিন্তু প্রতি ধাপে অর্ধেক f-মূল্যায়নে।
মূল কথা · Key takeaway

মাল্টিস্টেপ মেথড দেখায় নির্ভুলতা কেনার আরেকটি পথ আছে — প্রতি ধাপে বেশি হিসাব করার বদলে, আগের হিসাব পুনরায় ব্যবহার করা। AB2 হয়েনের সমান কনভারজেন্স-অর্ডার (O(h²)) পায় অর্ধেক প্রতি-ধাপ খরচে, কিন্তু এর বিনিময়ে বুটস্ট্র্যাপিং জটিলতা ও (L32-এ আমরা দেখব সাধারণভাবে) কিছুটা কম স্ট্যাবিলিটি মার্জিন সহ্য করতে হয়। বাস্তব ODE সলভার লাইব্রেরিতে (যেমন `scipy.integrate` — এই কোর্সের পরিধির বাইরে হলেও উল্লেখযোগ্য) প্রায়ই উচ্চতর-স্টেপ Adams-Bashforth/Moulton predictor-corrector জোড়া এবং অভিযোজিত step-size নিয়ন্ত্রণ ব্যবহৃত হয়, যা এই একই মৌলিক ধারণার আরও পরিশীলিত রূপ। L32-এ আমরা দেখব কোনো মেথডের কনভারজেন্স-অর্ডার যতই ভালো হোক, স্টিফ সমীকরণে ভুল step size নির্বাচন করলে যেকোনো এক্সপ্লিসিট মেথড — অয়লার, RK4, বা AB2 — সম্পূর্ণভাবে অস্থির হয়ে যেতে পারে।

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

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

প্র ০১ AB2 কেন নিজে থেকে প্রথম ধাপ চালাতে পারে না, অথচ RK4 পারে?

AB2-এর সূত্রে y_{n+1} গণনা করতে দুটি আগের বিন্দুর তথ্য লাগে (y_n ও f(x_{n-1}, y_{n-1}))। প্রথম ধাপে (n = 0) আমাদের কাছে শুধু y_0 আছে, কোনো y_{-1} নেই — তাই সূত্রটি প্রয়োগ করা অসম্ভব। RK4 (ও অয়লার, হয়েন) সিঙ্গল-স্টেপ হওয়ায় শুধু বর্তমান বিন্দুর তথ্যেই যথেষ্ট, তাই যেকোনো বিন্দু থেকে শুরু করতে পারে।

প্র ০২ যদি বুটস্ট্র্যাপ ধাপে RK4-এর বদলে সাধারণ অয়লার মেথড ব্যবহার করা হতো, তাহলে AB2-এর সামগ্রিক কনভারজেন্স-অর্ডারে কী প্রভাব পড়তে পারত?

সম্ভবত কিছুটা প্রভাব পড়ত, বিশেষত বড় h-এ, কারণ প্রথম বিন্দুর ভুল (অয়লারের O(h) লোকাল এরর, RK4-এর O(h⁴)-এর তুলনায় অনেক বড়) পরবর্তী সব AB2 ধাপে "ছড়িয়ে" যেত। ছোট h-এ এই প্রভাব কম হতো (কারণ একটি একক বড় লোকাল এরর মোট ধাপ সংখ্যার তুলনায় ছোট হয়ে যায়), কিন্তু সাধারণ ভালো অভ্যাস হলো সবসময় বুটস্ট্র্যাপের জন্য মূল মাল্টিস্টেপ মেথডের সমান বা উচ্চতর-ক্রম একটি সিঙ্গল-স্টেপ মেথড ব্যবহার করা — যা এখানে RK4 ব্যবহার করার কারণ।

প্র ০৩ AB2 প্রতি ধাপে ১টি f-মূল্যায়ন করে আর RK4 করে ৪টি, অথচ উভয়ে মিলে একই মোট ধাপ সংখ্যায় RK4 অনেক বেশি নির্ভুল। তাহলে AB2 ব্যবহার করার কোনো বাস্তব সুবিধা আছে কি?

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

অনুশীলন

  1. চিন্তা করুন: AB2-এর কনভারজেন্স-অর্ডার O(h²) হলে, h = 0.025-এর এরর (0.00007065) থেকে h = 0.0125-এ গেলে এরর মোটামুটি কত হবে বলে আপনার ধারণা?

    O(h²)-এ h অর্ধেক করলে এরর প্রায় চতুর্থাংশ হয়, তাই আনুমানিক 0.00007065 / 4 ≈ 0.0000177।

  2. পরীক্ষা করুন: চতুর্থ কোড সেলের hs তালিকায় 0.0125 যোগ করে Run চেপে AB2-এর প্রকৃত এরর ও অনুপাত যাচাই করুন।

    রান করলে দেখা যায় h = 0.0125-এ AB2-এর এরর প্রায় ০.০০০০১৭৭-এর কাছাকাছি, আর আগের ধাপের (0.025) তুলনায় অনুপাত ৪-এর খুব কাছাকাছি থাকে — নিশ্চিত করে AB2-এর দ্বিতীয়-ক্রম আচরণ ছোট h-এও ধারাবাহিকভাবে বজায় থাকে।

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

আগের পাঠ
রুঙ্গে-কুট্টা মেথড (RK4)