from sympy import Matrix, eyeDiagonalización
En este documento ilustraremos cómo usar Python para resolver los problemas tipo propuestos por L. Merino y E. Santos en página de resolución de ejercicios tipo correspondientes al bloque “Diagonalización”.
Ejemplo
Dada la matriz
\[ A=\left( \begin{array}{ccc} 5 & 1 & -3 \\ 1 & 5 & -3 \\ 2 & 2 & -2 \end{array}\right). \]
Determinar si es o no diagonalizable y, en caso de que lo sea, determinar su forma diagonal y una matriz de paso.
A=Matrix([(5,1,-3),(1,5,-3),(2,2,-2)])
A\(\displaystyle \left[\begin{matrix}5 & 1 & -3\\1 & 5 & -3\\2 & 2 & -2\end{matrix}\right]\)
Podemos calcular los valores propios con eigenvals.
A.eigenvals(){4: 2, 0: 1}
O ver toda la información (incluyendo multiplicidades y vectores propios) con eigenvects.
A.eigenvects()[(0,
1,
[Matrix([
[1/2],
[1/2],
[ 1]])]),
(4,
2,
[Matrix([
[-1],
[ 1],
[ 0]]),
Matrix([
[3],
[0],
[1]])])]
De la salida que obtenemos, observamos que tenemos dos valores propios: 0 con multiplicidad algebraica y geométrica 1, y 4 con multiplicidad algebraica y geométrica 2. También podemos construir la matriz de paso con los datos que hemos obtenido, pero es más fácil usar diagonalize.
A.diagonalize()(Matrix([
[1, -1, 3],
[1, 1, 0],
[2, 0, 1]]),
Matrix([
[0, 0, 0],
[0, 4, 0],
[0, 0, 4]]))
P, D = A.diagonalize()P\(\displaystyle \left[\begin{matrix}1 & -1 & 3\\1 & 1 & 0\\2 & 0 & 1\end{matrix}\right]\)
D\(\displaystyle \left[\begin{matrix}0 & 0 & 0\\0 & 4 & 0\\0 & 0 & 4\end{matrix}\right]\)
Comprobemos que efectivamente \(P^{-1}AP\) es diagonal.
P.inv()*A*P==DTrue
Hagamos este proceso paso a paso usando calculando el polinomio característico y los subespacios propios.
Empezamos calculando el polinomio característico de A y sus raíces (valores propios).
from sympy.abc import xA.charpoly()\(\displaystyle \operatorname{PurePoly}{\left( \lambda^{3} - 8 \lambda^{2} + 16 \lambda, \lambda, domain=\mathbb{Z} \right)}\)
A.charpoly(28)\(\displaystyle \operatorname{PurePoly}{\left( 28^{3} - 8 28^{2} + 16 28, 28, domain=\mathbb{Z} \right)}\)
p=A.charpoly(x)
p\(\displaystyle \operatorname{PurePoly}{\left( x^{4} - 8 x^{3} + 13 x^{2} - 6 x, x, domain=\mathbb{Z} \right)}\)
p.all_roots()[0, 1, 1, 6]
Por lo que 0 tiene multiplicidad 1, y 4 multiplicidad 2.
Calculemos ahora los subespacios propios asociados a cada uno de esos valores propios.
V0=A.nullspace()
V0[Matrix([
[-1],
[ 0],
[ 2],
[ 1]])]
V4=(A-4*eye(3)).nullspace()
V4--------------------------------------------------------------------------- ShapeError Traceback (most recent call last) Cell In[40], line 1 ----> 1 V4=(A-4*eye(3)).nullspace() 2 V4 File /usr/local/lib/python3.9/site-packages/sympy/core/decorators.py:106, in call_highest_priority.<locals>.priority_decorator.<locals>.binary_op_wrapper(self, other) 104 if f is not None: 105 return f(self) --> 106 return func(self, other) File /usr/local/lib/python3.9/site-packages/sympy/matrices/common.py:2937, in MatrixArithmetic.__sub__(self, a) 2935 @call_highest_priority('__rsub__') 2936 def __sub__(self, a): -> 2937 return self + (-a) File /usr/local/lib/python3.9/site-packages/sympy/core/decorators.py:106, in call_highest_priority.<locals>.priority_decorator.<locals>.binary_op_wrapper(self, other) 104 if f is not None: 105 return f(self) --> 106 return func(self, other) File /usr/local/lib/python3.9/site-packages/sympy/matrices/common.py:2642, in MatrixArithmetic.__add__(self, other) 2640 if hasattr(other, 'shape'): 2641 if self.shape != other.shape: -> 2642 raise ShapeError("Matrix size mismatch: %s + %s" % ( 2643 self.shape, other.shape)) 2645 # honest SymPy matrices defer to their class's routine 2646 if getattr(other, 'is_Matrix', False): 2647 # call the highest-priority class's _eval_add ShapeError: Matrix size mismatch: (4, 4) + (3, 3)
Podemos usar hstack para combinar los vectores que hemos encontrado.
P=Matrix.hstack(V0[0],V4[0],V4[1])
P\(\displaystyle \left[\begin{matrix}\frac{1}{2} & -1 & 3\\\frac{1}{2} & 1 & 0\\1 & 0 & 1\end{matrix}\right]\)
O de una forma más compacta.
Matrix.hstack(*(V0+V4))\(\displaystyle \left[\begin{matrix}\frac{1}{2} & -1 & 3\\\frac{1}{2} & 1 & 0\\1 & 0 & 1\end{matrix}\right]\)
P.inv()*A*P\(\displaystyle \left[\begin{matrix}0 & 0 & 0\\0 & 4 & 0\\0 & 0 & 4\end{matrix}\right]\)
Ejercicio
Estudiar si la siguiente matriz es o no diagonalizable y, en tal caso, determinar su forma diagonal y una matriz de paso. \[ A=\left( \begin{array}{ccc} 2 & 1 & -2 \\ 0 & 2 & -1 \\ 0 & 0 & 1 \end{array}\right) \]
A=Matrix([(2,1,-2),(0,2,-1),(0,0,1)])
A\(\displaystyle \left[\begin{matrix}2 & 1 & -2\\0 & 2 & -1\\0 & 0 & 1\end{matrix}\right]\)
Al ser triangular, ya sabemos cuáles van a ser los valores propios (2 y 1).
p=A.charpoly(x)
p.all_roots()[1, 2, 2]
El valor propio 2 tiene multiplicidad algebraica 2, pero sin embargo, su subespacio propio asociado tiene dimensión uno, por lo que \(A\) no es diagonalizable.
V2=(A-2*eye(3)).nullspace()
V2[Matrix([
[1],
[0],
[0]])]
try:
A.diagonalize()
except:
print("No es diagonalizable")No es diagonalizable
Ejercicio
Razonar que la siguiente matriz \(A\) es diagonalizable y determinar su forma diagonal y una matriz de paso. Determinar \(A^k\) en función de \(k\). \[ A=\left( \begin{array}{cccc} 1 & 0 & 0 & 1 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & -2 \\ 1 & 0 & -2 & 5 \end{array}\right) \]
A=Matrix([(1,0,0,1),(0,1,0,0),(0,0,1,-2),(1,0,-2,5)])
A\(\displaystyle \left[\begin{matrix}1 & 0 & 0 & 1\\0 & 1 & 0 & 0\\0 & 0 & 1 & -2\\1 & 0 & -2 & 5\end{matrix}\right]\)
A.eigenvects()[(0,
1,
[Matrix([
[-1],
[ 0],
[ 2],
[ 1]])]),
(1,
2,
[Matrix([
[0],
[1],
[0],
[0]]),
Matrix([
[2],
[0],
[1],
[0]])]),
(6,
1,
[Matrix([
[ 1/5],
[ 0],
[-2/5],
[ 1]])])]
Vemos que las multiplicidades algebraicas y geométricas coinciden. Por tanto, A es diagonalizable.
P,D = A.diagonalize()
P\(\displaystyle \left[\begin{matrix}-1 & 0 & 2 & 1\\0 & 1 & 0 & 0\\2 & 0 & 1 & -2\\1 & 0 & 0 & 5\end{matrix}\right]\)
P.inv()*A*P\(\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 6\end{matrix}\right]\)
Calculemos P de nuevo “a mano”.
A.charpoly().all_roots()[0, 1, 1, 6]
V0=A.nullspace()
V0[Matrix([
[-1],
[ 0],
[ 2],
[ 1]])]
V1=(A-eye(4)).nullspace()
V1[Matrix([
[0],
[1],
[0],
[0]]),
Matrix([
[2],
[0],
[1],
[0]])]
V6=(A-6*eye(4)).nullspace()
V6[Matrix([
[ 1/5],
[ 0],
[-2/5],
[ 1]])]
P=Matrix.hstack(*(V0+V1+V6))
P\(\displaystyle \left[\begin{matrix}-1 & 0 & 2 & \frac{1}{5}\\0 & 1 & 0 & 0\\2 & 0 & 1 & - \frac{2}{5}\\1 & 0 & 0 & 1\end{matrix}\right]\)
P.inv()*A*P\(\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 6\end{matrix}\right]\)
Calculemos ahora las potencias de \(A\). Para todo \(k\) entero positivo, \(A^k=(P^{-1}DP)^k=P^{-1}D^kP\).
from sympy import var, powsimpk=var("k", integer=True, nonzero=True)D=Matrix.diag([0,1,1,6])
D\(\displaystyle \left[\begin{matrix}0 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 6\end{matrix}\right]\)
D**k\(\displaystyle \left[\begin{matrix}0^{k} & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\0 & 0 & 0 & 6^{k}\end{matrix}\right]\)
Ak=P.inv()*Matrix.diag([0,1,1,6**k])*P
Ak\(\displaystyle \left[\begin{matrix}\frac{6^{k}}{6} + \frac{2}{3} & 0 & \frac{1}{3} & \frac{6^{k}}{6} - \frac{2}{15}\\0 & 1 & 0 & 0\\\frac{2}{5} & 0 & \frac{1}{5} & - \frac{2}{25}\\\frac{5 \cdot 6^{k}}{6} - \frac{2}{3} & 0 & - \frac{1}{3} & \frac{5 \cdot 6^{k}}{6} + \frac{2}{15}\end{matrix}\right]\)
powsimp(Ak)\(\displaystyle \left[\begin{matrix}\frac{6^{k}}{6} + \frac{2}{3} & 0 & \frac{1}{3} & \frac{6^{k}}{6} - \frac{2}{15}\\0 & 1 & 0 & 0\\\frac{2}{5} & 0 & \frac{1}{5} & - \frac{2}{25}\\\frac{5 \cdot 6^{k}}{6} - \frac{2}{3} & 0 & - \frac{1}{3} & \frac{5 \cdot 6^{k}}{6} + \frac{2}{15}\end{matrix}\right]\)
Ejercicio
Estudiar para qué valores de los parámetros \(a\) y \(b\) es diagonalizable la matriz \[ A=\left( \begin{array}{ccc} 1 & a & 0 \\ 0 & 0 & b \\ 0 & b & 0 \end{array}\right). \]
from sympy.abc import a,bA=Matrix([[1,a,0],[0,0,b],[0,b,0]])
A\(\displaystyle \left[\begin{matrix}1 & a & 0\\0 & 0 & b\\0 & b & 0\end{matrix}\right]\)
p=A.charpoly(x)
p\(\displaystyle \operatorname{PurePoly}{\left( x^{3} - x^{2} - b^{2} x + b^{2}, x, domain=\mathbb{Z}\left[b\right] \right)}\)
Factorizamos el polinomio característico.
p.factor_list()(1,
[(PurePoly(x - 1, x, domain='ZZ[b]'), 1),
(PurePoly(x - b, x, domain='ZZ[b]'), 1),
(PurePoly(x + b, x, domain='ZZ[b]'), 1)])
O bien como expresión.
p.as_expr().factor()\(\displaystyle \left(- b + x\right) \left(b + x\right) \left(x - 1\right)\)
O bien con solve.
from sympy import solvesolve(p.as_expr(),x)[1, -b, b]
Los valores propios son \(\{1,b,-b\}\). Así si \(b\not\in\{0,1,-1\}\), los tres valores propios son diferentes y la matriz es diagonalizable.
Estudiemos ahora qué ocurre para \(b=0\), en cuyo caso los valores propios son \(1\) y \(0\) con multiplicidad dos. Nos interesa por tanto ver si el subespacio propio asociado a \(0\) tiene dimensión dos.
Ab0=A.subs({b:0})
Ab0\(\displaystyle \left[\begin{matrix}1 & a & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]\)
Que tiene rango 1, por lo que que el valor propio 0 tiene multiplicidad geométrica 2.
Ab0.nullspace()[Matrix([
[-a],
[ 1],
[ 0]]),
Matrix([
[0],
[0],
[1]])]
Por lo que para \(b=0\), la multiplicidad algebraica y geométrica de cada valor propio coincide, siendo así Ab0 diagonalizable.
P0, D= Ab0.diagonalize()
P0\(\displaystyle \left[\begin{matrix}- a & 0 & 1\\1 & 0 & 0\\0 & 1 & 0\end{matrix}\right]\)
P0.inv()*Ab0*P0\(\displaystyle \left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 1\end{matrix}\right]\)
Veamos ahora el caso \(b=1\). Los valores propios son \(1\), con multiplicidad dos, y \(-1\).
Ab1=A.subs({b:1})
Ab1\(\displaystyle \left[\begin{matrix}1 & a & 0\\0 & 0 & 1\\0 & 1 & 0\end{matrix}\right]\)
Ab1-eye(3)\(\displaystyle \left[\begin{matrix}0 & a & 0\\0 & -1 & 1\\0 & 1 & -1\end{matrix}\right]\)
En este caso el rango de \(A-I\) depende de \(a\). - Si \(a\neq 0\), el rango es dos, y la dimension del subespacio propio asociado a 1 sería 1, por lo que la matriz no sería diagonalizable. - Si \(a=0\), entonces la matriz es diagonalizable, pues el rango de \(A-I\) es 1, y por tanto su núcleo tiene dimensión 2.
Hay que tener cuidado con usar rank o rref directamente, pues sympy considera a como un símbolo.
(Ab1-eye(3)).rank()2
(Ab1-eye(3)).rref()(Matrix([
[0, 1, 0],
[0, 0, 1],
[0, 0, 0]]),
(1, 2))
Podemos considerar el menor \(2\times 2\) superior derecho, que nos proporciona la distinción de los valores de \(a\) que hemos hecho arriba.
M=(Ab1-eye(3))[:2,1:]
M\(\displaystyle \left[\begin{matrix}a & 0\\-1 & 1\end{matrix}\right]\)
M.det()\(\displaystyle a\)
Para \(b=-1\), tenemos como valores propios a 1 (multiplicidad 2) y -1.
Abm1=A.subs({b:1})
Abm1\(\displaystyle \left[\begin{matrix}1 & a & 0\\0 & 0 & 1\\0 & 1 & 0\end{matrix}\right]\)
(Abm1-eye(3))\(\displaystyle \left[\begin{matrix}0 & a & 0\\0 & -1 & 1\\0 & 1 & -1\end{matrix}\right]\)
Repitiéndose la distinción que hicimos para \(b=1\).