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

JavaScript Discussion :

Implémentation algo: générateur pseudo aléatoire MWC


Sujet :

JavaScript

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2018
    Messages : 41
    Points : 33
    Points
    33
    Par défaut Implémentation algo: générateur pseudo aléatoire MWC
    Bonjour à tous !

    Pour une application de sérialisation de structures de données graphes
    j'ai besoin de générer des clés pseudo-aléatoires sur 4, 6 ou 8 digitss avec 52 positions (A_Za_z)
    donc de la forme 'Cafe', 'pizzas' ou 'AptiTude'.

    J'ai décidé d'utiliser des générateurs de nombres pseudo-aléatoires
    car cela devrait me permettre de reproduire les résultats de cette expérience lors des phases de test (même caractéristiques et même graine => même séquence de clés)
    et ai tenté d'adapter les générateurs MWC (Multply-With-Carry) en JS selon mes besoins.

    Le hic est que ma version bouble sur des périodes très courtes (~10k valeurs) là où,
    pour 4 digits Math.pow(52, 4) permttrait d'obtenir un cycle se comptant en millions...

    Pour ce qui est du code du générateur c'est à peu à cela : une version custom de l'algorithme de wikipedia... n'ayant pas complètement compris l'implémentation proposée en C++,
    j'ai repris ce document au niveau des équations théoriques, ce qui donne :

    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
     
        // a = modulus (safe prime en principe)
        // b = 52 (base)
        // r = 3 (lag = décalage) interprété ici comme nombre de digits à produire moins 1
        export const createMWC = (a, b, r) => {
     
          // le tableau de travail
          // xi = valuers
          // ci = retenues (carries)
          const xi = new Array(r + 1)
          const ci = new Array (r + 1)
     
          // les indices pour extraire X[n - r] et X[n - 1]
          // vu qu'on ne fait pas "ramper" le tableau enconsommant les valeurs de tête
          // et en poussant les nouvelles en fin de tableau !
          let n0 = 0
          let nr = r
     
          // variables temporaires
          let xn = 0
          let cn = 0
     
          // API JS exposée
          return {
     
            // la fonction d'initalisation
            init (seeds) {
              for (let k = 0; k < (r + 1); k++) {
                xi[k] = seeds[k]
                ci[k] = 0
              }
            },
     
            // génération de valeurs
            next() {
              let result = new Array (r + 1)
     
              // on décale à chaque appel à la fonction
              n0 = (n0 +  1) % (r + 1)
              nr = (nr +  1) % (r + 1)
     
              // from wikipedia...
              xn =            (a * xi[nr] + ci[n0]) % b
              cn = Math.floor((a * xi[nr] + ci[n0]) / b)
     
              // écrase l'ancienne valeuret place la nouvelle à la place
              xi[n0] = xn
              ci[n0] = cn
     
     
              // ultime twist...
              /*
                result =  (n0 === 0)
                  ? xi.slice(0)
                  : xi.slice(n0).concat(xi.slice(0, n0))
              */
     
              // ou plus simple
              for(let t = 0; t < r + 1; t++) {
                //result[t] = xi[t]
                result[(t + n0) % (r + 1)] = xi[t]
              }
     
              return result
            }
          }
        }
    Pour ce qui est du code de test il est assez simple : il est basé sur des statistiques de base sur des tirs (shots) du générateur, avec en paramètre un modulus (a) et une graine, avec stockage des couples {valeurr: rang-dans-la-série} dans un opbjet hash, avec détection et arrêt à la premère collision :

    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
     
        const MAX_LOOPS = 10000000
        const b = 52
        const r = 3
     
       const output = (arr) => {
          // console.log(arr)
          //return arr.reduce((acc, val) => b * acc + val, 0)
         return arr.join(':')
       }
     
       const shoot = (a, seeds) => {
         const store = {}
         const generator = createMWC(a, b, r)
         let i = 0
         let result = 0
         let text = seeds.join(':')
         let crashes = 0
     
         generator.init(seeds)
         store[output(seeds)] = 0
     
         while (i++ < MAX_LOOPS) {
          const generated = generator.next()
          const val = output(generated)
     
          text += '    ' + generated.join(':')
     
          if(store.hasOwnProperty(val)) {
              result = i
              crashes++
              // console.log('#### %s', i)
              break
            } else {
              store[val] = i
            }
     
            // console.log('store[%s]: %s', val, store[val])
            // console.log('     %s', generated.join(':'))
          }
     
          console.log('crashes: %s', crashes)
          return result
        }
    Enfin c'est assez baqieu mais pour l'instant cela ne me permet pas de comprendre
    les basses performances de l'algorithme, d'autant plus qu'une version boguée précédente, et un autre avec tableau "rampant",
    très coûteuse en termes d'allocation mémoire (push+unshift) donnaient de meilleurs résultats.

    Vu que je ne trouve pas de solution évidente par moi même j'en appelle à vos lumières
    pour tenter de trouver une solution. Quelqu'un aurait il une idée ?

  2. #2
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Citation Envoyé par francortes Voir le message
    avec détection et arrêt à la premère collision
    C'est à dire que dès qu'un élément aléatoire revient, on estime que le système boucle ?
    Le fait qu'une valeur revienne au bout de quelques milliers de tentatives ne suffit pas à indiquer que le générateur boucle, selon moi.
    Ne faudrait-il pas afficher quelques valeurs au delà pour voir si on rejoue bien la séquence qui démarrait à la précédente apparition de cette valeur ?

    une version custom de l'algorithme de wikipedia... n'ayant pas complètement compris l'implémentation proposée en C++,
    Le plus sûr reste de reprendre quelque chose d'existant, je trouve qu'il faudrait persévérer dans cette direction.
    Au minimum, si vous voulez qu'on s'intéresse à votre solution, il serait préférable de donner un exemple directement fonctionnel avec initialisation et mise en évidence nette des points faibles.


    Sinon, il y a quelques temps j'avais mis au point une mini fonction style Math.random, surtout par tâtonnement en fait.
    Pour l'usage que j'en fais, ça me suffit.
    En attendant de parfaire votre algorithme, ça pourrait peut-être servir pour faire des tests ?
    A la base c'était dans une classe et pas en JS.
    Je viens donc de réécrire cela en JS, mais sans classe, sous forme de brouillon et avec un petit 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
    //bloc à mettre en forme
    function aleatoire()
    	{
    	var i;
     
    	nb_=(nb_+ar_nb_coef[0])%nb_maxi;
    	i=-1;
    	while(++i<ar_nb_coef.length-1)
    		{
    		ar_nb_coef[i]=(ar_nb_coef[i]+ar_nb_coef[i+1])%nb_maxi;
    		}
    	return nb_/nb_maxi;
    	}
    var nb_maxi=1000000000000000; //maximum
    var nb_acce=1234512345123451; //accélération
    var ar_nb_coef=[nb_acce,nb_acce,nb_acce,nb_acce,nb_acce,nb_acce]; //coefficients
    var nb_=0; //peut être modifié (selon les cas, il faut une valeur suffisamment grande pour avoir un impact immédiat)
     
    //test
    function test(fc_)
    	{
    	var ar_;
    	var i;
    	var j;
    	var ob_;
    	var st_;
     
    	ob_={};
    	ar_="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
    	i=1000000; //nombre tentatives
    	while(--i>=0)
    		{
    		st_="";
    		j=6; //longueur clé (peut être modifiée aléatoirement avec la fonction passée en paramètre)
    		while(--j>=0)
    			{
    			st_+=ar_[Math.floor(fc_()*52)]; //l'un des 52 caractères possibles
    			}
    		ob_[st_]=i;
    		}
    //	console.log(ob_);
    	console.log(Object.keys(ob_).length);
    	}
    test(aleatoire); //999980 clés générées (fixe)
    test(Math.random); //999977 clés générées (variable d'une exécution à l'autre)

  3. #3
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 742
    Points
    4 742
    Par défaut
    Pour ce qui est du code du générateur c'est à peu à cela : une version custom de l'algorithme de wikipedia... n'ayant pas complètement compris l'implémentation proposée en C++,
    Ça qui serait sympa, c'est de d'indiquer le lien wikipedia !

    Sinon j'ai mois aussi un algo dans le genre dans un coin, mais c'était pour générer des clés uniques cryptées, faudrait que je retrouve.... peut-être
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  4. #4
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Points : 22 933
    Points
    22 933
    Billets dans le blog
    125
    Par défaut


    Si l'on peut se contenter de la qualité cryptographique (sic), il y a plus simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let arUint = new Uint8Array(10000);
     
    window.crypto.getRandomValues(arUint); // https://developer.mozilla.org/fr/docs/Web/API/RandomSource/getRandomValues
     
    for (const item of arUint) {
        console.log(item % 52); // pseudo aléatoire entre 0 et 51
    }

    Blog

    Sans l'analyse et la conception, la programmation est l'art d'ajouter des bogues à un fichier texte vide.
    (Louis Srygley : Without requirements or design, programming is the art of adding bugs to an empty text file.)

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2018
    Messages : 41
    Points : 33
    Points
    33
    Par défaut
    Après mûre réflexion (et tests), il apparaît que le système ne boucle pas à la première collision puisque l'état interne associé à une sortie n'est pas forcément le même (présdence des carries/retenues)n ce serait mieux de ,e pas en avoir puisque c'est pour générer des clés.... enfin je pourrais toujours bouchonner en faisant quelque chose du genre :

    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
     
        // utilisons des object hash et leur temps d'acces constant !
        const store = {}
     
        // ...
     
        next() {
          let i = 0
          let val = null
     
          do {
            val = generator.next()
            i++ // compte le nombrre d'essais
          } while(store.hasOwnProperty(val))
     
          store[val] = i 
     
          return val 
        }
    Pour ce qui est des tests, qi je ne m'arrête pas à la première collision, et que je compte, pour n=10M d'itérations, le nombre de collisions et le nombre de nouvelles valeurs créées, j'obtiens, pour les coefficients que j'ai testé environ : 5.45M nouvelles valeurs créées et 4.6M collisions.

    Rapporté au nombre de valeurs possibles 4 digits sur 52 positions, cela fait environ Math.pow(52, 4) = 7.31M, on obtient enfin une efficaité moyenne de 5.45 / 7.31 = 74=% de valeurs crées sur la plage de valeurs disponibles... peut être que l'algorithme ne peut pas faire mieux !

    J'ai déjà fait des affichages et j'ai des séquences intéressantes qui décalennt au cours du temps comme une file d'attente. Avec 4 digits sur 52 positions cela donne quelque chose qui peut ressembler à ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      // exemple de série (factice)
     0 [ 0, 1, 2, 3]
     1 [20, 0, 1, 2]
     2 [30,20, 0, 1]
     3 [42,30,20,10]
     4 etc...
    La clé résultant étant bien sûr une opération permettant de passer d'un tableau sur 4 valeurs à une chaîne sur 4 digits, évidemment. L'algo de wikipedia:

    [https://en.wikipedia.org/wiki/Multip...ber_generator]

    est en bon vieux C++ et peu évident à comprendre, donc j'ai un peu bricolé autour des équations de ce mêmme article. Je pourrais envoyer des samples de code bien entendu, j'ai également des routines de test que je pourrais vous envoyer c'est entendu.

    merci pour ces premiers éléments

  6. #6
    Expert confirmé Avatar de psychadelic
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    2 529
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 2 529
    Points : 4 742
    Points
    4 742
    Par défaut
    La clé résultant étant bien sûr une opération permettant de passer d'un tableau sur 4 valeurs à une chaîne sur 4 digits, évidemment. L'algo de wikipedia:

    Multiply-with-carry pseudorandom number generator

    est en bon vieux C++ et peu évident à comprendre, donc j'ai un peu bricolé autour des équations de ce mêmme article. Je pourrais envoyer des samples de code bien entendu, j'ai également des routines de test que je pourrais vous envoyer c'est entendu.
    Pour le transposer, il y aussi le probleme avec son utilisation d'entiers 64bits, ce que ne permet pas le langage JavaScript..
    «La pluralité des voix n'est pas une preuve, pour les vérités malaisées à découvrir, tant il est bien plus vraisemblable qu'un homme seul les ait rencontrées que tout un peuple.» [ René Descartes ] - Discours de la méthode

  7. #7
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Bonjour,
    Citation Envoyé par francortes Voir le message
    ce serait mieux de ,e pas en avoir puisque c'est pour générer des clés....
    Pour de l'aléatoire, c'est normal de retomber sur des valeurs déjà rencontrées.

    Citation Envoyé par francortes Voir le message
    enfin je pourrais toujours bouchonner en faisant quelque chose du genre :
    Plus "store" grandit, plus ça risque de boucler longtemps, voire très très longtemps.

    Citation Envoyé par francortes Voir le message
    Pour ce qui est des tests, qi je ne m'arrête pas à la première collision, et que je compte, pour n=10M d'itérations, le nombre de collisions et le nombre de nouvelles valeurs créées, j'obtiens, pour les coefficients que j'ai testé environ : 5.45M nouvelles valeurs créées et 4.6M collisions.
    Si vous testez mon code, vous aurez exactement la même chose !

    Exemples pour des clés de longueur 4 et une boucle de 10 millions :
    - Avec ma fonction personnelle : 5449599.
    - Avec Math.random : 5448662.

    peut être que l'algorithme ne peut pas faire mieux !
    Testez avec 20 millions.

    Pour ma part :
    - Avec ma fonction personnelle : 6836515.
    - Avec Math.random : 6838143.

  8. #8
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Bonjour,
    moi non plus je ne comprends pas bien l’algo proposé sur la page Wikipédia, en particulier le commentaire “Let c = t / 0xfffffff, x = t mod 0xffffffff” qui ne semble pas correspondre à ce qui suit dans le code. Des alternatives sont proposées dans la discussion de la page, mais je n’ai pas pu déterminer si l’une d’entre elles était correcte.

    psychadelic soulève un point important : en JS, il faut faire attention à la façon dont les nombres sont gérés. Le langage nous donne le type "number", mais sous le capot c’est le type double de la norme IEEE 754 qui est utilisé. Un entier ne peut être représenté avec 100 % de précision que s’il se trouve dans le domaine safe integer qui correspond, pour les entiers positifs, à l’intervalle [0 ; 253 - 1].
    Si, à un moment donné, le résultat de la multiplication (la variable xn dans ton code) n’est plus un safe integer, la représentation interne basculera en virgule flottante et il y aura une perte de précision, ce qui aura à coup sûr un impact sur la fiabilité du générateur.
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

  9. #9
    Membre éclairé
    Femme Profil pro
    Autre
    Inscrit en
    Janvier 2017
    Messages
    335
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Autre

    Informations forums :
    Inscription : Janvier 2017
    Messages : 335
    Points : 715
    Points
    715
    Par défaut
    Je tente une explication du fait qu'on obtient environ 5,45 millions de valeurs pour 10 millions de tentatives :

    Supposons :
    - On a X valeurs possibles.
    - A une itération donnée, on a Y valeurs enregistrées.

    La probabilité que la nouvelle valeur aléatoire générée n'appartienne pas déjà aux Y valeurs enregistrées devrait être de : (X - Y) / X.

    Suite à cette itération, le nombre moyen théorique de valeurs enregistrées sera de : Y + (X - Y) / X.

    Si j'applique ce principe dans une boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    var nombreValeursPossibles=Math.pow(52,4);
    var nombreValeursEnregistrees=0;
    var i=10000000;
    while(--i>=0)
    	{
    	nombreValeursEnregistrees+=(nombreValeursPossibles-nombreValeursEnregistrees)/nombreValeursPossibles;
    	}
    console.log(nombreValeursEnregistrees); //5449380.743167394
    A 20 millions, ça donne 6837313.171215921, ce qui est conforme au résultat que j'ai indiqué dans mon message précédent.

    Ainsi, on peut déterminer à l'avance le nombre de valeurs qu'on va obtenir pour un certain nombre de tentatives.

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2018
    Messages : 41
    Points : 33
    Points
    33
    Par défaut
    Bonjour,

    et merci pour vos réactions en nombre ! je vais tenter quelques réponses :

    - j'ai joint les fichiers issus du projet : src/dexm/mwc.js et test/dexm/mwc.js ; ils sont commentés à minima, et il vous faudra peut être transpiler l'ES2015 avec vous outils habituels (perso j'utilise rollup + buble avec les plugins d'alias, mais webpack + babel devrait fonctionner) pour pouvoir tester dans le navigateur ou dans le shell avec node JS.

    @loralina: Je vais tester l'implémentation que tu proposes, en remarquant que tu compares avec Math.random en termes de performance, ce que je n'ai pas fait pour l'instant, dans cette partie du projet. J'avais également représenté graphiquement les couples de points [u[i], u[i+1]] sur un graphe à échelle logarithmique et remarqué que les valeurs se distribuaient un peu plus que Math.random seule... il faudrait également faire des stats plus poussées là-dessus, c'est encore une autre histoire.

    @psychadelic : clairement on n'a pas de UInt64, juste des double IEE754, ce que j'avais compris de la page wiki, c'est de générer des petits nombres (ici b = 52) et de concaténer leur (r + 1)-ème séquence pour obtenir quelque chose de plus grand...

    @danielhagnoul : bonne idée que d'utiliser crypto, par contre je cherche à m'affranchir des libs externes et de ce qui ressemble à Math.random. Dans une optique future de programmation fonctionnelle (peut etre) il faut limiter au maximum l'appel à des routines externes pour garantir la testabilité du code ;

    @Watilin : pour l'instant je n'ai testé qu'avec de petites valeurs du multiplier "a" donc je ne pense pas que a * xi[n] dépasse les valeurs fatidiques.... je regarderai quand mlême ce point avec attention

    En résumé, si les performance à 4 digits de 52 sont trop faibmes : 5.45M valeurs, 4.5M collisions pour 10M tours, avec Math.pow(b, r+1 ) = Math.pow(52, 4) ~ 7.4M valeurs possibles, soit 74% d'efficacité... en passant à 20M tours, voir à 100M on augmente le nombre de valeurs visitées jusqu'à éventuellement couvrir tout le domaine de valeurs, par contre le nombre de collisions compte jusqu'à la totlité du nombre de tours effectués...

    SOLUTION que j'envisage: passer à 6 ou 8 digits et boucler un peu tant que je rencontre une valeur déjç calculée, les états internes (carries) devant être différents, les collisions seront peut être moins fréquentes.

    L'application de ce générateur est le fait de mettre "à plat" une structure de graphe dans un fichier ou un stream JSON. L'unité de base est le bloc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
      // typescript-like
     
      enum BlockKind = {
          EMPTY, ITEM, GROUP, LINKDEF, ROLEDEF, LINK, TERM
      }
     
      type Block = {
        uid: string // mes fameuses clés "poker" sur 4, 6 ou 8 positions
        kind: BlockKind,
        src: string // uid, source block
        rel: string[] // uid list, related blocks
       data: any // donnée associée à un block
      }
    ... et le JSON résultant est une suite de blocks concataténs les uns apres les autres, d'où l'important de la longueur des clésn s'il en a 1M et que chacin referencez 10 autres, cela fera 4/6/8 * 10M * 10 = .... beaucoup de place utilisée rien que pour les clés !!!

    Enfin quand j'aurais fini cet algo je ferais des tests de perofrmances tenant compte
    - du nombre de digits par clé
    - du nombre de noeuds
    - de leur connectivité

    Encore merci à tous pour vos remarqueset commentaires très inspirants ! Bonne soirée.
    Fichiers attachés Fichiers attachés
    • Type de fichier : js mwc.js (719 octets, 47 affichages)
    • Type de fichier : js mwc.js (2,1 Ko, 57 affichages)

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2018
    Messages : 41
    Points : 33
    Points
    33
    Par défaut 6.38M (confirmation de la théorie)
    @Loralina: je n'avais pas lu ton avant-dernier post, aussi je viens de relancer le test avec MAX_LOOPS = 20M (voir image en pièce jointe), et cela donne :

    - c'est très rapide : moins de 30s
    - j'arrive à 6.84M valeurs
    - 13,16M collisions

    Sachant qu'il y a Math.pow(52, 4) ~ 7.3M de valeurs possibles... on a bien une efficacité qui remonte autour de 6.84 / 7.3 = 93% pour ce qui de l'efficacité, les collisions se produisant à 2/3 du temps...

    En augmentant un peu le nombre de digits, on augemente énormément la plage de valeurs allouables :

    Math.pow(52, 5) ~ 380M

    Math.pow(52, 6) ~ 19,7G

    etc...

    faut que je teste encore, pour disons, 1M de blocks à allouer, ce que cela donne en termes de nouvelles valeurs et de collisions pour 5, 6, 7ou 8 digits. 5 ou 6 pourraient être de bons compromis. Il faut garder à l'esprit que chaque block alloué vient ajouter sa contribution en termes d(espace utilisé en caractères dans le fichier JSON (ou le flux).

    En images :

    - les résultats rapides du test 20M
    - un diagramme représentant la structure de données envisagée, blocks, structure, relation qu'ils entretiennet entre eux et exemple d'application au stockage en vif d'un MCD (E/R diagram) de base.
    Images attachées Images attachées   

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2018
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2018
    Messages : 41
    Points : 33
    Points
    33
    Par défaut
    Bonjour,

    OUPS ! Je me suis peut être un peu étalé sur mon sujet en donnant précédemment quelques détails d'implémentation sur le post N°10... enfin j'aurais sûrement l'occasion de débattre de ce sujet "implémenter des structures graphes de façon sérielle" quand j'aurais un peu plus avancé sur le codage !!!

    En guise de conclusion, je tiens à préciser :

    - que je vais pousser le nombre de digits à 64 positions possibles ( /A-Za-z0-9/ et '$' et "_", en essayant de garder des clés identificateur-compatibles

    - les mettre sur une longueur de 4

    mes blocs mémoire dans le JSON correspondant à la sérialisation de quelque chose du style :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
      { uid: 'cafe',
      btype: 'E',
      src: '900d',
      rel: [ 'KEYS', 'DONT', 'COST', '$999' ],
      data: 'plein-de-données-ou-alors-chaines-de-caractères-tres-longues'
    }
    ... dont la sérialisation fera sûrement entre 128 et 256 de long, peut etre 200...

    Les parseurs JSON étant limités me semble-t-il à 4M caractères, cela fait au moins 10 à 20k blocs allouables... ce qui me paraipt assez honorable pour représenter des portions de schémas relationnels, des graphes d'automates à état finis ou des morceaux de VDOM !

    Enfin c'est une autre histoire... et mon problème du moment.
    Merci à tous pour vos réactions, cela a fait avancer ma réflexion.

    A +, F-E

  13. #13
    Expert éminent
    Avatar de Watilin
    Homme Profil pro
    En recherche d'emploi
    Inscrit en
    Juin 2010
    Messages
    3 094
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : En recherche d'emploi

    Informations forums :
    Inscription : Juin 2010
    Messages : 3 094
    Points : 6 755
    Points
    6 755
    Par défaut
    Si tu as beaucoup d’entrées dans ton JSON, tu peux gagner un peu d’espace en supprimant les clés uid, btype, etc. et en transformant les entrées en tableaux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    [
      'cafe',
      'E',
      '900d',
      [ 'KEYS', 'DONT', 'COST', '$999' ],
      'plein-de-données-ou-alors-chaines-de-caractères-tres-longues'
    ]
    D’autre part, si tu représentes tes digits en base 64, avec + et / à la place de $ et _, tu peux tirer parti de l’encodage base64 existant. Pour le coup, ça ne te fera pas gagner de place mais tu peux peut-être économiser du temps de calcul. Je ne sais pas si ça peut t’aider, mais ça vaut au moins le coup de jeter un œil
    La FAQ JavaScript – Les cours JavaScript
    Touche F12 = la console → l’outil indispensable pour développer en JavaScript !

Discussions similaires

  1. Réponses: 3
    Dernier message: 20/04/2011, 13h52
  2. [C++][Jeux 2D][Algo] Générateur aléatoire d'objets
    Par Aspic dans le forum Développement 2D, 3D et Jeux
    Réponses: 9
    Dernier message: 31/10/2010, 14h28
  3. générateur de nombre (pseudo)-aléatoire
    Par mangeclous dans le forum Mathématiques
    Réponses: 0
    Dernier message: 28/08/2009, 05h18
  4. générateur de nombres pseudo-aléatoire
    Par salseropom dans le forum C
    Réponses: 3
    Dernier message: 22/08/2006, 13h21
  5. Générateur de nombres pseudo-aléatoires
    Par gege2061 dans le forum Algorithmes et structures de données
    Réponses: 10
    Dernier message: 25/08/2005, 13h38

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