সরাসরি পর্বে যান
পর্ব ১০ · ৭৭-এর মধ্যে · মডিউল ২

Positive definite matrix — quadratic form আর covariance

Positive Definite Matrices — Quadratic Forms, Definiteness Tests, Cholesky and Covariance

Taught in Bangla, this lesson reads xᵀAx as a height map with bowl, saddle and valley shapes, and tests definiteness by eigenvalues, leading minors and Cholesky. It works Cholesky by hand, proves covariance matrices are positive semidefinite, samples correlated Gaussians with x = μ + Lz, measures Mahalanobis distance, and links definiteness to Hessians, ridge and kernels.

এই পর্বে যা শিখবেন

  • Quadratic form xᵀAx হাতে হিসাব করা, আর কেন শুধু প্রতিসম অংশ (A + Aᵀ)/2 গুরুত্বপূর্ণ
  • Eigenvalue-এর চিহ্ন দেখে বাটি, জিন আর উপত্যকা চেনা, আর তার জ্যামিতিক কারণ
  • Positive definite-এর তিনটি পরীক্ষা (eigenvalue, Sylvester-এর minor, Cholesky), তাদের ফাঁদ আর পরীক্ষায় আসা হাতের হিসাব
  • Covariance আর Gram matrix কেন PSD, কখন rank কমে যায়, আর jitter কী সারায় ও কী লুকায়
  • Cholesky দিয়ে linear system সমাধান, correlated Gaussian sampling, Mahalanobis দূরত্ব, আর Hessian দিয়ে convexity-র প্রথম পরিচয়

AI-এর ভিত্তি কোর্সের পর্ব ১৭-এ matrix গুণ, solve আর condition number এসেছিল; পর্ব ৩৭-এ দুটি কলামের covariance আর correlation; আর পর্ব ৬৫-এ covariance-এর বড় দিক খুঁজে PCA. এই মডিউলের পর্ব ০৮ (Eigenvalue আর eigenvector — ধারণা থেকে PCA পর্যন্ত) প্রতিসম matrix-এর spectral theorem দেখায়। এই পর্বের প্রশ্ন: একটি প্রতিসম matrix কখন “ভালো আচরণের”, অর্থাৎ বাটির মতো, যার একটিই তলা আছে? উত্তরটি ML-এর প্রায় সব জায়গায় দরকার হয়: covariance, Gaussian, ridge, Newton পদ্ধতি, kernel. চালানো যায় এমন চারটি ব্লক পাতাতেই চলে (ব্রাউজারের Python, NumPy আর matplotlib); প্রথমবার প্যাকেজ নামতে কয়েক সেকেন্ড লাগে।

১ · Quadratic form xᵀAx — একটি matrix থেকে একটি উচ্চতার মানচিত্র

বর্ষার পর একটি মাঠের যেকোনো জায়গায় দাঁড়িয়ে মাটির উচ্চতা মাপছেন। কোনো মাঠ পুকুরের মতো: যেদিকেই যান, মাঝখান থেকে উঁচু হয়, আর পানি গড়িয়ে একটি বিন্দুতেই জমে। কোনো মাঠ ঘোড়ার জিনের মতো: সামনে-পেছনে উঁচু, ডানে-বাঁয়ে নিচু, পানি একদিকে গড়িয়ে চলেই যায়। আবার কোনো মাঠ একটি খালের মতো: দুই পাড় উঁচু, কিন্তু খালের তলা বরাবর পুরোটাই সমতল। একটি ২ × ২ matrix ঠিক এমন একটি মাঠের নকশা।

একটি বর্গাকার matrix A (আকার n × n) আর একটি vector x (দৈর্ঘ্য n) দিলে xᵀAx একটি সংখ্যা: প্রথমে Ax (একটি vector), তারপর x-এর সঙ্গে তার dot product. ᵀ মানে transpose, এখানে x-কে কলাম থেকে সারি বানানো। এই function-কে বলে quadratic form, কারণ এর প্রতিটি পদ x-এর দুটি উপাদানের গুণফল, অর্থাৎ ঘাত ২. ২ × ২ ক্ষেত্রে A = [[a, b], [c, d]] হলে:

xᵀAx = a·x1² + (b + c)·x1x2 + d·x2²

এখানে x1, x2 হলো x-এর দুটি উপাদান, a আর d কর্ণের দুটি ঘর, b আর c কর্ণের বাইরের দুটি। লক্ষ করুন, b আর c আলাদা করে আসে না, আসে শুধু তাদের যোগফল। তাই [[3, 1], [1, 2]] আর [[3, 2], [0, 2]] একই quadratic form দেয়। সাধারণ প্রমাণ এক লাইনের: xᵀAx একটি সংখ্যা, আর একটি সংখ্যার transpose সে নিজেই, তাই xᵀAx = (xᵀAx)ᵀ = xᵀAᵀx. দুটির গড় নিলে xᵀAx = xᵀ S x, যেখানে S = (A + Aᵀ)/2 হলো A-এর প্রতিসম অংশ। এজন্য এই পর্বে, আর সাধারণভাবে definiteness-এর আলোচনায়, A সবসময় symmetric matrix (A = Aᵀ) ধরা হয়।

একই সংখ্যা চার রাস্তায়: গুণ, পদ, বর্গ পূরণ, eigen-অক্ষ
ধাপ
হিসাব
সংখ্যায়
যা শিখছি
  1. শুরু। A প্রতিসম ২ × ২ matrix, আর x = (২, −১) মাঠের একটি বিন্দু। প্রশ্ন: এই বিন্দুতে “উচ্চতা” xᵀAx কত?
  2. প্রথমে Ax. প্রথম সারি: ৩·২ + ১·(−১) = ৫. দ্বিতীয় সারি: ১·২ + ২·(−১) = ০. তাই Ax = (৫, ০)।
  3. তারপর xᵀ(Ax). x আর (৫, ০)-এর dot product: ২·৫ + (−১)·০ = ১০. উচ্চতা ১০.
  4. পদ ধরে ধরে। সূত্রে বসাই: a·x₁² = ৩·৪ = ১২; (b + c)·x₁x₂ = ২·(২)(−১) = −৪; d·x₂² = ২·১ = ২. যোগফল ১০, আগের সঙ্গে মেলে। মাঝের পদটিই একমাত্র যা ঋণাত্মক হতে পারে।
  5. বর্গ পূরণ। ৩x₁² + ২x₁x₂ + ২x₂²-কে লেখা যায় ৩(x₁ + x₂/৩)² + (৫/৩)x₂². x = (২, −১)-এ ৩·(৫/৩)² + ৫/৩ = ২৫/৩ + ৫/৩ = ১০. দুটি সহগ ৩ আর ৫/৩ দুটিই ধনাত্মক, তাই x ≠ ০ হলে ফল সবসময় ধনাত্মক। এই দুটি সংখ্যাই পরে Cholesky-র “pivot” হিসেবে ফিরে আসবে (√৩ = ১.৭৩২, √(৫/৩) = ১.২৯১)।
  6. Eigen-অক্ষে। অক্ষ ঘুরিয়ে A-এর eigenvector বরাবর আনলে (y = Vᵀx) মাঝের পদ উধাও হয়: xᵀAx = λ₁y₁² + λ₂y₂². এখানে λ = ১.৩৮২ আর ৩.৬১৮, y = (১.৯০২, −১.১৭৬), আর দুটি পদ কাকতালীয়ভাবে ৫ আর ৫. যোগফল আবার ১০.

শেষ ধাপের ঘটনাটিই এই পর্বের মূল যন্ত্র। পর্ব ০৮-এর spectral theorem বলে, প্রতিসম A-কে লেখা যায় A = VΛVᵀ, যেখানে V-এর কলামগুলো পরস্পর লম্ব একক eigenvector, আর Λ কর্ণে eigenvalue-গুলো। তাহলে y = Vᵀx বসালে (V শুধু ঘোরায়, দৈর্ঘ্য বদলায় না):

xᵀAx = xᵀVΛVᵀx = yᵀΛy = λ1y1² + λ2y2² + … + λnyn²

প্রতিটি yi² ≥ ০, তাই xᵀAx-এর চিহ্ন পুরোপুরি λ-গুলোর চিহ্নের ওপর নির্ভর করে। আর একক দৈর্ঘ্যের x-এ xᵀAx-এর সর্বনিম্ন মান ঠিক ক্ষুদ্রতম eigenvalue, সর্বোচ্চ মান বৃহত্তম (এই অনুপাত xᵀAx / xᵀx-কে বলে Rayleigh quotient).

২ · তিন আকার — বাটি, জিন আর উপত্যকা

উপরের সূত্র থেকে সরাসরি পাঁচটি সংজ্ঞা আসে। প্রতিসম A-এর জন্য, শূন্য নয় এমন সব x-এ:

নামশর্ত (সব x ≠ 0)Eigenvalueআকার
Positive definite (PD)xᵀAx > 0সব > ০বাটি, একটিই তলা
Positive semidefinite (PSD)xᵀAx ≥ 0সব ≥ ০বাটি বা উপত্যকা (সমতল তলা)
Negative definitexᵀAx < 0সব < ০উল্টো বাটি, একটি চূড়া
Negative semidefinitexᵀAx ≤ 0সব ≤ ০উল্টো উপত্যকা
Indefiniteকিছু x-এ > 0, কিছুতে < 0ধনাত্মক আর ঋণাত্মক দুটিইঘোড়ার জিন

PD হলে PSD-ও, কিন্তু উল্টোটা নয়। চিহ্নগুলো লেখা হয় A ≻ 0 (PD) আর A ⪰ 0 (PSD). নিচের ছবিতে তিনটি ২ × ২ matrix-এর contour, অর্থাৎ সমান উচ্চতার রেখা, যেমন মানচিত্রে পাহাড়ের উচ্চতা-রেখা।

একই সূত্র xᵀAx, তিনটি আলাদা মাঠ

Level sets of xᵀAx on −2.5 ≤ x1, x2 ≤ 2.5: red = positive height, blue = negative, dashed = zero

Contours of a positive definite, an indefinite and a positive semidefinite quadratic form বাটি জিন উপত্যকা PD indefinite PSD [[3,1],[1,2]] [[1,2],[2,1]] [[1,1],[1,1]] λ = 1.38, 3.62 λ = 3, −1 λ = 2, 0 তলা: শুধু (0, 0) তলা নেই তলা: পুরো রেখা
ছবি ২.১ — বাঁয়ে বাটি: সমান উচ্চতার রেখা উপবৃত্ত, লম্বা অক্ষ ছোট eigenvalue-এর দিকে (সেদিকে ঢাল সবচেয়ে কম)। মাঝে জিন: (১, ১) দিকে ওপরে ওঠে (λ = ৩), (১, −১) দিকে নিচে নামে (λ = −১), আর ড্যাশ রেখায় উচ্চতা শূন্য। ডানে উপত্যকা: (x₁ + x₂)²-এর মান x₁ + x₂ = ০ রেখার সব বিন্দুতে শূন্য, তাই তলা একটি পুরো রেখা।

উপবৃত্তের জ্যামিতি সরাসরি eigenvalue থেকে আসে। xᵀAx = c রেখায়, eigen-অক্ষে λ1y1² + λ2y2² = c, তাই অর্ধ-অক্ষের দৈর্ঘ্য √(c/λ1) আর √(c/λ2). ছোট λ মানে লম্বা অক্ষ। দুটি λ খুব আলাদা হলে উপবৃত্ত সরু আর লম্বা, যা gradient descent-এর জন্য কঠিন উপত্যকা; এর মাপ হলো condition number λmax/λmin, এখানে ৩.৬১৮/১.৩৮২ = ২.৬২. পর্ব ১৩ (Gradient descent-এর পরিবার) এই সংখ্যাটি দিয়েই অভিসরণের গতি ব্যাখ্যা করবে।

নিচের ব্লক তিনটি matrix-এর contour আঁকে, eigenvalue ছাপে, আর প্রতিটি প্যানেলে ক্ষুদ্রতম eigenvalue-এর দিকে একটি কালো তীর দেয়।

import numpy as np
import matplotlib.pyplot as plt

mats = {"bowl: positive definite": np.array([[3.0, 1.0], [1.0, 2.0]]),
        "saddle: indefinite":      np.array([[1.0, 2.0], [2.0, 1.0]]),
        "valley: semidefinite":    np.array([[1.0, 1.0], [1.0, 1.0]])}

g = np.linspace(-2, 2, 201)
X1, X2 = np.meshgrid(g, g)
P = np.stack([X1, X2], axis=-1)              # প্রতিটি গ্রিড-বিন্দু x = (x1, x2)
levels = [-4, -2, -1, -0.5, 0.5, 1, 2, 4, 8]

fig, axes = plt.subplots(1, 3, figsize=(9, 3.3), layout="constrained")
for ax, (name, A) in zip(axes, mats.items()):
    Q = np.einsum("...i,ij,...j->...", P, A, P)   # প্রতিটি বিন্দুতে xᵀAx
    lam, V = np.linalg.eigh(A)                    # ছোট থেকে বড় eigenvalue
    print(f"{name:24s} λ = {np.round(lam, 3)}  min xᵀAx = {Q.min():6.2f}")
    print(f"{'':24s} ছোট λ-এর দিক v = {np.round(V[:, 0], 3)}")
    ax.contour(X1, X2, Q, levels=levels, cmap="RdBu_r")
    ax.quiver(0, 0, *V[:, 0], color="k", angles="xy", scale_units="xy", scale=1)
    ax.set_title(name, fontsize=10)
    ax.set_xlabel("x1"); ax.set_aspect("equal")
axes[0].set_ylabel("x2")
plt.show()

আসল আউটপুট (ব্রাউজারের Python):

bowl: positive definite  λ = [1.382 3.618]  min xᵀAx =   0.00
                         ছোট λ-এর দিক v = [ 0.526 -0.851]
saddle: indefinite       λ = [-1.  3.]  min xᵀAx =  -8.00
                         ছোট λ-এর দিক v = [-0.707  0.707]
valley: semidefinite     λ = [0. 2.]  min xᵀAx =  -0.00
                         ছোট λ-এর দিক v = [-0.707  0.707]

np.linalg.eigh প্রতিসম matrix-এর জন্য তৈরি, আর eigenvalue ছোট থেকে বড় ক্রমে দেয়। বাটিতে গ্রিডের সর্বনিম্ন উচ্চতা ০, কেবল মূলবিন্দুতে। জিনে −৮: (২, −২) কোণে উচ্চতা (−১)·(২√২)² = −৮, ঠিক ক্ষুদ্রতম eigenvalue-এর দিকে। উপত্যকায় “−0.00”: আসল মান শূন্য, কিন্তু floating-point rounding-এ একটি ক্ষুদ্র ঋণাত্মক সংখ্যা এসেছে। semidefinite matrix-এ এটি স্বাভাবিক, আর অংশ ৫-এ এটিই বড় সমস্যা হয়ে ফিরবে। তীরগুলো দেখুন: বাটিতে তীর লম্বা অক্ষ বরাবর, জিনে নিচে নামার দিকে, উপত্যকায় সমতল তলা বরাবর। Eigenvector-এর চিহ্ন (±) LAPACK-এর পছন্দ; v আর −v একই দিক।

৩ · PD-র তিন পরীক্ষা — eigenvalue, leading minor আর Cholesky

সংজ্ঞা “সব x-এ xᵀAx > ০” সরাসরি যাচাই করা যায় না, কারণ x অসীম। তাই তিনটি সমতুল্য পরীক্ষা ব্যবহার হয়, প্রতিসম A-এর জন্য:

১ · Eigenvalue

সব λi > ০. অংশ ১-এর সূত্র থেকে সরাসরি। কম্পিউটারে np.linalg.eigvalsh; খরচ বেশি, কিন্তু কতটা “কাছাকাছি” তাও বলে (ক্ষুদ্রতম λ)।

২ · Sylvester-এর নিয়ম

উপরের-বাঁ কোণের ১ × ১, ২ × ২, …, n × n অংশের determinant (leading principal minor) সবগুলো > ০. ২ × ২ ও ৩ × ৩-এ হাতে করার সবচেয়ে সহজ পথ।

৩ · Cholesky

A = LLᵀ, L নিচের-ত্রিভুজাকার আর কর্ণ ধনাত্মক: এমন L পাওয়া গেলে PD. কম্পিউটারে সবচেয়ে সস্তা আর প্রচলিত পরীক্ষা; ব্যর্থ হলে SciPy (আর ডেস্কটপের NumPy) LinAlgError দেয়।

২ × ২-এ Sylvester-এর নিয়ম হয় খুব সরল: [[a, b], [b, d]] PD হবে যদি এবং কেবল যদি a > ০ আর ad − b² > ০. কেন? বর্গ পূরণ করলে a·x₁² + 2b·x₁x₂ + d·x₂² = a(x₁ + (b/a)x₂)² + ((ad − b²)/a)·x₂². দুটি সহগ a আর (ad − b²)/a; দুটিই ধনাত্মক হলে যোগফল ধনাত্মক। অংশ ১-এর stepper-এ এই দুটিই ছিল ৩ আর ৫/৩. এই সহগগুলোকে বলে pivot; k-তম pivot = (k-তম minor)/(আগের minor), তাই সব minor ধনাত্মক ⇔ সব pivot ধনাত্মক ⇔ Cholesky সফল (কারণ Cholesky-র কর্ণ ঠিক pivot-গুলোর বর্গমূল)। তিনটি পরীক্ষা একই সত্যের তিন রূপ।

B = [[1, 2], [2, 1]]indefinite

            
  1. প্রথম বিন্দু ধোঁকা দেয়। x = (১, ১)-এ xᵀBx = ৬, ধনাত্মক; কর্ণের দুটি ঘরও ধনাত্মক। কয়েকটি বিন্দুতে ধনাত্মক দেখা PD-র প্রমাণ নয়।
  2. একটি পাল্টা উদাহরণই যথেষ্ট। x = (১, −১)-এ মাঝের পদ ২·২·(১)(−১) = −৪, ফল −২. সংজ্ঞা ভাঙল, B PD নয়।
  3. Eigenvalue পরীক্ষা। Characteristic polynomial (১ − λ)² − ৪ = ০ থেকে λ = ৩ আর −১. একটি ঋণাত্মক, তাই ফেল; আর −১-এর eigenvector (১, −১) ঠিক সেই দিক যেখানে আমরা ঋণাত্মক মান পেয়েছি।
  4. Sylvester পরীক্ষা। প্রথম minor ১ > ০, কিন্তু পুরো determinant ১ − ৪ = −৩ < ০. দুই eigenvalue-এর গুণফলই determinant: ৩ × (−১) = −৩, তাই ঋণাত্মক determinant মানে বিপরীত চিহ্নের eigenvalue.
  5. Cholesky পরীক্ষা। l₁₁ = ১, l₂₁ = ২, তারপর l₂₂² = ১ − ৪ = −৩. ঋণাত্মক সংখ্যার বাস্তব বর্গমূল নেই, তাই অ্যালগরিদম থেমে যায়। SciPy ঠিক এই জায়গায় LinAlgError দেয়, আর বার্তায় info = [2] মানে দ্বিতীয় pivot.
  6. Optimization-এর ভাষায়। f(x) = ½xᵀBx-এর gradient (০, ০)-তে শূন্য, কিন্তু সেটি minimum নয়: (১, −১) বরাবর f = −t², যা যত খুশি নিচে নামে। এমন বিন্দুকে বলে saddle point.

এবার তিন পরীক্ষা একসঙ্গে, সাতটি matrix-এ। শেষ দুটি ইচ্ছাকৃত ফাঁদ: F-এর leading minor দুটিই ০ (≥ ০), তবু সে PSD নয়; আর G প্রতিসম নয়।

import numpy as np
from scipy import linalg

def eig_test(A):                      # সব eigenvalue > 0?
    return f"{np.linalg.eigvalsh(A).min():+.3f}"

def minors_test(A):                   # Sylvester: উপরের-বাঁ কোণের k×k det
    return " ".join(f"{np.linalg.det(A[:k, :k]):+.0f}" for k in range(1, len(A) + 1))

def chol_test(A):                     # Cholesky সফল হলো, নাকি LinAlgError?
    try:
        linalg.cholesky(A, lower=True)
        return "ok"
    except linalg.LinAlgError as err:
        return f"LinAlgError: {err}"

cases = {
    "A bowl":   [[3, 1], [1, 2]],
    "B saddle": [[1, 2], [2, 1]],
    "C valley": [[1, 1], [1, 1]],
    "D 3x3":    [[4, 2, 0], [2, 3, 1], [0, 1, 2]],
    "E 3x3":    [[2, 3, 0], [3, 2, 1], [0, 1, 2]],
    "F trap":   [[0, 0], [0, -1]],
    "G nonsym": [[1, 4], [0, 1]],
}
print(f"{'matrix':9} {'min λ':>7} {'leading minors':>15}  Cholesky")
for name, rows in cases.items():
    A = np.array(rows, dtype=float)
    print(f"{name:9} {eig_test(A):>7} {minors_test(A):>15}  {chol_test(A)}")

G = np.array(cases["G nonsym"], dtype=float)
x = np.array([1.0, -1.0])
S = (G + G.T) / 2                     # quadratic form দেখে শুধু এই প্রতিসম অংশ
print("G: xᵀGx =", x @ G @ x, "| xᵀSx =", x @ S @ x)
print("S =", S.tolist(), "| eig(S) =", np.linalg.eigvalsh(S))

আসল আউটপুট (ব্রাউজারের Python):

matrix      min λ  leading minors  Cholesky
A bowl     +1.382           +3 +5  ok
B saddle   -1.000           +1 -3  LinAlgError: Internal potrf return info = [2] for slices [0].
C valley   +0.000           +1 +0  LinAlgError: Internal potrf return info = [2] for slices [0].
D 3x3      +0.855       +4 +8 +12  ok
E 3x3      -1.162       +2 -5 -12  LinAlgError: Internal potrf return info = [2] for slices [0].
F trap     -1.000           +0 +0  LinAlgError: Internal potrf return info = [1] for slices [0].
G nonsym   +1.000           +1 +1  ok
G: xᵀGx = -2.0 | xᵀSx = -2.0
S = [[1.0, 2.0], [2.0, 1.0]] | eig(S) = [-1.  3.]

A থেকে E: তিন পরীক্ষা প্রতিটি সারিতে একমত। SciPy-র বার্তায় “info = [2]” মানে LAPACK-এর potrf routine দ্বিতীয় pivot-এ আটকেছে, অর্থাৎ ২ × ২ leading minor-এ সমস্যা: Sylvester-এর কলামের প্রথম অ-ধনাত্মক সংখ্যার সঙ্গে হুবহু মেলে। C (উপত্যকা) PSD কিন্তু PD নয়: ক্ষুদ্রতম λ ০, দ্বিতীয় minor ০, আর Cholesky শূন্য pivot-এ থামে। F: leading minor দুটিই ০, তাই “সব ≥ ০” দেখে কেউ PSD বলে ফেলতে পারেন; কিন্তু λ = −১. PSD-র জন্য Sylvester-এর নিয়ম শুধু leading নয়, সব principal minor (যেকোনো সারি-কলামের একই সেট বেছে নেওয়া অংশ) চায়; F-এর নিচের-ডান ১ × ১ অংশ −১. G: তিন পরীক্ষাই “পাস”, অথচ xᵀGx = −২! কারণ eigvalsh আর cholesky(..., lower=True) দুটিই শুধু নিচের ত্রিভুজ পড়ে (docs-এ লেখা আছে), আর ধরে নেয় বাকিটা প্রতিসম; G-এর নিচের ত্রিভুজ [[1, ·], [0, 1]], যা identity-র মতো। আসল উত্তর দেয় প্রতিসম অংশ S = [[1, 2], [2, 1]], যা আমাদের জিন B. শিক্ষা: পরীক্ষার আগে np.allclose(A, A.T) যাচাই করুন, অথবা (A + A.T)/2 নিন।

কেন SciPy, NumPy নয়? ডেস্কটপে np.linalg.cholesky-ও ব্যর্থ হলে LinAlgError দেয়। কিন্তু এই পর্ব লেখার সময় ব্রাউজারের Python-এ (Pyodide) পরীক্ষা করে দেখা গেছে, সেটি error না দিয়ে NaN-ভরা L ফেরত দেয়। কারণ NumPy-র linalg ভুল ধরে floating-point-এর “invalid” flag দেখে, আর WebAssembly-তে সেই flag নেই। SciPy সরাসরি LAPACK-এর info সংখ্যা দেখে, তাই দুই জায়গাতেই ঠিকমতো LinAlgError দেয়। নিজের কোডে NumPy ব্যবহার করলে ফলাফলে np.isnan(L).any() যাচাই করাও নিরাপদ অভ্যাস।

Determinant একা যথেষ্ট নয়: [[−1, 0], [0, −1]]-এর determinant +১, কিন্তু matrix-টি negative definite. শুধু কর্ণ ধনাত্মক হওয়াও যথেষ্ট নয় (B-এর কর্ণ ১, ১)। PD-র প্রয়োজনীয় শর্ত হিসেবে কর্ণ ধনাত্মক আর |aij| < √(aiiajj) কাজে লাগে দ্রুত বাতিল করতে, প্রমাণ করতে নয়।

৪ · Cholesky decomposition — হাতে একটি ২ × ২, তারপর কেন এত জনপ্রিয়

PD matrix A-কে লেখা যায় A = LLᵀ, যেখানে L একটি lower triangular matrix (কর্ণের ওপরে সব শূন্য) আর কর্ণের সব ঘর ধনাত্মক। এই L একটিই (unique). এটি যেন matrix-এর “বর্গমূল”: সংখ্যায় ৯ = ৩ · ৩, matrix-এ A = L · Lᵀ. পদ্ধতিটির নাম ফরাসি সামরিক প্রকৌশলী André-Louis Cholesky-র নামে, যিনি জরিপের হিসাবের জন্য এটি বানান; ভাবনার প্রশ্ন ১-এ তাঁর গল্প আছে।

A = LLᵀb = (6, 5)

            
  1. অজানা L. L-এর তিনটি অজানা ঘর: l₁₁, l₂₁, l₂₂. LLᵀ গুণ করে A-এর সঙ্গে ঘর ধরে মেলাব। প্রতিসমতার কারণে (১,২) আর (২,১) একই সমীকরণ।
  2. প্রথম কলাম, কর্ণ। l₁₁² = ৪, তাই l₁₁ = ২ (ধনাত্মক বর্গমূল নেওয়ার নিয়ম, তাই L একটিই)।
  3. প্রথম কলাম, নিচে। l₁₁·l₂₁ = ২ থেকে l₂₁ = ১. আগের ধাপের l₁₁ দিয়ে ভাগ।
  4. দ্বিতীয় কর্ণ। l₂₁² + l₂₂² = ৩ থেকে l₂₂² = ২, l₂₂ = √২ ≈ ১.৪১৪২. এখানেই PD-র পরীক্ষা: বর্গমূলের ভেতরে (৩ − ১) ধনাত্মক হতেই হবে। জিনে সেটি −৩ হয়েছিল।
  5. যাচাই। LLᵀ গুণ করে A ফিরে আসে। বাড়তি লাভ: det A = (L-এর কর্ণের গুণফল)² = (২ × ১.৪১৪২)² = ৮, আর সরাসরি ৪·৩ − ২·২ = ৮. বড় matrix-এ log det A = ২ ∑ log lii, যা Gaussian-এর likelihood-এ লাগে।
  6. সমাধান। Ax = b মানে L(Lᵀx) = b. প্রথমে Ly = b সামনে থেকে (forward substitution): y = (৩, ১.৪১৪২). তারপর Lᵀx = y পেছন থেকে: x = (১, ১)। যাচাই: ৪·১ + ২·১ = ৬, ২·১ + ৩·১ = ৫.

সাধারণ n × n-এ একই নিয়ম কলাম ধরে চলে: ljj = √(ajj − ∑k<j ljk²), আর j-এর নিচের সারিতে lij = (aij − ∑k<j likljk) / ljj. খরচ প্রায় n³/3টি গুণ-যোগ, যেখানে সাধারণ LU decomposition-এর প্রায় 2n³/3; প্রতিসমতার কারণে অর্ধেক কাজ বাঁচে। আর PD matrix-এ সারি অদলবদল (pivoting) ছাড়াই পদ্ধতিটি সাংখ্যিকভাবে স্থিতিশীল। তত্ত্ব বলে প্রায় দ্বিগুণ দ্রুত; বাস্তবে কতটা? একটি ৩,০০০ × ৩,০০০ PD system-এ চারটি পথ তুলনা করা হলো (ডেস্কটপে সত্যিকারের run; Python 3.14.4, NumPy 2.5.4, SciPy 1.18.1; প্রতিটির ৫ বারের সেরা সময়, একটি local run, সাধারণ ফল নয়):

~/bazarghar-ml$ python chol_speed.py
numpy 2.5.4 | scipy 1.18.1 | n = 3000
LU   solve(assume_a='gen')        202.4 ms   residual 1.4e-13
Cholesky cho_factor+cho_solve     171.6 ms   residual 9.4e-14
solve(assume_a='pos')             171.2 ms   residual 9.4e-14
inv(A) @ b                        390.5 ms   residual 1.3e-13

Matrix-টি বানানো হয়েছিল XᵀX/m + ০.১·I হিসেবে, ঠিক ridge regression-এর মতো (অংশ ৮)। Cholesky এখানে LU-এর চেয়ে প্রায় ১৫% দ্রুত, দ্বিগুণ নয়: আধুনিক BLAS একাধিক core আর memory-র গতিতে আটকে যায়, তাই গণনার সংখ্যার অনুপাত সময়ে হুবহু আসে না। Inverse বানিয়ে গুণ করা সবচেয়ে ধীর, প্রায় দ্বিগুণ সময়; AI-এর ভিত্তি কোর্সের পর্ব ১৭-এর “inverse নয়, solve” নিয়ম এখানেও খাটে। SciPy-তে solve(A, b, assume_a="pos") ভেতরে Cholesky-ই চালায়, তাই সময় প্রায় এক। আপনার যন্ত্রে সংখ্যা আলাদা হবে।

৫ · Covariance matrix সবসময় PSD — প্রমাণ, rank কমে যাওয়া আর jitter

d-টি feature-এর covariance matrix Σ একটি d × d প্রতিসম matrix: কর্ণে প্রতিটি feature-এর variance, বাইরে প্রতিটি জোড়ার covariance. এর সবচেয়ে গুরুত্বপূর্ণ গুণ এক লাইনে প্রমাণ হয়। যেকোনো ধ্রুবক vector v নিন, আর নতুন একটি সংখ্যা বানান s = vᵀx, অর্থাৎ feature-গুলোর একটি ওজন-দেওয়া যোগফল। তাহলে

Var(vᵀx) = E[(vᵀ(x − μ))²] = vᵀ E[(x − μ)(x − μ)ᵀ] v = vᵀΣv ≥ 0

কারণ variance একটি বর্গের গড়, কখনো ঋণাত্মক নয়। এখানে μ হলো গড় vector, E প্রত্যাশিত মান। হাতের ডেটায় একই যুক্তি: কেন্দ্রীকৃত design matrix Xc (প্রতিটি কলাম থেকে তার গড় বাদ) নিয়ে sample covariance S = XcᵀXc/(n − 1), আর vᵀSv = ‖Xcv‖²/(n − 1) ≥ ০. দৈর্ঘ্যের বর্গ ঋণাত্মক হয় না। সমান চিহ্ন কখন? যখন Xcv = ০, অর্থাৎ feature-গুলোর কোনো একটি মিশ্রণ সব সারিতে ধ্রুবক। তখন S PSD কিন্তু PD নয়, আর তার rank d-এর চেয়ে কম। এটি ঘটে দুই ক্ষেত্রে: (১) একটি কলাম অন্যগুলোর রৈখিক ফল (পর্ব ০৬-এর linear dependence), (২) n − 1 < d, অর্থাৎ feature-এর চেয়ে সারি কম, কারণ S-এর rank সর্বোচ্চ n − 1.

নিচের ব্লক কাল্পনিক বাজারঘরের ২০০টি অর্ডারে (দূরত্ব, ডেলিভারির সময়, পণ্যের সংখ্যা) প্রমাণটি সংখ্যায় দেখায়, তারপর দুটি নির্ভরশীল কলাম যোগ করে: ডেলিভারি চার্জ, যা দূরত্বের হুবহু রৈখিক ফল (২০ + ৫ × km), আর একই ডেলিভারির সময় ঘণ্টায়, যা ডেটা জোড়া লাগানোর সময় প্রায়ই ঘটে।

import numpy as np
from scipy import linalg
np.set_printoptions(precision=3, linewidth=70)

def chol(S):                          # Cholesky: সফল হলে L-এর ক্ষুদ্রতম কর্ণ
    try:
        return f"ok, min L diag {linalg.cholesky(S, lower=True).diagonal().min():.1e}"
    except linalg.LinAlgError as err:
        return f"LinAlgError: {err}"

rng = np.random.default_rng(42)       # কাল্পনিক বাজারঘর: ২০০টি অর্ডার
n = 200
dist = rng.uniform(1, 15, n)                          # দূরত্ব, km
time = 15 + 2.5 * dist + rng.normal(0, 6, n)          # ডেলিভারির সময়, মিনিট
items = rng.integers(1, 8, n).astype(float)           # পণ্যের সংখ্যা
X = np.column_stack([dist, time, items])
S = np.cov(X, rowvar=False)           # 3×3 sample covariance
print("eig(S):", np.linalg.eigvalsh(S))
v = rng.normal(size=3)                # যেকোনো একটি দিক v
print(f"vᵀSv = {v @ S @ v:.4f} | var(Xv) = {np.var(X @ v, ddof=1):.4f}")

extras = {"charge = 20 + 5*dist": 20 + 5 * dist,      # দূরত্বের হুবহু রৈখিক ফল
          "time in hours":        time / 60}          # একই তথ্য, অন্য এককে
for name, col in extras.items():
    S2 = np.cov(np.column_stack([X, col]), rowvar=False)
    lam = np.linalg.eigvalsh(S2)
    print(f"+ {name}: rank {np.linalg.matrix_rank(S2)}, "
          f"min λ {lam[0]:.1e}, max λ {lam[-1]:.1e}")
    print(f"  Cholesky: {chol(S2)}")

S2 = np.cov(np.column_stack([X, time / 60]), rowvar=False)
for eps in (1e-10, 1e-8, 1e-6):       # jitter: S2 + εI
    print(f"eps={eps:g}: {chol(S2 + eps * np.eye(4))}")

আসল আউটপুট (ব্রাউজারের Python):

eig(S): [  3.31    3.951 169.278]
vᵀSv = 6.7850 | var(Xv) = 6.7850
+ charge = 20 + 5*dist: rank 3, min λ -2.1e-15, max λ 5.4e+02
  Cholesky: ok, min L diag 3.4e-07
+ time in hours: rank 3, min λ -3.9e-17, max λ 1.7e+02
  Cholesky: LinAlgError: Internal potrf return info = [4] for slices [0].
eps=1e-10: ok, min L diag 1.0e-05
eps=1e-08: ok, min L diag 1.0e-04
eps=1e-06: ok, min L diag 1.0e-03

প্রথম দুই লাইন: তিনটি eigenvalue-ই ধনাত্মক, আর একটি এলোমেলো দিক v-তে vᵀSv আর নতুন সংখ্যা Xv-এর variance হুবহু এক, ৬.৭৮৫০: প্রমাণটি সংখ্যায়। বড় eigenvalue ১৬৯-এর দিকটি দূরত্ব আর সময়ের যৌথ ছড়ানো (দুটি একসঙ্গে বাড়ে)। নির্ভরশীল কলাম: দুই ক্ষেত্রেই rank ৪ নয়, ৩. গণিতে ক্ষুদ্রতম eigenvalue ঠিক ০; কম্পিউটারে চার্জের ক্ষেত্রে −২.১ × ১০−১৫, ঘণ্টার ক্ষেত্রে −৩.৯ × ১০−১৭. এগুলো rounding-এর ধুলো, আর চিহ্ন ও মান যন্ত্রভেদে বদলায় (ডেস্কটপের একটি run-এ চার্জের ক্ষেত্রে এসেছিল +৬.৭ × ১০−১৫)। Cholesky-র ফলও তাই ভাগ্যনির্ভর: চার্জের ক্ষেত্রে “সফল”, অথচ একটি কর্ণ ৩.৪ × ১০−৭, যা দিয়ে ভাগ করলে উত্তর বিস্ফোরিত হয়; ঘণ্টার ক্ষেত্রে চতুর্থ pivot-এ (info = [4]) LinAlgError. দুটিই একই রোগ, আর “ok” মানে নিরাপদ নয়। Jitter: S2 + εI-এর সব eigenvalue ε পরিমাণ বাড়ে (একই eigenvector, λi + ε), তাই ক্ষুদ্রতম λ ≈ ε আর ক্ষুদ্রতম কর্ণ ≈ √ε: ১০−১০ → ১০−৫, ১০−৮ → ১০−৪, ১০−৬ → ১০−৩.

Jitter কী সারায়, কী লুকায়। কর্ণে ছোট ε যোগ করা Gaussian process, kernel পদ্ধতি আর বড় covariance-এর হিসাবে একটি প্রচলিত কৌশল। এটি rounding-এর ক্ষুদ্র ঋণাত্মক eigenvalue সারায় আর Cholesky চালু রাখে। কিন্তু উপরের ক্ষেত্রে আসল সমস্যা ডেটার: একই তথ্য দুবার আছে। সঠিক সমাধান একটি কলাম ফেলে দেওয়া; jitter শুধু উপসর্গ ঢাকে। ε বাছাইয়েও সাবধান: এটি matrix-এর মাপের সঙ্গে তুলনীয় হতে হয় (যেমন ε = ১০−৮ × গড় কর্ণ), কারণ কর্ণে ১০০-এর মতো সংখ্যা থাকলে ১০−১০ rounding-এর নিচে হারিয়ে যেতে পারে, আর বড় ε model-কে সত্যিই বদলে দেয় (ridge-এর λ-এর মতো)। আরেকটি সাধারণ ফাঁদ: হাতে বসানো বা আংশিক-অনুপস্থিত ডেটা থেকে জোড়ায় জোড়ায় হিসাব করা correlation matrix PSD না-ও হতে পারে; ভাবনার প্রশ্ন ৩ দেখুন।

একই যুক্তি আরেকটি বড় শ্রেণিতে খাটে। যেকোনো X-এর জন্য XᵀX (d × d) আর XXᵀ (n × n) দুটিই PSD, কারণ vᵀXᵀXv = ‖Xv‖². দ্বিতীয়টি হলো সারিগুলোর জোড়ায় জোড়ায় dot product-এর টেবিল, যাকে বলে Gram matrix. পর্ব ২৯ (Kernel trick)-এ dot product-এর জায়গায় একটি kernel function k(xi, xj) বসবে, আর “বৈধ kernel” মানেই এমন function যার Gram matrix সব ডেটায় PSD.

৬ · Cholesky দিয়ে correlated Gaussian — z থেকে x = μ + Lz

ধরুন বাজারঘর নতুন রাইডার-বণ্টনের নিয়ম পরীক্ষা করতে চায়, কিন্তু আসল ডেটা কম। দরকার কাল্পনিক অর্ডার, যেখানে দূরত্ব বেশি হলে সময়ও সাধারণত বেশি। দুটি আলাদা ছক্কা ছুড়ে দূরত্ব আর সময় বানালে এই সম্পর্ক আসবে না। Cholesky-র কৌশল: আগে দুটি স্বাধীন “ছক্কা” z ছুড়ুন, তারপর L দিয়ে মিশিয়ে দিন, ঠিক যতটা মেশানো দরকার।

z ~ N(0, I) মানে z-এর উপাদানগুলো স্বাধীন standard normal, গড় ০, variance ১, তাই Cov(z) = I (identity matrix). এখন x = μ + Lz নিন, যেখানে Σ = LLᵀ. তাহলে

E[x] = μ, Cov(x) = E[(Lz)(Lz)ᵀ] = L E[zzᵀ] Lᵀ = L I Lᵀ = LLᵀ = Σ

আর Gaussian-এর রৈখিক রূপান্তর Gaussian-ই থাকে, তাই x ~ N(μ, Σ), একটি multivariate Gaussian. লক্ষ করুন, Σ = LLᵀ-এর যেকোনো বর্গমূল কাজ করত (যেমন eigen থেকে VΛ½), কিন্তু Cholesky সবচেয়ে সস্তা, আর নিচের-ত্রিভুজ হওয়ায় একটি সুন্দর অর্থও আছে: x1 = μ1 + l11z1 শুধু প্রথম ছক্কা থেকে, x2 = μ2 + l21z1 + l22z2 প্রথমটির কিছু অংশ ধার নেয়। Σ PD না হলে Cholesky হয় না, আর PSD-ও না হলে এমন কোনো Gaussian-ই নেই: ঋণাত্মক variance-এর দিক বাস্তবে অসম্ভব।

বাজারঘরের কাল্পনিক ডেলিভারি: সময়ের গড় ৩৫ মিনিট, standard deviation ১০; দূরত্বের গড় ৬ km, standard deviation ৩; correlation ρ = ০.৭. তাহলে Σ = [[১০০, ২১], [২১, ৯]] (কারণ ০.৭ × ১০ × ৩ = ২১)। হাতে Cholesky: l11 = ১০, l21 = ২১/১০ = ২.১, l22 = √(৯ − ৪.৪১) = √৪.৫৯ ≈ ২.১৪২.

import numpy as np
import matplotlib.pyplot as plt
np.set_printoptions(precision=3, suppress=True)

mu = np.array([35.0, 6.0])            # গড়: ৩৫ মিনিট, ৬ km
sd = np.array([10.0, 3.0]); rho = 0.7
Sigma = np.array([[sd[0]**2,            rho * sd[0] * sd[1]],
                  [rho * sd[0] * sd[1], sd[1]**2]])
L = np.linalg.cholesky(Sigma)         # Sigma = L Lᵀ, L নিচের-ত্রিভুজ
print("Sigma =\n", Sigma, "\nL =\n", L)

rng = np.random.default_rng(42)
Z = rng.standard_normal((5000, 2))    # z ~ N(0, I): পরস্পর-স্বাধীন
Xs = mu + Z @ L.T                     # প্রতিটি সারিতে x = μ + L z
print("sample mean:", Xs.mean(axis=0))
print("sample cov:\n", np.cov(Xs, rowvar=False))
print("sample corr:", round(np.corrcoef(Xs, rowvar=False)[0, 1], 3))

orders = np.array([[55.0, 12.0], [55.0, 3.0]])   # দুটি নতুন অর্ডার: (মিনিট, km)
for x in orders:
    y = np.linalg.solve(L, x - mu)    # L y = x − μ, তারপর d² = ‖y‖²
    z = (x - mu) / sd                 # শুধু আলাদা আলাদা standardize
    print(f"order {x}: Mahalanobis {np.sqrt(y @ y):.2f} | "
          f"per-feature z {np.sqrt(z @ z):.2f}")

fig, ax = plt.subplots(1, 2, figsize=(8, 3.4), layout="constrained")
ax[0].scatter(Z[:800, 0], Z[:800, 1], s=4, alpha=0.4)
ax[0].set_title("z ~ N(0, I)"); ax[0].set_aspect("equal")
ax[1].scatter(Xs[:800, 1], Xs[:800, 0], s=4, alpha=0.4)
ax[1].scatter(orders[:, 1], orders[:, 0], c="red", marker="x", s=60)
ax[1].set_title("x = mu + L z"); ax[1].set_xlabel("distance (km)")
ax[1].set_ylabel("delivery time (min)")
plt.show()

আসল আউটপুট (ব্রাউজারের Python):

Sigma =
 [[100.  21.]
 [ 21.   9.]]
L =
 [[10.     0.   ]
 [ 2.1    2.142]]
sample mean: [34.903  5.956]
sample cov:
 [[97.87  20.927]
 [20.927  9.278]]
sample corr: 0.694
order [55. 12.]: Mahalanobis 2.17 | per-feature z 2.83
order [55.  3.]: Mahalanobis 3.91 | per-feature z 2.24

L হাতের হিসাবের সঙ্গে মেলে: ১০, ২.১, ২.১৪২. ৫,০০০টি নমুনার গড় (৩৪.৯০, ৫.৯৬), covariance [[৯৭.৯, ২০.৯], [২০.৯, ৯.৩]], correlation ০.৬৯৪: লক্ষ্য (৩৫, ৬), [[১০০, ২১], [২১, ৯]] আর ০.৭-এর কাছে, পার্থক্যটুকু নমুনার এলোমেলোতা (n বাড়ালে কমবে, প্রায় 1/√n হারে)। বাঁয়ের ছবিতে z-এর গোল মেঘ, ডানে L তাকে হেলানো উপবৃত্তে টেনেছে। NumPy-র rng.multivariate_normal(mu, Sigma, method="cholesky") ভেতরে একই কাজ করে; তার ডিফল্ট method "svd", যা PSD (singular) Σ-ও সামলায়, তবে ধীর। শেষ দুই লাইন পরের অংশের বিষয়।

৭ · Mahalanobis দূরত্ব — covariance মেনে “কতটা অস্বাভাবিক”

দুটি নতুন অর্ডার, দুটিতেই ৫৫ মিনিট লেগেছে: একটি ১২ km দূরে, অন্যটি মাত্র ৩ km. কোনটি বেশি সন্দেহজনক? প্রতিটি feature আলাদা করে standardize করলে (z-score, AI-এর ভিত্তি কোর্সের পর্ব ৩৭) প্রথমটি দূরে দেখায় (২.৮৩ বনাম ২.২৪), কারণ দুটি feature-ই গড় থেকে দূরে। কিন্তু সাধারণ বুদ্ধি বলে উল্টো: দূরের অর্ডারে বেশি সময় স্বাভাবিক, কাছের অর্ডারে ৫৫ মিনিট অস্বাভাবিক। Mahalanobis distance এই সম্পর্ক মানে:

dM(x)² = (x − μ)ᵀ Σ−1 (x − μ)

এটি আবার একটি quadratic form, এবার Σ−1 দিয়ে। Σ PD হলে Σ−1-ও PD (eigenvalue 1/λi, সব ধনাত্মক), তাই dM ≥ ০ আর শুধু x = μ-তে শূন্য, যা দূরত্বের জন্য জরুরি। Cholesky দিয়ে হিসাব সহজ: Σ−1 = L−ᵀL−1, তাই dM² = ‖y‖², যেখানে Ly = x − μ. inverse বানাতেই হয় না; ব্লকে ঠিক তাই করা হয়েছে। হাতে প্রথম অর্ডার: x − μ = (২০, ৬); y1 = ২০/১০ = ২, y2 = (৬ − ২.১ × ২)/২.১৪২ = ০.৮৪০; d = √(৪ + ০.৭০৬) = ২.১৭. দ্বিতীয়টি: x − μ = (২০, −৩); y2 = (−৩ − ৪.২)/২.১৪২ = −৩.৩৬১; d = √(৪ + ১১.২৯) = ৩.৯১. y হলো “সাদা করা” (whitened) স্থানাঙ্ক: সেখানে মেঘটি আবার গোল, তাই সাধারণ দৈর্ঘ্যই ঠিক মাপ। Gaussian ধরলে dM²-এর বণ্টন chi-square, যা দিয়ে outlier-এর সীমা টানা যায়; এ সবই পর্ব ১৯ (Multivariate Gaussian — covariance, Mahalanobis দূরত্ব আর শর্তসাপেক্ষ বণ্টন)-এ বিস্তারিত আসবে।

ইতিহাস: দূরত্বটির নাম পরিসংখ্যানবিদ প্রশান্তচন্দ্র মহলানবিশের (১৮৯৩–১৯৭২) নামে। তিনি কলকাতায় Indian Statistical Institute প্রতিষ্ঠা করেন, আর ১৯৩৬ সালে “On the generalised distance in statistics” প্রবন্ধে এই দূরত্বের সাধারণ রূপ প্রকাশ করেন; তার আগে, ১৯২০-এর দশকে, নৃতাত্ত্বিক মাপের ডেটায় জনগোষ্ঠী তুলনার কাজ থেকে এর ধারণা গড়ে ওঠে। তাঁর পরিবারের আদি নিবাস বিক্রমপুর অঞ্চলে বলে উল্লেখ পাওয়া যায়।

৮ · ML-এ কোথায় কোথায় — Hessian, ridge, kernel আর Newton

Hessian আর convexity. একটি loss function f(θ)-এর দ্বিতীয় অবকলনগুলোর matrix হলো Hessian H, যার (i, j) ঘর ∂²f/∂θi∂θj. একটি বিন্দু θ0-এর কাছে second-order Taylor approximation: f(θ0 + Δ) ≈ f(θ0) + ∇fᵀΔ + ½ΔᵀHΔ. শেষ পদটি একটি quadratic form! তাই gradient শূন্য এমন বিন্দুতে (stationary point) H PD হলে সেখানে কঠোর local minimum (বাটির তলা), H indefinite হলে saddle point, আর H শুধু PSD হলে পরীক্ষা অমীমাংসিত (উপত্যকা, আরও উঁচু ক্রমের পদ দেখতে হয়)। আর যদি সব বিন্দুতে H PSD হয়, তাহলে f একটি convex function, যার যেকোনো local minimum-ই global. Gradient আর Hessian কীভাবে বের করতে হয়, তা পর্ব ১১ (Matrix calculus — gradient, Jacobian আর Hessian)-এ; convexity কেন optimization সহজ করে, তা পর্ব ১২ (Convexity — কেন কিছু loss সহজ আর কিছু কঠিন)-এ।

Least squares আর ridge. f(w) = ‖Xw − y‖²-এর Hessian 2XᵀX, যা অংশ ৫-এর যুক্তিতে সবসময় PSD, তাই least squares সবসময় convex. X-এর কলামগুলো স্বাধীন হলে XᵀX PD, আর minimum একটিই (AI-এর ভিত্তি কোর্সের পর্ব ৫৮-এর normal equations, যার সমাধানে Cholesky-ই প্রচলিত)। কলাম নির্ভরশীল হলে, যেমন অংশ ৫-এর মিনিট-ঘণ্টা জোড়া, XᵀX singular আর অসংখ্য সমাধান। Ridge যোগ করে λ‖w‖², Hessian হয় 2(XᵀX + λI), আর vᵀ(XᵀX + λI)v = ‖Xv‖² + λ‖v‖² > ০: λ > ০ হলে সবসময় PD. Ridge তাই আসলে নীতিগত একটি “jitter”, যার একটি পরিসংখ্যানিক অর্থও আছে (পর্ব ১৭-এ MAP হিসেবে)।

Logistic regression. এর log loss-এর Hessian XᵀWX, যেখানে W কর্ণে pi(1 − pi) > ০, তাই PSD আর loss convex. Newton পদ্ধতি প্রতিটি ধাপে HΔ = −∇f সমাধান করে; H PD হলে Cholesky দিয়ে, আর না হলে ধাপটি নিচে না নেমে ওপরে বা saddle-এর দিকে যেতে পারে। এজন্য অনেক বাস্তব optimizer H-এর কর্ণে কিছু যোগ করে (পর্ব ১৫, Second-order পদ্ধতি)।

Kernel আর Gaussian process. SVM-এর dual problem আর kernel ridge-এ Gram matrix K PSD হলেই সমস্যাটি convex থাকে (পর্ব ২৮ আর ২৯)। Gaussian process regression-এ (পর্ব ৪৬) K + σ²I-এর Cholesky দিয়েই অনুমান আর likelihood হিসাব হয়, আর σ² খুব ছোট হলে অংশ ৫-এর jitter ঠিক এখানে লাগে।

আরও গভীরে: Rounding-এর মধ্যে Cholesky কতটা নির্ভরযোগ্য, তার বিশ্লেষণ Nicholas Higham-এর Accuracy and Stability of Numerical Algorithms (দ্বিতীয় সংস্করণ ২০০২) বইয়ে আছে: PD matrix-এ pivoting ছাড়াই এটি backward stable. LAPACK-এর potrf routine-ই NumPy আর SciPy-র Cholesky-র ভেতরে চলে; PSD matrix-এর জন্য pivoted Cholesky (pstrf) rank-ও বের করে। আর কোনো matrix-এর সবচেয়ে কাছের PSD বা correlation matrix খোঁজা নিজেই একটি optimization সমস্যা (Higham ২০০২, IMA Journal of Numerical Analysis).

পরীক্ষা ও ইন্টারভিউতে: এই ধরনের প্রশ্ন বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় প্রায়ই আসে।

  • [[a, b], [b, d]] কখন PD? a > ০ আর ad − b² > ০ (Sylvester).
  • [[1, k], [k, 4]] কোন k-তে PD? ৪ − k² > ০, অর্থাৎ |k| < ২.
  • Covariance matrix কেন PSD? vᵀΣv = Var(vᵀx) ≥ ০; PD নয় যদি feature-গুলোর কোনো মিশ্রণ ধ্রুবক হয়।
  • z ~ N(0, I) থেকে N(μ, Σ) কীভাবে? Σ = LLᵀ (Cholesky), x = μ + Lz.
  • Hessian indefinite হলে stationary point কী? Saddle point; PD হলে কঠোর local minimum.

৯ · AI-এর যুগে — definiteness-এর দাবি আর AI-এর কোড যাচাই

AI assistant এই বিষয়ে সূত্র ঠিকঠাক লেখে, কিন্তু শর্তগুলো প্রায়ই বাদ দেয়, আর ছোট সংখ্যার ভুল ধরা কঠিন কারণ লেখা আত্মবিশ্বাসী।

AI প্রায়ই যা করেকেন ভুলকীভাবে ধরবেন
“সব leading minor ≥ ০ হলে PSD” বলেPSD-র জন্য সব principal minor লাগে; [[0, 0], [0, −1]] পাল্টা উদাহরণছোট পাল্টা উদাহরণ নিজে বানিয়ে eigvalsh চালান
অপ্রতিসম matrix-এ eigvalsh বা cholesky চালায়এরা শুধু একটি ত্রিভুজ পড়ে, ভুল “পাস” দেয়np.allclose(A, A.T) assert করুন
ধরে নেয় Cholesky ব্যর্থ হলে সবসময় exception আসবেব্রাউজারের NumPy-তে NaN ফেরত আসতে পারেSciPy ব্যবহার করুন বা np.isnan যাচাই করুন
Correlated নমুনার জন্য np.sqrt(Sigma) (ঘর ধরে বর্গমূল) ব্যবহার করেLLᵀ ≠ Σ; covariance ভুল আসেনমুনার np.cov লক্ষ্য Σ-এর সঙ্গে মেলান
LinAlgError পেলে বড় jitter (যেমন +1.0) বসিয়ে দেয়Model বদলে যায়, আসল কারণ (নির্ভরশীল কলাম) লুকায়eigvalsh আর matrix_rank দেখুন; ε-এর মাপ লিখে রাখুন
“Hessian-এর determinant ধনাত্মক, তাই minimum” বলেNegative definite-এরও determinant ধনাত্মক হতে পারেসব eigenvalue-এর চিহ্ন দেখুন
পুরোনো বা বানানো API দেয় (যেমন অস্তিত্বহীন is_positive_definite)আপনার version-এ চলবে নানিজের version-এর NumPy/SciPy docs পড়ুন, চালিয়ে দেখুন

উত্তরের সঙ্গে ছোট উদাহরণ আর যাচাইয়ের কোড চেয়ে নিন; নিজে চালানো অংশটিই আসল পরীক্ষা।

আমার কাছে ৪টি feature-এর একটি covariance matrix আছে, আর np.linalg.cholesky "Matrix is not positive definite" দিচ্ছে। ১. কোন কোন কারণে এটি হতে পারে (নির্ভরশীল কলাম, n < d, pairwise missing data, rounding) — প্রতিটি আলাদা করে ব্যাখ্যা করো। ২. প্রতিটি কারণ ধরার জন্য একটি করে NumPy পরীক্ষা লেখো (eigvalsh, matrix_rank, প্রতিসমতা), seed দিয়ে ছোট উদাহরণসহ। ৩. Jitter কখন ঠিক সমাধান আর কখন সমস্যা লুকায়, আর ε কীভাবে matrix-এর মাপ অনুযায়ী বাছব — বলো। ৪. তোমার দেওয়া প্রতিটি NumPy/SciPy function আমার version-এ আছে কি না, docs-এর কোন পাতায় দেখব — লিখে দাও। ৫. তোমার উত্তরে কোথায় ভুল হওয়ার সম্ভাবনা বেশি, সেটিও বলো।

AI-এর দেওয়া linear algebra কোড হাতে পেলে — যাচাইয়ের চেকলিস্ট

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

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

প্র ০১একজন জরিপ-প্রকৌশলীর হাতের হিসাবের কৌশল কীভাবে আজকের ML লাইব্রেরির ভেতরের মূল routine হয়ে উঠল?

André-Louis Cholesky (১৮৭৫–১৯১৮) ছিলেন ফরাসি সেনাবাহিনীর একজন কর্মকর্তা ও ভূ-জরিপ (geodesy) বিশেষজ্ঞ। বিশ শতকের শুরুতে মানচিত্র তৈরির জরিপে কোণ আর দূরত্বের অনেক মাপ নেওয়া হতো, আর সব মাপের ভুল একসঙ্গে মেলাতে least squares-এর normal equations সমাধান করতে হতো। সেই matrix প্রতিসম আর positive definite, আর তখন হিসাব হতো হাতে বা যান্ত্রিক ক্যালকুলেটরে। Cholesky এমন একটি পদ্ধতি বের করেন যা প্রতিসমতার সুবিধা নিয়ে প্রায় অর্ধেক কাজে সমাধান দেয়। প্রচলিত বিবরণ অনুযায়ী তিনি প্রথম বিশ্বযুদ্ধে ১৯১৮ সালে নিহত হন, আর পদ্ধতিটি প্রকাশিত হয় তাঁর মৃত্যুর পর, ১৯২৪ সালে, সহকর্মী Commandant Benoît-এর লেখায়। অনেক পরে, ২০০০-এর দশকে, ফরাসি আর্কাইভে তাঁর হাতে লেখা মূল পাণ্ডুলিপি খুঁজে পাওয়ার কথা গণিতের ইতিহাসবিদেরা উল্লেখ করেছেন।

পদ্ধতিটি টিকে গেল তিন কারণে। প্রথমত, গণনার খরচ: n³/3, LU-এর অর্ধেক। দ্বিতীয়ত, স্থিতিশীলতা: PD matrix-এ সারি অদলবদল ছাড়াই rounding-এর ভুল নিয়ন্ত্রণে থাকে, যা Gaussian elimination-এ নিশ্চিত নয়। তৃতীয়ত, এটি নিজেই একটি পরীক্ষা: সফল হলে matrix PD, ব্যর্থ হলে নয়, আর এই পরীক্ষা eigenvalue বের করার চেয়ে অনেক সস্তা।

আজ NumPy-র np.linalg.cholesky, SciPy-র cho_factor, scikit-learn-এর Gaussian process, statsmodels-এর অনেক হিসাব, আর deep learning framework-গুলোর multivariate Gaussian, সবখানে ভেতরে LAPACK-এর potrf বা তার সমতুল্য। বাজারঘরের একজন data scientist যখন GaussianProcessRegressor চালান, তিনি না জেনেই একজন জরিপ-প্রকৌশলীর হাতের কৌশল ব্যবহার করছেন।

এখানে একটি শিক্ষাও আছে: সংখ্যাগত পদ্ধতির ভালো নকশা গঠনের সুবিধা নেয়। একটি matrix প্রতিসম আর PD, এটুকু জানলেই কাজ অর্ধেক আর ভুলের ঝুঁকি কম। ML-এর অনেক হিসাবে (covariance, XᵀX, kernel) এই গঠন বিনা খরচে পাওয়া যায়।

মূল উপলব্ধি: Cholesky দ্রুত, স্থিতিশীল আর নিজেই PD-র পরীক্ষা, কারণ এটি প্রতিসমতা আর positive definiteness-এর গঠনকে পুরোপুরি কাজে লাগায়। গঠন জানলে সঠিক সরঞ্জাম বাছা যায়।

প্র ০২Floating-point-এ “positive definite” প্রশ্নটির উত্তর কেন সবসময় হ্যাঁ বা না নয়, আর বাস্তবে সিদ্ধান্ত কীভাবে নেবেন?

গণিতে PD একটি তীক্ষ্ণ সীমা: ক্ষুদ্রতম eigenvalue ধনাত্মক হলেই হলো। কিন্তু কম্পিউটারে প্রতিটি সংখ্যা প্রায় ১৬টি দশমিক অঙ্কের নির্ভুলতায় রাখা হয় (double precision, machine epsilon প্রায় ২.২ × ১০−১৬)। একটি matrix-এর বড় eigenvalue যদি ১৭০ হয়, তাহলে eigenvalue হিসাবের ভুল প্রায় ১৭০ × ১০−১৬ মাপের। অংশ ৫-এ ঠিক তাই হয়েছে: গণিতে শূন্য eigenvalue কম্পিউটারে একবার −২.১ × ১০−১৫, আরেকবার −৩.৯ × ১০−১৭, আর ডেস্কটপে একই হিসাব +৬.৭ × ১০−১৫ দিয়েছিল। দুটিই আসলে “শূন্য, rounding-এর সীমার মধ্যে”।

তাই বাস্তব প্রশ্ন হলো: matrix-টি কতটা নিশ্চিতভাবে PD? উত্তর মাপা হয় আপেক্ষিক মাপে: λmin/λmax, অর্থাৎ condition number-এর উল্টো। এটি ১০−১২-এর মতো হলে matrix কাগজে PD হলেও সংখ্যাগতভাবে singular-এর মতো আচরণ করে, আর তার inverse বা Cholesky দিয়ে সমাধানে অনেক অঙ্ক হারাবে (AI-এর ভিত্তি কোর্সের পর্ব ১৭-এর হারানো অঙ্কের নিয়ম)। NumPy-র matrix_rank ঠিক এজন্য একটি tolerance ব্যবহার করে, যা সবচেয়ে বড় singular value, matrix-এর আকার আর machine epsilon থেকে আসে।

ব্যবহারিক নিয়ম তিনটি। (১) Cholesky ব্যর্থ হলে আগে কারণ খুঁজুন: eigvalsh-এ কতগুলো eigenvalue প্রায় শূন্য, matrix_rank কত, কোন কলামগুলো নির্ভরশীল। (২) কারণ যদি ডেটায় হয় (একই তথ্য দুবার, n < d), ডেটা ঠিক করুন বা regularize করুন। (৩) কারণ যদি শুধু rounding হয়, আপেক্ষিক মাপের jitter দিন, যেমন ১০−১০ × trace(A)/n, আর ব্যর্থ হলে ধাপে ধাপে বাড়ান; scikit-learn-এর Gaussian process-এ alpha parameter এই কাজটিই করে। আর “Cholesky সফল” দেখে নিশ্চিন্ত হবেন না: অংশ ৫-এ সফল Cholesky-র একটি কর্ণ ছিল ৩.৪ × ১০−৭, আর সেই matrix-এর ক্ষুদ্রতম eigenvalue ঋণাত্মক দেখাচ্ছিল: rounding-এর সীমায় দুই পরীক্ষাও একমত হয় না।

মূল উপলব্ধি: কম্পিউটারে definiteness একটি মাত্রার প্রশ্ন, শুধু চিহ্নের নয়। ক্ষুদ্রতম আর বৃহত্তম eigenvalue-এর অনুপাত দেখুন, আর প্রতিটি jitter-এর কারণ ও মাপ লিখে রাখুন।

প্র ০৩প্রতিটি জোড়ার correlation আলাদা আলাদা ঠিক থাকলেও পুরো correlation matrix কেন অবৈধ হতে পারে?

তিনটি feature ধরুন: A আর B-এর correlation ০.৯, B আর C-এর ০.৯, কিন্তু A আর C-এর −০.৯. প্রতিটি সংখ্যা −১ থেকে ১-এর মধ্যে, তাই আলাদা করে দেখলে কোনো সমস্যা নেই। কিন্তু একসঙ্গে অসম্ভব: A আর B প্রায় একসঙ্গে চলে, B আর C-ও, তাহলে A আর C কীভাবে প্রায় উল্টো চলবে? গণিতে এর মানে matrix [[1, 0.9, −0.9], [0.9, 1, 0.9], [−0.9, 0.9, 1]] PSD নয়; এর একটি eigenvalue ঋণাত্মক (determinant ঋণাত্মক, হিসাব করে দেখতে পারেন)। অর্থাৎ এমন একটি ওজন-যোগফল vᵀx আছে যার “variance” ঋণাত্মক, যা বাস্তবে কোনো ডেটায় সম্ভব নয়।

এটি বাস্তবে ঘটে কয়েকভাবে। প্রথমত, অনুপস্থিত মানের ডেটায় প্রতিটি জোড়ার correlation সেই জোড়ার দুটি মানই আছে এমন সারি দিয়ে হিসাব করলে (pairwise deletion; pandas-এর df.corr() ডিফল্টভাবে এভাবেই NaN সামলায়), আলাদা জোড়া আলাদা সারির ওপর দাঁড়ায়, তাই পুরো matrix আর কোনো একটি ডেটাসেটের covariance নয়। দ্বিতীয়ত, বিশেষজ্ঞরা হাতে correlation বসালে বা আলাদা উৎস থেকে জোড়া লাগালে। তৃতীয়ত, কিছু সংখ্যা বদলে “stress test” করলে, যেমন অর্থনীতির ঝুঁকি-মডেলে।

অর্থনীতির এই সমস্যা থেকেই Nicholas Higham ২০০২ সালে “Computing the nearest correlation matrix — a problem from finance” প্রবন্ধে একটি পদ্ধতি দেন: প্রদত্ত matrix-এর সবচেয়ে কাছের বৈধ correlation matrix খোঁজা (কর্ণ ১, PSD). সরল একটি বিকল্প হলো eigen-decomposition করে ঋণাত্মক eigenvalue-গুলো শূন্য বা ছোট ধনাত্মক করে দেওয়া, তারপর কর্ণ আবার ১-এ ফেরানো; এটি দ্রুত, তবে সবচেয়ে কাছেরটি দেয় না।

বাজারঘরের দলের জন্য শিক্ষা: অনুপস্থিত মান থাকলে df.corr() থেকে পাওয়া matrix দিয়ে সরাসরি Gaussian sampling বা Mahalanobis চালানোর আগে eigvalsh দেখুন। আর সম্ভব হলে অনুপস্থিত মান আগে সামলান, যাতে সব জোড়া একই সারির ওপর দাঁড়ায়।

মূল উপলব্ধি: PSD হওয়া একটি সামগ্রিক শর্ত, যা প্রতিটি ঘর আলাদা করে দেখে যাচাই করা যায় না। সংখ্যাগুলো একসঙ্গে কোনো বাস্তব ডেটা থেকে আসতে পারে কি না, সেটিই আসল প্রশ্ন।

প্র ০৪Kernel matrix PSD হওয়ার শর্ত কেন এত গুরুত্বপূর্ণ? PSD নয় এমন “kernel” ব্যবহার করলে কী হয়?

Kernel পদ্ধতির মূল ধারণা: k(x, x′) যেন কোনো (হয়তো অসীম-মাত্রার) feature space-এ দুটি বিন্দুর dot product. Dot product-এর Gram matrix সবসময় PSD (অংশ ৫), তাই উল্টো দিক থেকে প্রশ্ন: কোন function-গুলো সত্যিই কোনো feature space-এর dot product? উত্তরের গাণিতিক ভিত্তি James Mercer-এর ১৯০৯ সালের integral equation-এর কাজ, যা ML-এ “Mercer's theorem” নামে পরিচিত: মোটামুটি বললে, প্রতিসম k-এর Gram matrix যেকোনো সসীম বিন্দু-সেটে PSD হলে এমন একটি feature space আছে। এই শর্তকে বলে positive semidefinite kernel; বিস্তারিত পর্ব ২৯ (Kernel trick)-এ।

PSD-র ভূমিকা optimization-এ সরাসরি। SVM-এর dual problem-এ লক্ষ্য function-এ একটি quadratic form থাকে, αᵀ(yyᵀ ∘ K)α (∘ মানে ঘর-ধরে গুণ)। K PSD হলে Dual-এ এই রাশিটি বিয়োগ করে maximize করা হয়, তাই K PSD হলে লক্ষ্য function concave (উল্টো বাটি), আর তার চূড়া নির্ভরযোগ্যভাবে খোঁজা যায়। K indefinite হলে সমস্যাটি অংশ ২-এর জিনের মতো: solver আটকে যেতে পারে, বা নিচে নামতেই থাকে, আর ফল পরিস্থিতিভেদে বদলায়। Gaussian process-এ অবস্থা আরও খারাপ: K একটি covariance, আর অংশ ৬-এর মতো Cholesky না হলে কোনো Gaussian-ই সংজ্ঞায়িত নয়।

একটি পরিচিত উদাহরণ sigmoid (tanh) kernel, k(x, x′) = tanh(a·xᵀx′ + c). Neural network-এর সঙ্গে মিলের কারণে এটি জনপ্রিয় হয়েছিল, কিন্তু সাহিত্যে দেখানো হয়েছে যে a আর c-এর অনেক মানে এটি PSD নয়। scikit-learn-এর SVC তবু এটি চালাতে দেয়; ফল কাজ করতেও পারে, কিন্তু convexity-র নিশ্চয়তা আর থাকে না। একইভাবে, edit distance-এর মতো কোনো দূরত্ব থেকে exp(−d) বানালে তা স্বয়ংক্রিয়ভাবে বৈধ kernel হয় না।

ব্যবহারিক পরীক্ষা সহজ: আপনার ডেটার একটি নমুনায় Gram matrix বানিয়ে eigvalsh দেখুন। বড় ঋণাত্মক eigenvalue থাকলে kernel-টি অন্তত সেই ডেটায় বৈধ নয়; rounding-এর মাপের ঋণাত্মক মান হলে jitter যথেষ্ট।

মূল উপলব্ধি: “Kernel” মানে শুধু একটি মিলের মাপ নয়; তার Gram matrix PSD হতে হবে। এই শর্তই kernel পদ্ধতিকে convex, ব্যাখ্যাযোগ্য আর Gaussian-এর সঙ্গে সংগত রাখে।

প্র ০৫বড় neural network-এর loss-এ local minimum নাকি saddle point বেশি সমস্যা? Hessian-এর definiteness এখানে কী বলে?

দুই মাত্রায় ভাবলে মনে হয়, non-convex loss-এর প্রধান বিপদ খারাপ local minimum: একটি ছোট গর্তে আটকে যাওয়া। কিন্তু লাখ লাখ parameter-এর জগতে ছবিটি আলাদা। একটি stationary point-এ Hessian-এর লাখ লাখ eigenvalue আছে; local minimum হতে হলে সবগুলো ধনাত্মক হতে হবে। একটি সরল আন্দাজি যুক্তি: যদি প্রতিটির চিহ্ন মোটামুটি এলোমেলো হতো, সবগুলো একসঙ্গে ধনাত্মক হওয়া অতি বিরল, তাই অধিকাংশ stationary point হবে indefinite, অর্থাৎ saddle. বাস্তব loss-এ চিহ্নগুলো স্বাধীন নয়, তাই এই যুক্তি শুধু অন্তর্দৃষ্টি।

২০১৪ সালে Dauphin, Pascanu, Gulcehre, Cho, Ganguli আর Bengio-র প্রবন্ধ (“Identifying and attacking the saddle point problem in high-dimensional non-convex optimization”, NeurIPS) পরিসংখ্যানিক পদার্থবিদ্যা আর ছোট network-এর পরীক্ষা থেকে যুক্তি দেয় যে উচ্চ মাত্রায় উঁচু loss-এর stationary point-গুলো বেশিরভাগই saddle, আর নিচু loss-এর কাছে local minimum-গুলো প্রায় সমান ভালো। সমস্যা তখন saddle-এর কাছে ধীর হয়ে যাওয়া, যেখানে gradient প্রায় শূন্য। পরে তাত্ত্বিক কাজ দেখায় যে কিছু শর্তে noise-যুক্ত gradient descent strict saddle (যেখানে অন্তত একটি eigenvalue স্পষ্টভাবে ঋণাত্মক) থেকে বের হয়ে আসে। তবে এই ফলগুলো নির্দিষ্ট অনুমানের ওপর দাঁড়ানো, আর আধুনিক বড় model-এর loss landscape নিয়ে গবেষণা এখনো চলছে।

এখানে অংশ ৩-এর stepper-এর শেষ ধাপটি মনে করুন: জিনের (০, ০)-তে gradient শূন্য, কিন্তু (১, −১) দিকে সরলেই loss কমে। Newton পদ্ধতি এখানে বিপদে পড়ে: indefinite H দিয়ে HΔ = −∇f সমাধান করলে ধাপটি saddle-এর দিকে যেতে পারে। এজন্য second-order পদ্ধতি H-কে PD বানিয়ে নেয় (কর্ণে যোগ, বা ঋণাত্মক eigenvalue-এর চিহ্ন উল্টে), যা পর্ব ১৫-এ আসবে, আর deep learning-এর optimizer-এর বিস্তারিত পরে Deep Learning কোর্সে।

মূল উপলব্ধি: Stationary point-এর চরিত্র Hessian-এর eigenvalue-এর চিহ্নে লেখা। উচ্চ মাত্রায় “সব ধনাত্মক” শর্তটি কঠিন, তাই saddle অনেক বেশি সাধারণ, আর ভালো optimizer-কে saddle থেকে বের হতে জানতে হয়।

অনুশীলন

হিসাবগুলো খাতায় করুন, তারপর উত্তর মেলান। একটির জন্য কোড চালানো ঐচ্ছিক।

  1. ৩ × ৩-এর হাতের হিসাব: A = [[4, 2, 0], [2, 3, 1], [0, 1, 2]]. (ক) Sylvester-এর নিয়মে দেখান A PD. (খ) Cholesky factor L হাতে বের করুন। (গ) L-এর কর্ণ থেকে det A বের করে (ক)-এর শেষ minor-এর সঙ্গে মেলান।

    (ক) M1 = ৪ > ০. M2 = ৪·৩ − ২·২ = ৮ > ০. M3 = det A = ৪(৩·২ − ১·১) − ২(২·২ − ১·০) + ০ = ৪·৫ − ২·৪ = ২০ − ৮ = ১২ > ০. তিনটিই ধনাত্মক, তাই PD. (খ) l11 = √৪ = ২; l21 = ২/২ = ১; l31 = ০/২ = ০. l22 = √(৩ − ১²) = √২ ≈ ১.৪১৪২; l32 = (১ − l31l21)/l22 = (১ − ০)/√২ ≈ ০.৭০৭১. l33 = √(২ − ০² − ০.৫) = √১.৫ ≈ ১.২২৪৭. তাই L = [[2, 0, 0], [1, 1.4142, 0], [0, 0.7071, 1.2247]]. (গ) det A = (২ × √২ × √১.৫)² = ৪ × ২ × ১.৫ = ১২, M3-এর সঙ্গে মেলে। লক্ষ করুন pivot-গুলো lii² = ৪, ২, ১.৫ = M1, M2/M1, M3/M2 = ৪, ৮/৪, ১২/৮. np.linalg.cholesky হুবহু এই L দেয়।

  2. সমালোচনা ও নকশা: বাজারঘরের একজন বিশ্লেষক অনুপস্থিত মানসহ ৬টি গ্রাহক-feature থেকে df.corr() দিয়ে correlation matrix বানালেন, তারপর কাল্পনিক গ্রাহক বানাতে Cholesky চালালেন। LinAlgError আসায় একজন AI assistant পরামর্শ দিল: “কর্ণে 1.0 যোগ করুন।” তিনি তাই করে ১০,০০০ কাল্পনিক গ্রাহক বানালেন আর সেগুলো দিয়ে একটি churn model পরীক্ষা করলেন। এই প্রক্রিয়ার দুর্বলতাগুলো কী, আর আপনি কীভাবে নতুন করে সাজাবেন?

    দুর্বলতা: (১) df.corr() ডিফল্টভাবে প্রতিটি জোড়া আলাদা সারি দিয়ে হিসাব করে, তাই matrix PSD না-ও হতে পারে; ব্যর্থতার কারণ আগে খোঁজা হয়নি। (২) Correlation matrix-এর কর্ণ ১; তাতে ১.০ যোগ করলে কর্ণ ২, আর সব correlation কার্যত অর্ধেক হয়ে যায়: কাল্পনিক গ্রাহকদের feature-গুলো আসলের চেয়ে অনেক কম সম্পর্কিত। এটি “jitter” নয়, model বদল। (৩) কোনো যাচাই নেই: কাল্পনিক ডেটার covariance লক্ষ্যের সঙ্গে মেলানো হয়নি। (৪) Gaussian ধরা হয়েছে, অথচ গ্রাহক-feature (অর্ডারের সংখ্যা, খরচ) প্রায়ই বাঁকা আর ঋণাত্মক হতে পারে না। (৫) কাল্পনিক ডেটায় model “পরীক্ষা” আসল গ্রাহকদের ওপর কার্যকারিতার প্রমাণ নয়।

    নতুন নকশা: eigvalsh দিয়ে ঋণাত্মক eigenvalue-এর মাপ দেখুন; অনুপস্থিত মান আগে সামলান বা শুধু সম্পূর্ণ সারি নিন; দরকার হলে nearest correlation matrix বা eigenvalue ছেঁটে ঠিক করুন, আর যত ছোট সম্ভব আপেক্ষিক jitter দিন, মান লিখে রাখুন। নমুনা বানিয়ে np.corrcoef লক্ষ্যের সঙ্গে মেলান, কয়েকটি seed-এ। বাঁকা feature-এ log রূপান্তরের পর Gaussian ভাবুন। আর model-এর আসল মূল্যায়ন আসল ডেটার একটি তালা-দেওয়া test set-এ।

  3. আউটপুট অনুমান করুন: চালানোর আগে লিখে ফেলুন নিচের কোড কী ছাপবে।
    import numpy as np
    A = np.array([[2., 1.], [1., 2.]])
    L = np.linalg.cholesky(A)
    print(np.round(L, 3))
    print(np.round(np.linalg.eigvalsh(A), 3))
    x = np.array([1., -1.])
    print(x @ A @ x)
    [[1.414 0.   ]
     [0.707 1.225]]
    [1. 3.]
    2.0

    l11 = √২ = ১.৪১৪; l21 = ১/√২ = ০.৭০৭; l22 = √(২ − ০.৫) = √১.৫ = ১.২২৫. Eigenvalue: (২ − λ)² = ১ থেকে λ = ১, ৩, ছোট থেকে বড় ক্রমে। xᵀAx = ২·১ + ২·১·(১)(−১) + ২·১ = ২ − ২ + ২ = ২.০; x = (১, −১) ছোট eigenvalue ১-এর দিক, আর |x|² = ২, তাই ১ × ২ = ২. ছাপা ফরম্যাট একটি ডেস্কটপ run-এ যাচাই করা।

  4. Parameter-এর পরিসর: M(k) = [[1, k], [k, 4]]. (ক) কোন k-তে M PD, কোন k-তে শুধু PSD? (খ) M যদি দুটি feature-এর covariance হয় (variance ১ আর ৪), তাহলে correlation ρ কত, আর (ক)-এর শর্ত ρ-এর ভাষায় কী বলে? (গ) k = ২ হলে Cholesky-র কোন ধাপে কী ঘটে?

    (ক) Sylvester: ১ > ০ সবসময়; det = ৪ − k² > ০ ⇔ |k| < ২. তাই |k| < ২-এ PD; |k| = ২-এ det = ০, eigenvalue ০ আর ৫, তাই PSD কিন্তু PD নয়; |k| > ২-এ indefinite. (খ) ρ = k/(√১ · √৪) = k/২. শর্ত |k| < ২ মানে |ρ| < ১: correlation-এর পরিচিত সীমা আসলে PSD শর্তেরই রূপ, আর |ρ| = ১ মানে একটি feature অন্যটির হুবহু রৈখিক ফল। (গ) l11 = ১, l21 = ২, l22² = ৪ − ৪ = ০. গণিতে l22 = ০, তাই L-এর কর্ণে শূন্য, আর Lᵀx = y-তে শূন্য দিয়ে ভাগ; SciPy আর ডেস্কটপের NumPy এখানে LinAlgError দেয় (অংশ ৩-এর C valley-র মতো)।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমPD matrix A দিয়ে Ax = b সমাধানের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. A প্রতিসম কি না যাচাই: A = Aᵀ
  2. Cholesky: A = LLᵀ (ব্যর্থ হলে A PD নয়)
  3. সামনে থেকে সমাধান: Ly = b
  4. পেছন থেকে সমাধান: Lᵀx = y
  5. Residual ‖Ax − b‖ দেখে উত্তর যাচাই

প্রতিসম matrix [[2, 3], [3, 2]] কোন শ্রেণির?

  • Positive definite
  • Positive semidefinite, কিন্তু PD নয়
  • Indefinite
  • Negative definite

প্রতিসম একটি matrix-এর জন্য নিচের কোনটি একা positive definite হওয়ার যথেষ্ট শর্ত?

  • কর্ণের সব ঘর ধনাত্মক
  • উপরের-বাঁ কোণের সব k × k অংশের determinant ধনাত্মক
  • পুরো matrix-এর determinant ধনাত্মক
  • সব ঘর ধনাত্মক

A = [[9, 3], [3, 5]]-এর Cholesky factor L (A = LLᵀ, L নিচের-ত্রিভুজ, কর্ণ ধনাত্মক)-এর l22 কত?

  • 2
  • √5 ≈ 2.236
  • 1
  • 4

যেকোনো ডেটার sample covariance matrix S কেন সবসময় positive semidefinite?

  • কারণ S-এর সব ঘর ধনাত্মক
  • কারণ S প্রতিসম
  • কারণ সারির সংখ্যা feature-এর চেয়ে বেশি
  • কারণ যেকোনো v-তে vᵀSv হলো vᵀx-এর variance, যা ঋণাত্মক হতে পারে না

z ~ N(0, I) আর Σ = LLᵀ (Cholesky) হলে x = μ + Lz-এর covariance কত?

  • L
  • LᵀL
  • Σ
  • Σ + μμᵀ

একটি loss function-এর gradient একটি বিন্দুতে শূন্য, আর সেখানে Hessian-এর eigenvalue ৪.২ আর −০.৩. বিন্দুটি কী?

  • কঠোর local minimum
  • Saddle point
  • Local maximum
  • Global minimum, কারণ gradient শূন্য

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. xᵀAx একটি quadratic form; এতে শুধু প্রতিসম অংশ (A + Aᵀ)/2 গোনা হয়, আর eigen-অক্ষে এটি ∑ λiyi².
  2. সব λ > ০: PD, বাটি; সব λ ≥ ০: PSD, উপত্যকা হতে পারে; মিশ্র চিহ্ন: indefinite, জিন।
  3. তিন পরীক্ষা একমত: eigenvalue, leading minor (Sylvester), Cholesky. PSD-র জন্য সব principal minor লাগে, আর NumPy প্রতিসমতা যাচাই করে না।
  4. Covariance, XᵀX আর Gram matrix সবসময় PSD; নির্ভরশীল কলাম বা n ≤ d হলে singular. Jitter εI সব λ-কে ε বাড়ায়, কিন্তু ডেটার রোগ সারায় না।
  5. A = LLᵀ: n³/3 খরচে সমাধান, log det = 2∑log lii, x = μ + Lz দিয়ে N(μ, Σ), আর Ly = x − μ দিয়ে Mahalanobis দূরত্ব।

পরের পর্বে: এই পর্বে Hessian-এর definiteness দেখে minimum আর saddle চিনলাম। পর্ব ১১ (Matrix calculus — gradient, Jacobian আর Hessian) দেখাবে সেই gradient আর Hessian matrix আকারে কীভাবে বের করতে হয়: ∇(xᵀAx) থেকে least squares, ridge আর logistic regression পর্যন্ত, প্রতিটি সূত্র numerical gradient দিয়ে যাচাইসহ।

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

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান