Decomposição LU e Pivoteamento Parcial

Published on 2026-11-04·v1.0

Objetivos de Aprendizagem

  • Ler a decomposição LU como eliminação gaussiana com os multiplicadores registrados e dizer quando A=LUA=LU existe.
  • Calcular PA=LUPA=LU à mão com pivoteamento parcial, resolver por substituição direta e retroativa e reutilizar os fatores para um novo lado direito.
  • Contar o número exato de operações de ponto flutuante da fatoração e de cada solução.
  • Mostrar em float64 como a eliminação sem pivoteamento destrói a resposta numa matriz bem condicionada, medindo erro direto, erro reverso e crescimento.
  • Separar o pivô do pivoteamento parcial do pivô do simplex e apontar os casos em que o pivoteamento parcial é desnecessário ou insuficiente.

Contexto e Motivação

gaussian-elimination resolveu um sistema por operações de linha, com troca só quando um pivô necessário era zero. Duas coisas mudam num computador. Primeiro, aquela lição jogou os multiplicadores fora, então um segundo lado direito repetiria todo o trabalho, embora a matriz seja a mesma. Guardar os multiplicadores resolve isso: o trabalho sobre AA é feito uma vez e cada novo bb sai barato. Segundo, em ponto flutuante a regra de troca não basta. Um pivô minúsculo, mas não nulo, passa pela regra e arruína o resultado, mesmo quando o problema em si é bem condicionado, no sentido de conditioning-and-numerical-stability.

Teoria Central

A eliminação registra a própria inversa

O passo kk subtrai mik=aik/akkm_{ik}=a_{ik}/a_{kk} vezes a linha kk de cada linha i>ki>k. Em forma matricial isso é MkAM_kA com Mk=I−mkekTM_k=I-\mathbf m_k\mathbf e_k^T, em que mk\mathbf m_k guarda os multiplicadores abaixo da posição kk. Depois de n−1n-1 passos, Mn−1⋯M1A=UM_{n-1}\cdots M_1A=U é triangular superior. Cada inversa só troca um sinal, Mk−1=I+mkekTM_k^{-1}=I+\mathbf m_k\mathbf e_k^T, e na ordem em que aparecem os produtos não interagem:

A=M1−1⋯Mn−1−1⏟L U,L=I+∑k=1n−1mkekT.A=\underbrace{M_1^{-1}\cdots M_{n-1}^{-1}}_{L}\,U,\qquad L=I+\sum_{k=1}^{n-1}\mathbf m_k\mathbf e_k^T.

Assim, LL é triangular inferior unitária, com os multiplicadores no próprio lugar. A eliminação não precisa de uma segunda matriz: os multiplicadores sobrescrevem os zeros que criam, e esse é o formato que scipy.linalg.lu_factor devolve.

Existência. Uma matriz quadrada AA tem A=LUA=LU com LL triangular inferior unitária e UU triangular superior não singular se e somente se toda submatriz principal líder de AA é não singular. Não basta AA ser não singular: (0110)\begin{pmatrix}0&1\\1&0\end{pmatrix} é não singular e não tem essa fatoração, pois u11=0u_{11}=0 contradiria l21u11=1l_{21}u_{11}=1.

Por que um pivô pequeno causa dano

Os erros de arredondamento de uma fatoração escalam com as entradas de LL e UU, não com as de AA. Um pivô pequeno gera um multiplicador grande, que amplia uma linha, e somar isso a uma linha menor faz o arredondamento apagar a menor. Duas medidas acompanham o efeito: o fator de crescimento ρ=max⁡i,j∣uij∣/max⁡i,j∣aij∣\rho=\max_{i,j}\lvert u_{ij}\rvert/\max_{i,j}\lvert a_{ij}\rvert e o erro reverso ∥b−Ax^∥∞/(∥A∥∞∥x^∥∞+∥b∥∞)\lVert b-A\hat x\rVert_\infty\big/\big(\lVert A\rVert_\infty\lVert\hat x\rVert_\infty+\lVert b\rVert_\infty\big), que diz quanto os dados precisam mudar para x^\hat x ser solução exata. O erro direto relativo é no máximo algo como o número de condição vezes o erro reverso, então um erro direto grande numa matriz bem condicionada acusa o algoritmo.

Pivoteamento parcial e PA = LU

No passo kk, procure na coluna kk, da diagonal para baixo, o maior módulo, troque essa linha para a posição kk (linhas inteiras, multiplicadores guardados inclusive) e só então elimine. Todo multiplicador passa a ter ∣mik∣≤1\lvert m_{ik}\rvert\le1. "Parcial" significa que só uma coluna é examinada; o pivoteamento completo examina todo o bloco restante.

Teorema. Para toda matriz quadrada AA existe uma matriz de permutação PP com PA=LUPA=LU, em que LL é triangular inferior unitária com ∣lij∣≤1\lvert l_{ij}\rvert\le1 e UU é triangular superior. AA é não singular se e somente se todo ukk≠0u_{kk}\neq0.

Para resolver Ax=bAx=b, resolva Ly=PbLy=Pb para a frente e Ux=yUx=y para trás. Vale também det⁡A=(−1)s∏kukk\det A=(-1)^s\prod_k u_{kk} para ss trocas.

Este pivô não é o pivô do simplex

the-simplex-method-tableau-and-pivoting também diz "pivô". A palavra é compartilhada porque nos dois casos se divide por uma entrada para limpar uma coluna; as funções são diferentes.

Pivoteamento parcial em LU Pivô do simplex
Finalidade limitar o erro de arredondamento ir para um vértice adjacente
Entrada escolhida por maior módulo na coluna regra de entrada na linha objetivo, depois o teste da razão
Operação troca linhas, elimina só abaixo Gauss-Jordan: limpa a coluna inteira, linha objetivo inclusive
Efeito na resposta nenhum: o mesmo xx, por um caminho com menos arredondamento muda a solução atual, de propósito
Em aritmética exata necessário só para pivôs nulos é o próprio algoritmo

A regra do simplex olha viabilidade e objetivo, não o tamanho da entrada, então seu pivô pode ser pequeno. A regra do pivoteamento parcial olha só o tamanho.

Contando o trabalho

Conte um flop para cada ++, −-, ×\times, ÷\div. O passo kk faz n−kn-k divisões e (n−k)2(n-k)^2 pares de multiplicação e subtração, então

fatorac¸a˜o: ∑k=1n−1[(n−k)+2(n−k)2]=23n3−12n2−16n.\text{fatoração: }\sum_{k=1}^{n-1}\big[(n-k)+2(n-k)^2\big]=\tfrac23n^3-\tfrac12n^2-\tfrac16n.

A substituição direta com diagonal unitária custa n2−nn^2-n. A retroativa custa n2n^2, com nn divisões incluídas. Cada solução custa, portanto, 2n2−n2n^2-n flops. A busca do pivô acrescenta n(n−1)/2n(n-1)/2 comparações e as trocas, e nada disso é flop. Com kk lados direitos, o total é 23n3−12n2−16n+k(2n2−n)\tfrac23n^3-\tfrac12n^2-\tfrac16n+k(2n^2-n).

Exemplos Resolvidos

Exemplo 1: o mesmo sistema, agora fatorado

Use o sistema de gaussian-elimination:

A=(111231112),b=(6118).A=\begin{pmatrix}1&1&1\\2&3&1\\1&1&2\end{pmatrix},\qquad b=\begin{pmatrix}6\\11\\8\end{pmatrix}.

As operações de linha daquela lição usaram multiplicadores 22 e 11, e a terceira linha não precisou de nada na coluna 2. Guardá-los dá, sem trocas,

L=(100210101),U=(11101−1001).L=\begin{pmatrix}1&0&0\\2&1&0\\1&0&1\end{pmatrix},\quad U=\begin{pmatrix}1&1&1\\0&1&-1\\0&0&1\end{pmatrix}.

Com pivoteamento parcial, a maior entrada da coluna 1 é o 22, então as linhas 1 e 2 trocam de lugar. Os multiplicadores são 12,12\tfrac12,\tfrac12, o que deixa as linhas (0,−12,12)(0,-\tfrac12,\tfrac12) e (0,−12,32)(0,-\tfrac12,\tfrac32). A coluna 2 dá empate, então não há troca, o multiplicador é 11 e

P=(010100001),L=(10012101211),U=(2310−1212001).P=\begin{pmatrix}0&1&0\\1&0&0\\0&0&1\end{pmatrix},\quad L=\begin{pmatrix}1&0&0\\\tfrac12&1&0\\\tfrac12&1&1\end{pmatrix},\quad U=\begin{pmatrix}2&3&1\\0&-\tfrac12&\tfrac12\\0&0&1\end{pmatrix}.

Agora Pb=(11,6,8)Pb=(11,6,8), a substituição direta dá y=(11,12,2)y=(11,\tfrac12,2) e a retroativa dá x=(3,1,2)x=(3,1,2), a resposta daquela lição. Um novo b=(1,0,0)b=(1,0,0) não exige eliminação: Pb=(0,1,0)Pb=(0,1,0), y=(0,1,−1)y=(0,1,-1), x=(5,−3,−1)x=(5,-3,-1), por 15 flops. Além disso, det⁡A=(−1)1⋅2⋅(−12)⋅1=1\det A=(-1)^1\cdot2\cdot(-\tfrac12)\cdot1=1. scipy.linalg.lu devolve os mesmos LL e UU, com seu PP definido por A=PLUA=PLU, então o PP dela é a transposta deste. numpy.linalg.solve dá as mesmas duas soluções.

Exemplo 2: entradas comuns, um pivô feito de ruído

A=(3120,30,10,7121),x=(111),b=Ax=(61,14).A=\begin{pmatrix}3&1&2\\0{,}3&0{,}1&0{,}7\\1&2&1\end{pmatrix},\qquad x=\begin{pmatrix}1\\1\\1\end{pmatrix},\qquad b=Ax=\begin{pmatrix}6\\1{,}1\\4\end{pmatrix}.

Nada aqui é pequeno, e κ2(A)=10,3\kappa_2(A)=10{,}3, então o problema é bem condicionado. Em decimal, o primeiro passo torna a entrada (2,2)(2,2) exatamente 0,1−0,33⋅1=00{,}1-\tfrac{0{,}3}{3}\cdot1=0, e viria uma troca. Mas 0,30{,}3 e 0,10{,}1 não são frações binárias. Em float64, 0.3/3 dá 0.09999999999999999, e a entrada vira 1,39×10−171{,}39\times10^{-17}. Isso é ruído de arredondamento, não é zero, e a regra de troca de gaussian-elimination nunca dispara. O multiplicador seguinte é 1,667/(1,39×10−17)=1,2×10171{,}667/(1{,}39\times10^{-17})=1{,}2\times10^{17}, e u33=0,333−(1,2×1017)(0,5)=−6,0×1016u_{33}=0{,}333-(1{,}2\times10^{17})(0{,}5)=-6{,}0\times10^{16}, em que o 0,3330{,}333 desapareceu. Os resultados:

text
metodo x erro max erro reverso crescimento sem pivoteamento (1.3333, 0, 1.0000) 1.0 0.12 2.0e+16 pivoteamento parcial (1, 1, 1) 2.2e-16 0 1 numpy.linalg.solve (1, 1, 1)

O resíduo da resposta sem pivoteamento é (0,0,1,67)(0,0,1{,}67): as duas primeiras equações valem e a terceira se perdeu. O pivoteamento parcial usa a linha com 1,6671{,}667 como segundo pivô, e a entrada de ruído só produz um multiplicador de 8×10−188\times10^{-18}.

Exemplo 3: o tamanho do dano e uma armadilha de escala

Para A=(ε111)A=\begin{pmatrix}\varepsilon&1\\1&1\end{pmatrix} e b=(1,2)b=(1,2), a solução exata fica perto de (1,1)(1,1) e κ∞(A)≈4\kappa_\infty(A)\approx4 para todos estes ε\varepsilon:

text
epsilon erro sem pivoteamento erro com pivoteamento parcial 1e-08 5.0e-09 2.2e-16 1e-12 2.2e-05 0 1e-20 1.0 (x = (0, 1)) 0

O pivoteamento parcial compara tamanhos crus, então depende da escala. Multiplique a primeira equação do caso ε=10−20\varepsilon=10^{-20} por 102010^{20}: (1102011)\begin{pmatrix}1&10^{20}\\1&1\end{pmatrix} com b=(1020,2)b=(10^{20},2). A solução é a mesma, mas a primeira coluna agora empata, não há troca, e tanto um LU escrito à mão quanto numpy.linalg.solve devolvem (0,1)(0,1). Dividir cada linha pela sua maior entrada antes recupera (1,1)(1,1). O pivoteamento parcial supõe linhas de escala comparável.

O dano também aparece sem nenhuma entrada plantada. Tome rng = numpy.random.default_rng(42), A = rng.uniform(-1, 1, (1000, 1000)), x = rng.uniform(-1, 1, 1000), b = A @ x, para os quais κ2=4269\kappa_2=4269. Com erro direto relativo na norma infinito:

text
erro direto erro reverso crescimento max |L| sem pivoteamento 4.5e-10 7.5e-13 2.9e+04 1.3e+03 parcial 1.3e-12 1.3e-15 4.7e+01 1

Aqui o pivoteamento salva mais de dois dígitos, e a implementação concorda com numpy.linalg.solve em 2,2×10−122{,}2\times10^{-12}.

Exemplo 4: as contagens, executadas

Um laço instrumentado que incrementa um contador a cada operação aritmética, em matrizes aleatórias:

text
n sub mul div fator formula direta retro sol. 2n^2-n 2 1 1 1 3 3 2 4 6 6 3 5 5 3 13 13 6 9 15 15 10 285 285 45 615 615 90 100 190 190 100 328350 328350 4950 661650 661650 9900 10000 19900 19900 200 2646700 2646700 19900 5313300 5313300 39800 40000 79800 79800

Para n=2000n=2000 a fatoração custa 5,33×1095{,}33\times10^9 flops e uma solução 8,0×1068{,}0\times10^6, então uma fatoração equivale a cerca de 667 soluções. Para 100 lados direitos, fatorar uma vez e resolver 100 vezes custa 6,13×1096{,}13\times10^9 flops, contra 5,34×10115{,}34\times10^{11} de 100 eliminações separadas, um fator de 87.

Isso também resolve o "é só inverter AA". Calcular as nn colunas de A−1A^{-1} acrescenta n(2n2−n)n(2n^2-n) à fatoração, cerca de 83n3\tfrac83n^3 nesta contagem (menos se os zeros dos vetores unitários forem aproveitados), e depois A−1bA^{-1}b custa 2n2−n2n^2-n, exatamente o que custam as duas soluções triangulares. Não é mais rápido por lado direito, e na matriz aleatória do Exemplo 3 o erro reverso foi 7,7×10−147{,}7\times10^{-14} contra 2,0×10−152{,}0\times10^{-15} de numpy.linalg.solve, 38 vezes maior; as sementes de 0 a 3 deram fatores de 22 a 52.

Exemplo 5: onde o pivoteamento parcial não basta, e onde nem é preciso

Não basta. O teorema limita os multiplicadores, não o crescimento, e ρ≤2n−1\rho\le2^{n-1} pode ser atingido. Tome uns na diagonal, −1-1 abaixo dela e uns na última coluna. Toda entrada abaixo da diagonal empata com o pivô, então não há troca (empates mantêm a linha atual), a última coluna dobra a cada passo e, para n=60n=60:

text
kappa_2 = 26.8 crescimento = 5.8e+17 (2^59) numpy.linalg.solve: erro direto 0.89, erro reverso 0.045 fatoracao QR: erro direto 3.0e-15

Logo, o pivoteamento parcial não é estável no sentido reverso no pior caso. Ele é o padrão porque matrizes assim são raras na prática: nas 20 matrizes numpy.random.default_rng(s).uniform(-1, 1, (500, 500)), com s=0,…,19s=0,\dots,19, o crescimento ficou entre 25 e 41.

AA singular. A matriz AA de linhas (1,2,3)(1,2,3), (4,5,6)(4,5,6), (7,8,9)(7,8,9) é singular e b=(1,2,4)b=(1,2,4) não tem solução. O arredondamento deixa u33=−1,6×10−16u_{33}=-1{,}6\times10^{-16} em vez de 00, então numpy.linalg.solve não levanta nada e devolve entradas da ordem de 6×10156\times10^{15}. scipy.linalg.solve devolve o mesmo com um aviso de mau condicionamento. numpy.linalg.solve levanta LinAlgError em (1224)\begin{pmatrix}1&2\\2&4\end{pmatrix}, em que o pivô é exatamente 00. Um pivô não nulo não prova que a matriz é não singular.

Nem é preciso. Se cada entrada da diagonal domina estritamente sua coluna, ela continua a maior e o pivoteamento parcial nunca troca. Tome rng = numpy.random.default_rng(42), R = rng.uniform(-1, 1, (500, 500)), x = rng.uniform(-1, 1, 500), b = A @ x. Com AA igual a RR, mas com cada entrada da diagonal trocada por 11 mais a soma dos valores absolutos das outras entradas da sua coluna, houve 0 trocas, crescimento 1,001{,}00 e erro reverso 6×10−166\times10^{-16} sem pivoteamento. A simétrica definida positiva A=RTR+10−3IA=R^TR+10^{-3}I, com κ2=5×105\kappa_2=5\times10^5, deu crescimento 0,950{,}95 e erro reverso 8×10−178\times10^{-17} sem pivoteamento, e essas matrizes usam Cholesky, com cerca de metade dos flops. iterative-methods-jacobi-and-gauss-seidel trata do caso esparso, em que a fatoração tem outro problema.

Equívocos Comuns e Armadilhas

  • "Pivoteamento é para pivôs nulos." Em ponto flutuante o pivô perigoso é o pequeno, e no Exemplo 2 um zero verdadeiro chegou disfarçado de 10−1710^{-17}.
  • "Resposta ruim significa matriz ruim." O Exemplo 2 tem κ2=10,3\kappa_2=10{,}3. O dano veio do algoritmo.
  • "O pivoteamento parcial torna o LU sempre estável." O Exemplo 5 perdeu todos os dígitos em n=60n=60 com κ2=26,8\kappa_2=26{,}8. Ele é confiável na prática, não no pior caso.
  • "O pivô do simplex é o mesmo pivô." Um escolhe um vértice e muda a solução. O outro só reduz o arredondamento e não mexe na solução.
  • "Resíduo pequeno significa solução precisa." Significa erro reverso pequeno. O erro direto é isso vezes até o número de condição.
  • "Inverta AA e multiplique." Custa mais de início, o mesmo por lado direito, e o erro reverso foi 38 vezes maior na matriz do Exemplo 4.
  • "scipy.linalg.lu dá PA=LUPA=LU." Dá A=PLUA=PLU. Confira a convenção antes de usar seu PP.

Resumo

A decomposição LU é eliminação com memória: os multiplicadores formam uma LL triangular inferior unitária, o resultado é UU, e A=LUA=LU com UU não singular existe exatamente quando todas as submatrizes principais líderes são não singulares. O pivoteamento parcial toma a maior entrada de cada coluna, o que dá PA=LUPA=LU para toda matriz quadrada, com ∣lij∣≤1\lvert l_{ij}\rvert\le1. A fatoração custa exatamente 23n3−12n2−16n\tfrac23n^3-\tfrac12n^2-\tfrac16n flops e cada solução 2n2−n2n^2-n, então reutilizar os fatores é o principal ganho prático. Sem pivoteamento, um pivô de ruído de 10−1710^{-17} destruiu um sistema com κ2=10,3\kappa_2=10{,}3, e um sistema aleatório com n=1000n=1000 perdeu mais de dois dígitos. O pivô aqui reduz arredondamento e deixa a solução intacta, ao contrário do pivô do simplex. Ele depende da escala das linhas, pode ser derrotado por um crescimento de 2n−12^{n-1} e é desnecessário em matrizes diagonalmente dominantes e definidas positivas.

Documentation Links