Algoritmo di estrazione della forma canonica di Jordan

Lo scopo di questo notebook è illustrare un breve e semplice algoritmo di estrazione della forma canonica di Jordan di una matrice $A \in M(n, \mathbb{C})$ qualsiasi. Si ricorda che la forma canonica di Jordan è un invariante completo per similitudine di una matrice e che è una matrice a blocchi diagonale composta da più blocchi, detti per l'appunto di Jordan, della seguente forma:

$$ J_{\lambda, m} = \begin{bmatrix} \lambda & 1 & \; & \; \\ \; & \lambda & \ddots & \; \\ \; & \; & \ddots & 1 \\ \; & \; & \; & \lambda \end{bmatrix} \in M(m, \mathbb{C}). $$

Innanzitutto si sceglie un $n \in \mathbb{N}^+$ che rappresenta la taglia della matrice quadrata data in esame all'algoritmo e si crea la matrice $I = I_n$, ossia la matrice identità di taglia $n$.

In [35]:
%display latex
from IPython.display import display, Markdown, Latex

n = 10
I = matrix.identity(n)

Si definisce adesso una funzione $\operatorname{jordan}(A)$ che prende in ingresso una matrice $A \in M(n, \mathbb{C})$ senza restituire alcun risultato. Tale funzione illustra passo passo in output l'algoritmo di estrazione della forma canonica di Jordan della matrice $A$ nei seguenti passi:

  • Calcola il polinomio caratteristico $p_A(x)$ di $A$ e lo fattorizza;
  • Ne deduce lo spettro $\operatorname{sp}(A)$ e si riduce a studiare i blocchi relativi a ciascun autovalore;
  • Per ogni autovalore $\lambda$, calcola le dimensioni dei kernel delle potenze di $B = A - \lambda I$ fino a che non viene raggiunta la molteplicità algebrica di $\lambda$;
  • Infine, per l'autovalore $\lambda$, calcola il numero di blocchi $b_i$ di taglia $i$ secondo la formula $b_i = 2 \dim \ker B^i - \dim \ker B^{i-1} - \dim \ker B^{i+1}$;
  • Compone tutti i blocchi in una matrice a blocchi diagonale, ossia la forma canonica di Jordan.
In [58]:
def jordan(A):
    display(Latex(r"Innanzitutto, si calcola il polinomio caratteristico di $A$, che risulta essere $p_A(x) = " + latex(factor(charpoly(A)(SR('x')))) + "$."))
    eig = set(A.eigenvalues())
    sp = ", ".join(map(latex, eig))

    display(Latex(r"Allora, calcolandone le radici, si ricava $\operatorname{sp}(A) = \{" + sp + r"\}$."))
    display(Markdown("---"))

    Js = []

    for i, t in enumerate(eig, start=1):
        B = A - t*I
        r = rank(B)
        k = n - r

        display(Latex(f"({i}) " + r"Consideriamo $\lambda = " + latex(t) + r"$ e $B=A-\lambda I=" + latex(B) + r".$"))
        display(Latex(r"$B$ ha rango $" + str(r) + r"$ e quindi $\mu_g(\lambda) = " + str(k) + r"$."))

        if k == 1:
            display(Latex(r"Allora a $\lambda$ sarà dedicato esattamente un blocco nella forma canonica di Jordan."))
        else:
            display(Latex(r"Allora a $\lambda$ saranno dedicati esattamente $" + str(k) + "$ blocchi nella forma canonica di Jordan."))

        K = [k]
        k_1 = k
        k_2 = n-rank(B^2)

        i = 3
        while k_1 != k_2:
            K.append(k_2)
            k_1 = k_2
            k_2 = n-rank(B^i)
            i += 1

        display(Latex(r"Si calcolano adesso le dimensioni dei kernel fino a quando non viene raggiunta la molteplicità algebrica $\mu_a(\lambda) = " + str(K[-1]) + "$:"))

        for i, k in enumerate(K, start=1):
            if i == 1:
                if i == len(K):
                    display(Latex(r"‎ ‎ ‎ ‎ • $\dim \ker B = " + str(k) + "$."))
                else:
                    display(Latex(r"‎ ‎ ‎ ‎ • $\dim \ker B = " + str(k) + "$;"))
            else:
                if i == len(K):
                    display(Latex(r"‎ ‎ ‎ ‎ • $\dim \ker B^" + str(i) + r" = " + str(k) + "$."))
                else:
                    display(Latex(r"‎ ‎ ‎ ‎ • $\dim \ker B^" + str(i) + r" = " + str(k) + "$;"))

        display(Latex(r"Pertanto a $\lambda$ sono assegnati i seguenti blocchi (dove $b_n$ indica il numero di blocchi di taglia $n$):"))

        b = {}

        for i, k in enumerate(K, start=1):
            if i == len(K):
                if i == 2:
                    b[i] = k - K[0]
                    display(Latex(r"‎ ‎ ‎ ‎ • $b_2 = \dim \ker B^2 - \dim \ker B = " + str(b[i]) + "$."))
                elif i == 1:
                    b[i] = k
                    display(Latex(r"‎ ‎ ‎ ‎ • $b_1 = \dim \ker B = " + str(b[i]) + "$."))
                else:
                    b[i] = k - K[i-2]
                    display(Latex(r"‎ ‎ ‎ ‎ • $b_" + str(i) + r" = \dim \ker B^" + str(i) + r" - \dim \ker B^" + str(i-1) + " = " + str(b[i]) + "$."))
            elif i == 1:
                b[i] = 2*k - K[1]
                display(Latex(r"‎ ‎ ‎ ‎ • $b_1 = 2 \dim \ker B - \dim \ker B^2 = " + str(b[i]) + "$;"))
            else:
                if i != 2:
                    b[i] = 2*k - K[i-2] - K[i]
                    display(Latex(r"‎ ‎ ‎ ‎ • $b_" + str(i) + r" = 2 \dim \ker B^" + str(i) + r" - \dim \ker B^" + str(i-1) + r" - \dim \ker B^" + str(i+1) + " = " + str(b[i]) + "$;"))
                else:
                    b[i] = 2*k - K[0] - K[2]
                    display(Latex(r"‎ ‎ ‎ ‎ • $b_" + str(i) + r" = 2 \dim \ker B^2 - \dim \ker B - \dim \ker B^3 = " + str(b[i]) + "$;"))
        
        JBs = [jordan_block(t, N) for N, j in b.items() for _ in range(j)]
        Js.extend(JBs)
        
        display(Latex(r"Allora l'insieme di tutti i blocchi relativi a $\lambda$ sarà rappresentato dalla seguente matrice: $J_{\lambda} = " + latex(block_diagonal_matrix(JBs)) + "$."))
        display(Markdown("---"))
            
    JNF = block_diagonal_matrix(Js)
    
    display(Latex(r"La forma canonica di Jordan di $A$ sarà allora $J = " + latex(JNF) + "$."))

Si sceglie adesso una matrice $A \in M(n, \mathbb{C})$ di cui si vuole calcolare la forma canonica di Jordan.

In [59]:
# A deve avere esattamente n^2 elementi, essendo n x n...
A = matrix(SR, n, [1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3])
A
Out[59]:

Si calcola infine la forma canonica di Jordan della matrice $A$ mediante la funzione $\operatorname{jordan}$.

In [60]:
jordan(A)
Innanzitutto, si calcola il polinomio caratteristico di $A$, che risulta essere $p_A(x) = {\left(x - 1\right)}^{4} {\left(x - 2\right)}^{3} {\left(x - 3\right)}^{3} $.
Allora, calcolandone le radici, si ricava $\operatorname{sp}(A) = \{1, 2, 3\}$.

(1) Consideriamo $\lambda = 1 $ e $B=A-\lambda I= \left(\begin{array}{rrrrrrrrrr} 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 2 \end{array}\right) .$
$B$ ha rango $9$ e quindi $\mu_g(\lambda) = 1$.
Allora a $\lambda$ sarà dedicato esattamente un blocco nella forma canonica di Jordan.
Si calcolano adesso le dimensioni dei kernel fino a quando non viene raggiunta la molteplicità algebrica $\mu_a(\lambda) = 4$:
‎ ‎ ‎ ‎ • $\dim \ker B = 1$;
‎ ‎ ‎ ‎ • $\dim \ker B^2 = 2$;
‎ ‎ ‎ ‎ • $\dim \ker B^3 = 3$;
‎ ‎ ‎ ‎ • $\dim \ker B^4 = 4$.
Pertanto a $\lambda$ sono assegnati i seguenti blocchi (dove $b_n$ indica il numero di blocchi di taglia $n$):
‎ ‎ ‎ ‎ • $b_1 = 2 \dim \ker B - \dim \ker B^2 = 0$;
‎ ‎ ‎ ‎ • $b_2 = 2 \dim \ker B^2 - \dim \ker B - \dim \ker B^3 = 0$;
‎ ‎ ‎ ‎ • $b_3 = 2 \dim \ker B^3 - \dim \ker B^2 - \dim \ker B^4 = 0$;
‎ ‎ ‎ ‎ • $b_4 = \dim \ker B^4 - \dim \ker B^3 = 1$.
Allora l'insieme di tutti i blocchi relativi a $\lambda$ sarà rappresentato dalla seguente matrice: $J_{\lambda} = \left(\begin{array}{rrrr} 1 & 1 & 0 & 0 \\ 0 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{array}\right) $.

(2) Consideriamo $\lambda = 2 $ e $B=A-\lambda I= \left(\begin{array}{rrrrrrrrrr} -1 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & -1 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & -1 & 1 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & -1 & 1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \end{array}\right) .$
$B$ ha rango $8$ e quindi $\mu_g(\lambda) = 2$.
Allora a $\lambda$ saranno dedicati esattamente $2$ blocchi nella forma canonica di Jordan.
Si calcolano adesso le dimensioni dei kernel fino a quando non viene raggiunta la molteplicità algebrica $\mu_a(\lambda) = 3$:
‎ ‎ ‎ ‎ • $\dim \ker B = 2$;
‎ ‎ ‎ ‎ • $\dim \ker B^2 = 3$.
Pertanto a $\lambda$ sono assegnati i seguenti blocchi (dove $b_n$ indica il numero di blocchi di taglia $n$):
‎ ‎ ‎ ‎ • $b_1 = 2 \dim \ker B - \dim \ker B^2 = 1$;
‎ ‎ ‎ ‎ • $b_2 = \dim \ker B^2 - \dim \ker B = 1$.
Allora l'insieme di tutti i blocchi relativi a $\lambda$ sarà rappresentato dalla seguente matrice: $J_{\lambda} = \left(\begin{array}{r|rr} 2 & 0 & 0 \\ \hline 0 & 2 & 1 \\ 0 & 0 & 2 \end{array}\right) $.

(3) Consideriamo $\lambda = 3 $ e $B=A-\lambda I= \left(\begin{array}{rrrrrrrrrr} -2 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & -2 & 1 & 0 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & -2 & 1 & 0 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & -2 & 1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & -1 & 0 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & -1 & 1 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & -1 & 1 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \end{array}\right) .$
$B$ ha rango $9$ e quindi $\mu_g(\lambda) = 1$.
Allora a $\lambda$ sarà dedicato esattamente un blocco nella forma canonica di Jordan.
Si calcolano adesso le dimensioni dei kernel fino a quando non viene raggiunta la molteplicità algebrica $\mu_a(\lambda) = 3$:
‎ ‎ ‎ ‎ • $\dim \ker B = 1$;
‎ ‎ ‎ ‎ • $\dim \ker B^2 = 2$;
‎ ‎ ‎ ‎ • $\dim \ker B^3 = 3$.
Pertanto a $\lambda$ sono assegnati i seguenti blocchi (dove $b_n$ indica il numero di blocchi di taglia $n$):
‎ ‎ ‎ ‎ • $b_1 = 2 \dim \ker B - \dim \ker B^2 = 0$;
‎ ‎ ‎ ‎ • $b_2 = 2 \dim \ker B^2 - \dim \ker B - \dim \ker B^3 = 0$;
‎ ‎ ‎ ‎ • $b_3 = \dim \ker B^3 - \dim \ker B^2 = 1$.
Allora l'insieme di tutti i blocchi relativi a $\lambda$ sarà rappresentato dalla seguente matrice: $J_{\lambda} = \left(\begin{array}{rrr} 3 & 1 & 0 \\ 0 & 3 & 1 \\ 0 & 0 & 3 \end{array}\right) $.

La forma canonica di Jordan di $A$ sarà allora $J = \left(\begin{array}{rrrr|r|rr|rrr} 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 0 & 2 & 0 & 0 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 0 & 0 & 2 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 2 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 0 & 0 & 0 & 0 & 3 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 3 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 3 \end{array}\right) $.

(c) 2023, ~videtta