Algoritmo di bilanciamento della matrice


9

Ho scritto una toolbox del sistema di controllo da zero e puramente in Python3 (plug spudorato:) harold. Dalla mia ricerca passata, ho sempre lamentato il solutore Riccati care.mper ragioni tecniche / irrilevanti.

Quindi, ho scritto il mio set di routine. Una cosa che non riesco a trovare è quella di ottenere un algoritmo di bilanciamento ad alte prestazioni, almeno buono come balance.m. Prima di menzionarlo, la xGEBALfamiglia è esposta in Scipy e puoi sostanzialmente chiamare da Scipy come segue, supponiamo di avere un array 2D di tipo float A:

import scipy as sp
gebal = sp.linalg.get_lapack_funcs(('gebal'),(A,)) # this picks up DGEBAL
Ab, lo, hi, scaling , info = gebal(A, scale=1 , permute=1 , overwrite_a=0 )

Ora se uso la seguente matrice di test

array([[ 6.      ,  0.      ,  0.      ,  0.      ,  0.000002],
       [ 0.      ,  8.      ,  0.      ,  0.      ,  0.      ],
       [ 2.      ,  2.      ,  6.      ,  0.      ,  0.      ],
       [ 2.      ,  2.      ,  0.      ,  8.      ,  0.      ],
       [ 0.      ,  0.      ,  0.000002,  0.      ,  2.      ]])

ottengo

array([[ 8.      ,  0.      ,  0.      ,  2.      ,  2.      ],
       [ 0.      ,  2.      ,  0.000002,  0.      ,  0.      ],
       [ 0.      ,  0.      ,  6.      ,  2.      ,  2.      ],
       [ 0.      ,  0.000002,  0.      ,  6.      ,  0.      ],
       [ 0.      ,  0.      ,  0.      ,  0.      ,  8.      ]])

Tuttavia, se passo questo balance.m, ottengo

>> balance(A)

ans =

    8.0000         0         0    0.0625    2.0000
         0    2.0000    0.0001         0         0
         0         0    6.0000    0.0002    0.0078
         0    0.0003         0    6.0000         0
         0         0         0         0    8.0000

Se si controllano i modelli di permutazione, sono uguali ma il ridimensionamento è disattivato. gebaldà scalate unità, mentre MATLAB offre le seguenti potenze di 2: [-5,0,8,0,2].

Quindi apparentemente, questi non usano gli stessi macchinari. Ho provato varie opzioni come Lemonnier, Van Dooren ridimensionamento su due lati, l'originale Parlett-Reinsch e anche alcuni altri metodi meno noti in letteratura come la versione densa di SPBALANCE.

Un punto che forse potrei sottolineare è che sono a conoscenza del lavoro di Benner; in particolare il Symplectic Balancing delle matrici hamiltoniane appositamente per questo scopo. Tuttavia, si noti che questo tipo di trattamento viene eseguito all'interno gcare.m(solutore Riccati generalizzato) e il bilanciamento viene eseguito direttamente tramite balance.m. Pertanto, apprezzerei se qualcuno potesse indicarmi l'implementazione effettiva.


Divulgazione: non sto davvero cercando di decodificare il codice matematico: in realtà voglio scappare da esso per vari motivi tra cui la motivazione di questa domanda, vale a dire, non so cosa sta facendo che mi è costato molto indietro nel tempo. La mia intenzione è quella di ottenere un algoritmo di bilanciamento soddisfacente che mi permetta di passare esempi CAREX in modo tale da poter implementare i metodi di iterazione di Newton in cima al normale solutore.

Risposte:


7

Mi ci è voluto un po 'per capirlo e come al solito diventa ovvio dopo aver trovato il colpevole.

Dopo aver verificato i casi problematici riportati in David S. Watkins. Un caso in cui il bilanciamento è dannoso. Electron. Trans. Numer. Anal, 23: 1–4, 2006 e anche la discussione qui (entrambi citati in arXiv: 1401.5766v1 ), si scopre che matlab usa il bilanciamento separando prima gli elementi diagonali.

Il mio pensiero iniziale era, secondo la classica documentazione limitata sulle funzioni LAPACK, GEBAL lo ha eseguito automaticamente. Tuttavia, immagino che cosa intendano gli autori ignorando gli elementi diagonali non li rimuove dalle somme di riga / colonna.

In effetti, se rimuovo manualmente la diagonale dall'array, entrambi i risultati coincidono, cioè

import scipy as sp
gebal = sp.linalg.get_lapack_funcs(('gebal'),(A,)) # this picks up DGEBAL
Ab, lo, hi, scaling , info = gebal(A - np.diag(np.diag(A)), scale=1 , permute=1 , overwrite_a=0 )  

dà lo stesso risultato di balance.m(senza le voci diagonali ovviamente).

Se qualsiasi utente esperto di Fortran può confermarlo controllando dgebal.f , sarei grato.

EDIT: il risultato sopra non implica che questa sia l'unica differenza. Ho anche costruito matrici diverse in cui GEBAL e balance.m producono risultati diversi anche dopo la separazione delle diagonali.

Sono abbastanza curioso di sapere quale potrebbe essere la differenza, ma sembra che non ci sia modo di sapere dal momento che è un codice incorporato matlab e quindi chiuso.

EDIT2 : si scopre che matlab utilizzava una versione precedente di LAPACK (probabilmente precedente alla 3.5.0) e nel 2016b sembrano essere aggiornati alla versione più recente. Ora i risultati concordano per quanto posso testare. Quindi penso che risolva il problema. Avrei dovuto testarlo con le versioni precedenti di LAPACK.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.