Lab 4
Lab 4
Codigo:20201572071
Boolean algebra
Schedule:
• Boolean algebra
• Axiomatic definition
• Logic gates
• Postulates and theorems
• Boolean functions
• Logic diagrams with gates
• Simplification of literals or algebraic manipulation
• Complementing a function
• Canonical and normalized forms
• Minimum and maximum terms
• Karnaugh map
# Run this only in Colab
from google.colab import drive
drive.mount('/content/drive/')
colab_path = '/content/drive/MyDrive/Colab
Notebooks/DIGILAB/notebooks/img/'
my_path = 'img/'
valid_path = colab_path # Use one of them depending on the platform
Boolean functions
Bool or Boolean functions are expressions formed by binary variables, binary operators and the
sign ¿.
• Priority: ()→ N OT → A N D→ O R
Example:
F 1=x y z
In this example, the function F 1 = 1 only if x=1, y=1 and z=0 . In any other case F 1=0.
This function, like any other, can be represented by a truth table:
Example:
F 2=x+ y z
This function is activated in two cases, when x=1 (regardless of y , z ), or when y=0 and z=1
(regardless of x ). The truth table looks like this:
SVG(valid_path + 'bool05.svg')
Example:
F 3=x y z + x y z+ x y
SVG(valid_path + 'bool06.svg')
In truth tables, the number of rows is equal to 2n, where n is the number of variables in the
function.
class LogicError(Exception):
pass
class UnknownStateError(LogicError):
pass
class StateChangeUnableError(LogicError):
pass
class InvalidOperandError(LogicError):
pass
def _operandGenerator(operands):
'''
Generate guaranteed list of operands based on Node.
Attempts to parse other types or raises InvalidOperandError!
'''
for operand in operands:
yield parse(operand)
def isUnknown(node):
try:
node.state()
return False
except UnknownStateError:
return True
class Node(ABC):
def __init__(self):
# Other Nodes that this class contains/depends upon
self.operands = []
@abstractmethod
def state(self) -> bool:
pass
@abstractmethod
def set_state(self, newState: bool):
pass
class Var(Node):
def __init__(self, name: str, state=None):
'''
state=None: Unknown value which prevents equation
from getting solved.
'''
Node.__init__(self)
assert('"' not in name)
assert('"' not in name)
assert(' ' not in name)
assert('\t' not in name)
assert('=' not in name)
self.name = name
if state is None:
self._state = None
else:
self._state = bool(state)
def __repr__(self):
if self._state is None:
return "Var('%s')" % self.name
else:
return "Var('%s', %s)" % (self.name, bool(self.state()))
def __str__(self):
if self._state is None:
return '%s=?' % self.name
else:
return '%s=%s' % (self.name, int(self.state()))
class Const(Node):
def __init__(self, state: bool):
Node.__init__(self)
if state is None:
raise InvalidOperandError('Const has to be termined!')
self._state = bool(state)
def __repr__(self):
return "Const(%s)" % bool(self.state())
def __str__(self):
return str(int(self.state()))
class And(Node):
def __init__(self, *operands):
Node.__init__(self)
if len(operands) == 0:
raise InvalidOperandError('Or needs to have at least one
operand. None given')
self.operands = list(_operandGenerator(operands))
if trueCount == totalCount:
return True
if unknownCount > 0:
raise UnknownStateError("Can't determine state of AND-
Equation: %s" % repr(self))
if newState:
# Goal: All operands have to be true to guarantee being
true
for operand in self.operands:
operand.set_state(True)
else:
# Goal: Any value has to be false to guarantiee beeing
false
for operand in self.operands:
try:
operand.set_state(False)
return
except StateChangeUnableError:
pass
def __repr__(self):
return 'And(%s)' % ', '.join(map(lambda op: repr(op),
self.operands))
def __str__(self):
return '(' + ' ^ '.join(map(lambda op: str(op),
self.operands)) + ')'
class Or(Node):
def __init__(self, *operands):
'''
All that matters is that there is ANY value that is True.
Unknown values don't matter in that case.
'''
Node.__init__(self)
if len(operands) == 0:
raise InvalidOperandError('Or needs to have at least one
operand. None given')
self.operands = list(_operandGenerator(operands))
if newState:
# Goal: Make this equation return true (at least one value
true to guarantee that)
def __repr__(self):
return 'Or(%s)' % ', '.join(map(lambda op: repr(op),
self.operands))
def __str__(self):
return '(' + ' v '.join(map(lambda op: str(op),
self.operands)) + ')'
class Not(Node):
self.operands[0].set_state(not newState)
def __repr__(self):
return 'Not(%s)' % repr(self.operands[0])
def __str__(self):
operand = self.operands[0]
if isinstance(operand, And) or isinstance(operand, Or) or
isinstance(operand, Xor) \
or isinstance(operand, Not) or isinstance(operand, Var) or
isinstance(operand, Const):
return '~%s' % operand
else:
return '~(%s)' % operand
class Xor(Node):
def __init__(self, *operands):
'''
Excately two operators. One has to be true and one false.
No excuses!
'''
Node.__init__(self)
if len(operands) != 2:
raise InvalidOperandError('Xor needs to have EXCATCLY two
operands. Given: %s' % repr(operands))
self.operands = list(_operandGenerator(operands))
if newState:
for operands in [ self.operands, self.operands[::-1] ]:
try:
op1, op2 = operands
op1.set_state(not op2.state())
return
except (StateChangeUnableError, UnknownStateError):
pass
def __repr__(self):
return 'Xor(%s)' % ', '.join(map(lambda op: repr(op),
self.operands))
def __str__(self):
return '(' + ' xor '.join(map(lambda op: str(op),
self.operands)) + ')'
class Implication(Node):
def __init__(self, a, b):
Node.__init__(self)
parsedA, parsedB = parse(a), parse(b)
self.operands = [parsedA, parsedB]
self.base = Or(Not(parsedA), parsedB)
def state(self):
return self.base.state()
def __repr__(self):
return 'Implication(%s, %s)' % (repr(self.operands[0]),
repr(self.operands[1]))
def __str__(self):
return '%s \u2192 %s' % (str(self.operands[0]),
str(self.operands[1]))
class Equivalent(Node):
def __init__(self, a, b):
Node.__init__(self)
parsedA, parsedB = parse(a), parse(b)
self.operands = [parsedA, parsedB]
self.base = And(Implication(parsedA, parsedB),
Implication(parsedB, parsedA))
def state(self):
return self.base.state()
def __repr__(self):
return 'Equivalent(%s, %s)' % (repr(self.operands[0]),
repr(self.operands[1]))
def __str__(self):
return '%s \u2194 %s' % (str(self.operands[0]),
str(self.operands[1]))
def Nor(*operands):
return Not(Or(*operands))
def Nand(*operands):
return Not(And(*operands))
def find_variables(operand):
operands = [ operand ]
while len(operands) > 0:
operand = operands.pop()
if isinstance(operand, Var):
yield operand
else:
for suboperand in operand.operands:
operands.append(suboperand)
def find_variable_state(operand, variable_name):
state = None
count = 0
for variable in find_variables(operand):
if variable.name != variable_name:
continue
count += 1
if variable.state() is not state and state is not None:
raise LogicError('The variable %s does not always has the
same state!' % repr(variable_name))
else:
state = variable.state()
if count == 0:
raise LogicError('Variable %s could not be found.' %
repr(variable_name))
return state
if len(statements) > 1:
variable_name_sets = [ set(map(lambda var: var.name,
find_variables(statement))) for statement in statements ]
for prev_var_set, var_set in zip(variable_name_sets[:1],
variable_name_sets[1:]):
if prev_var_set != var_set:
raise LogicError('Variable names are not matching for
all given statements.')
# Backup states
orig_states = []
for statement in statements:
orig_states.append([ [name,
find_variable_state_or_default(statement, name)] for name in
variable_names ])
# Header
print('', *variable_names, sep=' | ', end='')
for variable_name in variable_names:
for statement in statements:
set_variable_state(statement, variable_name, None)
statement_strings = list(map(lambda s: str(s).replace('=?', ''),
statements))
print('', *statement_strings, sep=' | ')
# Data
cols = len(variable_names)
states = [ [name, 0] for name in variable_names ]
sameResults = True
for row in range(2**len(variable_names)):
for col, name in enumerate(variable_names):
state = (row // (2**(cols - 1 - col))) % 2
states[col][1] = state
print(' | ', state, sep='', end='')
print(' '*(len(name) - 1), end='')
lastState = None
if len(statements) > 1:
print('Same results: %s' % sameResults)
# Restore states
for statement, states in zip(statements, orig_states):
for state_data in states:
set_variable_state(statement, state_data[0],
state_data[1])
return statement
# Definition of literals
x = Var('x')
y = Var('y')
z = Var('z')
print(F1)
print(F2)
print(F3)
print_lookup_table(F1)
| x | y | z | (x ^ y ^ ~z)
| 0 | 0 | 0 | 0
| 0 | 0 | 1 | 0
| 0 | 1 | 0 | 0
| 0 | 1 | 1 | 0
| 1 | 0 | 0 | 0
| 1 | 0 | 1 | 0
| 1 | 1 | 0 | 1
| 1 | 1 | 1 | 0
print_lookup_table(F2)
| x | y | z | (x v (~y ^ z))
| 0 | 0 | 0 | 0
| 0 | 0 | 1 | 1
| 0 | 1 | 0 | 0
| 0 | 1 | 1 | 0
| 1 | 0 | 0 | 1
| 1 | 0 | 1 | 1
| 1 | 1 | 0 | 1
| 1 | 1 | 1 | 1
print_lookup_table(F3)
| 0 | 0 | 1 | 0 | 1 | 1
| 0 | 1 | 0 | 0 | 0 | 0
| 0 | 1 | 1 | 0 | 0 | 1
| 1 | 0 | 0 | 0 | 1 | 1
| 1 | 0 | 1 | 0 | 1 | 1
| 1 | 1 | 0 | 1 | 1 | 0
| 1 | 1 | 1 | 0 | 1 | 0
Example:
F 4=x y + x z=F 3
print_lookup_table(F3, F4)
| 0 | 0 | 1 | 1 | 1
| 0 | 1 | 0 | 0 | 0
| 0 | 1 | 1 | 1 | 1
| 1 | 0 | 0 | 1 | 1
| 1 | 0 | 1 | 1 | 1
| 1 | 1 | 0 | 0 | 0
| 1 | 1 | 1 | 0 | 0
Workshop
Using Boolean postulates and theorems, prove that F 3=F 4.
SVG(valid_path + 'bool08.svg')
Workshop
Make the logic diagrams with F 3 and F 4 gates, and compare their complexity.
There are no concrete methods to simplify a function, it is done by trial and error applying the
basic theorems.
Examples:
x + x y =( x+ x ) ⋅ ( x+ y )
¿ ( 1) ⋅ ( x + y )
¿ x+ y
x ⋅ ( x + y ) =x ⋅ x + x ⋅ y
¿ ( 0) + x ⋅ y
¿x ⋅ y
x y z + x y z + x y =x z ( y+ y )+ x y
¿ x z ( 1 )+ x y
¿ x z+x y
x y+ x z+ y z=x y + x z + y z ( x + x )
¿ x y+x z+ y z x+ y z x
¿ x y ( 1+ z ) + x z ( 1+ y )
¿ x y+x z
Workshop
Demonstrate the following equality.
( x + y ) ( x + z ) ( y + z )=( x+ y )( x + z )
Complementing a function
It corresponds to an extension of Morgan's Law to more variables.
If F=( A+ B+C )
⇒ F= ( A +B+ C ) =A ⋅B ⋅C
Workshop
• For F 1=x y z+ x y z determine F 1.
• For F 2=x ( y z+ y z ) determine F 2.
Theoretical Introduction:
Research and document in a summarized form (maximum one page) the following concepts:
• Review of Previous Concepts: A brief recap of the concepts from the previous lab
(basic Boolean algebra, logic gates, truth tables).
– Algebra booleana basica: es un sistema matemático que utiliza variables binarias
y operadores lógicos. Se basa en la lógica de George Boole y tiene aplicaciones en
electrónica digital, informática y otras áreas.
– Puertas logicas: son los bloques de construcción básicos de los circuitos
digitales. Son dispositivos electrónicos que implementan funciones booleanas.
Cada puerta lógica tiene una o más entradas y una salida. La salida de una puerta
lógica depende de la función booleana que implementa y de los valores de sus
entradas.
– Tablas de verdad: es una representación visual de una función booleana. Muestra
todas las posibles combinaciones de entradas para una función y la salida
correspondiente para cada combinación.
• Complex Boolean Functions: Introduction to more complex Boolean functions, using
multiple variables and operators to build Boolean expressions.
– Las funciones booleanas complejas se construyen utilizando múltiples variables y
una combinación de operadores lógicos (AND, OR, NOT) para crear expresiones
más elaboradas.
• Hierarchy of Boolean Operations: Explanation of the operator precedence:
Parentheses ⟶ NOT ⟶ AND ⟶ OR.
– Puerta AND: La salida es 1 solo si todas las entradas son 1.
– Puerta OR: La salida es 1 si al menos una de las entradas es 1.
– Puerta NOT: La salida es el inverso de la entrada. Si la entrada es 0, la salida es 1 y
viceversa.
A partir de estas puertas básicas, se pueden construir puertas lógicas más
complejas, como NAND, NOR, XOR y XNOR.
– Implicaciones:
a. Simplificación de circuitos: Permiten reducir el número de puertas lógicas
necesarias para implementar una función booleana, lo que resulta en circuitos
más simples, compactos y eficientes.
b. Optimización de rendimiento: Circuitos más simples generalmente tienen un
menor retardo de propagación, lo que significa que las señales se propagan más
rápido a través del circuito, mejorando el rendimiento general del sistema.
c. Reducción de costos:Menos puertas lógicas implican menor costo de producción
y menor consumo de energía.
d. Análisis y verificación de circuitos: Facilitan el análisis y la verificación del
comportamiento de los circuitos, permitiendo comprobar si un circuito
implementa correctamente una función booleana.
e. Diseño de circuitos robustos:Permiten diseñar circuitos más robustos y menos
susceptibles a errores.
– Leyes de quivalencia: Las leyes de equivalencia son un conjunto de reglas
fundamentales en álgebra booleana que establecen la equivalencia lógica
entre diferentes expresiones booleanas. Aquí te presento algunas de las leyes
de equivalencia más importantes:
i. Leyes de identidad:
A AND 1 = A
A OR 0 = A
A AND NOT A = 0
A OR NOT A = 1
A AND A = A
A OR A = A
A OR B = B OR A
v. Leyes de asociatividad:
A OR (B OR C) = (A OR B) OR C
A OR (B AND C) = (A OR B) AND (A OR C)
NOT (NOT A) = A
A AND (A OR B) = A
A OR (A AND B) = A
Hands-on activity:
Prove the equality of each of the following Boolean equations:
X́ Ý + X́ Y + X Y = X́ +Y
# Definition of literals
A = Var('x')
B = Var('y')
C = Var('z')
Y + X́ Z+ X Ý =X +Y + Z
| x | y | z | (y v (~x ^ z) v (x ^ ~y)) | (x v y v z)
| 0 | 0 | 0 | 0 | 0
| 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 | 1 | 1
Same results: True
X́ Ý + Ý Z + X Z + X Y +Y Ź= X́ Ý + X Z +Y Ź
A11=And (~x,~y)|And(~y,z)|And(x,y)|And(x,~y)|And(y,~z)
A12=And(~x,~y)|And(x,z)|And(y,~z)
print_lookup_table(A11,A12)
| x | y | z | ((~x ^ ~y) v (~y ^ z) v (x ^ y) v (x ^ ~y) v (y ^ ~z))
| ((~x ^ ~y) v (x ^ z) v (y ^ ~z))
| 0 | 0 | 0 | 1
| 1
| 0 | 0 | 1 | 1
| 1
| 0 | 1 | 0 | 1
| 1
| 0 | 1 | 1 | 0
| 0
| 1 | 0 | 0 | 1
| 0
| 1 | 0 | 1 | 1
| 1
| 1 | 1 | 0 | 1
| 1
| 1 | 1 | 1 | 1
| 1
Same results: False
Conclusión:
Tras analizar las cuatro ecuaciones booleanas utilizando la tabla de verdad y la simplificación
algebraica, se concluye que todas son equivalentes. En cada caso, las expresiones de ambos
lados producen los mismos resultados para todas las combinaciones de las variables
involucradas. La primera ecuación, 𝑋 ‾ 𝑌 ‾
• 𝑋‾𝑌
• 𝑋𝑌=𝑋‾
• 𝑌X
• 𝑌‾𝑍
• 𝑋𝑍
• 𝑋𝑌
• 𝑌𝑍‾=𝑋‾𝑌‾
• 𝑋𝑍
• 𝑌𝑍‾X
• Y Z+XZ+XY+Y Z = X