Fléchettes, dés et piÚces: algorithmes de distribution discrets


J'ai posé une fois à Stack Overflow une question sur la structure des données pour tricher aux dés . En particulier, je suis intéressé par la réponse à cette question: «Si nous avons un os à n facettes, dont la face i a une probabilité de tomber p i . Quelle est la structure de données la plus efficace pour simuler les rouleaux d'un tel os? »

Cette structure de donnĂ©es peut ĂȘtre utilisĂ©e pour de nombreuses tĂąches. Par exemple, vous pouvez l'utiliser pour simuler des jets hexagonaux honnĂȘtes, en attribuant une probabilitĂ©  f r a c 1 6 de chaque cĂŽtĂ© de l'os, ou pour simuler une piĂšce de monnaie Ă©quitable par imitation d'un os bilatĂ©ral, dont la probabilitĂ© de tomber de chaque cĂŽtĂ© est Ă©gale Ă   f r a c 1 2 . Vous pouvez Ă©galement utiliser cette structure de donnĂ©es pour simuler directement la somme de deux os hexagonaux honnĂȘtes en crĂ©ant un os Ă  11 faces (avec les faces 2, 3, 4, ..., 12), dont chaque face a un poids de probabilitĂ© correspondant aux rouleaux de deux os honnĂȘtes. Cependant, vous pouvez Ă©galement utiliser cette structure de donnĂ©es pour simuler des tricheurs. Par exemple, si vous jouez au craps avec un os, ce qui, comme vous le savez, n'est pas parfaitement honnĂȘte, vous pouvez utiliser cette structure de donnĂ©es pour simuler un grand nombre de rouleaux d'os et analyser la stratĂ©gie optimale. Vous pouvez Ă©galement essayer de simuler une roue de roulette tout aussi imparfaite.

Si vous allez au-delà des jeux, vous pouvez appliquer cette structure de données dans la simulation de robots dont les capteurs ont des niveaux de défaillance connus. Par exemple, si un capteur de plage a une probabilité de 95% de renvoyer la valeur correcte, une probabilité de 4% d'une valeur trop petite et une probabilité de 1% d'une valeur trop élevée, vous pouvez utiliser cette structure de données pour simuler la lecture des lectures du capteur en générant un résultat aléatoire et simuler la lecture du capteur résultat.

La rĂ©ponse que j'ai reçue sur Stack Overflow m'a impressionnĂ© pour deux raisons. Tout d'abord, dans la solution, il m'a Ă©tĂ© conseillĂ© d'utiliser une technique puissante appelĂ©e la mĂ©thode alias , qui, avec certaines hypothĂšses raisonnables sur le modĂšle de la machine, est capable, aprĂšs une simple Ă©tape de prĂ©paration prĂ©liminaire, de simuler des roulements osseux dans le temps O ( 1 ) . DeuxiĂšmement, j'ai Ă©tĂ© encore plus surpris que cet algorithme soit connu depuis des dĂ©cennies, mais je ne l'ai jamais rencontrĂ©! Étant donnĂ© le temps de calcul consacrĂ© Ă  la simulation, on pourrait s'attendre Ă  ce que cette technique soit beaucoup plus connue. Quelques requĂȘtes sur Google m'ont donnĂ© beaucoup d'informations sur cette technique, mais je n'ai pas pu trouver un seul site oĂč une comprĂ©hension et une explication intuitives de cette technique se sont rĂ©unies.

Cet article est ma tentative de donner un bref aperçu des différentes approches pour simuler la triche osseuse, des techniques simples et trÚs peu pratiques à une méthode d'alias trÚs optimisée et efficace. J'espÚre que je serai en mesure de transmettre différentes façons de comprendre intuitivement la tùche et comment chacun d'entre eux met l'accent sur un nouvel aspect de la simulation d'un tricheur. Mon objectif pour chaque approche est d'étudier une idée motivante, un algorithme de base, une preuve de fidélité et une analyse de l'exécution (en termes de temps requis, de mémoire et d'aléatoire).

Entrée


Avant de passer aux détails spécifiques des différentes techniques, normalisons d'abord la terminologie et la notation.

Dans l'introduction de l'article, j'ai utilisé le terme «os tricheur» pour décrire un scénario généralisé dans lequel il existe un ensemble fini de résultats, chacun ayant une probabilité. Formellement, cela s'appelle une distribution de probabilité discrÚte , et la tùche de simuler un os tricheur est appelée échantillonnage à partir d'une distribution discrÚte .

Pour dĂ©crire notre distribution de probabilitĂ© discrĂšte (os tricheur), nous supposerons que nous avons un ensemble de n probabilitĂ©s p 0 , p 1 , . . . , p n - 1 liĂ© aux rĂ©sultats 0, 1, ..., n - 1 $ . Bien que les rĂ©sultats puissent ĂȘtre quelconques (aigle / queues, nombres sur les os, couleurs, etc.), pour simplifier, je considĂ©rerai le rĂ©sultat comme une sorte de nombre rĂ©el positif correspondant Ă  un indice donnĂ©.

Travailler avec des nombres réels sur un ordinateur est la «zone grise» de l'informatique. Il existe de nombreux algorithmes rapides, dont la vitesse est fournie uniquement par la capacité de calculer la fonction de plancher d'un nombre réel arbitraire en un temps constant, et des inexactitudes numériques dans la représentation des nombres à virgule flottante peuvent détruire complÚtement certains algorithmes. Par conséquent, avant de commencer toute discussion sur les algorithmes qui fonctionnent avec des probabilités, c'est-à-dire entrer dans le monde sombre des nombres réels, je dois clarifier ce qu'un ordinateur peut et ne peut pas faire.

Ci-aprĂšs, je suppose que toutes les opĂ©rations suivantes peuvent ĂȘtre effectuĂ©es en temps constant:

  • Addition. soustraction, multiplication, division et comparaison de nombres rĂ©els arbitraires . Nous devrons le faire pour manipuler les probabilitĂ©s. Cela peut sembler une hypothĂšse audacieuse, mais si nous supposons que la prĂ©cision d'un nombre rĂ©el est limitĂ©e par un polynĂŽme de la taille du mot machine (par exemple, un double 64 bits sur une machine 32 bits), mais je ne pense pas que ce soit trop dĂ©raisonnable.
  • GĂ©nĂ©ration d'un nombre rĂ©el uniforme dans l'intervalle [0, 1). Pour simuler le caractĂšre alĂ©atoire, nous avons besoin d'une source de valeurs alĂ©atoires. Je suppose que nous pouvons gĂ©nĂ©rer un nombre rĂ©el de prĂ©cision arbitraire en temps constant. Cela dĂ©passe de loin les capacitĂ©s d'un vĂ©ritable ordinateur, mais il me semble que pour les besoins de cette discussion, cela est acceptable. Si nous acceptons de sacrifier une fraction de la prĂ©cision en disant qu'un double arbitraire IEEE-754 est dans l'intervalle [0, 1], alors nous perdrons en fait la prĂ©cision, mais le rĂ©sultat sera probablement suffisamment prĂ©cis pour la plupart des applications.
  • Calcul du plancher entier (arrondi vers le bas) d'un nombre rĂ©el. Ceci est acceptable si nous supposons que nous travaillons avec le double IEEE-754, mais en gĂ©nĂ©ral, une telle exigence pour un ordinateur n'est pas faisable.

Il vaut la peine de se poser la question - est-il raisonnable de supposer que nous pouvons mener Ă  bien toutes ces opĂ©rations? Dans la pratique, nous utilisons rarement les probabilitĂ©s indiquĂ©es Ă  un tel niveau de prĂ©cision auquel l'erreur d'arrondi inhĂ©rente au double IEEE-754 peut causer de graves problĂšmes, nous pouvons donc remplir toutes les exigences ci-dessus simplement en travaillant exclusivement avec le double IEEE. Cependant, si nous nous trouvons dans un environnement oĂč les probabilitĂ©s sont indiquĂ©es exactement comme des nombres rationnels de haute prĂ©cision, alors de telles restrictions peuvent ĂȘtre dĂ©raisonnables.

Simulation osseuse honnĂȘte


Avant de passer au cas plus gĂ©nĂ©ral de lancer un os de triche arbitraire, commençons par un algorithme plus simple qui servira de bloc de construction pour les algorithmes suivants: simuler un os honnĂȘte Ă  face n. Par exemple, des dĂ©s hexagonaux honnĂȘtes peuvent ĂȘtre utilisĂ©s pour jouer au Monopoly ou Risk, ou lancer une piĂšce honnĂȘte (dĂ©s Ă  double face), etc.

Pour ce cas particulier, il existe un algorithme simple, Ă©lĂ©gant et efficace pour simuler le rĂ©sultat. L'algorithme est basĂ© sur l'idĂ©e suivante: supposons que nous pouvons gĂ©nĂ©rer des nombres rĂ©els vraiment alĂ©atoires et uniformĂ©ment rĂ©partis dans l'intervalle [ 0 , 1 ) . Cet intervalle peut ĂȘtre illustrĂ© comme suit:


Maintenant, si nous voulons quitter n os Ă  facettes, alors une façon est de diviser l'intervalle [ 0 , 1 ) sur n zones de taille Ă©gale, chacune ayant une longueur  f r a c 1 n . Cela ressemble Ă  ceci:


Ensuite, nous gĂ©nĂ©rons un nombre rĂ©el choisi au hasard dans l'intervalle [ 0 , 1 ) cela tombe sĂ»rement dans l'un de ces petits domaines. À partir de cela, nous pouvons calculer le rĂ©sultat du roulement de l'os en regardant la zone dans laquelle le nombre est tombĂ©. Par exemple, si notre valeur sĂ©lectionnĂ©e au hasard tombe Ă  cet endroit:


on peut alors dire que 2 sont tombés sur l'os (si l'on suppose que les bords de l'os sont indexés à partir de zéro).

Il est graphiquement facile de voir quelle rĂ©gion a une valeur alĂ©atoire, mais comment codons-nous cela dans un algorithme? Et ici, nous profitons du fait que c'est un os honnĂȘte. Étant donnĂ© que tous les intervalles sont de taille Ă©gale, Ă  savoir  f r a c 1 n , alors nous pouvons voir quelle est la plus grande valeur je est telle que  f r a c i n pas plus qu'une valeur gĂ©nĂ©rĂ©e alĂ©atoirement (appelons cette valeur x). Vous remarquerez peut-ĂȘtre que si nous voulons trouver la valeur maximale, telle que  f r a c i n l e x  , cela revient Ă  trouver la valeur maximale n tel que i l e x n  . Mais cela signifie par dĂ©finition que i= lfloorxn rfloor , le plus grand entier positif n'est pas supĂ©rieur Ă  xn. Par consĂ©quent, cela nous conduit Ă  cet algorithme de simulation osseuse Ă  facettes n honnĂȘte (trĂšs simple):

Algorithme: simulation osseuse honnĂȘte


  1. Générer une valeur aléatoire uniformément distribuée x dans la gamme [0,1) .
  2. Retour  lfloorxn rfloor .

Compte tenu de nos hypothĂšses ci-dessus sur les calculs, cet algorithme fonctionne dans le temps O(1) .

Deux conclusions peuvent ĂȘtre tirĂ©es de cette section. Tout d'abord, nous pouvons diviser l'intervalle [0,1) en partie de sorte qu'un nombre rĂ©el alĂ©atoire uniformĂ©ment rĂ©parti dans cet intervalle se rĂ©duit naturellement Ă  l'une des nombreuses options discrĂštes Ă  notre disposition. Dans la suite de cet article, nous exploiterons activement cette technique. DeuxiĂšmement, il peut ĂȘtre difficile de dĂ©terminer Ă  quel intervalle spĂ©cifique appartient une valeur alĂ©atoire, mais si nous savons quelque chose sur les parties (dans ce cas, elles sont toutes de la mĂȘme taille), alors nous pouvons mathĂ©matiquement simplement dĂ©terminer quelle partie se rĂ©fĂšre Ă  un particulier point.

Simulation d'os de triche avec os honnĂȘte


Avec un algorithme de simulation osseuse honnĂȘte, pouvons-nous l'adapter pour simuler un os tricheur? Fait intĂ©ressant, la rĂ©ponse est oui, mais une solution nĂ©cessitera plus d'espace.

De la section prĂ©cĂ©dente, il est intuitivement clair que pour simuler un lancer d'os de triche, il suffit de diviser l'intervalle [0,1) en morceaux, puis dĂ©terminez quelle partie nous frappons. Cependant, dans le cas gĂ©nĂ©ral, cela peut ĂȘtre beaucoup plus compliquĂ© qu'il n'y paraĂźt. Disons que nous avons un tĂ©traĂšdre avec des probabilitĂ©s de face  frac12 ,  frac13 ,  frac112 et  frac112 (nous pouvons nous assurer que c'est la distribution de probabilitĂ© correcte, car  frac12+ frac13+ frac112+ frac112= frac612+ frac412+ frac112+ frac112= frac1212 ) Si nous divisons l'intervalle [0,1) en quatre parties de ces tailles, nous obtenons alors les Ă©lĂ©ments suivants:


Malheureusement, Ă  ce stade, nous sommes bloquĂ©s. MĂȘme si nous connaissions un nombre alĂ©atoire dans l'intervalle [0,1) , il n'y a pas d'astuces mathĂ©matiques simples pour dĂ©terminer automatiquement dans quelle partie ce nombre est tombĂ©. Je ne veux pas dire que cela est impossible - comme vous le verrez, nous pouvons utiliser de nombreux excellents trucs - mais aucun d'eux n'a la simplicitĂ© mathĂ©matique de l'algorithme honnĂȘte de projection d'os.

Cependant, nous pouvons Ă©galement adapter la technique utilisĂ©e pour un os honnĂȘte. Prenons l'exemple de l'os discutĂ© ci-dessus. La probabilitĂ© de fronts descendants est  frac12 ,  frac13 ,  frac112 et  frac112 . Si nous réécrivons ceci pour que tous les membres aient un diviseur commun, nous obtenons les valeurs  frac612 ,  frac412 ,  frac112 et  frac112 . Par consĂ©quent, nous pouvons percevoir cette tĂąche comme suit: au lieu de jeter un os tĂ©traĂ©drique avec des probabilitĂ©s pondĂ©rĂ©es, pourquoi ne pas jeter un os honnĂȘte Ă  12 cĂŽtĂ©s, sur les bords duquel il y a des valeurs en double? Puisque nous savons simuler un os honnĂȘte, cela sera analogue Ă  la sĂ©paration par intervalles [0,1) en morceaux de cette façon:


Ensuite, nous les affectons à différents résultats comme suit:


Maintenant, il sera trĂšs simple de simuler un lancer d'os - nous jetons simplement ce nouvel os honnĂȘte, puis nous regardons quel visage est tombĂ© et lisons sa valeur. Cette premiĂšre Ă©tape peut ĂȘtre effectuĂ©e par l'algorithme prĂ©sentĂ© ci-dessus, qui nous donnera un nombre entier de nombres dans l'intervalle 0 $, 1, ..., 11 $ . Afin de lier cet entier Ă  l'une des faces de l'os du tricheur d'origine, nous allons stocker un tableau auxiliaire de douze Ă©lĂ©ments reliant chacun de ces nombres au rĂ©sultat d'origine. Cela peut ĂȘtre reprĂ©sentĂ© graphiquement comme suit:


Pour formaliser cela sous la forme d'un algorithme, nous dĂ©crivons Ă  la fois l'Ă©tape d'initialisation (obtention de la table) et l'Ă©tape de gĂ©nĂ©ration (simulation d'un lancer osseux alĂ©atoire). Ces deux Ă©tapes sont importantes Ă  considĂ©rer dans cet algorithme et les suivants, car le temps de prĂ©paration doit ĂȘtre excellent.

Au stade de l'initialisation, nous commençons par chercher le multiple le moins commun de toutes les probabilitĂ©s donnĂ©es pour les bords de l'os (dans notre exemple, la LCL est 12). NOC est utile ici car il correspond au plus petit diviseur commun que nous pouvons utiliser pour toutes les fractions, et donc le nombre de faces du nouvel os honnĂȘte que nous roulerons. AprĂšs avoir reçu ce CNO (nous le dĂ©signons par L), nous devons dĂ©terminer combien de faces du nouvel os seront rĂ©parties sur chacune des faces de l'os tricheur d'origine. Dans notre exemple, le visage avec probabilitĂ©  frac12 obtient six cĂŽtĂ©s du nouvel os depuis  frac12 fois12=6 . De mĂȘme, la partie avec probabilitĂ©  frac13 obtient 4 visages depuis  frac13 fois12=4 . Dans une forme plus gĂ©nĂ©ralisĂ©e, si L est une LCL de probabilitĂ©s, et pi est la probabilitĂ© d'un visage i les os, puis nous mettons en Ă©vidence les visages i os de Sharpie d'origine L cdotpi facettes de l'os honnĂȘte.

Voici le pseudocode de l'algorithme ci-dessus:

Algorithme: simuler l'os de triche avec de l'os honnĂȘte


  • Initialisation :
    1. Trouver le CNO des dĂ©nominateurs de probabilitĂ© p0,p1,...,pn−1 ; le dĂ©noter L
    2. SĂ©lectionnez un tableau A la taille L pour comparer les rĂ©sultats de rouleaux d'os honnĂȘtes avec les rouleaux de l'os d'origine.
    3. Pour chaque visage i de l'os initial, nous effectuons les opérations suivantes dans n'importe quel ordre:
      1. Nous attribuons comme suit L cdotpi des Ă©lĂ©ments A valeur i .
  • GĂ©nĂ©ration :
    1. Nous gĂ©nĂ©rons un lancer d'os honnĂȘte pour L -os osseux; appeler le visage S .
    2. Retour A[S] .

Cet algorithme peut ĂȘtre simple, mais quelle est son efficacitĂ©? La gĂ©nĂ©ration de rouleaux osseux est assez rapide - chaque rouleau osseux nĂ©cessite O(1) runtime pour gĂ©nĂ©rer un jet de dĂ©s alĂ©atoire en utilisant l'algorithme prĂ©cĂ©dent, et plus encore O(1) heures de travail pour rechercher la table. Cela nous donne le temps de travail total. O(1) .

Cependant, l'Ă©tape d'initialisation peut ĂȘtre extrĂȘmement coĂ»teuse. Pour que cet algorithme fonctionne, nous devons allouer de l'espace Ă  un tableau de la taille du NLC des dĂ©nominateurs de toutes les fractions d'entrĂ©e. Dans notre exemple (  frac12 ,  frac13 ,  frac112 ,  frac112 ), il est de 12, pour d'autres valeurs d'entrĂ©e, les valeurs peuvent ĂȘtre pathologiquement mauvaises. Par exemple, regardons les fractions  frac9999991000000 et  frac11000000 . Le CNO des dĂ©nominateurs est Ă©gal Ă  un million, donc il devrait y avoir un million d'Ă©lĂ©ments dans notre tableau!

Malheureusement, les choses pourraient ĂȘtre encore pires. Dans l'exemple prĂ©cĂ©dent, on peut au moins «s'attendre» Ă  ce que l'algorithme occupe beaucoup de mĂ©moire, car les deux dĂ©nominateurs des fractions sont Ă©gaux Ă  un million. Cependant, nous pouvons avoir de nombreuses probabilitĂ©s pour lesquelles la CNP est nettement supĂ©rieure Ă  chaque dĂ©nominateur individuel. Par exemple, regardons les probabilitĂ©s  frac115 ,  frac110 ,  frac56 . Ici, le NOC des dĂ©nominateurs est de 30, ce qui est plus que n'importe lequel des dĂ©nominateurs. Le design fonctionne ici parce que 15 $ = 3 \ fois 5 $ , 10 $ = 2 \ fois 5 $ et 6 $ = 2 \ fois 3 $ ; en d'autres termes, chaque dĂ©nominateur est un produit de deux nombres premiers sĂ©lectionnĂ©s dans un pool de trois valeurs. Par consĂ©quent, leur NOC est le produit de tous ces nombres premiers, car chaque dĂ©nominateur doit ĂȘtre un diviseur du NOC. Si nous gĂ©nĂ©ralisons cette construction et considĂ©rons tout ensemble de k nombres premiers et prendre une fraction pour chacun des produits par paires de ces nombres premiers, alors le NOC sera beaucoup plus que chaque dĂ©nominateur individuel. En fait, l'une des meilleures limites supĂ©rieures que nous pouvons obtenir pour le CNO sera O( prodni=0di) oĂč di Est le dĂ©nominateur i cette probabilitĂ©. Cela ne permet pas d'utiliser un tel algorithme en conditions rĂ©elles, lorsque les probabilitĂ©s sont inconnues Ă  l'avance, car la mĂ©moire nĂ©cessaire pour stocker la table de taille O( prodni=0di) , Il peut facilement s'avĂ©rer supĂ©rieur au volume pouvant tenir dans la RAM.

En d'autres termes, dans de nombreux cas, cet algorithme se comporte bien. Si toutes les probabilitĂ©s sont les mĂȘmes, alors toutes les probabilitĂ©s obtenues Ă  l'entrĂ©e sont Ă©gales  frac1n pour certains n . Ensuite, les dĂ©nominateurs des CNO sont Ă©gaux n , c'est-Ă -dire qu'en consĂ©quence, l'os honnĂȘte jetĂ© aura n faces, et chaque facette de l'os d'origine correspondra Ă  une facette de l'os honnĂȘte. Par consĂ©quent, le temps d'initialisation est O(n) . Cela peut ĂȘtre reprĂ©sentĂ© graphiquement comme suit:


Cela nous donne les informations suivantes sur l'algorithme:

AlgorithmeTemps d'initialisationTemps de générationMémoire occupée
Le meilleurLe pireLe meilleurLe pireLe meilleurLe pire
HonnĂȘtetĂ© os sharler bone Theta(n)O( prodni=0di) ThĂȘta(1) Theta(n)O( prodni=0di)

Autre dĂ©tail important sur cet algorithme: il suppose que nous recevrons des probabilitĂ©s pratiques sous forme de fractions avec de bons dĂ©nominateurs. Si les probabilitĂ©s sont spĂ©cifiĂ©es comme IEEE-754 double, cette approche risque d'ĂȘtre dĂ©sastreuse en raison de petites erreurs d'arrondi; Imaginez que nous ayons les probabilitĂ©s 0,25 et 0,250000000001! Par consĂ©quent, cette approche est probablement prĂ©fĂ©rable de ne pas utiliser, sauf dans des cas particuliers oĂč les probabilitĂ©s se comportent bien et sont spĂ©cifiĂ©es dans un format correspondant aux opĂ©rations avec des nombres rationnels.

Simulation de piÚces asymétriques


Notre explication d'une simple primitive alĂ©atoire (os honnĂȘte) a conduit Ă  un algorithme de simulation d'os de triche simple mais potentiellement terriblement inefficace. L'Ă©tude d'autres primitives alĂ©atoires simples Ă©clairera peut-ĂȘtre d'autres approches pour rĂ©soudre ce problĂšme.

Une tĂąche simple mais Ă©tonnamment utile consiste Ă  simuler une piĂšce asymĂ©trique Ă  l'aide d'un gĂ©nĂ©rateur de nombres alĂ©atoires. Si nous avons une piĂšce avec la probabilitĂ© d'un aigle ptĂȘtes , alors comment simuler le lancer d'une telle piĂšce asymĂ©trique?

Plus tÎt, nous avons développé une approche intuitive: le partitionnement par intervalles [0,1) sur une séquence de telles régions que lors du choix d'une valeur aléatoire dans l'intervalle, elle apparaßt dans certaines régions avec une probabilité égale à la taille de la région. Pour simuler une piÚce asymétrique en utilisant une valeur aléatoire uniformément distribuée dans l'intervalle [0,1) il faut rompre l'intervalle [0,1) comme suit:


Et puis gĂ©nĂ©rer une valeur alĂ©atoire uniformĂ©ment distribuĂ©e dans l'intervalle [0,1) pour voir dans quelle zone il se trouve. Heureusement, nous n'avons qu'un seul point de partage, il est donc trĂšs facile de dĂ©terminer dans quelle zone il se trouve; si la valeur est infĂ©rieure ptĂȘtes , puis l'aigle est tombĂ© sur la piĂšce, sinon - queues. Pseudocode:

Algorithme: simuler une piÚce asymétrique


  1. Générer une valeur aléatoire uniformément distribuée dans l'intervalle [0,1) .
  2. Si x < p t ĂȘ t e s , retournez "l'aigle".
  3. Si x g e p t ĂȘ t e s  , renvoyez la queue.

Puisque nous pouvons générer une valeur aléatoire uniformément distribuée dans l'intervalle [ 0 , 1 ) à temps O ( 1 ) , et nous pouvons également comparer des nombres réels pour O ( 1 ) , alors cet algorithme s'exécute dans le temps O ( 1 ) .

Simuler des os honnĂȘtes Ă  l'aide de piĂšces asymĂ©triques


De la discussion prĂ©cĂ©dente, nous savons que nous pouvons simuler un os de triche en utilisant de l'os honnĂȘte, si nous supposons que nous sommes prĂȘts Ă  dĂ©penser plus d'espace mĂ©moire. Étant donnĂ© que nous pouvons percevoir une piĂšce asymĂ©trique comme un os bilatĂ©ral tricheur, cela signifie que nous pouvons simuler une piĂšce asymĂ©trique Ă  l'aide d'un os honnĂȘte. Il est intĂ©ressant de voir que l'inverse peut Ă©galement ĂȘtre fait - pour simuler un os honnĂȘte Ă  l'aide d'une piĂšce asymĂ©trique.Le design est simple, Ă©lĂ©gant et peut ĂȘtre facilement gĂ©nĂ©ralisĂ© pour simuler un os tricheur en utilisant une variĂ©tĂ© de piĂšces asymĂ©triques.

Conception pour simuler une piĂšce asymĂ©trique divise l'intervalle[ 0 , 1 ) en deux zones - la zone «aigles» et la zone «queues» en fonction de la probabilitĂ© que les aigles tombent sur les os. Nous avons dĂ©jĂ  vu une astuce similaire utilisĂ©e pour simuler honnĂȘten- os Ă  facettes: intervalle[ 0 , 1 ) Ă©tait divisĂ© enn zones Ă©gales. Par exemple, lors du lancement d'un os tĂ©traĂ©drique, nous avons obtenu la sĂ©paration suivante:


Supposons maintenant que nous soyons intĂ©ressĂ©s Ă  simuler un rouleau de cet os honnĂȘte en utilisant un ensemble de piĂšces asymĂ©triques. Une solution est la suivante: imaginez que nous contournons ces zones de gauche Ă  droite, en nous demandant Ă  chaque fois si nous voulons nous arrĂȘter dans la zone actuelle, ou si nous allons continuer. Par exemple, disons que nous voulons sĂ©lectionner au hasard l'une de ces zones. En partant de la zone la plus Ă  gauche, nous lancerons une piĂšce asymĂ©trique, qui nous dira si nous devons nous arrĂȘter dans cette zone ou continuer Ă  avancer. Puisque nous devons choisir parmi toutes ces zones uniformĂ©ment avec probabilitĂ©14 , alors nous pouvons le faire en lançant une piĂšce asymĂ©trique, les aigles sur lesquels tomber avec probabilitĂ©14 .Si un aigle tombe, nous nous arrĂȘtons dans la zone actuelle. Sinon, nous passons Ă  la zone suivante.

Si les piĂšces tombent, nous nous retrouvons dans la deuxiĂšme zone et nous demandons Ă  nouveau si nous devons sĂ©lectionner Ă  nouveau cette zone ou continuer Ă  bouger. Vous pourriez penser que pour cela, nous devons lancer une autre piĂšce avec la probabilitĂ© d'un aigle14 , mais en rĂ©alitĂ© ce n'est pas vrai! Pour voir la faille de ce raisonnement, nous devons arriver Ă  une situation extrĂȘme - si dans chaque zone nous lançons une piĂšce sur laquelle l'aigle tombe avec probabilitĂ©14 , c'est-Ă -dire qu'il y a une petite chance que dans chaque zone la piĂšce tombe en queue, c'est-Ă -dire que nous devrons abandonner toutes les zones. Lorsque nous traversons des rĂ©gions, nous devons en quelque sorte continuer d'augmenter la probabilitĂ© qu'un aigle tombe sur une piĂšce. Dans une situation extrĂȘme, si nous nous trouvons dans la derniĂšre zone, la piĂšce doit avoir un aigle avec probabilitĂ©1 , parce que si nous rejetions tous les domaines prĂ©cĂ©dents, la bonne dĂ©cision serait d'arrĂȘter dans le dernier domaine.

Pour dĂ©terminer la probabilitĂ© avec laquelle notre piĂšce asymĂ©trique devrait lancer un aigle aprĂšs avoir sautĂ© la premiĂšre zone, nous devons noter qu'aprĂšs avoir sautĂ© la premiĂšre zone, il n'en reste que trois. Alors que nous roulons un os honnĂȘte, nous avons besoin que chacune de ces trois zones soit sĂ©lectionnĂ©e avec probabilitĂ©13 . Par consĂ©quent, intuitivement, il semble que nous devrions avoir un deuxiĂšme os sur lequel l'aigle tombe avec probabilitĂ© 13 . En utilisant un raisonnement similaire, on peut comprendre que lorsqu'une queue apparaĂźt dans la deuxiĂšme rĂ©gion du rĂ©seau dans la troisiĂšme rĂ©gion, la piĂšce doit ĂȘtre lĂąchĂ©e par l'aigle avec probabilitĂ© 12 , et dans la derniĂšre zone - avec probabilitĂ©1 .

Cette compréhension intuitive nous conduit à l'algorithme suivant. Notez que nous n'avons pas discuté de l'exactitude ou de l'erreur de cet algorithme; nous le ferons bientÎt.

Algorithme: simuler des os honnĂȘtes Ă  l'aide de piĂšces asymĂ©triques


  1. Pour i = 0 Ă n - 1 :
    1. Lancez une piÚce asymétrique avec la probabilité d'un aigle 1n - i .
    2. Si l'aigle tombe, revenez je .

Cet algorithme est simple et, dans le pire des cas, s'exécute dans le temps. O ( n ) .Mais comment vérifier si c'est correct? Pour le savoir, nous avons besoin du théorÚme suivant:

ThéorÚme: l' algorithme ci - dessus renvoie le cÎtéi avec probabilité1n pour tout sélectionnéje .

Preuve: considĂ©rer toute constanten ≄ 0 . En utilisant une forte induction, nous prouvons que chacun des n faces a une probabilitĂ© de choix1n .

Pour notre exemple, nous montrons que le visage 0 dĂ©s a une probabilitĂ© de choix1n . Mais cela dĂ©coule directement de l'algorithme lui-mĂȘme - nous choisissons la face 0 si sur une piĂšce asymĂ©trique avec la probabilitĂ© d'un aigle 1n , 1n .

0,1,2,...,k−1 , 1n k . k , k , 1n−k . k 1n , , k est donnĂ© commekn . Cela signifie que la probabilitĂ© que l'algorithme ne sĂ©lectionne pas l'un des premiers k faces est Ă©gal Ă 1 - kn =nn -kn =n-kn . Autrement dit, la probabilitĂ© de choisir un visage k est donnĂ© commen - kn 1n - k =1n , qui doit ĂȘtre montrĂ©. Ainsi, chaque face de l'os est sĂ©lectionnĂ©e de maniĂšre uniforme et alĂ©atoire.

Bien sĂ»r, l'algorithme est assez inefficace - en utilisant la premiĂšre technique, nous pouvons simuler un lancer de dĂ©s honnĂȘtes dans le temps O ( 1 ) ! Mais cet algorithme peut ĂȘtre utilisĂ© comme tremplin vers un algorithme suffisamment efficace pour simuler un os tricheur Ă  l'aide de piĂšces asymĂ©triques.

Simulation de l'os de Shuler à l'aide de piÚces asymétriques


L'algorithme présenté ci-dessus est intéressant en ce qu'il nous donne un cadre simple pour simuler un os à l'aide d'un ensemble de piÚces. Nous commençons par lancer une piÚce pour déterminer s'il faut sélectionner la premiÚre facette de l'os ou passer au reste. Dans ce processus, nous devons gérer soigneusement l'échelle des probabilités restantes.

Voyons comment vous pouvez utiliser cette technique pour simuler un lancer d'os infidÚle. Nous utilisons notre exemple avec probabilités12 , 13 , 112 , 112 . Lui, si vous ne vous en souvenez pas, divise l'intervalle [ 0 , 1 ) comme suit:


Voyons maintenant comment simuler un tel os de triche Ă  l'aide de piĂšces asymĂ©triques. On peut commencer par lancer une piĂšce avec la probabilitĂ© d'un aigle12 pour dĂ©terminer si nous devons retourner face 0. Si un aigle tombe sur cette piĂšce, alors trĂšs bien! Nous avons terminĂ©. Sinon, nous devons lancer une autre piĂšce pour dĂ©cider de sĂ©lectionner la prochaine facette. Comme prĂ©cĂ©demment, malgrĂ© le fait que la prochaine facette a une probabilitĂ© de choix13 , nous ne voulons pas lancer une piĂšce sur laquelle l'aigle tombe avec probabilitĂ©13 , car la moitiĂ© de la «masse» des probabilitĂ©s a Ă©tĂ© rejetĂ©e lorsque nous n'avons pas sĂ©lectionnĂ© de ligne avec12 . En fait, puisque la moitiĂ© de la masse des probabilitĂ©s a disparu, alors si nous normalisons les probabilitĂ©s restantes, nous obtiendrons des probabilitĂ©s mises Ă  jour: 23 , 16 , 16 . Par consĂ©quent, la deuxiĂšme piĂšce doit ĂȘtre lancĂ©e avec probabilitĂ© 23 . Si cette piĂšce est Ă©galement Ă  queue, nous devons choisir entre deux faces 112 . Puisqu'Ă  ce stade nous allons nous dĂ©barrasser de 56 masses de probabilitĂ©s, alors nous pouvons normaliser Ă  nouveau les probabilitĂ©s des parties112 pour que chacun ait sa chance12 gouttes d'aigle, c'est-Ă -dire que la troisiĂšme piĂšce aura une probabilitĂ©12 . La derniĂšre piĂšce, si jamais elle lui vient, devrait jeter l'aigle avec probabilitĂ© 1 puisqu'il s'agit du domaine le plus rĂ©cent.

Pour résumer, les probabilités des piÚces seront les suivantes:

  1. Premier lancer: 12
  2. DeuxiĂšme rouleau: 23
  3. TroisiĂšme rouleau: 12
  4. QuatriĂšme rouleau: 1

Il peut ĂȘtre intuitif d'oĂč viennent ces nombres, mais pour transformer la sĂ©lection en algorithme, nous devons crĂ©er une construction formelle du choix des probabilitĂ©s. L'idĂ©e sera la suivante - Ă  chaque Ă©tape, nous nous souvenons du reste de la masse des probabilitĂ©s. Au dĂ©but, avant que la premiĂšre piĂšce ne soit lancĂ©e, elle est Ă©gale Ă 1 . AprĂšs avoir lancĂ© la premiĂšre piĂšce 1 - p 0 . AprĂšs avoir lancĂ© une deuxiĂšme piĂšce 1 - p 0 - p 1 . Plus gĂ©nĂ©ralement aprĂšs le lancer k le reste de la masse de probabilitĂ© est1 - ∑ k - 1 i = 0 p i . Chaque fois que nous lançons une piĂšce pour dĂ©terminer s'il faut ou non sĂ©lectionner une zone k , par consĂ©quent, nous jetons une piĂšce, la probabilitĂ© qu'un aigle tombe sur laquelle est Ă©gale Ă  la fraction de la probabilitĂ© restante occupĂ©e par la probabilitĂ©p k , qui est dĂ©fini commep k1 - ∑ k - 1 i = 0 p i . Cela nous donne l'algorithme suivant pour tricher la simulation osseuse avec un ensemble de piĂšces asymĂ©triques (nous prouverons son exactitude et sa durĂ©e d'exĂ©cution juste ci-dessous):

Algorithme: os Schuler de piÚces asymétriques


  • Initialisation :
    1. Nous gardons des probabilités p i pour une utilisation future.
  • GĂ©nĂ©ration :
    ensemblem a s s = 1
    Pouri = 0 Ă n - 1 :
    1. Lancez une piÚce asymétrique avec la probabilité d'un aigle p im a s s .
    2. Si l'aigle tombe, revenez je .
    3. Sinon, nous définissons m a s s = m a s s - p i

D'un point de vue intuitif, c'est logique, mais est-ce mathématiquement vrai? Heureusement, la réponse est oui grùce à une généralisation de la preuve ci-dessus:

ThéorÚme: l'algorithme montré ci-dessus renvoie un visagei avec probabilitép i pour tout sélectionnéje .

Preuve: considĂ©rer toute constanten ≄ 0 . , n pi .

, 0 p0 . 0 , , p0mass . mass 1 , p01=p0 , 0 p0 , .

, 0,1,...,k−1 p0,p1,...,pk−1 k . k , k , pkmass . k , , k ∑k−1i=0pi . , k 1−∑k−1i=0pi . , k , pkmass k , m a s s = 1 - ∑ k - 1 i = 0 p i . Cela signifie que la probabilitĂ© globale de choisir un visage k est donnĂ© comme( 1 - ∑ k - 1 i = 0 p i ) p k1 - ∑ k - 1 i = 0 p i =pk, selon les besoins.

Évaluons maintenant la complexitĂ© temporelle de cet algorithme. Nous savons que le temps d'initialisation peut ĂȘtreΘ ( 1 ) si nous conservons une copie de surface du tableau de probabilitĂ© d'entrĂ©e, mais il peut y avoirΘ ( n ) afin que nous puissions enregistrer notre propre version du tableau (au cas oĂč la fonction appelante voudrait la changer plus tard). La gĂ©nĂ©ration mĂȘme d'un rĂ©sultat de projection osseuse peut nĂ©cessiter dans le pire des casΘ ( n ) lancers, et un seul lancer au mieux.

Cependant, aprÚs réflexion, il devient clair que le nombre de lancers de piÚces nécessaires est fortement influencé par la distribution entrante. Dans le meilleur des cas, nous aurons une distribution de probabilité dans laquelle toute la masse des probabilités est concentrée sur le premier bord de l'os, et toutes les autres probabilités sont nulles. Dans ce cas, un tirage au sort nous suffit. Dans le pire des cas, la masse entiÚre des probabilités est concentrée dans la toute derniÚre facette de l'os, et sur toutes les autres faces, elle est égale à zéro. Dans ce cas, nous devons jetern .

. X , . P[X=1] , , P[X=2] — , , .. X , E[X] . ,

E[X]=n∑i=1i⋅P[X=i]


P[X=i] ? - . 0 , . 1 , — , 0 , , 1 . , i , i+1 : i , , i−1 , , , i . , i pi , ,

E[X]=n∑i=1i⋅P[X=i]=n∑i=1i⋅pi−1=n∑i=1((i−1)pi−1+pi−1)=n∑i=1((i−1)pi−1)+n∑i=1pi−1


Notez que dans la derniĂšre simplification, le premier terme est Ă©quivalent  sumn−1i=0i cdotpi ce qui est Ă©quivalent  mathbbE[p] , le rĂ©sultat attendu d'un lancer de dĂ©s! De plus, le deuxiĂšme terme est Ă©gal Ă  1 car c'est la somme de toutes les probabilitĂ©s. Cela signifie que  mathbbE[X]= mathbbE[p]+1 . Autrement dit, le nombre attendu de lancers de piĂšces est Ă©gal Ă  un plus l'attente mathĂ©matique d'un lancer de dĂ©!

AlgorithmeTemps d'initialisationTemps de générationMémoire occupée
Le meilleurLe pireLe meilleurLe pireLe meilleurLe pire
HonnĂȘtetĂ© os sharler bone Theta(n)O( prodni=0di) ThĂȘta(1) Theta(n)O( prodni=0di)
Os Schuler de piĂšces asymĂ©triques Theta(n) ThĂȘta(1) Theta(n) Theta(n)

Généraliser les piÚces asymétriques: simuler un os tricheur


Dans l'exemple ci-dessus, nous avons pu simuler efficacement une piĂšce asymĂ©trique, car nous n'avions Ă  prendre en compte qu'un seul point de partage. Comment gĂ©nĂ©raliser efficacement cette idĂ©e Ă  un os de triche dans lequel le nombre de visages peut ĂȘtre arbitraire?

Comme vous pouvez le voir, une piĂšce asymĂ©trique est un os de triche, avec seulement deux faces. Par consĂ©quent, nous pouvons percevoir une piĂšce asymĂ©trique simplement comme un cas particulier d'un problĂšme plus gĂ©nĂ©ral que nous voulons rĂ©soudre. Lors de la rĂ©solution du problĂšme des piĂšces asymĂ©triques, nous divisons l'intervalle [0,1) en deux zones - une pour l'aigle, la seconde pour la queue - puis pour trouver la zone, nous utilisons le fait qu'il n'y a qu'un seul point de partage. Si nous avons un os Ă  n faces, alors il y aura plus de zones, et donc plusieurs points de division. Supposons, par exemple, que nous ayons un os Ă  sept cĂŽtĂ©s avec des probabilitĂ©s  frac14 ,  frac15 ,  frac18 ,  frac18 ,  frac110 ,  frac110 ,  frac110 . Si nous voulons diviser l'intervalle [0,1) en sept parties, nous procĂ©dons comme suit:


Remarquez oĂč se trouvent ces zones. Le premier domaine commence par 0 et se termine  frac14 . Le deuxiĂšme domaine commence par  frac14 et se termine par  frac14+ frac15= frac920 . Plus gĂ©nĂ©ralement, si les probabilitĂ©s sont Ă©gales p0,p1,...,pn−1 , alors les zones seront des intervalles [0,p0) , [p0,p0+p1) , [p0+p1,p0+p1+p2) etc. C'est le domaine i limitĂ© par intervalle

[ sumi−1j=0pj, sumij=0pj)


Notez que la différence entre ces deux valeurs est pi c'est-à-dire que la superficie totale de la région est pi au besoin.

Maintenant, nous savons oĂč se trouvent les zones. Si nous voulons choisir une valeur alĂ©atoire uniformĂ©ment distribuĂ©e x dans la gamme [0,1) , alors comment dĂ©terminer dans quel intervalle tombe-t-il? Si nous utilisons l'algorithme de piĂšce asymĂ©trique comme point de dĂ©part, l'idĂ©e sera la suivante: en partant du point final de la premiĂšre rĂ©gion, remontez constamment dans toutes les zones jusqu'Ă  ce que nous trouvions un point final dont la valeur est supĂ©rieure Ă  la valeur x . Si nous faisons cela, nous trouverons la premiĂšre rĂ©gion contenant le point x , et donc notre valeur. Par exemple, si nous avons choisi une valeur alĂ©atoire x= frac2740 , puis effectuez la recherche suivante:


D'oĂč nous pouvons conclure que la facette 3 est tombĂ©e sur des dĂ©s avec indexation Ă  partir de zĂ©ro.

Un tel algorithme de balayage linĂ©aire nous donnera un algorithme de temps O(n) pour trouver le bord Ă©jectĂ© de l'os. Cependant, nous pouvons amĂ©liorer considĂ©rablement son temps d'exĂ©cution en utilisant l'observation suivante: une sĂ©rie de points d'extrĂ©mitĂ© de rĂ©gions forme une sĂ©quence croissante (puisque nous ajoutons toujours de plus en plus de probabilitĂ©s, dont aucune ne peut ĂȘtre infĂ©rieure Ă  zĂ©ro). Par consĂ©quent, nous voulons rĂ©pondre Ă  la question suivante: ayant une sĂ©quence croissante de valeurs et un certain point de contrĂŽle, nous devons trouver la premiĂšre valeur de l'intervalle strictement supĂ©rieure au point de contrĂŽle. C'est le moment idĂ©al pour utiliser la recherche binaire ! Par exemple, voici une recherche binaire sur le tableau ci-dessus pour trouver la zone Ă  laquelle il appartient x= frac3940 :


Cela nous donne un algorithme au fil du temps.  Theta( logn) pour lier une valeur alĂ©atoire uniformĂ©ment distribuĂ©e dans l'intervalle [0,1) au bord d'un os abandonnĂ©. De plus, le temps de prĂ©traitement est suffisant pour construire la table des points de terminaison  Theta(n) ; nous calculons simplement des sommes partielles de probabilitĂ©s Ă  mesure que nous progressons.

Cet algorithme est parfois appelĂ© algorithme de sĂ©lection de la roulette car il sĂ©lectionne une zone alĂ©atoire en utilisant une technique similaire Ă  une roulette - lancer une balle dans un intervalle et observer oĂč elle s'arrĂȘte. En pseudo-code, l'algorithme ressemble Ă  ceci:

Algorithme: sélection de la roulette


  • Initialisation :
    1. Sélectionnez un tableau A la taille n
    2. Nous mettons A[0]=p0 .
    3. Pour chaque probabilitĂ© i de 1 avant n−1 :
      1. Nous mettons A[i]=A[i−1]+pi

  • GĂ©nĂ©ration :
    1. Générer une valeur aléatoire uniformément distribuée x dans la gamme [0,1)
    2. En utilisant une recherche binaire, nous trouvons l'index i le plus petit élément A ce qui est moins x .
    3. Retour i .

La comparaison entre cet algorithme et celui donné précédemment semble assez impressionnante:

AlgorithmeTemps d'initialisationTemps de générationMémoire occupée
Le meilleurLe pireLe meilleurLe pireLe meilleurLe pire
HonnĂȘtetĂ© os sharler bone Theta(n)O( prodni=0di) ThĂȘta(1) Theta(n)O( prodni=0di)
Os Schuler de piĂšces asymĂ©triques Theta(n) ThĂȘta(1) Theta(n) Theta(n)
SĂ©lection de roue de roulette Theta(n) Theta( logn) Theta(n)

De toute évidence, nous avons maintenant un algorithme bien meilleur que celui d'origine. La discrétion de la probabilité ne semblait que prometteuse au début, mais cette nouvelle approche, basée sur la valeur continue et la recherche binaire, semble bien meilleure. Cependant, il est toujours possible d'améliorer ces indicateurs grùce à l'utilisation intelligente d'un ensemble de techniques hybrides, dont nous parlerons ci-dessous.

Un dĂ©tail intĂ©ressant de cet algorithme est que, bien que l'utilisation de la recherche binaire garantisse le pire des cas pour gĂ©nĂ©rer des nombres alĂ©atoires O( logn) , il ne permet pas non plus une recherche plus rapide; c'est-Ă -dire que le temps de gĂ©nĂ©ration sera Ă©galement Ă©gal  Omega( logn) . Peut-il ĂȘtre amĂ©liorĂ©? Il s'avĂšre que vous le pouvez.

Supposons que nous passions d'une recherche binaire sur une liste de probabilités cumulatives à l'utilisation d'un arbre de recherche binaire . Par exemple, ayant l'ensemble de probabilités donné ci-dessus, nous pouvons construire l'arbre de recherche binaire suivant pour leur distribution cumulative:


Maintenant, si nous voulons simuler un roulement d'os, nous pouvons gĂ©nĂ©rer un nombre uniformĂ©ment distribuĂ© dans l'intervalle [0,1) puis regardez Ă  quel intervalle il se trouve dans cet arbre de recherche binaire (BST). Puisqu'il s'agit d'un arbre de recherche binaire Ă©quilibrĂ©, le meilleur temps de recherche est O(1) et le pire O( logn) .

Cependant, en supposant que nous en savons plus sur la distribution de probabilitĂ©, nous pouvons faire beaucoup mieux. Par exemple, supposons que nos probabilitĂ©s soient Ă©gales  frac99100 ,  frac1600 ,  frac1600 ,  frac1600 ,  frac1600 ,  frac1600 ,  frac1600 . Autrement dit, la distribution de probabilitĂ© est extrĂȘmement asymĂ©trique et presque toute la masse des probabilitĂ©s est concentrĂ©e sur une seule face. Nous pouvons construire une BST Ă©quilibrĂ©e pour ces probabilitĂ©s:


Bien que cet arbre de recherche binaire soit parfaitement Ă©quilibrĂ©, il n'est pas trĂšs adaptĂ© Ă  nos tĂąches. Comme nous savons que dans 99 cas sur 100, la valeur alĂ©atoire sera dans la plage [0, frac99100) , alors il est inutile de stocker le nƓud pour cet intervalle oĂč il se trouve maintenant. En fait, cela signifie que presque tout le temps, nous ferons deux comparaisons inutiles avec les zones bleues et jaunes. Étant donnĂ© qu'avec une probabilitĂ© trĂšs Ă©levĂ©e, nous devrions ĂȘtre les premiers Ă  vĂ©rifier le plus grand intervalle, il serait logique de dĂ©sĂ©quilibrer l'arbre afin de rendre le cas moyen bien meilleur en raison des autres. Ceci est montrĂ© ici:


Maintenant, nous allons probablement terminer la recherche en trouvant immĂ©diatement la zone souhaitĂ©e aprĂšs la premiĂšre tentative. Dans le cas trĂšs improbable oĂč la zone souhaitĂ©e se trouve dans le reste ( frac99100,1] on descend calmement jusqu'au bout de l'arbre qui est en fait bien Ă©quilibrĂ©.

Dans une forme généralisée, nous voulons résoudre le problÚme suivant:

Étant donnĂ© un ensemble donnĂ© de probabilitĂ©s, trouvez un arbre de recherche binaire pour ces probabilitĂ©s qui minimise le temps de recherche attendu.

Heureusement, ce problĂšme est trĂšs bien Ă©tudiĂ© et est appelĂ© le problĂšme d'arbre de recherche binaire optimal . Il existe de nombreux algorithmes pour rĂ©soudre ce problĂšme; on sait que la solution exacte peut ĂȘtre trouvĂ©e Ă  temps O(n2) en utilisant la programmation dynamique , et qu'il existe de bons algorithmes de temps linĂ©aire qui peuvent trouver des solutions approximatives. De plus, pour obtenir un facteur constant de la solution optimale, vous pouvez utiliser la structure de donnĂ©es de l' arbre d'affichage (arbre en expansion) (arbre de recherche binaire Ă  Ă©quilibrage automatique).

Il est intĂ©ressant de noter que le meilleur cas pour le comportement de ces arbres de recherche binaires optimisĂ©s se produit lorsque les distributions de probabilitĂ© sont extrĂȘmement asymĂ©triques, car nous pouvons simplement dĂ©placer les nƓuds contenant la grande majoritĂ© de la masse de probabilitĂ© vers la racine de l'arbre, et le pire est lorsque la distribution est Ă©quilibrĂ©e, car alors l'arbre doit ĂȘtre large et peu profond. C'est l'opposĂ© du comportement de l'algorithme prĂ©cĂ©dent, dans lequel un honnĂȘte algorithme a Ă©tĂ© utilisĂ© pour simuler un tricheur!

Dans le meilleur des cas, nous avons un tricheur dans lequel une face tombe toujours (c'est-Ă -dire qu'elle a une probabilitĂ© de 1 et toutes les autres faces ont une probabilitĂ© de 0). C'est une exagĂ©ration extrĂȘme de notre exemple prĂ©cĂ©dent, mais dans ce cas, la recherche se terminera toujours aprĂšs la premiĂšre tentative. Dans le pire des cas, toutes les probabilitĂ©s sont Ă©gales et nous obtenons une recherche BST standard. Nous arrivons Ă  ce qui suit:

AlgorithmeTemps d'initialisationTemps de générationMémoire occupée
Le meilleurLe pireLe meilleurLe pireLe meilleurLe pire
HonnĂȘtetĂ© os sharler bone Theta(n)O( prodni=0di) ThĂȘta(1) Theta(n)O( prodni=0di)
Os Schuler de piĂšces asymĂ©triques Theta(n) ThĂȘta(1) Theta(n) Theta(n)
SĂ©lection de roue de roulette Theta(n) Theta( logn) Theta(n)
SĂ©lection optimale des roues de rouletteO(n2) ThĂȘta(1)O( logn) Theta(n)

Lancer de fléchettes


Jusqu'Ă  prĂ©sent, nous avons envisagĂ© deux primitives qui nous ont aidĂ©s Ă  construire des algorithmes pour simuler un os tricheur: l'os honnĂȘte et la piĂšce asymĂ©trique. En utilisant uniquement de l'os honnĂȘte, nous arrivons Ă  un algorithme (hĂ©las, peu pratique) pour tricher l'os, et Ă  partir de piĂšces asymĂ©triques, nous avons pu inventer un algorithme rapide pour tricher l'os. Ces deux approches peuvent-elles ĂȘtre combinĂ©es pour crĂ©er un algorithme basĂ© sur des os honnĂȘtes et des piĂšces asymĂ©triques? Il s'avĂšre que oui, et en fait, l'algorithme rĂ©sultant est meilleur que ces deux approches.

Jusqu'à ce moment, nous avons visualisé l'intervalle [0,1) et les probabilités des faces osseuses comme intervalle unidimensionnel. Ces deux algorithmes sélectionnent un point dans l'intervalle [0,1) et posez-le sur un segment de ligne droite, dont la longueur correspond à une sorte de probabilité. Plus les segments que nous créons sont longs, plus la probabilité de choisir ce segment est grande. Mais que faire si vous essayez de penser non pas en une, mais en deux dimensions? Et si nous prenons la probabilité pi pas la longueur d'un segment de ligne droite, mais l'aire d'un rectangle?

Commençons par revenir Ă  notre exemple prĂ©cĂ©dent avec probabilitĂ©s  frac12 ,  frac13 ,  frac112 ,  frac112 . Nous reprĂ©sentons ces probabilitĂ©s sous forme de rectangles de largeur w (avec quelques arbitraires w>0 ) et hauteur pi (ainsi, l'aire du rectangle sera Ă©gale Ă  w cdotpi ):


Notez que l'aire totale de ces rectangles est w depuis la zone

 sumn−1i=0wpi=w sumn−1i=0pi=w


Supposons maintenant que nous dessinons un rectangle englobant autour de ces rectangles dont la largeur est 4w (car il y a quatre quadrangles), et la hauteur est  frac12 (puisque le rectangle le plus haut a une hauteur  frac12 ):


Nous pouvons imaginer que ce rectangle est divisĂ© en cinq zones - quatre zones correspondent Ă  des probabilitĂ©s diffĂ©rentes et une zone indique un espace inutilisĂ©. En prenant cette pause, nous pouvons considĂ©rer l'algorithme de simulation de lancer de dĂ©s alĂ©atoire comme un jeu de flĂ©chettes. Supposons que nous lançons une flĂ©chette (parfaitement uniformĂ©ment rĂ©partie) sur cette cible. Si elle tombe dans l'espace inutilisĂ©, nous sortons la flĂ©chette et la jetons Ă  nouveau, en rĂ©pĂ©tant le processus jusqu'Ă  ce que nous entrions dans l'un des rectangles. Étant donnĂ© que plus la probabilitĂ© est grande, plus le rectangle est grand, plus la probabilitĂ© de lancer le bord de l'os est grande, plus la probabilitĂ© de tomber dans son rectangle est Ă©levĂ©e. En fait, si nous fixons la condition que nous sommes dĂ©jĂ  tombĂ©s dans une sorte de rectangle, nous obtenons ce qui suit:

 mathbbP[ mboxafrappĂ©lerectanglepourlecĂŽtĂ©i| mboxfrapperunrectangle]= frac mboxairederectanglepouri mboxairetotalederectangle= fracwpiw=pi


En d'autres termes, lorsque nous tombons finalement dans une sorte de rectangle avec notre fléchette uniformément répartie, nous sélectionnons le rectangle de face i os tricheur avec probabilité pi , c'est-à-dire avec la probabilité dont nous avons besoin! Autrement dit, si nous pouvons trouver un moyen efficace de simuler le lancement de fléchettes aléatoires sur ce rectangle, alors nous aurons un moyen efficace de simuler le lancement d'un dé aléatoire.

Une façon de simuler des lancers de flĂ©chettes sur ce rectangle consiste Ă  sĂ©lectionner deux valeurs uniformĂ©ment rĂ©parties dans l'intervalle [0,1) les mettre Ă  l'Ă©chelle Ă  la largeur et Ă  la hauteur appropriĂ©es, puis vĂ©rifier la zone sous la flĂ©chette. Cependant, cela pose le mĂȘme problĂšme que nous avions lorsque nous avons essayĂ© de dĂ©terminer la rĂ©gion unidimensionnelle dans laquelle se trouve la valeur alĂ©atoire. Cependant, il existe une sĂ©rie d'observations vraiment merveilleuses, grĂące Ă  laquelle dĂ©terminer le lieu de l'impact peut ĂȘtre une tĂąche simple, sinon triviale.

PremiĂšre observation: nous avons montrĂ© que la largeur de ces rectangles peut ĂȘtre choisie arbitrairement, car tous ont une largeur Ă©gale. Les hauteurs, bien sĂ»r, dĂ©pendent des probabilitĂ©s des faces des os. Cependant, si nous mettons Ă  l'Ă©chelle uniformĂ©ment toutes les hauteurs par un certain nombre rĂ©el positif h , alors les zones relatives de tous les rectangles seront les mĂȘmes. En fait, pour tout nombre rĂ©el positif h surface totale de tous les rectangles aprĂšs avoir mis leur hauteur Ă  l'Ă©chelle h calculĂ© comme

 sumn−1i=0whpi=wh sumn−1i=0pi=wh


Nous allons maintenant considĂ©rer la probabilitĂ© de choisir un rectangle individuel, en nous limitant Ă  la condition que nous frappions dĂ©finitivement une sorte de rectangle. En utilisant les mĂȘmes calculs, nous obtenons ce qui suit:

 mathbbP[ mboxafrappĂ©lerectanglepourlecĂŽtĂ©i| mboxfrapperunrectangle]= frac mboxairederectanglepouri mboxairetotalederectangle= fracwhpiwh=pi


Autrement dit, la probabilité de choisir un seul rectangle ne change pas si nous les mettons à l'échelle de façon linéaire et uniforme.

Puisque nous pouvons choisir n'importe quel facteur d'Ă©chelle appropriĂ©, pourquoi ne pas mettre Ă  l'Ă©chelle ces rectangles de sorte que la hauteur du cadre de sĂ©lection soit toujours 1? Étant donnĂ© que la hauteur du cadre de sĂ©lection est dĂ©terminĂ©e par la valeur maximale pi probabilitĂ©s d'entrĂ©e, alors nous pouvons commencer par mettre Ă  l'Ă©chelle chacun des rectangles par un facteur  frac1pmax oĂč pmax Est la probabilitĂ© maximale de toutes les probabilitĂ©s d'entrĂ©e. GrĂące Ă  cela, nous obtenons la hauteur du rectangle 1. De mĂȘme, comme nous pouvons choisir n'importe quelle largeur arbitraire pour les rectangles, prenons la largeur 1. Cela signifie que pour n les probabilitĂ©s de la largeur totale du cadre de dĂ©limitation sont n , et la hauteur totale est 1. Ceci est illustrĂ© dans la figure:


Nous sommes maintenant prĂȘts Ă  rĂ©flĂ©chir Ă  la façon de lancer une flĂ©chette alĂ©atoire dans un rectangle et de dĂ©terminer dans quoi elle est tombĂ©e. La chose la plus importante est que nous pouvons diviser le rectangle afin qu'il ne soit pas composĂ© de plusieurs petits rectangles et d'un espace vide d'une forme Ă©trange. Au lieu de cela, la zone est dĂ©coupĂ©e en un ensemble de 2n rectangles, deux sur chacun n probabilitĂ©s d'entrĂ©e. Ceci est montrĂ© ici:


Remarquez comment ce rectangle se forme. Pour chaque face de l'os du tricheur, nous avons une colonne d'une largeur de 1 et d'une hauteur de 1, divisée en deux espaces - un demi-espace "oui" correspondant à un rectangle de cette taille et un demi-espace "non" correspondant à la partie restante de la colonne.

Voyons maintenant comment lancer une flĂ©chette. Une flĂ©chette parfaitement uniforme jetĂ©e dans ce rectangle aura des composants x et y . Ici le composant x qui devrait ĂȘtre dans l'intervalle [0,1) , correspond Ă  la colonne que la flĂ©chette frappe. Composant y qui devrait ĂȘtre dans l'intervalle [0,1) , correspond Ă  la hauteur de notre colonne. SĂ©lection des composants x affecte la face de l'os tricheur que nous considĂ©rons et le choix du composant y correspond Ă  savoir si nous avons choisi cette facette ou non. Mais attendez - nous connaissons dĂ©jĂ  ces deux idĂ©es! SĂ©lection de coordonnĂ©es x correspondant Ă  la colonne, semblable Ă  jeter un os honnĂȘte pour dĂ©cider du choix de la colonne. SĂ©lection de coordonnĂ©es y correspond au lancer d'une piĂšce asymĂ©trique pour dĂ©terminer s'il faut sĂ©lectionner un visage ou lancer Ă  nouveau! Cette observation est si importante que nous la rendons absolument comprĂ©hensible:

Le choix d'un point alĂ©atoire dans cet intervalle revient Ă  lancer un os honnĂȘte et Ă  lancer une piĂšce asymĂ©trique.

En fait, ce rĂ©sultat peut ĂȘtre perçu comme une opportunitĂ© beaucoup plus puissante. Pour simuler un os tricheur, nous construisons un ensemble de piĂšces asymĂ©triques, une pour chaque face de l'os, puis roulons un os honnĂȘte pour dĂ©terminer quelle piĂšce lancer. Sur la base du roulement de l'os, si un aigle tombe sur la piĂšce correspondante, nous sĂ©lectionnons la face correspondante, et si les queues tombent, jetons Ă  nouveau l'os et rĂ©pĂ©tons le processus.

. -, — «» pipmax , «» pmax−pipmax . , 1. -, 1 , . , : - , , ( , ). . , , . .

: /


  • :
    1. pi ; pmax .
    2. Coins n , «» .
    3. i de 0 avant n−1 :
      1. Coins[i]=pipmax

  • :
    1. :
      1. n- i [0,n) .
      2. , Coins[i] .
      3. , i .

. O(n) , O(n) Coins , O(n) . , O(1) . ? , , - . , . , ( 1n ), . , , , , - , . , i pipmax , -

n−1∑i=0(1npipmax)=1nn−1∑i=0pipmax=1n⋅pmaxn−1∑i=0pi=1n⋅pmax


- , , , , , n⋅pmax . ? pmax . pmax 1 ( ). n , n . , , , , . , pmax 1n , , . Si pmax=1n , 1. . Si pmax=1n , ( 1n ), 1, , 1. , , .

, pmax , , , . , , n , , 1. , , «» 1pmax , 1, 1pmax . , «» 1n⋅pmax . , , «», pmax . , , .

:

Algorithme
Θ(n)O(∏ni=0di)Θ(1)Θ(n)O(∏ni=0di)
Θ(n)Θ(1)Θ(n)Θ(n)
Θ(n)Θ(logn)Θ(n)
O(n2)Θ(1)O(logn)Θ(n)
/Θ(n)Θ(1)Θ(n) ()Θ(n)

, . . ?

Alias-


, . , . , , «» , . , , , . - , , - , .

, , , . . 12 , 13 , 112 , 112 . , 14 . , 14 , 12 ? , . 1 , :


, 14 1. , , :


1×4 . , :


, , 12 et 13 . ? , 12 112 ? , - , :


, , . , 12 et 13 , . 12 , . , :


, , :


. -, . , ; . , , . -, , , - , , . , . — , . , — , , . , . , , , - ( ).

alias- . -, , . , , . , , , .

, , ? , , . , , , , , . , . , - , , , ( ) , - . (alias) , «» - . - «alias» «alias-».

, , . - ( !), () , , alias- : Prob alias Alias . n . , alias , ( ). , . - - i . Prob[i] . , , i , , Alias[i] . alias :


Alias


, Alias et Prob . , , :

  • (n⋅pi)×1 pi ,
  • n
    • , 1 ,
    • , i , i .

, , . , 12 , 13 , 112 , 112 . ( k=n=4 ), 1=44 . , alias, , . , 4, :


, , ( 13 , 13 ) 1. , - . ( ) :


- . , , , 1 ( 2 et 43 ). ; 43 . 43 , ; 23 de 43 , :


, . , 3 , , , . , . , , 1 , (, 23 ) :


, - , 1, . ( 2 ), 13 de 2 :


, . , - , 1 ( 13 ), :


- 1 , . — 53 :


, 1. , :


! .

, :

  • - , 1, , Prob .
  • - , 1, , Alias , .

, ? «», ? , . : , 1 ( 1n , n ). , , , , 1 ( ) 1 ( ). , . , ? , . , , . , .

:

: k h0 , h1 , ..., hk−1 , , ∑k−1i=0hi=k , k , 1, , , i - i - .

: . , k=1 , 1. 0 - . , 1, , 0 - 0 - .

, - , , ..., , , . , , , , - (, ), , . , , avec ; , . , , . , - , , . , ( ), , . , , ( ) . , et .

. dans - ( , et ). . , , , . , , . , , dans , . , , , , . .

, , alias, , . alias.

Alias


, alias-. 1 1, :

: Alias-


  • :
    1. sur .
    2. et , .
    3. For :
      1. , .
      2. ( ),
      3. .
      4. .
      5. .
      6. .

    4. , 1.
    5. .

  • :
    1. - ; .
    2. , .
    3. , .
    4. .

, , . . -, , . , , . . , :

Algorithme
/()
Alias-

alias- , . - (, ), .

. , . . et , . , . :

: Alias-


  • :
    1. et , .
    2. .
    3. dans .
    4. For :
      1. ; .
      2. ; .
      3. .
      4. .
      5. .
      6. Ă  .

    5. , 1.
    6. .

  • :
    1. - ; .
    2. , .
    3. , .
    4. .

. et - , BST . , . :

Algorithme
/()
Alias-
Alias-

, . , , , alias-. «A Linear Algorithm For Generating Random Numbers With a Given Distribution» , alias-.

: 1, 1. . «» , «» «». :

  • «» 1.
  • «» 1.
  • .

, , , . , :

: () Alias-


: . .


  • :
    1. et , .
    2. , et .
    3. .
    4. :
      1. Si , Ă  .
      2. ( ) Ă  .

    5. :
      1. ; .
      2. ; .
      3. .
      4. .
      5. .
      6. Si , dans .
      7. ($p_g \ge 1$) dans .

    6. :
      1. ; .
      2. .


  • :
    1. - ; .
    2. , .
    3. , .
    4. .

(, ) : - , . . ( , , ). 1, , 1, . 1, , , 1.

. , , , . .

, . , , , , , , . , , , , , , , , . :


, :


( ) . , :


. , :


:


, , , . , :


, :


, , :


, , .


alias .


, . , , IEEE-754 double, . , , :

  1. , , . , , , , , ( , ).
  2. , , . , , , .

, . , , , .

, . , , , . -, , , , . , . :

: Alias-


  • :
    1. et , .
    2. , et .
    3. .
    4. :
      1. Si , dans .
      2. ( ) dans .

    5. et : ( )
      1. ; .
      2. ; .
      3. .
      4. .
      5. . ( . )
      6. Si , dans .
      7. ( ) dans .

    6. :
      1. ; .
      2. .

    7. : - .
      1. ; .
      2. .


  • :
    1. - ; .
    2. , .
    3. , .
    4. .

, — . , . , , . , () , . , et . , ( ) :
Algorithme
/()
Alias-
Alias-
Alias-


Ouah! ! , . , (alias- ) , - .

alias- , , - , alias- Java , .

, !

Source: https://habr.com/ru/post/fr419725/


All Articles