পাঠ ০৫ · ৫৭-এর মধ্যে · মডিউল ২
Home / Courses / Numerical Methods / রুট-ফাইন্ডিং ও বাইসেকশন

রুট-ফাইন্ডিং সমস্যা ও বাইসেকশন মেথড

The root-finding problem & bisection method
৮ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

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

১ · রুট-ফাইন্ডিং সমস্যা কী

রুট-ফাইন্ডিং সমস্যাRoot-finding problemএকটি ফাংশন f(x) দেওয়া থাকলে, এমন x মান (মূল বা root) খুঁজে বের করা যেখানে f(x) = 0। হলো নিউমেরিক্যাল অ্যানালাইসিসের সবচেয়ে মৌলিক ও ব্যাপক-প্রয়োগযোগ্য সমস্যাগুলোর একটি: একটি ফাংশন f(x) দেওয়া থাকলে, এমন এক বা একাধিক x মান বের করা যেখানে f(x) = 0। এই ফর্মটি বিস্ময়কর রকম সাধারণ — f(x) = x - cos(x) লিখলে L01-এর সমীকরণ x = cos(x)-ও একটি রুট-ফাইন্ডিং সমস্যা, আর যেকোনো সমীকরণ g(x) = h(x)-কে f(x) = g(x) - h(x) = 0 আকারে লেখা যায়।

এই মডিউল (M2) জুড়ে আমরা একই ধরনের সমস্যা — একটি একক-চলকের অ-লিনিয়ার সমীকরণ সমাধান — বিভিন্ন কৌশলে সমাধান করব: বাইসেকশন (এই পাঠ), ফিক্সড-পয়েন্ট ইটারেশন (L06), নিউটন-রাফসন (L07), সেকেন্ট ও রেগুলা ফালসি (L08), এবং সবশেষে L09-এ সবগুলো মেথড একসাথে তুলনা করা হবে।

প্রকৌশলে
একটি স্ট্রাকচারের ভার-বহন ক্ষমতা কোন লোডে ভেঙে পড়ে তা বের করতে f(লোড) = স্ট্রেস - ধারণক্ষমতা = 0 সমাধান করা হয়।
ফাইন্যান্সে
একটি বন্ডের প্রকৃত রিটার্ন রেট (yield) বের করা মানে একটি নন-লিনিয়ার সমীকরণের রুট বের করা (M12/L54-এ বিস্তারিত)।
বিজ্ঞানে
রাসায়নিক ভারসাম্য (equilibrium concentration) বা কোনো সিস্টেমের স্থির-অবস্থা (steady state) বের করাও প্রায়ই একটি রুট-ফাইন্ডিং সমস্যা।

২ · ইন্টারমিডিয়েট ভ্যালু থিওরেম — বাইসেকশনের ভিত্তি

বাইসেকশন মেথড একটি একদম সরল কিন্তু শক্তিশালী গাণিতিক সত্যের উপর দাঁড়িয়ে আছে — ইন্টারমিডিয়েট ভ্যালু থিওরেমIntermediate Value Theorem (IVT)যদি f একটি কন্টিনিউয়াস ফাংশন হয় এবং [a, b]-এর উপর f(a) ও f(b)-এর চিহ্ন বিপরীত হয়, তাহলে (a, b)-এর মধ্যে অন্তত একটি বিন্দু c থাকবে যেখানে f(c) = 0।। সহজ কথায়: যদি একটি কন্টিনিউয়াস (অবিচ্ছিন্ন) ফাংশন একটি ইন্টারভালের এক প্রান্তে ঋণাত্মক এবং অন্য প্রান্তে ধনাত্মক হয়, তাহলে মাঝে কোথাও এটি অবশ্যই শূন্য হবে — কারণ একটি কন্টিনিউয়াস ফাংশন "লাফ দিয়ে" চিহ্ন পরিবর্তন করতে পারে না।

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

বাইসেকশন অ্যালগরিদম — সংক্ষেপে

১) এমন a, b বেছে নাও যেখানে f(a) ও f(b)-এর চিহ্ন বিপরীত। ২) মধ্যবিন্দু m = (a+b)/2 গণনা করো। ৩) যদি f(a) ও f(m)-এর চিহ্ন বিপরীত হয়, রুট বামের অর্ধেকে — তাই b = m সেট করো; নাহলে রুট ডানের অর্ধেকে — তাই a = m সেট করো। ৪) কাঙ্ক্ষিত নির্ভুলতা না পাওয়া পর্যন্ত ২-৩ পুনরাবৃত্তি করো।

৩ · একটি নতুন উদাহরণ — x³ - x - 2 = 0

L01-এ আমরা x = cos(x) সমাধান করেছিলাম। এই পাঠে ধারাবাহিকতা বজায় রেখে কিন্তু একটি নতুন সমীকরণ ব্যবহার করব যা এই পুরো M2 মডিউল জুড়ে (L06–L09-এ) বারবার ফিরে আসবে:

$$f(x) = x^3 - x - 2 = 0$$

প্রথমে একটি ব্র্যাকেট (bracket) বের করতে হবে যেখানে চিহ্ন বিপরীত। f(1) = 1 - 1 - 2 = -2 (ঋণাত্মক) এবং f(2) = 8 - 2 - 2 = 4 (ধনাত্মক) — তাই IVT অনুযায়ী 1 ও 2-এর মাঝে একটি রুট নিশ্চিতভাবে আছে। নিচের কোড সেলে বাইসেকশন মেথড দিয়ে এই রুটটি ধাপে ধাপে বের করা হয়েছে, প্রতিটি ইটারেশনে একটি অত্যন্ত নির্ভুল রেফারেন্স মূলের (২০০ ইটারেশনের বাইসেকশন দিয়ে আগেই গণনা করা) বিপরীতে প্রকৃত এরর দেখানো হয়েছে।

Python
def f(x):
    return x**3 - x - 2

a, b = 1.0, 2.0
print(f"f({a}) = {f(a):.6f}   f({b}) = {f(b):.6f}")
print()

# অনেক বেশি ইটারেশন চালিয়ে একটি অত্যন্ত নির্ভুল রেফারেন্স মূল আগেই বের করা
ra, rb = 1.0, 2.0
for _ in range(200):
    m = (ra + rb) / 2
    if f(ra) * f(m) < 0:
        rb = m
    else:
        ra = m
reference_root = (ra + rb) / 2
print(f"রেফারেন্স মূল (২০০ ইটারেশন পর): {reference_root:.10f}")
print()

N = 12
a, b = 1.0, 2.0
print(f"{'ইটার':>4} {'x':>12} {'f(x)':>12} {'প্রস্থ':>10} {'এরর':>12}")
for i in range(1, N + 1):
    mid = (a + b) / 2
    fm = f(mid)
    if f(a) * fm < 0:
        b = mid
    else:
        a = mid
    err = abs(mid - reference_root)
    print(f"{i:4d} {mid:12.6f} {fm:+12.6f} {b - a:10.6f} {err:12.8f}")

final = (a + b) / 2
print()
print(f"{N} ইটারেশন পর চূড়ান্ত আনুমানিক মূল: {final:.6f}")
print(f"চূড়ান্ত প্রকৃত এরর: {abs(final - reference_root):.8f}")

    
কোডটি চালালে দেখা যায় রেফারেন্স মূল ১.৫২১৩৭৯৭০৬৮, এবং ১২ ইটারেশন পর চূড়ান্ত আনুমানিক মূল ১.৫২১৩৬২৩০৪৭ — প্রকৃত এরর মাত্র ০.০০০০১৭৪০। লক্ষ্য করুন ইটারেশন ৯-এ এরর হঠাৎ ০.০০০১০৪৬৭-এ নেমে যায় (কারণ মধ্যবিন্দুটি রুটের খুব কাছাকাছি পড়ে যায়), কিন্তু তারপরও ইন্টারভাল প্রস্থ কমতে থাকে বলে এরর সামগ্রিকভাবে নির্ভরযোগ্যভাবে সংকুচিত হতেই থাকে — এটাই বাইসেকশনের মূল গ্যারান্টি।

৪ · এরর বাউন্ড ও লিনিয়ার কনভারজেন্স

বাইসেকশনের একটি বিশেষ শক্তি হলো এর এররের উপর একটি গাণিতিকভাবে প্রমাণযোগ্য উপরের সীমা আছে। যদি প্রাথমিক ইন্টারভাল প্রস্থ b - a হয়, তাহলে nটি ইটারেশন পর এরর সবসময় নিশ্চিতভাবে:

$$|x_n - x^*| \le \frac{b - a}{2^{n+1}}$$

এই সূত্রের মানে হলো আমরা আগে থেকেই বলতে পারি ঠিক কত ইটারেশন লাগবে একটি নির্দিষ্ট নির্ভুলতায় পৌঁছাতে — অন্য কোনো তথ্য ছাড়াই। যেহেতু এরর প্রতি ধাপে একটি স্থির অনুপাতে (অর্ধেক) কমে, একে লিনিয়ার কনভারজেন্সLinear convergenceযখন প্রতি ইটারেশনে এরর একটি স্থির অনুপাতে (এখানে ১/২) কমে যায় — কনভারজেন্স রেট সম্পর্কে বিস্তারিত L09-এ। বলা হয় — L01-এর বাইসেকশন ডেমোতেও এই একই বৈশিষ্ট্য দেখা গিয়েছিল।

সহোদর পাঠের সাথে সম্পর্ক

M1/L04-এ আমরা অ্যালগরিদম কনভারজেন্স সাধারণভাবে আলোচনা করেছিলাম — এই পাঠ সেই ধারণাকে একটি নির্দিষ্ট, সম্পূর্ণ বাস্তবায়িত মেথডে প্রয়োগ করে দেখাল। L09-এ আমরা বাইসেকশনের এই লিনিয়ার কনভারজেন্স রেটকে নিউটন-রাফসনের কোয়াড্রেটিক কনভারজেন্স রেটের সাথে সরাসরি, সংখ্যাগতভাবে তুলনা করব।

৫ · বাইসেকশনের সীমাবদ্ধতা

ধীরগতি
প্রতি ইটারেশনে মাত্র ১ বিট নির্ভুলতা যোগ হয় — উচ্চ নির্ভুলতার জন্য অনেক ইটারেশন লাগে (L09-এ Newton-Raphson-এর সাথে সরাসরি তুলনা)।
ব্র্যাকেট প্রয়োজন
শুরুতেই এমন দুটি বিন্দু দরকার যেখানে চিহ্ন বিপরীত — যদি এমন কোনো বিন্দু-জোড়া সহজে না পাওয়া যায়, মেথডটি শুরুই করা যায় না।
জোড়-গুণিতক রুট
যেখানে ফাংশন রুটের কাছে চিহ্ন পরিবর্তন করে না (যেমন (x-r)²-এর মতো ইভেন-মাল্টিপ্লিসিটি রুট), সেখানে বাইসেকশন প্রযোজ্য নয়।

এই সীমাবদ্ধতাগুলোই পরবর্তী পাঠগুলোর প্রেরণা: L06-এ ফিক্সড-পয়েন্ট ইটারেশন ব্র্যাকেট ছাড়াই কাজ করার চেষ্টা করবে, আর L07-এর নিউটন-রাফসন ফাংশনের ঢাল (derivative) ব্যবহার করে অনেক দ্রুত কনভার্জ করবে — যদিও প্রতিটি নতুন মেথডই নিজস্ব নতুন ঝুঁকি নিয়ে আসবে।

মূল কথা · Key takeaway

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

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

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

প্র ০১ উপরের কোডে আমরা [1, 2] ব্র্যাকেট বেছে নিয়েছি। যদি আমরা পরিবর্তে [0, 1] ব্র্যাকেট বেছে নিতাম (যেখানে f(0) = -2 এবং f(1) = -2, দুটোই ঋণাত্মক), কী হতো?

বাইসেকশন শুরুই করা যেত না — বা শুরু করলেও ভুল ফলাফল দিত। যেহেতু f(0) ও f(1)-এর চিহ্ন একই, IVT কোনো নিশ্চয়তা দেয় না যে এই ইন্টারভালে রুট আছে (থাকতেও পারে, জোড়-সংখ্যক রুট থাকলে, কিন্তু নিশ্চিতভাবে নয়)। কোডে if f(a) * fm < 0 শর্তটি সবসময় একই দিকে সরে যেত, এবং ইন্টারভালটি ভুল জায়গায় সংকুচিত হতো, অথচ কোনো এরর মেসেজ ছাড়াই।

প্র ০২ এরর বাউন্ড সূত্র |error| ≤ (b-a)/2ⁿ⁺¹ ব্যবহার করে, [1,2] ব্র্যাকেট থেকে শুরু করে এরর 10⁻⁶-এর নিচে নামাতে কমপক্ষে কত ইটারেশন লাগবে বলে আপনার ধারণা?

1/2ⁿ⁺¹ ≤ 10⁻⁶ সমাধান করলে 2ⁿ⁺¹ ≥ 10⁶, অর্থাৎ n+1 ≥ log₂(10⁶) ≈ 19.93 — তাই n ≥ 19, মানে কমপক্ষে ১৯–২০ ইটারেশন লাগবে। এটি L09-এর সংখ্যাগত তুলনায় সরাসরি যাচাই করা হবে, যেখানে দেখা যাবে নিউটন-রাফসনের মাত্র ৫টি ইটারেশন লাগে একই নির্ভুলতায় পৌঁছাতে।

প্র ০৩ বাইসেকশন ফাংশনের ঢাল (derivative) সম্পূর্ণ উপেক্ষা করে, শুধু চিহ্ন ব্যবহার করে। আপনার কী মনে হয়, এটি কি বাইসেকশনকে বেশি নাকি কম "রোবাস্ট" (robust) করে তোলে?

বেশি রোবাস্ট — কারণ ঢাল ব্যবহার না করায় বাইসেকশন কখনো "বিভ্রান্ত" হয় না এমন জায়গায় যেখানে ঢাল খুব খাড়া, খুব সমতল, বা শূন্যের কাছাকাছি (L07-এ দেখা যাবে নিউটন-রাফসন ঠিক এই কারণেই মাঝেমধ্যে ব্যর্থ হয়)। কম তথ্য ব্যবহার করার মূল্য হলো ধীরগতি — বাইসেকশন প্রতি ধাপে শুধু "কোন অর্ধেকে" জানে, "কত কাছাকাছি" তা অনুমান করার কোনো উপায় নেই।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে N = 12-কে N = 16-এ বাড়ালে চূড়ান্ত এরর মোটামুটি কত গুণ ছোট হবে বলে আপনার ধারণা?

    ৪টি অতিরিক্ত ইটারেশন মানে ইন্টারভাল প্রস্থ আরও 2⁴ = 16 গুণ ছোট হবে, তাই এরর বাউন্ডও প্রায় ১৬ গুণ ছোট হওয়ার কথা (প্রকৃত এরর হয়তো এর চেয়ে কিছুটা কম বা বেশি হতে পারে, কারণ প্রকৃত এরর সবসময় বাউন্ডের চেয়ে ছোট থাকে, ঠিক বাউন্ডের সমান নয়)।

  2. পরীক্ষা করুন: কোড সেলে f(x)-কে x**3 - x - 2 থেকে বদলে x**2 - 2 করুন (যার প্রকৃত রুট √2 ≈ 1.41421356) এবং প্রাথমিক ব্র্যাকেট a, b = 1.0, 2.0 রেখে Run চেপে দেখুন কনভারজেন্স কেমন হয়।

    f(1) = -1 ও f(2) = 2 — চিহ্ন বিপরীত, তাই ব্র্যাকেটটি বৈধ। বাইসেকশন একই লিনিয়ার হারে (প্রতি ধাপে ইন্টারভাল অর্ধেক) √2-এর দিকে কনভার্জ করবে — মূল ফাংশন যা-ই হোক না কেন, বাইসেকশনের কনভারজেন্স রেট শুধু ইন্টারভাল প্রস্থের উপর নির্ভর করে, ফাংশনের নির্দিষ্ট আকৃতির উপর নয় (এটাই এর নির্ভরযোগ্যতার মূল কারণ)।

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

আগের পাঠ
অ্যালগরিদম স্ট্যাবিলিটি, কন্ডিশনিং ও কনভারজেন্স