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

Algorithmes et structures de données Discussion :

Génération des combinaisons K parmi N d'une liste mais avec des éléments ayant plusieurs états (vecteurs)


Sujet :

Algorithmes et structures de données

  1. #1
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut Génération des combinaisons K parmi N d'une liste mais avec des éléments ayant plusieurs états (vecteurs)
    Bonjour,
    Il faut que je génère la liste de toutes les combinaisons possibles de cardinalité K pour une liste d'élément de N éléments.
    Le problème c'est que chacun des éléments de ma liste peut avoir plusieurs états. Il me faut générer toutes les combinaisons possibles de cardinalité K (2< K < N) en prenant en compte les variantes de chacun des éléments, sans mettre dans la combinaison un même élément sous deux états.

    Je ne sais pas si je suis très clair, je vais donc vous donner un exemple:
    List<Elements> list = (elemA, elemB, elemC)
    elemA a 2 états: elemA1, elemA2
    elemB a 2 états: elemB1, elemB2
    elemC a 2 états: elemC1, elemC2

    je dois générer l'ensemble des combinaisons non ordonnées des elements avec les autres peut importe leur état.
    Si la cardinalité est 2, je pense que cela donnerait:
    (elemA1, elemB1), (elemA1, elemB2), (elemA1, elemC1), (elemA1, elemC2),
    (elemA2, elemB1), (elemA2, elemB2), (elemA2, elemC1), (elemA2, elemC2),
    (elemB1, elemC1), (elemB1, elemC2),
    (elemB2, elemC1), (elemB2, elemC2)

    la cardinalité de la liste N est variable. Idem pour la cardinalité K des combinaisons à générer. (il me faudra toutes les combinaisons pour K allant de 2 à N-1)
    Mon nombre d'état est fixe (2) pour chacun des éléments de la liste mais tant qu'à faire, je me pose la question d'une solution générique ou chacun des éléments aurait son vecteur d'état de dimension variable.

    Quelqu'un a une idée ou déjà fait ce genre de combinatoire?
    Mon appli est en C++ mais le langage importe peu.

    Merci d'avance!

  2. #2
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Génération des combinaisons K parmis N d'une liste mais avec des éléments ayant plusieurs états (vecteurs))?
    Bonjour,

    À priori, la sélection de (K) éléments pris dans une liste en comportant (N) devrait permettre de réaliser CNK = N!/(K!*(N - K)!) combinaisons.

    Si de plus chacun de ces éléments présente (Ei) états différents, sans exclusion mutuelle (sont compatibles au sein d'une combinaison donnée tous les états de tous les éléments présents), le nombre de combinaisons possibles devient:

    C' = Somme(P(Ei))

    expression dans laquelle intervient la somme des produits des nombres d'états des éléments présents dans une combinaison donnée, soit (CNK) termes.

    Exemple: pour un ensemble de (N = 5) éléments (V, W, X, Y, Z) présentant respectivement (2, 3, 4, 5, 6) états différents, on devrait avoir:
    C53 = (4*5/2) = 10 combinaisons de 3 termes, et en tenant compte des divers états:
    C' = PVWX + PVWY + PVWZ + PVXY + PVXZ + PVYZ + PWXY + PWXZ + PWYZ + PXYZ avec
    # PVWX = 2 * 3 * 4 = 24
    # PVWY = 2 * 3 * 5 = 30
    # PVWZ = 2 * 3 * 6 = 36
    # PVXY = 2 * 4 * 5 = 40
    # PVXZ = 2 * 4 * 6 = 48
    # PVYZ = 2 * 5 * 6 = 60
    # PWXY = 3 * 4 * 5 = 60
    # PWXZ = 3 * 4 * 6 = 72
    # PWYZ = 3 * 5 * 6 = 90
    # PXYZ = 4 * 5 * 6 = 120 , soit au total: 580 (calculs à vérifier ).

    Dans le cas particulier de nombres d'états tous identiques, on obtient C'(N, K, NE) = (CNK)*(NE)K , soit:
    # C'(N, K, 1) = (CNK)*(1K) = CNK dans le cas d'un état unique, et
    # C'(3, 2, 2) = (C32)*(22) = 3 * 4 = 12 pour l'exemple que tu as choisi (N = 3, K = 2, NE = 2).

    L'expression générale de (C') est possible, mais vraiment très lourde.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  3. #3
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    re bonjour,
    Merci pour ta réponse rapide. En effet je vois maintenant la formule C'(N, K, NE) = C(N,K)*NE^K

    Sachant qu'il va me falloir générer l'ensemble des combinaisons de cardinalité K dans N éléments qui ont 2 états pour K variant de 1 à N, j'obtiens
    SUM(k=1..N, C(n,k)*2^k)
    ce qui donne:
    SUM(C(2, k) with 2 states) = 8
    SUM(C(3, k) with 2 states) = 26
    SUM(C(4, k) with 2 states) = 80
    SUM(C(5, k) with 2 states) = 242
    SUM(C(6, k) with 2 states) = 728
    SUM(C(7, k) with 2 states) = 2186
    SUM(C(8, k) with 2 states) = 6560
    SUM(C(9, k) with 2 states) = 19682
    SUM(C(10, k) with 2 states) = 59048
    SUM(C(11, k) with 2 states) = 177146
    SUM(C(12, k) with 2 states) = 531440
    SUM(C(13, k) with 2 states) = 1594322
    SUM(C(14, k) with 2 states) = 4782968
    SUM(C(15, k) with 2 states) = 14348906

    ça monte vite! Normalement mon N sera inférieur à 10... j'espère...

    Du coup je vois mieux comment générer toutes les combinaisons pour un N, K donné:
    - d'abord je génère la liste avec le premier état
    - puis pour J allant de 1 à N, j'augmente la liste en changeant l'état de l'élément J

    sur mon exemple de 2 parmis 3 cela ferait:
    iter1: (A1, B1) (A1, C1) (B1, C1)
    iter2: (A1, B1) (A1, C1) (B1, C1), (A2, B1) (A2, C1)
    iter3: (A1, B1) (A1, C1) (B1, C1), (A2, B1) (A2, C1) , (A1, B2) (B2, C1), (A2, B2)
    iter4: (A1, B1) (A1, C1) (B1, C1), (A2, B1) (A2, C1) , (A1, B2) (B2, C1), (A2, B2) , (A1, C2) (B1, C2), (A2, C2) , (B2, C2)

    Que pensez vous de cette approche?

    Le problème c'est que j'ai une contrainte en plus:
    Lorsque je calcule mon ensemble de combinaison K parmis N, List(N, K), je fais un calcul pour chacune des combinaisons.
    J'ai donc une MAP avec pour clef une liste, et pour valeur mon résultat.

    Pour la génération de l'ensemble de combinaisons K+1 parmis N, je ne suis pas intéressé par celle contenant un sous ensemble de cardinalité K qui a un résultat spécifique dans ma Map.
    Serait il possible de générer cet ensemble de combinaisons K+1 parmis N en excluant directement celles qui ne m'intéressent plus?
    Cela m'éviterait de les calculer toutes pour ensuite tester pour chacune d'elle tous les sous ensembles de cardinalité K et potentiellement les enlever.

    Voyez vous ce que je veux dire?
    dans mon exemple en dimension 3, j'avais d'abord calculé l'ensemble des combinaison de cardinalité 1: A1, B1, C1, A2, B2, C2
    Supposons que mon calcul me donne le résultat attendu pour A1,
    je ne veux donc plus dans ma liste de cardinalité 2 tous les couples contenant A1.
    i.e: (B1, C1), (A2, B1) (A2, C1) , (B2, C1), (A2, B2) , (B1, C2), (A2, C2) , (B2, C2)

    Une idée de comment générer une telle liste directement? ma méthode simple ne marche plus...

    Pour continuer la logique en cardinalité 3, si (A2, B2) et (B2, C2) me donne le résultat attendu, au lieu de la liste complète
    (A1, B1, C1) (A2, B1, C1) (A1, B2, C1) (A2, B2, C1) (A1, B1, C1) (A2, B1, C1) (A1, B2, C1) (A2, B2, C1)

    je ne suis intéressé que par: (A2, B1, C1) (A2, B1, C1)

  4. #4
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Bonjour

    Que pensez vous de cette approche?
    Elle est foireuse.
    Wiwaxia a été très clair : Tu choisis les éléments, puis, tu choisis les états.
    Je ne comprends pas que tu listes des AC avant d'avoir lister tous les états des AB.

    Serait il possible de générer cet ensemble de combinaisons K+1 parmis N en excluant directement celles qui ne m'intéressent plus?
    Oui.

    Voyez vous ce que je veux dire?
    Un peu. Mais quel est la difficulté ?

    Une idée de comment générer une telle liste directement?
    Ben déjà, nous ne savons pas où tu es. Dans des boucles imbriquées ? Dans une liste que tu stockes vraiment en mémoire ?
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  5. #5
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Elle est foireuse.
    Wiwaxia a été très clair : Tu choisis les éléments, puis, tu choisis les états.
    Je ne comprends pas que tu listes des AC avant d'avoir lister tous les états des AB.
    Je serais parti d'un algo existant me fournissant la liste des combinaisons utilisant le premier état de chacun des éléments. (Iter1, j'obtiens une liste de C(n,k) éléments)
    C'est ensuite que j'imaginais compléter la liste avec une boucle sur chacun des élements pour ajouter les variantes.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for each element
        for each combination of the list
            if the combination contains the element
                 add to the list the combination where the state of the element is changed
    Ben déjà, nous ne savons pas où tu es. Dans des boucles imbriquées ? Dans une liste que tu stockes vraiment en mémoire ?
    Je ne sais pas encore comment je vais partir. Je prends des avis avant car j'aimerais partir sur une direction optimale...
    Ça ne m'a pas l'air le cas de la méthode que j'ai décrite, notamment car je ne pourrai pas exclure les combinaisons qui ne m'intéressent pas lors de la construction de la liste...

    Je n'ai pas trop d'autres idées, c'est pourquoi je demande...

  6. #6
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Génération des combinaisons K parmis N d'une liste mais avec des éléments ayant plusieurs états (vecteurs))?
    Citation Envoyé par ramislebob Voir le message
    Je serais parti d'un algo existant me fournissant la liste des combinaisons utilisant le premier état de chacun des éléments. (Iter1, j'obtiens une liste de C(n,k) éléments)
    C'est ensuite que j'imaginais compléter la liste avec une boucle sur chacun des élements pour ajouter les variantes ...
    Il y a bien une autre piste, encore que je n'en voie pas très bien la finalité ... Celle d'une variable tableau de dimensions approximatives (CNK)×((NE)K), que l'on peut envisager si les données (N) et (NE) restent en-deçà de limites raisonnables, conformément aux indications du message (#3): N <~ 10 et NE = 2 .

    Il s'agit apparemment (si j'ai bien compris) de mémoriser:
    a) les (CNK) combinaisons de (K) termes parmi (N), et
    b) la liste correspondante de toutes les combinaisons d'états possibles, soit (NE)K.

    1°) Les combinaisons (VWX, VWY, VWZ ...) peuvent être représentées d'une manière ordonnée en notation binaire par les nombres ($00111, $01011, $10011 ...), donc par des entiers au plus égaux à (25 - 1 = 31) et tels que la somme de leurs chiffres soit égale à 3 (dans le même système de numération); soit donc en généralisant par des entiers vérifiant: Nmax = 2N - 1 et Schb = K
    2°) Les suites d'états sont représentables d'une manière semblable par les nombres ($001, $010, $011 ... $111) au plus égaux à (23 - 1 = 7); et pour un nombre d'états quelconque, par un entier écrit en base (NE) et limité par Emax = (NE)K - 1).

    Etant donné deux types d'entiers (T_Entier1, T_Entier2) respectivement compatibles avec les limites précédentes (Nmax, Emax), un tableau d'enregistrements comme ci-dessous, dont l'initialisation ne poserait pas de problème, pourrait peut-être convenir:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    TYPE LstE2 = ARRAY[0..Emax] OF T_Entier2;
         Ligne = RECORD  Monome: T_Entier1; ListeE: LstE2  END;
         Tab_L = ARRAY[1..Cnk] OF Ligne;
     
    VAR Tableau: Tab_L;


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  7. #7
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Ce n'est pas tout a fait ça. Je vais reformuler le problème:
    - J'ai un ensemble d'éléments de cardinalité N
    - chacun d'eux peut avoir J états (pour l'instant 2 mais ça pourrait changer à 3 ou 4 plus tard, il me faut donc être générique).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    for (K=1 ; K < N ; ++K)
    {
    	combi = get Next Combinaison de cardinalité K avec variation d'état qui ne contient pas une sous liste de cardinalité K-1 incluse dans Resultats_KO[K-1]
    	resultat = executeTest(combi)
    	if (resultat == KO)
    		Resultats_KO[K].insert(combi)
    	else
    		Resultats_Ok[K].insert(combi)
    }
    Je n'ai pas besoin de stocker la liste des combinaisons de cardinalité C(N,K). Ce qui m'intéresse c'est directement mes listes Resultats_KO et Resultats_Ok (classées par cardinalité) qui utilisent directement les variations d'état.
    Le truc c'est que je dois considérer les resultats calculés pour K-1. Cela devrait me limiter considérablement la liste de cardinalité K.

    Je me dis qu'il doit être possible d'inclure cela directement dans l'algo de génération des combinaisons.

    Si je pars sur un algo récursif pour générer les combinaison de K parmis N.
    Quand j'ai une sous liste de cardinalité K-1, ne pourrais je pas partir de là et générer toutes les variantes, ignorer celles qui sont dans MAP Resultats_KO[K-1] et uniquement remplir la dernière étape (pour arriver à une cardinalité K) pour celles restantes?

    Je ne sais pas trop si ça marcherait... ni non plus comment imbriquer l'algo de génération des variantes d'états sur une combinaison de cardinalité K à l'intérieur du générateur de combinaison K parmis N.

  8. #8
    Expert éminent sénior Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 243
    Points : 13 458
    Points
    13 458
    Par défaut
    Si je pars sur un algo récursif
    Ça, c'est pas un bon réflexe.
    Les mathématiciens adorent la récursion car c'est beau, simple et propre.
    Les informaticiens détestent la récursion car tu vas facilement et rapidement faire sauter ta pile d'appel (de fonctions).
    L'alternative à l'algorithme récursif est l'algorithme itératif.

    Le truc c'est que je dois considérer les resultats calculer pour K-1 qui devrait me limiter considérablement la liste de cardinalité K.
    Tu sembles présupposer que tous les cas sont à étudier, sauf ceux déjà validés.
    À ta place, je ferais le contraire. Aucun cas n'est à étudier, sauf ceux que je pointe. Cela évite de vérifier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (K=1 ; K < N ; ++K)
    Une boucle for s'utilise quand on connaît le nombre d'itérations.
    Une boucle while s'utilise quand on ne connaît pas le nombre d'itérations.

    Ici, tu ne connais pas le nombre d'itérations. (sauf pour K)
    Tu peux faire des boucles sur les éléments, mais pour chaque élément, il faut boucler sur les états.
    Et comme le nombre d'éléments changent, le nombre de boucles changent, donc ton code change, et ça, ce n'est pas possible.
    Donc il faut utiliser une forme dynamique, pénible mais naturelle, avec un while capable d'avancer, reculer dans les cas possibles, et savoir quand c'est fini.
    Cette réponse vous apporte quelque chose ? Cliquez sur en bas à droite du message.

  9. #9
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Ça, c'est pas un bon réflexe.
    Les mathématiciens adorent la récursion car c'est beau, simple et propre.
    Les informaticiens détestent la récursion car tu vas facilement et rapidement faire sauter ta pile d'appel (de fonctions).
    Mon nombre d'élément qui est limité (10 max) correspond à mon nombre max d'appel de la fonction. Pas de souci de stackoverflow, du coup je pars sur la solution élégante

    Citation Envoyé par Flodelarab Voir le message
    L'alternative à l'algorithme récursif est l'algorithme itératif.
    Qu'appelles tu algorithme itératif? utilisation de boucles? comment transforme-t'on simplement un algo récursif en itératif?

    Citation Envoyé par Flodelarab Voir le message
    Tu sembles présupposer que tous les cas sont à étudier, sauf ceux déjà validés.
    À ta place, je ferais le contraire. Aucun cas n'est à étudier, sauf ceux que je pointe. Cela évite de vérifier.
    Je ne comprends pas ce que tu veux dire.
    Lors de l'exécution des variations de la cardinalité K-1, j'ai trouvé un sous ensemble de variations ( Resultat_KO[K-1] ) que je n'ai pas besoin d'enrichir d'un element pour la cardinalité K.


    Bon j'ai fait une première version en C++, je vous donne le code. Je génère toutes les variations et ne fait que les afficher pour l'instant.
    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
     
    #include <iostream>
    #include <string>
    #include <vector>
    #include <list>
    #include <utility>
     
    typedef unsigned short ushort;
    typedef unsigned int uint;
    typedef unsigned long ulong;
     
     
    using namespace std;
     
    enum STATES {E1 = 1, E2 = 2, LAST};
    static ushort nbStates = 2;
     
    //enum STATES {E1 = 1, E2 = 2, E3 = 3, LAST};
    //static ushort nbStates = 3;
     
    ulong pow(ushort n, ushort k){
    	ulong res = n;
    	for (ushort i = 1; i < k; ++i)
    		res *= n;
    	return res;
    }
     
    class MyObject{
    	friend ostream& operator<< (ostream& stream, const MyObject& obj){cout << obj.name /*<< obj.type*/; return stream;}
     
    	public:
    		MyObject():name() {}
    		MyObject(const string &str):name(str){}
     
    		bool operator==(const MyObject &other) { return name == other.name;}
     
    	private:
    		string name;
    };
     
     
    template<typename T> void printStateVariations(const vector<T*> &combi, int K)
    {
    	uint nbVariants = pow(nbStates, K);
     
    	// Initialize the output (reserve memory)
    	vector<pair<T*, ushort>*> variants;
    	variants.reserve(nbVariants);
    	for (uint i = 0 ; i < nbVariants ; ++i)
    		variants[i] = new pair<T*, ushort>[K];
     
    	// Initialize the list with all elements in the first state
    	ushort indexNewVar = 0;
    	for (ushort i = 0 ; i < K ; ++i){
    		variants[indexNewVar][i] = {combi[i], E1};
    	}
    	++indexNewVar;
     
     
    	for (ushort indexElem = 0 ; indexElem < K ; ++indexElem)
    	{// for each element
    		T *elem = combi[indexElem];
     
     
    		list<pair<T*, ushort>*>  elemVariants;
    		for (ushort state = E1 + 1 ; state != LAST ; ++state)
    		{ // for all other state
    			for (int i = 0 ; i < indexNewVar ; ++i)
    			{ // for all the variants
    				pair<T*, ushort> *exitingVar = variants[i];
    				ushort index = 0;
    				bool containElem = false;
    				for (; index < K; ++index)
    				{ // find the current element in the combination
    					if (exitingVar[index].first == elem)
    					{
    						containElem = true;
    						break;
    					}
    				}
    				if (containElem)
    				{ // we found the element so we double the combination with the other state
    					pair<T*, ushort> *newVar = new pair<T*, ushort>[K];
    					for (int k = 0 ; k < K ; ++k)
    						newVar[k] = exitingVar[k];
     
    					newVar[index].second = state;
    					elemVariants.push_back(newVar);
    				}
    			}
    		}
     
    		for (pair<T*, ushort> *newVar : elemVariants)
    			variants[indexNewVar++] = newVar;
    	}
     
     
    	for (uint i = 0 ; i < indexNewVar ; ++i)
    	{
    		pair<T*, ushort> *variant = variants[i];
    		for (ushort i = 0 ; i < K ; i++)
    		{
    			cout << *(variant[i].first) << "_" << variant[i].second << " ";
    		}
    		cout << "\n";
    		delete[] variant;
    	}
    }
     
    /* arr[]  ---> Input Array
       data[] ---> Temporary array to store current combination
       start & end ---> Staring and Ending indexes in arr[]
       index  ---> Current index in data[]
       K ---> Size of a combination to be printed */
    template<typename T> void combinationUtil(const vector<T*> &elements, vector<T*> &data, int start, int end, int index, int K)
    {
    	// Current combination is ready to be printed, print it
    	if (index == K)
    	{
    /*
    		for (int i=0; i<r; i++)
    			cout << *(data[i]) << " ";
    		cout << " (data.size() = " << data.size() << ")\n";
    */
    		printStateVariations(data, K);
    		return;
    	}
     
    	// replace index with all possible elements. The condition
    	// "end-i+1 >= r-index" makes sure that including one element
    	// at index will make a combination with remaining elements
    	// at remaining positions
    	for (int i=start; i<=end && end-i+1 >= K-index; i++)
    	{
    		data[index] = elements[i];
    		combinationUtil(elements, data, i+1, end, index+1, K);
    	}
    }
     
     
    template<typename T> void printCombination(const vector<T*> &elements, int N, int K)
    {
    	// A temporary array to store all combination one by one
    	vector<T*> data;
    	data.reserve(K);
     
    	// Print all combination using temprary array 'data[]'
    	combinationUtil(elements, data, 0, N-1, 0, K);
    }
     
    int main()
    {
    	vector<MyObject*> elements = {
    		  new MyObject("A")
    		, new MyObject("B")
    		, new MyObject("C")
    //		, new MyObject("D")
    	};
    	int K = 2;
     
    	printCombination(elements, elements.size(), K);
     
    	for (int k = 0 ; k < elements.size(); ++k)
    		delete elements[k];
     
    	return 0;
    }
    Pour compiler et le lancer:
    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
     
    $ g++ --std=c++11 combi.cpp -o combi
    $ ./combi 
    A_1 B_1 
    A_2 B_1 
    A_1 B_2 
    A_2 B_2 
    A_1 C_1 
    A_2 C_1 
    A_1 C_2 
    A_2 C_2 
    B_1 C_1 
    B_2 C_1 
    B_1 C_2 
    B_2 C_2 
    $

    J'ai l'impression qu'il doit pouvoir y avoir moyen de limiter la production des variantes de cardinalité K en les calculant d'abord dans combinationUtil lorsqu'on a atteint la cardinalité K-1 puis au tour d'après de n'enrichir d'un élément que celles qui sont à traiter.
    Qu'en pensez vous?

  10. #10
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Bon c'est cool, je crois que j'ai une solution plutôt optimale \o/
    Je ne stocke rien, je calcule à la volée pour une cardinalité K donnée chacune des variantes (en utilisant les états) mais ne teste uniquement que celles validant le résultat de l'itération avec la cardinalité K-1.

    Du coup, je génère mes variantes (combinaisons avec prise en compte des états) lorsque j'arrive à la cardinalité K-1, comme ça je peux valider avec l'itération d'avant, puis par récursivité je rajoute le dernier élément K manquant en utilisant ses J variantes (J étant le nombre d'état). La petite dernière chose à faire est juste de vérifier que la combinaison de cardinalité K-1 le prenant en compte soit bien validé. Puisque la récursivité me permet d'être sûr de l'ordre de mes éléments, je n'ai qu'une seule comparaison à faire (et non tous les sous ensemble de K-1 parmis K éléments)

    Je vous mets le code (toujours en C++11) pour ceux que ça intéresse.

    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
     
    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
     
    typedef unsigned short ushort;
    typedef unsigned int uint;
    typedef unsigned long ulong;
     
    #define __COMBI_WITH_EXCLUSION_OF_PREVIOUS_CARDINALITY__ 1
    //#define __DEBUG__ 1
     
    using namespace std;
     
    enum STATES {E1 = 1, E2 = 2, LAST};
    static ushort nbStates = 2;
     
    //enum STATES {E1 = 1, E2 = 2, E3 = 3, LAST};
    //static ushort nbStates = 3;
     
     
    ulong pow(ushort n, ushort k){
        ulong res = n;
        for (ushort i = 1; i < k; ++i)
            res *= n;
        return res;
    }
     
    class MyObject{
        friend ostream& operator<< (ostream& stream, const MyObject& obj){cout << obj.name /*<< obj.type*/; return stream;}
     
        public:
            MyObject():name() {}
            MyObject(const string &str):name(str){}
     
            bool operator==(const MyObject &other) { return name == other.name;}
     
        private:
            string name;
    };
     
    template<typename T> struct Resultats{
        map<ushort, vector<vector<pair<T*, ushort>> > > var_KO;
        map<ushort, vector<vector<pair<T*, ushort>> > > var_OK;
    };
     
    static Resultats<MyObject> resultats;
     
     
    template<typename T> bool combinationIsOK(pair<T*, ushort> *combiToTest, ushort K)
    {
    // TODO: if resultats.var_KO[K].size() < resultats.var_OK[K].size()
    // else we should loop on resultats.var_OK[K] ;)
        for (auto & variantKO : resultats.var_KO[K])
        {
            bool isMatching = true;
            for (ushort i = 0 ; i < K ; ++i)
            {
                if (variantKO[i] != combiToTest[i])
                {
                    isMatching = false;
                    break;
                }
            }
            if (isMatching)
                return false;
        }
        return true;
    }
     
     
    template<typename T>  void printCombiVariant(const char* title, pair<T*, ushort> *newVar, ushort K)
    {
        cout << title << " ";
        for (int i = 0 ; i < K ; ++i)
            cout << *(newVar[i].first) << "_" << newVar[i].second << ", ";
        cout << "\n";
    }
     
     
    template<typename T> vector<pair<T*, ushort>*> *getStateVariationsKminus1(
            const vector<T*> &combi,
            ushort K)
    {
        // 1.: Initialize the output (and reserve memory)
        vector<pair<T*, ushort>*> *variants = new vector<pair<T*, ushort>*>();
        variants->reserve(pow(nbStates, K));
     
     
        // 2.: Initialize the list with all elements in the first state
        variants->push_back(new pair<T*, ushort>[K]);
        for (ushort i = 0 ; i < K ; ++i){
            (*variants)[0][i] = {combi[i], E1};
        }
     
     
        // 3.: Do the job!
        for (ushort indexElem = 0 ; indexElem < K ; ++indexElem)
        {// for each element
            T *elem = combi[indexElem];
     
            ushort nbExistingVariants = variants->size();
            vector<pair<T*, ushort>*>  elemVariants;
            for (ushort state = E1 + 1 ; state != LAST ; ++state)
            { // for all other state
     
                for (int i = 0 ; i < nbExistingVariants ; ++i)
                { // for all the variants
                    pair<T*, ushort> *exitingVar = (*variants)[i];
                    ushort index = 0;
                    bool containElem = false;
                    for (; index < K; ++index)
                    { // find the current element in the combination
                        if (exitingVar[index].first == elem)
                        {
                            containElem = true;
                            break;
                        }
                    }
                    if (containElem)
                    { // we found the element so we double the combination with the other state
                        pair<T*, ushort> *newVar = new pair<T*, ushort>[K];
                        for (int k = 0 ; k < K ; ++k)
                            newVar[k] = exitingVar[k];
     
                        newVar[index].second = state;
                        elemVariants.push_back(newVar);
                    }
                }
            }
     
            for (pair<T*, ushort> *newVar : elemVariants)
            {
                if (combinationIsOK(newVar, K))
                {
    #ifdef __DEBUG__
                    printCombiVariant("Adding combi: ", newVar, K);
    #endif
                    variants->push_back(newVar);
                }
            }
        }
     
     
        // 4.: check if we should remove the first variantion
        if (!combinationIsOK((*variants)[0], K))
        {
            auto it = variants->begin();
            delete *it;
            variants->erase(it);
    #ifdef __DEBUG__
            cout << "First combi is not OK...\n";
    #endif
        }
     
     
        // 5.: if the list is empty, free the memory
        if (variants->size() == 0)
        {
            delete variants;
            variants = nullptr;
        }
     
        return variants;
    }
     
    /* arr[]  ---> Input Array
       data[] ---> Temporary array to store current combination
       start & end ---> Staring and Ending indexes in arr[]
       index  ---> Current index in data[]
       K ---> Size of a combination to be printed */
    template<typename T> void combinationWithStateAndSomeExclusions(
            const vector<T*> &elements,
            vector<T*> &data,
            int start,
            int end,
            int index,
            int K,
            vector<pair<T*, ushort>*> *variantsKminus1)
    {
        if (index == K - 1)
        {
    #ifdef __DEBUG__
            cout << "[DEBUG] index = K-1  >>>>>>>>>\n";
    #endif
            variantsKminus1 = getStateVariationsKminus1(data, index);
        }
     
        // Current combination is ready to be printed, print it
        else if (index == K)
        {
            if (variantsKminus1)
            {
                MyObject *lastElem = data[K-1];
                for (uint i = 0 ; i < variantsKminus1->size() ; ++i)
                {
                    pair<T*, ushort> *variant = (*variantsKminus1)[i];
     
                    // we need to add all the variant of the last element missing
                    // if the combination including it from the end is OK
                    for (ushort state = E1 ; state != LAST ; ++state)
                    {
                        pair<T*, ushort> *lastVar = new pair<T*, ushort>[K-1];
                        for (ushort i = 1 ; i < K-1 ; ++i)
                            lastVar[i-1] = variant[i];
                        lastVar[K-2] = {lastElem, state};
     
                        if (combinationIsOK(lastVar, K-1))
                        {
                            for (ushort i = 0 ; i < K-1 ; ++i)
                            {
                                cout << *(variant[i].first) << "_" << variant[i].second << " ";
                            }
                            cout << " " << *lastElem << "_" << state << "\n";
                        }
                    }
                }
            }
            return;
        }
     
        // replace index with all possible elements. The condition
        // "end-i+1 >= r-index" makes sure that including one element
        // at index will make a combination with remaining elements
        // at remaining positions
        for (int i=start; i<=end && end-i+1 >= K-index; i++)
        {
            data[index] = elements[i];
            combinationWithStateAndSomeExclusions(elements, data, i+1, end, index+1, K, variantsKminus1);
        }
     
     
        if (variantsKminus1 && index == K - 1)
        {
            for (uint i = 0 ; i < variantsKminus1->size() ; ++i)
                delete[] (*variantsKminus1)[i];
            variantsKminus1->clear();
            delete variantsKminus1;
            variantsKminus1 = nullptr;
    #ifdef __DEBUG__
            cout << "[DEBUG] index = K-1  <<<<<<<<\n";
    #endif
        }
    }
     
     
     
     
    template<typename T> void combinationWithState(
            const vector<T*> &elements,
            vector<T*> &data,
            int start,
            int end,
            int index,
            int K,
            vector<pair<T*, ushort>*> *variantsKminus1);
     
    template<typename T> void printCombination(const vector<T*> &elements, int N, int K)
    {
        // A temporary array to store all combination one by one
        vector<T*> data;
        data.reserve(K);
     
        // Print all combination using temprary array 'data[]'
        vector<pair<T*, ushort>*> *variantsKminus1 = nullptr;
     
    #ifdef __COMBI_WITH_EXCLUSION_OF_PREVIOUS_CARDINALITY__
        combinationWithStateAndSomeExclusions(elements, data, 0, N-1, 0, K, variantsKminus1);
    #else
        combinationWithState(elements, data, 0, N-1, 0, K, variantsKminus1);
    #endif
    }
     
     
     
    int main()
    {
        vector<MyObject*> elements = {
              new MyObject("A")
            , new MyObject("B")
            , new MyObject("C")
            , new MyObject("D")
        };
        int K = 2;
     
        resultats.var_KO[1].push_back({ {elements[0], E1} }); // exlude A_1
        resultats.var_KO[1].push_back({ {elements[1], E2} }); // exclude B_2
        resultats.var_KO[1].push_back({ {elements[2], E1} }); // exclude C_1
     
     
        printCombination(elements, elements.size(), K);
     
        for (uint k = 0 ; k < elements.size(); ++k)
            delete elements[k];
     
        return 0;
    }
     
     
     
     
     
     
    template<typename T> vector<pair<T*, ushort>*> *getStateVariations(const vector<T*> &combi, int K)
    {
        uint nbVariants = pow(nbStates, K);
     
        // Initialize the output (reserve memory)
        vector<pair<T*, ushort>*> *variants = new vector<pair<T*, ushort>*>();
        variants->reserve(nbVariants);
        for (uint i = 0 ; i < nbVariants ; ++i)
            (*variants)[i] = new pair<T*, ushort>[K];
     
        // Initialize the list with all elements in the first state
        ushort indexNewVar = 0;
        for (ushort i = 0 ; i < K ; ++i){
            (*variants)[indexNewVar][i] = {combi[i], E1};
        }
        ++indexNewVar;
     
     
        for (ushort indexElem = 0 ; indexElem < K ; ++indexElem)
        {// for each element
            T *elem = combi[indexElem];
     
     
            vector<pair<T*, ushort>*>  elemVariants;
            for (ushort state = E1 + 1 ; state != LAST ; ++state)
            { // for all other state
                for (int i = 0 ; i < indexNewVar ; ++i)
                { // for all the variants
                    pair<T*, ushort> *exitingVar = (*variants)[i];
                    ushort index = 0;
                    bool containElem = false;
                    for (; index < K; ++index)
                    { // find the current element in the combination
                        if (exitingVar[index].first == elem)
                        {
                            containElem = true;
                            break;
                        }
                    }
                    if (containElem)
                    { // we found the element so we double the combination with the other state
                        pair<T*, ushort> *newVar = new pair<T*, ushort>[K];
                        for (int k = 0 ; k < K ; ++k)
                            newVar[k] = exitingVar[k];
     
                        newVar[index].second = state;
                        elemVariants.push_back(newVar);
                    }
                }
            }
     
            for (pair<T*, ushort> *newVar : elemVariants)
                (*variants)[indexNewVar++] = newVar;
        }
     
        return variants;
    }
     
     
     
    template<typename T> void combinationWithState(
            const vector<T*> &elements,
            vector<T*> &data,
            int start,
            int end,
            int index,
            int K,
            vector<pair<T*, ushort>*> *variantsKminus1)
    {
     
        // Current combination is ready to be printed, print it
        if (index == K)
        {
            variantsKminus1 = getStateVariations(data, index);
            uint nbVariants = pow(nbStates, index);
            for (uint i = 0 ; i < nbVariants ; ++i)
            {
                pair<T*, ushort> *variant = (*variantsKminus1)[i];
                for (ushort i = 0 ; i < index ; i++)
                {
                    cout << *(variant[i].first) << "_" << variant[i].second << " ";
                }
                delete[] variant;
                cout << "\n";
            }
            variantsKminus1->clear();
            delete variantsKminus1;
            variantsKminus1 = nullptr;
     
            return;
        }
     
        // replace index with all possible elements. The condition
        // "end-i+1 >= r-index" makes sure that including one element
        // at index will make a combination with remaining elements
        // at remaining positions
        for (int i=start; i<=end && end-i+1 >= K-index; i++)
        {
            data[index] = elements[i];
            combinationWithState(elements, data, i+1, end, index+1, K, variantsKminus1);
        }
    }
    dans l'exemple, je génère les variantes de cardinalité 2 dans l'ensemble {A B C D} chacun des éléments ayant 2 états. Je suppose que je ne suis pas intéressé par tous les couples contenant A1, B2 ou C1.
    Voici la sortie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    $ g++ --std=c++11 combi_withStates.cpp -o combi
    $ ./combi 
    A_2  B_1
    A_2  C_2
    A_2  D_1
    A_2  D_2
    B_1  C_2
    B_1  D_1
    B_1  D_2
    C_2  D_1
    C_2  D_2
    Si vous avez des retours je suis preneur

  11. #11
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Génération des combinaisons K parmis N d'une liste mais avec des éléments ayant plusieurs états (vecteurs))?
    Il y a une autre option: caractériser toute combinaison-séquence d'états par une suite finie de (K) nombres présentant l'une des valeurs suivantes:
    # 0 (terme absent)
    # 1, 2 ... NE (terme présent dans l'un des (NE) états envisagés)
    ce qui revient à adopter une numération en base B = (NE + 1), et à coder les exemples que tu cites de la façon suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    A_2  B_1   $0012 =  5
    A_2  C_2   $0202 = 20
    A_2  D_1   $1002 = 29
    A_2  D_2   $2002 = 56
    B_1  C_2   $0210 = 21
    B_1  D_1   $1010 = 30
    B_1  D_2   $2010 = 57
    C_2  D_1   $1200 = 45
    C_2  D_2   $2200 = 72
    Il suffit de choisir un format d'entier (T_Entier) compatible avec la borne supérieure des nombres précédents (B , ici 3), et de coder une procédure d'incrémentation appropriée à la variable, en partant de la valeur initiale (Zero = 0 = $00 ... 0):
    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
    TYPE T_Sequence = ARRAY[1..N] OF T_Entier;
    VAR s: T_Sequence;
     
    PROCEDURE IncS(VAR S_: T_Sequence);
      CONST B = 3;
      VAR k: Byte; s: T_Sequence;
      BEGIN
        s:= S_; k:= 0;
        REPEAT
          Inc(k); r:= s[k]; 
          IF (r<(B - 1)) THEN Inc(r)
                         ELSE BEGIN
                                r:= 0; Inc(s[k + 1])  
                              END      
          s[k]:= r
        UNTIL ((k=N) AND (s[N]= (B - 1)));
        S_:= s
      END;     // Code non compilé, donc à vérifier
    L'énumération des suites successives comportera la sélection des séquences valides, présentant (K) termes non-nuls, et l'élimination des valeurs particulières à écarter.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  12. #12
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    L'idée me semble très intéressante mais je ne vois pas vraiment ni comment générer l'ensemble des combinaisons ni comment je pourrais me servir des résultats d'avant pour les éviter.
    Prenons un exemple plus simple, 3 éléments {A, B, C}, 2 états.
    Première itération, j'obtiens:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    0 0 1 : A1 = 1
    0 0 2 : A2 = 2
    0 1 0 : B1 = 3
    Comment je passe de B1 à B2? je pars du dernier bit non nul pour incrémenter?
    j'obtiens donc la suite:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    0 2 0 : B2 = 6
    1 0 0 : C1 = 9
    2 0 0 : C2 = 18
    Ok donc si mon test me dit d'éviter A1, B2 et C1.
    je suppose que les valeurs décimales ne servent pas.
    Je pars de la première combinaison d'ordre 2 : 0 1 1

    Je ne vois pas trop comment on va maintenir le nombre de bit à 2. Ni comment on va éviter les éléménts que l'on ne doit pas considérer...
    j'imagine une solution en gardant le nombre de bit dans une variable
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    0 1 1 : KO car A1
    0 1 2 : A2 B1
    0 2 1 : KO car A1
    0 2 2 : KO car B2
    1 0 1 : KO car A1
    1 0 2 : KO car C1
    1 1 0 : KO car C1
    1 2 0 : KO car B2
    2 0 1 : KO car A1
    2 0 2 : A2 C2
    2 1 0 : B1 C2
    2 2 0 : KO car B2
    hum... pour la dimension 3 il va falloir que je fasse des test entres mes nouveaux vecteur à 3 bits et ceux à éviter à 2 bits. ça revient un peu au même qu'avec des vecteurs d'élément au final non?

  13. #13
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Génération des combinaisons K parmis N d'une liste mais avec des éléments ayant plusieurs états (vecteurs))?
    Citation Envoyé par ramislebob Voir le message
    ... Le problème c'est que j'ai une contrainte en plus:
    Lorsque je calcule mon ensemble de combinaison K parmis N, List(N, K), je fais un calcul pour chacune des combinaisons.
    J'ai donc une MAP avec pour clef une liste, et pour valeur mon résultat.

    Pour la génération de l'ensemble de combinaisons K+1 parmis N, je ne suis pas intéressé par celle contenant un sous ensemble de cardinalité K qui a un résultat spécifique dans ma Map.
    Serait il possible de générer cet ensemble de combinaisons K+1 parmis N en excluant directement celles qui ne m'intéressent plus?
    Cela m'éviterait de les calculer toutes pour ensuite tester pour chacune d'elle tous les sous ensembles de cardinalité K et potentiellement les enlever ...
    Citation Envoyé par ramislebob Voir le message
    ... je ne vois pas vraiment ni comment générer l'ensemble des combinaisons ni comment je pourrais me servir des résultats d'avant pour les éviter ...
    Pourquoi éviter absolument les résultats antérieurs ?
    Vouloir passer de la suite des combinaisons à 2 termes (K=2) à celle qui en comporte un de plus (K = 3) n'apporte rien, parce qu'une telle filiation détruira l'ordre naturel de l'ensemble des résultats, alors qu'il est possible de les obtenir tous et séparément au cours d'une énumération unique.
    Va par ailleurs se poser le problème de la filiation multiple, puisqu'une combinaison d'ordre (K) (ABCD) peut se rattacher à (K) autres combinaisons d'ordre immédiatement inférieur (ABC, ABD, ACD, BCD): laquelle choisira-t-on ?

    Quant à la récursion, il est prudent de ne s'y résoudre que contraint et forcé, comme le souligne une autre personne

    Citation Envoyé par Flodelarab Voir le message
    ... Les mathématiciens adorent la récursion car c'est beau, simple et propre.(1)
    Les informaticiens détestent la récursion car tu vas facilement et rapidement faire sauter ta pile d'appel (de fonctions) ...
    Il existe un procédé encore plus simple que celui décrit au message (#11) pour l'inventaire des combinaisons et de leurs divers états: l'énumération des entiers de (0) à (3N - 1), suivie de leur codage en base 3 (= NE + 1 = 2 + 1) et de leur sélection en fonction de la somme de leurs chiffres.
    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
    CONST Max = 242;     // Max = 3<sup>N</sup> - 1 = 3<sup>5</sup> - 1 = 243 - 1
    T_Sequence = ARRAY[1..N] OF Byte;
    VAR s: T_Sequence;
     
    PROCEDURE Inventaire;
      CONST B = 3;          // B = 1 + Ne = 1 + 2 = 3
      VAR z: LongInt; s: T_Sequence;
      BEGIN   
        FOR z:= 0 TO Max DO
          BEGIN
            Sch:= 0; p:= z; 
            FOR k:= 1 TO N DO
              BEGIN
                q:= p DIV B; r:= p MOD B; 
                s[k]!:= r;   p:= q;
                IF (r>0) THEN Inc(Sch) 
              END;
              IF (Sch=3) THEN <Enregistrer s dans une liste>  
          END 
      END;
    (1) : ils ne sont pas naïfs au point de ne pas soupçonner les risques inhérents au procédé


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  14. #14
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Citation Envoyé par wiwaxia Voir le message
    Pourquoi éviter absolument les résultats antérieurs ?
    Je fais de la Safety: simulation de génération de pannes afin de calculer l'impact sur le système associé. Si je considère un ensemble de N éléments, mon but est de trouver:
    - les éléments (avec leurs états) qui font perdre mon système.
    - les couples d'éléments (avec leurs états) qui font perdre mon système.
    - les triplets d'éléments (avec leurs états) qui font perdre mon système...

    Si A1 fait perdre mon système, il n'est pas possible de récupérer le système en rajoutant d'autres pannes... ça ne peut qu'agraver. C'est pourquoi je ne veux pas lancer ma simulation pour les cas contenant A1. La simulation peut être longue et coûteuse (mémoire, CPU)

    même raisonnement en passant aux dimensions (cardinalité) supérieures. Plus j'augmente la dimension, moins j'aurai de simulation à exécuter, il est fort probable que je m'arrête bien avant d'arriver à la cardinalité N-1 .
    Par exemple si au cours de la première itération, chaque élément (avec son état) fait perdre le système; je n'ai pas besoin d'aller plus loin et de considérer les couples.

    Voilà pourquoi j'ai besoin des résultat antérieurs. Ce n'est pas la génération de tous les cas qui m'intéresse en soit mais de trouver toutes les combinaisons de cardinalité minimale qui font perdre le système lors de la simulation.

    C'est pourquoi lors d'une itération (cardinalité K), je stocke les combinaisons KO (c'est la sortie finale de mon programme, ce qui m'intéresse) mais aussi celle qui sont OK afin de n'enrichir que celle là en dimension K+1 (les autres n'ayant plus d'inrérêt).


    Citation Envoyé par wiwaxia Voir le message
    Vouloir passer de la suite des combinaisons à 2 termes (K=2) à celle qui en comporte un de plus (K = 3) n'apporte rien, parce qu'une telle filiation détruira l'ordre naturel de l'ensemble des résultats, alors qu'il est possible de les obtenir tous et séparément au cours d'une énumération unique.
    Je ne pars pas des combinaison d'ordre K-1 pour faire la génération d'ordre K. Je fais bien la génération d'ordre K sous forme récursive afin de garder l'ordre naturel. Par contre c'est là que je pense avoir une optimisation, durant cette génération d'ordre K, c'est à l'étape K-1 que je fais UNE comparaison avec les résultats d'ordre K-1 pour ne continuer en ordre K que celle ayant un intérêt. Cela me limite directement la production de combinaison d'ordre K et donc le nombre de test que j'aurai à l'ordre K. Tu vois ce que je veux dire?

    Citation Envoyé par wiwaxia Voir le message
    Va par ailleurs se poser le problème de la filiation multiple, puisqu'une combinaison d'ordre (K) (ABCD) peut se rattacher à (K) autres combinaisons d'ordre immédiatement inférieur (ABC, ABD, ACD, BCD): laquelle choisira-t-on ?
    Je suis à l'étape 3 de la génération d'ordre 4. Il ne sera pas possible d'avoir ABD et ACD. Seuls ABC et BCD. Il me suffit d'avoir l'un des 2 KO à l'ordre 3 pour ignorer ABCD.

    En fait je pourrais très bien générer toutes les combinaisons d'ordre 4. Il me faudrait ensuite tester que les deux triplets en partant du début et de la fin (ABC et BCD) ne sont pas à exclure du fait des résultats de l'itération d'ordre 3. Tous les deux doivent être présents dans les resultat OK d'ordre 3.

    J'imagine éviter des comparaisons (je ne sais pas trop combien; je ne sais pas trop si c'est vrai) en faisant mon test à l'étape de récursivité K-1 de la génération d'ordre K au lieu de le faire directement à la dernière étape sur toutes les combinaisons possibles.

    Est ce plus clair? Y a-t'il un intérêt à procéder ainsi? moins de comparaisons? gain en rapidité? J'imagine que très vite, cardinalité 2 ou 3, je n'aurai plus beaucoup de combinaisons qui ne feront pas tomber mon système, donc très peu d'ordre 4 à considérer. C'est pourquoi je pensais utile d'essayer de ne pas générer l'ensemble de toutes les combinaisons (pour limiter le nombre de comparaisons)


    Citation Envoyé par wiwaxia Voir le message
    Quant à la récursion, il est prudent de ne s'y résoudre que contraint et forcé, comme le souligne une autre personne
    Pourquoi vraiment diaboliser la récursivité? Si elle est sous controle: que l'on connait son nombre max d'appel en quoi est il problématique de l'utiliser? il faut juste s'assurer de ne pas avoir de boucles infinies mais cela peut se vérifier avant de commencer la récursion et être une condition de la faire ou bien de signaler une erreur au lieu d'aller à l'overflow. On peut aussi allouer la taille de la stack dont on a besoin pour un programme...


    Citation Envoyé par wiwaxia Voir le message
    Il existe un procédé encore plus simple que celui décrit au message (#11) pour l'inventaire des combinaisons et de leurs divers états: l'énumération des entiers de (0) à (3N - 1), suivie de leur codage en base 3 (= NE + 1 = 2 + 1) et de leur sélection en fonction de la somme de leurs chiffres.
    Quel est ton langage? dans mon souvenir ça pourrait ressembler à du Pascal mais c'est loin...
    Je testerai l'algo en C++.
    Par curiosité je pense que je ferai des tests de rapidité entre cette méthode et la récursion. (en excluant certaines valeurs du résultat final)


    PS: au vu de mon use case, je me demande aussi si il ne serait pas plus performant de ne pas utiliser du tout de générateurs de combinaison d'ordre K mais de n'enrichir uniquement d'un éléments que les cas intéressant d'ordre K-1, les trier (car j'ai perdu l'ordre naturel et j'ai donc potentiellement des doublons), exécuter ma simulation dessus et reboucler tant que j'ai des cas intéressant.
    Qu'en pensez vous?

  15. #15
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 392
    Points
    9 392
    Par défaut
    Le codage en base 3 .. ou autre. Ce n'est pas lié au langage. Si tu as N élément, chacun a 3 valeurs possibles, alors il y a 3^N possibilités. On peut donc faire une boucle de 1 à 3^16 ... et très facilement trouver la seule configuration qui donne ce nombre.
    Mais ça ne semble pas la bonne voie avec la contrainte que tu donnes.

    A peut prendre 3 valeurs ; J'analyse A1 , A2 et A3. Je constate par exemple que A3 crée un accident, je ne charge en mémoire que A1 et A2
    B peut prendre 3 valeurs ; Je vais donc devoir analyser les 6 combinaisons A1B1, A1B2, A1B3, A2B1, A2B2 et A2B3. Si l'une ou l'autre de ces 6 combinaisons crée un accident on la rejette.
    Puis on croise les 3 valeurs possibles de C avec les combinaisons valides
    etc etc.
    C'est bien ça le besoin ?
    Si oui, alors la récursivité me paraît totalement adaptée.


    Si on traite A puis B puis C ....
    Ou si on traite J puis I puis H puis G ... On va trouver le même résultat ?
    (C'est la fonction qui dit quelles combinaisons sont valides qui me surprend un peu). Mais même si on trouve les mêmes résultats, on a peut-être intéret à traiter les éléments dans un ordre optimisé.
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  16. #16
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Citation Envoyé par tbc92 Voir le message
    A peut prendre 3 valeurs ; J'analyse A1 , A2 et A3. Je constate par exemple que A3 crée un accident, je ne charge en mémoire que A1 et A2
    B peut prendre 3 valeurs ; Je vais donc devoir analyser les 6 combinaisons A1B1, A1B2, A1B3, A2B1, A2B2 et A2B3. Si l'une ou l'autre de ces 6 combinaisons crée un accident on la rejette.
    Puis on croise les 3 valeurs possibles de C avec les combinaisons valides
    etc etc.
    C'est bien ça le besoin ?
    Si oui, alors la récursivité me paraît totalement adaptée.
    C'est quasiment ça sauf qu'il faut traiter tous les cas de cardinalité 1 en premier avant d'augmenter la cardinalité:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Itération 1:
       - A peut prendre 2 valeurs, A1 ou A2.   A1 crée un incident, je le stocke dans ma liste resultsFAIL[1], et je mets A2 dans resultsOK[1]
       - B peut prendre 2 valeurs, B1 ou B2.   B2 crée un incident, je le stocke dans ma liste resultsFAIL[1], et je mets B1 dans resultsOK[1]
       - C peut prendre 2 valeurs, C1 ou C2.   Aucun d'eux ne crée un incident, je mets C1 et C2 dans resultsOK[1]
    Donc le résultat de mon programme à cette étape doit être les deux listes:
    resultsFAIL[1] = { A1 , B2 }
    resultsOK[1] = { A2, B1, C1, C2}
    Maintenant je peux passer à la cardinalité 2. Seuls les combinaisons partant de resultsOK[1] et ne contenant pas les éléments de resultsFAIL[1] m'intéressent.
    J'imagine avoir 2 solutions pour l'itération suivante:
    - 1.: soit je pars des éléments de resultsOK[1] en les enrichissant d'un élément qui n'est pas présent. Le problème c'est que je vais générer des doublons et perdre l'ordre naturel. Pour palier à cela je peux re-ordonner le résultat. (opération coûteuse). Une fois ordonnés, il faudra que je teste que mes combinaison de cardinalité K n'aient pas leur premier et dernier sous ensemble de cardinalité K-1 qui seraient dans resultsFAIL[K-1]

    - 2: j'uilise un générateur de combinaison qui les génère selon l'ordre naturel (déjà triées) et je ne garde que celles qui m'intéressent pour faire la simulation. Il faut donc que leur premier et dernier sous ensemble de cardinalité K-1 ne soient pas resultsFAIL[K-1] MAIS AUSSI soient contenus dans resultsOK[K-1].
    Par rapport à la solution 1, j'ai donc à faire en plus les 2 comparaisons avec les éléments de resultsOK[K-1] pour chacun des éléments qui ne contiennent pas resultsFAIL[K-1]. Mais je n'ai pas l'opération de ré-ordonnage (pas trop français ce mot...) à faire.
    Avec la méthode que j'ai implémentée dans mon post #10, je pense limiter un poil ce nombre de comparaison avec resultsOK[K-1] en faisant le test à l'état K-1 dans la production récursive de mes nouvelles combinaisons de cardinalité K. Je ne sais pas si je suis très clair et si cette solution apporte vraiment un gain... Intuitivement j'ai l'impression.

    Bref, sachant que vraisemblablement la liste de mes combinaisons OK à continuer à la cardinalité supérieure risque de diminuer considérablement voire se terminer à K = 3 ou 4, quelle solution vous parrait la plus pertinente?

    Je vous fais l'itération 2 et 3 avec la solution 1
    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
     
    resultsOK[1] = { A2, B1, C1, C2}
    de A2 je peux générer:
        - (A2, B1), (A2, B2) hors B2 est dans resultsFAIL[1] donc je ne lancerai pas la simulation dessus. 
        - (A2, C1), (A2, C2) (les 2 doivent lancer la simu)
    de B1 je peux générer: (c'est là ou je perds l'ordre)
       - (B1, A1), (B1, A2) : le premier est interdit car il contient A1, le deuxième a déjà été généré en partant de A2 (il ne faut pas relancer la simu)
       - (B1, C1), (B1, C2) : tous les deux à exécuter
    de C1: toutes les possibilités ont déjà été testées mais je ne peux pas le savoir, il faut que je les génère et les ré-ordonne pour m'en rendre compte
     
    Bilan: je n'ai a tester que (A2, B1), (A2, C1), (A2, C2), (B1, C1) et (B1, C2)
    Supposons que tous donnent lieu à un incident excepté (B1, C1)
     
    J'ai donc
    resultsFAIL[2] = { (A2, B1), (A2, C1), (A2, C2), (B1, C2) }
    resultsOK[2] = { (B1, C1) }
     
     
    Pour l'itération 3, en partant de resultsOK[2], je n'ai comme choix que:
    (B1, C1, A1) et (B1, C1, A2)
    je les ré-ordonne, ça donne (A1, B1, C1) et (A2, B1, C1)
    mais comme (A2, B1) est dans resultsFAIL[2], seul (A1, B1, C1) est à considérer
    supposons que le résultat donne un incident
    j'obtient:
    resultsFAIL[3] =  { (A1, B1, C1) }
    resultsOK[3] = {}
    Voilà en ayant fait le cheminement jusqu'au bout, ce qui m'intéresse en sortie c'est mes 2 tableaux de listes et le combinaisons qu'elles contiennent. Je ne veux exécuter la simulation que pour les combinaisons qu'elles contiennent. Ce doit être la sortie de mon programme.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    resultsFAIL[1] = { A1 , B2 }
    resultsOK[1] = { A2, B1, C1, C2}
     
    resultsFAIL[2] = { (A2, B1), (A2, C1), (A2, C2), (B1, C2) }
    resultsOK[2] = { (B1, C1) }
     
    resultsFAIL[3] =  { (A1, B1, C1) }
    resultsOK[3] = {}
    Est ce plus clair?
    En faisant l'itération de la solution 1 je me rend compte que c'est certainement l'option la plus efficace même si j'ai l'opération de tri. être avec un ensemble de cardinalité 3 fausse peut être la donne.
    Qu'en pensez vous?

  17. #17
    Membre émérite

    Homme Profil pro
    Formation: Chimie et Physique (structure de la matière)
    Inscrit en
    Décembre 2010
    Messages
    1 333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 77
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Formation: Chimie et Physique (structure de la matière)
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 333
    Points : 2 570
    Points
    2 570
    Billets dans le blog
    9
    Par défaut Génération des combinaisons K parmis N d'une liste mais avec des éléments ayant plusieurs états (vecteurs))?
    Citation Envoyé par ramislebob Voir le message
    ... Quel est ton langage? dans mon souvenir ça pourrait ressembler à du Pascal mais c'est loin ...
    C'est effectivement du Pascal, et cela se lit pratiquement comme du pseudo-code.

    Citation Envoyé par ramislebob Voir le message
    ... Si A1 fait perdre mon système, il n'est pas possible de récupérer le système en rajoutant d'autres pannes... ça ne peut qu'agraver. C'est pourquoi je ne veux pas lancer ma simulation pour les cas contenant A1. La simulation peut être longue et coûteuse (mémoire, CPU) ...
    C'est ce que je soupçonnais un peu, mais que tu as très bien expliqué.
    Ton algorithme se développe donc par accumulation d'expériences (ici de blocage du système); le programme se plante-t-il obligatoirement, ou y a-t-il moyen de s'arrêter avant pour revenir à une autre combinaison ?
    On pourrait alors envisager l'inventaire des valeurs incompatibles avec l'exécution correcte de l'algorithme, valeurs probablement minoritaires.

    Soit TestI(Rang, Sequence) une fonction booléenne signalant l'incompatibilité d'une valeur testée, ou la suspension réversible de l'exécution du programme; un inventaire sur cinq niveaux (N = 5) peut être codé rudimentairement de la façon suivante:
    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
    CONST N = 5; Ne = 2; NmaxS = 50;     // Valeur à l'essai
    TYPE T_Sequence = ARRAY[1..N] OF Byte;
         T_TabSeq = ARRAY[1..NmaxS] OF T_Sequence;
    VAR Nc: Byte;
        s: T_Sequence;
        ListeS: T_TabSeq;
     
    PROCEDURE Initialisation(VAR Nc_: Byte; VAR S_: T_Sequence; VAR Ls: T_TabSeq);
      CONST m = 255; Sini: T_Sequence = (m, m, m, m, m);          // On peut prendre m = 0
      VAR k: Byte;
      BEGIN
        Nc_:= 0; S_:= Sini;
        FOR k:= 1 TO NmaxS DO Ls[k]:= Sini
      END;
     
    PROCEDURE InitS(i, w: Byte; VAR S_: T_Sequence);
      BEGIN
        S_[i]:= w
      END;
     
    PROCEDURE Inventaire5(VAR Ls: T_TabSeq);
      VAR Je: Byte;          // Indice d'état
      BEGIN
        FOR Je:= 1 TO Ne DO
          BEGIN
            InitS(5, Je, s);
            IF TestI(5, s) THEN BEGIN
                                  Inc(Nc); Ls[Nc]:= s
                                END            
          END
      END;
     
    ... / ...
     
    PROCEDURE Inventaire2(VAR Ls: T_TabSeq);
      VAR Je: Byte;          // Indice d'état
      BEGIN
        FOR Je:= 1 TO Ne DO
          BEGIN
            InitS(2, Je, s);
            IF TestI(2, s) THEN BEGIN
                                  Inc(Nc); Ls[Nc]:= s
                                END       
                           ELSE Inventaire3(ListeS)      
          END
      END;
     
    PROCEDURE Inventaire1(VAR Ls: T_TabSeq);
      VAR Je: Byte;          // Indice d'état
      BEGIN
        FOR Je:= 1 TO Ne DO
          BEGIN
            InitS(1, Je, s);
            IF TestI(1, s) THEN BEGIN
                                  Inc(Nc); Ls[Nc]:= s
                                END       
                           ELSE Inventaire2(ListeS)      
          END
      END;
     
    BEGIN          // Programme principal 
      InitLs(Nc, s, ListeS);
      Inventaire1(ListeS)
    END.
    Si ce programme n'est pas une incitation à la récursivité, il y ressemble fortement .

    Il n'en coûte que quelques modifications minimes pour passer à l'acte:
    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
    CONST N = 5; Ne = 2; NmaxS = 50;     // Valeur à l'essai
    TYPE T_Sequence = ARRAY[1..N] OF Byte;
         T_TabSeq = ARRAY[1..NmaxS] OF T_Sequence;
    VAR k, Nc: Byte;
        s: T_Sequence;
        ListeS: T_TabSeq;
     
    PROCEDURE Initialisation(VAR K_, Nc_: Byte; VAR S_: T_Sequence; VAR Ls: T_TabSeq);
      CONST m = 255; Sini: T_Sequence = (m, m, m, m, m);
      VAR i: Byte;
      BEGIN
        K_:= 1; Nc_:= 0; S_:= Sini;
        FOR i:= 1 TO NmaxS DO Ls[i]:= Sini
      END;
     
    PROCEDURE InitS(i, w: Byte; VAR S_: T_Sequence);
      BEGIN
        S_[i]:= w
      END;
     
    PROCEDURE Inventaire(k1: Byte; VAR Ls: T_TabSeq);
      VAR Je: Byte;          // Indice d'état
      BEGIN
        FOR Je:= 1 TO Ne DO
          BEGIN
            InitS(k1, Je, s);
            IF TestI(k1, s) THEN BEGIN
                                   Inc(Nc); Ls[Nc]:= s
                                 END       
                            ELSE IF (k1<N) THEN BEGIN
                                                  Inc(k); Inventaire(k, ListeS)      
                                                END
          END
      END;
     
    BEGIN          // Programme principal 
      InitLs(k, Nc, s, ListeS);
      Inventaire(k, ListeS)
    END.
    Je laisse aux autres intervenants, plus familiers que moi du procédé, de faire les vérifications nécessaires.


    Le français, notre affaire à tous
    Grand Dictionnaire Terminologique

  18. #18
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 053
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 053
    Points : 9 392
    Points
    9 392
    Par défaut
    resultsOK[1] = { A2, B1, C1, C2}
    de A2 je peux générer:
    - (A2, B1), (A2, B2) hors B2 est dans resultsFAIL[1] donc je ne lancerai pas la simulation dessus.
    - (A2, C1), (A2, C2) (les 2 doivent lancer la simu)
    de B1 je peux générer: (c'est là ou je perds l'ordre)
    - (B1, A1), (B1, A2) : le premier est interdit car il contient A1, le deuxième a déjà été généré en partant de A2 (il ne faut pas relancer la simu)
    - (B1, C1), (B1, C2) : tous les deux à exécuter
    de C1: toutes les possibilités ont déjà été testées mais je ne peux pas le savoir, il faut que je les génère et les ré-ordonne pour m'en rendre compte

    Bilan: je n'ai a tester que (A2, B1), (A2, C1), (A2, C2), (B1, C1) et (B1, C2)
    Supposons que tous donnent lieu à un incident excepté (B1, C1)

    J'ai donc
    resultsFAIL[2] = { (A2, B1), (A2, C1), (A2, C2), (B1, C2) }
    resultsOK[2] = { (B1, C1) }


    Pour l'itération 3, en partant de resultsOK[2], je n'ai comme choix que:
    (B1, C1, A1) et (B1, C1, A2)
    je les ré-ordonne, ça donne (A1, B1, C1) et (A2, B1, C1)
    mais comme (A2, B1) est dans resultsFAIL[2], seul (A1, B1, C1) est à considérer
    supposons que le résultat donne un incident
    j'obtient:
    resultsFAIL[3] = { (A1, B1, C1) }
    resultsOK[3] = {}
    Il y a 2 ou 3 choses qui me paraissent incohérentes dans cette partie. Soit c'est effectivement conforme à ton besoin, et dans ce cas, il y a quelques galères à envisager, soit c'est une erreur dans ce 'résumé', et ça va bien simplifier.

    Point 1.
    En ligne 2 , tu écris : De A2 je peux générer ... ok
    Mais en ligne 5, tu écris : de B1 je peux générer ... : Ici, à mon avis, il suffit que tu associes B1 avec les éléments qui viennent après. Quand tu associes B1 avec des éléments qui apparaissent avant B1, tu généres forcément des doublons.

    Point 2 :
    Plus bas, tu écris : je n'ai comme choix que: (B1, C1, A1) et (B1, C1, A2) A1 n'est pas une option, on sait qu'il plante.
    Et tu dis juste après : seul (A1, B1, C1) est à considérer ; supposons que le résultat donne un incident . De ce que je comprends, je ne dirais pas 'supposons que le resultat donne un incident'. Vu que (A1, B1) donne un incident, forcément (A1, B1, C1) va donner un incident.

    Ou alors tu considères que (A1,B1)+C1 n'est pas la même chose que A1+(B1+C1).
    N'oubliez pas le bouton Résolu si vous avez obtenu une réponse à votre question.

  19. #19
    Membre habitué

    Inscrit en
    Janvier 2006
    Messages
    188
    Détails du profil
    Informations forums :
    Inscription : Janvier 2006
    Messages : 188
    Points : 142
    Points
    142
    Par défaut
    Citation Envoyé par wiwaxia Voir le message
    Ton algorithme se développe donc par accumulation d'expériences (ici de blocage du système); le programme se plante-t-il obligatoirement, ou y a-t-il moyen de s'arrêter avant pour revenir à une autre combinaison ?
    On pourrait alors envisager l'inventaire des valeurs incompatibles avec l'exécution correcte de l'algorithme, valeurs probablement minoritaires.
    Le programme ne plante pas, la simulation me retourne juste le résultat de l'état de mon système en prenant en compte un certain nombre de pannes. Pour faire simple, soit il est OK, soit il est FAIL. Le but de cet algorithm Safety est de trouver l'ensemble de combinaisons de cardinalité minimum qui donnent chacun de ces états.

    Comme tu dis, il faut utiliser l'accumulation d'expérience lorsque l'on augmente la cardinalité. Après réflexion et le bilan sur les 2 solutions possibles (cf mon post #16) en fait je n'ai pas besoin d'utiliser de générateur de combinaison pour K > 1. C'est contre productif. Il me suffit de d'enrichir uniquement les résultats OK de l'itération précédente.


    Citation Envoyé par tbc92 Voir le message
    Point 1.
    En ligne 2 , tu écris : De A2 je peux générer ... ok
    Mais en ligne 5, tu écris : de B1 je peux générer ... : Ici, à mon avis, il suffit que tu associes B1 avec les éléments qui viennent après. Quand tu associes B1 avec des éléments qui apparaissent avant B1, tu généres forcément des doublons.
    En effet, j'y ai pensé après avoir écrit le post... Du coup pas besoin de tri pour cette solution. Donc il est clair que c'est la plus performante, j'évite de faire des comparaisons inutiles!


    Citation Envoyé par tbc92 Voir le message
    Point 2 :
    Plus bas, tu écris : je n'ai comme choix que: (B1, C1, A1) et (B1, C1, A2) A1 n'est pas une option, on sait qu'il plante.
    Et tu dis juste après : seul (A1, B1, C1) est à considérer ; supposons que le résultat donne un incident . De ce que je comprends, je ne dirais pas 'supposons que le resultat donne un incident'. Vu que (A1, B1) donne un incident, forcément (A1, B1, C1) va donner un incident.

    Ou alors tu considères que (A1,B1)+C1 n'est pas la même chose que A1+(B1+C1).
    Oui c'est une erreur de ma part. Pour passer à la dimension supérieure j'enrichissais avec tout autre élément possible non contenu dans la combinaison. Du coup j'ai oublié que A1 n'était pas une option. En fait il me suffit de n'enrichir qu'avec les éléments contenus dans resultsOK[1], à savoir dans mon exemple des éléments de { A2, B1, C1, C2}. Il n'y aurait donc aucune combinaison d'ordre 3 utile.

    Merci beaucoup pour votre aide. Après avoir un peu bifurqué je crois savoir comment je devrais partir
    Voici l'algo en pseudo code: (désolé c'est en patois, j'ai du mal à coder en français...)
    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
     
    resultsOK    = array of list of combinations (the cardinality of the combinations matches the index of the array)
    resultsFAIL  = array of list of combinations (the cardinality of the combinations matches the index of the array)
    resultsERROR = array of list of combinations (the cardinality of the combinations matches the index of the array)
     
    STATES   = enum {LOST, ERRONEOUS}
    Elements = ordered list of elements of cardinality N > 1. each element can take the 2 states from the enum STATES
     
     
    // Initialization K = 1
    foreach elt in Elements
    	foreach state in STATES
    		res = run simulation with { {elt, state} }
    		switch res
    			case OK:
    				add (elt, state) in resultsOK[1]
    			case LOST:
    				add (elt, state) in resultsFAIL[1]
    			case ERRONEOUS:
    				add (elt, state) in resultsERROR[1]
     
     
    // Now loop to increase the cardinality
    K = 1
    while ( resultsOK[K] is not empty  AND  K <= N )
    	foreach combination in resultsOK[K]
    		lastElem = last element of the combination
    		foreach newElem in resultsOK[1] starting just after lastElem (order in Elements)
    			combiKplus1 = { combination[1..K], newElem}
    			res = run simulation with combiKplus1
    			switch res
    				case OK:
    					add combiKplus1 in resultsOK[K+1]
    				case LOST:
    					add combiKplus1 in resultsFAIL[K+1]
    				case ERRONEOUS:
    					add combiKplus1 in resultsERROR[K+1]
    	++K
    qu'en pensez vous?

  20. #20
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 419
    Points : 5 818
    Points
    5 818
    Par défaut
    salut

    je pense que tu te complique la vie

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // Initialization K = 1
    foreach elt in Elements
    	foreach state in STATES
    		res = run simulation with { {elt, state} }
    		switch res
    		case OK:	add (elt, state) in resultsOK[1] // l'indice 1 correspond a quoi ? 
    		case LOST: add (elt, state) in resultsFAIL[1]
    		case ERRONEOUS:add (elt, state) in resultsERROR[1]
    a quoi sert l'ajou du state dans ton add ?
    pour moi la premiere boucle se reume ainsi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // Initialization K = 1
    N =0;
    foreach elt in Elements
       res = run simulation with {elt }// ici tu retourne l'etat de ta simulation
        switch res
           case OK               : add (elt) in resultsOK[]  ++N 
           case LOST            : add (elt) in resultsFAIL[]
           case ERRONEOUS : add (elt) in resultsERROR[]
    partant de là le code devient plus simple
    on va rechercher toutes les nouvelle combinaison possible

    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
     
    // Now loop to increase the cardinality
    K = 1
    while ( resultsOK[K] is not empty  AND  K < N ) // Attention 
    {
      L= K+1 
      while ( resultsOK[L] is not empty  AND  K <= N )
      {
         newElem = 	resultsOK[K]&&resultsOK[L] 
         res = run simulation with {newElem}
         switch res
    	case OK             :  add (newElem) in resultsOK[]
    	case LOST          :  add (newElem) in  resultsFAIL[]
    	case ERRONEOUS: add (newElem) in  resultsERROR[]
         ++L
       }
    ++K
    }
    et ensuite il te suffit d'afficher ton resultsOK
    Nous souhaitons la vérité et nous trouvons qu'incertitude. [...]
    Nous sommes incapables de ne pas souhaiter la vérité et le bonheur, et sommes incapables ni de certitude ni de bonheur.
    Blaise Pascal
    PS : n'oubliez pas le tag

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Faire une liste déroulante avec des drapeaux
    Par identifiant_bidon dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 25/04/2011, 22h04
  2. [MySQL] Remplir une liste déroulante avec des données de la base de données
    Par moukit233 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 12/08/2009, 11h05
  3. Réponses: 2
    Dernier message: 11/05/2009, 09h36
  4. une liste deroulante avec des logos
    Par petitdebutant dans le forum VBA Word
    Réponses: 1
    Dernier message: 26/01/2009, 16h10
  5. Réponses: 1
    Dernier message: 01/03/2008, 11h25

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