def intersection(aut1, aut2):

    aut1 = completer(aut1)
    aut2 = completer(aut2)

    alpha = list(aut1.get_alphabet() - aut1.get_epsilons())

    if alpha != list(aut2.get_alphabet() - aut2.get_epsilons()):
        return automaton()

    #Tous les états
    etats1 = list(aut1.get_states())
    etats2 = list(aut2.get_states())
    etats = produit_cartesien(etats1, etats2)

    # les etats initiaux
    ini1 = list(aut1.get_initial_states())
    ini2 = list(aut2.get_initial_states())
    ini = produit_cartesien(ini1, ini2)

    #lLes etats finaux
    fin1 = list(aut1.get_final_states())
    fin2 = list(aut2.get_final_states())
    fin = produit_cartesien(fin1, fin2)

    trans = nouvelles_transitions_IU(aut1, aut2, etats1, etats2, alpha)

    a = automaton(alphabet=alpha,
                  states=etats,
                  initials=ini,
                  finals=fin,
                  transitions=trans)
    a.renumber_the_states()
    return a
def intersection(aut1,aut2) :

    aut1 = completer(aut1)
    aut2 = completer(aut2)
    
    alpha = list(aut1.get_alphabet() - aut1.get_epsilons() )

    if alpha != list( aut2.get_alphabet() - aut2.get_epsilons() ) :
        return automaton()

    #Tous les états
    etats1 = list( aut1.get_states() )
    etats2 = list( aut2.get_states() )
    etats = produit_cartesien(etats1,etats2)

    # les etats initiaux
    ini1 = list( aut1.get_initial_states() )
    ini2 = list( aut2.get_initial_states() )
    ini = produit_cartesien(ini1,ini2)

    #lLes etats finaux
    fin1 = list( aut1.get_final_states() )
    fin2 = list( aut2.get_final_states() )
    fin = produit_cartesien(fin1,fin2)

    trans = nouvelles_transitions_IU(aut1, aut2,etats1,etats2,alpha)

    a = automaton(alphabet = alpha,
             states = etats,
             initials = ini,
             finals = fin,
             transitions = trans )
    a.renumber_the_states()
    return a
def determiniser(Aut):
    """
    This function returns the equivalent deterministic automaton
    of the one given.
    """
    if is_deterministic(Aut):
        return Aut
    A = suppress_epsilon_transitions(Aut)
    initials = A.get_initial_states()
    finals = A.get_final_states()
    alphabet = A.get_alphabet()
    B = automaton()
    start = pretty_set(initials)
    B.add_initial_state(start)
    state_to_compute = [start]
    state_computed = []
    while state_to_compute:
        state = state_to_compute[0]
        successor = {x: set() for x in alphabet}
        for substate in state:
            for a in alphabet:
                successor[a] = successor[a].union(A.delta(a, [substate]))
        for key in successor:
            successor_set = pretty_set(successor[key])
            if successor_set not in state_computed and successor_set not in state_to_compute:
                state_to_compute.append(successor_set)
            B.add_transition((state, key, successor_set))
        state_to_compute.remove(state)
        state_computed.append(state)
    for state in state_computed:
        for substate in state:
            if substate in finals:
                B.add_final_state(state)
    return B
def determiniser(aut):

    ini = aut.get_initial_states(
    )  # nouvelle etat defini par l'ensemble des etats initiaux
    states = [ini]  #liste des nouveaux états
    trans = []

    alpha = aut.get_alphabet() - aut.get_epsilons()

    l = [ini]  # on enfile cette etat, dans la file des etats a traiter
    while (len(l) != 0):  # tant qu'on a des etats a traiter
        for i in alpha:  # pour chaque lettre
            tmp = aut.delta(i, l[0])  #on defini l'etat qu'il peut rejoindre
            if len(tmp) != 0:  #s'il y en a
                trans += [(l[0], i, tmp)]  #on crée la transitions
                if not tmp in states:  #et s'il n'a jamais été vu, on le rajoute
                    states += [tmp]
                    l += [tmp]
        l.pop(0)  #on defile l'etat traiter

    oldFinals = aut.get_final_states()
    fin = []
    for i in states:
        for j in i:
            if j in oldFinals:  #pour chaque nouveaux sommet, si un des sommets qui le définie est final, il devient final
                fin += [i]
                break

    a = automaton(alphabet=alpha,
                  states=states,
                  initials=[ini],
                  finals=fin,
                  transitions=trans)
    a.renumber_the_states()
    return a
def determiniser( aut ) :

    ini = aut.get_initial_states() # nouvelle etat defini par l'ensemble des etats initiaux
    states = [ini] #liste des nouveaux états
    trans = []
        
    alpha = aut.get_alphabet() - aut.get_epsilons()

    l = [ini]  # on enfile cette etat, dans la file des etats a traiter
    while( len(l) != 0 ) : # tant qu'on a des etats a traiter
        for i in alpha : # pour chaque lettre 
            tmp = aut.delta(i,l[0]) #on defini l'etat qu'il peut rejoindre
            if len(tmp) != 0 : #s'il y en a
                trans += [ ( l[0] , i , tmp ) ] #on crée la transitions
                if not tmp in states : #et s'il n'a jamais été vu, on le rajoute
                    states += [tmp]
                    l += [tmp]
        l.pop(0) #on defile l'etat traiter

    oldFinals = aut.get_final_states()
    fin = []
    for i in states :
        for j in i :
            if j in oldFinals : #pour chaque nouveaux sommet, si un des sommets qui le définie est final, il devient final
                fin += [i]
                break

    a = automaton(
        alphabet = alpha,
        states = states,
        initials = [ini],
        finals = fin,
        transitions = trans)
    a.renumber_the_states()
    return a
def delete_state(Aut, state):

    alpha = list(Aut.get_alphabet())
    s = list(Aut.get_states())
    if state not in s:
        return Aut
    else:
        s.remove(state)

    init = list(Aut.get_initial_states())
    if state in init:
        init.remove(state)

    fin = list(Aut.get_final_states())
    if state in fin:
        fin.remove(state)

    trans = list(Aut.get_transitions())
    i = 0
    while i != len(trans):
        if trans[i][0] == state or trans[i][2] == state:
            trans.pop(i)
        else:
            i += 1

    return automaton(epsilons=Aut.get_epsilons(),
                     alphabet=alpha,
                     states=s,
                     initials=init,
                     finals=fin,
                     transitions=trans)
def delete_state( Aut, state ) :

    alpha = list(Aut.get_alphabet())
    s = list(Aut.get_states())
    if state not in s :
        return Aut
    else :
        s.remove(state)
    
    init = list(Aut.get_initial_states())
    if state in init :
        init.remove(state)

    fin = list(Aut.get_final_states())
    if state in fin :
        fin.remove(state)

    trans = list(Aut.get_transitions())
    i = 0
    while i != len(trans) :
        if trans[i][0] == state or trans[i][2] == state :
            trans.pop(i)
        else :
            i+=1

    return automaton(
        epsilons = Aut.get_epsilons(),
        alphabet = alpha,
        states = s,
        initials = init,
        finals = fin,
        transitions = trans)
def minimiser( Aut ) :

    Aut2 = completer( Aut )
    Aut2 = determiniser( Aut2 )

    etats = list(Aut2.get_states())
    alpha = list(Aut2.get_alphabet())

    # Initialisation. On sépare les états finaux du reste.
    lm1 = list()
    for i in range(len(etats)) :
        if Aut2.state_is_final(etats[i]) :
            lm1.append(tuple((1,)))
        else :
            lm1.append(tuple((0,)))
        for j in range(len(alpha)) :
            d = list(Aut2.delta(alpha[j], [ etats[i] ]))
            if Aut2.state_is_final(d[0]) :
                lm1[i] = lm1[i] + tuple((1,))
            else :
                lm1[i] = lm1[i] + tuple((0,))
    
    # On applique l'algorithme de Moore tant que la liste 
    # n'est pas stable.
    lm2 = moore(Aut2, etats, alpha, lm1)
    while lm1 != lm2 :
        lm1 = lm2
        lm2 = moore(Aut2, etats, alpha, lm1)

    # On récupère l'état initial.
    init = lm2[etats.index(list(Aut2.get_initial_states())[0])][0]

    # On recherche les nouveaux états finaux.
    lm1 = list()
    ets = list()
    for i in range(len(etats)) :
        if Aut2.state_is_final(etats[i]) :
            lm1.append(lm2[i][0])
        ets.append(lm2[i][0])
    # On enlève les doublons
    # lm1 la liste des états finaux.
    # lm2 la totalité des états et des transitions.
    # ets la liste de tous les états.
    lm1 = list(set(lm1))
    lm2 = list(set(lm2))
    ets = list(set(ets))

    amin = automaton(
        alphabet = alpha,
        states = ets,
        initials = [init],
        finals = lm1)

    # On récupère les nouvelles transitions.
    for i in range(len(lm2)) :
        for j in range(len(alpha)) :
            amin.add_transition( (lm2[i][0], alpha[j], lm2[i][j + 1]) )

    return amin
def minimiser(Aut):

    Aut2 = completer(Aut)
    Aut2 = determiniser(Aut2)

    etats = list(Aut2.get_states())
    alpha = list(Aut2.get_alphabet())

    # Initialisation. On sépare les états finaux du reste.
    lm1 = list()
    for i in range(len(etats)):
        if Aut2.state_is_final(etats[i]):
            lm1.append(tuple((1, )))
        else:
            lm1.append(tuple((0, )))
        for j in range(len(alpha)):
            d = list(Aut2.delta(alpha[j], [etats[i]]))
            if Aut2.state_is_final(d[0]):
                lm1[i] = lm1[i] + tuple((1, ))
            else:
                lm1[i] = lm1[i] + tuple((0, ))

    # On applique l'algorithme de Moore tant que la liste
    # n'est pas stable.
    lm2 = moore(Aut2, etats, alpha, lm1)
    while lm1 != lm2:
        lm1 = lm2
        lm2 = moore(Aut2, etats, alpha, lm1)

    # On récupère l'état initial.
    init = lm2[etats.index(list(Aut2.get_initial_states())[0])][0]

    # On recherche les nouveaux états finaux.
    lm1 = list()
    ets = list()
    for i in range(len(etats)):
        if Aut2.state_is_final(etats[i]):
            lm1.append(lm2[i][0])
        ets.append(lm2[i][0])
    # On enlève les doublons
    # lm1 la liste des états finaux.
    # lm2 la totalité des états et des transitions.
    # ets la liste de tous les états.
    lm1 = list(set(lm1))
    lm2 = list(set(lm2))
    ets = list(set(ets))

    amin = automaton(alphabet=alpha, states=ets, initials=[init], finals=lm1)

    # On récupère les nouvelles transitions.
    for i in range(len(lm2)):
        for j in range(len(alpha)):
            amin.add_transition((lm2[i][0], alpha[j], lm2[i][j + 1]))

    return amin
def miroir(Aut):
    """ 
    This function compute and returns the miror  of the given autamaton.
    """
    initials = Aut.get_initial_states()
    finals = Aut.get_final_states()
    transit = list(Aut.get_transitions())
    A = automaton(initials=finals, finals=initials)

    for t in transit:
        A.add_transition(tuple(reversed(t)))
    return A
def automaton_with_cartesian_product(A, B, union_or_intersect=0):
    """ 
    This function returns the union or the intersection of two automata
    if keyword union_or_intersect = 0 , the union of returned,
    intersection is returned otherwise
    TODO: use set comprehension generation , add keyword parameter to specify 
    either union or intersection
    """

    if A.get_alphabet() != B.get_alphabet():
        print("/!\\Automaton don't have the same alphabet /!\\")
        sys.exit()

    if is_deterministic(A):
        new_A = completer(A)
    else:
        new_A = determiniser(A)
    new_A.renumber_the_states()
    if is_deterministic(B):
        new_B = completer(B)
    else:
        new_B = determiniser(B)
    new_B.renumber_the_states()

    states_of_A = new_A.get_states()
    initials_of_A = new_A.get_initial_states()
    finals_of_A = new_A.get_final_states()
    states_of_B = new_B.get_states()
    initials_of_B = new_B.get_initial_states()
    finals_of_B = new_B.get_final_states()
    product_aut = automaton()
    for s in states_of_A:
        for t in states_of_B:
            for a in A.get_alphabet():
                x = list(new_A.delta(a, [s]))
                x.extend(list(new_B.delta(a, [t])))
                x_y_tuple = tuple(x)
                product_aut.add_transition(((s, t), a, x_y_tuple))
                if s in initials_of_A and t in initials_of_B:
                    product_aut.add_initial_state((s, t))
    states_product_aut = product_aut.get_states()
    if union_or_intersect == 0:
        for state in states_product_aut:
            if state[0] in finals_of_A or state[1] in finals_of_B:
                product_aut.add_final_state(state)
    else:
        for state in states_product_aut:
            if state[0] in finals_of_A and state[1] in finals_of_B:
                product_aut.add_final_state(state)
    return product_aut
def union( Aut1, Aut2 ) :
    Aut1 = completer(Aut1)
    Aut2 = completer(Aut2)
    
    alpha = list(Aut1.get_alphabet() - Aut1.get_epsilons())

    if alpha != list( Aut2.get_alphabet() - Aut2.get_epsilons() ) :
        return automaton()

    # Tous les états.
    et1 = list(Aut1.get_states())
    et2 = list(Aut2.get_states())
    et = produit_cartesien(et1, et2)

    # Les états finaux.
    f1 = produit_cartesien(list(Aut1.get_final_states()), et2)
    f2 = produit_cartesien(et1, list(Aut2.get_final_states()))

    for i in range(len(f1)) :
        if f1[i] not in f2 :
            f2.append(f1[i])

    # Les états initiaux.
    ini = produit_cartesien(list(Aut1.get_initial_states()), 
        list(Aut2.get_initial_states()))

    tr = nouvelles_transitions_IU(Aut1, Aut2, et1, et2, alpha)

    u = automaton( 
        alphabet = alpha,
        states = et,
        initials = ini,
        finals = f2,
        transitions = tr)
    
    u.renumber_the_states()
    return u
def union(Aut1, Aut2):
    Aut1 = completer(Aut1)
    Aut2 = completer(Aut2)

    alpha = list(Aut1.get_alphabet() - Aut1.get_epsilons())

    if alpha != list(Aut2.get_alphabet() - Aut2.get_epsilons()):
        return automaton()

    # Tous les états.
    et1 = list(Aut1.get_states())
    et2 = list(Aut2.get_states())
    et = produit_cartesien(et1, et2)

    # Les états finaux.
    f1 = produit_cartesien(list(Aut1.get_final_states()), et2)
    f2 = produit_cartesien(et1, list(Aut2.get_final_states()))

    for i in range(len(f1)):
        if f1[i] not in f2:
            f2.append(f1[i])

    # Les états initiaux.
    ini = produit_cartesien(list(Aut1.get_initial_states()),
                            list(Aut2.get_initial_states()))

    tr = nouvelles_transitions_IU(Aut1, Aut2, et1, et2, alpha)

    u = automaton(alphabet=alpha,
                  states=et,
                  initials=ini,
                  finals=f2,
                  transitions=tr)

    u.renumber_the_states()
    return u
def miroir( Aut ) :

    trans = list( Aut.get_transitions() )
    newTrans = []
    for i in range( len(trans) ) :
        newTrans = newTrans + [(trans[i][2], trans[i][1], trans[i][0] )] #chaque transitions de la forme (x,a,y) et remplacé par la trnsition (y,a,x)
    
    a = automaton(
        epsilons = Aut.get_epsilons(),
        alphabet = Aut.get_alphabet(), 
        states = Aut.get_states(), 
        initials = Aut.get_final_states(), # les etats finaux deviennent initiaux
        finals = Aut.get_initial_states(), #les etats initiaux deviennent finaux
        transitions = newTrans )
    return a
def complement(Aut):
    """" 
    This function returns the complement of the given automaton.
    """

    if is_deterministic(Aut):
        B = completer(Aut)
    else:
        B = determiniser(Aut)
    transitions = B.get_transitions()
    initials = B.get_initial_states()
    finals = B.get_final_states()
    states = B.get_states()
    non_finals = states - finals
    return automaton(initials=initials, finals=non_finals, transitions=transitions)
def operation(expr) :
    if len(expr) != 0 :
        if expr[0] == '*' :
            return etoile(expr[1])
        elif expr[0] == '+' :
            return unionEVA(expr[1],expr[2])
        elif expr[0] == '.' :
            return concatenation(expr[1],expr[2])
        elif len(expr) == 1 :
            return automaton(alphabet = expr,
                    states = [1,2],
                    initials = [1],
                    finals = [2],
                    transitions = [ (1 , expr , 2) ] )
        
    return None
def operation(expr):
    if len(expr) != 0:
        if expr[0] == '*':
            return etoile(expr[1])
        elif expr[0] == '+':
            return unionEVA(expr[1], expr[2])
        elif expr[0] == '.':
            return concatenation(expr[1], expr[2])
        elif len(expr) == 1:
            return automaton(alphabet=expr,
                             states=[1, 2],
                             initials=[1],
                             finals=[2],
                             transitions=[(1, expr, 2)])

    return None
def complement(aut):

    a = completer(determiniser(aut))

    oldFinals = a.get_final_states()
    fin = []
    """
    Pour chaque sommet, s'il n'etait pas final, il le devient.
    """
    for i in a.get_states():
        if not i in oldFinals:
            fin += [i]

    return automaton(alphabet=a.get_alphabet(),
                     states=a.get_states(),
                     initials=a.get_initial_states(),
                     finals=fin,
                     transitions=a.get_transitions())
def miroir(Aut):

    trans = list(Aut.get_transitions())
    newTrans = []
    for i in range(len(trans)):
        newTrans = newTrans + [
            (trans[i][2], trans[i][1], trans[i][0])
        ]  #chaque transitions de la forme (x,a,y) et remplacé par la trnsition (y,a,x)

    a = automaton(
        epsilons=Aut.get_epsilons(),
        alphabet=Aut.get_alphabet(),
        states=Aut.get_states(),
        initials=Aut.get_final_states(
        ),  # les etats finaux deviennent initiaux
        finals=Aut.get_initial_states(),  #les etats initiaux deviennent finaux
        transitions=newTrans)
    return a
def complement( aut ) :

    a = completer(determiniser( aut ) )

    oldFinals = a.get_final_states()
    fin = []

    """
    Pour chaque sommet, s'il n'etait pas final, il le devient.
    """
    for i in a.get_states() :
        if not i in oldFinals :
            fin += [i]

    return automaton(
        alphabet = a.get_alphabet(),
        states = a.get_states(),
        initials = a.get_initial_states(),
        finals = fin,
        transitions = a.get_transitions())
def etoile(expr) :
    aut = operation(expr) # on recupere l'automate defini par expr.
    
    """
    On crée les etats nécessaires.
    """
    s1 = aut.get_maximal_id()
    if s1 == None :
        s1 = 0
    else :
        s1 += 1
    s2 = s1 + 1
    s3 = s2 + 1
    s4 = s3 + 1

    alpha = aut.get_alphabet()
    
    #On récupère un charactère definissant epsilons.
    if(aut.has_epsilon_characters()) :
        epsilon = list(aut.get_epsilons())[0]
    else :
        epsilon = generer_epsilon(alpha)

    #on genere les nouvelles transitions nécessaire.
    transitions = list( aut.get_transitions() ) 
    transitions += [ (s1 , epsilon , s2) ,
             (s1 , epsilon , s4) ,
             (s3 , epsilon , s2) ,
             (s3 , epsilon , s4) ]
    for i in aut.get_initial_states() :
        transitions += [ (s2 , epsilon , i ) ]
    for i in aut.get_final_states() :
        transitions += [ ( i , epsilon , s3 ) ]

    return automaton(
        alphabet = alpha,
        epsilons = [epsilon] + list(aut.get_epsilons()) ,
        states = list(aut.get_states()) + [s1 , s2 , s3, s4] ,
        initials = [s1] ,
        finals = [s4],
        transitions = transitions)
def etoile(expr):
    aut = operation(expr)  # on recupere l'automate defini par expr.
    """
    On crée les etats nécessaires.
    """
    s1 = aut.get_maximal_id()
    if s1 == None:
        s1 = 0
    else:
        s1 += 1
    s2 = s1 + 1
    s3 = s2 + 1
    s4 = s3 + 1

    alpha = aut.get_alphabet()

    #On récupère un charactère definissant epsilons.
    if (aut.has_epsilon_characters()):
        epsilon = list(aut.get_epsilons())[0]
    else:
        epsilon = generer_epsilon(alpha)

    #on genere les nouvelles transitions nécessaire.
    transitions = list(aut.get_transitions())
    transitions += [(s1, epsilon, s2), (s1, epsilon, s4), (s3, epsilon, s2),
                    (s3, epsilon, s4)]
    for i in aut.get_initial_states():
        transitions += [(s2, epsilon, i)]
    for i in aut.get_final_states():
        transitions += [(i, epsilon, s3)]

    return automaton(alphabet=alpha,
                     epsilons=[epsilon] + list(aut.get_epsilons()),
                     states=list(aut.get_states()) + [s1, s2, s3, s4],
                     initials=[s1],
                     finals=[s4],
                     transitions=transitions)
def suppress_epsilon_transitions(Aut):
    """ This function returns the equivalent automaton of the given 
    one with e-move suppressed.
    """
    initials = Aut.get_initial_states()
    finals = Aut.get_final_states()
    states = Aut.get_states()
    epsilon_set = Aut.get_epsilons()
    alphabet = Aut.get_alphabet()

    A = automaton(initials=initials, finals=finals, states=states)
    valid_alphabet = alphabet - epsilon_set
    transition_list = [list(x) for x in Aut.get_transitions()]
    # add all transitions except e-transitions
    for l in transition_list:
        if l[1] in valid_alphabet:
            A.add_transition(tuple(l))

    for s in states:
        next_by_e_move = []
        for e in epsilon_set:
            item = Aut.delta(e, [s])
            item = [x for x in item]
            next_by_e_move.extend(item)
        if s in next_by_e_move:
            next_by_e_move.remove(s)
        for a in valid_alphabet:
            successor = []
            for after in next_by_e_move:
                item = Aut.delta(a, [after], ignore_epsilons=True)
                successor.extend(item)
            for succ in successor:
                A.add_transition((s, a, succ))
                if after in finals:
                    A.add_final_states([s])
    return A
Esempio n. 24
0
	def intersection(self, aut2, destructif=False):
		"""
		Calcule l'intersection de deux automates. Le paramètre "destructif" rend destructive la méthode sur le premier automate.
		Par défaut, la méthode ne modifie pas le premier automate
		"""
		assert self.get_alphabet() == aut2.get_alphabet(), "Les deux automates n'ont pas le meme alphabet"
		assert self.get_epsilons() == aut2.get_epsilons(), "Les epsilons ne sont pas encodees par les memes caracteres"

		automate_clone = self.clone()

		# On travaille sur des automates deterministes
		if not aut2.est_deterministe():
			aut2 = aut2.determinisation()
			
		if not self.est_deterministe():
			automate_clone = self.determinisation(destructif)
		
		# On travaille sur des automates complet
		if not aut2.est_complet():
			aut2 = aut2.completer()

		if not self.est_complet():
			automate_clone = self.completer(destructif)		

		alphabet_courant = self.get_alphabet()

		automate_tmp = automaton(
		alphabet= alphabet_courant,
		epsilons= self.get_epsilons()
			)

		finaux_1 = automate_clone.get_final_states()
		finaux_2 = aut2.get_final_states()
		
		# Création états initiaux de l'automate de l'union


		for ini_1 in automate_clone.get_initial_states():
			for ini_2 in aut2.get_initial_states():
				etat = (ini_1, ini_2)
				automate_tmp.add_initial_state(etat)

		# Création de l'automate des couples (automate de l'union)
		for etat_1 in automate_clone.get_states():
			for etat_2 in aut2.get_states():
				automate_tmp.add_state((etat_1, etat_2))
				for lettre in alphabet_courant:
					for dest_1 in automate_clone.delta(lettre, [etat_1]):
						for dest_2 in aut2.delta(lettre, [etat_2]):
							automate_tmp.add_transition(((etat_1, etat_2), lettre, (dest_1, dest_2)))
				if etat_1 in finaux_1 and etat_2 in finaux_2:
					automate_tmp.add_final_state((etat_1, etat_2))


		################## ANCIENNE IMPLÉMENTATION ##################################
		# while len(pile_etats) > 0:
		# 	etat_courant = pile_etats.pop()
		# 	if not etat_courant == set():
		# 		etat_1, etat_2 = etat_courant
		# 		for l in self.get_alphabet():
		# 			if not l in self.get_epsilons():
		# 				delta_etat_1 = self._delta(l, [etat_1])
		# 				delta_etat_2 =  aut2._delta(l, [etat_2])
		# 				nouveau = set()
		# 				for e1 in delta_etat_1:
		# 					for e2 in delta_etat_2:
		# 						nouveau = (e1,e2)
						
		# 				if not nouveau == set():
		# 					if not nouveau in automate_tmp.get_states():
		# 						pile_etats.append(nouveau)
		# 					final = True
		# 					for e in nouveau:								
		# 						if not e in finaux:
		# 							final = False
		# 							break
		# 					if final:
		# 						automate_tmp.add_final_state(nouveau)
		# 					automate_tmp.add_transition((etat_courant, l, nouveau))
		if destructif:
			self.reconstruction(automate_tmp)

		return automate_tmp
def minimiser_moore(Aut):
    """"
    This function returns the minimize automaton of the given one by using 
    moore algorithm.
    """
    if is_deterministic(Aut):
        B = completer(Aut)
    else:
        B = determiniser(Aut)
    B.renumber_the_states()
    B.map(lambda x: x - 1)
    alphabet = B.get_alphabet()
    card_alphabet = len(alphabet)
    states = B.get_states()
    maxi = B.get_maximal_id()
    states_list = [x for x in range(maxi + 1)]
    destination_reference = [[] for _ in range(len(alphabet))]
    i = 0
    for a in alphabet:
        destination_reference[i] = []
        for s in states_list:
            l = B.delta(a, [s])
            l = [x for x in l][0]
            destination_reference[i].append(l)
        i += 1
    equivalence_classes = [0 for x in states]
    for i in range(maxi + 1):
        if B.state_is_final(i):
            equivalence_classes[i] = 1
    pre_equivalence_classes = []
    while pre_equivalence_classes != equivalence_classes:
        class_number = 0
        mark_array = [False for _ in range(maxi + 1)]
        pre_equivalence_classes = [x for x in equivalence_classes]
        # going through the states
        for i in range(maxi + 1):
            if mark_array[i] == True:
                continue
            eq_per_loop = [i]
            list_tuple = [pre_equivalence_classes[i]]
            # going through the alphabet
            for j in range(card_alphabet):
                # first get the successor of i by j and then compute his equivalence_class
                list_tuple.append(pre_equivalence_classes[destination_reference[j][i]])
            # check if other states have the same list , if so then the two are in same eq_class
            for k in range(i + 1, maxi + 1):
                inner_list_tuple = [pre_equivalence_classes[k]]
                # going again through the alphabet
                for l in range(card_alphabet):
                    inner_list_tuple.append(pre_equivalence_classes[destination_reference[l][k]])
                    # same class
                if list_tuple == inner_list_tuple:
                    eq_per_loop.append(k)
            # update the equivalence_classes
            for s in eq_per_loop:
                mark_array[s] = True
                equivalence_classes[s] = class_number
            class_number += 1
    mini_state = {x for x in equivalence_classes}
    mini_state = [x for x in mini_state]
    # initial state of the original automaton
    initials = [x for x in B.get_initial_states()]
    # final state of the original automaton
    finals = [x for x in B.get_final_states()]
    mini_initial = equivalence_classes[initials[0]]
    mini_final = []
    for s in finals:
        mini_final.append(equivalence_classes[s])
    minimal_aut = automaton(states=mini_state, initials=[mini_initial], finals=mini_final, alphabet=alphabet)
    for s in states_list:
        eq_s = equivalence_classes[s]
        i = 0
        for a in alphabet:
            successor_by_a = equivalence_classes[destination_reference[i][s]]
            minimal_aut.add_transition((eq_s, a, successor_by_a))
            i += 1
    return minimal_aut
def concatenation(expr1, expr2):

    #on renomme les états au cas où il y aurait des redondances
    aut1 = operation(expr1)
    aut2 = operation(expr2)

    aut1.renumber_the_states()
    aut2.renumber_the_states()
    x = aut1.get_maximal_id()
    if x == None:
        x = 0
    else:
        x += 1

    def rajouter(y):
        return y + x

    aut2.map(rajouter)

    #on génère le nouvel alphabet et on fusionne tous les epsilons en un même symbole,
    #permet d'éviter les problèmes liés au fait qu'un epsilon de aut1
    #peut être dans l'alphabet de aut2, et inversement.
    old_epsilon1 = aut1.get_epsilons()
    old_epsilon2 = aut2.get_epsilons()

    alpha1 = list(aut1.get_alphabet() - old_epsilon1)
    alpha2 = list(aut2.get_alphabet() - old_epsilon2)

    alpha = list(aut1.get_alphabet() - old_epsilon1)
    for i in alpha2:
        if not i in alpha:
            alpha += [i]

    epsilon = generer_epsilon(alpha)

    transitions = []

    for i in aut1.get_transitions():
        if i[1] in old_epsilon1:
            transitions += [(i[0], epsilon, i[2])]
        else:
            transitions += [i]
    for i in aut2.get_transitions():
        if i[1] in old_epsilon2:
            transitions += [(i[0], epsilon, i[2])]
        else:
            transitions += [i]

    #creation de l'automate concaténation
    s1 = aut2.get_maximal_id()
    if s1 == None:
        s1 = 0
    else:
        s1 += 1
    s2 = s1 + 1

    for i in aut1.get_initial_states():
        transitions += [(s1, epsilon, i)]
    for i in aut1.get_final_states():
        for j in aut2.get_initial_states():
            transitions += [(i, epsilon, j)]
    for i in aut2.get_final_states():
        transitions += [(i, epsilon, s2)]

    return automaton(alphabet=alpha,
                     epsilons=[epsilon],
                     finals=[s2],
                     initials=[s1],
                     transitions=transitions)
def concatenation(expr1,expr2) :

    #on renomme les états au cas où il y aurait des redondances
    aut1 = operation(expr1)
    aut2 = operation(expr2)

    aut1.renumber_the_states()
    aut2.renumber_the_states()
    x = aut1.get_maximal_id()
    if x == None :
        x = 0
    else :
        x+=1

    def rajouter(y) :
        return y + x

    aut2.map(rajouter)

    #on génère le nouvel alphabet et on fusionne tous les epsilons en un même symbole,
    #permet d'éviter les problèmes liés au fait qu'un epsilon de aut1
    #peut être dans l'alphabet de aut2, et inversement.
    old_epsilon1 = aut1.get_epsilons()
    old_epsilon2 = aut2.get_epsilons()
    
    alpha1 = list( aut1.get_alphabet()  - old_epsilon1 )
    alpha2 = list( aut2.get_alphabet()  - old_epsilon2 )
    
    alpha = list( aut1.get_alphabet() - old_epsilon1 )
    for i in alpha2 :
        if not i in alpha :
            alpha += [i]

    epsilon = generer_epsilon(alpha)

    transitions = []

    for i in aut1.get_transitions() :
        if i[1] in old_epsilon1 :
            transitions += [ ( i[0] , epsilon , i[2] ) ]
        else :
            transitions += [i]
    for i in aut2.get_transitions() :
        if i[1] in old_epsilon2 :
            transitions += [ ( i[0] , epsilon , i[2] ) ]
        else :
            transitions += [i]
            
    #creation de l'automate concaténation
    s1 = aut2.get_maximal_id()
    if s1 == None :
        s1 = 0
    else :
        s1 += 1
    s2 = s1 + 1

    for i in aut1.get_initial_states() :
        transitions += [ (s1 , epsilon , i ) ]
    for i in aut1.get_final_states() :
        for j in aut2.get_initial_states() :
            transitions += [ (i , epsilon , j) ]
    for i in aut2.get_final_states() :
        transitions += [ (i , epsilon , s2) ]

    return automaton( alphabet = alpha ,
              epsilons = [ epsilon ] ,
              finals = [s2] ,
              initials = [s1] ,
              transitions = transitions )