Como mapear uma tabela verdade para funções lógicas ternárias?

8

Por favor seja gentil. Tenho uma pergunta espinhosa e importante de um campo diferente da engenharia, cuja resposta pode ser bastante conhecida na engenharia elétrica. Fiz uma pergunta semelhante no StackOverflow


Suponha que eu tenha uma tabela verdade de 5 entradas e 1 saída. Eu usei o algoritmo Espresso (por exemplo, Logic Friday) para minimizar a tabela e escrever alguns VHDL eficientes. Tudo funciona bem.

Em vez de minimizar e mapear a tabela verdade para portas NAND, eu gostaria de mapear para uma função lógica ternária arbitrária. Não estou interessado em lógica com valores múltiplos, mas em funções lógicas que possuem três variáveis ​​de entrada. Existem 256 dessas funções, e o NAND de 3 polegadas é apenas uma delas. Nem todas essas 256 funções podem ser interessantes: algumas se reduzem a seus dois irmãos variáveis ​​de entrada.

Pergunta : como você pode mapear uma tabela verdade (por exemplo, com 7 entradas) para qualquer uma dessas funções de 3 entradas. Uma ferramenta que faça algo semelhante seria ótima, mas um método para simplificar as funções ternárias arbitrárias seria o melhor.


Antecedentes: as CPUs modernas podem executar operações lógicas ternárias arbitrárias em registros de 512 bits (por exemplo, instrução vpternlog ), mas devido à complexidade, os compiladores deixam isso para o programador, que é um pouco ignorante sobre como otimizar isso.

HJLebbink
fonte
Não existe uma maneira formal de "mapear" para uma função binária arbitrária . E nem todas as funções binárias compreendem um sistema funcional completo. O mesmo vale para o ternário.
Eugene Sh.
1
Eu acredito que isso é NP difícil para funções binárias.
user110971
@ user110971 Acho que não. Acho que você confunde com o problema do SAT.
Eugene Sh.
1
@EugeneSh. Acho que o problema se reduz à minimização booleana, o que é difícil para o NP, porque, caso contrário, você poderia resolver o problema do SAT. Pelo menos é o que acho que o OP está perguntando.
user110971
2
@ user110971 Os algoritmos padrão (que eu saiba) não reduzem a funções lógicas arbitrária ternários (que é a questão). Eles simplificam para NANDs de 3 polegadas e ANDs de 3 polegadas, mas não todas as outras funções lógicas de 3 polegadas que permitiriam uma redução muito mais compacta.
precisa saber é o seguinte

Respostas:

4

Análise

Observe que a instrução codifica todas as funções ternárias possíveis. Portanto, dadas as três variáveis ​​booleanas e as operações bit a bit, podemos sempre encontrar o byte de codificação. Por exemplo, se for dada uma função

f:Bool×Bool×BoolBool,
então o valor verdadeiro pode ser encontrado para cada combinação de valores de entrada e armazenado em uma tabela. Por exemplo, se
f(uma,b,c)=uma&(!b|c),
então
f(uma,b,c)=TERN101100002(uma,b,c),
como pode ser visto em uma tabela da verdade.
a b c | f
------+--
0 0 0 | 0
0 0 1 | 0
0 1 0 | 0
0 1 1 | 0
1 0 0 | 1
1 0 1 | 1
1 1 0 | 0
1 1 1 | 1

Como existem apenas 8 entradas para codificação e apenas 2 resultados binários, isso pode ser codificado como um número de 8 bits, neste caso 0b10110000 = 0xB0.

Otimizações

Dado um n arbitrário função arar dos valores booleanos, tudo o que precisamos fazer é converter funções binárias em funções ternárias. Podemos fazer isso, porque sabemos que podemos calcular qualquer combinação de funções. Partindo de uma árvore de sintaxe abstrata de nós unários e binários, começaríamos representando funções unárias e binárias de maneira semelhante à "codificação" acima.

Então, para o nosso f :

f = AND(a, OR(NOT(b), c)) = BIN[1000](a, BIN[1110](UNARY[10](b), c))

Usando lógica recursiva, podemos combinar BIN e UNARY em:

f = AND(a, OR(NOT(b), c)) = BIN[1000](a, BIN[1011](b, c))

Que pode então ser otimizado (regras de conversão seguem facilmente a partir da lógica booleana):

f = AND(a, OR(NOT(b), c)) = TERN[10110000](a, b, c)

Observação

Isso é muito semelhante ao modo como as tabelas de pesquisa FPGA (LUTs) são calculadas. Tenho certeza de que você pode encontrar muitos textos e algoritmos para mapear a lógica para LUTs. Por exemplo: Mapa de fluxo ( http://cadlab.cs.ucla.edu/~cong/papers/tcad94.pdf )

Pål-Kristian Engstad
fonte
1
Você diz que "as regras de conversão seguem facilmente a lógica booleana", portanto tentei criar um TRS (Term Rewriting System) para fazer exatamente isso. <br/> O primeiro BF de 4 anos (do tipo mais complexo) BF [100010110, 4] possui tabela verdade: <br/> 0000 => 1 <br/> 0010 => 1 <br/> 0100 => 1 <br/> 1000 => 1 <br/> A'B'C'D + A'B'CD '+ A'BC'D' + AB'C'D '= BF [0xd1,3] (A, BF [0x16,3] (D, C, B), BF [0x02,3] (C, B, A)) Qual é a menor redução que eu poderia encontrar pela pesquisa de força bruta. <br/> Minha pergunta: Como você reescreveria isso (ineficientemente), não vejo como as regras de conversão da lógica booleana são de qualquer ajuda aqui.
precisa saber é o seguinte
1
E depois de 6 minutos lendo isso, você não pode nem remover o que não é muito funcional. <br/>
HJLebbink
1
Você não precisa reescrevê-lo. Basta fazer uma avaliação de força bruta para cada combinação de valores de verdade.
Pål-Kristian Engstad
@engstad: ah finalmente entendi sua observação: você quer dizer algo como: BF [i, K] (a_0, ..., a_K) = BF [0xCA, 3] (a_0, BF [upperhalf (i), K-1 ] (a_1, ..., a_K), BF [metade inferior (i), K-1] (a_1, ..., a_K))
HJLebbink
2

Trecho da minha própria resposta .

  1. Traduza a tabela verdade em uma fórmula lógica; use, por exemplo, Logic Friday.
  2. Armazene a fórmula lógica no formato da equação da Synopsys (.eqn).

Conteúdo de BF_Q6.eqn:

INORDER = A B C D E F; 
OUTORDER = F0 F1;
F0 = (!A*!B*!C*!D*!E*F) + (!A*!B*!C*!D*E*!F) + (!A*!B*!C*D*!E*!F) + (!A*!B*C*!D*!E*!F) + (!A*B*!C*!D*!E*!F) + (A*!B*!C*!D*!E*!F);
F1 = (!A*!B*!C*!D*E) + (!A*!B*!C*D*!E) + (!A*!B*C*!D*!E) + (!A*B*!C*!D*!E) + (A*!B*!C*!D*!E);
  1. Use "ABC: um sistema para síntese e verificação seqüencial" do Berkeley Verification and Synthesis Research Center.

No ABC eu corro:

abc 01> read_eqn BF_Q6.eqn
abc 02> choice; if -K 3; ps
abc 03> lutpack -N 3 -S 3; ps
abc 04> show
abc 05> write_bench BF_Q6.bench

Pode ser necessário executar choice; if -K 3; psvárias vezes para obter melhores resultados.

O BF_Q6.bench resultante contém os 3-LUTs para um FPGA:

INPUT(A)
INPUT(B)
INPUT(C)
INPUT(D)
INPUT(E)
INPUT(F)
OUTPUT(F0)
OUTPUT(F1)
n11         = LUT 0x01 ( B, C, D )
n12         = LUT 0x1 ( A, E )
n14         = LUT 0x9 ( A, E )
n16         = LUT 0xe9 ( B, C, D )
n18         = LUT 0x2 ( n11, n14 )
F1          = LUT 0xae ( n18, n12, n16 )
n21         = LUT 0xd9 ( F, n11, n14 )
n22         = LUT 0xd9 ( F, n12, n16 )
F0          = LUT 0x95 ( F, n21, n22 )

Isso pode ser reescrito (mecanicamente) no C ++ que eu estava procurando.

HJLebbink
fonte
1
Bom uso do ABC!
Pål-Kristian Engstad