Capítulo 4

Normas y Ortogonalidad

4.1 Producto Interno

Un producto interno es una función bilineal, simétrica y definida positiva:

x,y=xTy=i=1nxiyi\langle \mathbf{x}, \mathbf{y} \rangle = \mathbf{x}^T \mathbf{y} = \sum_{i=1}^n x_i y_i

Para espacios de funciones: f,g=f(x)g(x)dx\langle f, g \rangle = \int f(x)g(x) dx.

4.2 Normas

L2 (Euclídea)

x2=xi2\|\mathbf{x}\|_2 = \sqrt{\sum x_i^2}

La norma más común, inducida por el producto interno.

L1 (Manhattan)

x1=xi\|\mathbf{x}\|_1 = \sum |x_i|

Usada en LASSO y cuando queremos sparseza.

L∞ (Máximo)

x=maxixi\|\mathbf{x}\|_\infty = \max_i |x_i|
python
import numpy as np

x = np.array([3, -4])

print(f"||x||_1 = {np.linalg.norm(x, 1):.2f}")   # 7
print(f"||x||_2 = {np.linalg.norm(x, 2):.2f}")   # 5
print(f"||x||_∞ = {np.linalg.norm(x, np.inf):.2f}")  # 4

# Matriz: norma de Frobenius
A = np.array([[1, 2], [3, 4]])
print(f"||A||_F = {np.linalg.norm(A, 'fro'):.2f}")

4.3 Ángulos y Ortogonalidad

El ángulo entre dos vectores está dado por el coseno:

cosθ=x,yxy\cos \theta = \frac{\langle \mathbf{x}, \mathbf{y} \rangle}{\|\mathbf{x}\| \|\mathbf{y}\|}

Son ortogonales si x,y=0\langle \mathbf{x}, \mathbf{y} \rangle = 0.Ortonormales si además tienen norma 1.

python
import numpy as np

x = np.array([1, 0])
y = np.array([0, 1])

cos_theta = np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))
print(f"cos(θ) = {cos_theta:.2f} → θ = {np.degrees(np.arccos(cos_theta)):.0f}°")
print("Ortogonales:", np.isclose(np.dot(x, y), 0))

# Base ortonormal: Q^T Q = I
Q = np.array([[1/np.sqrt(2), -1/np.sqrt(2)],
              [1/np.sqrt(2),  1/np.sqrt(2)]])
print("Q^T Q:
", Q.T @ Q)  # ≈ identidad

4.4 Proyección Ortogonal

La proyección de y\mathbf{y} sobre un vector x\mathbf{x} es:

projx(y)=x,yx,xx\text{proj}_{\mathbf{x}}(\mathbf{y}) = \frac{\langle \mathbf{x}, \mathbf{y} \rangle}{\langle \mathbf{x}, \mathbf{x} \rangle} \mathbf{x}

Sobre un subespacio con base ortonormal Q: proj(y)=QQTy\text{proj}(\mathbf{y}) = QQ^T \mathbf{y}.

python
import numpy as np

# Proyección de y sobre x
y = np.array([3, 4])
x = np.array([1, 2])

proj = np.dot(x, y) / np.dot(x, x) * x
print(f"Proyección: {proj}")
print(f"Residuo: {y - proj}")
print(f"Ortogonal: {np.dot(x, y - proj):.6f}")  # ≈ 0

# Gram-Schmidt: ortogonalización
def gram_schmidt(V):
    U = []
    for v in V:
        u = v.copy()
        for w in U:
            u -= np.dot(w, v) / np.dot(w, w) * w
        if np.linalg.norm(u) > 1e-10:
            U.append(u)
    return np.array(U)

V = np.array([[1, 1, 0], [1, 0, 1], [0, 1, 1]], dtype=float)
U = gram_schmidt(V)
print("Base ortogonal:
", U)