.. -*- coding: utf-8 -*-
.. _section-linalg:

Álgebra Lineal
==============

Sage soporta construcciones estándar de álgebra lineal, como el
polinomio característico, la forma escalonada, la traza, 
descomposición, etcétera de una matriz.

La creación de matrices y la multiplicación es sencilla y 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]

La descripción de ``kernel(A)`` indica que se trata de un
subespacio de dimensión 1 ("rank 1") de un espacio de dimensión 3
("degree 3"). Por el momento, tanto ``kernel(A)`` como el espacio 
ambiente admiten coeficientes enteros ("over Integer Ring").
Finalmente, Sage nos muestra una base escalonada ("Echelon basis").

Observa que en Sage, el núcleo de la matriz :math:`A` es el "núcleo por
la izquierda", e.g. el subespacio formado por los vectores :math:`w` 
tales que :math:`wA=0`.

Resolver ecuaciones matriciales es sencillo, usando el método 
``solve_right`` (resolver por la derecha). Al evaluar 
``A.solve_right(Y)`` obtenemos una matriz (o un vector)
:math:`X` tal que :math:`AX=Y`:

.. link

::

    sage: Y = vector([0, -4, -1])
    sage: X = A.solve_right(Y)
    sage: X
    (-2, 1, 0)
    sage: A * X   # comprobando la solución...
    (0, -4, -1)

Si no hay solución, Sage lanza un error:

.. skip

::

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

De forma similar, usamos ``A.solve_left(Y)`` para despejar :math:`X` de
la ecuación :math:`XA=Y`.

Sage también puede calcular autovalores ("eigenvalues") y autovectores
("eigenvectors")::

    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)]

(La sintaxis de la salida de ``eigenvectors_left`` es una lista de
tuplas: (autovalor, autovector, multiplicidad).)  Los autovalores
y autovectores sobre ``QQ`` o ``RR`` también se pueden calcular
usando Maxima.

Como ya indicamos en :ref:`section-rings`, el anillo sobre el que se 
define una matriz afecta algunas de sus propiedades. En las líneas que 
siguen, el primer argumento al comando ``matrix`` le dice a Sage que
considere la matriz como una matriz de enteros (si el argumento es
``ZZ``), de números racionales (si es ``QQ``), o de números reales 
(si es ``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]

(El comando ``echelon_form`` devuelve una forma escalonada de la matriz)

Espacios de matrices
--------------------

Creamos el espacio :math:`\text{Mat}_{3\times 3}(\QQ)` matrices 
`3 \times 3` con coeficientes racionales::

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

(Para especificar el espacio de matrices 3 por 4, usaríamos
``MatrixSpace(QQ,3,4)``. Si se omite el número de columnas, se adopta
por defecto el número de filas, de modo que ``MatrixSpace(QQ,3)``
es un sinónimo de ``MatrixSpace(QQ,3,3)``.) El espacio de matrices
está equipado con su base canónica:

.. link

::

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

Creamos una matriz como un elemento de ``M``.

.. link

::

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

Calculamos su forma escalonada por filas y su núcleo.

.. link

::

    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]

Ilustramos un cálculo de matrices definidas sobre cuerpos finitos:

::

    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)]

Construimos el subespacio sobre `\GF{2}` engendrado por las filas de 
arriba.

.. link

::

    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]

La base de `S` usada por Sage se obtiene de las filas no nulas de la
forma escalonada reducida de la matriz compuesta por los generadores
de `S`.

Álgebra Lineal Dispersa
-----------------------

Sage soporta espacios de matrices sobre DIPs almacenados de forma
dispersa.

::

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

El algoritmo multi-modular de Sage es bueno para matrices cuadradas
(pero no tan bueno para matrices no cuadradas):

::

    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()

