# Funciones y expresiones booleanas

El paquete `sympy` tiene un módulo de [lógica](http://docs.sympy.org/latest/modules/logic.html). Con él podemos hacer algunas simplificaciones


```python
from sympy import *
```

Definimos los símbolos que vamos a utilizar. Supremo e ínfimo se introducen usando el o e y lógicos. Aunque también podemos utilizar `And` y `Or` como funciones. Para la negación usamos `Not` o `~`. Tenemos además `Xor`, `Nand`, `Implies` (que se puede usar de forma prefija con `>>`) y `Equivalent`.


```python
x, y, z = symbols("x,y,z")
```


```python
p = (x | y) & ~ z
```


```python
pprint(p)
```

    ¬z ∧ (x ∨ y)


La formas normales conjuntiva y disyuntivas las podemos calcular como sigue


```python
to_cnf(p)
```




    And(Not(z), Or(x, y))




```python
to_dnf(p)
```




    Or(And(Not(z), x), And(Not(z), y))



También podemos simplificar expresiones


```python
simplify(x | ~x)
```




    True



O dar valores de verdad a las variables


```python
p.xreplace({x:True})
```




    Not(z)



Esto nos permite crear nuestras propias tablas de verdad


```python
p.free_symbols
```




    {x, y, z}




```python
p = Or(x,And(x,y))
```


```python
from IPython.display import HTML,display

```


```python
colores=['LightCoral','Aquamarine']
tabla="<table style='width:25%'><tr><td bgcolor='lightblue'>$"+latex(x)
tabla=tabla+"$ </td><td bgcolor='lightblue'>$"+latex( y)+"$</td><td bgcolor='lightblue'>$"+latex(p)+"$</td></tr>"
for t in cartes({True,False}, repeat=2):
    v =dict(zip((x,y),t))
    tabla=tabla+"<tr> <td bgcolor="+colores[v[x]]+">"+str(v[x])
    tabla=tabla+"</td><td bgcolor="+colores[v[y]]+">"+str(v[y])
    tabla=tabla+"</td><td bgcolor="+colores[v[x]]+">"+str(p.xreplace(v))+"</td></tr>"
tabla=tabla+"</table>"
display(HTML(tabla))
```


<table style='width:25%'><tr><td bgcolor='lightblue'>$x$ </td><td bgcolor='lightblue'>$y$</td><td bgcolor='lightblue'>$x \vee \left(x \wedge y\right)$</td></tr><tr> <td bgcolor=LightCoral>False</td><td bgcolor=LightCoral>False</td><td bgcolor=LightCoral>False</td></tr><tr> <td bgcolor=LightCoral>False</td><td bgcolor=Aquamarine>True</td><td bgcolor=LightCoral>False</td></tr><tr> <td bgcolor=Aquamarine>True</td><td bgcolor=LightCoral>False</td><td bgcolor=Aquamarine>True</td></tr><tr> <td bgcolor=Aquamarine>True</td><td bgcolor=Aquamarine>True</td><td bgcolor=Aquamarine>True</td></tr></table>


Una forma de comprobar que dos expresiones son equivalentes es la siguiente


```python
Equivalent(simplify(p), simplify(x))
```




    True



Veamos ahora cómo podemos encontrar la versión simplificada de una función booleana que venga dada por minterms. Aparentemente `SOPform` hace algunas simplificaciones usando el algoritmo de Quine-McCluskey


```python
p=SOPform([x,y,z],[[0,0,1],[0,1,0],[0,1,1],[1,1,0],[1,0,0],[1,0,1]])
```


```python
p
```




    Or(And(Not(x), y), And(Not(x), z), And(Not(y), z), And(Not(z), x), And(Not(z), y))



Al utilizar `sympy` podemos escribir una forma más amigable de una expresión booleana


```python
pprint(p)
```

    (x ∧ ¬z) ∨ (y ∧ ¬x) ∨ (y ∧ ¬z) ∨ (z ∧ ¬x) ∨ (z ∧ ¬y)


Los comandos `simplify` or `simplify_logic` pueden simplificar aún más


```python
pprint(simplify(p))
```

    (x ∧ ¬y) ∨ (x ∧ ¬z) ∨ (y ∧ ¬x) ∨ (z ∧ ¬y)



```python
pprint(simplify_logic(p))
```

    (x ∧ ¬y) ∨ (x ∧ ¬z) ∨ (y ∧ ¬x) ∨ (z ∧ ¬y)


De hecho, `p` se puede escribir de forma más compacta. Para ello vamos a utilizar el algoritmo espresso, que viene implementado en el paquete `pyeda`


```python
from pyeda.inter import *
```

Este paquete no admite las variables definidas con `symbols`, así que las vamos a declarar con `expvar` para definir variables booleanas


```python
x,y,z = map(exprvar,"xyz")
```


```python
p=SOPform([x,y,z],[[0,0,1],[0,1,0],[0,1,1],[1,1,0],[1,0,0],[1,0,1]])
```

Otro problema es que la salida de `SOPform` no es una expresión de `pyeda`. Lo podemos arreglar pasándola a cadena de caracteres y releyéndola en `pyeda`


```python
p=expr(str(p))
```

Ahora sí que podemos utilizar el simplificador *espresso* implementado en `pyeda`


```python
pm, =espresso_exprs(p)
```


```python
pm
```




    Or(And(x, ~z), And(~x, y), And(~y, z))



Y podemos comprobar que es más corta que la salida que daba `sympy`. Para escribirla de forma más "legible" volvemos a utilizar `pprint` de `sympy`, pero para ello necesitamos pasar nuestra expresión en `pyeda` a `sympy`


```python
pprint(sympify(pm))
```

    (x ∧ ¬z) ∨ (y ∧ ¬x) ∨ (z ∧ ¬y)


Podríamos haber definido directamente `p` utilizando tablas de verdad


```python
p=truthtable([x,y,z], "01111110")
```


```python
pm, = espresso_tts(p)
```


```python
pprint(sympify(pm))
```

    (x ∧ ¬z) ∨ (y ∧ ¬x) ∨ (z ∧ ¬y)


La tabla de verdad de una expresión se obtiene como sigue


```python
expr2truthtable(pm)
```




    z y x
    0 0 0 : 0
    0 0 1 : 1
    0 1 0 : 1
    0 1 1 : 1
    1 0 0 : 1
    1 0 1 : 1
    1 1 0 : 1
    1 1 1 : 0



Veamos un ejemplo análogo pero con más variables, y de paso mostramos como definir vectores de variables 


```python
X = ttvars('x', 4)
f = truthtable(X, "0111111111111110")
```


```python
fm, = espresso_tts(f)
```


```python
fm
```




    Or(And(~x[0], x[1]), And(~x[1], x[2]), And(x[0], ~x[3]), And(~x[2], x[3]))




```python
expr2truthtable(fm)
```




    x[3] x[2] x[1] x[0]
       0    0    0    0 : 0
       0    0    0    1 : 1
       0    0    1    0 : 1
       0    0    1    1 : 1
       0    1    0    0 : 1
       0    1    0    1 : 1
       0    1    1    0 : 1
       0    1    1    1 : 1
       1    0    0    0 : 1
       1    0    0    1 : 1
       1    0    1    0 : 1
       1    0    1    1 : 1
       1    1    0    0 : 1
       1    1    0    1 : 1
       1    1    1    0 : 1
       1    1    1    1 : 0



### Un ejemplo de simplificación

Veamos que el o exclusivo con la definición $x\oplus y=(x\wedge \neg y)\vee (\neg x\wedge y)$ es asociativo


```python
x, y, z = map(exprvar,"xyz")
```


```python
f = lambda x,y : Or(And(x,~ y),And(~x,y))
```


```python
f(x,y)
```




    Or(And(x, ~y), And(~x, y))




```python
expr2truthtable(f(x,y))
```




    y x
    0 0 : 0
    0 1 : 1
    1 0 : 1
    1 1 : 0




```python
f(x,y).equivalent(Xor(x,y))
```




    True



Veamos que efectivamente $x\oplus(y\oplus z)=(x\oplus y)\oplus z$


```python
pprint(simplify_logic(f(x,f(y,z))))
```

    (x ∧ y ∧ z) ∨ (x ∧ ¬y ∧ ¬z) ∨ (y ∧ ¬x ∧ ¬z) ∨ (z ∧ ¬x ∧ ¬y)



```python
pprint(simplify_logic(f(f(x,y),z)))
```

    (x ∧ y ∧ z) ∨ (x ∧ ¬y ∧ ¬z) ∨ (y ∧ ¬x ∧ ¬z) ∨ (z ∧ ¬x ∧ ¬y)



```python
a= f(f(x,y),z)
b= f(x,f(y,z))
```


```python
a.equivalent(b)
```




    True



Podemos hacer una función que pase de minterm a expresions en pyeda


```python
def minterm2expr(l,v):
    n = len(l)
    vv=v.copy()
    for i in range(n):
        if not(l[i]):
            vv[i]=Not(vv[i])
    return And(*vv)
```


```python
x,y,z,t = map(exprvar,"xyzt")
```


```python
minterm2expr([0,1,0,1],[x,y,z,t])
```




    And(~x, y, ~z, t)




```python
def minterms2expr(l,v):
    return Or(*[minterm2expr(a,v) for a in l])
```


```python
hh2=minterms2expr([[0,0,0,0],[0,0,1,0],[0,1,0,0],[0,1,1,0],[0,1,1,1],[1,0,0,0],[1,0,1,0],[1,1,0,0]],[x,y,z,t])
```


```python
hh2
```




    Or(And(x, y, ~z, ~t), And(~x, ~y, z, ~t), And(~x, y, ~z, ~t), And(~x, y, z, ~t), And(~x, y, z, t), And(x, ~y, ~z, ~t), And(x, ~y, z, ~t), And(~x, ~y, ~z, ~t))




```python
pprint(sympify(hh2))
```

    (t ∧ y ∧ z ∧ ¬x) ∨ (x ∧ y ∧ ¬t ∧ ¬z) ∨ (x ∧ z ∧ ¬t ∧ ¬y) ∨ (x ∧ ¬t ∧ ¬y ∧ ¬z) 
    ∨ (y ∧ z ∧ ¬t ∧ ¬x) ∨ (y ∧ ¬t ∧ ¬x ∧ ¬z) ∨ (z ∧ ¬t ∧ ¬x ∧ ¬y) ∨ (¬t ∧ ¬x ∧ ¬y 
    ∧ ¬z)


Y ahora la podemos simplificar


```python
sh2, = espresso_exprs(hh2)
```


```python
sh2
```




    Or(And(~z, ~t), And(~y, ~t), And(~x, y, z))



8ae466315b9480a2a5e34656b610e3ee044fdab9
ipynb
Jupyter Notebook
Funciones Booleanas/Boole.ipynb
lmd-ugr/LMD
677033858074fc31e0a65885ea424f8ae05591b8
MIT
2016-02-24T09:29:47.000Z
2021-03-23T15:29:52.000Z
Funciones Booleanas/Boole.ipynb
pedritomelenas/LMD
cf49271dcb05b1c39339a10a933d30c67b9445f3
MIT
Funciones Booleanas/Boole.ipynb
pedritomelenas/LMD
cf49271dcb05b1c39339a10a933d30c67b9445f3
MIT
2016-05-09T14:46:11.000Z
2016-05-09T14:46:11.000Z
Qwen/Qwen-72B
1. YES
2. YES