Returns a AFW that reads the intersection of the
    languages read by input AFWs.

    Let :math:`A_1 = (Σ, S_1 , s^0_1, ρ_1 , F_1 )` and :math:`A_2
    = (Σ, S_2 , s^0_2, ρ_2 , F_2 )`
    be alternating automata accepting the languages :math:`L(
    A_1)` and :math:`L(A_2)`.
    Then, :math:`B_∩ = (Σ, S_1 ∪ S_2 ∪ {root}, root, ρ_∩ , F_1 ∪
    F_2 )` with
    :math:`ρ_∩ = ρ_1 ∪ ρ_2 ∪ [(root, a): ρ(s^0_1 , a) ∧ ρ(s^0_2 ,
    a)]` accepts :math:`L(A_1) ∩ L(A_2)`.

    :param dict afw_1: first input AFW;
    :param dict afw_2: second input AFW.
    :return: *(dict)* representing a AFW.

def afw_intersection(afw_1: dict, afw_2: dict) -> dict:
    """ Returns a AFW that reads the intersection of the
    languages read by input AFWs.

    Let :math:`A_1 = (Σ, S_1 , s^0_1, ρ_1 , F_1 )` and :math:`A_2
    = (Σ, S_2 , s^0_2, ρ_2 , F_2 )`
    be alternating automata accepting the languages :math:`L(
    A_1)` and :math:`L(A_2)`.
    Then, :math:`B_∩ = (Σ, S_1 ∪ S_2 ∪ {root}, root, ρ_∩ , F_1 ∪
    F_2 )` with
    :math:`ρ_∩ = ρ_1 ∪ ρ_2 ∪ [(root, a): ρ(s^0_1 , a) ∧ ρ(s^0_2 ,
    a)]` accepts :math:`L(A_1) ∩ L(A_2)`.

    :param dict afw_1: first input AFW;
    :param dict afw_2: second input AFW.
    :return: *(dict)* representing a AFW.
    """
    # make sure new root state is unique
    initial_state = 'root'
    i = 0
    while initial_state in afw_1['states'] or initial_state in afw_2['states']:
        initial_state = 'root' + str(i)
        i += 1

    intersection = {
        'alphabet': afw_1['alphabet'].union(afw_2['alphabet']),
        'states':
            afw_1['states'].union(afw_2['states']).union({initial_state}),
        'initial_state': initial_state,
        'accepting_states':
            afw_1['accepting_states'].union(afw_2['accepting_states']),
        'transitions': deepcopy(afw_1['transitions'])
    }

    # add also afw_2 transitions
    intersection['transitions'].update(afw_2['transitions'])

    # if both initial states are accepting, so the new one is
    if afw_1['initial_state'] in afw_1['accepting_states'] \
            and afw_2['initial_state'] in afw_2['accepting_states']:
        intersection['accepting_states'].add(
            intersection['initial_state'])

    # New initial state transitions will be the conjunction of
    # precedent inital states ones
    for action in intersection['alphabet']:
        if (afw_1['initial_state'], action) in afw_1['transitions']:
            intersection['transitions'][initial_state, action] = \
                '(' + \
                afw_1['transitions'][afw_1['initial_state'], action] + \
                ')'
            if (afw_2['initial_state'], action) in afw_2['transitions']:
                intersection['transitions'][initial_state, action] += \
                    ' and (' + \
                    afw_2['transitions'][afw_2['initial_state'], action] + \
                    ')'
            else:
                intersection['transitions'][
                    initial_state, action] += ' and False'
        elif (afw_2['initial_state'], action) in afw_2['transitions']:
            intersection['transitions'][initial_state, action] = \
                'False and (' + \
                afw_2['transitions'][afw_2['initial_state'], action] + \
                ')'

    return intersection