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

ম্যাট্রিক্স নর্ম, কন্ডিশন নাম্বার ও এরর বাউন্ড

Matrix norms, condition number & error bounds
১১ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • ম্যাট্রিক্স নর্ম কী এবং ইনফিনিটি-নর্ম কীভাবে হাতে গণনা করা হয়
  • কন্ডিশন নাম্বারের সংজ্ঞা এবং এটি L04-এর কন্ডিশনিং ধারণার সাথে কীভাবে সম্পর্কিত
  • Gauss-Jordan পদ্ধতিতে হাতে ম্যাট্রিক্স ইনভার্স বের করা
  • একটি সত্যিকারের, চলমান Python ডেমো — ভালো বনাম খারাপ-কন্ডিশনড ম্যাট্রিক্সের কন্ডিশন নাম্বার ও perturbation-প্রতিক্রিয়া তুলনা

১ · ম্যাট্রিক্স নর্ম — একটি ম্যাট্রিক্সের "আকার"

একটি সংখ্যার absolute value যেমন তার "আকার" বোঝায়, তেমনি একটি ম্যাট্রিক্সের নর্ম তার সামগ্রিক "আকার" একটি একক সংখ্যায় প্রকাশ করে। এই পাঠে আমরা ইনফিনিটি-নর্ম ব্যবহার করি, যা গণনা করা সবচেয়ে সহজ:

$$\|A\|_\infty = \max_{i} \sum_{j} |a_{ij}|$$

অর্থাৎ প্রতিটি সারির উপাদানগুলোর absolute value যোগ করে, তারপর সব সারির মধ্যে সর্বোচ্চ যোগফলটি নেওয়া হয়।

২ · কন্ডিশন নাম্বার — সংবেদনশীলতার পরিমাপ

L04-এ আমরা ধারণাগতভাবে দেখেছিলাম একটি সিস্টেম "ভালো" বা "খারাপ" কন্ডিশনড হতে পারে। এখন সেই ধারণাটিকে একটি সুনির্দিষ্ট সংখ্যায় রূপান্তর করা যাক:

$$\kappa(A) = \|A\| \times \|A^{-1}\|$$

κ(A) যত বড়, সিস্টেমটি তত বেশি ill-conditioned — অর্থাৎ b-এর একটি ছোট পরিবর্তন x-এ একটি বড়, অসামঞ্জস্যপূর্ণ পরিবর্তন ঘটাতে পারে। κ(A) = ১ সবচেয়ে ভালো (আদর্শ) কন্ডিশনিং নির্দেশ করে; κ(A) যত বড় হয়, ততই সিস্টেম সংবেদনশীল হয়ে ওঠে — এমনকি সঠিকভাবে বাস্তবায়িত গসিয়ান এলিমিনেশন/পিভোটিং (L10-L12) থাকলেও।

ম্যাট্রিক্স ইনভার্স
A⁻¹ এমন একটি ম্যাট্রিক্স যেন A × A⁻¹ = I (আইডেন্টিটি ম্যাট্রিক্স)। Gauss-Jordan পদ্ধতিতে [A | I] augmented ম্যাট্রিক্সে এলিমিনেশন চালিয়ে [I | A⁻¹] রূপে পৌঁছানো যায়।
Forward error বাউন্ড
কন্ডিশন নাম্বার সরাসরি একটি এরর বাউন্ড দেয়: relative input error-কে κ(A) গুণ করলে relative output error-এর একটি উচ্চ-সীমা পাওয়া যায় (আনুমানিক)।
Singular-এর কাছাকাছি
যখন A singular-এর (ডিটারমিন্যান্ট শূন্য) খুব কাছাকাছি চলে যায়, A⁻¹-এর উপাদান বিশাল হয়ে যায়, ফলে κ(A)ও বিশাল হয়ে যায় — L12-এর near-singular সিস্টেমের সাথে সরাসরি সম্পর্কিত।

৩ · একটি সত্যিকারের ডেমো — ভালো বনাম খারাপ-কন্ডিশনড ম্যাট্রিক্স

নিচে একটি সাধারণ ইনফিনিটি-নর্ম ফাংশন এবং Gauss-Jordan পদ্ধতিতে একটি হাতে-লেখা ম্যাট্রিক্স-ইনভার্স ফাংশন লেখা হয়েছে। দুটি 2x2 ম্যাট্রিক্সে — একটি স্পষ্টত ভালো-কন্ডিশনড, আরেকটি প্রায়-singular (খারাপ কন্ডিশনড) — কন্ডিশন নাম্বার গণনা করে তুলনা করা হয়েছে, এবং সবশেষে b-তে ছোট perturbation-এর প্রকৃত প্রভাব দেখানো হয়েছে।

Python
def inf_norm(A):
    # ম্যাট্রিক্স ইনফিনিটি-নর্ম = সারিগুলোর absolute-value যোগফলের মধ্যে সর্বোচ্চটি
    return max(sum(abs(v) for v in row) for row in A)

def mat_inverse(A):
    n = len(A)
    M = [A[i][:] + [1.0 if i == j else 0.0 for j in range(n)] for i in range(n)]

    for col in range(n):
        pivot_row = max(range(col, n), key=lambda r: abs(M[r][col]))
        if abs(M[pivot_row][col]) < 1e-15:
            raise ValueError("ম্যাট্রিক্সটি singular -- inverse নেই")
        M[col], M[pivot_row] = M[pivot_row], M[col]

        pivot_val = M[col][col]
        M[col] = [v / pivot_val for v in M[col]]

        for r in range(n):
            if r != col:
                factor = M[r][col]
                M[r] = [M[r][k] - factor * M[col][k] for k in range(2 * n)]

    return [row[n:] for row in M]

def mat_mult(X, Y):
    n, m, p = len(X), len(Y), len(Y[0])
    return [[sum(X[i][t] * Y[t][j] for t in range(m)) for j in range(p)] for i in range(n)]

def condition_number(A):
    A_inv = mat_inverse(A)
    return inf_norm(A) * inf_norm(A_inv), A_inv

print("=== ভালোভাবে-কন্ডিশনড (well-conditioned) ম্যাট্রিক্স ===")
A_good = [[4.0, 1.0], [2.0, 3.0]]
cond_good, Ainv_good = condition_number(A_good)
print("A =", A_good)
print("||A||_inf =", inf_norm(A_good))
print("A^-1 =", [[round(v, 6) for v in row] for row in Ainv_good])
print("||A^-1||_inf =", round(inf_norm(Ainv_good), 6))
print(f"কন্ডিশন নাম্বার κ(A) = {cond_good:.6f}")

print()
print("=== খারাপভাবে-কন্ডিশনড (ill-conditioned) ম্যাট্রিক্স ===")
A_bad = [[1.0, 1.0], [1.0, 1.0001]]
cond_bad, Ainv_bad = condition_number(A_bad)
print("A =", A_bad)
print("||A||_inf =", inf_norm(A_bad))
print("A^-1 =", [[round(v, 4) for v in row] for row in Ainv_bad])
print("||A^-1||_inf =", round(inf_norm(Ainv_bad), 4))
print(f"কন্ডিশন নাম্বার κ(A) = {cond_bad:.4f}")

print()
print(f"তুলনা: κ(A_good) = {cond_good:.4f}   বনাম   κ(A_bad) = {cond_bad:.2f}")
print(f"অনুপাত = {cond_bad / cond_good:.1f}x")

def solve_2x2(A, b):
    det = A[0][0]*A[1][1] - A[0][1]*A[1][0]
    x0 = (b[0]*A[1][1] - A[0][1]*b[1]) / det
    x1 = (A[0][0]*b[1] - b[0]*A[1][0]) / det
    return [x0, x1]

b1 = [2.0, 2.0]
b2 = [2.0, 2.001]   # b-তে মাত্র 0.001 পার্থক্য

print()
print("=== ছোট perturbation-এর প্রভাব (b-তে 0.001 পরিবর্তন) ===")
for name, A in [("good", A_good), ("bad", A_bad)]:
    x1 = solve_2x2(A, b1)
    x2 = solve_2x2(A, b2)
    change = max(abs(x1[i]-x2[i]) for i in range(2))
    print(f"{name}: x পরিবর্তন = {change:.6f}")
=== ভালোভাবে-কন্ডিশনড (well-conditioned) ম্যাট্রিক্স ===
A = [[4.0, 1.0], [2.0, 3.0]]
||A||_inf = 5.0
A^-1 = [[0.3, -0.1], [-0.2, 0.4]]
||A^-1||_inf = 0.6
কন্ডিশন নাম্বার κ(A) = 3.000000

=== খারাপভাবে-কন্ডিশনড (ill-conditioned) ম্যাট্রিক্স ===
A = [[1.0, 1.0], [1.0, 1.0001]]
||A||_inf = 2.0000999999999998
A^-1 = [[10001.0, -10000.0], [-10000.0, 10000.0]]
||A^-1||_inf = 20001.0
কন্ডিশন নাম্বার κ(A) = 40004.0001

তুলনা: κ(A_good) = 3.0000   বনাম   κ(A_bad) = 40004.00
অনুপাত = 13334.7x

=== ছোট perturbation-এর প্রভাব (b-তে 0.001 পরিবর্তন) ===
good: x পরিবর্তন = 0.000400
bad: x পরিবর্তন = 10.000000
সংখ্যাগুলো নিজেরাই কথা বলছে: ভালো-কন্ডিশনড ম্যাট্রিক্সের κ = ৩, খারাপ-কন্ডিশনডের κ ≈ ৪০,০০৪ — ১৩,৩৩৪ গুণ বেশি। আর এর ব্যবহারিক ফলাফল সরাসরি দেখা যাচ্ছে: b-তে মাত্র ০.০০১ পরিবর্তনে ভালো-কন্ডিশনড সিস্টেমে x নড়ে মাত্র ০.০০০৪, কিন্তু খারাপ-কন্ডিশনড সিস্টেমে x নড়ে পুরো ১০.০ — একই ইনপুট-পরিবর্তনের জন্য ২৫,০০০ গুণ বড় আউটপুট-পরিবর্তন।
মূল কথা · Key takeaway

কন্ডিশন নাম্বার একটি সিস্টেমের অন্তর্নিহিত বৈশিষ্ট্য — এটি কোনো নির্দিষ্ট এলিমিনেশন অ্যালগরিদমের ত্রুটি নয় (L12-এর পিভোটিং এটি ঠিক করতে পারে না)। বাস্তব ব্যবহারে, যদি κ(A) অনেক বড় হয়, তাহলে সিস্টেমটি নিজেই পুনর্গঠন করা প্রয়োজন হতে পারে (যেমন regularization, বা সমস্যার ভৌত মডেলিং পুনর্বিবেচনা) — শুধু আরও নির্ভুল arithmetic ব্যবহার করে এটি সমাধান করা যায় না। L50-এ forward/backward error analysis-এ এই ধারণাটি আরও গভীরভাবে বিশ্লেষণ করা হবে।

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

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

প্র ০১ কোড সেলে if abs(M[pivot_row][col]) < 1e-15: লাইনটি কেন আছে, এবং এটি L12-এর কোন ধারণার সাথে সরাসরি সম্পর্কিত?

এটি Gauss-Jordan ইনভার্স-গণনায় partial pivoting প্রয়োগ করছে (L12-এর একই কৌশল) — কলামের মধ্যে সবচেয়ে বড় absolute মান খুঁজে পিভোট হিসেবে বেছে নিচ্ছে, এবং যদি সেটিও কার্যত শূন্য হয় তাহলে ম্যাট্রিক্সটি সত্যিই singular ধরে নিয়ে একটি স্পষ্ট এরর ছুঁড়ে দিচ্ছে — নীরবে ভুল উত্তর দেওয়ার বদলে।

প্র ০২ A_bad-এর দুটি সারি ([1,1] ও [1, 1.0001]) প্রায় হুবহু একই — এটি জ্যামিতিকভাবে কী বোঝায়, এবং কেন এটি কন্ডিশন নাম্বার এত বড় করে তোলে?

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

প্র ০৩ যদি A_bad-এর দ্বিতীয় সারি ঠিক [1, 1] (অর্থাৎ প্রথম সারির হুবহু কপি) হতো, তাহলে mat_inverse ফাংশনে কী ঘটত?

তখন ম্যাট্রিক্সটি সত্যিকারের singular হয়ে যেত (ডিটারমিন্যান্ট ঠিক শূন্য) — কোনো ইনভার্স অস্তিত্ব থাকত না। কোড সেলে pivot_row নির্বাচনের পরও abs(M[pivot_row][col]) শূন্যের কাছাকাছি থেকে যেত, এবং raise ValueError("ম্যাট্রিক্সটি singular -- inverse নেই") লাইনটি কার্যকর হতো — কন্ডিশন নাম্বার তখন গাণিতিকভাবে অসীম।

অনুশীলন

  1. চিন্তা করুন: উপরের কোড সেলে A_bad-এর 1.0001-কে 1.00001 (আরও কাছাকাছি) করলে কন্ডিশন নাম্বার আরও বাড়বে না কমবে বলে আপনার মনে হয়?

    বাড়বে — সারি দুটো যত বেশি একে অপরের কাছাকাছি (প্রায়-সমান্তরাল) হয়, ম্যাট্রিক্সটি তত বেশি singular-এর কাছাকাছি চলে যায়, এবং A⁻¹-এর উপাদান তত বেশি বিশাল হয়ে যায় — ফলে কন্ডিশন নাম্বার আরও অনেক বেশি বড় হবে।

  2. পরীক্ষা করুন: উপরের কোড সেলে A_bad-এর 1.0001-কে 1.00001-এ পরিবর্তন করে Run চেপে নতুন কন্ডিশন নাম্বার যাচাই করুন।

    নতুন কন্ডিশন নাম্বার প্রায় κ ≈ ৪০০,০০৪-এর কাছাকাছি চলে যায় — আগের ৪০,০০৪-এর প্রায় ১০ গুণ, ঠিক যেমন অনুমান করা হয়েছিল। এই প্যাটার্নটি সাধারণীকরণযোগ্য: পিভটের কাছাকাছি দূরত্ব যত ছোট হয়, কন্ডিশন নাম্বার তার বিপরীত অনুপাতে বাড়ে।

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

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