📅  最后修改于: 2023-12-03 15:12:44.878000             🧑  作者: Mango
在计算机科学中,开关、异或门(XOR门)和与门(AND门)是最基本的电路组件。门电路中,开关门是一种特殊的门,它具有两个输入,在这两个输入中的一个或两个输入同时高电平时,输出端将输出高电平。 像开关门这样的电路很容易理解。但是,当存在大量门时,这些门的实际操作变得复杂且难以理解。适当使用领域特定语言(DSL)可以使门电路设计人员更容易理解电路,并且可以更快地修复问题和改进功能。
在此问题中,我们将使用Python中的一种DSL来描述门电路。
我们将使用Python中的字典来表示门电路。每个门(开关,异或和与门)都是字典的一个条目。字典条目的键是门的名称(字符串),值是字典,包含以下项:
gateType
: 门的类型(开关,异或或与)input1
: 第一个输入门的名称(字符串)input2
: 第二个输入门的名称(字符串)。这是应用于第二个输入的开关门的情况,因此如果该门的类型为开关,则input2为None
。output
: 该门的输出管脚的名称(字符串)truthTable
: 门的真值表。只有开关门有真值表。以下是示意图。我们将表示为二进制数的输入输出信号与每个门的真值表进行配对。
A B| Y
0 0| 0
0 1| 1
1 0| 1
1 1| 0
其中,A和B是两个输入开关门,Y是一个开关门的输出
真值表由单独一个字典表示,每个真值由输入的二进制表示作为键(00
代表A = 0
且B = 0
,01
代表A = 0
且B = 1
,依此类推),输出信号的二进制表示作为值。
该门字典的示例:
{
'A': {
'gateType': 'switch',
'input1': None,
'input2': None,
'output': 'A',
'truthTable': {
'0': '0',
'1': '1',
}
},
'B': {
'gateType': 'switch',
'input1': None,
'input2': None,
'output': 'B',
'truthTable': {
'0': '0',
'1': '1',
}
},
'XOR1': {
'gateType': 'xor',
'input1': 'A',
'input2': 'B',
'output': 'XOR1_Out',
'truthTable': {
'00': '0',
'01': '1',
'10': '1',
'11': '0',
}
},
'AND1': {
'gateType': 'and',
'input1': 'XOR1_Out',
'input2': 'B',
'output': 'AND1_Out',
'truthTable': None,
}
}
在此示例中,我们有两个开关门(A
和B
),一个异或门(XOR1
)和一个与门(AND1
)。
现在,我们考虑如何实际门电路工作。
首先,我们将从输出开始,递归地计算电路中的输入,并最终找到每个开关门的输入。我们将此值存储在门字典中,并在后面进行重用。
def calculate_output(gates, gate_name):
"""
从递归方式计算电路的输出。
"""
gate = gates[gate_name]
# 如果该门是一个开关门,则直接返回真值。
if gate['gateType'] == 'switch':
return gate['truthTable']['0']
# 否则,递归地计算每个门的输出。
input1 = calculate_output(gates, gate['input1'])
input2 = None
if gate['gateType'] != 'not':
input2 = calculate_output(gates, gate['input2'])
# 保存输入以备后用
if gate['gateType'] == 'and' or gate['gateType'] == 'or':
gate['inputs'] = [input1, input2]
if gate['gateType'] == 'xor':
a_xor_b = int(input1) ^ int(input2)
gate['inputs'] = [input1, input2, str(a_xor_b)]
# 查找下一个门,在基于之前计算的值计算之后再次尝试从缓存中获取值。
next_gates = get_gates_of_type(gates, 'xor', 'and')
next_gates.extend(get_gates_of_type(gates, 'and'))
for next_gate_name in next_gates:
next_gate = gates[next_gate_name]
if next_gate['input1'] == gate['output'] or \
next_gate['input2'] == gate['output']:
calculate_output(gates, next_gate_name)
if gate['gateType'] == 'and':
if input1 == '1' and input2 == '1':
gate['outputVal'] = '1'
else:
gate['outputVal'] = '0'
if gate['gateType'] == 'or':
if input1 == '1' or input2 == '1':
gate['outputVal'] = '1'
else:
gate['outputVal'] = '0'
if gate['gateType'] == 'not':
if input1 == '1':
gate['outputVal'] = '0'
else:
gate['outputVal'] = '1'
return gate['outputVal']
我们使用calculate_output
函数来计算每个门的输出。我们递归地处理每个门的输入,直到我们遇到在真值表中定义了输出的开关门。对于开关门,我们直接从真值表中查找该输入的值,然后我们返回该值。对于非开关门,我们继续递归计算每个输入的输出(输入1)和(如果有)第二个输入的输出(输入2)。在根据输入计算输出之后,我们将其保存在该门中。这是因为在我们计算下一个门的输出值时,我们可能会重用它们。
在计算时,我们还保存了其他数据。对于AND门和OR门,我们保存它们的两个输入供后续查找和计算。对于异或门,我们还保存了按以下格式计算的值:
为什么我们需要保存该值?因为在某些情况下,我们可能需要它来计算其他门的输出。
为了计算每个门的输出,我们必须解决门之间的依存关系。为此,我们需要查找每个门的所有输入,以了解它们是否已经计算。如果它们已经计算,我们可以重用它们。否则,我们计算它们的值,并将结果存储在该门中供后续查找。
def connect_wires(gates):
"""
处理门之间的依存关系。遍历每个门的输入,并在导线上查找计算结果。
"""
for gate_name in gates:
gate = gates[gate_name]
# 排除开关门
if gate['gateType'] == 'switch':
continue
for input_name in [gate['input1'], gate['input2']]:
if input_name is None:
continue
# 检查该门的输入是否在导线上
input_gate = gates[input_name]
if input_gate['outputVal']:
continue
# 如果尚未计算,请计算输入门的输出,并保存结果。
if input_gate['gateType'] == 'switch':
input_gate['outputVal'] = input_gate['truthTable']['0']
else:
if input_gate['gateType'] == 'and' or input_gate['gateType'] == 'or':
prev_input1 = input_gate['inputs'][0]
prev_input2 = input_gate['inputs'][1]
calculate_output(gates, input_name)
if prev_input1 != input_gate['inputs'][0] or \
prev_input2 != input_gate['inputs'][1]:
connect_wires(gates)
elif input_gate['gateType'] == 'xor':
prev_input1 = input_gate['inputs'][0]
prev_input2 = input_gate['inputs'][1]
prev_output = input_gate['inputs'][2]
calculate_output(gates, input_name)
if prev_input1 != input_gate['inputs'][0] or \
prev_input2 != input_gate['inputs'][1] or \
prev_output != input_gate['inputs'][2]:
connect_wires(gates)
elif input_gate['gateType'] == 'not':
prev_input = input_gate['inputs'][0]
calculate_output(gates, input_name)
if prev_input != input_gate['inputs'][0]:
connect_wires(gates)
connect_wires
函数遍历每个门的输入,并查找电路中存储的值。如果该输入未在电路中计算,则对其进行计算并保存结果。为了确保输入的值始终是最新的,我们检查之前计算的结果是否与当前结果相同。如果不相同,我们重新计算该门的输出并更新该门的输入。
我们回归一个示例。假设我们有以下描述的电路。
{
'A': {
'gateType': 'switch',
'input1': None,
'input2': None,
'output': 'A',
'truthTable': {
'0': '0',
'1': '1',
}
},
'B': {
'gateType': 'switch',
'input1': None,
'input2': None,
'output': 'B',
'truthTable': {
'0': '0',
'1': '1',
}
},
'XOR1': {
'gateType': 'xor',
'input1': 'A',
'input2': 'B',
'output': 'XOR1_Out',
'truthTable': {
'00': '0',
'01': '1',
'10': '1',
'11': '0',
}
},
'AND1': {
'gateType': 'and',
'input1': 'XOR1_Out',
'input2': 'B',
'output': 'AND1_Out',
'truthTable': None,
}
}
通过使用calculate_output
函数和connect_wires
函数,我们可以计算该电路。
connect_wires(gates)
output = calculate_output(gates, 'AND1')
此后,变量output
包含实际输出。在此示例中,该变量将包含二进制值1
。