পাঠ ২৫ · ৫৭-এর মধ্যে · মডিউল ৫
Home / Courses / Numerical Methods / অ্যাডাপটিভ কোয়াড্রেচার

কম্পোজিট রুল ও অ্যাডাপটিভ কোয়াড্রেচার

Composite rules & adaptive quadrature
৯ মিনিট পড়া মধ্যম-উচ্চ · Intermediate-Advanced Python কোডসহ সম্পূর্ণ বাংলায়

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

  • কম্পোজিট (স্থির-প্রস্থ) রুলের একটি বাস্তব সীমাবদ্ধতা — অ-সমতল আচরণের ফাংশনে অদক্ষতা
  • অ্যাডাপটিভ কোয়াড্রেচারের মূল ধারণা — রিকার্সিভ সাব-ডিভিশন ও স্থানীয় এরর এস্টিমেট
  • একটি সত্যিকারের রিকার্সিভ অ্যাডাপটিভ সিম্পসনস ইমপ্লিমেন্টেশন Python-এ
  • একটি তীক্ষ্ণ-শিখরযুক্ত ফাংশনে অ্যাডাপটিভ বনাম ইউনিফর্ম গ্রিডের সত্যিকারের কার্যকারিতা তুলনা

১ · স্থির-প্রস্থ গ্রিডের সীমাবদ্ধতা

L23-L24-এ আমরা যে কম্পোজিট রুল ব্যবহার করেছি তাতে পুরো ইন্টারভাল [a, b]-কে সমান-প্রস্থের nটি সাব-ইন্টারভালে ভাগ করা হয়েছিল। এই পদ্ধতি তখনই দক্ষ যখন ফাংশনটি পুরো ইন্টারভাল জুড়ে মোটামুটি একই রকম আচরণ করে। কিন্তু বাস্তবে অনেক ফাংশন এমন নয় — যেমন একটি সংকীর্ণ রেজোন্যান্স পিক (একটি নির্দিষ্ট ফ্রিকোয়েন্সিতে সিগন্যাল প্রসেসিংয়ে), বা একটি সংকীর্ণ পিক-শেপড ডিস্ট্রিবিউশন।

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

২ · অ্যাডাপটিভ কোয়াড্রেচার — রিকার্সিভ সমাধান

অ্যাডাপটিভ সিম্পসনস কোয়াড্রেচারের ধারণা সহজ কিন্তু শক্তিশালী:

একটি ইন্টারভালে সিম্পসনস চালান
[a, b]-এ একবার সিম্পসনস রুল দিয়ে এস্টিমেট S বের করুন।
দুই ভাগে ভেঙে আবার চালান
ইন্টারভালটিকে মাঝখানে ভেঙে দুই অর্ধেকে আলাদাভাবে সিম্পসনস চালিয়ে যোগফল S₂ বের করুন।
তুলনা করে সিদ্ধান্ত নিন
S ও S₂ কাছাকাছি হলে (একটি টলারেন্সের মধ্যে) থামুন — যথেষ্ট নির্ভুল ধরে নিন। না হলে প্রতিটি অর্ধেকে আবার একই প্রক্রিয়া রিকার্সিভভাবে প্রয়োগ করুন।

ফলাফল — ফাংশনটি যেখানে দ্রুত পরিবর্তিত হয় (যেখানে S ও S₂ অনেক আলাদা), সেখানে রিকার্সন গভীরে যায় এবং অনেক ছোট সাব-ইন্টারভাল তৈরি হয়। যেখানে ফাংশন প্রায় সমতল বা প্যারাবোলার মতো (S ≈ S₂), সেখানে রিকার্সন দ্রুত থেমে যায় — পয়েন্টগুলো স্বয়ংক্রিয়ভাবে "প্রয়োজনের জায়গায়" কেন্দ্রীভূত হয়।

৩ · সত্যিকারের ডেমো — একটি তীক্ষ্ণ-শিখরযুক্ত ফাংশন

পরীক্ষার জন্য একটি ফাংশন বেছে নেওয়া হলো যার একটি সংকীর্ণ শিখর x = 5-এ আছে কিন্তু [0, 10] ইন্টারভালের বাকি অংশে প্রায় শূন্যের কাছাকাছি:

$$f(x) = \frac{1}{1 + 1000(x-5)^2}$$

এই ফাংশনের এন্টিডেরিভেটিভ আর্কট্যানজেন্ট ব্যবহার করে জানা যায়, তাই প্রকৃত ইন্টিগ্রাল নির্ভুলভাবে গণনা করে তুলনার রেফারেন্স হিসেবে ব্যবহার করা যায়।

Python
import math

def f(x):
    return 1.0 / (1.0 + 1000*(x-5.0)**2)

a, b = 0.0, 10.0
sa = math.sqrt(1000)
true_val = (1.0/sa) * (math.atan(sa*(b-5.0)) - math.atan(sa*(a-5.0)))
print(f"true integral = {true_val:.10f}")
print()

def simpson(f, a, b, n):
    h = (b-a)/n
    total = f(a) + f(b)
    for i in range(1, n):
        x = a + i*h
        total += (4 if i % 2 != 0 else 2)*f(x)
    return total*h/3

print("স্থির/ইউনিফর্ম গ্রিডে কম্পোজিট সিম্পসনস:")
for n in [16, 64, 256, 1024]:
    approx = simpson(f, a, b, n)
    err = abs(approx-true_val)
    print(f"  n={n:>5} (evals={n+1:>5})  approx={approx:.10f}  error={err:.3e}")

    
প্রকৃত ইন্টিগ্রাল ০.০৯৮৯৪৫৮৮৮০। n = 16-এ এরর ৩.২৩৫ × ১০⁻¹ — পুরোপুরি ভুল দিকে! কারণ ইন্টারভাল [0,10]-এ মাত্র ১৬টি সমান-দূরত্বের পয়েন্টের মধ্যে শিখরের সরু অঞ্চলটি প্রায় সম্পূর্ণ মিস হয়ে যাচ্ছে। এমনকি n = 1024-এ (১০২৫টি ফাংশন-ইভ্যালুয়েশন) গিয়েও এরর ২.৫২৯ × ১০⁻⁶ — এখনো যথেষ্ট বড়।

এবার একই ফাংশনে অ্যাডাপটিভ সিম্পসনস প্রয়োগ করা যাক — একটি রিকার্সিভ ফাংশন যা প্রতিটি সাব-ইন্টারভালে স্থানীয় এরর এস্টিমেট পরীক্ষা করে সিদ্ধান্ত নেয় আরও ভাঙতে হবে কিনা:

Python
import math

def f(x):
    return 1.0 / (1.0 + 1000*(x-5.0)**2)

a, b = 0.0, 10.0
sa = math.sqrt(1000)
true_val = (1.0/sa) * (math.atan(sa*(b-5.0)) - math.atan(sa*(a-5.0)))

def simpson_rule(fa, fm, fb, a, b):
    return (b - a) / 6 * (fa + 4*fm + fb)

def adaptive_simpson(f, a, b, tol, fa=None, fm=None, fb=None, depth=0, max_depth=50):
    if fa is None: fa = f(a)
    if fm is None: fm = f((a+b)/2)
    if fb is None: fb = f(b)
    S = simpson_rule(fa, fm, fb, a, b)

    m = (a+b)/2
    lm, rm = (a+m)/2, (m+b)/2
    flm, frm = f(lm), f(rm)
    S_left  = simpson_rule(fa, flm, fm, a, m)
    S_right = simpson_rule(fm, frm, fb, m, b)
    S2 = S_left + S_right

    if depth >= max_depth or abs(S2 - S) < 15*tol:
        return S2 + (S2 - S)/15   # রিচার্ডসন-স্টাইল সংশোধন, L22 দেখুন
    return (adaptive_simpson(f, a, m, tol/2, fa, flm, fm, depth+1, max_depth) +
            adaptive_simpson(f, m, b, tol/2, fm, frm, fb, depth+1, max_depth))

evals_count = [0]
def f_counted(x):
    evals_count[0] += 1
    return f(x)

result = adaptive_simpson(f_counted, a, b, 1e-8)
err = abs(result - true_val)
print(f"true integral        = {true_val:.10f}")
print(f"adaptive Simpson     = {result:.10f}")
print(f"error                = {err:.3e}")
print(f"function evaluations = {evals_count[0]}")

    
অ্যাডাপটিভ সিম্পসনস মাত্র ৮৮৯টি ফাংশন-ইভ্যালুয়েশন ব্যবহার করে এরর ২.৯১৫ × ১০⁻¹⁰ পৌঁছায় — ইউনিফর্ম গ্রিডের n = 1024 (১০২৫ ইভ্যালুয়েশন, প্রায় সমান সংখ্যক ফাংশন-কল) ব্যবহার করেও যে এরর ছিল (২.৫২৯ × ১০⁻⁶), তার চেয়ে প্রায় ৮৭০০ গুণ বেশি নির্ভুল — কম বা সমান সংখ্যক ফাংশন-কল ব্যবহার করে! এটাই অ্যাডাপটিভ কোয়াড্রেচারের আসল শক্তি — এটি স্বয়ংক্রিয়ভাবে "বুঝে নেয়" শিখরের কাছাকাছি বেশি রেজোলিউশন দরকার, আর বাকি সমতল অঞ্চলে কম যথেষ্ট — গণনার প্রতিটি একক ইভ্যালুয়েশন যেখানে সবচেয়ে বেশি কাজে লাগে, ঠিক সেখানেই ব্যয় করা হয়।
মূল কথা · Key takeaway

কম্পোজিট রুল ফাংশন সম্পর্কে কোনো তথ্য ছাড়াই একটি স্থির গ্রিড চাপিয়ে দেয়। অ্যাডাপটিভ কোয়াড্রেচার প্রতিটি সাব-ইন্টারভালের নিজের এরর এস্টিমেট ব্যবহার করে গ্রিডকে ফাংশনের আচরণের সাথে খাপ খাইয়ে নেয় — এই "রিসোর্স যেখানে দরকার সেখানে খরচ করা" নীতি অপ্টিমাইজেশনে (M9) ও ODE সলভারে (M6-M7, যেমন অ্যাডাপটিভ স্টেপ-সাইজ RK-মেথড) বারবার ফিরে আসবে।

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

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

প্র ০১ অ্যাডাপটিভ সিম্পসনসের কোডে প্রতিটি রিকার্সিভ কলে tol-কে tol/2 করে ভাগ করা হয়েছে (দুই সাব-ইন্টারভালে পাঠানোর সময়)। কেন এটি প্রয়োজন?

মূল লক্ষ্য পুরো ইন্টারভালের মোট এরর একটি টলারেন্সের মধ্যে রাখা। যদি ইন্টারভালটি দুই ভাগে ভাগ করা হয় এবং প্রতিটি অর্ধেক তার নিজের মধ্যে পুরো tol পরিমাণ এরর "অনুমতি" পায়, তাহলে দুই অর্ধেকের মোট এরর যোগ হয়ে মূল tol-এর দ্বিগুণ পর্যন্ত হয়ে যেতে পারে। tol-কে অর্ধেক করে ভাগ করলে প্রতিটি অর্ধেকের এরর বাজেট এমনভাবে নিয়ন্ত্রিত হয় যাতে যোগফল মূল টলারেন্স অতিক্রম না করে।

প্র ০২ কোডে max_depth নামের একটি সীমা রাখা হয়েছে। এটি না রাখলে কী সমস্যা হতে পারত?

যদি ফাংশনটি এত অসংলগ্ন বা তীক্ষ্ণ হয় (বা কোনো বাগের কারণে) যে S ও S₂ কখনোই টলারেন্সের মধ্যে না আসে, রিকার্সন তাত্ত্বিকভাবে অসীম গভীরে যেতে পারে — বাস্তবে এটি Python-এর রিকার্সন লিমিট অতিক্রম করে ক্র্যাশ করবে বা সিমুলেশন সীমাহীন সময় ধরে চলবে। max_depth একটি নিরাপত্তা গার্ড হিসেবে কাজ করে — এটি এই কোর্সের CLAUDE.md-এ উল্লেখিত "গার্ড রাখুন যাতে ক্র্যাশ বা হ্যাং না হয়" নীতির একটি সরাসরি প্রয়োগ।

প্র ০৩ উপরের ডেমোতে ইউনিফর্ম গ্রিড n = 16-এ শিখরটি প্রায় সম্পূর্ণ মিস করেছিল। যদি ফাংশনের শিখরের অবস্থান আগে থেকে জানা থাকত (যেমন x = 5), তাহলে কি অ্যাডাপটিভ মেথড ছাড়াই ভালো ফলাফল পাওয়া সম্ভব ছিল?

হ্যাঁ — যদি শিখরের অবস্থান আগে থেকে জানা থাকে, ইন্টারভালকে ম্যানুয়ালি ভেঙে শিখরের কাছে বেশি ঘনত্বের পয়েন্ট বসিয়ে একটি "নন-ইউনিফর্ম কিন্তু হাতে-ডিজাইন করা" গ্রিড ব্যবহার করা সম্ভব। কিন্তু বাস্তবে বেশিরভাগ সময় ফাংশনের "কঠিন" অংশ কোথায় তা আগে থেকে জানা থাকে না — অ্যাডাপটিভ মেথডের আসল সুবিধা হলো এটি স্বয়ংক্রিয়ভাবে, কোনো আগাম জ্ঞান ছাড়াই, সেই কঠিন অংশগুলো খুঁজে বের করে।

অনুশীলন

  1. চিন্তা করুন: দ্বিতীয় কোড সেলে tol = 1e-8-কে tol = 1e-4-এ (কম কঠোর টলারেন্স) পরিবর্তন করলে evals_count বাড়বে না কমবে বলে আপনার ধারণা?

    কমবে — কম কঠোর টলারেন্স মানে অ্যাডাপটিভ অ্যালগরিদম আগেই "যথেষ্ট নির্ভুল" ধরে নিয়ে রিকার্সন থামিয়ে দেবে, ফলে কম সাব-ইন্টারভাল তৈরি হবে এবং কম ফাংশন-ইভ্যালুয়েশন লাগবে — কিন্তু চূড়ান্ত এরর আগের চেয়ে বড় হবে।

  2. পরীক্ষা করুন: দ্বিতীয় কোড সেলে tol = 1e-4 সেট করে Run চেপে evals_count ও error কতটা বদলায় দেখুন, এবং প্রথম কোড সেলের ইউনিফর্ম n=256 ফলাফলের সাথে তুলনা করুন।

    tol = 1e-4-এ অ্যাডাপটিভ মেথড উল্লেখযোগ্যভাবে কম ফাংশন-ইভ্যালুয়েশন ব্যবহার করবে (মূল tol=1e-8-এর ৮৮৯টির চেয়ে অনেক কম), তবুও তার এরর ইউনিফর্ম n=256 (২৫৭ ইভ্যালুয়েশন, এরর ৪.০০৩ × ১০⁻³)-এর চেয়ে ভালো বা কাছাকাছি থাকবে — অ্যাডাপটিভ মেথডের দক্ষতা টলারেন্সের কড়াকড়ি নির্বিশেষে বজায় থাকে, কারণ এটি সবসময় পয়েন্টগুলো সবচেয়ে প্রয়োজনীয় জায়গায় কেন্দ্রীভূত করে।

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

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ এরর অ্যানালাইসিস, রুট-ফাইন্ডিং, লিনিয়ার সিস্টেম, ইন্টারপোলেশন, নিউমেরিক্যাল ইন্টিগ্রেশন, ODE সলভিং, আইগেনভ্যালু মেথড, অপ্টিমাইজেশন ও ক্যাপস্টোন — বাকি পাঠগুলো একে একে যুক্ত হচ্ছে।
  • L24 · সিম্পসনস রুল পূর্ববর্তী পাঠ অ্যাডাপটিভ কোয়াড্রেচারের ভিত্তি — একই সিম্পসনস ফর্মুলা, এবার রিকার্সিভভাবে প্রয়োগ করা।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, Machine Learning, Deep Learning, System Design, Cybersecurity, Cloud Computing & DevOps, এবং আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
সিম্পসনস রুল