Di bab Inverse Matriks, matriks singular ditandai dengan exception LinAlgError: baris yang merupakan kelipatan baris lain membuat np.linalg.inv menolak bekerja. Padahal di dunia nyata, data redundan justru sering muncul. Contohnya: pemilik warung mencatat paket menu di sebuah sistem kasir, lalu staf menambahkan entri ganda “paket ganda = 2 kali paket hemat”. Baris baru itu tidak membawa informasi tambahan, dan matriks sistem persamaan harga yang terbentuk menjadi singular.

Pseudo-inverse adalah generalisasi inverse yang tetap terdefinisi untuk matriks singular sekalipun. NumPy menyediakannya sebagai np.linalg.pinv, dan fungsi ini selalu mengembalikan hasil untuk matriks apa pun — persegi atau tidak, full-rank maupun rank-deficient. Bab ini membandingkan perilaku inv dan pinv, menguji sifat Moore-Penrose, memakai pinv sebagai mesin least squares, lalu menutup dengan ambang rcond dan hubungannya dengan SVD.

inv Menolak, pinv Tetap Menghitung #

Kita pakai matriks 2x2 dengan baris kedua tepat 2 kali baris pertama — pola entri ganda pada cerita di atas:

python
import numpy as np

A = np.array([[1.0, 1.0],
              [2.0, 2.0]])  # baris kedua = 2 kali baris pertama
try:
    np.linalg.inv(A)
except np.linalg.LinAlgError as e:
    print("inv -> LinAlgError:", e)
print("pinv(A) =")
print(np.round(np.linalg.pinv(A), 2))

Output yang Dihasilkan:

text
inv -> LinAlgError: Singular matrix
pinv(A) =
[[0.1 0.2]
 [0.1 0.2]]

Bedah baris demi baris:

  1. Baris 3-4 (A): matriks 2x2 dengan rank 1 — np.linalg.matrix_rank pada bab Matrix Rank menilai matriks ini hanya membawa satu baris informasi bebas.
  2. Baris 5-8 (try/except): np.linalg.inv gagal karena inverse memang tidak ada; fungsi tersebut melempar np.linalg.LinAlgError dengan pesan “Singular matrix”. Kita menangkap exception itu dan mencetaknya, sehingga program tetap berjalan dan output tetap terukur.
  3. Baris 9-10 (pinv): np.linalg.pinv bekerja lewat SVD dan tidak melempar exception untuk matriks singular. Hasilnya bukan inverse (yang tidak ada), melainkan matriks P = [[0.1, 0.2], [0.1, 0.2]] — pasangan terbaik yang mungkin untuk A.

Sifat Moore-Penrose #

Hasil pinv bukan matriks sebarang; hasilnya adalah Moore-Penrose inverse, satu-satunya matriks P yang memenuhi empat sifat sekaligus. Dua sifat utamanya bisa kita verifikasi langsung:

python
import numpy as np

A = np.array([[1.0, 1.0],
              [2.0, 2.0]])
P = np.linalg.pinv(A)
print("rank A        :", np.linalg.matrix_rank(A))
print("A @ P @ A == A:", np.allclose(A @ P @ A, A))
print("P @ A @ P == P:", np.allclose(P @ A @ P, P))
print("A @ P @ A =")
print(np.round(A @ P @ A, 10))

Output yang Dihasilkan:

text
rank A        : 1
A @ P @ A == A: True
P @ A @ P == P: True
A @ P @ A =
[[1. 1.]
 [2. 2.]]

Baris demi baris:

  1. Baris 6 (P = ...): pseudo-inverse dihitung sekali lalu disimpan.
  2. Baris 7: rank A = 1, konfirmasi bahwa matriks 2x2 ini rank-deficient.
  3. Baris 8: A @ P @ A kembali menjadi A — sifat pertama Moore-Penrose. Untuk matriks invertible, sifat ini dipenuhi inverse biasa; untuk matriks singular, pinv menghadirkan padanannya.
  4. Baris 9: P @ A @ P kembali menjadi P — sifat kedua. Dua sifat lainnya menuntut A @ P dan P @ A simetris; keduanya juga berlaku untuk hasil pinv.

pinv sebagai Mesin Least Squares #

Kembali ke kasus warung, kini dengan tiga catatan struk: paket hemat (1 nasi goreng + 1 es teh = Rp15000), entri gandanya (2 nasi goreng + 2 es teh = Rp31000 — kelipatan baris pertama, tetapi totalnya tidak konsisten karena salah ketik), dan paket keluarga (1 nasi goreng + 2 es teh = Rp19000). Sistem ini overdetermined, redundan, dan tidak konsisten sekaligus — kombinasi yang membuat solve maupun inv tidak relevan:

python
import numpy as np

A = np.array([[1.0, 1.0],
              [2.0, 2.0],
              [1.0, 2.0]])
b = np.array([15000.0, 31000.0, 19000.0])
x_pinv = np.linalg.pinv(A) @ b
x_lstsq = np.linalg.lstsq(A, b, rcond=None)[0]
print("pinv @ b :", x_pinv)
print("lstsq    :", x_lstsq)
print("allclose :", np.allclose(x_pinv, x_lstsq))
print("galat maks:", np.abs(A @ x_pinv - b).max())

Output yang Dihasilkan:

text
pinv @ b : [11800.  3600.]
lstsq    : [11800.  3600.]
allclose : True
galat maks: 400.0
  1. Baris 7 (x_pinv = ...): mengalikan pseudo-inverse dengan b menghasilkan solusi least squares: harga kompromi nasi goreng Rp11800 dan es teh Rp3600.
  2. Baris 8 (x_lstsq = ...): fungsi lstsq dari bab Least Squares menghasilkan angka yang sama.
  3. Baris 10 (allclose): kedua jalur identik karena pinv dan lstsq sama-sama bekerja di atas SVD.
  4. Baris 11: galat terbesar Rp400 — kompromi yang tak terhindarkan dari struk yang saling bertentangan.

Ketika kolom A bebas linear, solusi least squares bersifat tunggal dan pinv(A) @ b memberikan jawaban yang sama dengan lstsq. Ketika kolom tidak bebas, pinv tetap menjawab dengan solusi least squares ber norma terkecil — keunggulan yang tidak dimiliki jalur inverse biasa.

Ambang rcond dan Hubungan dengan SVD #

Secara konsep, pinv menghitung SVD A = U S V^T (bab Singular Value Decomposition) lalu membentuk V · diag(1/s, dengan cutoff) · U^T: setiap nilai singular s yang berada di bawah ambang diperlakukan nol dan tidak dibalik. Ambang itu dikendalikan argumen rcond:

python
import numpy as np

A = np.array([[1.0, 0.0],
              [0.0, 1e-10]])
print("rcond default:")
print(np.linalg.pinv(A))
print("rcond=1e-8:")
print(np.linalg.pinv(A, rcond=1e-8))

Output yang Dihasilkan:

text
rcond default:
[[1.e+00 0.e+00]
 [0.e+00 1.e+10]]
rcond=1e-8:
[[1. 0.]
 [0. 0.]]
  1. Baris 5-6 (rcond default): nilai singular 1e-10 masih di atas ambang bawaan, sehingga dibalik menjadi 1e10. Angka sebesar itu adalah sinyal numerik buruk: pembalikan yang membengkak.
  2. Baris 7-8 (rcond=1e-8): nilai singular 1e-10 kini dianggap nol, sehingga kontribusinya ditiadakan dan P berisi 0 pada posisi tersebut.

Matriks dengan nilai singular yang sangat kecil disebut ill-conditioned; keputusan memotong atau membalik nilai singular itulah yang menentukan kestabilan hasil — tema utama bab Stabilitas Numerik.

Sebagai ringkasan:

Situasinp.linalg.invnp.linalg.pinv
Matriks invertibleinverse persissetara (dalam toleransi)
Matriks singular / rank-deficientLinAlgErrortetap menghitung
Matriks tidak persegiLinAlgErrortetap menghitung