Estoy tratando de encontrar el espacio nulo (espacio de la solución de Ax=0) de una matriz dada. He encontrado dos ejemplos, pero me parece que no puede obtener ya sea para trabajar. Por otra parte, yo no puede entender lo que están haciendo para llegar allí, así que no se puede depurar. Estoy esperando que alguien podría ser capaz de caminar a través de mí este.

Las páginas de la documentación (numpy.linalg.svd, y numpy.comprimir) son opacos a mí. He aprendido a hacer esto mediante la creación de la matriz de C = [A|0], la búsqueda de la reducción escalonada y la solución para las variables de fila. Me parece que no puede seguir como se está haciendo en estos ejemplos.

Gracias por cualquier ayuda!

Aquí está mi matriz de la muestra, que es el mismo que el wikipedia ejemplo:

A = matrix([
    [2,3,5],
    [-4,2,3]
    ])  

Método (encuentra aquí, y aquí):

import scipy
from scipy import linalg, matrix
def null(A, eps=1e-15):
    u, s, vh = scipy.linalg.svd(A)
    null_mask = (s <= eps)
    null_space = scipy.compress(null_mask, vh, axis=0)
    return scipy.transpose(null_space)

Cuando lo intento, me pongo de nuevo un vacío de la matriz:

Python 2.6.6 (r266:84292, Sep 15 2010, 16:22:56) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import scipy
>>> from scipy import linalg, matrix
>>> def null(A, eps=1e-15):
...    u, s, vh = scipy.linalg.svd(A)
...    null_mask = (s <= eps)
...    null_space = scipy.compress(null_mask, vh, axis=0)
...    return scipy.transpose(null_space)
... 
>>> A = matrix([
...     [2,3,5],
...     [-4,2,3]
...     ])  
>>> 
>>> null(A)
array([], shape=(3, 0), dtype=float64)
>>> 
  • La página de la wikipedia que vinculados a la realidad le da una muy buena explicación de por qué usted debe utilizar un SVD para calcular el espacio nulo (o resolver) de una matriz cuando usted está tratando con valores de punto flotante. en.wikipedia.org/wiki/… El enfoque que usted describe (solución para las variables de fila por fila) se amplifican los errores de redondeo, etc. (Esta es la misma razón por la que debería casi nunca explícitamente calcular la inversa de una matriz…)
InformationsquelleAutor Nona Urbiz | 2011-05-04

6 Comentarios

  1. 5

    Parece estar funcionando bien para mí:

    A = matrix([[2,3,5],[-4,2,3],[0,0,0]])
    A * null(A)
    >>> [[  4.02455846e-16]
    >>>  [  1.94289029e-16]
    >>>  [  0.00000000e+00]]
    • Estoy seguro de que me estoy perdiendo algo, pero Wikipedia sugiere que los valores deben ser [ [-.0625], [-1.625], [1] ]?
    • Además, se devuelve una matriz vacía para mí []. Lo que podría estar equivocado?
    • Urbiz – Es devolver un vacío de la matriz debido a que usted no está poniendo en una fila de ceros, como Bashwork (y wikipedia) hace. También, el espacio nulo valores devueltos ([-0.33, -0.85, 0.52]) se normalizan de modo que la magnitud del vector es de 1. El ejemplo de la wikipedia no está normalizada. Si usted acaba de tomar n = null(A) y echar un vistazo a n / n.max(), obtendrá [-.0625, -1.625, 1].
    • Cómo iba yo a saber agregar mediante programación una fila de ceros? Que la matriz tiene que ser cuadrado?
  2. 17

    Sympy hace de este sencillo.

    >>> from sympy import Matrix
    >>> A = [[2, 3, 5], [-4, 2, 3], [0, 0, 0]]
    >>> A = Matrix(A)
    >>> A * A.nullspace()[0]
    Matrix([
    [0],
    [0],
    [0]])
    >>> A.nullspace()
    [Matrix([
    [-1/16],
    [-13/8],
    [    1]])]
    • Exactamente la solución que estaba buscando!
  3. 9

    Obtener la descomposición SVD de la matriz A. s es un vector de valores propios. Usted está interesado en casi cero autovalores (ver $a*x=\lambda*x$ donde $\abs(\lambda)<\epsilon$), el cual es dado por el vector de valores lógicos null_mask.

    A continuación, un extracto de la lista de vh los vectores propios correspondientes a los casi cero autovalores, que es exactamente lo que está buscando: una manera de abarcar el espacio nulo. Básicamente, usted extracto de las filas y, a continuación, transposición de los resultados de modo que se obtiene una matriz con los vectores propios como columnas.

    • Muchas gracias por tomarse el tiempo para responder y ayudarme. Su respuesta fue muy útil para mí, pero he aceptado Bashworks respuesta, en última instancia, me trajo a la solución. La única razón por la que yo soy capaz de entender la solución, aunque, es su respuesta.
    • No te preocupes, yo pensaba que el problema era algo más.
  4. 3

    Un más rápido, pero menos numéricamente estable método es utilizar un rango que revela descomposición QR, tales como scipy.linalg.qr con pivoting=True:

    import numpy as np
    from scipy.linalg import qr
    
    def qr_null(A, tol=None):
        Q, R, P = qr(A.T, mode='full', pivoting=True)
        tol = np.finfo(R.dtype).eps if tol is None else tol
        rnk = min(A.shape) - np.abs(np.diag(R))[::-1].searchsorted(tol)
        return Q[:, rnk:].conj()

    Por ejemplo:

    A = np.array([[ 2, 3, 5],
                  [-4, 2, 3],
                  [ 0, 0, 0]])
    Z = qr_null(A)
    
    print(A.dot(Z))
    #[[  4.44089210e-16]
    # [  6.66133815e-16]
    # [  0.00000000e+00]]
  5. 2

    Su método es casi correcta. El problema es que la forma de s devuelto por la función scipy.linalg.svd es (K), donde K=min(M,N). Así, en el ejemplo, sólo tiene dos entradas (los valores propios de los dos primeros vectores singulares). La siguiente corrección a su nula función debe permitir que funcione para cualquier tamaño de la matriz.

    import scipy
    import numpy as np
    from scipy import linalg, matrix
    def null(A, eps=1e-12):
    ...    u, s, vh = scipy.linalg.svd(A)
    ...    padding = max(0,np.shape(A)[1]-np.shape(s)[0])
    ...    null_mask = np.concatenate(((s <= eps), np.ones((padding,),dtype=bool)),axis=0)
    ...    null_space = scipy.compress(null_mask, vh, axis=0)
    ...    return scipy.transpose(null_space)
    A = matrix([[2,3,5],[-4,2,3]])
    print A*null(A)
    >>>[[  4.44089210e-16]
    >>> [  6.66133815e-16]]
    A = matrix([[1,0,1,0],[0,1,0,0],[0,0,0,0],[0,0,0,0]])
    print null(A)
    >>>[[ 0.         -0.70710678]
    >>> [ 0.          0.        ]
    >>> [ 0.          0.70710678]
    >>> [ 1.          0.        ]]
    print A*null(A)
    >>>[[ 0.  0.]
    >>> [ 0.  0.]
    >>> [ 0.  0.]
    >>> [ 0.  0.]]
    • He estado usando este código en mi trabajo y me di cuenta de un problema. Una eps el valor de 1e-15 parece ser demasiado pequeño. En particular, considere la matriz A = np.queridos(13,2). Este código se informe de que esta matriz tiene un rango de 0 en el espacio nulo. Esto es debido a la scipy.linalg.svd función de los informes que el segundo singular valor está por encima de 1e-15. No sé mucho acerca de los algoritmos detrás de esta función, sin embargo, me sugieren el uso de eps=1e-12 (y tal vez menor para los muy grandes matrices) a menos que alguien con más conocimiento a meter la cuchara. (En precisión infinita la segunda de singular valor debe ser 0).
  6. 2

    Como la del año pasado (2017), scipy ahora tiene un built-in null_space método en el scipy.linalg módulo (docs).

    La la aplicación de la siguiente manera canónica de la descomposición SVD y es bastante pequeño si usted tiene una versión anterior de scipy y la necesidad de implementar a ti mismo (ver más abajo). Sin embargo, si usted está para arriba-hasta la fecha, está ahí para usted.

    def null_space(A, rcond=None):
        u, s, vh = svd(A, full_matrices=True)
        M, N = u.shape[0], vh.shape[1]
        if rcond is None:
            rcond = numpy.finfo(s.dtype).eps * max(M, N)
        tol = numpy.amax(s) * rcond
        num = numpy.sum(s > tol, dtype=int)
        Q = vh[num:,:].T.conj()
        return Q

Dejar respuesta

Please enter your comment!
Please enter your name here