Algoritmo de balanceamento de matrizes


9

Eu tenho escrito uma caixa de ferramentas do sistema de controle a partir do zero e puramente em Python3 (plug descarado:) harold. Nas minhas pesquisas anteriores, sempre tenho reclamações sobre o solucionador de Riccati care.mpor motivos técnicos / irrelevantes.

Por isso, tenho escrito meu próprio conjunto de rotinas. Uma coisa que não consigo encontrar é uma maneira de obter um algoritmo de balanceamento de alto desempenho, pelo menos tão bom quanto balance.m. Antes de mencionar, a xGEBALfamília é exposta no Scipy e você pode basicamente ligar do Scipy da seguinte maneira, suponha que você tenha uma matriz 2D do 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 )

Agora, se eu usar a seguinte matriz de teste

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

eu recebo

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

No entanto, se eu passar isso para balance.m, recebo

>> 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 você verificar os padrões de permutação, eles são os mesmos, porém a escala está desativada. gebaldá escaladas unidade enquanto Matlab dá as seguintes potências de 2: [-5,0,8,0,2].

Então, aparentemente, eles não estão usando a mesma maquinaria. Eu tentei várias opções, como Lemonnier, Van Dooren, escala de dois lados, Parlett-Reinsch original e também alguns outros métodos menos conhecidos na literatura, como a versão densa SPBALANCE.

Um ponto que talvez eu deva enfatizar é que estou ciente do trabalho de Benner; em particular o balanceamento simplético das matrizes hamiltonianas especificamente para esse fim. No entanto, observe que esse tipo de tratamento é feito dentro gcare.m(solucionador de Riccati generalizado) e o equilíbrio é feito diretamente via balance.m. Por isso, eu apreciaria se alguém pudesse me indicar a implementação real.


Divulgação: Eu realmente não estou tentando fazer engenharia reversa do código do mathworks: eu realmente quero me afastar dele devido a várias razões, incluindo a motivação desta pergunta, ou seja, eu não sei o que está fazendo, o que me custou muito de tempo no dia. Minha intenção é obter um algoritmo de balanceamento satisfatório que me permita passar exemplos CAREX para que eu possa implementar métodos de iteração de Newton sobre o solucionador regular.

Respostas:


7

Demorei um pouco para descobrir isso e, como sempre, fica óbvio depois que você encontra o culpado.

Depois de verificar os casos problemáticos relatados em David S. Watkins. Um caso em que o balanceamento é prejudicial. Electron. Trans. Numer. Anal, 23: 1–4, 2006 e também a discussão aqui (ambos citados em arXiv: 1401.5766v1 ), verifica-se que o matlab usa o balanceamento separando os elementos diagonais primeiro.

Meu pensamento inicial foi, de acordo com a documentação limitada clássica sobre as funções do LAPACK, a GEBAL executou isso automaticamente. No entanto, acho que o que os autores querem dizer com ignorar os elementos diagonais não os está removendo das somas de linha / coluna.

De fato, se eu remover manualmente a diagonal da matriz, os dois resultados coincidirão, ou seja,

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á o mesmo resultado que balance.m(sem as entradas diagonais, é claro).

Se qualquer usuário experiente em Fortran puder confirmar isso, verifique dgebal.f , eu ficaria agradecido.

EDIT: O resultado acima não implica que esta seja a única diferença. Também construí matrizes diferentes em que GEBAL e balance.m produzem resultados diferentes mesmo depois que as diagonais são separadas.

Estou curioso para saber qual pode ser a diferença, mas parece que não há como saber, pois é um código interno do matlab e, portanto, fechado.

EDIT2 : Acontece que o matlab estava usando uma versão mais antiga do LAPACK (provavelmente anterior à 3.5.0) e até 2016b eles parecem ter sido atualizados para a versão mais recente. Agora, os resultados concordam, tanto quanto eu posso testar. Então eu acho que isso resolve o problema. Eu deveria ter testado com versões mais antigas do LAPACK.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.