Itération de compositions (permutation-cycle)

Bonjour,

Je dois définir une fonction, qui à une permutation sigma donnée, me donne la liste des cycles de sigma.
Par exemple pour sigma = [4,1,6,2,3,5], je retrouve 4,2,1],[6,5,3.

Dans mon code, j'ai commencé par :
def permutation_de_cycles(sigma):
    ss=sigma
    s=deepcopy(ss)
    pp=[]
    p=[pp]
    s[0]=a1
    if a1==1: # Si le premier élément du cycle correspond à la position 1
        pp=[] # Le cycle est vide
    else:
        pp.append(a1)
        s[a1-1]=a2 # Je cherche la valeur de la position a1, donc a1-1 dans sage
        if a2==1:
            pp.append(a2)
        else:
            s[a2-1]=a3 # Et ainsi de suite jusqu'à a_n où n est égale à len(ss)
Question 1 : Comment je peux faire une itération (boucle) de compositions ? Cela me semble long si la longueur de sigma est longue
Question 2 : Cela n'est valable que si je comment mon cycle à la position 0 (dans sage). Une fois que j'ai fini ce cycle, je dois rajouter une boucle pour la position i qui n'est pas encore apparu dans le cycle précédent. Comment pourrais-je écrire cela ?

Merci d'avance

Réponses

  • Tu pourrais maintenir un tableau qui se souvienne des points qui ont été utilisés.
  • Merci pour ta réponse aléa, mais même si je fais ça, je dois quand même écrire une fonction qui itère les compositions et ça, je ne sais pas comment le faire avec une boucle…
  • Que veux-tu dire avec ton "itération de compositions" ? Compositions de quoi ?
    Tu devrais commencer par décrire ce que ton algorithme fait avant d'écrire du code.
  • J'ai un permutation d'une longueur n.
    Je regarde ce que j'ai à la position 0, donc c'est l'image de 1 par sigma. J'appelle cette valeur, a1. Si a1 = 1 (ou 0+1), alors j'arrête mon cycle, sinon je regarde la position a1-1 (puisque sage commence à 0), et j'ai une valeur a2. Si a2 = 1, j'arrête mon cycle, sinon je regarde à la position a2-1.
    A chaque fois que je regarde une position, je dois entrer dans sage, la commande sigma, et donc j'ai des sigma de sigma etc. que j'appelle abusivement "composition d'itérations".

    Une fois que j'ai fini un cycle, je dois regarder à la position i où il n'y a pas encore de valeurs trouvée dans les a_i précédemment. Et donc j'ai encore une boucle.

    Mon problème, c'est que j'ai du mal à écrire ces boucles…
  • Préliminaire : si la permutation $\sigma$ est donnée par une liste sigma, comment calculer l'image $\sigma(k)$ d'un entier $k$ ?

    Suggestion : plutôt que garder une trace des points déjà utilisés, garder une trace des points qui restent. À chaque fois qu'un point est intégré dans un cycle, le supprimer de cette liste.

    Une stratégie possible : tant qu'il reste des points (dans la liste des points qui restent...), en choisir un et calculer le cycle auquel il appartient, ce qui peut se faire en ajoutant l'image du dernier point qu'on a sous la main tant qu'on ne retombe sur le premier point du cycle ; une fois qu'on a le cycle, on l'ajoute à la liste des cycles calculés jusque là.

    Si ceci est confus, une idée qui doit l'être moins : tu peux t'en sortir en utilisant des while (emboîtés).
  • Voici le code que j'ai actuellement :
    def my_cycles_perm(sigma):
        ss=sigma
        s=deepcopy(ss)
        l=len(ss) # Longueur de sigma
        c=range(l)
        p=[] # Je commence par une liste vide
        pp=[[p]] # Liste de mes cycles
        for i in (c): # Je cherche la position i dans c qui me donne une valeur qui n'est pas encore dans p
            lp=len(p)
            j=0
            while j<lp:
                if i==p[j]:
                    j=j+1
                else: # Une fois que j'ai trouvé une valeur i qui n'est pas encore dans un cycle p, je regarde ce que donne i par sigma
                    while i<l:
                        r=s[i-1] # Car SAGE commence à compter de 0
                        p.append(r) # Je rajoute cette valeur trouvée dans ma liste
                        if r!=(i): # Si l'image est différent de la position, je regarde l'image de l'image
                            r=s[r]
                            p.append(r) # Je rajoute la nouvelle valeur dans ma liste
                        else:
                            print(p)
    

    Je n'arrive pas à aller plus loin…
  • C'est peu engageant. Il y a des choses très étrange, en voici deux. Tu initialise p=[] puis tu définis pp=p, c'est-à-dire la liste qui contient la liste qui contient la liste vide. C'est bien utile, cette accumulation ? Dans le même genre, mais sans conséquences, tu écris "for i in (c)" : pourquoi ces parenthèses ?

    On ne voit pas vraiment l'influence des suggestions d'alea (ou moi) de garder une trace des points qui ont déjà été choisis (ou qui restent).

    Mais surtout, comme le disait GaBuZoMeu, ta description de l'algorithme n'est pas convaincante. Tu as essayé de la faire tourner comme si tu étais le programme ? Il manque des tas de choses avant de pouvoir la traduire en code. On imagine que les valeurs a1, a2 vont alimenter une liste a dont on ne voit pas de trace dans le code. Puis la phrase « A chaque fois que je regarde une position » suggère qu'il y a une itération : de quoi ? qu'est-ce qu'une position ?
  • Donc les positions
    1 2 3 4 5 6
    Et sigma correspondant :
    4 1 6 2 3 5

    Donc la position 1 (0 dans sage) envoie dans 4, 2 dans 1, etc.

    Je voulais partir d'une liste vide p=[].
    Pour le premier cycle, je regarde à la position 1 (donc 0), et je vois que ça donne 4 (ou a_1 pour être général). Ce nombre est différent de la position 1 (donc différent de 0), je rajoute ce nombre dans p et ensuite, je regarde à la position a_1 (donc a_1 -1 dans SAGE), et je regarde son image, si cela vaut 1 ou pas. Si oui, je m'arrête là et sinon, je rajoute la valeur dans p et je continue.
    Donc pour cette partie, même si je fais une liste a qui prend toutes les valeurs de a_i, je suis incapable d'écrire la bouche qui regarde l'image de l'image de l'image de…

    Une fois que j'ai fait tout ça, je regarde un nombre qui n'est pas dans a, et j'itère mon algorithme ci-dessus. Et j'ai un second cycle.

    J'itère jusqu'au moment où j'ai regardé l'image de tous les nombres de 1 à n (où n est la longueur de mon sigma).
  • Miniportecle a écrit:
    je voulais partir d'une liste vide p
    Cette liste est destinée à accumuler quoi ? Un cycle ? des cycles ?
    Ne serait-il pas plus clair d'avoir une liste qui contient tous les cycles calculés jusque là et une liste temporaire qui contient le cycle en train de se construire ?
    Miniportecle a écrit:
    et je continue
    Jusqu'à quand ? Tu vas traduire ça par une condition d'arrêt qui porte sur quelle(s) variable(s) ?

    Avant de faire une fonction qui décompose en cycle, pourrais-tu décrire un algorithme (ça veut dire qu'il faut expliciter les boucles sous forme "for ..." ou "while..." et surtout toutes les variables) correspondant au sous-problème suivant :
    données :
        sigma = liste d'entiers tous différents de 1 au nombre d'éléments de la liste
        k = un entier entre 1 et le nombre d'éléments de sigma
    sortie :
        c = liste qui décrit le cycle contenant k dans la décomposition de sigma en produits de cycles disjoints
    
  • Math Cross a écrit:
    Cette liste est destinée à accumuler quoi ? Un cycle ? des cycles ?
    Ne serait-il pas plus clair d'avoir une liste qui contient tous les cycles calculés jusque là et une liste temporaire qui contient le cycle en train de se construire ?
    C'est ce que j'ai fait, pp étant la liste de tous les cycles et p la liste temporaire qui contient le cycle en construction.
    Math Cross a écrit:
    Jusqu'à quand ? Tu vas traduire ça par une condition d'arrêt qui porte sur quelle(s) variable(s) ?

    Jusqu'au moment où je trouve sigma = 1. C'est ce que j'ai écrit dans mon code
                    while i<l:
                        r=s[i-1] # Car SAGE commence à compter de 0
                        p.append(r) # Je rajoute cette valeur trouvée dans ma liste
                        if r!=(i): # Si l'image est différent de la position, je regarde l'image de l'image
                            r=s[r-1]
                            p.append(r) # Je rajoute la nouvelle valeur dans ma liste
                        else:
                            print(p)
    
    Donc tant que i<l, je regarde son image par sigma. Si cette image (que j'appelle r ici) est différente de i (par exemple i = 1), je continue mon algorithme en lui appliquant encore sigma (à r-1 car sage commence à 0) jusqu'au moment où je trouve r = i et j'arrête. Tant que je ne trouve pas r=i, je rajoute r dans ma liste p. Et une fois que j'ai trouvé r=i, je print juste p qui est mon cycle.
    Ensuite, j'utilise la partie supérieure de mon algorithme, je varie mon i de telle sorte que i ne soit pas encore dans p.
        for i in (c): # Je cherche la position i dans c qui me donne une valeur qui n'est pas encore dans p
            lp=len(p)
            j=0
            while j<lp:
                if i==p[j]:
                    j=j+1
                else: # Une fois que j'ai trouvé une valeur i qui n'est pas encore dans un cycle p, je regarde ce que donne i
    
    Math Cross a écrit:
    Avant de faire une fonction qui décompose en cycle, pourrais-tu décrire un algorithme (ça veut dire qu'il faut expliciter les boucles sous forme "for ..." ou "while..." et surtout toutes les variables) correspondant au sous-problème suivant :
    # Soit list une liste, je cherche une liste d'entiers tous différents de 1 au nombre d'éléments de la liste
    a=len(list)
    b=range(2,a)
    # k = un entier entre 1 et le nombre d'éléments de sigma
    r=range(1,a)
    for r in c:
    

    Pour la sortie, je suis en train de faire.
  • Math Cross a écrit:

    Avant de faire une fonction qui décompose en cycle, pourrais-tu décrire un algorithme (ça veut dire qu'il faut expliciter les boucles sous forme "for ..." ou "while..." et surtout toutes les variables) correspondant au sous-problème suivant :
    données :
        sigma = liste d'entiers tous différents de 1 au nombre d'éléments de la liste
        k = un entier entre 1 et le nombre d'éléments de sigma
    sortie :
        c = liste qui décrit le cycle contenant k dans la décomposition de sigma en produits de cycles disjoints
    


    En fait, je ne comprends pas… Désolé…
  • Dans ta boucle qui commence par "while i<l", vu que ni i ni l ne changent par la suite, qu'espères-tu qu'il se passe ? Comment pourrait-on sortir de la boucle ? (Pourquoi le test $i<\ell$ serait-il pertinent au fait ?)

    Mais surtout, reprendre des morceaux de code qui ne marchent pas en les commentant, eh bien, ça ne les fera pas marcher.

    Visiblement, tu n'as pas éclairci ce qu'il faut faire : nous n'en sommes pas au stade des virgules, il y a des problème de conception de l'algorithme. Pour t'en convaincre, joue le rôle de l'ordinateur et constate que tes instructions ne permettent pas de sortir quoi que ce soit.

    Revenons en arrière s'il te plaît : décris les étapes à faire pour décrire le cycle qui contient un élément k.

    Au passage, une astuce : il y a une instruction simple qui permet de tester si un élément k est dans une liste L : "if k in L:" (cela évite de faire une boucle sur les éléments de L et de tester s'il y en a un égal à k). Et une remarque : si un élément apparaît dans la liste qui décrit un cycle en train de se construire, a priori c'est le premier, sinon il y a un problème. Donc l'instruction précédente ne sert à rien a priori...
  • Le problème, c'est d'écrire une fonction cycle(sigma,k) qui prend en entrée une liste sigma (par exemple [5,4,6,1,2,3], que l'on interprète comme une permutation (dans l'exemple : $\sigma(1)=2$, $\sigma(2)=4$, etc.) et un entier k pas trop grand (qui apparaît dans sigma) et qui renvoie une liste qui est le cycle des images successives de k par sigma.

    Par exemple, il faudrait que :
    • cycle([5,4,6,1,2,3],1) renvoie [1,5,2,4] (ou une permutation circulaire) ;
    • cycle([5,4,6,1,2,3],2) renvoie [1,5,2,4] (ou une permutation circulaire) ;
    • cycle([5,4,6,1,2,3],3) renvoie [3,6] (ou une permutation circulaire) ;
    • etc.
  • Bonjour
    Je suis arrivé à ce stade-ci :
    def cycle(sigma,k):
        ss=sigma
        s=deepcopy(ss)
        p=[]
        r=s[k-1]
        if r!=k:
            p.append(k)
            while r!=k:
                p.append(r)
                r=s[r-1]
        return(p)
    
    def my_cycles_perm(sigma):
        ss=sigma
        s=deepcopy(ss)
        l=len(ss)
        p=[]                      # On commence par une liste vide
        k=1                        
        while k<l:
            yy=cycle(sigma,k)     # On veut le cycle de permutations pour k
            if p==[]:             # Si on au départ, la liste est vide, on rajoute le cycle précédent
                p.append(yy)
            if p!=[]:             # Si c'est non vide, il faut d'abord vérifier que le cycle n'est pas déjà dans p
                y=Set(yy)         # On utilise la fonction Set pour ne vérifier que les éléments dans les listes
                ll=len(p)
                c=range(ll)
                i=0               # On commence par vérifier pour le premier élément de la liste des listes de p
                ens=Set(p[ i])    # On définit les ensembles des listes dans p
                last=Set(p[ll-1]) # On appelle last, le dernier ensemble dans la liste des listes de p
                if y!=ens:        # Et si y est différent d'un ensemble de la liste p,
                    while i<ll:   # Tant que i est plus petit que la longueur de la liste p
                        i=i+1     # on passe à la vérification de l'élément suivant, (sinon on fait k=k+1)
                        if y!=last: # Si après vérification de tous les i, à chaque fois c'est différent, on arrive au dernier élément de la liste p et que c'est différent, alors on l'ajoute dans p
                            p.append(yy)
            k=k+1
        return(p)
    
    
    Deux problèmes :
    1) Lorsque sigma commence par un 1 (par exemple [1,4,2,3]), j'ai un cycle vide donné en premier. Ou plus généralement quand un entier i est à la sa position i.
    2) Pour sigma = [4,1,6,2,3,5], ma fonction donne bien 4,2,1],[6,5,3 mais pour sigma comme [4,1,6,2,5,7,3], ma fonction ne fonctionne plus… Cela me donne 1, 4, 2], [3, 6, 7], [], [], [6, 7, 3], [6, 7, 3], [6, 7, 3], [6, 7, 3
  • 1) A quoi te sert de faire une copie de sigma dans "cycle" et dans "my_cycles_perm" alors que tu ne modifies jamais sigma ? Dans le pire des cas, tu auras copié n+1 fois ta liste... pour rien !

    2) Tu devrais t'affranchir d'une des difficultés en supposant que ta permutation sigma est une permutation de {0,1,...,n-1} au lieu d'une permutation de {1,...,n}. Cela éviterait d'avoir recours à des changements d'indices.

    3) Tu n'as toujours pas décrit ton algorithme correctement avant d'essayer de le traduire en Python. Le résultat est un charabia qui, de temps en temps produit quelque chose qui ressemble à ce que tu veux... et la plupart du temps renvoie n'importe quoi.
    Il faudrait que tu l'écrives en bon français, en ayant conscience des variables nécessaires pour stocker les différentes informations. Tu devrais constater que, pour l'instant, tu fais bien plus compliqué que nécessaire !

    Ton algorithme devrait ressembler à quelque chose du genre :
      J'initialise une liste des cycles à une liste vide.
      Tant qu'il reste des indices non traités dans ma permutation :
        Je cherche le plus petit indice non traité
        J'initialise un cycle avec cet indice
        Tant que je ne suis pas retombé sur cet indice :
          L'indice est remplacé par son image par sigma
          La nouvelle valeur est ajoutée au cycle
        Le nouveau cycle est ajouté à la liste de cycles
      Je renvoie la liste des cycles
    
Connectez-vous ou Inscrivez-vous pour répondre.