¿Cómo mapear una tabla de verdad con funciones lógicas ternarias?

8

Por favor se amable. Tengo una pregunta espinosa e importante de un campo diferente de ingeniería cuya respuesta puede ser bastante conocida en ingeniería eléctrica. Hice una pregunta similar en StackOverflow


Supongamos que tengo una tabla de verdad de 5 entradas y 1 salida. Utilicé el algoritmo Espresso (p. Ej., Logic Friday) para minimizar la tabla y escribir algunos VHDL eficientes. Todo funciona bien

En lugar de minimizar y asignar la tabla de verdad a las puertas NAND, me gustaría asignar a una función lógica ternaria arbitraria. No me interesa la lógica de valores múltiples, sino las funciones lógicas que tienen 3 variables de entrada. Hay 256 de estas funciones, y NAND de 3 pulgadas es solo una de ellas. No todas estas 256 funciones pueden ser interesantes: algunas se reducen a sus 2 hermanos variables de entrada.

Pregunta : ¿cómo puede asignar una tabla de verdad (por ejemplo, con 7 entradas) a cualquiera de estas funciones de 3 entradas? Una herramienta que haga algo similar sería genial, pero un método sobre cómo simplificar a funciones ternarias arbitrarias sería lo mejor.


Antecedentes: las CPU modernas pueden realizar operaciones lógicas ternarias arbitrarias en registros de 512 bits (por ejemplo, instrucción vpternlog ), pero debido a la complejidad, los compiladores se lo dejan al programador, que no tiene ni idea de cómo optimizar esto.

HJLebbink
fuente
Ni siquiera hay una forma formal de "asignar" a una función binaria arbitraria . Y no todas las funciones binarias comprenden un sistema funcional completo. Lo mismo es cierto para ternary.
Eugene Sh.
1
Creo que esto es NP difícil para las funciones binarias.
user110971
@ user110971 No lo creo. Creo que te confundes con el problema SAT.
Eugene Sh.
1
@EugeneSh. Creo que el problema se reduce a la minimización booleana, que es NP difícil, porque de lo contrario podría resolver el problema SAT. Al menos esto es lo que creo que el OP está pidiendo.
user110971
2
@ user110971 Los algoritmos estándar (que yo sepa) no se reducen a funciones lógicas ternarias arbitrarias (esa es la pregunta). Se simplifican a NAND de 3 pulgadas y AND de 3 pulgadas, pero no todas las demás funciones lógicas de 3 pulgadas que permitirían una reducción mucho más compacta.
HJLebbink

Respuestas:

4

Análisis

Tenga en cuenta que la instrucción codifica todas las funciones ternarias posibles. Por lo tanto, dadas las tres variables booleanas y las operaciones en bits, siempre podemos encontrar el byte de codificación. Por ejemplo, si se le asigna una función

f:Bool×Bool×BoolBool,
entonces se puede encontrar el valor de verdad para cada combinación de valores de entrada y almacenarlo en una tabla. Por ejemplo, si
f(a,b,c)=a&(!b|c),
entonces
f(a,b,c)=TERN101100002(a,b,c),
como se puede ver en una tabla de verdad.
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 solo hay 8 entradas para codificar y solo 2 resultados binarios, esto puede codificarse como un número de 8 bits, en este caso 0b10110000 = 0xB0.

Optimizaciones

Dada una función arbitraria n -ary de valores booleanos, todo lo que tenemos que hacer es convertir las funciones binarias en funciones ternarias. Podemos hacer esto, porque sabemos que podemos calcular cualquier combinación de funciones. Partiendo de un árbol de sintaxis abstracta de nodos unarios y binarios, comenzaríamos representando funciones unarias y binarias de manera similar a la "codificación" anterior.

Entonces, para nuestra f :

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

Usando lógica recursiva, podemos combinar BIN y UNARY en:

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

Que luego se puede optimizar (las reglas de conversión se siguen fácilmente de la lógica booleana):

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

Observación

Esto es muy similar a cómo se calculan las tablas de búsqueda FPGA (LUT). Estoy bastante seguro de que puede encontrar muchos textos y algoritmos para asignar lógica a LUT. Por ejemplo: Flow-map ( http://cadlab.cs.ucla.edu/~cong/papers/tcad94.pdf )

Pål-Kristian Engstad
fuente
1
Usted dice "las reglas de conversión se siguen fácilmente de la lógica booleana", por lo que intenté construir un Sistema de Reescritura de Términos (TRS) para hacer precisamente eso. <br/> El primer BF de 4 arios (del tipo más complejo) BF [100010110, 4] tiene tabla de verdad: <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)) ¿Cuál es la reducción más pequeña que pude encontrar mediante la búsqueda de fuerza bruta. <br/> Mi pregunta: ¿Cómo reescribiría esto (ineficientemente)? ​​No veo cómo son las reglas de conversión de la lógica booleana. de alguna ayuda aquí.
HJLebbink
1
Y después de 6 minutos leyendo esto , ni siquiera puede eliminar el no muy funcional <br/>
HJLebbink
1
No necesitas reescribirlo. Simplemente haga una evaluación de fuerza bruta para cada combinación de valores de verdad.
Pål-Kristian Engstad
@engstad: ah Finalmente entendí tu comentario: te refieres a algo como: BF [i, K] (a_0, ..., a_K) = BF [0xCA, 3] (a_0, BF [upperhalf (i), K-1 ] (a_1, ..., a_K), BF [lowhalf (i), K-1] (a_1, ..., a_K))
HJLebbink
2

Extracto de mi propia respuesta .

  1. Traduce la tabla de verdad a una fórmula lógica; use, por ejemplo, Logic Friday.
  2. Almacene la fórmula lógica en formato de ecuación de Synopsys (.eqn).

Contenido 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. Utilice "ABC: un sistema para la síntesis y verificación secuenciales" del Centro de investigación de verificación y síntesis de Berkeley.

En ABC ejecuto:

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

Es posible que deba ejecutar choice; if -K 3; psvarias veces para obtener mejores resultados.

El BF_Q6.bench resultante contiene las 3 LUT para un 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 )

Esto se puede reescribir (mecánicamente) en el C ++ que estaba buscando.

HJLebbink
fuente
1
Buen uso de ABC!
Pål-Kristian Engstad