📌  相关文章
📜  门| Sudo GATE 2020 Mock I(2019年12月27日)|问题16(1)

📅  最后修改于: 2023-12-03 15:12:44.878000             🧑  作者: Mango

门| Sudo GATE 2020 Mock I(2019年12月27日)|问题16

在计算机科学中,开关、异或门(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 = 0B = 001代表A = 0B = 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,
    }
}

在此示例中,我们有两个开关门(AB),一个异或门(XOR1)和一个与门(AND1)。

实际门电路

现在,我们考虑如何实际门电路工作。

  1. 从输入到输出进行递归计算

首先,我们将从输出开始,递归地计算电路中的输入,并最终找到每个开关门的输入。我们将此值存储在门字典中,并在后面进行重用。

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门,我们保存它们的两个输入供后续查找和计算。对于异或门,我们还保存了按以下格式计算的值:

  • A ^ B(输入1,输入2和异或)。

为什么我们需要保存该值?因为在某些情况下,我们可能需要它来计算其他门的输出。

  1. 处理门之间的依存关系

为了计算每个门的输出,我们必须解决门之间的依存关系。为此,我们需要查找每个门的所有输入,以了解它们是否已经计算。如果它们已经计算,我们可以重用它们。否则,我们计算它们的值,并将结果存储在该门中供后续查找。

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函数遍历每个门的输入,并查找电路中存储的值。如果该输入未在电路中计算,则对其进行计算并保存结果。为了确保输入的值始终是最新的,我们检查之前计算的结果是否与当前结果相同。如果不相同,我们重新计算该门的输出并更新该门的输入。

  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,
    }
}

通过使用calculate_output函数和connect_wires函数,我们可以计算该电路。

connect_wires(gates)
output = calculate_output(gates, 'AND1')

此后,变量output包含实际输出。在此示例中,该变量将包含二进制值1