2013-02-04 9 views
5

Sto trovando che scipy.linalg.eig a volte dà risultati incoerenti. Ma non ogni volta.risultati erratici per eigendecompositions numpy/scipy

>>> import numpy as np 
>>> import scipy.linalg as lin 
>>> modmat=np.random.random((150,150)) 
>>> modmat=modmat+modmat.T # the data i am interested in is described by real symmetric matrices 
>>> d,v=lin.eig(modmat) 
>>> dx=d.copy() 
>>> vx=v.copy() 
>>> d,v=lin.eig(modmat) 
>>> np.all(d==dx) 
False 
>>> np.all(v==vx) 
False 
>>> e,w=lin.eigh(modmat) 
>>> ex=e.copy() 
>>> wx=w.copy() 
>>> e,w=lin.eigh(modmat) 
>>> np.all(e==ex) 
True 
>>> e,w=lin.eigh(modmat) 
>>> np.all(e==ex) 
False 

Mentre io non sono il più grande mago di algebra lineare, capisco che l'eigendecomposition è intrinsecamente soggetto a errori di arrotondamento strani, ma non capisco il motivo per ripetere il calcolo si tradurrebbe in un valore diverso. Ma i miei risultati e riproducibilità sono variabili.

Qual è esattamente la natura del problema - beh, a volte i risultati sono accettabilmente diversi e, a volte, non lo sono. Ecco alcuni esempi:

>>> d[1] 
(9.8986888573772465+0j) 
>>> dx[1] 
(9.8986888573772092+0j) 

La differenza sopra di ~ 3e-13 non sembra un grande affare enorme. Invece, il vero problema (almeno per il mio progetto attuale) è che alcuni degli autovalori non sembrano concordare sul segno corretto.

>>> np.all(np.sign(d)==np.sign(dx)) 
False 
>>> np.nonzero(np.sign(d)!=np.sign(dx)) 
(array([ 38, 39, 40, 41, 42, 45, 46, 47, 79, 80, 81, 82, 83, 
    84, 109, 112]),) 
>>> d[38] 
(-6.4011617320002525+0j) 
>>> dx[38] 
(6.1888785138080209+0j) 

Codice simile a MATLAB non sembra presentare questo problema.

+0

(+1) Interessante ... – NPE

+0

Ho cercato di riprodurre questo utilizzando NumPy 1.6.1/SciPy 0.10.1, ma non ci riuscì. – NPE

+0

Sto usando numpy 1.6.1 e scipy 0.10.0. Inoltre, quando non ho usato copy() non ero in grado di produrre questo errore (ma esiste nella mia applicazione più grande dove sta succedendo qualcosa di simile a copy()). Il che non significa molto, perché è incredibilmente incoerente. – aestrivex

risposta

5

Le scomposizioni autovalori soddisfano AV = V Lambda, che è tutto ciò che è garantito --- per esempio l'ordine degli autovalori non lo è.

risposta alla seconda parte della tua domanda:

compilatori moderni/librerie di algebra lineare producono/contengono codice che fa cose diverse a seconda che i dati vengono allineati in memoria (per esempio) i limiti di 16 byte. Ciò influenza l'errore di arrotondamento nei calcoli, poiché le operazioni in virgola mobile vengono eseguite in un ordine diverso. Piccole variazioni nell'errore di arrotondamento possono quindi influire su cose come l'ordinamento degli autovalori se l'algoritmo (qui, LAPACK/xGEEV) non garantisce la stabilità numerica a questo riguardo.

(Se il codice è sensibile a cose come questa, che non è corretto in esecuzione ad esempio su una piattaforma diversa o una versione libreria diversa porterebbe a un problema simile!).

I risultati di solito sono quasi-deterministico - - Ad esempio, si ottiene uno dei 2 possibili risultati, a seconda che l'array sia allineato in memoria o meno. Se sei curioso di allineare, controlla A.__array_interface__['data'][0] % 16.

Vedi http://www.nccs.nasa.gov/images/FloatingPoint_consistency.pdf per più

+0

Sarebbe estremamente utile includere una soluzione al problema qui oltre alla spiegazione. Non so come/dove usare 'A .__ array_interface __ ['data'] [0]% 16', e in fondo, dato che questo è il mio problema, come faccio a cambiare il mio codice in modo che non sia sensibile in questo modo? –

2

Penso che il tuo problema è che ti aspetti che gli autovalori vengano restituiti in un ordine particolare, e non sempre escono allo stesso modo. Ordinali, e sarai sulla buona strada. Se corro il codice per generare d e dx con eig ottengo il seguente:

>>> np.max(d - dx) 
(19.275224236664116+0j) 

Ma ...

>>> d_i = np.argsort(d) 
>>> dx_i = np.argsort(dx) 
>>> np.max(d[d_i] - dx[dx_i]) 
(1.1368683772161603e-13+0j) 
+0

Ah.Non è proprio la risposta giusta, ma è abbastanza vicina da indurmi nella giusta direzione. Quello che stava succedendo nel mio programma è che da qualche parte nel mio codice stavo indicizzando gli autovettori in luoghi in cui non lo erano. Mi ha aiutato a sistemare il mio bug (quindi grazie) ma non spiega la domanda che ho posto, ed è per questo che questo calcolo fornisce risposte diverse - o un diverso ordine - quando viene eseguito più volte. Cioè, okay, non è garantito che gli autovalori siano in un ordine particolare, ma se gli dai la stessa matrice di input perché cambierebbero? – aestrivex

Problemi correlati