IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Changer la numérotation d'un sommaire


Sujet :

Langage Perl

  1. #41
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    La version qui fournit le résultat sous forme de simple hash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #!/usr/bin/perl
     
    use strict;
    use warnings;
    use feature qw(:5.14);
     
    use Data::Dumper;
    my @sections = qw(i* i-a i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b );
     
    say Data::Dumper->Dump([\@sections], [qw(*sections)]);
     
    my %new_sections;
    my ($level, @level, @changes) = (0, []);
    while (my $num = shift @sections) {
      $level = -1 + split /-/, $num;
      my $old_num = $num;
      my $to_remove = $num =~ s/\*$//;
      push @level, [] if    $level > @level-1;
      pop  @level     while $level < @level-1;
     
      $num =~ s/$_->[0]/$_->[1]/ foreach @changes;
      push @{$level[$level]}, $num;
      if ($to_remove) {
        $new_sections{ $old_num } = "0-$num" ;
        push @changes, [ "^".quotemeta "$num-", "0-$num-" ];
      }
      else {
        my $new_num = shift @{$level[$level]};
        push @changes, [ "^".quotemeta "$num-", "$new_num-" ];
        $new_sections { $old_num } = $new_num ;
      }
    }
     
    $Data::Dumper::Sortkeys++;
    say Data::Dumper->Dump([\%new_sections], [qw(*new_sections)]);
    Résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    $ perl sommaire2hash.pl
    @sections = (
                  'i*',
                  'i-a',
                  'i-b',
                  'ii',
                  'ii-a*',
                  'ii-b',
                  'ii-b-A',
                  'ii-b-B',
                  'ii-b-C',
                  'iii*',
                  'iii-a',
                  'iii-b',
                  'iv',
                  'iv-a',
                  'iv-b'
                );
     
    %new_sections = (
                      'i*' => '0-i',
                      'i-a' => '0-i-a',
                      'i-b' => '0-i-b',
                      'ii' => 'i',
                      'ii-a*' => '0-i-a',
                      'ii-b' => 'i-a',
                      'ii-b-A' => 'i-a-A',
                      'ii-b-B' => 'i-a-B',
                      'ii-b-C' => 'i-a-C',
                      'iii*' => '0-iii',
                      'iii-a' => '0-iii-a',
                      'iii-b' => '0-iii-b',
                      'iv' => 'ii',
                      'iv-a' => 'ii-a',
                      'iv-b' => 'ii-b'
                    );
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  2. #42
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Bonsoir,

    Tout est OK. J'ai fait mon programme et tout fonctionne à merveille.
    Seul hic :

    my @sections = qw(i* i-a* i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b );
    Cela double le préfixe : 'i-a*' => '0-0-i-a',.

    Bon, pas grave, une regex pour supprimer les préfixes en plus et c'est réglé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foreach ( values %new_sections) { s/^(?:0-)+/0-/g; }
    Merci à tous

  3. #43
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Code directement intégrable dans la boucle principale, comme ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #!/usr/bin/perl
     
    use strict;
    use warnings;
    use feature qw(:5.14);
     
    use Data::Dumper;
    my @sections = qw(i* i-a* i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b );
     
    say Data::Dumper->Dump([\@sections], [qw(*sections)]);
     
    my %new_sections;
    my ($level, @level, @changes) = (0, []);
    while (my $num = shift @sections) {
      $level = -1 + split /-/, $num;
      my $old_num = $num;
      my $to_remove = $num =~ s/\*$//;
      push @level, [] if    $level > @level-1;
      pop  @level     while $level < @level-1;
     
      $num =~ s/$_->[0]/$_->[1]/ foreach @changes;
      push @{$level[$level]}, $num;
      if ($to_remove) {
        my $new_num = $num =~ s/^(?:0-)?/0-/r;
        $new_sections{ $old_num } = $new_num ;
        push @changes, [ "^".quotemeta "$num-", "$new_num-" ];
      }
      else {
        my $new_num = shift @{$level[$level]};
        push @changes, [ "^".quotemeta "$num-", "$new_num-" ];
        $new_sections { $old_num } = $new_num ;
      }
    }
     
    $Data::Dumper::Sortkeys++;
    say Data::Dumper->Dump([\%new_sections], [qw(*new_sections)]);
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  4. #44
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut

  5. #45
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    En fait, ce n'est pas bon !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    %new_sections = (
                      'i*' => '0-i',
                      'i-a*' => '0-i-a',
                      'i-b' => '0-i-a',
                      'ii' => 'i',
                      'ii-a*' => '0-i-a',
                      'ii-b' => 'i-a',
                      'ii-b-A' => 'i-a-A',
                      'ii-b-B' => 'i-a-B',
                      'ii-b-C' => 'i-a-C',
                      'iii*' => '0-iii',
                      'iii-a' => '0-iii-a',
                      'iii-b' => '0-iii-b',
                      'iv' => 'ii',
                      'iv-a' => 'ii-a',
                      'iv-b' => 'ii-b'
                    );
    'i-a*' => '0-i-a',
    'i-b' => '0-i-a',
    Doublon !

  6. #46
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par djibril Voir le message
    Merci à vous deux.
    Effectivement philou, ta solution rendant l'indépendance au type de numérotation est vraiment bien.
    cmcmc, ton algo est aussi pas mal. C'est vrai que les étoiles ont disparu dans ta solution comme l'a précisé philou.
    ...
    Je vais donc lire ces fichiers, extraire le sommaire sous forme de tableaux (c'est plus simple). Ensuite je le soumets à l'un de vos codes qui me recalcule le sommaire. Ayant, la correspondance ancien => nouveau, il me suffit de relire les fichiers pour appliquer la nouvelle numérotation. De la même façon, le 0- est juste pour les identifier.

    Voilà !
    Ah non pas Voilà ! Il y a encore plein de choses à dire et à faire !

    D'abord je dois dire que je trouve cette discussion fascinante. Clairement Philou67430 et moi-même avont abordé le problème selon deux perspectives assez différentes, même si nous nous rejoignons tous les deux sur l'exploitation du fait que la séquence des numéros est préordonnée. Pour en avoir un peu bavé pour gérer les différents systèmes de numérotation c'est presque vexant qu'il puisse les ignorer aussi superbement

    Rétrospectivement, il me semble que plusieurs considérations ont parasité le développement des méthodes :
    1. la structure de données (hash, tableau,...) sur laquelle on était censés travailler. Je crois que mon inspiration initiale de dire qu'il suffisait de travailler sur la liste (ordonnée) des numéros était correcte
    2. la gestion de différents systèmes de numérotation : c'est sans doute quelque chose à réserver à un post traitement si ça simplifie les choses de travailler sur des numéros entiers (1-1, 1-2, 1-2-1, 1-2-2, etc.)
    3. le préfixage par 0- : ça me semble une complication un peu inutile dans la mesure où, une fois qu'on dispose du hash de renumérotation new => old (ou son inverse), il est trivial de préfixer tous les numéros non renumérotés


    Je crois notamment que ce dernier point risque de pénaliser la méthode de Philou67430 si on commence à la regarder du point de vue complexité algorithmique (en lecture superficielle, j'ai le sentiment que @level est bien géré mais j'ai de sérieuses inquiétudes sur @changes, et donc sur le nombre de s/// à réaliser...)

    Les deux méthodes sont mono-passes et séquentielles, ce qui veut dire qu'on peut les repackager de manière à traiter les numéros à la volée. Pour toi djibril, ça signifie qu'il peut y avoir une stratégie alternative à celle que tu proposes : au lieu de
    Je vais donc lire ces fichiers, extraire le sommaire sous forme de tableaux (c'est plus simple). Ensuite je le soumets à l'un de vos codes qui me recalcule le sommaire. Ayant, la correspondance ancien => nouveau, il me suffit de relire les fichiers pour appliquer la nouvelle numérotation.
    on peut envisager
    lors de la lecture, à chaque fois qu'on trouve un numéro, on peut le modifier en direct et passer au suivant
    c'est ce que je veux dire par traitement "à la volée". Tu pourrais ainsi traiter ton fichier en une seule passe. Imagine par exemple que tu veuilles réindexer wikipedia

    Par ailleurs avec un traitement à la volée on va pouvoir tester les méthodes sur des sommaires virtuels arbitraires.

    Accrochez vos ceintures, c'est parti

    Citation Envoyé par Philou67430 Voir le message
    La version qui fournit le résultat sous forme de simple hash :
    On part de la dernière version de Philou67430. Pour se faciliter les tests, on va la mettre dans un module, et la modifier pour travailler 'à la volée' : pour celà il suffit de virer la boucle externe qui itère sur la liste. Par contre on doit conserver quelque part les variables qui servent d'une itération à l'autre, en l'occurrence @level, @changes, et %new_sections. Une manière de faire proprement (sans utiliser de variables globales) est d'utiliser une fermeture (closure) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    { # cette accolade ouvrante introduit un espace privé
        my (@level, @change, %new_sections) = [];
        sub {
            # cette fonction (anonyme) peut modifier @level, @changes et %new_sections
            # et leur état sera conservé d'une itération à l'autre
        }
    }
    # @level, @changes et %new_sections ne sont plus accessibles ici
    que l'on va intégrer dans une infrastructure qui nous permette de nous en servir, et qui va constituer notre module
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # Philou67430_v1.pm
    package Philou67430_v1;
    use strict;
    use warnings;
    use 5.010;
    
    sub transformateur {
        my $balaye = shift;
    
        my (@level, @changes, %new_sections) = ();
        my %stats;
        my $a_la_volee = sub { 
    	my $num = shift;
    
    	my $level = -1 + split /-/, $num;
    	my $old_num = $num;
    	my $to_remove = $num =~ s/\*$//;
    	push @level, [] if    $level > @level-1;
    	pop  @level     while $level < @level-1;
    	
    	$stats{substitutions}++, $num =~ s/$_->[0]/$_->[1]/ foreach @changes;
    	push @{$level[$level]}, $num;
    	if ($to_remove) {
    	    push @changes, [ "^".quotemeta "$num-", "0-$num-" ];
    	    $new_sections{ $old_num } = "0-$num" ;
    	}
    	else {
    	    my $new_num = shift @{$level[$level]};
    	    push @changes, [ "^".quotemeta "$num-", "$new_num-" ];
    	    $new_sections { $old_num } = $new_num ;
    	}
        };
    
        $balaye->($a_la_volee, @_);
        return wantarray ? (\%new_sections, \@level, \@changes, \%stats) : \%new_sections;
    }
    
    1;
    Il y a très peu de changements par rapport au code d'origine. J'ai inversé les deux lignes en bleu pour éviter d'avoir à ajouter un return $new_sections{$old_num} en fin de fonction, et j'ai ajouté %stats pour capturer le nombre de substitutions effectuées (en rouge).

    Le code de Philou67430 est en gros celui en gras ci-dessus, la fonction elle même étant définie comme une fonction anonyme (c'est important mais hors sujet ici) à laquelle on accède via la variable $a_la_volee. Le reste est l'infrastructure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    sub transformateur {
        my $balaye = shift;
     
        ...
     
        $balaye->($a_la_volee, @_);
        return wantarray ? (\%new_sections, \@level, \@changes, \%stats) : \%new_sections;
    }
    On a défini une fonction transformateur, qui prend comme premier paramètre une (référence à une) fonction de balayage, et qui invoque cette dernière avec comme premier paramètre une référence à notre belle fonction a_la_volee, et comme autres paramètres ceux passés en plus lors de l'appel à transformateur. Ça va être la responsabilité de la fonction de balayage par exemple de naviguer dans des fichiers, d'en extraire un sommaire, et pour chaque numéro d'invoquer a_la_volee pour obtenir un nouveau numéro, de modifier les fichiers en conséquence, et de passer au suivant jusqu'à ce qu'elle ait fini son traitement.

    Notez bien que ni transformateur ni a_la_volee n'ont la moindre idée de comment la fonction de balayage va s'y prendre; transformateur pourra lui relayer -- sans même les regarder -- quelques paramètres pour qu'elle puisse travailler, mais c'est tout.

    Par contre transformateur est effectivement liée à la méthode utilisée par a_la_volee, notamment par le fait qu'elle peut retourner tout ou partie des variables capturées dans la fermeture et utilisées par a_la_volee ; elle va rendre la main quand le balayage aura fini son travail -- et donc en principe traité l'ensemble du sommaire --, et c'est le bon moment pour retourner des statistiques ou la table de correspondance qui a été construite.

    On va laisser djibril développer une fonction de balayage adaptée à son propre besoin, qui pourrait avoir la forme suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    sub balayage_et_modification_de_fichiers_xml_en_une_traite {
        my ($renum, @autres_parametre) = @_;
        for my $entree (recherche_des_entrees_de_sommaire(@autres_parametres)) {
            my $old = extraire_numero($entree); # ou peut-être $entree->numero()
            my $new = $renum->($old);
    	modifier_numero($entree, $new); # ou peut-être $entree->modifier_numero($new)
        }
    }
    mais s'il veut rester sur sa stratégie initiale, rien de l'empêche de développer plutôt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    sub balayage_et_modification_de_fichiers_xml_en_deux_passes {
        my ($renum, @autres_parametre) = @_;
        my @liste = extraire_le_sommaire_sous_forme_de_tableaux(@autres_parametres);
        my %hash = map { $_ => $renum->($_) } @liste;
        relire_les_fichiers_pour_appliquer_la_nouvelle_numerotation(%hash, @autres_parametres);
    }
    c'est son problème, sa cuisine, tout ça ne nous regarde pas

    Nous, on avait dit qu'on voulait tester des choses. Eh bien faisons le, en commençant par vérifier que la nouvelle version fonctionne. Pour cela, on va se simplifier la vie, en essayant de modifier en place des listes de numéros, par exemple la dernière utilisée par Philou67430, et en vérifiant qu'on obtient bien le même résultat que lui :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    # t1.pl
    use strict;
    use warnings;
    use Philou67430_v1;
    use 5.010; 
     
    # notre premiere fonction de balayage et modification de sommaire. 
    sub balaye_et_modifie_liste {
        my ($renum, $liste) = @_;
        $_ = $renum->($_) for @$liste;
    }
     
    my @sections = qw(i* i-a i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b );
    # on utilise les résultats obtenus par Philou67430
    my %new_sections = (
                      'i*' => '0-i',
                      'i-a' => '0-i-a',
                      'i-b' => '0-i-b',
                      'ii' => 'i',
                      'ii-a*' => '0-i-a',
                      'ii-b' => 'i-a',
                      'ii-b-A' => 'i-a-A',
                      'ii-b-B' => 'i-a-B',
                      'ii-b-C' => 'i-a-C',
                      'iii*' => '0-iii',
                      'iii-a' => '0-iii-a',
                      'iii-b' => '0-iii-b',
                      'iv' => 'ii',
                      'iv-a' => 'ii-a',
                      'iv-b' => 'ii-b'
                    );
    # voilà comment devrait être la liste après modifications
    my @voulu = map $new_sections{$_}, @sections;
     
     
    say "avant: @sections";
    Philou67430_v1::transformateur(\&balaye_et_modifie_liste, \@sections);
    say "apres: @sections";
    say "voulu: @voulu";
     
    use Test::More;
    is_deeply(\@sections, \@voulu, "notre première liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    ta daaaa... suspens...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Taisha:~/tttmp/sommaire $ perl t1.pl
    avant: i* i-a i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b
    apres: 0-i 0-i-a 0-i-b i 0-i-a i-a i-a-A i-a-B i-a-C 0-iii 0-iii-a 0-iii-b ii ii-a ii-b
    voulu: 0-i 0-i-a 0-i-b i 0-i-a i-a i-a-A i-a-B i-a-C 0-iii 0-iii-a 0-iii-b ii ii-a ii-b
    ok 1 - notre première liste (15 éléments) a bien été modifiée comme attendu
    1..1
    Taisha:~/tttmp/sommaire $
    oui oui oui oui oui oui ça marche !
    Notez l'utilisation de Test::More : dès qu'on peut automatiser un test, on a tout intérêt à le faire parce que l'inspection visuelle c'est fatigant et qu'on n'est pas à l'abri d'une faute d'inattention... On peut ainsi vérifier avec d'autres données de test, en changeant simplement @sections et %new_sections (impressions omises) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    # t2.pl
    use strict;
    use warnings;
    use Philou67430_v1;
    use 5.010; 
     
    # notre premiere fonction de balayage et modification de sommaire. 
    # 
    sub balaye_et_modifie_liste {
        my ($renum, $liste) = @_;
        $_ = $renum->($_) for @$liste;
    }
     
    my @sections = qw(I* I-A I-A-1 I-A-1-a I-A-2 I-A-2-a I-A-2-b I-A-2-c I-A-3 I-A-3-a
    I-A-3-b I-A-3-c I-A-3-d I-A-3-e I-A-4 I-B I-B-1 I-B-1-a I-B-1-b
    I-B-1-c I-B-1-d I-B-1-e I-B-2 I-B-2-a I-B-2-b I-B-2-c I-B-3 I-B-3-a
    I-B-3-b I-B-3-c I-B-4 I-B-5 I-B-5-a I-B-5-b I-B-5-c I-B-6 I-B-6-a
    I-B-6-b II* II-A II-A-1 II-A-2 II-A-3 II-A-3-a II-A-3-b II-A-3-c
    II-A-3-d II-A-4 II-A-5 II-A-6 II-A-7 II-A-8 II-B II-B-1 II-B-1-a
    II-B-1-b II-B-1-c II-B-1-d II-B-2 II-B-2-a II-B-2-b II-B-2-c II-B-2-d
    II-B-2-e II-B-3 II-B-3-a II-B-3-b II-B-3-c II-B-3-d II-B-3-e II-B-4
    II-B-4-a II-B-4-b II-B-4-c II-C II-C-1 II-C-1-a II-C-1-b II-C-2
    II-C-2-a II-C-2-b II-C-2-c II-C-2-d II-C-3 II-C-4 II-C-4-a II-C-4-b
    II-C-4-c II-D II-D-1 II-D-1-a II-D-1-b II-D-1-c II-D-2 II-D-2-a
    II-D-2-b II-D-2-c II-D-2-d II-D-2-e II-D-2-f II-D-2-g II-D-3 II-D-3-a
    II-D-3-b II-D-3-c II-D-4 II-D-4-a II-D-4-b II-D-4-c II-D-4-d III*
    III-A III-A-1 III-A-1-a III-A-1-b III-A-2 III-A-3 III-A-3-a III-A-3-b
    III-A-4 III-A-4-a III-A-4-b III-A-4-c III-A-5 III-A-5-a III-A-5-b
    III-A-5-c III-A-5-d III-B III-B-1 III-B-1-a III-B-1-b III-B-2
    III-B-2-a III-B-2-b III-B-3 III-B-3-a III-B-3-b III-B-3-c III-B-3-d
    III-B-3-e III-B-4 III-B-5 III-C III-C-1 III-C-2 III-C-2-a III-C-2-b
    III-C-2-c III-C-2-d III-C-3 III-D III-D-1 III-D-1-a III-D-1-b
    III-D-1-c III-D-2 III-D-2-a III-D-2-b III-D-3 III-D-3-a III-D-3-b
    III-D-3-c III-D-3-d III-D-3-e III-D-3-f III-D-3-g IV* IV-A IV-A-1
    IV-A-1-a IV-A-1-b IV-A-1-c IV-A-1-d IV-A-2 IV-A-2-a IV-A-2-b IV-A-2-c
    IV-A-2-d IV-A-2-e IV-A-2-f IV-A-2-g IV-A-3 IV-A-3-a IV-A-3-b IV-A-3-c
    IV-A-4 IV-A-4-a IV-A-4-b IV-A-4-c IV-A-4-d IV-A-4-e IV-A-4-f IV-B
    IV-B-1 IV-B-1-a IV-B-1-b IV-B-1-c IV-B-1-d IV-B-1-e IV-B-2 IV-B-2-a
    IV-B-2-b IV-B-2-c IV-B-2-d IV-B-3 IV-B-3-a IV-B-3-b IV-C IV-C-1 IV-C-2
    IV-C-3 IV-C-4 IV-C-5 IV-C-6 IV-C-7 IV-C-7-a IV-C-8 IV-C-8-a IV-D
    IV-D-1 IV-D-2 IV-D-3 IV-D-4 IV-D-5 IV-D-6 IV-D-6-a IV-D-6-b IV-D-6-c
    IV-D-6-d IV-E IV-E-1 IV-E-2 IV-E-3 IV-E-4 IV-E-5 IV-E-6 IV-F IV-F-1
    IV-F-2 IV-F-3 IV-G IV-G-1 IV-G-1-a IV-G-1-b IV-G-1-c IV-G-1-d IV-G-1-e
    IV-G-1-f IV-G-1-g IV-G-2 IV-G-2-a IV-G-2-b IV-G-2-c IV-G-2-d IV-G-3
    IV-G-3-a IV-G-3-b IV-G-3-c IV-G-3-d V* V-A V-A-1 V-A-2 V-A-3 V-B V-B-1
    V-B-2 V-B-2-a V-B-2-b V-B-3 V-B-4 V-B-4-a V-B-4-b V-B-4-c V-B-4-d
    V-B-5 V-B-6 V-B-7 V-C V-C-1 V-C-1-a V-C-1-b V-C-1-c V-C-1-d V-C-1-e
    V-C-1-f V-C-2 V-C-2-a V-C-2-b V-C-2-c V-C-2-d V-C-2-e V-C-2-f V-D
    V-D-1 V-D-1-a V-D-1-b V-D-1-c V-D-2 V-D-2-a V-D-2-b V-D-2-c V-E V-E-1
    V-E-2 V-E-3 V-F VI VI-A VI-A-1 VI-A-1-a VI-A-1-b VI-A-1-c VI-A-2
    VI-A-2-a VI-A-2-b VI-A-2-c VI-A-2-d VI-A-2-e VI-B VI-B-1 VI-B-1-a
    VI-B-1-b VI-B-1-c VI-B-1-d VI-B-1-e VI-B-2 VI-B-2-a VI-B-2-b VI-B-2-c
    VI-B-2-d VI-B-2-e VI-B-3 VI-B-3-a VI-B-4 VI-B-4-a VI-B-4-b VI-B-4-c
    VI-B-4-d VI-B-5 VI-B-5-a VI-B-5-b VI-B-5-c VI-B-5-d VI-B-5-e VI-C
    VI-C-1 VI-C-1-a VI-C-1-b VI-C-1-c VI-C-1-d VI-C-1-e VI-C-2 VI-C-3
    VI-C-4 VI-C-4-a VI-C-4-b VI-C-4-c VI-C-4-d VI-C-4-e VII*
    );
    my %new_sections = (
                      'I*' => '0-I',
                      'I-A' => '0-I-A',
                      'I-A-1' => '0-I-A-1',
                      'I-A-1-a' => '0-I-A-1-a',
                      'I-A-2' => '0-I-A-2',
                      'I-A-2-a' => '0-I-A-2-a',
                      'I-A-2-b' => '0-I-A-2-b',
                      'I-A-2-c' => '0-I-A-2-c',
                      'I-A-3' => '0-I-A-3',
                      'I-A-3-a' => '0-I-A-3-a',
                      'I-A-3-b' => '0-I-A-3-b',
                      'I-A-3-c' => '0-I-A-3-c',
                      'I-A-3-d' => '0-I-A-3-d',
                      'I-A-3-e' => '0-I-A-3-e',
                      'I-A-4' => '0-I-A-4',
                      'I-B' => '0-I-B',
                      'I-B-1' => '0-I-B-1',
                      'I-B-1-a' => '0-I-B-1-a',
                      'I-B-1-b' => '0-I-B-1-b',
                      'I-B-1-c' => '0-I-B-1-c',
                      'I-B-1-d' => '0-I-B-1-d',
                      'I-B-1-e' => '0-I-B-1-e',
                      'I-B-2' => '0-I-B-2',
                      'I-B-2-a' => '0-I-B-2-a',
                      'I-B-2-b' => '0-I-B-2-b',
                      'I-B-2-c' => '0-I-B-2-c',
                      'I-B-3' => '0-I-B-3',
                      'I-B-3-a' => '0-I-B-3-a',
                      'I-B-3-b' => '0-I-B-3-b',
                      'I-B-3-c' => '0-I-B-3-c',
                      'I-B-4' => '0-I-B-4',
                      'I-B-5' => '0-I-B-5',
                      'I-B-5-a' => '0-I-B-5-a',
                      'I-B-5-b' => '0-I-B-5-b',
                      'I-B-5-c' => '0-I-B-5-c',
                      'I-B-6' => '0-I-B-6',
                      'I-B-6-a' => '0-I-B-6-a',
                      'I-B-6-b' => '0-I-B-6-b',
                      'II*' => '0-II',
                      'II-A' => '0-II-A',
                      'II-A-1' => '0-II-A-1',
                      'II-A-2' => '0-II-A-2',
                      'II-A-3' => '0-II-A-3',
                      'II-A-3-a' => '0-II-A-3-a',
                      'II-A-3-b' => '0-II-A-3-b',
                      'II-A-3-c' => '0-II-A-3-c',
                      'II-A-3-d' => '0-II-A-3-d',
                      'II-A-4' => '0-II-A-4',
                      'II-A-5' => '0-II-A-5',
                      'II-A-6' => '0-II-A-6',
                      'II-A-7' => '0-II-A-7',
                      'II-A-8' => '0-II-A-8',
                      'II-B' => '0-II-B',
                      'II-B-1' => '0-II-B-1',
                      'II-B-1-a' => '0-II-B-1-a',
                      'II-B-1-b' => '0-II-B-1-b',
                      'II-B-1-c' => '0-II-B-1-c',
                      'II-B-1-d' => '0-II-B-1-d',
                      'II-B-2' => '0-II-B-2',
                      'II-B-2-a' => '0-II-B-2-a',
                      'II-B-2-b' => '0-II-B-2-b',
                      'II-B-2-c' => '0-II-B-2-c',
                      'II-B-2-d' => '0-II-B-2-d',
                      'II-B-2-e' => '0-II-B-2-e',
                      'II-B-3' => '0-II-B-3',
                      'II-B-3-a' => '0-II-B-3-a',
                      'II-B-3-b' => '0-II-B-3-b',
                      'II-B-3-c' => '0-II-B-3-c',
                      'II-B-3-d' => '0-II-B-3-d',
                      'II-B-3-e' => '0-II-B-3-e',
                      'II-B-4' => '0-II-B-4',
                      'II-B-4-a' => '0-II-B-4-a',
                      'II-B-4-b' => '0-II-B-4-b',
                      'II-B-4-c' => '0-II-B-4-c',
                      'II-C' => '0-II-C',
                      'II-C-1' => '0-II-C-1',
                      'II-C-1-a' => '0-II-C-1-a',
                      'II-C-1-b' => '0-II-C-1-b',
                      'II-C-2' => '0-II-C-2',
                      'II-C-2-a' => '0-II-C-2-a',
                      'II-C-2-b' => '0-II-C-2-b',
                      'II-C-2-c' => '0-II-C-2-c',
                      'II-C-2-d' => '0-II-C-2-d',
                      'II-C-3' => '0-II-C-3',
                      'II-C-4' => '0-II-C-4',
                      'II-C-4-a' => '0-II-C-4-a',
                      'II-C-4-b' => '0-II-C-4-b',
                      'II-C-4-c' => '0-II-C-4-c',
                      'II-D' => '0-II-D',
                      'II-D-1' => '0-II-D-1',
                      'II-D-1-a' => '0-II-D-1-a',
                      'II-D-1-b' => '0-II-D-1-b',
                      'II-D-1-c' => '0-II-D-1-c',
                      'II-D-2' => '0-II-D-2',
                      'II-D-2-a' => '0-II-D-2-a',
                      'II-D-2-b' => '0-II-D-2-b',
                      'II-D-2-c' => '0-II-D-2-c',
                      'II-D-2-d' => '0-II-D-2-d',
                      'II-D-2-e' => '0-II-D-2-e',
                      'II-D-2-f' => '0-II-D-2-f',
                      'II-D-2-g' => '0-II-D-2-g',
                      'II-D-3' => '0-II-D-3',
                      'II-D-3-a' => '0-II-D-3-a',
                      'II-D-3-b' => '0-II-D-3-b',
                      'II-D-3-c' => '0-II-D-3-c',
                      'II-D-4' => '0-II-D-4',
                      'II-D-4-a' => '0-II-D-4-a',
                      'II-D-4-b' => '0-II-D-4-b',
                      'II-D-4-c' => '0-II-D-4-c',
                      'II-D-4-d' => '0-II-D-4-d',
                      'III*' => '0-III',
                      'III-A' => '0-III-A',
                      'III-A-1' => '0-III-A-1',
                      'III-A-1-a' => '0-III-A-1-a',
                      'III-A-1-b' => '0-III-A-1-b',
                      'III-A-2' => '0-III-A-2',
                      'III-A-3' => '0-III-A-3',
                      'III-A-3-a' => '0-III-A-3-a',
                      'III-A-3-b' => '0-III-A-3-b',
                      'III-A-4' => '0-III-A-4',
                      'III-A-4-a' => '0-III-A-4-a',
                      'III-A-4-b' => '0-III-A-4-b',
                      'III-A-4-c' => '0-III-A-4-c',
                      'III-A-5' => '0-III-A-5',
                      'III-A-5-a' => '0-III-A-5-a',
                      'III-A-5-b' => '0-III-A-5-b',
                      'III-A-5-c' => '0-III-A-5-c',
                      'III-A-5-d' => '0-III-A-5-d',
                      'III-B' => '0-III-B',
                      'III-B-1' => '0-III-B-1',
                      'III-B-1-a' => '0-III-B-1-a',
                      'III-B-1-b' => '0-III-B-1-b',
                      'III-B-2' => '0-III-B-2',
                      'III-B-2-a' => '0-III-B-2-a',
                      'III-B-2-b' => '0-III-B-2-b',
                      'III-B-3' => '0-III-B-3',
                      'III-B-3-a' => '0-III-B-3-a',
                      'III-B-3-b' => '0-III-B-3-b',
                      'III-B-3-c' => '0-III-B-3-c',
                      'III-B-3-d' => '0-III-B-3-d',
                      'III-B-3-e' => '0-III-B-3-e',
                      'III-B-4' => '0-III-B-4',
                      'III-B-5' => '0-III-B-5',
                      'III-C' => '0-III-C',
                      'III-C-1' => '0-III-C-1',
                      'III-C-2' => '0-III-C-2',
                      'III-C-2-a' => '0-III-C-2-a',
                      'III-C-2-b' => '0-III-C-2-b',
                      'III-C-2-c' => '0-III-C-2-c',
                      'III-C-2-d' => '0-III-C-2-d',
                      'III-C-3' => '0-III-C-3',
                      'III-D' => '0-III-D',
                      'III-D-1' => '0-III-D-1',
                      'III-D-1-a' => '0-III-D-1-a',
                      'III-D-1-b' => '0-III-D-1-b',
                      'III-D-1-c' => '0-III-D-1-c',
                      'III-D-2' => '0-III-D-2',
                      'III-D-2-a' => '0-III-D-2-a',
                      'III-D-2-b' => '0-III-D-2-b',
                      'III-D-3' => '0-III-D-3',
                      'III-D-3-a' => '0-III-D-3-a',
                      'III-D-3-b' => '0-III-D-3-b',
                      'III-D-3-c' => '0-III-D-3-c',
                      'III-D-3-d' => '0-III-D-3-d',
                      'III-D-3-e' => '0-III-D-3-e',
                      'III-D-3-f' => '0-III-D-3-f',
                      'III-D-3-g' => '0-III-D-3-g',
                      'IV*' => '0-IV',
                      'IV-A' => '0-IV-A',
                      'IV-A-1' => '0-IV-A-1',
                      'IV-A-1-a' => '0-IV-A-1-a',
                      'IV-A-1-b' => '0-IV-A-1-b',
                      'IV-A-1-c' => '0-IV-A-1-c',
                      'IV-A-1-d' => '0-IV-A-1-d',
                      'IV-A-2' => '0-IV-A-2',
                      'IV-A-2-a' => '0-IV-A-2-a',
                      'IV-A-2-b' => '0-IV-A-2-b',
                      'IV-A-2-c' => '0-IV-A-2-c',
                      'IV-A-2-d' => '0-IV-A-2-d',
                      'IV-A-2-e' => '0-IV-A-2-e',
                      'IV-A-2-f' => '0-IV-A-2-f',
                      'IV-A-2-g' => '0-IV-A-2-g',
                      'IV-A-3' => '0-IV-A-3',
                      'IV-A-3-a' => '0-IV-A-3-a',
                      'IV-A-3-b' => '0-IV-A-3-b',
                      'IV-A-3-c' => '0-IV-A-3-c',
                      'IV-A-4' => '0-IV-A-4',
                      'IV-A-4-a' => '0-IV-A-4-a',
                      'IV-A-4-b' => '0-IV-A-4-b',
                      'IV-A-4-c' => '0-IV-A-4-c',
                      'IV-A-4-d' => '0-IV-A-4-d',
                      'IV-A-4-e' => '0-IV-A-4-e',
                      'IV-A-4-f' => '0-IV-A-4-f',
                      'IV-B' => '0-IV-B',
                      'IV-B-1' => '0-IV-B-1',
                      'IV-B-1-a' => '0-IV-B-1-a',
                      'IV-B-1-b' => '0-IV-B-1-b',
                      'IV-B-1-c' => '0-IV-B-1-c',
                      'IV-B-1-d' => '0-IV-B-1-d',
                      'IV-B-1-e' => '0-IV-B-1-e',
                      'IV-B-2' => '0-IV-B-2',
                      'IV-B-2-a' => '0-IV-B-2-a',
                      'IV-B-2-b' => '0-IV-B-2-b',
                      'IV-B-2-c' => '0-IV-B-2-c',
                      'IV-B-2-d' => '0-IV-B-2-d',
                      'IV-B-3' => '0-IV-B-3',
                      'IV-B-3-a' => '0-IV-B-3-a',
                      'IV-B-3-b' => '0-IV-B-3-b',
                      'IV-C' => '0-IV-C',
                      'IV-C-1' => '0-IV-C-1',
                      'IV-C-2' => '0-IV-C-2',
                      'IV-C-3' => '0-IV-C-3',
                      'IV-C-4' => '0-IV-C-4',
                      'IV-C-5' => '0-IV-C-5',
                      'IV-C-6' => '0-IV-C-6',
                      'IV-C-7' => '0-IV-C-7',
                      'IV-C-7-a' => '0-IV-C-7-a',
                      'IV-C-8' => '0-IV-C-8',
                      'IV-C-8-a' => '0-IV-C-8-a',
                      'IV-D' => '0-IV-D',
                      'IV-D-1' => '0-IV-D-1',
                      'IV-D-2' => '0-IV-D-2',
                      'IV-D-3' => '0-IV-D-3',
                      'IV-D-4' => '0-IV-D-4',
                      'IV-D-5' => '0-IV-D-5',
                      'IV-D-6' => '0-IV-D-6',
                      'IV-D-6-a' => '0-IV-D-6-a',
                      'IV-D-6-b' => '0-IV-D-6-b',
                      'IV-D-6-c' => '0-IV-D-6-c',
                      'IV-D-6-d' => '0-IV-D-6-d',
                      'IV-E' => '0-IV-E',
                      'IV-E-1' => '0-IV-E-1',
                      'IV-E-2' => '0-IV-E-2',
                      'IV-E-3' => '0-IV-E-3',
                      'IV-E-4' => '0-IV-E-4',
                      'IV-E-5' => '0-IV-E-5',
                      'IV-E-6' => '0-IV-E-6',
                      'IV-F' => '0-IV-F',
                      'IV-F-1' => '0-IV-F-1',
                      'IV-F-2' => '0-IV-F-2',
                      'IV-F-3' => '0-IV-F-3',
                      'IV-G' => '0-IV-G',
                      'IV-G-1' => '0-IV-G-1',
                      'IV-G-1-a' => '0-IV-G-1-a',
                      'IV-G-1-b' => '0-IV-G-1-b',
                      'IV-G-1-c' => '0-IV-G-1-c',
                      'IV-G-1-d' => '0-IV-G-1-d',
                      'IV-G-1-e' => '0-IV-G-1-e',
                      'IV-G-1-f' => '0-IV-G-1-f',
                      'IV-G-1-g' => '0-IV-G-1-g',
                      'IV-G-2' => '0-IV-G-2',
                      'IV-G-2-a' => '0-IV-G-2-a',
                      'IV-G-2-b' => '0-IV-G-2-b',
                      'IV-G-2-c' => '0-IV-G-2-c',
                      'IV-G-2-d' => '0-IV-G-2-d',
                      'IV-G-3' => '0-IV-G-3',
                      'IV-G-3-a' => '0-IV-G-3-a',
                      'IV-G-3-b' => '0-IV-G-3-b',
                      'IV-G-3-c' => '0-IV-G-3-c',
                      'IV-G-3-d' => '0-IV-G-3-d',
                      'V*' => '0-V',
                      'V-A' => '0-V-A',
                      'V-A-1' => '0-V-A-1',
                      'V-A-2' => '0-V-A-2',
                      'V-A-3' => '0-V-A-3',
                      'V-B' => '0-V-B',
                      'V-B-1' => '0-V-B-1',
                      'V-B-2' => '0-V-B-2',
                      'V-B-2-a' => '0-V-B-2-a',
                      'V-B-2-b' => '0-V-B-2-b',
                      'V-B-3' => '0-V-B-3',
                      'V-B-4' => '0-V-B-4',
                      'V-B-4-a' => '0-V-B-4-a',
                      'V-B-4-b' => '0-V-B-4-b',
                      'V-B-4-c' => '0-V-B-4-c',
                      'V-B-4-d' => '0-V-B-4-d',
                      'V-B-5' => '0-V-B-5',
                      'V-B-6' => '0-V-B-6',
                      'V-B-7' => '0-V-B-7',
                      'V-C' => '0-V-C',
                      'V-C-1' => '0-V-C-1',
                      'V-C-1-a' => '0-V-C-1-a',
                      'V-C-1-b' => '0-V-C-1-b',
                      'V-C-1-c' => '0-V-C-1-c',
                      'V-C-1-d' => '0-V-C-1-d',
                      'V-C-1-e' => '0-V-C-1-e',
                      'V-C-1-f' => '0-V-C-1-f',
                      'V-C-2' => '0-V-C-2',
                      'V-C-2-a' => '0-V-C-2-a',
                      'V-C-2-b' => '0-V-C-2-b',
                      'V-C-2-c' => '0-V-C-2-c',
                      'V-C-2-d' => '0-V-C-2-d',
                      'V-C-2-e' => '0-V-C-2-e',
                      'V-C-2-f' => '0-V-C-2-f',
                      'V-D' => '0-V-D',
                      'V-D-1' => '0-V-D-1',
                      'V-D-1-a' => '0-V-D-1-a',
                      'V-D-1-b' => '0-V-D-1-b',
                      'V-D-1-c' => '0-V-D-1-c',
                      'V-D-2' => '0-V-D-2',
                      'V-D-2-a' => '0-V-D-2-a',
                      'V-D-2-b' => '0-V-D-2-b',
                      'V-D-2-c' => '0-V-D-2-c',
                      'V-E' => '0-V-E',
                      'V-E-1' => '0-V-E-1',
                      'V-E-2' => '0-V-E-2',
                      'V-E-3' => '0-V-E-3',
                      'V-F' => '0-V-F',
                      'VI' => 'I',
                      'VI-A' => 'I-A',
                      'VI-A-1' => 'I-A-1',
                      'VI-A-1-a' => 'I-A-1-a',
                      'VI-A-1-b' => 'I-A-1-b',
                      'VI-A-1-c' => 'I-A-1-c',
                      'VI-A-2' => 'I-A-2',
                      'VI-A-2-a' => 'I-A-2-a',
                      'VI-A-2-b' => 'I-A-2-b',
                      'VI-A-2-c' => 'I-A-2-c',
                      'VI-A-2-d' => 'I-A-2-d',
                      'VI-A-2-e' => 'I-A-2-e',
                      'VI-B' => 'I-B',
                      'VI-B-1' => 'I-B-1',
                      'VI-B-1-a' => 'I-B-1-a',
                      'VI-B-1-b' => 'I-B-1-b',
                      'VI-B-1-c' => 'I-B-1-c',
                      'VI-B-1-d' => 'I-B-1-d',
                      'VI-B-1-e' => 'I-B-1-e',
                      'VI-B-2' => 'I-B-2',
                      'VI-B-2-a' => 'I-B-2-a',
                      'VI-B-2-b' => 'I-B-2-b',
                      'VI-B-2-c' => 'I-B-2-c',
                      'VI-B-2-d' => 'I-B-2-d',
                      'VI-B-2-e' => 'I-B-2-e',
                      'VI-B-3' => 'I-B-3',
                      'VI-B-3-a' => 'I-B-3-a',
                      'VI-B-4' => 'I-B-4',
                      'VI-B-4-a' => 'I-B-4-a',
                      'VI-B-4-b' => 'I-B-4-b',
                      'VI-B-4-c' => 'I-B-4-c',
                      'VI-B-4-d' => 'I-B-4-d',
                      'VI-B-5' => 'I-B-5',
                      'VI-B-5-a' => 'I-B-5-a',
                      'VI-B-5-b' => 'I-B-5-b',
                      'VI-B-5-c' => 'I-B-5-c',
                      'VI-B-5-d' => 'I-B-5-d',
                      'VI-B-5-e' => 'I-B-5-e',
                      'VI-C' => 'I-C',
                      'VI-C-1' => 'I-C-1',
                      'VI-C-1-a' => 'I-C-1-a',
                      'VI-C-1-b' => 'I-C-1-b',
                      'VI-C-1-c' => 'I-C-1-c',
                      'VI-C-1-d' => 'I-C-1-d',
                      'VI-C-1-e' => 'I-C-1-e',
                      'VI-C-2' => 'I-C-2',
                      'VI-C-3' => 'I-C-3',
                      'VI-C-4' => 'I-C-4',
                      'VI-C-4-a' => 'I-C-4-a',
                      'VI-C-4-b' => 'I-C-4-b',
                      'VI-C-4-c' => 'I-C-4-c',
                      'VI-C-4-d' => 'I-C-4-d',
                      'VI-C-4-e' => 'I-C-4-e',
                      'VII*' => '0-VII'
                    );
     
    my @voulu = map $new_sections{$_}, @sections;
     
     
    # say "avant: @sections";
    Philou67430_v1::transformateur(\&balaye_et_modifie_liste, \@sections);
    # say "apres: @sections";
    # say "voulu: @voulu";
     
    use Test::More;
    is_deeply(\@sections, \@voulu, "notre seconde liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    et là encore
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Taisha:~/tttmp/sommaire $ perl t2.pl
    ok 1 - notre seconde liste (362 éléments) a bien été modifiée comme attendu
    1..1
    Taisha:~/tttmp/sommaire $
    On est rassuré, la version à la volée se comporte bien comme la version initiale, et on a maintenant les moyens d'étudier la méthode sous l'angle de la complexité et de la performance. Petite pause café et on s'y colle

    On peut commencer par modifier nos programmes de test pour inspecter les valeurs retournées par transformateur. Comme je le disais, je suis inquiet sur @changes et le nombre de substitutions. Voyons ce que ça donne en modifiant l'appel comme suit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    my ($new_sections, $level, $changes, $stats) = Philou67430_v1::transformateur(\&balaye_et_modifie_liste, \@sections);
    say "taille de \@changes: ", scalar(@$changes);
    say "nombre de substitutions: ", $stats{substitutions};
    on obtient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Taisha:~/tttmp/sommaire $ perl t1a.pl
    taille de @changes: 15
    nombre de substitutions: 105
    ok 1 - notre première liste (15 éléments) a bien été modifiée comme attendu
    1..1
    Taisha:~/tttmp/sommaire $ perl t2a.pl
    taille de @changes: 362
    nombre de substitutions: 65341
    ok 1 - notre seconde liste (362 éléments) a bien été modifiée comme attendu
    1..1
    Taisha:~/tttmp/sommaire $
    et il semble bien que mon intution soit confirmée la taille de @changes ne paraît pas inquiétante, mais on ne peut pas en dire autant du nombre de substitutions...

    A ce stade, on aimerait bien pouvoir passer une grosse liste en paramètre pour voir ce que ça donne. Est-ce qu'on se lance pour autant dans l'écriture d'un t3a.pl, avec une grosse liste d'entrée et une grosse table de résultats ? Ce n'est pas très attractif comme perspective, le t2a.pl était déjà limite...

    Mais au fait, si on maîtrise complètement la génération de la liste et le processus de marquage, on peut vérifier directement dans la fonction de balayage si le résultat est correct à chaque itération, sans générer réellement la liste. Avec ce concept de liste virtuelle, on peut envisager de faire des tests de charge sur des listes arbitrairement grandes ou complexes.

    Mettons ça en oeuvre sur un cas simple. On va considérer des listes régulières de profondeur $p avec $k noeuds à chaque niveau. Ces listes virtuelles sont de la forme
    1 1-1 ... 1-k-..-k
    2 2-1 ... 2-k-..-k
    ...
    k k-1 ... k-k-..-k
    On peut par exemple essayer de marquer tous les noeuds de profondeur 1 (c'est à dire 1 2 3 ...) sauf le dernier ($k). Dans ce cas on sait qu'après modification tous les noeuds doivent être préfixés par 0 sauf les 1+2+...+p = p(p+1)/2 derniers, à savoir k k.1 ... k-k..k, qui sont transformés en 1 1-1 ... 1-k..k
    On va intégrer dans la fonction de balayage des appels à deux fonctions, marque et expect, qui vont respectivement marquer les noeuds comme indiqué et produire pour chaque numéro la valeur attendue. On pourra ensuite tester pour différentes valeurs de $k et $p.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    # t1v.pl
    use strict;
    use warnings;
    use Philou67430_v1;
    use 5.010; 
     
    # balaye et modifie une liste régulière de profondeur $p, 
    # avec $k noeuds à chaque niveau. 
    #  1 1-1 ... 1-k-..-k
    #  2 2-1 ... 2-k-..-k
    #  ...
    #  k k-1 ... k-k-..-k
    # cette liste contient k*(1 + 2 + ... + p) = k*p*(p+1)/2 élements
     
    sub balaye_et_modifie_liste_virtuelle_reguliere {
        my ($renum, $marque, $expect, $k, $p, $debug) = @_;
        for my $top (1 .. $k) {
    	my $num = $marque->($top, $k, $p);
    	my $exp = $expect->($top, $k, $p);
    	my $new = $renum->($num);
    	die "$num -> $new au lieu de $exp"
    	    if $renum->($num) ne $exp;
    	print "$num/$new" if $debug;
    	balaye_sous_liste($renum, $marque, $expect, $top, $k, $p-1, $debug);
    	print "\n" if $debug;
        }
    }
     
    sub balaye_sous_liste {
        my ($renum, $marque, $expect, $parent, $k, $p, $debug) = @_;
        return unless $p;
        for (1 .. $k) {
    	my $num = $marque->("$parent-$_", $k, $p);
    	my $exp = $expect->($num, $k, $p);
    	my $new = $renum->($num);
    	die "$num -> $new au lieu de $exp"
    	    if $renum->($num) ne $exp;	
    	print " $num/$new" if $debug;
    	balaye_sous_liste($renum, $marque, $expect, $num, $k, $p-1, $debug);
        }	
    }
     
     
    # Tous les noeuds de profondeur 1 sont marqués sauf le dernier : 
    # après modification tous les noeuds doivent être préfixés par 0
    # sauf les p derniers (k k.1 ... k-k..k) qui sont
    # transformés en      (1 1-1 ... 1-k..k)
    sub marque_top_but_last {
        my ($num, $k, $p) = @_;
        ($num =~ m/^\d+$/ && $num != $k)
    	? "$num*"
    	: $num;
    }
     
    sub expect_top_but_last {
        my ($num, $k, $p) = @_;
        $num =~ m/^$k-?/
    	? $num =~ s/^\d+/1/r
    	: "0-$num";
    }
     
    for my $k (2 .. 4) {
        say "------- k = $k, p = $k";
        my ($new_sections, $level, $changes, $stats)
    	= Philou67430_v1::transformateur(\&balaye_et_modifie_liste_virtuelle_reguliere,
    					 \&marque_top_but_last,
    					 \&expect_top_but_last,
    					 $k, $k, ($k <= 3));
        say "taille de \@changes: ", scalar(@$changes);
        say "nombre de substitutions: ", $stats->{substitutions};
    }
    Voilà ce que ça donne pour $k allant de 2 à 4, avec $p == $k. Pour faire un peu de validation visuelle j'ai activé l'impression des listes avant/après pour $k <= 3. Ça a l'air correct :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    Taisha:~/tttmp/sommaire $ perl tv1.pl
    ------- k = 2, p = 2
    1*/0-1 1-1/0-1-1 1-2/0-1-2
    2/1 2-1/1-1 2-2/1-2
    taille de @changes: 12
    nombre de substitutions: 66
    ------- k = 3, p = 3
    1*/0-1 1-1/0-1-1 1-1-1/0-1-1-1 1-1-2/0-1-1-2 1-1-3/0-1-1-3 1-2/0-1-2 1-2-1/0-1-2-1 1-2-2/0-1-2-2 1-2-3/0-1-2-3 1-3/0-1-3 1-3-1/0-1-3-1 1-3-2/0-1-3-2 1-3-3/0-1-3-3
    2*/0-2 2-1/0-2-1 2-1-1/0-2-1-1 2-1-2/0-2-1-2 2-1-3/0-2-1-3 2-2/0-2-2 2-2-1/0-2-2-1 2-2-2/0-2-2-2 2-2-3/0-2-2-3 2-3/0-2-3 2-3-1/0-2-3-1 2-3-2/0-2-3-2 2-3-3/0-2-3-3
    3/1 3-1/1-1 3-1-1/1-1-1 3-1-2/1-1-2 3-1-3/1-1-3 3-2/1-2 3-2-1/1-2-1 3-2-2/1-2-2 3-2-3/1-2-3 3-3/1-3 3-3-1/1-3-1 3-3-2/1-3-2 3-3-3/1-3-3
    taille de @changes: 78
    nombre de substitutions: 3003
    ------- k = 4, p = 4
    taille de @changes: 680
    nombre de substitutions: 230860
    Taisha:~/tttmp/sommaire $
    Par contre ce qui ne va pas du tout c'est le nombre de substitutions qui a l'air hors de contrôle.

    C'est sans doute dû à une petite erreur ou omission de la part de Philou67430.

    Mais du coup, je me demande si ces substitutions sont vraiment nécessaires... Il doit être possible de reprendre son principe directeur de compactage/recyclage des anciens numéros avec une autre technique. Voici ce à quoi j'arrive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # CM_v1.pl
    package CM_v1;
     
    use strict;
    use warnings;
    use 5.014;
     
    sub transformateur {
        my $balaye = shift;
     
        my (@r, %k, %p, %stats);
        my $a_la_volee = sub {
    	# le numéro traité est passé en paramètre. On n'a pas besoin de le recopier, 
            # tout va passer par la variable implicite $_ qui le contient à ce stade
     
    	# décomposition d'un numero passé en paramètre, marqué ou non
    	# la marque est un caractère non alphanumérique et différent du séparateur '-')
    	# elle peut être différente d'un numéro à l'autre
    	my ($b, $p, $m) = m/^((?:(.*)-)?.*?)([^\d\w-])?$/; # m// opère implicitement sur $_
     
    	my $d = y/-/-/;              # profondeur de ce numéro dans le sommaire (== nombre de '-' dans $_)
    	$r[$d+1] = ();               # on efface les candidats de profondeur supérieure, 
                                         # qui ne peuvent plus à ce stade être recyclés
     
    	# il vaut mieux connaître les règles de précédence pour l'expression ci-dessous !
    	!$m                          # si le numéro n'est pas marqué (remarque : $b eq $_)
    	    and (!$p or $k{$p})      # ... et il est au top ou on a gardé son parent
    	    and ++$k{$_}             # ... alors on le garde
    	    and return               # ... et on retourne
    	       $p                    # ..... en le mémorisant dans %p (le hash old ==> new)
                     {$_}                # ..... sous la clé ``ce numéro''
    	           =                 #       (la mémorisation se faisant via cette affectation)
    	             pop(@{$r[$d]})  # ... le premier candidat au recyclage
    	             || $_           # ... ou le numéro lui même en l'absence de remplaçant
    	or                           # sinon (on ne le garde pas, il est recyclable, on ne sait pas si $b eq $_)
    	    push(@{$r[$d]}, $b)      # ... on l'ajoute (sans marque) au pool des numéros recyclables à cette profondeur
    	    , return "0-$b"          # ... et on le renvoie préfixé ($b: sans marque, $_: marque comprise). 
        };
     
        $balaye->($a_la_volee, @_);
        return wantarray ? (\%p, \%k, \%stats) : \%p;
    }
     
    1;
    Pour tester, je vais reprendre le premier test t1a.pl, en remplaçant simplement le transformateur version Philou67430 par le mien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    # t1c.pl
    use strict;
    use warnings;
    use CM_v1;
    use 5.010; 
     
    # notre premiere fonction de balayage et modification de sommaire. 
    sub balaye_et_modifie_liste {
        my ($renum, $liste) = @_;
        $_ = $renum->($_) for @$liste;
    }
     
    my @sections = qw(i* i-a i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b );
    # on utilise les résultats obtenus par Philou67430
    my %new_sections = (
                      'i*' => '0-i',
                      'i-a' => '0-i-a',
                      'i-b' => '0-i-b',
                      'ii' => 'i',
                      'ii-a*' => '0-i-a',
                      'ii-b' => 'i-a',
                      'ii-b-A' => 'i-a-A',
                      'ii-b-B' => 'i-a-B',
                      'ii-b-C' => 'i-a-C',
                      'iii*' => '0-iii',
                      'iii-a' => '0-iii-a',
                      'iii-b' => '0-iii-b',
                      'iv' => 'ii',
                      'iv-a' => 'ii-a',
                      'iv-b' => 'ii-b'
                    );
    # voilà comment devrait être la liste après modifications
    my @voulu = map $new_sections{$_}, @sections;
     
     
    say "avant: @sections";
    CM_v1::transformateur(\&balaye_et_modifie_liste, \@sections);
    say "apres: @sections";
    say "voulu: @voulu";
     
    use Test::More;
    is_deeply(\@sections, \@voulu, "notre première liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    Voyons ce que ça donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Taisha:~/tttmp/sommaire $ perl t1c.pl
    avant: i* i-a i-b ii ii-a* ii-b ii-b-A ii-b-B ii-b-C iii* iii-a iii-b iv iv-a iv-b
    apres: 0-i 0-i-a 0-i-b i 0-ii-a ii-a ii-b-A ii-b-B ii-b-C 0-iii 0-iii-a 0-iii-b iii iv-a iv-b
    voulu: 0-i 0-i-a 0-i-b i 0-i-a i-a i-a-A i-a-B i-a-C 0-iii 0-iii-a 0-iii-b ii ii-a ii-b
    not ok 1 - notre première liste (15 éléments) a bien été modifiée comme attendu
    #   Failed test 'notre première liste (15 éléments) a bien été modifiée comme attendu'
    #   at t1c.pl line 42.
    #     Structures begin differing at:
    #          $got->[4] = '0-ii-a'
    #     $expected->[4] = '0-i-a'
    1..1
    # Looks like you failed 1 test of 1.
    Taisha:~/tttmp/sommaire $
    Ouh là, qu'est ce qui se passe ? les deux méthodes ne sont pas d'accord. Mais en fait, à l'inspection détaillée, il semble bien que l'erreur soit chez Philou67430 : la valeur 0-i-a apparaît deux fois...

    Peut-être va-t-il corriger sa méthode, et détecter des erreurs sur la mienne. Il y a donc encore du boulot... Mais au moins à ce stade on commence à disposer d'une infrastructure de test et d'analyse correcte

    Pfouuu. Vous pouvez détacher vos ceintures, on s'arrête là pour aujourd'hui . J'espère que la promenade vous a plu. N'hésitez pas à me faire part de vos commentaires, et de votre appréciation en votant sur les posts ou sur la discussion
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  7. #47
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Pour revenir au bogue du code de philou, pour le moment, pour le contourner, j'ai fait un modification dans ma liste de soumission.
    Elle ne pourra plus proposer un parent étoilé avec un descendance étoilée.
    En gros, on ne pourra plus avoir
    I* I-A I-B*... on aura I* I-A I-B. Étant donné que l'étoile impacte la descendance, pas besoin d'en rajouter. Et du coup, ça fonctionne.
    Cela me permet d'avoir un code fonctionnel car je dois le passer en prod.

    Par contre, vu que le sujet est passionnant, je suis pour l'améliorer et continuer la discussion .
    cmcmc, je vais manger et revenir lire ton long message .

  8. #48
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Je vais répondre aux deux points importants soulevés par cmcmc (sans reprendre le message en entier ):
    - concernant le "bug" constaté par Djibril et toi, je l'ai signalé ici comme étant une "feature"
    A priori, pour l'éviter, il faut éviter de faire les substitutions sur un numéro se terminant par * (je n'ai pas vérifié). On peut réaliser l'opération en ajoutant une assertion (?!\*) à la fin du motif de la regexp.
    - concernant la taille de @changes et le nombre de substitution, j'ai conscience d'avoir fait "au plus simple", car il m'a semblé à priori que le besoin ne nécessitait pas de mettre l'accent sur les performances. Au départ, j'avais un algorithme "récursif" pour lequel le tableau @changes était local, et qui limitait beaucoup plus le nombre de substitution il me semble.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  9. #49
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par djibril Voir le message
    ... car je dois le passer en prod.
    Ouch.

    Voyons vois si on peut compléter nos tests pour avoir confiance dans l'une ou l'autre méthode.

    Une première technique consiste à tester si la table new => old produite est bijective (ou biunivoque), c'est à dire qu'il y a autant de valeurs distinctes que de clés. Bien que cela ne constitue pas une preuve que la méthode fonctionne (la renumérotation peut être bijective sans pour autant faire ce qu'on lui demande, par exemple une renumérotation identité qui ignore purement et simplement les marques passerait ce test ), cela permet de détecter les cas où un numéro est utilisé plusieurs fois.

    La méthode la plus simple pour cela est de construire la table inverse et compter le nombre de clés de cette dernière, qui doit être égale au nombre de clés de la table directe, et à la taille de la liste d'entrée (que cette dernière soit réelle ou virtuelle).

    J'ai modifié t1a.pl et t1b.pl à partir de use Test::More comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    use Test::More;
    my $ndkeys = keys %{$new_sections};
    is $ndkeys, scalar(@sections), "le nombre de clés (old) est bien égal à taille de la liste";
    my %old_sections = reverse %{$new_sections};
    my $ndvals = keys %old_sections;
    is $ndvals, $ndkeys, "le nombre de valeurs (new) est égal au nombre de clés (old)";
    is_deeply(\@sections, \@voulu, "notre seconde liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    et le résultat est le suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    Taisha:~/tttmp/sommaire $ perl t1a.pl
    taille de @changes: 15
    nombre de substitutions: 105
    ok 1 - le nombre de clés (old) est bien égal à taille de la liste
    not ok 2 - le nombre de valeurs (new) est égal au nombre de clés (old)
    #   Failed test 'le nombre de valeurs (new) est égal au nombre de clés (old)'
    #   at t1a.pl line 48.
    #          got: '14'
    #     expected: '15'
    ok 3 - notre première liste (15 éléments) a bien été modifiée comme attendu
    1..3
    # Looks like you failed 1 test of 3.
    Taisha:~/tttmp/sommaire $ perl t2a.pl
    taille de @changes: 362
    nombre de substitutions: 65341
    ok 1 - le nombre de clés (old) est bien égal à taille de la liste
    ok 2 - le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 3 - notre seconde liste (362 éléments) a bien été modifiée comme attendu
    1..3
    Taisha:~/tttmp/sommaire $
    Cette méthode de Philou67430 a donc bien un problème. On voit que ce n'est pas évident car elle se comporte bien sur l'un des deux tests...

    Ceci dit j'ai commis un certain nombre d'erreurs dans mon message précédent . Ma méthode était toute moisie et la taille de liste était fausse (pour une liste régulière k/p, cette taille est k+k**2+...+k**p). L'inspiration me venant, j'ai fait évoluer cette méthode comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # CM_v2.pm
    package CM_v2;
     
    use strict;
    use warnings;
    use 5.010;
     
    sub transformateur {
        my $balaye = shift;
     
        my (@r, %k, %p, %stats, @a2n, @n2a);
        my @w = qw{~};
        my $a_la_volee = sub {
    	for ($_[0]) {
    	    # le numéro traité est passé en paramètre. On n'a pas besoin de le recopier, 
    	    # tout va passer par la variable implicite $_ qui le contient à ce stade
    	    # décomposition du numero passé en paramètre, marqué ou non
    	    # la marque est un caractère non alphanumérique et différent du séparateur '-')
    	    # elle peut être différente d'un numéro à l'autre
    	    my ($b, $p, $c, $m) = m/^((?:(.*)-)?(.*?))([^\d\w-])?$/; # m// opère implicitement sur $_
    	    my @nums; push @nums, $1 while $b =~ m/\G([^-]+)-?/g;
     
    	    my $d; 
    	    # capture des chaînes de caractères utilisées à chaque profondeur et association avec un index (0 .. n-1)
    	    exists($a2n[++$d]{$_})         # $_ est déjà connue à la profondeur ++$d : on ne fait rien
    		or push( @{$n2a[$d]}, $_), # sinon on la rajoute en fin du tableau des chaînes de profondeur $d
    		         $a2n[$d]{$_}      # en on l'enregistre en profondeur $d ...
    	                   = scalar(@{$n2a[$d]}) # ... avec comme valeur associée le nombre de chaînes déjà vues à cette profondeur
    		   for @nums;
    	    # à ce stade $d contient la profondeur de ce numéro dans le sommaire (toplevel = 1)
     
    	    if (!$m                          # si le numéro n'est pas marqué (remarque : $b eq $_)
    		and (!$p or $k{$p})) {       # ... et il est au top ou on a gardé son parent
    		++$k{$_};                    # ... alors on le garde
    		++$w[$d];                    # ... on incrémente l'index courant au rang $d
    		$w[$d+1] = 0;                # ... on invalide les index de profondeur supérieure à $d (pour les nombres à venir)
    		# construction du nouveau nombre à partir des index
    		# attention les index vont de 1 à n, mais les positions de leurs chaînes associées dans $n2a[prof][...] vont de 0 à n-1
    		$p{$_} = join q{-}, map {
    		    $n2a[$_][$w[$_]-1]
    		} 1 .. $d;
    		return $p{$_};
    	    } else {                         # sinon (on ne le garde pas, on ne sait pas si $b eq $_)
    		return $p{$_} = "0-$b"       # ... et on le renvoie préfixé ($b: sans marque, $_: marque comprise). 
    	    }
    	}
        };
     
        $balaye->($a_la_volee, @_);
        return wantarray ? (\%p, \%k, \%stats, \@a2n, \@n2a) : \%p;
    }
     
    1;
    C'est fondamentalement la même technique que mes premières versions. La ruse consiste à ne pas cherche à faire d'arithmétique sur les composants de nombres tels qu'ils sont passés, mais de les associer à un index : le premier "nombre" vu en profondeur 1 sera associé à l'index 1, le second à 2, etc. On peut donc prendre des "nombres" arbitraires à chaque profondeur, par exemple Un, Deux, Trois, Quatre ou Foo, Bar pourvu qu'ils soient toujours associés au même index à cette profondeur. Ca donne des entrées de sommaire du type Un-Foo-One, Un-Foo-Two, etc. comme dans le test suivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    # test_CM_v2.pl
    use strict;
    use warnings;
    use CM_v2;
    use 5.010; 
     
    # notre premiere fonction de balayage et modification de sommaire. 
    sub balaye_et_modifie_liste {
        my ($renum, $liste) = @_;
        $_ = $renum->($_) for @$liste;
    }
     
    my @sections = qw(Un* Un-Foo Un-Bar Deux Deux-Foo* Deux-Bar Deux-Bar-One Deux-Bar-Two Deux-Bar-Three Trois* Trois-Foo Trois-Bar Quatre Quatre-Foo Quatre-Bar );
    my %new_sections = (
                      'Un*' => '0-Un',
                      'Un-Foo' => '0-Un-Foo',
                      'Un-Bar' => '0-Un-Bar',
                      'Deux' => 'Un',
                      'Deux-Foo*' => '0-Deux-Foo',
                      'Deux-Bar' => 'Un-Foo',
                      'Deux-Bar-One' => 'Un-Foo-One',
                      'Deux-Bar-Two' => 'Un-Foo-Two',
                      'Deux-Bar-Three' => 'Un-Foo-Three',
                      'Trois*' => '0-Trois',
                      'Trois-Foo' => '0-Trois-Foo',
                      'Trois-Bar' => '0-Trois-Bar',
                      'Quatre' => 'Deux',
                      'Quatre-Foo' => 'Deux-Foo',
                      'Quatre-Bar' => 'Deux-Bar'
                    );
    # voilà comment devrait être la liste après modifications
    my @voulu = map $new_sections{$_}, @sections;
     
     
    say "avant: @sections";
    CM_v2::transformateur(\&balaye_et_modifie_liste, \@sections);
    say "apres: @sections";
    say "voulu: @voulu";
     
    use Test::More;
    is_deeply(\@sections, \@voulu, "notre première liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    et ça marche:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Taisha:~/tttmp/sommaire $ perl test_CM_v2.pl
    avant: Un* Un-Foo Un-Bar Deux Deux-Foo* Deux-Bar Deux-Bar-One Deux-Bar-Two Deux-Bar-Three Trois* Trois-Foo Trois-Bar Quatre Quatre-Foo Quatre-Bar
    apres: 0-Un 0-Un-Foo 0-Un-Bar Un 0-Deux-Foo Un-Foo Un-Foo-One Un-Foo-Two Un-Foo-Three 0-Trois 0-Trois-Foo 0-Trois-Bar Deux Deux-Foo Deux-Bar
    voulu: 0-Un 0-Un-Foo 0-Un-Bar Un 0-Deux-Foo Un-Foo Un-Foo-One Un-Foo-Two Un-Foo-Three 0-Trois 0-Trois-Foo 0-Trois-Bar Deux Deux-Foo Deux-Bar
    ok 1 - notre première liste (15 éléments) a bien été modifiée comme attendu
    1..1
    Taisha:~/tttmp/sommaire $
    J'ai ensuite testé cette méthode de manière beaucoup plus extensive en utilisant l'approche de liste virtuelle pour plusieurs scénarios :
    • aucun noeud n'est marqué
    • tous les noeuds sont marqués
    • tous les noeuds de profondeur 1 sont marqués sauf le dernier
    • les noeuds de profondeur 1 et d'index impair (1, 3, 5, ...) sont marqués
    • les noeuds de valeur k et parents k à la profondeur k sont marqués
    • marquage aléatoire (pas de vérification possible, sauf que la table produite est bijective)

    Voici le fichier de test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    # test_CM_v2_lvr_abl_1.pl
    use strict;
    use warnings;
    use CM_v2;
    use 5.010;
    use Test::More; 
     
    # balaye une liste virtuelle régulière de profondeur $p (toplevel = 1, feuilles = p), 
    # avec $k noeuds à chaque niveau. 
    #  1 1-1 ... 1-k-..-k
    #  2 2-1 ... 2-k-..-k
    #  ...
    #  k k-1 ... k-k-..-k
    # cette liste contient k + k**2 + ... + k**p) élements
    #
    # appelle $process->($renum, $k, $p, $current, @rest) pour chacun des numéros $current de la liste. 
     
    sub balaye_lvr {
        my ($renum, $process, $k, $p, @rest) = @_;
        my $balaye; # fonction auxiliaire interne récursive
        $balaye = sub {
    	my $parent = shift;
    	$parent //= q{};
    	for (1 .. $k) {
    	    my $current = $parent ? "$parent-$_" : $_;
    	    return if ($current =~ y/-/-/) >= $p;
    	    $process->($renum, $k, $p, $current, @rest);
    	    $balaye->($current);
    	}
        };
        $balaye->();
    }
     
    sub taille {
        my ($k, $p) = @_;
        my $t = 0;
        $t = $k + $k*$t for (1 .. $p);
        $t
    }
     
    if (0) {
        sub show_list {
    	my ($renum, $k, $p, $current) = @_;
    	say +(q{  } x $current =~ y/-/-/), $current;
        }
     
        for my $k (1 .. 3) {
    	for my $p (1 .. 3) {
    	    say "-------- show_list k = $k p = $p";
    	    balaye_lvr(undef, \&show_list, $k, $p);
    	}
        }
    }
     
    # aucun noeud n'est marqué
    sub process_marque_aucun {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = $cur;
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $new eq $exp;
    }
     
    # tous les noeuds sont marqués
    sub process_marque_tous {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = "$cur*";
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = "0-$cur";
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $new eq $exp;
    }
     
    # Tous les noeuds de profondeur 1 sont marqués sauf le dernier : 
    # après modification tous les noeuds doivent être préfixés par 0
    # sauf les p derniers (k k.1 ... k-k..k) qui sont
    # transformés en      (1 1-1 ... 1-k..k)
    sub process_marque_top_sauf_k {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = ($cur =~ m/^\d+$/ && $cur != $k) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = $cur =~ m/^$k-?/
    	? $cur =~ s/^\d+/1/r
    	: "0-$cur";
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $new eq $exp;
    }
     
    # les noeuds de profondeur 1 et d'index impair (1, 3, 5, ...) sont marqués
    # après modification tous les noeuds dont le toplevel est d'index impair doivent être préfixés par 0
    # et les autres (n n-1 ... n-k..k) transformés en (m m-1 ... m-k..k) avec m = n/2
    sub process_marque_top_impair {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = (($cur =~ m/^\d+$/) and ($cur % 2)) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = do {
    	my ($top) = $cur =~ m/^(\d+)/;
    	if ($top % 2) {
    	    "0-$cur";
    	} else {
    	    $cur =~ s{^$top}{$top/2}e;
    	    $cur
    	}
        };
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $new eq $exp;
    }
     
    # les noeuds de valeur k et parents k à la profondeur k sont marqués :
    #>  1*  1-1   1-1-1   1-1-2   1-1-3   1-2   1-2-1   1-2-2   1-2-3   1-3   1-3-1   1-3-2   1-3-3
    #<  0-1 0-1-1 0-1-1-1 0-1-1-2 0-1-1-3 0-1-2 0-1-2-1 0-1-2-2 0-1-2-3 0-1-3 0-1-3-1 0-1-3-2 0-1-3-3
    #>  2   2-1   2-1-1   2-1-2   2-1-3   2-2*  2-2-1   2-2-2   2-2-3   2-3   2-3-1   2-3-2   2-3-3
    #<  1   1-1   1-1-1   1-1-2   1-1-3   0-2-2 0-2-2-1 0-2-2-2 0-2-2-3 1-2   1-2-1   1-2-2   1-2-3
    #>  3   3-1   3-1-1   3-1-2   3-1-3   3-2   3-2-1   3-2-2   3-2-3   3-3   3-3-1   3-3-2   3-3-3*
    #<  2   2-1   2-1-1   2-1-2   2-1-3   2-2   2-2-1   2-2-2   2-2-3   2-3   2-3-1   2-3-2   0-3-3-3
    sub process_marque_diagonale_k_k {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $is_marked;
        my $is_marked_or_after_marked = 1;
        {
    	my @nums = split q{-}, $cur;
          loop:
    	for (1 .. $nums[0]) {
    	    if (@nums < $nums[0]) {
    		$is_marked_or_after_marked = 0;
    		last loop
    	    }
    	    unless ($nums[$_-1] == $nums[0]) {
    		$is_marked_or_after_marked = 0;
    		last loop
    	    }
    	}
    	$is_marked = $is_marked_or_after_marked && ($nums[0] == scalar(@nums));
        }
        my $old = $is_marked ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = do {
    	if ($is_marked_or_after_marked) {
    	    "0-$cur";
    	} else {
    	    my @nums = split q{-}, $cur;
    	    my @orig = @nums;
    	    # pour décrémenter le nombre en position x
    	    # il faut que tous ses parents soient == x 
    	    # et que lui même soit >= x
    	  decrement:
    	    for my $depth (0 .. $#nums) { # x - 1 
    		for (0 .. $depth-1) {
    		    next if $_ < 0;
    		    next decrement unless $orig[$_] == $depth + 1;
    		}
    		for ($depth) {
    		    next if $_ < 0;
    		    next decrement unless $orig[$_] >= $depth + 1;
    		}
    		--$nums[$depth];
    	    }
    	    join q{-}, @nums;
    	}
        };
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $new eq $exp;
    }
     
    # marque de manière aléatoire un pourcentage donné de noeuds
    # pas de vérification possible : on renvoie un nombre d'erreurs négatif
    sub process_marque_x_pourcent {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref, $pourcentage) = @_;
        # marquage et renumérotation
        my $old = (rand(100) <= $pourcentage) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # pas de vérification possible : on renvoie un nombre d'erreurs négatif
        --$$nb_errs_ref;
    }
     
    my $kmax = (shift @ARGV) // 3;
    for my $marquage (qw(aucun tous top_sauf_k top_impair diagonale_k_k 10 20 30 40 50)) {
        for my $k (2 .. $kmax) {
    	my ($p, $debug, $nb_errs, $last_err) = ($k, $k <= 3, 0);
    	my $taille_de_la_liste = taille($k,$p);
    	my $process = sub {
    	    no strict 'refs';
    	    $marquage =~ m/^\d+$/ 
    		? "process_marque_x_pourcent"->(@_, $marquage)
    		: "process_marque_$marquage"->(@_)
    	};
    	my ($new_sections)
    	    = CM_v2::transformateur(\&balaye_lvr, $process, $k, $p, $debug, \$nb_errs, \$last_err);
    	my $methode = $marquage =~ m/^\d+$/ ? "${marquage}_pourcent" : $marquage ;
    	cmp_ok $nb_errs, "<=", 0, "[$methode k=$k p=$p] " . ($nb_errs == 0 ? "pas d'erreurs de numérotations observées" : "(non significatif : contrôle non effectué)");
    	my $ndkeys = keys %{$new_sections};
    	is $ndkeys, $taille_de_la_liste, "[$methode k=$k p=$p] le nombre de clés (old) est bien égal à taille de la liste";
    	my %new2old= reverse %{$new_sections};
    	my $ndvals = keys %new2old;
    	is $ndvals, $ndkeys, "[$methode k=$k p=$p] le nombre de valeurs (new) est égal au nombre de clés (old)";
        }
    }
     
    done_testing;
    et le résultat en profondeur max 6
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    Taisha:~/tttmp/sommaire $ perl test_CM_v2_lvr.pl 6
    1         1         
      1-1       1-1       
      1-2       1-2       
    2         2         
      2-1       2-1       
      2-2       2-2       
    ok 1 - [aucun k=2 p=2] pas d'erreurs de numérotations observées
    ok 2 - [aucun k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 3 - [aucun k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1       1-1       
        1-1-1     1-1-1     
        1-1-2     1-1-2     
        1-1-3     1-1-3     
      1-2       1-2       
        1-2-1     1-2-1     
        1-2-2     1-2-2     
        1-2-3     1-2-3     
      1-3       1-3       
        1-3-1     1-3-1     
        1-3-2     1-3-2     
        1-3-3     1-3-3     
    2         2         
      2-1       2-1       
        2-1-1     2-1-1     
        2-1-2     2-1-2     
        2-1-3     2-1-3     
      2-2       2-2       
        2-2-1     2-2-1     
        2-2-2     2-2-2     
        2-2-3     2-2-3     
      2-3       2-3       
        2-3-1     2-3-1     
        2-3-2     2-3-2     
        2-3-3     2-3-3     
    3         3         
      3-1       3-1       
        3-1-1     3-1-1     
        3-1-2     3-1-2     
        3-1-3     3-1-3     
      3-2       3-2       
        3-2-1     3-2-1     
        3-2-2     3-2-2     
        3-2-3     3-2-3     
      3-3       3-3       
        3-3-1     3-3-1     
        3-3-2     3-3-2     
        3-3-3     3-3-3     
    ok 4 - [aucun k=3 p=3] pas d'erreurs de numérotations observées
    ok 5 - [aucun k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 6 - [aucun k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 7 - [aucun k=4 p=4] pas d'erreurs de numérotations observées
    ok 8 - [aucun k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 9 - [aucun k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 10 - [aucun k=5 p=5] pas d'erreurs de numérotations observées
    ok 11 - [aucun k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 12 - [aucun k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 13 - [aucun k=6 p=6] pas d'erreurs de numérotations observées
    ok 14 - [aucun k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 15 - [aucun k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
      1-2*      0-1-2     
    2*        0-2       
      2-1*      0-2-1     
      2-2*      0-2-2     
    ok 16 - [tous k=2 p=2] pas d'erreurs de numérotations observées
    ok 17 - [tous k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 18 - [tous k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
        1-1-1*    0-1-1-1   
        1-1-2*    0-1-1-2   
        1-1-3*    0-1-1-3   
      1-2*      0-1-2     
        1-2-1*    0-1-2-1   
        1-2-2*    0-1-2-2   
        1-2-3*    0-1-2-3   
      1-3*      0-1-3     
        1-3-1*    0-1-3-1   
        1-3-2*    0-1-3-2   
        1-3-3*    0-1-3-3   
    2*        0-2       
      2-1*      0-2-1     
        2-1-1*    0-2-1-1   
        2-1-2*    0-2-1-2   
        2-1-3*    0-2-1-3   
      2-2*      0-2-2     
        2-2-1*    0-2-2-1   
        2-2-2*    0-2-2-2   
        2-2-3*    0-2-2-3   
      2-3*      0-2-3     
        2-3-1*    0-2-3-1   
        2-3-2*    0-2-3-2   
        2-3-3*    0-2-3-3   
    3*        0-3       
      3-1*      0-3-1     
        3-1-1*    0-3-1-1   
        3-1-2*    0-3-1-2   
        3-1-3*    0-3-1-3   
      3-2*      0-3-2     
        3-2-1*    0-3-2-1   
        3-2-2*    0-3-2-2   
        3-2-3*    0-3-2-3   
      3-3*      0-3-3     
        3-3-1*    0-3-3-1   
        3-3-2*    0-3-3-2   
        3-3-3*    0-3-3-3   
    ok 19 - [tous k=3 p=3] pas d'erreurs de numérotations observées
    ok 20 - [tous k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 21 - [tous k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 22 - [tous k=4 p=4] pas d'erreurs de numérotations observées
    ok 23 - [tous k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 24 - [tous k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 25 - [tous k=5 p=5] pas d'erreurs de numérotations observées
    ok 26 - [tous k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 27 - [tous k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 28 - [tous k=6 p=6] pas d'erreurs de numérotations observées
    ok 29 - [tous k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 30 - [tous k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
      1-2       0-1-2     
    2         1         
      2-1       1-1       
      2-2       1-2       
    ok 31 - [top_sauf_k k=2 p=2] pas d'erreurs de numérotations observées
    ok 32 - [top_sauf_k k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 33 - [top_sauf_k k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
        1-1-1     0-1-1-1   
        1-1-2     0-1-1-2   
        1-1-3     0-1-1-3   
      1-2       0-1-2     
        1-2-1     0-1-2-1   
        1-2-2     0-1-2-2   
        1-2-3     0-1-2-3   
      1-3       0-1-3     
        1-3-1     0-1-3-1   
        1-3-2     0-1-3-2   
        1-3-3     0-1-3-3   
    2*        0-2       
      2-1       0-2-1     
        2-1-1     0-2-1-1   
        2-1-2     0-2-1-2   
        2-1-3     0-2-1-3   
      2-2       0-2-2     
        2-2-1     0-2-2-1   
        2-2-2     0-2-2-2   
        2-2-3     0-2-2-3   
      2-3       0-2-3     
        2-3-1     0-2-3-1   
        2-3-2     0-2-3-2   
        2-3-3     0-2-3-3   
    3         1         
      3-1       1-1       
        3-1-1     1-1-1     
        3-1-2     1-1-2     
        3-1-3     1-1-3     
      3-2       1-2       
        3-2-1     1-2-1     
        3-2-2     1-2-2     
        3-2-3     1-2-3     
      3-3       1-3       
        3-3-1     1-3-1     
        3-3-2     1-3-2     
        3-3-3     1-3-3     
    ok 34 - [top_sauf_k k=3 p=3] pas d'erreurs de numérotations observées
    ok 35 - [top_sauf_k k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 36 - [top_sauf_k k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 37 - [top_sauf_k k=4 p=4] pas d'erreurs de numérotations observées
    ok 38 - [top_sauf_k k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 39 - [top_sauf_k k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 40 - [top_sauf_k k=5 p=5] pas d'erreurs de numérotations observées
    ok 41 - [top_sauf_k k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 42 - [top_sauf_k k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 43 - [top_sauf_k k=6 p=6] pas d'erreurs de numérotations observées
    ok 44 - [top_sauf_k k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 45 - [top_sauf_k k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
      1-2       0-1-2     
    2         1         
      2-1       1-1       
      2-2       1-2       
    ok 46 - [top_impair k=2 p=2] pas d'erreurs de numérotations observées
    ok 47 - [top_impair k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 48 - [top_impair k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
        1-1-1     0-1-1-1   
        1-1-2     0-1-1-2   
        1-1-3     0-1-1-3   
      1-2       0-1-2     
        1-2-1     0-1-2-1   
        1-2-2     0-1-2-2   
        1-2-3     0-1-2-3   
      1-3       0-1-3     
        1-3-1     0-1-3-1   
        1-3-2     0-1-3-2   
        1-3-3     0-1-3-3   
    2         1         
      2-1       1-1       
        2-1-1     1-1-1     
        2-1-2     1-1-2     
        2-1-3     1-1-3     
      2-2       1-2       
        2-2-1     1-2-1     
        2-2-2     1-2-2     
        2-2-3     1-2-3     
      2-3       1-3       
        2-3-1     1-3-1     
        2-3-2     1-3-2     
        2-3-3     1-3-3     
    3*        0-3       
      3-1       0-3-1     
        3-1-1     0-3-1-1   
        3-1-2     0-3-1-2   
        3-1-3     0-3-1-3   
      3-2       0-3-2     
        3-2-1     0-3-2-1   
        3-2-2     0-3-2-2   
        3-2-3     0-3-2-3   
      3-3       0-3-3     
        3-3-1     0-3-3-1   
        3-3-2     0-3-3-2   
        3-3-3     0-3-3-3   
    ok 49 - [top_impair k=3 p=3] pas d'erreurs de numérotations observées
    ok 50 - [top_impair k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 51 - [top_impair k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 52 - [top_impair k=4 p=4] pas d'erreurs de numérotations observées
    ok 53 - [top_impair k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 54 - [top_impair k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 55 - [top_impair k=5 p=5] pas d'erreurs de numérotations observées
    ok 56 - [top_impair k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 57 - [top_impair k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 58 - [top_impair k=6 p=6] pas d'erreurs de numérotations observées
    ok 59 - [top_impair k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 60 - [top_impair k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
      1-2       0-1-2     
    2         1         
      2-1       1-1       
      2-2*      0-2-2     
    ok 61 - [diagonale_k_k k=2 p=2] pas d'erreurs de numérotations observées
    ok 62 - [diagonale_k_k k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 63 - [diagonale_k_k k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
        1-1-1     0-1-1-1   
        1-1-2     0-1-1-2   
        1-1-3     0-1-1-3   
      1-2       0-1-2     
        1-2-1     0-1-2-1   
        1-2-2     0-1-2-2   
        1-2-3     0-1-2-3   
      1-3       0-1-3     
        1-3-1     0-1-3-1   
        1-3-2     0-1-3-2   
        1-3-3     0-1-3-3   
    2         1         
      2-1       1-1       
        2-1-1     1-1-1     
        2-1-2     1-1-2     
        2-1-3     1-1-3     
      2-2*      0-2-2     
        2-2-1     0-2-2-1   
        2-2-2     0-2-2-2   
        2-2-3     0-2-2-3   
      2-3       1-2       
        2-3-1     1-2-1     
        2-3-2     1-2-2     
        2-3-3     1-2-3     
    3         2         
      3-1       2-1       
        3-1-1     2-1-1     
        3-1-2     2-1-2     
        3-1-3     2-1-3     
      3-2       2-2       
        3-2-1     2-2-1     
        3-2-2     2-2-2     
        3-2-3     2-2-3     
      3-3       2-3       
        3-3-1     2-3-1     
        3-3-2     2-3-2     
        3-3-3*    0-3-3-3   
    ok 64 - [diagonale_k_k k=3 p=3] pas d'erreurs de numérotations observées
    ok 65 - [diagonale_k_k k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 66 - [diagonale_k_k k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 67 - [diagonale_k_k k=4 p=4] pas d'erreurs de numérotations observées
    ok 68 - [diagonale_k_k k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 69 - [diagonale_k_k k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 70 - [diagonale_k_k k=5 p=5] pas d'erreurs de numérotations observées
    ok 71 - [diagonale_k_k k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 72 - [diagonale_k_k k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 73 - [diagonale_k_k k=6 p=6] pas d'erreurs de numérotations observées
    ok 74 - [diagonale_k_k k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 75 - [diagonale_k_k k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1       1-1       
      1-2       1-2       
    2         2         
      2-1       2-1       
      2-2*      0-2-2     
    ok 76 - [10_pourcent k=2 p=2] (non significatif : contrôle non effectué)
    ok 77 - [10_pourcent k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 78 - [10_pourcent k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1       1-1       
        1-1-1     1-1-1     
        1-1-2     1-1-2     
        1-1-3     1-1-3     
      1-2       1-2       
        1-2-1     1-2-1     
        1-2-2     1-2-2     
        1-2-3     1-2-3     
      1-3       1-3       
        1-3-1     1-3-1     
        1-3-2*    0-1-3-2   
        1-3-3     1-3-2     
    2*        0-2       
      2-1       0-2-1     
        2-1-1     0-2-1-1   
        2-1-2*    0-2-1-2   
        2-1-3     0-2-1-3   
      2-2       0-2-2     
        2-2-1     0-2-2-1   
        2-2-2     0-2-2-2   
        2-2-3     0-2-2-3   
      2-3       0-2-3     
        2-3-1     0-2-3-1   
        2-3-2     0-2-3-2   
        2-3-3     0-2-3-3   
    3*        0-3       
      3-1       0-3-1     
        3-1-1     0-3-1-1   
        3-1-2*    0-3-1-2   
        3-1-3     0-3-1-3   
      3-2       0-3-2     
        3-2-1     0-3-2-1   
        3-2-2     0-3-2-2   
        3-2-3     0-3-2-3   
      3-3       0-3-3     
        3-3-1     0-3-3-1   
        3-3-2     0-3-3-2   
        3-3-3     0-3-3-3   
    ok 79 - [10_pourcent k=3 p=3] (non significatif : contrôle non effectué)
    ok 80 - [10_pourcent k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 81 - [10_pourcent k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 82 - [10_pourcent k=4 p=4] (non significatif : contrôle non effectué)
    ok 83 - [10_pourcent k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 84 - [10_pourcent k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 85 - [10_pourcent k=5 p=5] (non significatif : contrôle non effectué)
    ok 86 - [10_pourcent k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 87 - [10_pourcent k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 88 - [10_pourcent k=6 p=6] (non significatif : contrôle non effectué)
    ok 89 - [10_pourcent k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 90 - [10_pourcent k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1       0-1-1     
      1-2       0-1-2     
    2         1         
      2-1       1-1       
      2-2       1-2       
    ok 91 - [20_pourcent k=2 p=2] (non significatif : contrôle non effectué)
    ok 92 - [20_pourcent k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 93 - [20_pourcent k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1       1-1       
        1-1-1*    0-1-1-1   
        1-1-2     1-1-1     
        1-1-3     1-1-2     
      1-2       1-2       
        1-2-1*    0-1-2-1   
        1-2-2     1-2-1     
        1-2-3     1-2-2     
      1-3       1-3       
        1-3-1     1-3-1     
        1-3-2     1-3-2     
        1-3-3     1-3-3     
    2         2         
      2-1       2-1       
        2-1-1*    0-2-1-1   
        2-1-2     2-1-1     
        2-1-3*    0-2-1-3   
      2-2*      0-2-2     
        2-2-1     0-2-2-1   
        2-2-2*    0-2-2-2   
        2-2-3*    0-2-2-3   
      2-3       2-2       
        2-3-1     2-2-1     
        2-3-2     2-2-2     
        2-3-3     2-2-3     
    3         3         
      3-1       3-1       
        3-1-1     3-1-1     
        3-1-2     3-1-2     
        3-1-3     3-1-3     
      3-2       3-2       
        3-2-1     3-2-1     
        3-2-2*    0-3-2-2   
        3-2-3*    0-3-2-3   
      3-3       3-3       
        3-3-1     3-3-1     
        3-3-2     3-3-2     
        3-3-3     3-3-3     
    ok 94 - [20_pourcent k=3 p=3] (non significatif : contrôle non effectué)
    ok 95 - [20_pourcent k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 96 - [20_pourcent k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 97 - [20_pourcent k=4 p=4] (non significatif : contrôle non effectué)
    ok 98 - [20_pourcent k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 99 - [20_pourcent k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 100 - [20_pourcent k=5 p=5] (non significatif : contrôle non effectué)
    ok 101 - [20_pourcent k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 102 - [20_pourcent k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 103 - [20_pourcent k=6 p=6] (non significatif : contrôle non effectué)
    ok 104 - [20_pourcent k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 105 - [20_pourcent k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1*      0-1-1     
      1-2*      0-1-2     
    2*        0-2       
      2-1*      0-2-1     
      2-2       0-2-2     
    ok 106 - [30_pourcent k=2 p=2] (non significatif : contrôle non effectué)
    ok 107 - [30_pourcent k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 108 - [30_pourcent k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1         1         
      1-1       1-1       
        1-1-1*    0-1-1-1   
        1-1-2*    0-1-1-2   
        1-1-3*    0-1-1-3   
      1-2       1-2       
        1-2-1     1-2-1     
        1-2-2     1-2-2     
        1-2-3*    0-1-2-3   
      1-3       1-3       
        1-3-1     1-3-1     
        1-3-2     1-3-2     
        1-3-3     1-3-3     
    2         2         
      2-1       2-1       
        2-1-1*    0-2-1-1   
        2-1-2     2-1-1     
        2-1-3     2-1-2     
      2-2       2-2       
        2-2-1     2-2-1     
        2-2-2     2-2-2     
        2-2-3*    0-2-2-3   
      2-3*      0-2-3     
        2-3-1     0-2-3-1   
        2-3-2     0-2-3-2   
        2-3-3     0-2-3-3   
    3         3         
      3-1       3-1       
        3-1-1*    0-3-1-1   
        3-1-2     3-1-1     
        3-1-3     3-1-2     
      3-2*      0-3-2     
        3-2-1*    0-3-2-1   
        3-2-2*    0-3-2-2   
        3-2-3     0-3-2-3   
      3-3       3-2       
        3-3-1*    0-3-3-1   
        3-3-2     3-2-1     
        3-3-3     3-2-2     
    ok 109 - [30_pourcent k=3 p=3] (non significatif : contrôle non effectué)
    ok 110 - [30_pourcent k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 111 - [30_pourcent k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 112 - [30_pourcent k=4 p=4] (non significatif : contrôle non effectué)
    ok 113 - [30_pourcent k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 114 - [30_pourcent k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 115 - [30_pourcent k=5 p=5] (non significatif : contrôle non effectué)
    ok 116 - [30_pourcent k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 117 - [30_pourcent k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 118 - [30_pourcent k=6 p=6] (non significatif : contrôle non effectué)
    ok 119 - [30_pourcent k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 120 - [30_pourcent k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
      1-2       0-1-2     
    2         1         
      2-1       1-1       
      2-2       1-2       
    ok 121 - [40_pourcent k=2 p=2] (non significatif : contrôle non effectué)
    ok 122 - [40_pourcent k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 123 - [40_pourcent k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
        1-1-1     0-1-1-1   
        1-1-2*    0-1-1-2   
        1-1-3     0-1-1-3   
      1-2       0-1-2     
        1-2-1     0-1-2-1   
        1-2-2     0-1-2-2   
        1-2-3     0-1-2-3   
      1-3       0-1-3     
        1-3-1     0-1-3-1   
        1-3-2     0-1-3-2   
        1-3-3*    0-1-3-3   
    2*        0-2       
      2-1       0-2-1     
        2-1-1     0-2-1-1   
        2-1-2*    0-2-1-2   
        2-1-3     0-2-1-3   
      2-2       0-2-2     
        2-2-1     0-2-2-1   
        2-2-2*    0-2-2-2   
        2-2-3*    0-2-2-3   
      2-3*      0-2-3     
        2-3-1     0-2-3-1   
        2-3-2     0-2-3-2   
        2-3-3*    0-2-3-3   
    3*        0-3       
      3-1*      0-3-1     
        3-1-1*    0-3-1-1   
        3-1-2     0-3-1-2   
        3-1-3     0-3-1-3   
      3-2*      0-3-2     
        3-2-1     0-3-2-1   
        3-2-2*    0-3-2-2   
        3-2-3     0-3-2-3   
      3-3*      0-3-3     
        3-3-1     0-3-3-1   
        3-3-2     0-3-3-2   
        3-3-3*    0-3-3-3   
    ok 124 - [40_pourcent k=3 p=3] (non significatif : contrôle non effectué)
    ok 125 - [40_pourcent k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 126 - [40_pourcent k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 127 - [40_pourcent k=4 p=4] (non significatif : contrôle non effectué)
    ok 128 - [40_pourcent k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 129 - [40_pourcent k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 130 - [40_pourcent k=5 p=5] (non significatif : contrôle non effectué)
    ok 131 - [40_pourcent k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 132 - [40_pourcent k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 133 - [40_pourcent k=6 p=6] (non significatif : contrôle non effectué)
    ok 134 - [40_pourcent k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 135 - [40_pourcent k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
      1-2*      0-1-2     
    2         1         
      2-1*      0-2-1     
      2-2*      0-2-2     
    ok 136 - [50_pourcent k=2 p=2] (non significatif : contrôle non effectué)
    ok 137 - [50_pourcent k=2 p=2] le nombre de clés (old) est bien égal à taille de la liste
    ok 138 - [50_pourcent k=2 p=2] le nombre de valeurs (new) est égal au nombre de clés (old)
    1*        0-1       
      1-1*      0-1-1     
        1-1-1*    0-1-1-1   
        1-1-2     0-1-1-2   
        1-1-3*    0-1-1-3   
      1-2       0-1-2     
        1-2-1*    0-1-2-1   
        1-2-2     0-1-2-2   
        1-2-3*    0-1-2-3   
      1-3       0-1-3     
        1-3-1*    0-1-3-1   
        1-3-2     0-1-3-2   
        1-3-3*    0-1-3-3   
    2         1         
      2-1*      0-2-1     
        2-1-1*    0-2-1-1   
        2-1-2*    0-2-1-2   
        2-1-3     0-2-1-3   
      2-2       1-1       
        2-2-1     1-1-1     
        2-2-2*    0-2-2-2   
        2-2-3*    0-2-2-3   
      2-3       1-2       
        2-3-1     1-2-1     
        2-3-2*    0-2-3-2   
        2-3-3     1-2-2     
    3         2         
      3-1       2-1       
        3-1-1     2-1-1     
        3-1-2*    0-3-1-2   
        3-1-3*    0-3-1-3   
      3-2       2-2       
        3-2-1     2-2-1     
        3-2-2     2-2-2     
        3-2-3     2-2-3     
      3-3       2-3       
        3-3-1*    0-3-3-1   
        3-3-2     2-3-1     
        3-3-3     2-3-2     
    ok 139 - [50_pourcent k=3 p=3] (non significatif : contrôle non effectué)
    ok 140 - [50_pourcent k=3 p=3] le nombre de clés (old) est bien égal à taille de la liste
    ok 141 - [50_pourcent k=3 p=3] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 142 - [50_pourcent k=4 p=4] (non significatif : contrôle non effectué)
    ok 143 - [50_pourcent k=4 p=4] le nombre de clés (old) est bien égal à taille de la liste
    ok 144 - [50_pourcent k=4 p=4] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 145 - [50_pourcent k=5 p=5] (non significatif : contrôle non effectué)
    ok 146 - [50_pourcent k=5 p=5] le nombre de clés (old) est bien égal à taille de la liste
    ok 147 - [50_pourcent k=5 p=5] le nombre de valeurs (new) est égal au nombre de clés (old)
    ok 148 - [50_pourcent k=6 p=6] (non significatif : contrôle non effectué)
    ok 149 - [50_pourcent k=6 p=6] le nombre de clés (old) est bien égal à taille de la liste
    ok 150 - [50_pourcent k=6 p=6] le nombre de valeurs (new) est égal au nombre de clés (old)
    1..150
    Taisha:~/tttmp/sommaire $
    Il semble au final que cette méthode fonctionne enfin, tolère des systèmes de numérotation arbitraires, et ait une complexité linéaire par rapport à la taille de la liste.

    Ouf!
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  10. #50
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Salut cmcmc, on dirait que tu n'as pas lu mon message précédent

    L'idée que l'application "old num" => "new num" soit bijective est une contrainte que tu imposes, mais dont djibril n'a peut-être pas besoin. Tout dépend du besoin sous-jacent à l'usage de "new num". Par exemple, on pourrait imaginer que le renumérotation des numéros en * puisse n'avoir rien à voir avec celle d'origine, parce que, par exemple, elle ne serait plus utilisée par la suite (les § seraient supprimés, ou déplacés dans un autre sommaire, ou bien que sais-je). Imposer la bijection ne me semble pas une évidence, c'est d'ailleurs pour cela que j'ai notifié ce "fonctionnement" (feature) que vous appelez "bug" concernant le fait que la renumérotation puisse produire des numéros en 0-* identiques.

    Mais cela dit, si c'est effectivement une contrainte, j'ai fait une proposition de modification dans mon message précédent pour ne plus avoir ce problème
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  11. #51
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Salut cmcmc, on dirait que tu n'as pas lu mon message précédent

    L'idée que l'application "old num" => "new num" soit bijective est une contrainte que tu imposes, mais dont djibril n'a peut-être pas besoin. Tout dépend du besoin sous-jacent à l'usage de "new num". Par exemple, on pourrait imaginer que le renumérotation des numéros en * puisse n'avoir rien à voir avec celle d'origine, parce que, par exemple, elle ne serait plus utilisée par la suite (les § seraient supprimés, ou déplacés dans un autre sommaire, ou bien que sais-je). Imposer la bijection ne me semble pas une évidence, c'est d'ailleurs pour cela que j'ai notifié ce "fonctionnement" (feature) que vous appelez "bug" concernant le fait que la renumérotation puisse produire des numéros en 0-* identiques.

    Mais cela dit, si c'est effectivement une contrainte, j'ai fait une proposition de modification dans mon message précédent pour ne plus avoir ce problème
    Effectivement j'ai composé mon message "hors ligne" et n'avais pas ton dernier message.

    Ceci dit, il me semble que quel que soit le devenir des paragraphes numérotés 0-xxx, il reste intéressant que le xxx soit égal au numéro initial. On peut choisir ou non d'y intégrer la marque s'il y en a une (dans CM_v2.pl, ce comportement est contrôlé ligne 44, voir le commentaire, et pourrait être passé en option). En tout cas imposer la bijectivité de la transformation fournit à bon compte un test d'intégrité que je trouve bienvenu.

    Je n'ai pas testé la suggestion de modification, mais il devrait être facile de l'appliquer à Philou67430_v1.pm pour produire Philou67430_v2.pm , et d'adapter test_CM_v2_lvr.pl en test_Philou67430_v2_lvr.pl (s/CM_v2/Philou67430/g) pour faire un test
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  12. #52
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par cmcmc Voir le message
    Ceci dit, il me semble que quel que soit le devenir des paragraphes numérotés 0-xxx, il reste intéressant que le xxx soit égal au numéro initial.
    C'est discutable, dans le sens où aucun des numéros suivant un numéro marqué * ne sera identique à sa valeur initiale (dans ce cas, pourquoi les numéros marqués 0- le devraient ? seul Djibril peut nous renseigner en nous indiquant comment seront utilisés ces numéros).

    On peut choisir ou non d'y intégrer la marque s'il y en a une (dans CM_v2.pl, ce comportement est contrôlé ligne 44, voir le commentaire, et pourrait être passé en option). En tout cas imposer la bijectivité de la transformation fournit à bon compte un test d'intégrité que je trouve bienvenu.
    J'en conviens. Mais gardons à l'esprit que ce n'est pas le "fonctionnel" qui doit être guidé par le "test" mais l'inverse (j'ai sans doute trop l'habitude de travailler dans des contextes "sécuritaires", qui notamment interdisent les codes "morts" ou les codes de test au sein d'un code produit, cf standards aéro et ferro ; ceci explique peut-être cela).
    Je n'ai pas testé la suggestion de modification, mais il devrait être facile de l'appliquer à Philou67430_v1.pm pour produire Philou67430_v2.pm , et d'adapter test_CM_v2_lvr.pl en test_Philou67430_v2_lvr.pl (s/CM_v2/Philou67430/g) pour faire un test
    Devant la profusion de scripts fonctionnel et de test, je n'oserais plus intervenir. Bravo pour ce travail de test, qui montre une démarche saine et trop rarement mise en oeuvre en perl (à part sans doute pour les modules publiés sur le CPAN).
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  13. #53
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Devant la profusion de scripts fonctionnel et de test, je n'oserais plus intervenir. Bravo pour ce travail de test, qui montre une démarche saine et trop rarement mise en oeuvre en perl (à part sans doute pour les modules publiés sur le CPAN).
    Merci, et comme tu veux , mais le test est vraiment fait pour fonctionner avec différentes méthodes. La seule modif à apporter dans le code de test est bien dans le "use méthode.pm;" et l'invocation du transformateur "méthode::transformateur(\&balaye_lvr, $process, $k, $p, $debug, \$nb_errs, \$last_err);".
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  14. #54
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Merci à tous.

    Moi, le 0- était juste utile pour me faire une indication. Dans mon programme déjà mis en prod, j'ai d'ailleur utilisé le préfixe no- au lieu de 0-.
    De plus, je donne au code une liste ordonnée ne contenant qu'une seule étoile par profondeur afin que le code de philou fonctionne comme je le souhaite (I* I-A, I-B... et non I* I-A* I-B...).
    Et la correspondance ne m'est utile que dans un seul sens à savoir ancien -> nouveau.

  15. #55
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    @cmcmc: j'ai modifié ton fichier de test pour qu'il ne dépende plus du nom du module à tester (au prix d'une de-strictification des références, appliquée localement) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    # test.pl
    use strict;
    use warnings;
    use 5.010;
     
    sub try_load($;$) {
      my ($module, $catch) = @_;
      eval "use $module;";
      say $@ if $@;
      die !defined $catch ? "Please install module $module by calling\ncpan $module\n" :
        $catch if (!defined $catch || $catch) && $@;
      return !$@;
    }
     
    my $module = $ARGV[0] or die "Usage: $0 <module to check>\n";
    say "Loading module $module";
    try_load($module) or die "Failed !\n";
     
    # notre premiere fonction de balayage et modification de sommaire.
    sub balaye_et_modifie_liste {
        my ($renum, $liste) = @_;
        $_ = $renum->($_) for @$liste;
    }
     
    my @sections = qw(Un* Un-Foo Un-Bar Deux Deux-Foo* Deux-Bar Deux-Bar-One Deux-Bar-Two Deux-Bar-Three Trois* Trois-Foo Trois-Bar Quatre Quatre-Foo Quatre-Bar );
    my %new_sections = (
                      'Un*' => '0-Un',
                      'Un-Foo' => '0-Un-Foo',
                      'Un-Bar' => '0-Un-Bar',
                      'Deux' => 'Un',
                      'Deux-Foo*' => '0-Deux-Foo',
                      'Deux-Bar' => 'Un-Foo',
                      'Deux-Bar-One' => 'Un-Foo-One',
                      'Deux-Bar-Two' => 'Un-Foo-Two',
                      'Deux-Bar-Three' => 'Un-Foo-Three',
                      'Trois*' => '0-Trois',
                      'Trois-Foo' => '0-Trois-Foo',
                      'Trois-Bar' => '0-Trois-Bar',
                      'Quatre' => 'Deux',
                      'Quatre-Foo' => 'Deux-Foo',
                      'Quatre-Bar' => 'Deux-Bar'
                    );
    # voilà comment devrait être la liste après modifications
    my @voulu = map $new_sections{$_}, @sections;
     
    say "avant: @sections";
    {
      no strict qw(refs);
      &{$module."::transformateur"}(\&balaye_et_modifie_liste, \@sections);
    }
    say "apres: @sections";
    say "voulu: @voulu";
     
    use Test::More;
    is_deeply(\@sections, \@voulu, "notre première liste (" . scalar(@sections) . " éléments) a bien été modifiée comme attendu");
    done_testing;
    J'ai aussi modifié la version Philou67430_v1.pm en v2 avec la modification que j'avais proposée, mais elle échoue à double titre :
    - d'abord, les numéros en * sont modifiés malgré l'ajout de l'assertion négative (?!\*) ; j'investiguerai demain
    - ensuite parce que cette modification ne permettra pas d'éviter la modification des descendants de ces numéros en *, et là, le correctif nécessaire est beaucoup moins trivial : il faudrait revoir le mécanisme des @changes pour limiter leur étendue de manière explicite lors de leur mise en place ; je verrai demain si je trouve une solution élégante pour ça.
    En attendant, le contenu du module modifié :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    # Philou67430_v2.pm
    package Philou67430_v2;
    use strict;
    use warnings;
    use 5.010;
     
    sub transformateur {
      my $balaye = shift;
     
      my (@level, @changes, %new_sections) = ();
      my %stats;
      my $a_la_volee = sub {
        my $num = shift;
     
        my $level = -1 + split /-/, $num;
        my $old_num = $num;
        my $to_remove = $num =~ s/\*$//;
        push @level, [] if    $level > @level-1;
        pop  @level     while $level < @level-1;
     
        $stats{substitutions}++, $num =~ s/$_->[0](?!\*)/$_->[1]/ foreach @changes;
        push @{$level[$level]}, $num;
        if ($to_remove) {
    	    push @changes, [ "^".quotemeta "$num-", "0-$num-" ];
    	    $new_sections{ $old_num } = "0-$num" ;
        }
        else {
    	    my $new_num = shift @{$level[$level]};
    	    push @changes, [ "^".quotemeta "$num-", "$new_num-" ];
    	    $new_sections { $old_num } = $new_num ;
        }
      };
     
      $balaye->($a_la_volee, @_);
      return wantarray ? (\%new_sections, \@level, \@changes, \%stats) : \%new_sections;
    }
     
    1;
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  16. #56
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    En fait c'est un peu plus complexe que prévu de tester Philou67430_v1.pm.

    Il faut éliminer les test de bijectivité de la transformation. Ce qui veut dire qu'on n'a pas de test en fait pour les marquages aléatoires. Par ailleurs, il ne faut pas non plus effectuer la comparaison lorsque la valeur attendue est préfixée par 0-. Modulo ces aménagements, les tests passent (pour ce qu'ils valent ). Par contre les perfs ne suivent pas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v1_lvr.pl 3 | tail -1
    1..20
     
    real	0m0.454s
    user	0m0.061s
    sys	0m0.031s
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v1_lvr.pl 4 | tail -1
    1..30
     
    real	0m3.619s
    user	0m0.124s
    sys	0m0.015s
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v1_lvr.pl 5 | tail -1
    1..40
     
    real	8m4.998s
    user	0m0.030s
    sys	0m0.061s
    Taisha:~/tttmp/sommaire $
    k = p = 5 correspond à un sommaire de 3950 entrées, ce qui commence peut être à être important mais je ne connais pas le domaine d'application...

    Ci-dessous jusqu'à k = p = 7 (960799 entrées ) avec CM_v2 (il y a trois fois plus de tests à chaque niveau car on vérifie que la transformation est bijective).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    time perl test_CM_v2_lvr.pl 3 | tail -1
    1..60
     
    real	0m0.402s
    user	0m0.047s
    sys	0m0.045s
    Taisha:~/tttmp/sommaire $ time perl test_CM_v2_lvr.pl 4 | tail -1
    1..90
     
    real	0m0.552s
    user	0m0.015s
    sys	0m0.045s
    Taisha:~/tttmp/sommaire $ time perl test_CM_v2_lvr.pl 5 | tail -1
    1..120
     
    real	0m2.029s
    user	0m0.077s
    sys	0m0.015s
    Taisha:~/tttmp/sommaire $ time perl test_CM_v2_lvr.pl 6 | tail -1
    1..150
     
    real	0m25.125s
    user	0m0.047s
    sys	0m0.030s
    Taisha:~/tttmp/sommaire $ time perl test_CM_v2_lvr.pl 7 | tail -1
    1..180
     
    real	7m18.354s
    user	0m0.061s
    sys	0m0.015s
    Taisha:~/tttmp/sommaire $
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  17. #57
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    En attendant, le contenu du module modifié :
    Il passe les tests aussi, mais les perfs se dégradent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v2_lvr.pl | tail -1
    1..20
     
    real	0m0.426s
    user	0m0.031s
    sys	0m0.062s
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v2_lvr.pl 4 | tail -1
    1..30
     
    real	0m5.840s
    user	0m0.016s
    sys	0m0.061s
    Taisha:~/tttmp/sommaire $ time perl test_Philou67430_v2_lvr.pl 5 | tail -1
    1..40
     
    real	10m42.549s
    user	0m0.046s
    sys	0m0.046s
    Taisha:~/tttmp/sommaire $
    Pour référence, voici le code de test modifié utilisé:


    C'est le même que test_Philou67430_v1_lvr.pl, en remplaçant v1 par v2.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    # test_Philou67430_v2_lvr.pl
    use strict;
    use warnings;
    use Philou67430_v2;
    use 5.010;
    use Test::More; 
     
    # balaye une liste virtuelle régulière de profondeur $p (toplevel = 1, feuilles = p), 
    # avec $k noeuds à chaque niveau. 
    #  1 1-1 ... 1-k-..-k
    #  2 2-1 ... 2-k-..-k
    #  ...
    #  k k-1 ... k-k-..-k
    # cette liste contient k + k**2 + ... + k**p) élements
    #
    # appelle $process->($renum, $k, $p, $current, @rest) pour chacun des numéros $current de la liste. 
     
    sub balaye_lvr {
        my ($renum, $process, $k, $p, @rest) = @_;
        my $balaye; # fonction auxiliaire interne récursive
        $balaye = sub {
    	my $parent = shift;
    	$parent //= q{};
    	for (1 .. $k) {
    	    my $current = $parent ? "$parent-$_" : $_;
    	    return if ($current =~ y/-/-/) >= $p;
    	    $process->($renum, $k, $p, $current, @rest);
    	    $balaye->($current);
    	}
        };
        $balaye->();
    }
     
    sub taille {
        my ($k, $p) = @_;
        my $t = 0;
        $t = $k + $k*$t for (1 .. $p);
        $t
    }
     
    if (0) {
        sub show_list {
    	my ($renum, $k, $p, $current) = @_;
    	say +(q{  } x $current =~ y/-/-/), $current;
        }
     
        for my $k (1 .. 3) {
    	for my $p (1 .. 3) {
    	    say "-------- show_list k = $k p = $p";
    	    balaye_lvr(undef, \&show_list, $k, $p);
    	}
        }
    }
     
    # aucun noeud n'est marqué
    sub process_marque_aucun {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = $old;
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $exp =~ m/^0-/ || $new eq $exp;
    }
     
    # tous les noeuds sont marqués
    sub process_marque_tous {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = "$cur*";
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = "0-$cur";
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $exp =~ m/^0-/ || $new eq $exp;
    }
     
    # Tous les noeuds de profondeur 1 sont marqués sauf le dernier : 
    # après modification tous les noeuds doivent être préfixés par 0
    # sauf les p derniers (k k.1 ... k-k..k) qui sont
    # transformés en      (1 1-1 ... 1-k..k)
    sub process_marque_top_sauf_k {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = ($cur =~ m/^\d+$/ && $cur != $k) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = $cur =~ m/^$k-?/
    	? $cur =~ s/^\d+/1/r
    	: "0-$cur";
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $exp =~ m/^0-/ || $new eq $exp;
    }
     
    # les noeuds de profondeur 1 et d'index impaire (1, 3, 5, ...) sont marqués
    # après modification tous les noeuds dont le toplevel est d'index impair doivent être préfixés par 0
    # et les autres (n n-1 ... n-k..k) transformés en (m m-1 ... m-k..k) avec m = n/2
    sub process_marque_top_impair {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $old = (($cur =~ m/^\d+$/) and ($cur % 2)) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = do {
    	my ($top) = $cur =~ m/^(\d+)/;
    	if ($top % 2) {
    	    "0-$cur";
    	} else {
    	    $cur =~ s{^$top}{$top/2}e;
    	    $cur
    	}
        };
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $exp =~ m/^0-/ || $new eq $exp;
    }
     
    # les noeuds de valeur k et parents k à la profondeur k sont marqués :
    #>  1*  1-1   1-1-1   1-1-2   1-1-3   1-2   1-2-1   1-2-2   1-2-3   1-3   1-3-1   1-3-2   1-3-3
    #<  0-1 0-1-1 0-1-1-1 0-1-1-2 0-1-1-3 0-1-2 0-1-2-1 0-1-2-2 0-1-2-3 0-1-3 0-1-3-1 0-1-3-2 0-1-3-3
    #>  2   2-1   2-1-1   2-1-2   2-1-3   2-2*  2-2-1   2-2-2   2-2-3   2-3   2-3-1   2-3-2   2-3-3
    #<  1   1-1   1-1-1   1-1-2   1-1-3   0-2-2 0-2-2-1 0-2-2-2 0-2-2-3 1-2   1-2-1   1-2-2   1-2-3
    #>  3   3-1   3-1-1   3-1-2   3-1-3   3-2   3-2-1   3-2-2   3-2-3   3-3   3-3-1   3-3-2   3-3-3*
    #<  2   2-1   2-1-1   2-1-2   2-1-3   2-2   2-2-1   2-2-2   2-2-3   2-3   2-3-1   2-3-2   0-3-3-3
    sub process_marque_diagonale_k_k {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref) = @_;
     
        # marquage et renumérotation
        my $is_marked;
        my $is_marked_or_after_marked = 1;
        {
    	my @nums = split q{-}, $cur;
          loop:
    	for (1 .. $nums[0]) {
    	    if (@nums < $nums[0]) {
    		$is_marked_or_after_marked = 0;
    		last loop
    	    }
    	    unless ($nums[$_-1] == $nums[0]) {
    		$is_marked_or_after_marked = 0;
    		last loop
    	    }
    	}
    	$is_marked = $is_marked_or_after_marked && ($nums[0] == scalar(@nums));
        }
        my $old = $is_marked ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # vérification
        my $exp = do {
    	if ($is_marked_or_after_marked) {
    	    "0-$cur";
    	} else {
    	    my @nums = split q{-}, $cur;
    	    my @orig = @nums;
    	    # pour décrémenter le nombre en position x
    	    # il faut que tous ses parents soient == x 
    	    # et que lui même soit >= x
    	  decrement:
    	    for my $depth (0 .. $#nums) { # x - 1 
    		for (0 .. $depth-1) {
    		    next if $_ < 0;
    		    next decrement unless $orig[$_] == $depth + 1;
    		}
    		for ($depth) {
    		    next if $_ < 0;
    		    next decrement unless $orig[$_] >= $depth + 1;
    		}
    		--$nums[$depth];
    	    }
    	    join q{-}, @nums;
    	}
        };
     
        ++$$nb_errs_ref, warn "$old gave $new instead of $exp" unless $exp =~ m/^0-/ || $new eq $exp;
    }
     
    # marque de manière aléatoire un pourcentage donné de noeuds
    # pas de vérification possible : on renvoie un nombre d'erreurs négatif
    sub process_marque_x_pourcent {
        my ($renum, $k, $p, $cur, $debug, $nb_errs_ref, $last_err_ref, $pourcentage) = @_;
        # marquage et renumérotation
        my $old = (rand(100) <= $pourcentage) ? "$cur*" : $cur;
        my $new = $renum->($old);
        say +(q{  } x ($cur =~ y/-/-/)), sprintf("%-10s%-10s", $old, $new) if $debug;
     
        # pas de vérification possible : on renvoie un nombre d'erreurs négatif
        --$$nb_errs_ref;
    }
     
    my $kmax = (shift @ARGV) // 3;
    for my $marquage (qw(aucun tous top_sauf_k top_impair diagonale_k_k 10 20 30 40 50)) {
        for my $k (2 .. $kmax) {
    	my ($p, $debug, $nb_errs, $last_err) = ($k, $k <= 3, 0);
    	my $taille_de_la_liste = taille($k,$p);
    	my $process = sub {
    	    no strict 'refs';
    	    $marquage =~ m/^\d+$/ 
    		? "process_marque_x_pourcent"->(@_, $marquage)
    		: "process_marque_$marquage"->(@_)
    	};
    	my ($new_sections)
    	    = Philou67430_v2::transformateur(\&balaye_lvr, $process, $k, $p, $debug, \$nb_errs, \$last_err);
    	my $methode = $marquage =~ m/^\d+$/ ? "${marquage}_pourcent" : $marquage ;
    	cmp_ok $nb_errs, "<=", 0, "[$methode k=$k p=$p] " . ($nb_errs == 0 ? "pas d'erreurs de numérotations observées" : "(non significatif : contrôle non effectué)");
    	# my $ndkeys = keys %{$new_sections};
    	# is $ndkeys, $taille_de_la_liste, "[$methode k=$k p=$p] le nombre de clés (old) est bien égal à taille de la liste";
    	# my %new2old= reverse %{$new_sections};
    	# my $ndvals = keys %new2old;
    	# is $ndvals, $ndkeys, "[$methode k=$k p=$p] le nombre de valeurs (new) est égal au nombre de clés (old)";
        }
    }
     
    done_testing;
    A ce stade je crois que personne ne t'en voudra si tu jettes l'éponge
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  18. #58
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Evidemment, l'idéal serait d'avoir simplement un test_lvl.pl et de passer le module testé en paramètre, comme Philou67430 l'a fait avec test_CM_v2.pl, qu'il aurait pu rebaptiser pour l'occasion test.pl puisqu'il ne dépend plus du tout de CM_v2.

    Mais ça suppose que les modules testés passent le test de bijection et préfixent par 0- comme je le fais, ce qui n'est pas forcément requis.
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  19. #59
    Membre confirmé
    Avatar de cmcmc
    Homme Profil pro
    Inscrit en
    Juillet 2013
    Messages
    316
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2013
    Messages : 316
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Mais gardons à l'esprit que ce n'est pas le "fonctionnel" qui doit être guidé par le "test" mais l'inverse (j'ai sans doute trop l'habitude de travailler dans des contextes "sécuritaires", qui notamment interdisent les codes "morts" ou les codes de test au sein d'un code produit, cf standards aéro et ferro ; ceci explique peut-être cela).
    C'est un point très intéressant. Je pourrais contester la première phrase, en disant qu'un programme ne vaut que s'il a été testé. Idéalement, complètement testé, et ceux qui ont fait joujou avec Devel::Cover savent à quel point c'est difficile. Si la testabilité du code implique un peu de feedback sur les specs fonctionnelles, en particulier à la marge ou sur des aspects laissés libres, ce n'est pas grave...

    En l'occurrence, et comme déjà mentionné, le test de bijection était a minima un garde fou, et le seul dont on dispose pour les tests de marquage aléatoire. Si tu as une autre idée je suis preneur !

    On peut observer également qu'il n'y a aucun code mort ou de test dans CM_V2.pm, hormis peut être le fait de retourner certaines variables internes à fins d'instrumentation (cette instrumentation pouvant par exemple être déclenchée par l'utilisation de transformateur en contexte de liste). J'avais été un peu plus agressif dans ma réécriture initiale de Philou67430_v1.pm, en introduisant la déclaration de %stats et la mesure effective du nombre de substitutions effectuées. Ce genre de code d'instrumentation peut facilement être ignoré en prod.

    Toutes les impressions de debug sont en fait générées par les fonctions de test elles mêmes.

    Et comme souvent, on se retrouve avec un code de test significativement plus volumineux que le code à tester lui même, voire plus complexe.... Mais c'est normal, même si ça pose d'autres problèmes (j'ai plus transpiré pour écrire le code de validation de diagonale_k_k que sur tout le reste du code ). Les codes de tests sont normalement utilisables pour tester d'autre approches, et sont typiquement plus pérennes que les codes testés...
    Sauf indication contraire tous les codes que je présente sont utilisables et testés (mais sans garantie d'aucune sorte)
    J'apporte beaucoup de soin à la rédaction de mes posts et apprécie les retours donc merci de s'il vous paraissent pertinents ou utiles
    Lazyness, Impatience and Hubris are good for you

  20. #60
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par cmcmc Voir le message
    Evidemment, l'idéal serait d'avoir simplement un test_lvl.pl et de passer le module testé en paramètre, comme Philou67430 l'a fait avec test_CM_v2.pl, qu'il aurait pu rebaptiser pour l'occasion test.pl puisqu'il ne dépend plus du tout de CM_v2.
    C'est exactement ce que j'ai fait chez moi, le fichier s'appelant test.pl. J'ai juste oublié de modifié l'information dans le commentaire d'entête
    Mais ça suppose que les modules testés passent le test de bijection et préfixent par 0- comme je le fais, ce qui n'est pas forcément requis.
    Ne peut-on pas définir un test comme "optionnel" ? (ainsi, s'il échoue, il ne pénalise pas globalement le test).

    Citation Envoyé par cmcmc Voir le message
    C'est un point très intéressant. Je pourrais contester la première phrase, en disant qu'un programme ne vaut que s'il a été testé.
    La phrase que tu cites ne dit pas qu'un programme ne doit pas être testé, mais simplement que ses fonctionnalités ne doivent pas, a priori, intégrer des contraintes pour les tests. Tout au plus, au niveau design, on peut introduire des moyens de test (interface de test et de diagnostic par exemple), mais selon moi, en aucun cas les spécifications fonctionnelles ne doivent être impactées. Il serait préjudiciable à tout projet qu'une fonctionnalité de test, et donc développée dans le produit, soit sujette à des effets de bord sur d'autres fonctionnalités, une complexification du projet, ou même à des bugs.

    Idéalement, complètement testé, et ceux qui ont fait joujou avec Devel::Cover savent à quel point c'est difficile. Si la testabilité du code implique un peu de feedback sur les specs fonctionnelles, en particulier à la marge ou sur des aspects laissés libres, ce n'est pas grave...
    Je ne suis pas convaincu : la robustesse d'un code résidant aussi dans sa simplicité, ajouter des fonctionnalités "inutiles pour le produit final" (en dehors de sa testabilité), c'est souvent ajouter des risques et des couts. Mais bien sûr, cela peu se mesurer en amont. Dans le cas présent, la bijectivité comme fonctionnalité me semble inutile, mais elle ne devrait pas présenter de grand risque à l'appliquer.
    En l'occurrence, et comme déjà mentionné, le test de bijection était a minima un garde fou, et le seul dont on dispose pour les tests de marquage aléatoire. Si tu as une autre idée je suis preneur !
    On pourrait tester la bijectivité pour tous les numéros de sections non écartés (non suivi de * dans le sommaire d'origine), et ne rien tester concernant ceux écartés, ce qui correspondrait à tester ce qui est fonctionnellement spécifié : on souhaite obtenir un nouveau sommaire en écartant certains numéro d'un sommaire initial. Ainsi, on ne teste que le nouveau sommaire, et on vérifie bien que chaque élément à conserver dans l'ancien sommaire est bien présent une et une seule fois dans le nouveau sommaire.
    On peut observer également qu'il n'y a aucun code mort ou de test dans CM_V2.pm, hormis peut être le fait de retourner certaines variables internes à fins d'instrumentation (cette instrumentation pouvant par exemple être déclenchée par l'utilisation de transformateur en contexte de liste).
    J'avais parler de ces aspects pour illustrer mes contraintes sur les projets qui m'occupent en ce moment, et pour justifier que je sois "si pointilleux" Je ne voulais pas dire que ton code contenait de tels éléments.
    J'avais été un peu plus agressif dans ma réécriture initiale de Philou67430_v1.pm, en introduisant la déclaration de %stats et la mesure effective du nombre de substitutions effectuées. Ce genre de code d'instrumentation peut facilement être ignoré en prod.
    Pour moi, ce code ajouté fait partie de la conception, et représente un code de test. Il est à différencier d'une spécification fonctionnelle de test, qui serait décrite au niveau supérieur, et qui imposerait (comme la bijection par exemple) des fonctions non utiles au produit lui-même. Cela dit, même l'instrumentation de code est interdite sur les projets aéro et ferro (en production et en développement : la phase de test doit se faire avec une version "identique" à la version de production). Bien sûr, pour un projet comme celui de djibril, ces considérations sont excessives.
    Toutes les impressions de debug sont en fait générées par les fonctions de test elles mêmes.

    Et comme souvent, on se retrouve avec un code de test significativement plus volumineux que le code à tester lui même, voire plus complexe.... Mais c'est normal, même si ça pose d'autres problèmes (j'ai plus transpiré pour écrire le code de validation de diagonale_k_k que sur tout le reste du code ). Les codes de tests sont normalement utilisables pour tester d'autre approches, et sont typiquement plus pérennes que les codes testés...
    Repose toi bien alors

    Bon, je vais essayer de reprendre mon code v2 pour voir comment traiter les * (ou bien encore comment reprendre le code de test.pl pour supprimer le test de bijectivité sur les éléments en *)
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

Discussions similaires

  1. [Débutant] Changer la numérotation sc. de l'axe x dans un plot
    Par nels81 dans le forum MATLAB
    Réponses: 2
    Dernier message: 13/04/2013, 15h35
  2. Changer les numérotations des \subsubsection{} par une lettre
    Par amad206 dans le forum Mise en forme
    Réponses: 2
    Dernier message: 09/11/2009, 17h40
  3. changer la numérotation des sections
    Par Infotic dans le forum Mise en forme
    Réponses: 2
    Dernier message: 16/07/2009, 13h27
  4. Changer la numérotation chapitre et sections
    Par timesmoney dans le forum Mise en forme
    Réponses: 5
    Dernier message: 12/05/2008, 23h00
  5. Changer la numérotation des sections
    Par Doniphon dans le forum Mise en forme
    Réponses: 5
    Dernier message: 09/11/2006, 12h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo