Partage
  • Partager sur Facebook
  • Partager sur Twitter

automate deterministe

5 avril 2021 à 12:09:20

Bonjour,

J'essaie de faire une fonction qui permet de savoir si un automate est deterministe ou non. 

Seulement je suis bloqué pour la condition du : au maximum une fleche d'un caractère sortant d'un état.

J'ai donc fait cette fonction : 

def auto_det(nb)
fichier = open('automate.txt', 'r')
    for i in range(0, nb+1):
        ligne1 = fichier.readline()
        l1 = list(ligne1)
        print(l1)
        l1.pop()
        """for j in range(0,nb+1):
            ligne2 = fichier.readline()
            l2 = list(ligne2)
            l2.pop()
            if(l2[1] == l2[1]):
                print("l'automate à un doublons de libellé")"""

Pour faire simple : 1- je veux lire dans le fichier les transitions (exemple : 3a5) ; 2 transformer cette ligne en liste; 3 supprimer le dernier élément de cette liste (car je ne compare que les deux premiers éléments) 

Je fais ça pour la ligne courante et la suivante. Mais j'ai un  problème, apparemment la liste l1 (et l2 mais le programme n'arrive pas à cette étape) est vide. Pourtant la fonction lit bien les lignes.

Quelqu'un saurait pourquoi ? 

Merci 

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 12:44:29

Bonjour,

Une ligne lue dans un fichier est forcément une chaine de caractères

donc ligne1  en est une et donc list(ligne1) plante ...

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 12:53:38

Kidorich a écrit:

Mais j'ai un  problème, apparemment la liste l1 (et l2 mais le programme n'arrive pas à cette étape) est vide. Pourtant la fonction lit bien les lignes.


Python ne se trompe pas: si la liste est vide, c'est que la chaine de caractères est vide, donc que readline() a retourné une chaine de caractères vide...

Or si readline retourne une ligne, une ligne vide n'est jamais une chaine vide: elle contiendra au moins '\n' disant fin de ligne.

chaine vide est un retour particulier de readline qui signale juste qu'il n'y plus rien à lire.

Tout ce qu'on peut dire c'est que le fichier contient un nombre de lignes inférieur à nb.

Après, est ce que le fichier est supposé contenir nb lignes et si on en trouve moins ben... c'est pas un fichier "intègre" et il faut traiter l'erreur ou est-ce que vous avez écrit cette boucle un peu au hasard et qu'il faudrait revoir un peu tout çà?

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 13:20:28

mps a écrit:

Kidorich a écrit:

Mais j'ai un  problème, apparemment la liste l1 (et l2 mais le programme n'arrive pas à cette étape) est vide. Pourtant la fonction lit bien les lignes.


Python ne se trompe pas: si la liste est vide, c'est que la chaine de caractères est vide, donc que readline() a retourné une chaine de caractères vide...

Or si readline retourne une ligne, une ligne vide n'est jamais une chaine vide: elle contiendra au moins '\n' disant fin de ligne.

chaine vide est un retour particulier de readline qui signale juste qu'il n'y plus rien à lire.

Tout ce qu'on peut dire c'est que le fichier contient un nombre de lignes inférieur à nb.

Après, est ce que le fichier est supposé contenir nb lignes et si on en trouve moins ben... c'est pas un fichier "intègre" et il faut traiter l'erreur ou est-ce que vous avez écrit cette boucle un peu au hasard et qu'il faudrait revoir un peu tout çà?

Merci à tous les deux pour vos réponses, en effet après avoir longuement deboggé, le problème venait du faire que le programme lisait une ligne +1 et donc la liste devenait vide. J'ai donc réduire la boucle de 0 à nb et le problème est réglé. 

Par hasard, comme ce problème ne vient pas tout seul :D, je voulais savoir, comme dit plus haut, je souhaite comparé les deux premiers elements de deux listes differentes (où les listes seraient la ligne actuellement lu et la ligne suivante).D'où la double boucle. j'ai donc tenté ceci : 

 for i in range(0, nb):
        ligne1 = fichier.readline()
        l1 = list(ligne1)
        print(l1)
        l1.pop()
        for j in range(0,nb):
            ligne2 = fichier.readline()
            l2 = list(ligne2)
            l2.pop()
            if(l1[0] and l1[1] == l2[0] and l2[1]):
                print("l'automate à un doublons de libellé")

Or je veux commencer les opérations à partir d'une certaine ligne et non sur tout le fichier.

Mais j'ai en erreur un out of range. dans le if. Auriez vous des pistes ? 

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 14:25:29

Pourquoi faire une boucle pour juste aller lire la ligne suivante?

Le code doit refléter ce que vous voulez faire. Si vous dites "je veux commencer les opérations à partir d'une certaine ligne", çà veut dire qu'on va lire des lignes en les ignorant ou tant qu'on n'y trouve pas une certaine condition... puis on passe à l'étape suivante.

Si dans le code on ne trouve rien qui traduise l'intention de départ, çà ne marchera pas.

Ce que vous pouvez constater à l'exécution. Vous auriez pu le constater déjà en essayant de relire le code tout en imaginant ce que la machine allait bien pouvoir en faire.


  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 15:17:38

Aussi, si on en vient à comparer la dernière ligne à sa suivante, on aura un IndexError.
Il faut arrêter la recherche à l'avant dernière ligne.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

5 avril 2021 à 15:40:02

mps a écrit:

Pourquoi faire une boucle pour juste aller lire la ligne suivante?

Le code doit refléter ce que vous voulez faire. Si vous dites "je veux commencer les opérations à partir d'une certaine ligne", çà veut dire qu'on va lire des lignes en les ignorant ou tant qu'on n'y trouve pas une certaine condition... puis on passe à l'étape suivante.

Si dans le code on ne trouve rien qui traduise l'intention de départ, çà ne marchera pas.

Ce que vous pouvez constater à l'exécution. Vous auriez pu le constater déjà en essayant de relire le code tout en imaginant ce que la machine allait bien pouvoir en faire.

ha ! 

je me disais que faire deux boucles étaient bons. Le problèm est que je ne vois pas comment faire pour faire en sorte de commencer à une certaine ligne. 

Je comptais comparer deux listes donc deux boucles pour savoir si elles étaient identiques par cette méthode

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 16:38:03

Veux-tu comparer les listes au complet?  if l1 == l2:  marcherais.
Si tu connais la position de départ:  if l1[pos:] == l2[pos:]:
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

5 avril 2021 à 17:01:20

Kidorich a écrit:

je me disais que faire deux boucles étaient bons. Le problèm est que je ne vois pas comment faire pour faire en sorte de commencer à une certaine ligne. 

C'est un fichier texte. Les lignes sont à priori de longueur variable. Et si on veut dire j'ignore tout ce qui est avant la 10ième ligne, il faut lire 9 lignes en ignorant leur contenu... puis arrivé là, on va pouvoir passer aux choses sérieuses.

Kidorich a écrit:

Je comptais comparer deux listes donc deux boucles pour savoir si elles étaient identiques par cette méthode

Séparez les difficultés: avant de comparer vos listes, il faut lire le fichier pour y récupérer ce qui permettra de construire les listes. Et lire un fichier texte, c'est déjà une boucle qui va produire les listes à comparer. Tant que ce boulot là n'est pas fait, pas de listes et à fortiori pas de listes à comparer.

A la sortie de cette boucle là, par contre, on devrait avoir 2 listes.

Comment les comparer sera l'étape suivante... Et si çà fait du sens de le faire avec une boucle ou des boucles imbriquées pourquoi pas mais çà ne change pas le boulot à faire avant.

  • Partager sur Facebook
  • Partager sur Twitter
5 avril 2021 à 17:35:10

Ce qui m'agace est la ligne suivante:
if(l1[0] and l1[1] == l2[0] and l2[1]):
Ça laisse supposer qu'il y a des booléens ou des 0 et des 1 dans ces éléments. Je ne crois pas que c'est ça qui s'y trouve.
Il faudra revoir ce test.
Pourquoi l1[0] et l1[1]?
Revises ce que mps a écrit.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

10 avril 2021 à 23:20:08

rebonsoir à tous,

Après avoir lu vos messages, vos conseils, j''ai repris "à zéro" ma (mes) fonction(s) en les découpant en sous problème.

Voici ce que j'ai fait :

j'ai donc découper ma grosse fonction en sous fonctions afin de recuperer les resultats de ces sous fonctions.

1 qui va recuperer les deux premieres transiitions uniquement (car si deux transitions avec le meme caractère : non deterministe)

1 qui va transformer les deux premieres transitions (ligne du fichier) en liste et enlever le dernier élément  et cela pour la ligne courante et la ligne suivante

1 qui va pouvoir comparer le premier et deuxieme élément et donc dire s'ils dans les deux listes ce sont les meme. SI oui ==> doublons = 1 sinon doublons = 0

1 qui prend le nb d'entree et le doublon

Le problème est lors de la comparaison, j'ai un out of range et j'ai repensé au truc du binaire mais je comprends toujours pas.

 Je pense ne pas être loin.

Voici le code : 

def recup_transitions(nb):
    fichier = open('automate.txt', 'r')
    for i in range(0,nb):
        ligne = fichier.readline()
        if(i==3):
            l1 = etat_entree_et_transition(ligne) #liste de la ligne courante 
            ligne_suivante = fichier.readline()
            ligne_suivante = etat_entree_et_transition(ligne_suivante)
            l2 = ligne_suivante
            l_entree = [l1,l2]
            return l_entree
            
def etat_entree_et_transition(ligne):
    liste_etats = list(ligne)
    liste_etats.pop()
    return liste_etats

def check_libelle_transition(liste_etats):
    temp1 = liste_etats[0]
    temp2 = liste_etats[1]
    if temp1[0] == temp2[0]:
        pass
        if temp1[1] == temp2[1]:
            #il y a un doublon de libellé
            doublon = 1
            return doublon
        else :
            doublon = 0
            return 0
    return 0

def est_un_automate_deterministe(nb_entree, doublon):
    if(nb_entree == 0):
        print("l'automate n'existe pas")
    elif(nb_entree == 1):
        print("l'automate n'est pas deterministe")
    elif(nb_entree == 2 and doublon == 0):
        print("l'automate à une entrée et un libellé unique\n")
        print("L'automate est deterministe")
  • Partager sur Facebook
  • Partager sur Twitter
11 avril 2021 à 2:48:45

Dans ton premier message, tu disais que les lignes ont l'allure suivante:
3a5
Est-ce bien correct? Puis tu veux transformer en une liste:
[3, 5]
Et faire un pop du dernier?
Donne des exemples de lignes complètes.
On ne connais pas la valeur de nb passée en paramètre.
Je n'aime pas l'idée de lire une ligne et la suivante. La suivante existe-t-elle toujours?
Peux-tu donner le TraceBack complet pour qu'on sache où ça bloque?
Je soupçonne que c'est dans le pop() mais ...
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

11 avril 2021 à 12:21:01

Les lignes ont bien l'allure 3a5. Non , je veux transformer la liste en ["3","a"], donc oui je veux faire un pop du dernier element.

une ligne complete dans le fichier : 0a1.

Nb est le nombre de ligne du fichier (retourner dans une autre fonction). Dans le fichier automate.txt il est de 15.

Dans le fichier les transitions commencent à la ligne 5 (erreur dans mon code lors de la condition if dans recup_transition). Les lignes suivantres sont les autres transitions. 

Oui après test la ligne suivante est bien lue.  et j'ai aussi remarqué que je dois pop() deux fois car le retour à la ligne st presente dans la liste.

Voici le traceback : 

Traceback (most recent call last):
  File "d:\GitHub\Projet-math-info-\main.py", line 21, in <module>
    main()
  File "d:\GitHub\Projet-math-info-\main.py", line 14, in main
    doublon = check_libelle_transition(liste_etats)
  File "d:\GitHub\Projet-math-info-\fonctions.py", line 61, in check_libelle_transition
    temp2 = liste_etats[1]
IndexError: list index out of range
  • Partager sur Facebook
  • Partager sur Twitter
11 avril 2021 à 15:35:24

L'erreur dit juste que liste_etats ne contient pas le nombre d'items attendus.

Affichez les lignes et le contenu des listes pour avoir une idée du problème:

def recup_transitions(nb):
    fichier = open('automate.txt', 'r')
    for i in range(0,4):
        ligne = fichier.readline()
    l1 = etat_entree_et_transition(ligne) #liste de la ligne courante
    print(ligne, l1)
    ligne = fichier.readline()
    l2 = etat_entree_et_transition(ligne_suivante)
    print(ligne, l2)
    l_entree = [l1,l2]
    return l_entree



  • Partager sur Facebook
  • Partager sur Twitter
11 avril 2021 à 17:38:40

J'ai fait un copier-coller deton code sans le main que je n'avais pas.
Je suis sur Windows 10, je travaille avec cmd et j'édite avec notepad (Block-Notes)
Si je fais un print(ord(ligne_suivante[-1])), j'obtiens 54 qui est le code d'un '6' qui se trouvait bien dans mon fichier automate.txt
Le code du '\n' aurait été 10. Tu n'as pas besoin de faire un pop() pour l'enlever.
Comme l'a suggéré mps, fait des print un peu partout pour suivre la progression.
Il y a beaucoup de choses bizarres dans ton code.
Par exemple, '3a6' devient ['3', 'a', '6'] après le list() et ['3', 'a'] après le pop()
            l_entree = [l1,l2]
            return l_entree
Tu peux faire directement return [l1, l2]
Puisque tu ne sembles pas avoir beaucoup de lignes dans ton fichier automate.txt et qu'elles sont assez courtes, je les aurais toutes lues sans me fier au nb et je les aurais placées dans une liste de str.
J'aurais vérifié que le nombre de lignes était suffisant et j'aurais pris les lignes qui m'intéressent.
Je te rappelle que les nombres sont en format str et non int. Si tu veux faire des calculs, tu devras les convertir.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

11 avril 2021 à 20:25:10

Ok je vais voir ça avec des prints.

Oui c'est normal qu'il ne reste que quelque chose de la forme ['3', 'a' ]

UPDATE : après avoir vérifier la fonction de récup des transitions , les différents print m'ont permis de voir que c'est correct, que ça fonctionne (après légère modif) et que le problème se situe plus sur la fonction check_libelle_transition. Je revois ça.

REUPDATE

Bon.. j'ai revu les fonctions et il s'avère que la fonction check est bizarre. La liste de liste que je crée dans recup_transistions est bien là mais dés qu'il faut passer la liste dans etat_entree_et_transition ça ne fonctionne pas. PIRE, j'ai print pour voir, elle est vide alors que dans recup_transition elle est bonne...

Là je ne sais vraiment pas pourquoi..

def recup_transitions(nb):
    fichier = open('automate.txt', 'r')
    liste_etats = []
    for i in range(0,nb):
        ligne_courante = fichier.readline()
        if(i==5):
            ligne_courante = etat_entree_et_transition(ligne_courante)
            print(ligne_courante)
            liste_etats.append(ligne_courante)
            ligne_suivante = fichier.readline()
            ligne_suivante = etat_entree_et_transition(ligne_suivante)
            liste_etats.append(ligne_suivante)
            print("liste après ope : ", liste_etats)
            return liste_etats
            
def etat_entree_et_transition(ligne):
    i = 0
    ligne = list(ligne)
    print(ligne)
    while(i<=1):
        ligne.pop()
        i = i+1
    return ligne

def check_libelle_transition(liste_etats):
    print("liste recu apres op", liste_etats)
    l1 = liste_etats[0]
    l2 = liste_etats[1]
    return 0
    if l1[0] == l2[0]:
        pass
        if l1[1] == l2[1]:
            #il y a un doublon de libellé
            doublon = 1
            return doublon
        else :
            doublon = 0
            return doublon

-
Edité par Kidorich 11 avril 2021 à 22:57:58

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2021 à 2:38:37

Tu peux simplifier si tu ne fais qu'un pop()
def etat_entree_et_transition(ligne):
 return list(ligne)[:-1]
Pour la fin de ligne, je crois que tu avais raison, il y a bien un '\n' à la fin.
Je n'avais que 4 lignes dans mon fichier automate.txt et la dernière n'avait pas de fin de ligne.
Qu'il y en ait une ou pas, tu peux faire:
 ligne = ligne.replace('\n', '')
Tu le fais pour les deux lignes juste après la lecture.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

12 avril 2021 à 13:41:48

Kidorich a écrit:

Là je ne sais vraiment pas pourquoi..


S'il le ligne juste avant l'appel de la fonction n'est pas le même que le ligne reçu en paramètre, c'est qu'il s'est passé des choses entre les 2 ou que vous avez mal regardé. Et pour le coup sans code qui permette de reproduire quoi que ce soit, pas facile d'imaginer quelque chose qu'il faut voir pour y croire.
  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2021 à 17:47:37

dans ton code modifié, tu ne traites que le cas i==5 et pas les suivantes (d'autant plus avec le return dans le if)

sinon normal qu'après la liste soit vide dans check_libelle_transisition puisque liste_etats est un de ses paramètres.

pour utiliser le résultat de recup_transitions, il faut quelque part l'appel à cette fonction

liste=recup_transitions(15)
check_libelle_transition(liste)

et ta fonction etat_entree_et_transition est complexe pour faire juste un pop (à moins qu'elle doive faire d'autres choses par la suite)

def recup_transitions(nb):
    fichier = open('automate.txt', 'r')
    liste_etats = []
    for i in range(0,nb):
        ligne_courante = fichier.readline()
        if(i>=5):
            ligne_courante = list(ligne_courante[:2])
            print(ligne_courante)
            liste_etats.append(ligne_courante)
    return liste_etats



-
Edité par umfred 12 avril 2021 à 17:53:40

  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2021 à 18:18:10

J'ai eu un peu de difficulté à comprendre.
Dans mon code, j'ai fait ce que humfred a dit. J'ai appelé les fonctions à la suite dans le main.
J'ai déjà mentionné qu'effectivement, il y a une fin de ligne qu'il faut enlever. Je précise comment.
Je crois que Kidorich ne comprend pas lui-même ce qu'il doit faire.
On se retrouve avec des listes du genre: [['4', 'a'], ['3', 'a']]
À quoi servent les 'a' ?
J'aurais vu séparer la ligne comme suit: '1a3' -> ['1', '3']
La fonction check aurait deux nombres à comparer.
Il suffit de faire un ligne.split('a') après avoir enlevé la fin de ligne ('\n')
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

12 avril 2021 à 18:29:17

c'est vrai que ça semble plus logique d'avoir des chiffres (en espérant qu'il n'y ai pas de nombres en fait) à comparer mais bon, c'est lui le sachant du pourquoi
  • Partager sur Facebook
  • Partager sur Twitter
12 avril 2021 à 18:41:13

On peut avoir simplement:
def etat_entree_et_transition(ligne):
    ligne = ligne.replace('\n', '')
    ligne = ligne.replace(' ', '')   # si requis
    return ligne.split('a')
t

  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

12 avril 2021 à 20:01:18

Après divers tentative j'ai trouvé un autre moyen de faire ce que je voulais faire, à savoir récupérer la ligne et la transformer en liste. J'ai finalement trouver une autre méthode qui me permet de raccourcir et d'éviter ainsi les problèmes "d'algorithmie".

Pour vous répondre, le 'a' dans la ligne est le caractère de transition de l'automate. Il est nécessaire pour ma fonction. Le seul caractère inutile est le troisième.

Voici le code "réparer" :

def recup_transitions(nb):
    fichier = open('automate.txt', 'r')
    liste_etats = []
    for i in range(0,nb):
        ligne_courante = fichier.readline()
        
        if(i==5):
            ligne_courante = ligne_courante.replace("\n", "")
            print(ligne_courante)
            ligne_courante = etat_entree_et_transition(ligne_courante)
            ligne_suivante = fichier.readline() 
            print(ligne_suivante)
            ligne_suivante = ligne_suivante.replace("\n", "")
            ligne_suivante = etat_entree_et_transition(ligne_suivante)
            liste_etats.append(ligne_courante)
            liste_etats.append(ligne_suivante)
            print("liste après ope : ", liste_etats)
            return liste_etats
            
def etat_entree_et_transition(ligne):
    ligne = ligne[:-1]
    return ligne
    

def check_libelle_transition(liste_etats):
    print("liste recu apres op", liste_etats)
    l1 = liste_etats[0]
    l2 = liste_etats[1] 
    if(l1[0][0] == l2[1][0]):
        print("il y a un doublon")
    else:
        print("ici")

tout est bon sauf la fonction check_libelle_transition, dans la laquelle je n'arrive pas à comparer les éléments de chaque liste.  Voilà un aperçu du output que j'obtiens: 

Comme on peut le voir, la fonction ne passe même pas dans ma condition if. Comme une str est une liste en soit, je compare chaque caractère de str avec l'autre.

  • Partager sur Facebook
  • Partager sur Twitter
13 avril 2021 à 3:02:04

Dans ta fonction recup_transition, puisque tu n'as que 2 éléments dans liste_etats, tu peux faire directement:
 return [ligne_courante, ligne_suivante]
Tu peux mettre les deux replace dans la fonction etat_entree_et_transition avant le slicing ligne[:-1]
Ton code en sera d'autant simplifié.
Si le 'a' est nécessaire, dois-je comprendre qu'il pourrait y avoir une autre lettre? Sinon ce serait inutile.
Dans ta fonction check_libelle_transition, tu reçois une liste de 2 chaînes. Exemple: ['1a', '2a']
l1 vaut '1a', l1[0] vaut '1', mais que vaut l1[0][0] ?
Tu dois reviser ce bout de code.
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.

13 avril 2021 à 12:33:14

regarde ton test, tu compares l1[0][0] qui vaut '0' et l2[1][0] qi vaut 'a';

l1='0a', l1[0]='0', l1[0][0]='0' aussi

l2='0a', l2[1]='a', l2[1][0]='a' aussi

cela vient du fait que n'a plus une liste de liste de caractères l=[['0','a'],['0','a']] mais une liste de chaine l=['0a','0a'] (en quelque sorte, tu "perds" 1 niveau de liste).

Je reviens sur le if(i==5) dans la boucle qui ne permet donc de lire actuellement que les lignes 5 et 6 du fichier. c'est normal ? j'aurai fait comme dans le code de mps plus haut (faire une boucle pour lire les 4 premières lignes, puis ensuite lire et traiter les 2 suivantes (donc en dehors de la boucle et sans if)

Pareil pour la fonction "etat_entree_et_transition(ligne)", vu l'unique instruction qu'elle fait, autant la faire directement au moment de l'appel actuel (si la fonction n'a que cette instruction à faire au final)

  • Partager sur Facebook
  • Partager sur Twitter
13 avril 2021 à 15:10:26

On peut écrire:
ligne_suivante = ligne_suivante.replace('\n', '')[:-1]t
  • Partager sur Facebook
  • Partager sur Twitter

Le Tout est souvent plus grand que la somme de ses parties.