Notas para contenedor de docker:

Comando de docker para ejecución de la nota de forma local:

nota: cambiar <ruta a mi directorio> por la ruta de directorio que se desea mapear a /datos dentro del contenedor de docker.

docker run --rm -v <ruta a mi directorio>:/datos --name jupyterlab_numerical -p 8888:8888 -d palmoreck/jupyterlab_numerical:1.1.0

password para jupyterlab: qwerty

Detener el contenedor de docker:

docker stop jupyterlab_numerical

Documentación de la imagen de docker palmoreck/jupyterlab_numerical:1.1.0 en liga.


Nota basada en liga

Factorización QR

Si $A \in \mathbb{R}^{m \times n}$ con $m >= n$ entonces existen $Q \in \mathbb{R}^{m \times m}$ ortogonal y $R \in \mathbb{R}^{m \times n}$ triangular superior tales que $A=QR$:

Comentario: la factorización $QR$ puede escribirse en una forma "delgada" obteniéndose la factorización thin QR:

En este caso $Q_1$ no se llama ortogonal sino con columnas ortonormales, $R_1$ es triangular superior. Si el rank(A) es igual a $n$ (matriz $A$ se nombra de rank completo o full rank) y $R_1$ tiene entradas en la diagonal positivas, la factorización thin QR es única.

¿Ortogonal, columnas ortonormales?

Un conjunto de vectores $\{x_1, \dots, x_p\}$ en $\mathbb{R}^m$ ($x_i \in \mathbb{R}^m$)es ortogonal si $x_i^Tx_j=0$ $\forall i\neq j$. Por ejemplo, para un conjunto de $2$ vectores $x_1,x_2$ en $\mathbb{R}^3$ esto se visualiza:

Comentarios:

  • Si el conjunto $\{x_1,\dots,x_p\}$ en $\mathbb{R}^m$ satisface $x_i^Tx_j= \delta_{ij}= \begin{cases} 1 &\text{ si } i=j,\\ 0 &\text{ si } i\neq j \end{cases}$ se le nombra conjunto ortonormal, esto es, constituye un conjunto ortogonal y cada elemento del conjunto tiene norma Euclidiana igual a $1$: $||x_i||_2 = 1, \forall i=1,\dots,p$.

  • Si definimos a la matriz $X$ con columnas dadas por cada uno de los vectores del conjunto $\{x_1,\dots, x_p\}$: $X=(x_1, \dots , x_p) \in \mathbb{R}^{m \times p}$ entonces la propiedad de que cada par de columnas satisfaga $x_i^Tx_j=\delta_{ij}$ se puede escribir en notación matricial como $X^TX = I_p$ con $I_p$ la matriz identidad de tamaño $p$ o bien $XX^T=I_m$. A la matriz $X$ se le nombra matriz con columnas ortonormales.

  • Si cada $x_i$ está en $\mathbb{R}^p$ (en lugar de $\mathbb{R}^m$) entonces construímos a la matriz $X$ como el punto anterior con la diferencia que $X \in \mathbb{R}^{p \times p}$. En este caso $X$ se le nombra matriz ortogonal.

Reflexiones de Householder

La factorización $QR$ es posible calcularla con las reflexiones de Householder las cuales son matrices simétricas, ortogonales, $R^TR = R^2 = I_m$, $R^{-1}=R$, $det(R)=-1$. Una reflexión de Householder se puede construir a partir de un vector $v \neq 0$ definiendo:

$$R = I_m-\beta v v^T$$

con $v \in \mathbb{R}^m - \{0\}$ y $\beta = \frac{2}{v^Tv}$. El vector $v$ se llama vector de Householder. La multiplicación $Rx$ representa la reflexión del vector $x \in \mathbb{R}^m$ a través del hiperplano $span\{v\}^\perp$*

*$span\{v\}$ es el conjunto generado por $v$. Se define como el conjunto de combinaciones lineales de $v$: $span\{v\} = \left \{\displaystyle \sum_{i=1}^m k_i v_i | k_i \in \mathbb{R} \forall i =1,\dots,m \right \}$.

Un dibujo que representa lo anterior es el siguiente en el que se utiliza $u \in \mathbb{R}^m - \{0\}$ , $||u||_2 = 1$ y $R=I_m-2 u u^T$, el reflector elemental alrededor de $u^\perp$:

Comentario: en el dibujo anterior se utiliza el proyector ortogonal elemental sobre el complemento ortogonal de u: $u^\perp = \{x \in \mathbb{R}^m| u^Tx=0\}$ definido como: $P=I_m- u u^T$ y $Px$ es la proyección ortogonal de $x$ sobre $u^\perp$ . Los proyectores ortogonales elementales no son matrices ortogonales, son singulares, son simétricas y $P^2=P$. El proyector ortogonal elemental de $x$ sobre $u^\perp$ tienen $rank$ igual a $m-1$ y el proyector ortogonal de $x$ sobre $span\{u\}$ definido por $I_m-P=uu^T$ tienen $rank$ igual a $1$.

Las reflexiones de Householder pueden utilizarse para hacer ceros por debajo de una entrada de un vector. Por ejemplo:


In [1]:
import numpy as np

In [2]:
x = np.array([1,2,3])

In [3]:
x


Out[3]:
array([1, 2, 3])

Utilizamos la definición $v=x-||x||_2e_1$ con $e_1=(1,0,0)^T$ vector canónico para construir al vector de Householder:


In [4]:
v = x-np.linalg.norm(x)*np.array([1,0,0]) #uno en la primer entrada pues se desea
                                          #hacer ceros en las entradas restantes

In [5]:
beta = 2/v.dot(v)

Hacemos ceros por debajo de la primera entrada de $x$ haciendo la multiplicación matriz-vector $Rx$. Pero para aplicar $Rx$ no construímos $R = I_3 -\beta vv^T$, en lugar de eso hacemos $Rx = x - \beta v v^Tx$:


In [6]:
x-beta*v*(v.dot(x))


Out[6]:
array([3.74165739, 0.        , 0.        ])

obsérvese que el resultado de $Rx$ es $(||x||_2,0,0)^T$:


In [14]:
np.linalg.norm(x)


Out[14]:
3.7416573867739413

Sólo para mostrar que $Rx$ construyendo $R$ es equivalente a lo anterior, se construye a continuación $R$:


In [17]:
R = np.eye(3)-beta*np.outer(v,np.transpose(v))

In [18]:
R


Out[18]:
array([[ 0.26726124,  0.53452248,  0.80178373],
       [ 0.53452248,  0.61007346, -0.5848898 ],
       [ 0.80178373, -0.5848898 ,  0.12266529]])

In [19]:
R@x


Out[19]:
array([3.74165739e+00, 0.00000000e+00, 2.22044605e-16])

Comentario:

  • Otra opción para definir al vector de Householder es $v=x+||x||_2e_1$ con $e_1=(1,0,0)^T$:

In [22]:
v = x+np.linalg.norm(x)*np.array([1,0,0]) #uno en la primer entrada pues se desea
                                          #hacer ceros en las entradas restantes

In [24]:
beta = 2/v.dot(v)

In [25]:
x-beta*v*(v.dot(x))


Out[25]:
array([-3.74165739e+00, -4.44089210e-16, -4.44089210e-16])

¿Cuál definición del vector de Householder usar?

La respuesta a la pregunta tiene que ver con que en cualquiera de las dos definiciones del vector de Householder $v=x \pm ||x||_2 e_1$, la multiplicación $Rx$ refleja $x$ en el primer eje coordenado:

El vector $v^+ = - u_0^+ = x-||x||_2e_1$ refleja $x$ respecto al subespacio $H^+$. El vector $v^- = -u_0^- = x+||x||_2e_1$ refleja $x$ respecto al subespacio $H^-$. Para disminuir los errores por redondeo y evitar el problema de cancelación en la aritmética de punto flotante (ver 1.2.Sistema_de_punto_flotante) se utiliza $v = x+signo(x_1)||x||_2e_1$ donde $signo(x_1) = \begin{cases} 1 &\text{ si } x_1 \geq 0 ,\\ -1 &\text{ si } x_1 < 0 \end{cases}$. La idea de la definción anterior con la función $signo(\cdot)$ es que la reflexión (en el dibujo anterior $-||x||_2e_1$ o $||x||_2e_1$) sea lo más alejada posible de $x$. En el dibujo anterior como $x_1, x_2>0$ entonces se refleja respecto al subespacio $H^-$ quedando su reflexión igual a $-||x||_2e_1$.

Comentarios:

  • Otra forma de lidiar con el problema de cancelación es definiendo a la primera componente del vector de Householder $v_1$ como $v_1=x_1-||x||_2$ y haciendo una manipulación algebraica como sigue:
$$v_1=x_1-||x||_2 = \frac{x_1^2-||x||_2^2}{x_1+||x||_2} = -\frac{x_2^2+x_3^2+\dots + x_m^2}{x_1+||x||_2}.$$
  • En la implementación del cálculo del vector de Householder, es útil que $v_1=1$ y así únicamente se almacenará $v(2:m)$. Al vector $v(2:m)$ se le nombra parte esencial del vector de Householder.

Algoritmo para el cálculo del vector de Householder, nombre de función: $house(\cdot)$

Entrada: $x \in \mathbb{R}^m$.

Salida: $v \in \mathbb{R}^m$ con $v_1 =1$ y $\beta \in \mathbb{R}$ tal que $R=I_m-\beta vv^T$ es ortogonal con $Rx = ||x||_2e_1$.

  • Definir $m$ como la longitud de $x$.

  • Definir $norm\text{_2_m} = x(2:m)^Tx(2:m)$.

  • Definir $v = \left[\begin{array}{c} 1\\ x(2:m) \end{array} \right]$

//Checamos con las siguientes condiciones si $x$ es un múltiplo del vector canónico $e_1$ y el $signo(x_1)$

  • Si $norm\text{_2_m} = 0$, $x_1 \geq 0$ hacer $\beta=0$. En otro caso:

    • Si $norm\text{_2_m} = 0$, $x_1 <0$ hacer $\beta=2$. #la referencia Golub, Van Loan tiene un error... es beta=2 no beta=-2, corroborar con 3a edición del libro.

      En otro caso:

      • $norm\text{_x} = \sqrt{x_1^2 + norm\text{_2_m}}$

      • Si $x_1 \leq 0$ hacer $v_1 = x_1-norm\text{_x}$. En otro caso: $v_1 = - \frac{norm\text{_2_m}}{x_1+norm\text{_x}}$

      • Definir $\beta = \frac{2v_1^2}{norm\text{_2_m}+v_1^2}$

      • Definir $v = \frac{v}{v_1}$

Algoritmo para calcular la factorización $QR$ con reflexiones de Householder

Entrada: $A \in \mathbb{R}^{m \times n}$ con $m \geq n$.

Salida: matriz $A$ sobreescrita con la parte esencial del vector de Householder y las entradas de la matriz $R$. Ver comentarios de abajo.

  • Para j de 1 a n

    • Calcular $v,\beta$ llamando a la función $house(A(j:m,j))$

    • $A(j:m, j:n) = A(j:m,j:n)-(\beta v)(v^TA(j:m,j:n))$

    • Si $j < m$ definir $A(j+1:m,j) = v(2:m-j+1)$.

Comentarios:

  • La parte triangular superior de $A$ se sobreescribe con la parte triangular superior de $R$ y las componentes $j+1:m$ del $j$-ésimo vector de Householder se almacenan en $A(j+1:m,j)$ para $j<m$:

Si $v^{(j)} = [0, \dots ,0,1,v_{j+1}^{(j)}, \dots,v_m^{(j)}]^T$ es el $j$-ésimo vector de Householder para $j=1,\dots,m$, y por ejemplo $m=5$, $n=4$ entonces con el algoritmo anterior se obtiene:

$$A=\begin{array}{l} \left[ \begin{array}{cccc} r_{11} & r_{12} & r_{13} & r_{14}\\ v_2^{(1)} & r_{22} & r_{23} & r_{24}\\ v_3^{(1)} & v_3^{(2)} & r_{33} & r_{34}\\ v_4^{(1)} & v_4^{(2)} & v_4^{(3)} & r_{44}\\ v_5^{(1)} & v_5^{(2)} & v_5^{(3)} & v_5^{(4)} \end{array} \right] \end{array} $$
  • Los valores de las $\beta$'s para cada vector de Householder se pueden calcular con la expresión:
$$\beta_j = \frac{2}{1+||A(j+1:m,j)||_2^2}$$

para $j=1,\dots,m$.

  • El almacenamiento de los vectores $v^{(1)}, v^{(2)}, \dots, v^{(n)}$ y las $\beta_j$'s correspondientes se le nombra factor form representation de $Q$.

  • Típicamente no es necesario construír a la matriz $Q$ en la factorización $QR$. Por ejemplo para realizar la multiplicación: $Q^TC$ con $C \in \mathbb{R}^{m \times p}$ se realiza con:

    • Para $j$ de $1$ a $n$

      • $v(j:m) = \left[\begin{array}{c} 1\\ A(j+1:m,j) \end{array} \right]$

        *$\beta_j = \frac{2}{1+||A(j+1:m,j)||_2^2}$

        *$C(j:m,:) = C(j:m,:) - (\beta_jv(j:m))(v(j:m)^TC(j:m,:))$

¿Qué es lo que está realizando el algoritmo para calcular la factorización QR?

Está aplicando las transformaciones de Householder a la matriz $A$ por la izquierda. Si $Q_j = I_m - \beta_j v^{(j)}v^{T(j)}$ es la $j$-ésima transformación de Householder y $v^{(j)}$ es el $j$-ésimo vector de Householder, entonces en el ciclo for del algoritmo se realiza el producto $Q^TA$ con $Q=Q_1Q_2 \cdots Q_n$. En cada paso del ciclo for se hacen ceros por debajo de una entrada de la matriz:

En el dibujo anterior se muestran los ceros en la matriz $A$ después de aplicar $Q_1, Q_2$ a la matriz, lo cual se representa con el producto: $Q_2Q_1A$. La matriz $Q_3$ se aplicará a continuación y modificará las entradas en rojo. Finalmente $Q^TA = R$ y como $Q$ es ortogonal se tendrá la igualdad: $A=QR$.

¿Dado el sistema $Ax=b$, $A \in \mathbb{R}^{n \times n}$ cómo se resuelve con la factorización $QR$?

Paso 1: encontrar factores $Q,R$ tales que $A=QR$. La $Q$ se puede obtener con la factor form representation, no es necesario calcularla pues para el paso $2$ se puede hacer uso del algoritmo de multiplicación $Q^Tb$ descrito en esta nota.

Paso 2: resolver con el método de sustitución hacia atrás el sistema triangular superior $Rx=Q^Tb$.

Referencias:

  • G. H. Golub, C. F. Van Loan, Matrix Computations, John Hopkins University Press, 2013.

  • Ver 0_definiciones_generales para algunas definiciones del álgebra lineal como ortogonalidad, matriz de reflexión de Householder y matrices de rotación.