Notação de Dirac: álgebra linear em hardware¶
O recurso mais singular do C±: vetores e matrizes se operam com a notação bra-ket da física, e cada expressão vira código totalmente desenrolado, sem laços. Um produto interno de 4 elementos gera cerca de dez instruções em linha reta; as dimensões precisam ser constantes conhecidas na compilação, e é exatamente isso que permite o desenrolamento.
As formas suportadas¶
Com vetores a, b, d, matrizes A, B, M, P e escalares c, g, e:
Escrita |
Calcula |
|---|---|
|
produto interno \(\langle w \mid x \rangle\) dentro de expressão |
|
\(a = M b\) (matriz vezes vetor) |
|
\(a = c\,b\) (escalar vezes vetor) |
|
\(a = b + c\,d\) (soma ponderada) |
|
\(A = a\,b^{T}\) (produto externo) |
|
\(A = B - a\,b^{T}\) |
|
\(A = c\,B\) |
|
\(A = c\,I\) (identidade escalada) |
|
zera o vetor |
|
preenche |
|
registrador de deslocamento: desloca |
|
escreve o vetor inteiro na porta, cada elemento vezes |
O # marca a atribuição vetorial. As declarações também aceitam inicialização por Dirac: float Px[4] # |P|x⟩;.
Regras verificadas na compilação: dimensões compatíveis, tipos iguais dos dois lados (int com int, float com float), e nada de comp. O registrador de deslocamento exige o mesmo vetor dos dois lados.
Tutorial: um filtro RLS em 66 linhas¶
O filtro adaptativo RLS (Recursive Least Squares) é o caso de uso perfeito: seu miolo é puro produto de matriz e vetor, e em C com laços ele viraria uma página de índices. Em Dirac, cada linha do algoritmo matemático vira uma linha de código.
Crie um processador proc_rls (32 bits, mantissa 23, expoente 8, uma porta de entrada e uma de saída, pilha de dados 8) e use o programa:
1#PRNAME proc_rls
2#NUBITS 32
3#NBMANT 23
4#NBEXPO 8
5#NDSTAC 8
6#SDEPTH 2
7#NUIOIN 1
8#NUIOOU 1
9
10#define N 4 // ordem do filtro
11
12void main()
13{
14 float x[N]; // entradas recentes
15 float w[N]; // coeficientes do filtro
16 float P[N][N]; // matriz de covariancia inversa
17 float Px[N];
18 float K[N];
19 float d, y, e, g;
20
21 P # 1000.0|I|; // P = 1000 * identidade
22 w # |0⟩; // coeficientes zerados
23
24 while (1)
25 {
26 x # fin(0) -> |x⟩; // desloca x e insere a amostra nova
27 d = fin(0); // sinal desejado
28
29 y = ⟨w|x⟩; // saida do filtro
30 e = d - y; // erro
31
32 Px # |P|x⟩; // P x
33 g = 1.0 / (1.0 + ⟨x|Px⟩);
34 K # g|Px⟩; // ganho de Kalman
35
36 w # |w⟩ + e|K⟩; // atualiza os coeficientes
37 P # |P| - |K⟩⟨Px|; // atualiza a covariancia
38 P # 1.0101|P|; // fator de esquecimento
39
40 fout(0, y);
41 }
42}
Leia o miolo do while ao lado das equações do RLS em qualquer livro de filtragem adaptativa: é uma transcrição. Esse é o argumento do recurso.
Figura 18 O editor entende os brackets: realce e espaçamento próprios para a notação.¶
Para digitar ⟨ e ⟩, use os caracteres U+27E8 e U+27E9 (o editor os aceita normalmente; vale montar atalhos de teclado do sistema ou copiar do próprio código de exemplo).
Quando usar¶
Dirac compensa quando o algoritmo é álgebra linear de dimensão pequena e fixa: filtros adaptativos, projeções, transformações de coordenadas, redes pequenas. Para dimensões grandes, o desenrolamento explode o número de instruções; o compilador avisa o tamanho gerado, e o relatório do TASM mostra o total. A alternativa nesses casos é escrever os laços em C± comum.