# Álgebra Linear

O Sage fornece os objetos usuais em álgebra linear, por exemplo, o polinômio característico, matriz escalonada, traço, decomposição, etc., de uma matriz.

Criar e multiplicar matrizes é fácil e natural:

    sage: A = Matrix([[1,2,3],[3,2,1],[1,1,1]])
    sage: w = vector([1,1,-4])
    sage: w*A
    (0, 0, 0)
    sage: A*w
    (-9, 1, -2)
    sage: kernel(A)
    Free module of degree 3 and rank 1 over Integer Ring
    Echelon basis matrix:
    [ 1  1 -4]

Note que no Sage, o núcleo de uma matriz \(A\) é o núcleo à esquerda, i.e., o conjunto de vetores \(w\) tal que \(wA=0\).

Resolver equações matriciais é fácil usando o método `solve_right`. Calculando `A.solve_right(Y)` obtém-se uma matrix (ou vetor) \(X\) tal que \(AX=Y\):

    sage: Y = vector([0, -4, -1])
    sage: X = A.solve_right(Y)
    sage: X
    (-2, 1, 0)
    sage: A * X   # checking our answer...
    (0, -4, -1)

Uma barra invertida `\` pode ser usada no lugar de `solve_right`; use `A \ Y` no lugar de `A.solve_right(Y)`.

    sage: A \ Y
    (-2, 1, 0)

Se não existir solução, o Sage retorna um erro:

    sage: A.solve_right(w)
    Traceback (most recent call last):
    ...
    ValueError: matrix equation has no solutions

Similarmente, use `A.solve_left(Y)` para resolver para \(X\) em \(XA=Y\).

O Sage também pode calcular autovalores e autovetores:

    sage: A = matrix([[0, 4], [-1, 0]])
    sage: A.eigenvalues ()
    [-2*I, 2*I]
    sage: B = matrix([[1, 3], [3, 1]])
    sage: B.eigenvectors_left()
    [(4, [
    (1, 1)
    ], 1), (-2, [
    (1, -1)
    ], 1)]

(A sintaxe para a resposta de `eigenvectors_left` é uma lista com três componentes: (autovalor, autovetor, multiplicidade).) Autovalores e autovetores sobre `QQ` ou `RR` também podem ser calculados usando o Maxima (veja Maxima).

Como observado em Anéis Básicos, o anel sobre o qual a matriz esta definida afeta alguma de suas propriedades. A seguir, o primeiro argumento do comando `matrix` diz para o Sage considerar a matriz como uma matriz de inteiros (o caso `ZZ`), uma matriz de números racionais (`QQ`), ou uma matriz de números reais (`RR`):

    sage: AZ = matrix(ZZ, [[2,0], [0,1]])
    sage: AQ = matrix(QQ, [[2,0], [0,1]])
    sage: AR = matrix(RR, [[2,0], [0,1]])
    sage: AZ.echelon_form()
    [2 0]
    [0 1]
    sage: AQ.echelon_form()
    [1 0]
    [0 1]
    sage: AR.echelon_form()
    [ 1.00000000000000 0.000000000000000]
    [0.000000000000000  1.00000000000000]

## Espaços de Matrizes

Agora criamos o espaço \(\text{Mat}_{3\times 3}(\QQ)\) de matrizes \(3 \times 3\) com entradas racionais:

    sage: M = MatrixSpace(QQ,3)
    sage: M
    Full MatrixSpace of 3 by 3 dense matrices over Rational Field

(Para especificar o espaço de matrizes 3 por 4, você usaria `MatrixSpace(QQ,3,4)`. Se o número de colunas é omitido, ele é considerado como igual ao número de linhas, portanto, `MatrixSpace(QQ,3)` é sinônimo de `MatrixSpace(QQ,3,3)`.) O espaço de matrizes é equipado com sua base canônica:

    sage: B = M.basis()
    sage: len(B)
    9
    sage: B[0,1]
    [0 1 0]
    [0 0 0]
    [0 0 0]

Vamos criar uma matriz como um elemento de `M`.

    sage: A = M(range(9)); A
    [0 1 2]
    [3 4 5]
    [6 7 8]

A seguir calculamos a sua forma escalonada e o núcleo.

    sage: A.echelon_form()
    [ 1  0 -1]
    [ 0  1  2]
    [ 0  0  0]
    sage: A.kernel()
    Vector space of degree 3 and dimension 1 over Rational Field
    Basis matrix:
    [ 1 -2  1]

Agora ilustramos o cálculo com matrizes definidas sobre um corpo finito:

    sage: M = MatrixSpace(GF(2),4,8)
    sage: A = M([1,1,0,0, 1,1,1,1, 0,1,0,0, 1,0,1,1,
    ....:        0,0,1,0, 1,1,0,1, 0,0,1,1, 1,1,1,0])
    sage: A
    [1 1 0 0 1 1 1 1]
    [0 1 0 0 1 0 1 1]
    [0 0 1 0 1 1 0 1]
    [0 0 1 1 1 1 1 0]
    sage: rows = A.rows()
    sage: A.columns()
    [(1, 0, 0, 0), (1, 1, 0, 0), (0, 0, 1, 1), (0, 0, 0, 1),
     (1, 1, 1, 1), (1, 0, 1, 1), (1, 1, 0, 1), (1, 1, 1, 0)]
    sage: rows
    [(1, 1, 0, 0, 1, 1, 1, 1), (0, 1, 0, 0, 1, 0, 1, 1),
     (0, 0, 1, 0, 1, 1, 0, 1), (0, 0, 1, 1, 1, 1, 1, 0)]

Criamos o subespaço sobre \(\GF{2}\) gerado pelas linhas acima.

    sage: V = VectorSpace(GF(2),8)
    sage: S = V.subspace(rows)
    sage: S
    Vector space of degree 8 and dimension 4 over Finite Field of size 2
    Basis matrix:
    [1 0 0 0 0 1 0 0]
    [0 1 0 0 1 0 1 1]
    [0 0 1 0 1 1 0 1]
    [0 0 0 1 0 0 1 1]
    sage: A.echelon_form()
    [1 0 0 0 0 1 0 0]
    [0 1 0 0 1 0 1 1]
    [0 0 1 0 1 1 0 1]
    [0 0 0 1 0 0 1 1]

A base de \(S\) usada pelo Sage é obtida a partir das linhas não-nulas da forma escalonada da matriz de geradores de \(S\).

## Álgebra Linear Esparsa

O Sage fornece suporte para álgebra linear esparsa.

    sage: M = MatrixSpace(QQ, 100, sparse=True)
    sage: A = M.random_element(density = 0.05)
    sage: E = A.echelon_form()

O algoritmo multi-modular no Sage é bom para matrizes quadradas (mas não muito bom para matrizes que não são quadradas):

    sage: M = MatrixSpace(QQ, 50, 100, sparse=True)
    sage: A = M.random_element(density = 0.05)
    sage: E = A.echelon_form()
    sage: M = MatrixSpace(GF(2), 20, 40, sparse=True)
    sage: A = M.random_element()
    sage: E = A.echelon_form()

Note que o Python é sensível a maiúsculas e minúsculas:

    sage: M = MatrixSpace(QQ, 10,10, Sparse=True)
    Traceback (most recent call last):
    ...
    TypeError: __classcall__() got an unexpected keyword argument 'Sparse'